@firecms/data_import_export 3.0.0-canary.19 → 3.0.0-canary.191

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