@vuu-ui/vuu-table-extras 4.0.0-alpha.18 → 4.0.0-alpha.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +13 -13
- package/src/column-expression-input/useColumnExpressionSuggestionProvider.js +2 -2
- package/src/column-formatting-settings/ColumnFormattingPanel.js +12 -9
- package/src/column-formatting-settings/DateTimeFormattingSettings.js +107 -3
- package/src/column-formatting-settings/LongTypeFormattingSettings.js +8 -3
- package/src/csv-export/export-utils.js +66 -19
- package/src/csv-export/index.js +1 -1
- package/src/csv-export/useCsvExport.js +9 -1
- package/src/table-footer/TableFooter.js +3 -3
- package/types/column-formatting-settings/DateTimeFormattingSettings.d.ts +1 -1
- package/types/csv-export/export-utils.d.ts +22 -9
- package/types/csv-export/index.d.ts +1 -1
- package/types/csv-export/useCsvExport.d.ts +5 -2
- package/types/inline-add-row/useInlineAddRow.d.ts +2 -1
- package/types/table-footer/TableFooter.d.ts +2 -2
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "4.0.0-alpha.
|
|
2
|
+
"version": "4.0.0-alpha.19",
|
|
3
3
|
"author": "heswell",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"license": "Apache-2.0",
|
|
@@ -12,20 +12,20 @@
|
|
|
12
12
|
"lezer-generate:column": "lezer-generator --output ./src/column-expression-input/column-language-parser/generated/column-parser.ts ./src/column-expression-input/column-language-parser/grammar/column.grammar"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
|
-
"@vuu-ui/vuu-filter-types": "4.0.0-alpha.
|
|
16
|
-
"@vuu-ui/vuu-protocol-types": "4.0.0-alpha.
|
|
15
|
+
"@vuu-ui/vuu-filter-types": "4.0.0-alpha.19",
|
|
16
|
+
"@vuu-ui/vuu-protocol-types": "4.0.0-alpha.19"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@vuu-ui/core": "4.0.0-alpha.
|
|
20
|
-
"@vuu-ui/vuu-codemirror": "4.0.0-alpha.
|
|
21
|
-
"@vuu-ui/vuu-data-editing": "4.0.0-alpha.
|
|
22
|
-
"@vuu-ui/vuu-data-react": "4.0.0-alpha.
|
|
23
|
-
"@vuu-ui/vuu-data-types": "4.0.0-alpha.
|
|
24
|
-
"@vuu-ui/vuu-table-types": "4.0.0-alpha.
|
|
25
|
-
"@vuu-ui/vuu-popups": "4.0.0-alpha.
|
|
26
|
-
"@vuu-ui/vuu-table": "4.0.0-alpha.
|
|
27
|
-
"@vuu-ui/vuu-utils": "4.0.0-alpha.
|
|
28
|
-
"@vuu-ui/vuu-ui-controls": "4.0.0-alpha.
|
|
19
|
+
"@vuu-ui/core": "4.0.0-alpha.19",
|
|
20
|
+
"@vuu-ui/vuu-codemirror": "4.0.0-alpha.19",
|
|
21
|
+
"@vuu-ui/vuu-data-editing": "4.0.0-alpha.19",
|
|
22
|
+
"@vuu-ui/vuu-data-react": "4.0.0-alpha.19",
|
|
23
|
+
"@vuu-ui/vuu-data-types": "4.0.0-alpha.19",
|
|
24
|
+
"@vuu-ui/vuu-table-types": "4.0.0-alpha.19",
|
|
25
|
+
"@vuu-ui/vuu-popups": "4.0.0-alpha.19",
|
|
26
|
+
"@vuu-ui/vuu-table": "4.0.0-alpha.19",
|
|
27
|
+
"@vuu-ui/vuu-utils": "4.0.0-alpha.19",
|
|
28
|
+
"@vuu-ui/vuu-ui-controls": "4.0.0-alpha.19",
|
|
29
29
|
"@lezer/lr": "1.4.2",
|
|
30
30
|
"@salt-ds/core": "1.67.0",
|
|
31
31
|
"@salt-ds/lab": "1.0.0-alpha.99",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AnnotationType, getRelationalOperators, numericOperators, stringOperators, toSuggestions } from "@vuu-ui/vuu-codemirror";
|
|
2
2
|
import { getTypeaheadParams, useTypeaheadSuggestions } from "@vuu-ui/vuu-data-react";
|
|
3
|
-
import { isNumericColumn, isTextColumn } from "@vuu-ui/vuu-utils";
|
|
3
|
+
import { isNumericColumn, isTemporalColumn, isTextColumn } from "@vuu-ui/vuu-utils";
|
|
4
4
|
import { useCallback, useRef } from "react";
|
|
5
5
|
import { columnFunctionDescriptors } from "./column-function-descriptors.js";
|
|
6
6
|
import { functionDocInfo } from "./functionDocInfo.js";
|
|
@@ -64,7 +64,7 @@ const arithmeticOperators = [
|
|
|
64
64
|
}
|
|
65
65
|
];
|
|
66
66
|
const getOperators = (column)=>{
|
|
67
|
-
if (void 0 === column || isNumericColumn(column)) return arithmeticOperators;
|
|
67
|
+
if (void 0 === column || isNumericColumn(column) || isTemporalColumn(column)) return arithmeticOperators;
|
|
68
68
|
return NO_OPERATORS;
|
|
69
69
|
};
|
|
70
70
|
const getConditionOperators = (column)=>{
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { getCellRendererOptions, getConfigurationEditor, isColumnTypeRenderer, isTypeDescriptor } from "@vuu-ui/vuu-utils";
|
|
2
|
+
import { getCellRendererOptions, getConfigurationEditor, isColumnTypeRenderer, isTemporalColumn, isTypeDescriptor } from "@vuu-ui/vuu-utils";
|
|
3
3
|
import { Dropdown, FormField, FormFieldLabel, Option } from "@salt-ds/core";
|
|
4
4
|
import clsx from "clsx";
|
|
5
5
|
import { useCallback, useMemo } from "react";
|
|
@@ -88,21 +88,24 @@ const ColumnFormattingPanel = ({ availableRenderers, className, column, onChange
|
|
|
88
88
|
function getFormattingSettingsComponent(props) {
|
|
89
89
|
const { column } = props;
|
|
90
90
|
switch(column.serverDataType){
|
|
91
|
+
case "long":
|
|
92
|
+
return /*#__PURE__*/ jsx(LongTypeFormattingSettings, {
|
|
93
|
+
...props
|
|
94
|
+
});
|
|
95
|
+
case "epochtimestamp":
|
|
96
|
+
case "epochtimestampnano":
|
|
97
|
+
return /*#__PURE__*/ jsx(DateTimeFormattingSettings, {
|
|
98
|
+
...props
|
|
99
|
+
});
|
|
91
100
|
case "double":
|
|
92
101
|
case "scaleddecimal2":
|
|
93
102
|
case "scaleddecimal4":
|
|
94
103
|
case "scaleddecimal6":
|
|
95
104
|
case "scaleddecimal8":
|
|
96
105
|
case "int":
|
|
97
|
-
return /*#__PURE__*/ jsx(
|
|
106
|
+
return isTemporalColumn(column) ? /*#__PURE__*/ jsx(DateTimeFormattingSettings, {
|
|
98
107
|
...props
|
|
99
|
-
})
|
|
100
|
-
case "long":
|
|
101
|
-
return /*#__PURE__*/ jsx(LongTypeFormattingSettings, {
|
|
102
|
-
...props
|
|
103
|
-
});
|
|
104
|
-
case "epochtimestamp":
|
|
105
|
-
return /*#__PURE__*/ jsx(DateTimeFormattingSettings, {
|
|
108
|
+
}) : /*#__PURE__*/ jsx(BaseNumericFormattingSettings, {
|
|
106
109
|
...props
|
|
107
110
|
});
|
|
108
111
|
default:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { dateTimeLabelByType, defaultPatternsByType, fallbackDateTimePattern, getTypeFormattingFromColumn, isDatePattern, isTimePattern, supportedDateTimePatterns } from "@vuu-ui/vuu-utils";
|
|
2
|
+
import { dateTimeLabelByType, dateTimePattern, defaultPatternsByType, fallbackDateTimePattern, getTemporalInfo, getTypeFormattingFromColumn, isDatePattern, isTimePattern, supportedDateTimePatterns } from "@vuu-ui/vuu-utils";
|
|
3
3
|
import { Dropdown, FormField, FormFieldLabel, Option, ToggleButton, ToggleButtonGroup } from "@salt-ds/core";
|
|
4
4
|
import { useCallback, useMemo, useState } from "react";
|
|
5
5
|
const toggleValues = [
|
|
@@ -7,6 +7,32 @@ const toggleValues = [
|
|
|
7
7
|
"time",
|
|
8
8
|
"both"
|
|
9
9
|
];
|
|
10
|
+
const DEFAULT = "default";
|
|
11
|
+
const fractionalSecondDigitOptions = [
|
|
12
|
+
DEFAULT,
|
|
13
|
+
"0",
|
|
14
|
+
"3",
|
|
15
|
+
"6",
|
|
16
|
+
"9"
|
|
17
|
+
];
|
|
18
|
+
const timeZoneOptions = [
|
|
19
|
+
DEFAULT,
|
|
20
|
+
"local",
|
|
21
|
+
"UTC",
|
|
22
|
+
"Europe/London",
|
|
23
|
+
"Europe/Paris",
|
|
24
|
+
"America/New_York",
|
|
25
|
+
"Asia/Tokyo",
|
|
26
|
+
"Asia/Hong_Kong"
|
|
27
|
+
];
|
|
28
|
+
const localeOptions = [
|
|
29
|
+
DEFAULT,
|
|
30
|
+
"en-GB",
|
|
31
|
+
"en-US",
|
|
32
|
+
"de-DE",
|
|
33
|
+
"fr-FR",
|
|
34
|
+
"ja-JP"
|
|
35
|
+
];
|
|
10
36
|
function getToggleValue(pattern) {
|
|
11
37
|
return pattern.time ? pattern.date ? "both" : "time" : "date";
|
|
12
38
|
}
|
|
@@ -20,7 +46,8 @@ const getSelectedPattern = (pattern)=>{
|
|
|
20
46
|
};
|
|
21
47
|
const DateTimeFormattingSettings = ({ column, onChangeFormatting: onChange })=>{
|
|
22
48
|
const formatting = getTypeFormattingFromColumn(column);
|
|
23
|
-
const
|
|
49
|
+
const temporalInfo = getTemporalInfo(column);
|
|
50
|
+
const { pattern = temporalInfo ? dateTimePattern(column.type, temporalInfo.kind) : fallbackDateTimePattern } = formatting;
|
|
24
51
|
const toggleValue = useMemo(()=>getToggleValue(pattern), [
|
|
25
52
|
pattern
|
|
26
53
|
]);
|
|
@@ -28,6 +55,26 @@ const DateTimeFormattingSettings = ({ column, onChangeFormatting: onChange })=>{
|
|
|
28
55
|
time: pattern.time ?? defaultPatternsByType.time,
|
|
29
56
|
date: pattern.date ?? defaultPatternsByType.date
|
|
30
57
|
});
|
|
58
|
+
const onFractionalSecondDigitsChange = useCallback((_, [value])=>{
|
|
59
|
+
const { fractionalSecondDigits, ...rest } = formatting;
|
|
60
|
+
onChange(value === DEFAULT ? rest : {
|
|
61
|
+
...rest,
|
|
62
|
+
fractionalSecondDigits: parseInt(value, 10)
|
|
63
|
+
});
|
|
64
|
+
}, [
|
|
65
|
+
formatting,
|
|
66
|
+
onChange
|
|
67
|
+
]);
|
|
68
|
+
const onFormattingOptionChange = useCallback((key)=>(_, [value])=>{
|
|
69
|
+
const { [key]: _previous, ...rest } = formatting;
|
|
70
|
+
onChange(value === DEFAULT ? rest : {
|
|
71
|
+
...rest,
|
|
72
|
+
[key]: value
|
|
73
|
+
});
|
|
74
|
+
}, [
|
|
75
|
+
formatting,
|
|
76
|
+
onChange
|
|
77
|
+
]);
|
|
31
78
|
const onPatternChange = useCallback((pattern)=>onChange({
|
|
32
79
|
...formatting,
|
|
33
80
|
pattern
|
|
@@ -109,7 +156,64 @@ const DateTimeFormattingSettings = ({ column, onChangeFormatting: onChange })=>{
|
|
|
109
156
|
}, i))
|
|
110
157
|
})
|
|
111
158
|
]
|
|
112
|
-
}, v))
|
|
159
|
+
}, v)),
|
|
160
|
+
pattern.time ? /*#__PURE__*/ jsxs(FormField, {
|
|
161
|
+
labelPlacement: "top",
|
|
162
|
+
children: [
|
|
163
|
+
/*#__PURE__*/ jsx(FormFieldLabel, {
|
|
164
|
+
children: "Fractional second digits"
|
|
165
|
+
}),
|
|
166
|
+
/*#__PURE__*/ jsx(Dropdown, {
|
|
167
|
+
onSelectionChange: onFractionalSecondDigitsChange,
|
|
168
|
+
selected: [
|
|
169
|
+
`${formatting.fractionalSecondDigits ?? DEFAULT}`
|
|
170
|
+
],
|
|
171
|
+
value: `${formatting.fractionalSecondDigits ?? DEFAULT}`,
|
|
172
|
+
children: fractionalSecondDigitOptions.filter((digits)=>temporalInfo?.precision === "ns" || "6" !== digits && "9" !== digits).map((digits)=>/*#__PURE__*/ jsx(Option, {
|
|
173
|
+
value: digits,
|
|
174
|
+
children: digits
|
|
175
|
+
}, digits))
|
|
176
|
+
})
|
|
177
|
+
]
|
|
178
|
+
}) : null,
|
|
179
|
+
/*#__PURE__*/ jsxs(FormField, {
|
|
180
|
+
labelPlacement: "top",
|
|
181
|
+
children: [
|
|
182
|
+
/*#__PURE__*/ jsx(FormFieldLabel, {
|
|
183
|
+
children: "Time zone"
|
|
184
|
+
}),
|
|
185
|
+
/*#__PURE__*/ jsx(Dropdown, {
|
|
186
|
+
onSelectionChange: onFormattingOptionChange("timeZone"),
|
|
187
|
+
selected: [
|
|
188
|
+
formatting.timeZone ?? DEFAULT
|
|
189
|
+
],
|
|
190
|
+
value: formatting.timeZone ?? DEFAULT,
|
|
191
|
+
children: timeZoneOptions.map((timeZone)=>/*#__PURE__*/ jsx(Option, {
|
|
192
|
+
value: timeZone,
|
|
193
|
+
children: timeZone
|
|
194
|
+
}, timeZone))
|
|
195
|
+
})
|
|
196
|
+
]
|
|
197
|
+
}),
|
|
198
|
+
/*#__PURE__*/ jsxs(FormField, {
|
|
199
|
+
labelPlacement: "top",
|
|
200
|
+
children: [
|
|
201
|
+
/*#__PURE__*/ jsx(FormFieldLabel, {
|
|
202
|
+
children: "Locale"
|
|
203
|
+
}),
|
|
204
|
+
/*#__PURE__*/ jsx(Dropdown, {
|
|
205
|
+
onSelectionChange: onFormattingOptionChange("locale"),
|
|
206
|
+
selected: [
|
|
207
|
+
formatting.locale ?? DEFAULT
|
|
208
|
+
],
|
|
209
|
+
value: formatting.locale ?? DEFAULT,
|
|
210
|
+
children: localeOptions.map((locale)=>/*#__PURE__*/ jsx(Option, {
|
|
211
|
+
value: locale,
|
|
212
|
+
children: locale
|
|
213
|
+
}, locale))
|
|
214
|
+
})
|
|
215
|
+
]
|
|
216
|
+
})
|
|
113
217
|
]
|
|
114
218
|
});
|
|
115
219
|
};
|
|
@@ -5,7 +5,8 @@ import { useWindow } from "@salt-ds/window";
|
|
|
5
5
|
import { useCallback } from "react";
|
|
6
6
|
import { BaseNumericFormattingSettings } from "./BaseNumericFormattingSettings.js";
|
|
7
7
|
import LongTypeFormattingSettings from "./LongTypeFormattingSettings.css";
|
|
8
|
-
import { isTypeDescriptor } from "@vuu-ui/vuu-utils";
|
|
8
|
+
import { isTemporalColumn, isTypeDescriptor } from "@vuu-ui/vuu-utils";
|
|
9
|
+
import { DateTimeFormattingSettings } from "./DateTimeFormattingSettings.js";
|
|
9
10
|
const classBase = "vuuLongColumnFormattingSettings";
|
|
10
11
|
const LongTypeFormattingSettings_LongTypeFormattingSettings = (props)=>{
|
|
11
12
|
const targetWindow = useWindow();
|
|
@@ -41,7 +42,9 @@ const LongTypeFormattingSettings_LongTypeFormattingSettings = (props)=>{
|
|
|
41
42
|
})
|
|
42
43
|
]
|
|
43
44
|
}),
|
|
44
|
-
/*#__PURE__*/ jsx(
|
|
45
|
+
isTemporalColumn(column) ? /*#__PURE__*/ jsx(DateTimeFormattingSettings, {
|
|
46
|
+
...props
|
|
47
|
+
}) : /*#__PURE__*/ jsx(BaseNumericFormattingSettings, {
|
|
45
48
|
...props
|
|
46
49
|
})
|
|
47
50
|
]
|
|
@@ -49,6 +52,8 @@ const LongTypeFormattingSettings_LongTypeFormattingSettings = (props)=>{
|
|
|
49
52
|
};
|
|
50
53
|
const toggleValues = [
|
|
51
54
|
"number",
|
|
52
|
-
"date/time"
|
|
55
|
+
"date/time",
|
|
56
|
+
"date",
|
|
57
|
+
"time"
|
|
53
58
|
];
|
|
54
59
|
export { LongTypeFormattingSettings_LongTypeFormattingSettings as LongTypeFormattingSettings };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Range, isSessionTable, metadataKeys } from "@vuu-ui/vuu-utils";
|
|
1
|
+
import { Range, buildColumnMap, getValueFormatter, isSessionTable, metadataKeys } from "@vuu-ui/vuu-utils";
|
|
2
2
|
const EXPORT_EXCLUDED_COLUMNS = new Set([
|
|
3
3
|
"vuuMsg",
|
|
4
4
|
"vuuAction",
|
|
@@ -28,10 +28,31 @@ const triggerCsvDownload = (csv, filename)=>{
|
|
|
28
28
|
document.body.removeChild(a);
|
|
29
29
|
setTimeout(()=>URL.revokeObjectURL(url), 10000);
|
|
30
30
|
};
|
|
31
|
+
const createRowAccessor = (row, columnMap)=>new Proxy({}, {
|
|
32
|
+
get (_, prop) {
|
|
33
|
+
if ("string" == typeof prop) {
|
|
34
|
+
const idx = columnMap[prop];
|
|
35
|
+
if (void 0 !== idx) return row[idx];
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
has (_, prop) {
|
|
39
|
+
return "string" == typeof prop && void 0 !== columnMap[prop];
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
const isExportableColumn = (descriptor)=>{
|
|
43
|
+
if (!descriptor) return true;
|
|
44
|
+
if (false === descriptor.exportable) return false;
|
|
45
|
+
if (descriptor.hidden) return false;
|
|
46
|
+
if (descriptor.isSystemColumn) return false;
|
|
47
|
+
if (true === descriptor.exportable) return true;
|
|
48
|
+
if ("client" === descriptor.source && !descriptor.exportFormatter) return false;
|
|
49
|
+
return true;
|
|
50
|
+
};
|
|
31
51
|
const exportCsvTemplate = async (dataSource, options = {})=>{
|
|
32
52
|
const { filename = "template.csv", excludeColumns = [], columns, overrides, timeout = DEFAULT_TEMPLATE_TIMEOUT, onError, onSuccess } = options;
|
|
33
|
-
const
|
|
34
|
-
|
|
53
|
+
const targetColumnNames = columns ? columns.filter((col)=>"string" == typeof col ? true : isExportableColumn(col) && "client" !== col.source).map((col)=>"string" == typeof col ? col : col.name) : void 0;
|
|
54
|
+
const sessionOverrides = overrides ?? (targetColumnNames ? {
|
|
55
|
+
columns: targetColumnNames
|
|
35
56
|
} : void 0);
|
|
36
57
|
if (!isSessionTable(dataSource.table) && dataSource.createSessionDataSource && "initialising" !== dataSource.status && "unsubscribed" !== dataSource.status) try {
|
|
37
58
|
const sessionDataSource = await dataSource.createSessionDataSource("Empty", "export", sessionOverrides);
|
|
@@ -72,7 +93,7 @@ const exportCsvTemplate = async (dataSource, options = {})=>{
|
|
|
72
93
|
console.warn("[exportCsvTemplate] createSessionDataSource failed, falling back to tableSchema", error);
|
|
73
94
|
}
|
|
74
95
|
const schema = dataSource.tableSchema;
|
|
75
|
-
const targetColumns =
|
|
96
|
+
const targetColumns = targetColumnNames ?? overrides?.columns;
|
|
76
97
|
if (void 0 !== targetColumns) {
|
|
77
98
|
if (schema) {
|
|
78
99
|
const schemaColumnNames = new Set(schema.columns.map((col)=>col.name));
|
|
@@ -99,7 +120,18 @@ const exportCsvTemplate = async (dataSource, options = {})=>{
|
|
|
99
120
|
onSuccess?.();
|
|
100
121
|
};
|
|
101
122
|
const exportSessionTableToCsv = async (dataSource, options = {})=>{
|
|
102
|
-
const { filename = "export.csv", copyOption = "All", excludeColumns = [], maxRows = MAX_EXPORT_ROWS, columnDescriptors, overrides, timeout = DEFAULT_EXPORT_TIMEOUT, onError, onSuccess } = options;
|
|
123
|
+
const { filename = "export.csv", copyOption = "All", excludeColumns = [], maxRows = MAX_EXPORT_ROWS, columnDescriptors: rawColumnDescriptors, columns: rawColumns, overrides, timeout = DEFAULT_EXPORT_TIMEOUT, onError, onSuccess } = options;
|
|
124
|
+
const rawInputColumns = rawColumns ?? rawColumnDescriptors;
|
|
125
|
+
const columnDescriptors = rawInputColumns?.map((col)=>"string" == typeof col ? {
|
|
126
|
+
name: col
|
|
127
|
+
} : col);
|
|
128
|
+
const sessionOverrides = overrides ? {
|
|
129
|
+
...overrides,
|
|
130
|
+
columns: overrides.columns?.filter((name)=>{
|
|
131
|
+
const desc = columnDescriptors?.find((d)=>d.name === name);
|
|
132
|
+
return desc?.source !== "client";
|
|
133
|
+
})
|
|
134
|
+
} : void 0;
|
|
103
135
|
const isRemote = !!dataSource.isRemote;
|
|
104
136
|
if (isRemote && !isSessionTable(dataSource.table) && ("initialising" === dataSource.status || "unsubscribed" === dataSource.status)) {
|
|
105
137
|
const error = new Error(`exportSessionTableToCsv: dataSource must be subscribed before exporting (current status: "${dataSource.status}")`);
|
|
@@ -108,7 +140,7 @@ const exportSessionTableToCsv = async (dataSource, options = {})=>{
|
|
|
108
140
|
}
|
|
109
141
|
let sessionDataSource;
|
|
110
142
|
if (!isSessionTable(dataSource.table) && dataSource.createSessionDataSource) try {
|
|
111
|
-
sessionDataSource = await dataSource.createSessionDataSource(copyOption, "export",
|
|
143
|
+
sessionDataSource = await dataSource.createSessionDataSource(copyOption, "export", sessionOverrides);
|
|
112
144
|
} catch (err) {
|
|
113
145
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
114
146
|
if (onError) return void onError(error);
|
|
@@ -152,18 +184,23 @@ const exportSessionTableToCsv = async (dataSource, options = {})=>{
|
|
|
152
184
|
const { columns } = message;
|
|
153
185
|
if (columnDescriptors) {
|
|
154
186
|
const subscribedSet = new Set(columns);
|
|
155
|
-
const unknown = columnDescriptors.filter((d)
|
|
187
|
+
const unknown = columnDescriptors.filter((d)=>"client" !== d.source && !excluded.has(d.name) && !subscribedSet.has(d.name)).map((d)=>d.name);
|
|
156
188
|
if (unknown.length > 0) return void fail(new Error(`exportToCsv: unknown column(s) in columnDescriptors: ${unknown.join(", ")}`));
|
|
157
189
|
descriptorMap = Object.fromEntries(columnDescriptors.map((d)=>[
|
|
158
190
|
d.name,
|
|
159
191
|
d
|
|
160
192
|
]));
|
|
161
193
|
}
|
|
162
|
-
exportCols =
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
194
|
+
if (rawColumns) exportCols = rawColumns.map((c)=>"string" == typeof c ? c : c.name).filter((name)=>!excluded.has(name) && isExportableColumn(descriptorMap[name]));
|
|
195
|
+
else if (columnDescriptors?.some((d)=>"client" === d.source)) {
|
|
196
|
+
const definedNames = new Set(columnDescriptors.map((d)=>d.name));
|
|
197
|
+
const remainingSubscribed = columns.filter((name)=>!excluded.has(name) && !definedNames.has(name) && isExportableColumn(descriptorMap[name]));
|
|
198
|
+
exportCols = [
|
|
199
|
+
...columnDescriptors.filter((d)=>!excluded.has(d.name) && isExportableColumn(d)).map((d)=>d.name),
|
|
200
|
+
...remainingSubscribed
|
|
201
|
+
];
|
|
202
|
+
} else exportCols = columns.filter((name)=>!excluded.has(name) && isExportableColumn(descriptorMap[name]));
|
|
203
|
+
colNameToRowIdx = buildColumnMap(columns);
|
|
167
204
|
} else if ("viewport-update" === message.type) {
|
|
168
205
|
if ("size-only" === message.mode) {
|
|
169
206
|
totalSize = message.size ?? 0;
|
|
@@ -191,11 +228,21 @@ const exportSessionTableToCsv = async (dataSource, options = {})=>{
|
|
|
191
228
|
];
|
|
192
229
|
for(let i = 0; i < totalSize; i++){
|
|
193
230
|
const row = collectedRows.get(i);
|
|
194
|
-
if (row)
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
231
|
+
if (row) {
|
|
232
|
+
const rowAccessor = createRowAccessor(row, colNameToRowIdx);
|
|
233
|
+
lines.push(exportCols.map((c)=>{
|
|
234
|
+
const descriptor = descriptorMap[c];
|
|
235
|
+
const isClientCol = descriptor?.source === "client";
|
|
236
|
+
const raw = isClientCol ? void 0 : void 0 !== colNameToRowIdx[c] ? row[colNameToRowIdx[c]] : void 0;
|
|
237
|
+
let formatted;
|
|
238
|
+
if (descriptor?.exportFormatter) formatted = descriptor.exportFormatter(raw, rowAccessor);
|
|
239
|
+
else if (descriptor && ("type" in descriptor || "serverDataType" in descriptor)) {
|
|
240
|
+
const tableFormatter = getValueFormatter(descriptor);
|
|
241
|
+
formatted = tableFormatter(raw);
|
|
242
|
+
} else formatted = raw;
|
|
243
|
+
return csvCell(formatted);
|
|
244
|
+
}).join(","));
|
|
245
|
+
}
|
|
199
246
|
}
|
|
200
247
|
triggerCsvDownload(lines.join("\r\n"), filename);
|
|
201
248
|
onSuccess?.();
|
|
@@ -213,9 +260,9 @@ const exportSessionTableToCsv = async (dataSource, options = {})=>{
|
|
|
213
260
|
};
|
|
214
261
|
activeSessionDataSource.subscribe({
|
|
215
262
|
range: Range(0, 0),
|
|
216
|
-
columns:
|
|
263
|
+
columns: sessionOverrides?.columns
|
|
217
264
|
}, handleMessage);
|
|
218
265
|
});
|
|
219
266
|
};
|
|
220
267
|
const exportToCsv = async (dataSource, options)=>exportSessionTableToCsv(dataSource, options);
|
|
221
|
-
export { exportCsvTemplate, exportSessionTableToCsv, exportToCsv };
|
|
268
|
+
export { exportCsvTemplate, exportSessionTableToCsv, exportToCsv, isExportableColumn };
|
package/src/csv-export/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { exportCsvTemplate, exportSessionTableToCsv, exportToCsv } from "./export-utils.js";
|
|
1
|
+
export { exportCsvTemplate, exportSessionTableToCsv, exportToCsv, isExportableColumn } from "./export-utils.js";
|
|
2
2
|
export { useCsvExport } from "./useCsvExport.js";
|
|
@@ -6,7 +6,7 @@ function useCsvExport(propsOrDataSource) {
|
|
|
6
6
|
const config = propsOrDataSource && "table" in propsOrDataSource ? {
|
|
7
7
|
dataSource: propsOrDataSource
|
|
8
8
|
} : propsOrDataSource ?? {};
|
|
9
|
-
const { dataSource: defaultDataSource, onError, onSuccess } = config;
|
|
9
|
+
const { dataSource: defaultDataSource, tableConfig, columns: defaultColumns, onError, onSuccess } = config;
|
|
10
10
|
const exportCsv = useCallback(async (options, overrideDataSource)=>{
|
|
11
11
|
const activeDataSource = overrideDataSource ?? defaultDataSource;
|
|
12
12
|
if (!activeDataSource) {
|
|
@@ -19,7 +19,9 @@ function useCsvExport(propsOrDataSource) {
|
|
|
19
19
|
setIsExporting(true);
|
|
20
20
|
setError(null);
|
|
21
21
|
try {
|
|
22
|
+
const columnsToExport = options?.columns ?? options?.columnDescriptors ?? defaultColumns ?? tableConfig?.columns;
|
|
22
23
|
await exportToCsv(activeDataSource, {
|
|
24
|
+
columns: columnsToExport,
|
|
23
25
|
...options,
|
|
24
26
|
onError: (err)=>{
|
|
25
27
|
setError(err);
|
|
@@ -42,6 +44,8 @@ function useCsvExport(propsOrDataSource) {
|
|
|
42
44
|
}
|
|
43
45
|
}, [
|
|
44
46
|
defaultDataSource,
|
|
47
|
+
defaultColumns,
|
|
48
|
+
tableConfig,
|
|
45
49
|
onError,
|
|
46
50
|
onSuccess
|
|
47
51
|
]);
|
|
@@ -57,7 +61,9 @@ function useCsvExport(propsOrDataSource) {
|
|
|
57
61
|
setIsExporting(true);
|
|
58
62
|
setError(null);
|
|
59
63
|
try {
|
|
64
|
+
const templateColumns = options?.columns ?? defaultColumns ?? tableConfig?.columns;
|
|
60
65
|
await exportCsvTemplate(activeDataSource, {
|
|
66
|
+
columns: templateColumns,
|
|
61
67
|
...options,
|
|
62
68
|
onError: (err)=>{
|
|
63
69
|
setError(err);
|
|
@@ -80,6 +86,8 @@ function useCsvExport(propsOrDataSource) {
|
|
|
80
86
|
}
|
|
81
87
|
}, [
|
|
82
88
|
defaultDataSource,
|
|
89
|
+
defaultColumns,
|
|
90
|
+
tableConfig,
|
|
83
91
|
onError,
|
|
84
92
|
onSuccess
|
|
85
93
|
]);
|
|
@@ -4,10 +4,10 @@ import { useComponentCssInjection } from "@salt-ds/styles";
|
|
|
4
4
|
import { useWindow } from "@salt-ds/window";
|
|
5
5
|
import TableFooter from "./TableFooter.css";
|
|
6
6
|
const classBase = "vuuTableFooter";
|
|
7
|
-
const TableFooterTray = ({ children, position =
|
|
7
|
+
const TableFooterTray = ({ children, position = "end" })=>/*#__PURE__*/ jsx("div", {
|
|
8
8
|
className: clsx(`${classBase}Tray`, {
|
|
9
|
-
[`${classBase}Tray-center`]:
|
|
10
|
-
[`${classBase}Tray-end`]:
|
|
9
|
+
[`${classBase}Tray-center`]: "center" === position,
|
|
10
|
+
[`${classBase}Tray-end`]: "end" === position
|
|
11
11
|
}),
|
|
12
12
|
children: children
|
|
13
13
|
});
|
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
import type { CopyOption, DataSource, SessionDataSourceOverrides } from "@vuu-ui/vuu-data-types";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import type { ColumnDescriptor, RowAccessor } from "@vuu-ui/vuu-table-types";
|
|
3
|
+
export type { RowAccessor };
|
|
4
|
+
export type ExportServerColumnDescriptor = Omit<ColumnDescriptor, "source" | "exportFormatter"> & {
|
|
5
|
+
name: string;
|
|
6
|
+
source?: "server";
|
|
5
7
|
label?: string;
|
|
6
|
-
|
|
8
|
+
exportable?: boolean;
|
|
9
|
+
exportFormatter?: (value: unknown, row: RowAccessor) => string;
|
|
7
10
|
};
|
|
8
|
-
export
|
|
11
|
+
export type ExportClientColumnDescriptor = Omit<ColumnDescriptor, "source" | "exportFormatter"> & {
|
|
12
|
+
name: string;
|
|
13
|
+
source: "client";
|
|
14
|
+
label?: string;
|
|
15
|
+
exportable?: boolean;
|
|
16
|
+
exportFormatter: (value: unknown, row: RowAccessor) => string;
|
|
17
|
+
};
|
|
18
|
+
export type ExportColumnDescriptor = ExportServerColumnDescriptor | ExportClientColumnDescriptor;
|
|
19
|
+
export interface ExportToCsvOptions {
|
|
9
20
|
filename?: string;
|
|
10
21
|
copyOption?: CopyOption;
|
|
11
22
|
excludeColumns?: string[];
|
|
12
23
|
maxRows?: number;
|
|
13
|
-
columnDescriptors?: ExportColumnDescriptor
|
|
24
|
+
columnDescriptors?: readonly (ExportColumnDescriptor | ColumnDescriptor)[];
|
|
25
|
+
columns?: readonly (string | ExportColumnDescriptor | ColumnDescriptor)[];
|
|
14
26
|
overrides?: SessionDataSourceOverrides;
|
|
15
27
|
/** Timeout in milliseconds before the export times out. Default: 30_000ms (0 to disable). */
|
|
16
28
|
timeout?: number;
|
|
@@ -20,13 +32,14 @@ export interface ExportToCsvOptions<TName extends string = string> {
|
|
|
20
32
|
export interface ExportCsvTemplateOptions {
|
|
21
33
|
filename?: string;
|
|
22
34
|
excludeColumns?: string[];
|
|
23
|
-
columns?: string[];
|
|
35
|
+
columns?: readonly (string | ColumnDescriptor)[];
|
|
24
36
|
overrides?: SessionDataSourceOverrides;
|
|
25
37
|
/** Timeout in milliseconds before template generation times out. Default: 10_000ms (0 to disable). */
|
|
26
38
|
timeout?: number;
|
|
27
39
|
onError?: (error: Error) => void;
|
|
28
40
|
onSuccess?: () => void;
|
|
29
41
|
}
|
|
42
|
+
export declare const isExportableColumn: (descriptor?: ExportColumnDescriptor | ColumnDescriptor) => boolean;
|
|
30
43
|
/** Downloads a single-row CSV containing only the column headers, for use as an import template. */
|
|
31
44
|
export declare const exportCsvTemplate: (dataSource: DataSource, options?: ExportCsvTemplateOptions) => Promise<void>;
|
|
32
45
|
/**
|
|
@@ -35,8 +48,8 @@ export declare const exportCsvTemplate: (dataSource: DataSource, options?: Expor
|
|
|
35
48
|
* then triggers a browser download. The session data source is unsubscribed automatically once the download
|
|
36
49
|
* is initiated.
|
|
37
50
|
*/
|
|
38
|
-
export declare const exportSessionTableToCsv:
|
|
51
|
+
export declare const exportSessionTableToCsv: (dataSource: DataSource, options?: ExportToCsvOptions) => Promise<void>;
|
|
39
52
|
/**
|
|
40
53
|
* Creates an export session table from `dataSource`, collects all rows in memory, then triggers a CSV download.
|
|
41
54
|
*/
|
|
42
|
-
export declare const exportToCsv:
|
|
55
|
+
export declare const exportToCsv: (dataSource: DataSource, options?: ExportToCsvOptions) => Promise<void>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { exportCsvTemplate, exportSessionTableToCsv, exportToCsv, type ExportColumnDescriptor, type ExportCsvTemplateOptions, type ExportToCsvOptions, } from "./export-utils";
|
|
1
|
+
export { exportCsvTemplate, exportSessionTableToCsv, exportToCsv, isExportableColumn, type ExportClientColumnDescriptor, type ExportColumnDescriptor, type ExportCsvTemplateOptions, type ExportServerColumnDescriptor, type ExportToCsvOptions, type RowAccessor, } from "./export-utils";
|
|
2
2
|
export { useCsvExport, type UseCsvExportProps, type UseCsvExportResult, } from "./useCsvExport";
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import type { DataSource } from "@vuu-ui/vuu-data-types";
|
|
2
|
-
import {
|
|
2
|
+
import type { ColumnDescriptor, TableConfig } from "@vuu-ui/vuu-table-types";
|
|
3
|
+
import { type ExportColumnDescriptor, type ExportCsvTemplateOptions, type ExportToCsvOptions } from "./export-utils";
|
|
3
4
|
export interface UseCsvExportProps {
|
|
4
5
|
dataSource?: DataSource;
|
|
6
|
+
tableConfig?: TableConfig;
|
|
7
|
+
columns?: readonly (string | ExportColumnDescriptor | ColumnDescriptor)[];
|
|
5
8
|
onError?: (error: Error) => void;
|
|
6
9
|
onSuccess?: () => void;
|
|
7
10
|
}
|
|
8
11
|
export interface UseCsvExportResult {
|
|
9
12
|
isExporting: boolean;
|
|
10
13
|
error: Error | null;
|
|
11
|
-
exportCsv:
|
|
14
|
+
exportCsv: (options?: ExportToCsvOptions, overrideDataSource?: DataSource) => Promise<void>;
|
|
12
15
|
exportTemplate: (options?: ExportCsvTemplateOptions, overrideDataSource?: DataSource) => Promise<void>;
|
|
13
16
|
}
|
|
14
17
|
export declare function useCsvExport(propsOrDataSource?: DataSource | UseCsvExportProps): UseCsvExportResult;
|
|
@@ -16,7 +16,8 @@ export declare const useInlineAddRow: ({ columns }: UseInlineAddRowProps) => {
|
|
|
16
16
|
allowColumnHeaderMenu?: false;
|
|
17
17
|
colHeaderContentRenderer?: string;
|
|
18
18
|
colHeaderLabelRenderer?: string;
|
|
19
|
-
|
|
19
|
+
exportable?: boolean;
|
|
20
|
+
exportFormatter?: (value: unknown, row: import("@vuu-ui/vuu-table-types").RowAccessor) => string;
|
|
20
21
|
getIcon?: (row: DataRow) => string | undefined;
|
|
21
22
|
groupable?: boolean;
|
|
22
23
|
hidden?: boolean;
|
|
@@ -3,8 +3,8 @@ export interface TableFooterProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
3
3
|
onInvokeAction?: (action: string) => void;
|
|
4
4
|
tooltrayActions?: ReactNode;
|
|
5
5
|
}
|
|
6
|
-
export declare const TableFooterTray: ({ children, position }: {
|
|
6
|
+
export declare const TableFooterTray: ({ children, position, }: {
|
|
7
7
|
children: ReactNode;
|
|
8
|
-
position?:
|
|
8
|
+
position?: "center" | "end";
|
|
9
9
|
}) => import("react").JSX.Element;
|
|
10
10
|
export declare const TableFooter: ({ children, className, onInvokeAction, tooltrayActions, ...htmlAttributes }: TableFooterProps) => import("react").JSX.Element;
|