@firecms/data_import_export 3.0.0-canary.2 → 3.0.0-canary.200

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