@firecms/data_import_export 3.0.0-canary.80 → 3.0.0-canary.82

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.
Files changed (50) hide show
  1. package/LICENSE +2 -1
  2. package/dist/index.d.ts +2 -5
  3. package/dist/index.es.js +12 -1364
  4. package/dist/index.es.js.map +1 -1
  5. package/dist/index.umd.js +29 -2
  6. package/dist/index.umd.js.map +1 -1
  7. package/dist/useImportExportPlugin.d.ts +5 -3
  8. package/package.json +5 -7
  9. package/src/index.ts +2 -5
  10. package/src/useImportExportPlugin.tsx +9 -5
  11. package/dist/components/DataNewPropertiesMapping.d.ts +0 -13
  12. package/dist/components/ImportFileUpload.d.ts +0 -3
  13. package/dist/components/ImportNewPropertyFieldPreview.d.ts +0 -10
  14. package/dist/components/ImportSaveInProgress.d.ts +0 -8
  15. package/dist/components/index.d.ts +0 -4
  16. package/dist/export_import/BasicExportAction.d.ts +0 -7
  17. package/dist/export_import/ExportCollectionAction.d.ts +0 -11
  18. package/dist/export_import/ImportCollectionAction.d.ts +0 -15
  19. package/dist/export_import/export.d.ts +0 -21
  20. package/dist/export_import/index.d.ts +0 -4
  21. package/dist/hooks/index.d.ts +0 -1
  22. package/dist/hooks/useImportConfig.d.ts +0 -2
  23. package/dist/types/column_mapping.d.ts +0 -20
  24. package/dist/types/index.d.ts +0 -1
  25. package/dist/utils/data.d.ts +0 -4
  26. package/dist/utils/file_headers.d.ts +0 -1
  27. package/dist/utils/file_to_json.d.ts +0 -16
  28. package/dist/utils/get_import_inference_type.d.ts +0 -2
  29. package/dist/utils/get_properties_mapping.d.ts +0 -0
  30. package/dist/utils/index.d.ts +0 -3
  31. package/src/components/DataNewPropertiesMapping.tsx +0 -241
  32. package/src/components/ImportFileUpload.tsx +0 -42
  33. package/src/components/ImportNewPropertyFieldPreview.tsx +0 -60
  34. package/src/components/ImportSaveInProgress.tsx +0 -122
  35. package/src/components/index.ts +0 -4
  36. package/src/export_import/BasicExportAction.tsx +0 -147
  37. package/src/export_import/ExportCollectionAction.tsx +0 -288
  38. package/src/export_import/ImportCollectionAction.tsx +0 -442
  39. package/src/export_import/export.ts +0 -234
  40. package/src/export_import/index.ts +0 -4
  41. package/src/hooks/index.ts +0 -1
  42. package/src/hooks/useImportConfig.tsx +0 -34
  43. package/src/types/column_mapping.ts +0 -32
  44. package/src/types/index.ts +0 -1
  45. package/src/utils/data.ts +0 -133
  46. package/src/utils/file_headers.ts +0 -90
  47. package/src/utils/file_to_json.ts +0 -106
  48. package/src/utils/get_import_inference_type.ts +0 -27
  49. package/src/utils/get_properties_mapping.ts +0 -63
  50. package/src/utils/index.ts +0 -3
@@ -1,442 +0,0 @@
1
- import React, { useCallback, useEffect } from "react";
2
- import {
3
- CollectionActionsProps,
4
- EntityCollectionTable,
5
- getFieldConfig,
6
- getPropertiesWithPropertiesOrder,
7
- getPropertyInPath,
8
- PropertiesOrBuilders,
9
- Property,
10
- PropertyConfigBadge,
11
- resolveCollection,
12
- ResolvedProperties,
13
- slugify,
14
- useCustomizationController,
15
- User,
16
- useSelectionController,
17
- useSnackbarController
18
- } from "@firecms/core";
19
- import {
20
- Button,
21
- cls,
22
- defaultBorderMixin,
23
- Dialog,
24
- DialogActions,
25
- DialogContent,
26
- FileUploadIcon,
27
- IconButton,
28
- Select,
29
- SelectItem,
30
- Tooltip,
31
- Typography,
32
- } from "@firecms/ui";
33
- import { buildEntityPropertiesFromData } from "@firecms/schema_inference";
34
- import { useImportConfig } from "../hooks";
35
- import { convertDataToEntity, getInferenceType } from "../utils";
36
- import { DataNewPropertiesMapping, ImportFileUpload, ImportSaveInProgress } from "../components";
37
- import { ImportConfig } from "../types";
38
-
39
- type ImportState = "initial" | "mapping" | "preview" | "import_data_saving";
40
-
41
- export function ImportCollectionAction<M extends Record<string, any>, UserType extends User>({
42
- collection,
43
- path,
44
- collectionEntitiesCount,
45
- onAnalyticsEvent
46
- }: CollectionActionsProps<M, UserType> & {
47
- onAnalyticsEvent?: (event: string, params?: any) => void;
48
- }
49
- ) {
50
-
51
- const customizationController = useCustomizationController();
52
-
53
- const snackbarController = useSnackbarController();
54
-
55
- const [open, setOpen] = React.useState(false);
56
-
57
- const [step, setStep] = React.useState<ImportState>("initial");
58
-
59
- const importConfig = useImportConfig();
60
-
61
- const handleClickOpen = useCallback(() => {
62
- setOpen(true);
63
- onAnalyticsEvent?.("import_open");
64
- setStep("initial");
65
- }, [onAnalyticsEvent]);
66
-
67
- const handleClose = useCallback(() => {
68
- setOpen(false);
69
- }, [setOpen]);
70
-
71
- const onMappingComplete = useCallback(() => {
72
- onAnalyticsEvent?.("import_mapping_complete");
73
- setStep("preview");
74
- }, [onAnalyticsEvent]);
75
-
76
- const onPreviewComplete = useCallback(() => {
77
- onAnalyticsEvent?.("import_data_save");
78
- setStep("import_data_saving");
79
- }, [onAnalyticsEvent]);
80
-
81
- const onDataAdded = async (data: object[]) => {
82
- importConfig.setImportData(data);
83
-
84
- if (data.length > 0) {
85
- const originProperties = await buildEntityPropertiesFromData(data, getInferenceType);
86
- importConfig.setOriginProperties(originProperties);
87
-
88
- const headersMapping = buildHeadersMappingFromData(data, collection?.properties);
89
- importConfig.setHeadersMapping(headersMapping);
90
- const firstKey = Object.keys(headersMapping)?.[0];
91
- if (firstKey?.includes("id") || firstKey?.includes("key")) {
92
- importConfig.setIdColumn(firstKey);
93
- }
94
- }
95
- setTimeout(() => {
96
- onAnalyticsEvent?.("import_data_added");
97
- setStep("mapping");
98
- }, 100);
99
- // setStep("mapping");
100
- };
101
-
102
- const resolvedCollection = resolveCollection({
103
- collection,
104
- path,
105
- fields: customizationController.propertyConfigs
106
- });
107
-
108
- const properties = getPropertiesWithPropertiesOrder<M>(resolvedCollection.properties, resolvedCollection.propertiesOrder as Extract<keyof M, string>[]) as ResolvedProperties<M>;
109
-
110
- const propertiesAndLevel = Object.entries(properties)
111
- .flatMap(([key, property]) => getPropertiesAndLevel(key, property, 0));
112
- const propertiesOrder = (resolvedCollection.propertiesOrder ?? Object.keys(resolvedCollection.properties)) as Extract<keyof M, string>[];
113
- if (collection.collectionGroup) {
114
- return null;
115
- }
116
-
117
- return <>
118
-
119
- <Tooltip title={"Import"}>
120
- <IconButton color={"primary"} onClick={handleClickOpen}>
121
- <FileUploadIcon/>
122
- </IconButton>
123
- </Tooltip>
124
-
125
- <Dialog open={open}
126
- fullWidth={step === "preview"}
127
- fullHeight={step === "preview"}
128
- maxWidth={step === "initial" ? "lg" : "7xl"}>
129
- <DialogContent className={"flex flex-col gap-4 my-4"} fullHeight={step === "preview"}>
130
-
131
- {step === "initial" && <>
132
- <Typography variant={"h6"}>Import data</Typography>
133
- <Typography variant={"body2"}>Upload a CSV, Excel or JSON file and map it to your existing
134
- schema</Typography>
135
- <ImportFileUpload onDataAdded={onDataAdded}/>
136
- </>}
137
-
138
- {step === "mapping" && <>
139
- <Typography variant={"h6"} className={"ml-3.5"}>Map fields</Typography>
140
- <DataNewPropertiesMapping importConfig={importConfig}
141
- destinationProperties={properties}
142
- buildPropertyView={({
143
- isIdColumn,
144
- property,
145
- propertyKey,
146
- importKey,
147
- }) => {
148
- return <PropertyTreeSelect
149
- selectedPropertyKey={propertyKey ?? ""}
150
- properties={properties}
151
- propertiesAndLevel={propertiesAndLevel}
152
- isIdColumn={isIdColumn}
153
- onIdSelected={() => {
154
- importConfig.setIdColumn(importKey);
155
- }}
156
- onPropertySelected={(newPropertyKey) => {
157
-
158
- onAnalyticsEvent?.("import_mapping_field_updated");
159
- const newHeadersMapping: Record<string, string | null> = Object.entries(importConfig.headersMapping)
160
- .map(([currentImportKey, currentPropertyKey]) => {
161
- if (currentPropertyKey === newPropertyKey) {
162
- return { [currentImportKey]: null };
163
- }
164
- if (currentImportKey === importKey) {
165
- return { [currentImportKey]: newPropertyKey };
166
- }
167
- return { [currentImportKey]: currentPropertyKey };
168
- })
169
- .reduce((acc, curr) => ({ ...acc, ...curr }), {});
170
- importConfig.setHeadersMapping(newHeadersMapping as Record<string, string>);
171
-
172
- if (newPropertyKey === importConfig.idColumn) {
173
- importConfig.setIdColumn(undefined);
174
- }
175
-
176
- }}
177
- />;
178
- }}/>
179
- </>}
180
-
181
- {step === "preview" && <ImportDataPreview importConfig={importConfig}
182
- properties={properties}
183
- propertiesOrder={propertiesOrder}/>}
184
-
185
- {step === "import_data_saving" && importConfig &&
186
- <ImportSaveInProgress importConfig={importConfig}
187
- collection={collection}
188
- path={path}
189
- onImportSuccess={(importedCollection) => {
190
- handleClose();
191
- snackbarController.open({
192
- type: "info",
193
- message: "Data imported successfully"
194
- });
195
- }}
196
- />}
197
-
198
- </DialogContent>
199
- <DialogActions>
200
-
201
- {step === "mapping" && <Button onClick={() => setStep("initial")}
202
- variant={"text"}>
203
- Back
204
- </Button>}
205
-
206
- {step === "preview" && <Button onClick={() => setStep("mapping")}
207
- variant={"text"}>
208
- Back
209
- </Button>}
210
-
211
- <Button onClick={handleClose}
212
- variant={"text"}>
213
- Cancel
214
- </Button>
215
-
216
- {step === "mapping" && <Button variant="filled"
217
- onClick={onMappingComplete}>
218
- Next
219
- </Button>}
220
-
221
- {step === "preview" && <Button variant="filled"
222
- onClick={onPreviewComplete}>
223
- Save data
224
- </Button>}
225
-
226
- </DialogActions>
227
- </Dialog>
228
-
229
- </>;
230
- }
231
-
232
- const internalIDValue = "__internal_id__";
233
-
234
- function PropertyTreeSelect({
235
- selectedPropertyKey,
236
- properties,
237
- onPropertySelected,
238
- onIdSelected,
239
- propertiesAndLevel,
240
- isIdColumn
241
- }: {
242
- selectedPropertyKey: string | null;
243
- properties: Record<string, Property>;
244
- onPropertySelected: (propertyKey: string | null) => void;
245
- onIdSelected: () => void;
246
- propertiesAndLevel: PropertyAndLevel[];
247
- isIdColumn?: boolean;
248
- }) {
249
-
250
- const selectedProperty = selectedPropertyKey ? getPropertyInPath(properties, selectedPropertyKey) : null;
251
-
252
- const renderValue = useCallback((selectedPropertyKey: string) => {
253
-
254
- if (selectedPropertyKey === internalIDValue) {
255
- return <Typography variant={"body2"} className={"p-4"}>Use this column as ID</Typography>;
256
- }
257
-
258
- if (!selectedPropertyKey || !selectedProperty) {
259
- return <Typography variant={"body2"} color="disabled" className={"p-4"}>Do not import this
260
- property</Typography>;
261
- }
262
-
263
- return <PropertySelectEntry propertyKey={selectedPropertyKey}
264
- property={selectedProperty as Property}/>;
265
- }, [selectedProperty]);
266
-
267
- const onSelectValueChange = (value: string) => {
268
- if (value === internalIDValue) {
269
- onIdSelected();
270
- onPropertySelected(null);
271
- } else if (value === "__do_not_import") {
272
- onPropertySelected(null);
273
- } else {
274
- onPropertySelected(value);
275
- }
276
- };
277
-
278
- return <Select value={isIdColumn ? internalIDValue : (selectedPropertyKey ?? undefined)}
279
- onValueChange={onSelectValueChange}
280
- renderValue={renderValue}>
281
-
282
- <SelectItem value={"__do_not_import"}>
283
- <Typography variant={"body2"} color={"disabled"} className={"p-4"}>Do not import this property</Typography>
284
- </SelectItem>
285
-
286
- <SelectItem value={internalIDValue}>
287
- <Typography variant={"body2"} className={"p-4"}>Use this column as ID</Typography>
288
- </SelectItem>
289
-
290
- {propertiesAndLevel.map(({
291
- property,
292
- level,
293
- propertyKey
294
- }) => {
295
- return <SelectItem value={propertyKey}
296
- key={propertyKey}
297
- disabled={property.dataType === "map"}>
298
- <PropertySelectEntry propertyKey={propertyKey}
299
- property={property}
300
- level={level}/>
301
- </SelectItem>;
302
- })}
303
-
304
- </Select>;
305
- }
306
-
307
- type PropertyAndLevel = {
308
- property: Property,
309
- level: number,
310
- propertyKey: string
311
- };
312
-
313
- function getPropertiesAndLevel(key: string, property: Property, level: number): PropertyAndLevel[] {
314
- const properties: PropertyAndLevel[] = [];
315
- properties.push({
316
- property,
317
- level,
318
- propertyKey: key
319
- });
320
- if (property.dataType === "map" && property.properties) {
321
- Object.entries(property.properties).forEach(([childKey, value]) => {
322
- properties.push(...getPropertiesAndLevel(`${key}.${childKey}`, value as Property, level + 1));
323
- });
324
- }
325
- return properties;
326
- }
327
-
328
- export function PropertySelectEntry({
329
- propertyKey,
330
- property,
331
- level = 0
332
- }: {
333
- propertyKey: string;
334
- property: Property;
335
- level?: number;
336
- }) {
337
-
338
- const { propertyConfigs } = useCustomizationController();
339
- const widget = getFieldConfig(property, propertyConfigs);
340
-
341
- return <div
342
- className="flex flex-row w-full text-start items-center h-full">
343
-
344
- {new Array(level).fill(0).map((_, index) =>
345
- <div className={cls(defaultBorderMixin, "ml-8 border-l h-12")} key={index}/>)}
346
-
347
- <div className={"m-4"}>
348
- <Tooltip title={widget?.name}>
349
- <PropertyConfigBadge propertyConfig={widget}/>
350
- </Tooltip>
351
- </div>
352
-
353
- <div className={"flex flex-col flex-grow p-2 pl-2"}>
354
- <Typography variant="body1"
355
- component="span"
356
- className="flex-grow pr-2">
357
- {property.name
358
- ? property.name
359
- : "\u00a0"
360
- }
361
- </Typography>
362
-
363
- <Typography className=" pr-2"
364
- variant={"body2"}
365
- component="span"
366
- color="secondary">
367
- {propertyKey}
368
- </Typography>
369
- </div>
370
-
371
- </div>;
372
-
373
- }
374
-
375
- export function ImportDataPreview<M extends Record<string, any>>({
376
- importConfig,
377
- properties,
378
- propertiesOrder
379
- }: {
380
- importConfig: ImportConfig,
381
- properties: ResolvedProperties<M>,
382
- propertiesOrder: Extract<keyof M, string>[],
383
- }) {
384
-
385
- useEffect(() => {
386
- const mappedData = importConfig.importData.map(d => convertDataToEntity(d, importConfig.idColumn, importConfig.headersMapping, properties, "TEMP_PATH", importConfig.defaultValues));
387
- importConfig.setEntities(mappedData);
388
- }, []);
389
-
390
- const selectionController = useSelectionController();
391
-
392
- return <EntityCollectionTable
393
- title={<div>
394
- <Typography variant={"subtitle2"}>Imported data preview</Typography>
395
- <Typography variant={"caption"}>Entities with the same id will be overwritten</Typography>
396
- </div>}
397
- tableController={{
398
- data: importConfig.entities,
399
- dataLoading: false,
400
- noMoreToLoad: false
401
- }}
402
- enablePopupIcon={false}
403
- endAdornment={<div className={"h-12"}/>}
404
- filterable={false}
405
- sortable={false}
406
- selectionController={selectionController}
407
- properties={properties}/>
408
-
409
- }
410
-
411
- function buildHeadersMappingFromData(objArr: object[], properties?: PropertiesOrBuilders<any>) {
412
- const headersMapping: Record<string, string> = {};
413
- objArr.filter(Boolean).forEach((obj) => {
414
- Object.keys(obj).forEach((key) => {
415
- // @ts-ignore
416
- const child = obj[key];
417
- if (typeof child === "object" && !Array.isArray(child)) {
418
- const childProperty = properties?.[key];
419
- const childProperties = childProperty && "properties" in childProperty ? childProperty.properties : undefined;
420
- const childHeadersMapping = buildHeadersMappingFromData([child], childProperties);
421
- Object.entries(childHeadersMapping).forEach(([subKey, mapping]) => {
422
- headersMapping[`${key}.${subKey}`] = `${key}.${mapping}`;
423
- });
424
- }
425
-
426
- if (!properties) {
427
- headersMapping[key] = key;
428
- } else if (key in properties) {
429
- headersMapping[key] = key;
430
- } else {
431
- const slug = slugify(key);
432
- if (slug in properties) {
433
- headersMapping[key] = slug;
434
- } else {
435
- headersMapping[key] = key;
436
- }
437
- }
438
-
439
- });
440
- });
441
- return headersMapping;
442
- }
@@ -1,234 +0,0 @@
1
- import {
2
- ArrayValuesCount,
3
- Entity,
4
- EntityReference,
5
- getArrayValuesCount,
6
- getValueInPath,
7
- ResolvedProperties,
8
- ResolvedProperty
9
- } from "@firecms/core";
10
-
11
- interface Header {
12
- key: string;
13
- label: string;
14
- }
15
-
16
- export interface DownloadEntitiesExportParams<M extends Record<string, any>> {
17
- data: Entity<M>[];
18
- additionalData: Record<string, any>[] | undefined;
19
- properties: ResolvedProperties<M>;
20
- propertiesOrder: string[] | undefined;
21
- name: string;
22
- flattenArrays: boolean;
23
- additionalHeaders: string[] | undefined;
24
- exportType: "csv" | "json";
25
- dateExportType: "timestamp" | "string";
26
- }
27
-
28
- export function downloadEntitiesExport<M extends Record<string, any>>({
29
- data,
30
- additionalData,
31
- properties,
32
- propertiesOrder,
33
- name,
34
- flattenArrays,
35
- additionalHeaders,
36
- exportType,
37
- dateExportType
38
- }: DownloadEntitiesExportParams<M>
39
- ) {
40
-
41
- console.debug("Downloading export", {
42
- dataLength: data.length,
43
- properties,
44
- exportType,
45
- dateExportType
46
- });
47
-
48
- if (exportType === "csv") {
49
- const arrayValuesCount = flattenArrays ? getArrayValuesCount(data.map(d => d.values)) : {};
50
- const headers = getExportHeaders(properties, propertiesOrder, additionalHeaders, arrayValuesCount);
51
- const exportableData = getEntityCSVExportableData(data, additionalData, properties, headers, dateExportType);
52
- const headersData = entryToCSVRow(headers.map(h => h.label));
53
- const csvData = exportableData.map(entry => entryToCSVRow(entry));
54
- downloadBlob([headersData, ...csvData], `${name}.csv`, "text/csv");
55
- } else {
56
- const exportableData = getEntityJsonExportableData(data, additionalData, properties, dateExportType);
57
- const json = JSON.stringify(exportableData, null, 2);
58
- downloadBlob([json], `${name}.json`, "application/json");
59
- }
60
- }
61
-
62
- export function getEntityCSVExportableData(data: Entity<any>[],
63
- additionalData: Record<string, any>[] | undefined,
64
- properties: ResolvedProperties,
65
- headers: Header[],
66
- dateExportType: "timestamp" | "string"
67
- ) {
68
-
69
- const mergedData: any[] = data.map(e => ({
70
- id: e.id,
71
- ...processValuesForExport(e.values, properties, "csv", dateExportType)
72
- }));
73
-
74
- if (additionalData) {
75
- additionalData.forEach((additional, index) => {
76
- mergedData[index] = { ...mergedData[index], ...additional };
77
- });
78
- }
79
-
80
- return mergedData && mergedData.map((entry) => {
81
- return headers.map((header) => getValueInPath(entry, header.key));
82
- });
83
- }
84
-
85
- export function getEntityJsonExportableData(data: Entity<any>[],
86
- additionalData: Record<string, any>[] | undefined,
87
- properties: ResolvedProperties,
88
- dateExportType: "timestamp" | "string"
89
- ) {
90
-
91
- const mergedData: any[] = data.map(e => ({
92
- id: e.id,
93
- ...processValuesForExport(e.values, properties, "json", dateExportType)
94
- }));
95
-
96
- if (additionalData) {
97
- additionalData.forEach((additional, index) => {
98
- mergedData[index] = { ...mergedData[index], ...additional };
99
- });
100
- }
101
-
102
- return mergedData;
103
- }
104
-
105
- function getExportHeaders<M extends Record<string, any>>(properties: ResolvedProperties<M>,
106
- propertiesOrder: string[] | undefined,
107
- additionalHeaders: string[] | undefined,
108
- arrayValuesCount?: ArrayValuesCount): Header[] {
109
-
110
- const headers: Header[] = [
111
- {
112
- label: "id",
113
- key: "id"
114
- },
115
- ...(propertiesOrder ?? Object.keys(properties))
116
- .flatMap((childKey) => {
117
- const property = properties[childKey];
118
- if (!property) {
119
- console.warn("Property not found", childKey, properties);
120
- return [];
121
- }
122
- if (arrayValuesCount && arrayValuesCount[childKey] > 1) {
123
- return Array.from({ length: arrayValuesCount[childKey] },
124
- (_, i) => getHeaders(property as ResolvedProperty, `${childKey}[${i}]`, ""))
125
- .flat();
126
- } else {
127
- return getHeaders(property as ResolvedProperty, childKey, "");
128
- }
129
- })
130
- ];
131
-
132
- if (additionalHeaders) {
133
- headers.push(...additionalHeaders.map(h => ({
134
- label: h,
135
- key: h
136
- })));
137
- }
138
-
139
- return headers;
140
- }
141
-
142
- /**
143
- * Get headers for property. There could be more than one header per property
144
- * @param property
145
- * @param propertyKey
146
- * @param prefix
147
- */
148
- function getHeaders(property: ResolvedProperty, propertyKey: string, prefix = ""): Header[] {
149
- const currentKey = prefix ? `${prefix}.${propertyKey}` : propertyKey;
150
- if (property.dataType === "map" && property.properties) {
151
- return Object.entries(property.properties)
152
- .map(([childKey, p]) => getHeaders(p, childKey, currentKey))
153
- .flat();
154
- } else {
155
- return [{
156
- label: currentKey,
157
- key: currentKey
158
- }];
159
- }
160
- }
161
-
162
- function processValueForExport(inputValue: any,
163
- property: ResolvedProperty,
164
- exportType: "csv" | "json",
165
- dateExportType: "timestamp" | "string"
166
- ): any {
167
-
168
- let value;
169
- if (property.dataType === "map" && property.properties) {
170
- value = processValuesForExport(inputValue, property.properties as ResolvedProperties, exportType, dateExportType);
171
- } else if (property.dataType === "array") {
172
- if (property.of && Array.isArray(inputValue)) {
173
- if (Array.isArray(property.of)) {
174
- value = property.of.map((p, i) => processValueForExport(inputValue[i], p, exportType, dateExportType));
175
- } else if (property.of.dataType === "map") {
176
- value = exportType === "csv"
177
- ? inputValue.map((e) => JSON.stringify(e))
178
- : inputValue.map((e) => processValueForExport(e, property.of as ResolvedProperty, exportType, dateExportType));
179
- ;
180
- } else {
181
- value = inputValue.map((e) => processValueForExport(e, property.of as ResolvedProperty, exportType, dateExportType));
182
- }
183
- } else {
184
- value = inputValue;
185
- }
186
- } else if (property.dataType === "reference" && inputValue && inputValue.isEntityReference && inputValue.isEntityReference()) {
187
- const ref = inputValue ? inputValue as EntityReference : undefined;
188
- value = ref ? ref.pathWithId : null;
189
- } else if (property.dataType === "date" && inputValue instanceof Date) {
190
- value = inputValue ? (dateExportType === "timestamp" ? inputValue.getTime() : inputValue.toISOString()) : null;
191
- } else {
192
- value = inputValue;
193
- }
194
-
195
- return value;
196
- }
197
-
198
- function processValuesForExport<M extends Record<string, any>>
199
- (inputValues: Record<keyof M, any>,
200
- properties: ResolvedProperties<M>,
201
- exportType: "csv" | "json",
202
- dateExportType: "timestamp" | "string"
203
- ): Record<keyof M, any> {
204
- const updatedValues = Object.entries(properties)
205
- .map(([key, property]) => {
206
- const inputValue = inputValues && (inputValues)[key];
207
- const updatedValue = processValueForExport(inputValue, property as ResolvedProperty, exportType, dateExportType);
208
- if (updatedValue === undefined) return {};
209
- return ({ [key]: updatedValue });
210
- })
211
- .reduce((a, b) => ({ ...a, ...b }), {}) as Record<keyof M, any>;
212
- return { ...inputValues, ...updatedValues };
213
- }
214
-
215
- function entryToCSVRow(entry: any[]) {
216
- return entry
217
- .map((v: any) => {
218
- if (v === null || v === undefined) return "";
219
- if (Array.isArray(v))
220
- return "\"" + JSON.stringify(v).replaceAll("\"", "\\\"") + "\"";
221
- const s = String(v);
222
- return "\"" + s.replaceAll("\"", "\"\"") + "\"";
223
- })
224
- .join(",") + "\r\n";
225
- }
226
-
227
- export function downloadBlob(content: BlobPart[], filename: string, contentType: string) {
228
- const blob = new Blob(content, { type: contentType });
229
- const url = URL.createObjectURL(blob);
230
- const pom = document.createElement("a");
231
- pom.href = url;
232
- pom.setAttribute("download", filename);
233
- pom.click();
234
- }
@@ -1,4 +0,0 @@
1
- export * from "./export";
2
- export * from "./BasicExportAction";
3
- export * from "./ExportCollectionAction";
4
- export * from "./ImportCollectionAction";
@@ -1 +0,0 @@
1
- export * from "./useImportConfig";