@firecms/data_import_export 3.0.0-canary.5 → 3.0.0-canary.51

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 (40) hide show
  1. package/LICENSE +113 -21
  2. package/README.md +1 -1
  3. package/dist/components/DataNewPropertiesMapping.d.ts +3 -5
  4. package/dist/components/ImportFileUpload.d.ts +1 -1
  5. package/dist/export_import/BasicExportAction.d.ts +7 -0
  6. package/dist/export_import/ExportCollectionAction.d.ts +2 -1
  7. package/dist/export_import/ImportCollectionAction.d.ts +3 -1
  8. package/dist/export_import/export.d.ts +4 -4
  9. package/dist/export_import/index.d.ts +4 -0
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.es.js +901 -546
  12. package/dist/index.es.js.map +1 -1
  13. package/dist/index.umd.js +2 -2
  14. package/dist/index.umd.js.map +1 -1
  15. package/dist/types/column_mapping.d.ts +5 -7
  16. package/dist/useImportExportPlugin.d.ts +2 -1
  17. package/dist/utils/data.d.ts +3 -10
  18. package/dist/utils/file_headers.d.ts +1 -0
  19. package/dist/utils/file_to_json.d.ts +6 -1
  20. package/dist/utils/get_properties_mapping.d.ts +0 -3
  21. package/dist/utils/index.d.ts +0 -1
  22. package/package.json +20 -18
  23. package/src/components/DataNewPropertiesMapping.tsx +155 -41
  24. package/src/components/ImportFileUpload.tsx +12 -4
  25. package/src/components/ImportNewPropertyFieldPreview.tsx +7 -2
  26. package/src/components/ImportSaveInProgress.tsx +24 -2
  27. package/src/export_import/BasicExportAction.tsx +137 -0
  28. package/src/export_import/ExportCollectionAction.tsx +15 -7
  29. package/src/export_import/ImportCollectionAction.tsx +52 -31
  30. package/src/export_import/export.ts +50 -30
  31. package/src/export_import/index.ts +4 -0
  32. package/src/hooks/useImportConfig.tsx +6 -0
  33. package/src/index.ts +1 -0
  34. package/src/types/column_mapping.ts +6 -6
  35. package/src/useImportExportPlugin.tsx +4 -3
  36. package/src/utils/data.ts +50 -127
  37. package/src/utils/file_headers.ts +90 -0
  38. package/src/utils/file_to_json.ts +33 -15
  39. package/src/utils/get_properties_mapping.ts +63 -59
  40. package/src/utils/index.ts +0 -1
@@ -28,7 +28,7 @@ import {
28
28
  Tooltip,
29
29
  Typography,
30
30
  } from "@firecms/ui";
31
- import { downloadExport } from "./export";
31
+ import { downloadEntitiesExport } from "./export";
32
32
 
33
33
  const DOCS_LIMIT = 500;
34
34
 
@@ -36,11 +36,13 @@ export function ExportCollectionAction<M extends Record<string, any>, UserType e
36
36
  collection: inputCollection,
37
37
  path: inputPath,
38
38
  collectionEntitiesCount,
39
+ onAnalyticsEvent,
39
40
  exportAllowed,
40
41
  notAllowedView
41
42
  }: CollectionActionsProps<M, UserType, EntityCollection<M, any>> & {
42
43
  exportAllowed?: (props: { collectionEntitiesCount: number, path: string, collection: EntityCollection }) => boolean;
43
44
  notAllowedView?: React.ReactNode;
45
+ onAnalyticsEvent?: (event: string, params?: any) => void;
44
46
  }) {
45
47
 
46
48
  const customizationController = useCustomizationController();
@@ -122,6 +124,9 @@ export function ExportCollectionAction<M extends Record<string, any>, UserType e
122
124
  const doDownload = useCallback(async (collection: ResolvedEntityCollection<M>,
123
125
  exportConfig: ExportConfig<any> | undefined) => {
124
126
 
127
+ onAnalyticsEvent?.("export_collection", {
128
+ collection: collection.path
129
+ });
125
130
  setDataLoading(true);
126
131
  dataSource.fetchCollection<M>({
127
132
  path,
@@ -134,7 +139,10 @@ export function ExportCollectionAction<M extends Record<string, any>, UserType e
134
139
  ...exportConfig?.additionalFields?.map(column => column.key) ?? [],
135
140
  ...collection.additionalFields?.map(field => field.key) ?? []
136
141
  ];
137
- downloadExport(data, additionalData, collection, flattenArrays, additionalHeaders, exportType, dateExportType);
142
+ downloadEntitiesExport(data, additionalData, collection.properties, collection.propertiesOrder, collection.name, flattenArrays, additionalHeaders, exportType, dateExportType);
143
+ onAnalyticsEvent?.("export_collection_success", {
144
+ collection: collection.path
145
+ });
138
146
  })
139
147
  .catch((e) => {
140
148
  console.error("Error loading export data", e);
@@ -142,7 +150,7 @@ export function ExportCollectionAction<M extends Record<string, any>, UserType e
142
150
  })
143
151
  .finally(() => setDataLoading(false));
144
152
 
145
- }, [dataSource, path, fetchAdditionalFields, flattenArrays, exportType, dateExportType]);
153
+ }, [onAnalyticsEvent, dataSource, path, fetchAdditionalFields, flattenArrays, exportType, dateExportType]);
146
154
 
147
155
  const onOkClicked = useCallback(() => {
148
156
  doDownload(collection, exportConfig);
@@ -183,7 +191,7 @@ export function ExportCollectionAction<M extends Record<string, any>, UserType e
183
191
  onChange={() => setExportType("csv")}
184
192
  className={cn(focusedMixin, "w-4 text-primary-dark bg-gray-100 border-gray-300 dark:bg-gray-700 dark:border-gray-600")}/>
185
193
  <label htmlFor="radio-csv"
186
- className="p-2 text-sm font-medium text-gray-900 dark:text-gray-300">CSV</label>
194
+ className="p-2 text-sm font-medium text-gray-900 dark:text-slate-300">CSV</label>
187
195
  </div>
188
196
  <div className="flex items-center">
189
197
  <input id="radio-json" type="radio" value="json" name="exportType"
@@ -191,7 +199,7 @@ export function ExportCollectionAction<M extends Record<string, any>, UserType e
191
199
  onChange={() => setExportType("json")}
192
200
  className={cn(focusedMixin, "w-4 text-primary-dark bg-gray-100 border-gray-300 dark:bg-gray-700 dark:border-gray-600")}/>
193
201
  <label htmlFor="radio-json"
194
- className="p-2 text-sm font-medium text-gray-900 dark:text-gray-300">JSON</label>
202
+ className="p-2 text-sm font-medium text-gray-900 dark:text-slate-300">JSON</label>
195
203
  </div>
196
204
  </div>
197
205
 
@@ -202,7 +210,7 @@ export function ExportCollectionAction<M extends Record<string, any>, UserType e
202
210
  onChange={() => setDateExportType("timestamp")}
203
211
  className={cn(focusedMixin, "w-4 text-primary-dark bg-gray-100 border-gray-300 dark:bg-gray-700 dark:border-gray-600")}/>
204
212
  <label htmlFor="radio-timestamp"
205
- className="p-2 text-sm font-medium text-gray-900 dark:text-gray-300">Dates as
213
+ className="p-2 text-sm font-medium text-gray-900 dark:text-slate-300">Dates as
206
214
  timestamps ({dateRef.current.getTime()})</label>
207
215
  </div>
208
216
  <div className="flex items-center">
@@ -211,7 +219,7 @@ export function ExportCollectionAction<M extends Record<string, any>, UserType e
211
219
  onChange={() => setDateExportType("string")}
212
220
  className={cn(focusedMixin, "w-4 text-primary-dark bg-gray-100 border-gray-300 dark:bg-gray-700 dark:border-gray-600")}/>
213
221
  <label htmlFor="radio-string"
214
- className="p-2 text-sm font-medium text-gray-900 dark:text-gray-300">Dates as
222
+ className="p-2 text-sm font-medium text-gray-900 dark:text-slate-300">Dates as
215
223
  strings ({dateRef.current.toISOString()})</label>
216
224
  </div>
217
225
  </div>
@@ -2,13 +2,15 @@ import React, { useCallback, useEffect } from "react";
2
2
  import {
3
3
  CollectionActionsProps,
4
4
  EntityCollectionTable,
5
- PropertyConfigBadge,
6
5
  getFieldConfig,
7
6
  getPropertiesWithPropertiesOrder,
8
7
  getPropertyInPath,
8
+ PropertiesOrBuilders,
9
9
  Property,
10
+ PropertyConfigBadge,
10
11
  resolveCollection,
11
12
  ResolvedProperties,
13
+ slugify,
12
14
  useCustomizationController,
13
15
  User,
14
16
  useSelectionController,
@@ -30,7 +32,7 @@ import {
30
32
  } from "@firecms/ui";
31
33
  import { buildEntityPropertiesFromData } from "@firecms/schema_inference";
32
34
  import { useImportConfig } from "../hooks";
33
- import { convertDataToEntity, getInferenceType, getPropertiesMapping } from "../utils";
35
+ import { convertDataToEntity, getInferenceType } from "../utils";
34
36
  import { DataNewPropertiesMapping, ImportFileUpload, ImportSaveInProgress } from "../components";
35
37
  import { ImportConfig } from "../types";
36
38
 
@@ -40,8 +42,12 @@ export function ImportCollectionAction<M extends Record<string, any>, UserType e
40
42
  collection,
41
43
  path,
42
44
  collectionEntitiesCount,
43
- }: CollectionActionsProps<M, UserType>
45
+ onAnalyticsEvent
46
+ }: CollectionActionsProps<M, UserType> & {
47
+ onAnalyticsEvent?: (event: string, params?: any) => void;
48
+ }
44
49
  ) {
50
+
45
51
  const customizationController = useCustomizationController();
46
52
 
47
53
  const snackbarController = useSnackbarController();
@@ -54,20 +60,23 @@ export function ImportCollectionAction<M extends Record<string, any>, UserType e
54
60
 
55
61
  const handleClickOpen = useCallback(() => {
56
62
  setOpen(true);
63
+ onAnalyticsEvent?.("import_open");
57
64
  setStep("initial");
58
- }, [setOpen]);
65
+ }, [onAnalyticsEvent]);
59
66
 
60
67
  const handleClose = useCallback(() => {
61
68
  setOpen(false);
62
69
  }, [setOpen]);
63
70
 
64
71
  const onMappingComplete = useCallback(() => {
72
+ onAnalyticsEvent?.("import_mapping_complete");
65
73
  setStep("preview");
66
- }, []);
74
+ }, [onAnalyticsEvent]);
67
75
 
68
76
  const onPreviewComplete = useCallback(() => {
77
+ onAnalyticsEvent?.("import_data_save");
69
78
  setStep("import_data_saving");
70
- }, []);
79
+ }, [onAnalyticsEvent]);
71
80
 
72
81
  const onDataAdded = async (data: object[]) => {
73
82
  importConfig.setImportData(data);
@@ -76,15 +85,15 @@ export function ImportCollectionAction<M extends Record<string, any>, UserType e
76
85
  const originProperties = await buildEntityPropertiesFromData(data, getInferenceType);
77
86
  importConfig.setOriginProperties(originProperties);
78
87
 
79
- const headersMapping = buildHeadersMappingFromData(data);
88
+ const headersMapping = buildHeadersMappingFromData(data, collection?.properties);
80
89
  importConfig.setHeadersMapping(headersMapping);
81
90
  const firstKey = Object.keys(headersMapping)?.[0];
82
91
  if (firstKey?.includes("id") || firstKey?.includes("key")) {
83
- const idColumn = firstKey;
84
- importConfig.setIdColumn(idColumn);
92
+ importConfig.setIdColumn(firstKey);
85
93
  }
86
94
  }
87
95
  setTimeout(() => {
96
+ onAnalyticsEvent?.("import_data_added");
88
97
  setStep("mapping");
89
98
  }, 100);
90
99
  // setStep("mapping");
@@ -104,6 +113,7 @@ export function ImportCollectionAction<M extends Record<string, any>, UserType e
104
113
  if (collection.collectionGroup) {
105
114
  return null;
106
115
  }
116
+
107
117
  return <>
108
118
 
109
119
  <Tooltip title={"Import"}>
@@ -126,17 +136,14 @@ export function ImportCollectionAction<M extends Record<string, any>, UserType e
126
136
  </>}
127
137
 
128
138
  {step === "mapping" && <>
129
- <Typography variant={"h6"}>Map fields</Typography>
130
- <DataNewPropertiesMapping headersMapping={importConfig.headersMapping}
131
- idColumn={importConfig.idColumn}
132
- originProperties={importConfig.originProperties}
139
+ <Typography variant={"h6"} className={"ml-3.5"}>Map fields</Typography>
140
+ <DataNewPropertiesMapping importConfig={importConfig}
133
141
  destinationProperties={properties}
134
- onIdPropertyChanged={(value) => importConfig.setIdColumn(value)}
135
142
  buildPropertyView={({
136
143
  isIdColumn,
137
144
  property,
138
145
  propertyKey,
139
- importKey
146
+ importKey,
140
147
  }) => {
141
148
  return <PropertyTreeSelect
142
149
  selectedPropertyKey={propertyKey ?? ""}
@@ -148,6 +155,7 @@ export function ImportCollectionAction<M extends Record<string, any>, UserType e
148
155
  }}
149
156
  onPropertySelected={(newPropertyKey) => {
150
157
 
158
+ onAnalyticsEvent?.("import_mapping_field_updated");
151
159
  const newHeadersMapping: Record<string, string | null> = Object.entries(importConfig.headersMapping)
152
160
  .map(([currentImportKey, currentPropertyKey]) => {
153
161
  if (currentPropertyKey === newPropertyKey) {
@@ -248,30 +256,31 @@ function PropertyTreeSelect({
248
256
  }
249
257
 
250
258
  if (!selectedPropertyKey || !selectedProperty) {
251
- return <Typography variant={"body2"} className={"p-4"}>Do not import this property</Typography>;
259
+ return <Typography variant={"body2"} color="disabled" className={"p-4"}>Do not import this
260
+ property</Typography>;
252
261
  }
253
262
 
254
263
  return <PropertySelectEntry propertyKey={selectedPropertyKey}
255
264
  property={selectedProperty as Property}/>;
256
265
  }, [selectedProperty]);
257
266
 
258
- const onSelectValueChange = useCallback((value: string) => {
267
+ const onSelectValueChange = (value: string) => {
259
268
  if (value === internalIDValue) {
260
269
  onIdSelected();
261
270
  onPropertySelected(null);
262
- } else if (value === "") {
271
+ } else if (value === "__do_not_import") {
263
272
  onPropertySelected(null);
264
273
  } else {
265
274
  onPropertySelected(value);
266
275
  }
267
- }, []);
276
+ };
268
277
 
269
278
  return <Select value={isIdColumn ? internalIDValue : (selectedPropertyKey ?? undefined)}
270
279
  onValueChange={onSelectValueChange}
271
280
  renderValue={renderValue}>
272
281
 
273
- <SelectItem value={""}>
274
- <Typography variant={"body2"} className={"p-4"}>Do not import this property</Typography>
282
+ <SelectItem value={"__do_not_import"}>
283
+ <Typography variant={"body2"} color={"disabled"} className={"p-4"}>Do not import this property</Typography>
275
284
  </SelectItem>
276
285
 
277
286
  <SelectItem value={internalIDValue}>
@@ -370,12 +379,11 @@ export function ImportDataPreview<M extends Record<string, any>>({
370
379
  }: {
371
380
  importConfig: ImportConfig,
372
381
  properties: ResolvedProperties<M>,
373
- propertiesOrder: Extract<keyof M, string>[]
382
+ propertiesOrder: Extract<keyof M, string>[],
374
383
  }) {
375
384
 
376
385
  useEffect(() => {
377
- const propertiesMapping = getPropertiesMapping(importConfig.originProperties, properties);
378
- const mappedData = importConfig.importData.map(d => convertDataToEntity(d, importConfig.idColumn, importConfig.headersMapping, properties, propertiesMapping, "TEMP_PATH"));
386
+ const mappedData = importConfig.importData.map(d => convertDataToEntity(d, importConfig.idColumn, importConfig.headersMapping, properties, "TEMP_PATH", importConfig.defaultValues));
379
387
  importConfig.setEntities(mappedData);
380
388
  }, []);
381
389
 
@@ -391,30 +399,43 @@ export function ImportDataPreview<M extends Record<string, any>>({
391
399
  dataLoading: false,
392
400
  noMoreToLoad: false
393
401
  }}
402
+ enablePopupIcon={false}
394
403
  endAdornment={<div className={"h-12"}/>}
395
404
  filterable={false}
396
405
  sortable={false}
397
406
  selectionController={selectionController}
398
- displayedColumnIds={propertiesOrder.map(p => ({
399
- key: p,
400
- disabled: false
401
- }))}
402
407
  properties={properties}/>
403
408
 
404
409
  }
405
410
 
406
- function buildHeadersMappingFromData(objArr: object[]) {
411
+ function buildHeadersMappingFromData(objArr: object[], properties?: PropertiesOrBuilders<any>) {
407
412
  const headersMapping: Record<string, string> = {};
408
413
  objArr.filter(Boolean).forEach((obj) => {
409
414
  Object.keys(obj).forEach((key) => {
410
415
  // @ts-ignore
411
416
  const child = obj[key];
412
417
  if (typeof child === "object" && !Array.isArray(child)) {
413
- Object.entries(buildHeadersMappingFromData([child])).forEach(([subKey, mapping]) => {
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]) => {
414
422
  headersMapping[`${key}.${subKey}`] = `${key}.${mapping}`;
415
423
  });
416
424
  }
417
- headersMapping[key] = key;
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
+
418
439
  });
419
440
  });
420
441
  return headersMapping;
@@ -4,7 +4,6 @@ import {
4
4
  EntityReference,
5
5
  getArrayValuesCount,
6
6
  getValueInPath,
7
- ResolvedEntityCollection,
8
7
  ResolvedProperties,
9
8
  ResolvedProperty
10
9
  } from "@firecms/core";
@@ -14,37 +13,43 @@ interface Header {
14
13
  label: string;
15
14
  }
16
15
 
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"
16
+ export function downloadEntitiesExport<M extends Record<string, any>>(data: Entity<M>[],
17
+ additionalData: Record<string, any>[] | undefined,
18
+ properties: ResolvedProperties<M>,
19
+ propertiesOrder: string[] | undefined,
20
+ name: string,
21
+ flattenArrays: boolean,
22
+ additionalHeaders: string[] | undefined,
23
+ exportType: "csv" | "json",
24
+ dateExportType: "timestamp" | "string"
24
25
  ) {
25
26
 
26
- console.debug("Downloading export", { dataLength: data.length, collection, exportType, dateExportType });
27
- const properties = collection.properties;
27
+ console.debug("Downloading export", {
28
+ dataLength: data.length,
29
+ properties,
30
+ exportType,
31
+ dateExportType
32
+ });
28
33
 
29
34
  if (exportType === "csv") {
30
35
  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);
36
+ const headers = getExportHeaders(properties, propertiesOrder, additionalHeaders, arrayValuesCount);
37
+ const exportableData = getEntityCSVExportableData(data, additionalData, properties, headers, dateExportType);
33
38
  const headersData = entryToCSVRow(headers.map(h => h.label));
34
39
  const csvData = exportableData.map(entry => entryToCSVRow(entry));
35
- downloadBlob([headersData, ...csvData], `${collection.name}.csv`, "text/csv");
40
+ downloadBlob([headersData, ...csvData], `${name}.csv`, "text/csv");
36
41
  } else {
37
- const exportableData = getJsonExportableData(data, additionalData, properties, dateExportType);
42
+ const exportableData = getEntityJsonExportableData(data, additionalData, properties, dateExportType);
38
43
  const json = JSON.stringify(exportableData, null, 2);
39
- downloadBlob([json], `${collection.name}.json`, "application/json");
44
+ downloadBlob([json], `${name}.json`, "application/json");
40
45
  }
41
46
  }
42
47
 
43
- export function getCSVExportableData(data: Entity<any>[],
44
- additionalData: Record<string, any>[] | undefined,
45
- properties: ResolvedProperties,
46
- headers: Header[],
47
- dateExportType: "timestamp" | "string"
48
+ export function getEntityCSVExportableData(data: Entity<any>[],
49
+ additionalData: Record<string, any>[] | undefined,
50
+ properties: ResolvedProperties,
51
+ headers: Header[],
52
+ dateExportType: "timestamp" | "string"
48
53
  ) {
49
54
 
50
55
  const mergedData: any[] = data.map(e => ({
@@ -63,10 +68,10 @@ export function getCSVExportableData(data: Entity<any>[],
63
68
  });
64
69
  }
65
70
 
66
- export function getJsonExportableData(data: Entity<any>[],
67
- additionalData: Record<string, any>[] | undefined,
68
- properties: ResolvedProperties,
69
- dateExportType: "timestamp" | "string"
71
+ export function getEntityJsonExportableData(data: Entity<any>[],
72
+ additionalData: Record<string, any>[] | undefined,
73
+ properties: ResolvedProperties,
74
+ dateExportType: "timestamp" | "string"
70
75
  ) {
71
76
 
72
77
  const mergedData: any[] = data.map(e => ({
@@ -84,13 +89,22 @@ export function getJsonExportableData(data: Entity<any>[],
84
89
  }
85
90
 
86
91
  function getExportHeaders<M extends Record<string, any>>(properties: ResolvedProperties<M>,
92
+ propertiesOrder: string[] | undefined,
87
93
  additionalHeaders: string[] | undefined,
88
94
  arrayValuesCount?: ArrayValuesCount): Header[] {
89
95
 
90
96
  const headers: Header[] = [
91
- { label: "id", key: "id" },
92
- ...Object.entries(properties)
93
- .flatMap(([childKey, property]) => {
97
+ {
98
+ label: "id",
99
+ key: "id"
100
+ },
101
+ ...(propertiesOrder ?? Object.keys(properties))
102
+ .flatMap((childKey) => {
103
+ const property = properties[childKey];
104
+ if(!property) {
105
+ console.warn("Property not found", childKey, properties);
106
+ return [];
107
+ }
94
108
  if (arrayValuesCount && arrayValuesCount[childKey] > 1) {
95
109
  return Array.from({ length: arrayValuesCount[childKey] },
96
110
  (_, i) => getHeaders(property as ResolvedProperty, `${childKey}[${i}]`, ""))
@@ -102,7 +116,10 @@ function getExportHeaders<M extends Record<string, any>>(properties: ResolvedPro
102
116
  ];
103
117
 
104
118
  if (additionalHeaders) {
105
- headers.push(...additionalHeaders.map(h => ({ label: h, key: h })));
119
+ headers.push(...additionalHeaders.map(h => ({
120
+ label: h,
121
+ key: h
122
+ })));
106
123
  }
107
124
 
108
125
  return headers;
@@ -121,7 +138,10 @@ function getHeaders(property: ResolvedProperty, propertyKey: string, prefix = ""
121
138
  .map(([childKey, p]) => getHeaders(p, childKey, currentKey))
122
139
  .flat();
123
140
  } else {
124
- return [{ label: currentKey, key: currentKey }];
141
+ return [{
142
+ label: currentKey,
143
+ key: currentKey
144
+ }];
125
145
  }
126
146
  }
127
147
 
@@ -149,7 +169,7 @@ function processValueForExport(inputValue: any,
149
169
  } else {
150
170
  value = inputValue;
151
171
  }
152
- } else if (property.dataType === "reference" && inputValue.isEntityReference && inputValue.isEntityReference()) {
172
+ } else if (property.dataType === "reference" && inputValue && inputValue.isEntityReference && inputValue.isEntityReference()) {
153
173
  const ref = inputValue ? inputValue as EntityReference : undefined;
154
174
  value = ref ? ref.pathWithId : null;
155
175
  } else if (property.dataType === "date" && inputValue instanceof Date) {
@@ -0,0 +1,4 @@
1
+ export * from "./export";
2
+ export * from "./BasicExportAction";
3
+ export * from "./ExportCollectionAction";
4
+ export * from "./ImportCollectionAction";
@@ -5,10 +5,12 @@ import { ImportConfig } from "../types";
5
5
  export const useImportConfig = (): ImportConfig => {
6
6
 
7
7
  const [inUse, setInUse] = useState<boolean>(false);
8
+ const [defaultValues, setDefaultValues] = useState<Record<string, any>>({});
8
9
  const [idColumn, setIdColumn] = useState<string | undefined>();
9
10
  const [importData, setImportData] = useState<object[]>([]);
10
11
  const [entities, setEntities] = useState<Entity<any>[]>([]);
11
12
  const [headersMapping, setHeadersMapping] = useState<Record<string, string | null>>({});
13
+ const [headingsOrder, setHeadingsOrder] = useState<string[]>([]);
12
14
  const [originProperties, setOriginProperties] = useState<Record<string, Property>>({});
13
15
 
14
16
  return {
@@ -20,9 +22,13 @@ export const useImportConfig = (): ImportConfig => {
20
22
  setEntities,
21
23
  importData,
22
24
  setImportData,
25
+ headingsOrder: (headingsOrder ?? []).length > 0 ? headingsOrder : Object.keys(headersMapping),
26
+ setHeadingsOrder,
23
27
  headersMapping,
24
28
  setHeadersMapping,
25
29
  originProperties,
26
30
  setOriginProperties,
31
+ defaultValues,
32
+ setDefaultValues
27
33
  };
28
34
  };
package/src/index.ts CHANGED
@@ -3,3 +3,4 @@ export * from "./components";
3
3
  export * from "./types";
4
4
  export * from "./utils";
5
5
  export * from "./hooks";
6
+ export * from "./export_import";
@@ -22,11 +22,11 @@ export type ImportConfig = {
22
22
  originProperties: Record<string, Property>;
23
23
  setOriginProperties: React.Dispatch<React.SetStateAction<Record<string, Property>>>;
24
24
 
25
- }
25
+ // unmapped headings order
26
+ headingsOrder: string[];
27
+ setHeadingsOrder: React.Dispatch<React.SetStateAction<string[]>>;
28
+
29
+ defaultValues: Record<string, any>;
30
+ setDefaultValues: React.Dispatch<React.SetStateAction<Record<string, any>>>;
26
31
 
27
- export type DataTypeMapping = {
28
- from: DataType;
29
- fromSubtype?: DataType;
30
- to: DataType;
31
- toSubtype?: DataType;
32
32
  }
@@ -9,8 +9,8 @@ import { ExportCollectionAction } from "./export_import/ExportCollectionAction";
9
9
  export function useImportExportPlugin(props?: ImportExportPluginProps): FireCMSPlugin<any, any, any, ImportExportPluginProps> {
10
10
 
11
11
  return useMemo(() => ({
12
- name: "Import/Export",
13
- collections: {
12
+ key: "import_export",
13
+ collectionView: {
14
14
  CollectionActions: [ImportCollectionAction, ExportCollectionAction],
15
15
  collectionActionsProps: props
16
16
  }
@@ -19,6 +19,7 @@ export function useImportExportPlugin(props?: ImportExportPluginProps): FireCMSP
19
19
 
20
20
  export type ImportExportPluginProps = {
21
21
  exportAllowed?: (props: ExportAllowedParams) => boolean;
22
- notAllowedView: React.ReactNode;
22
+ notAllowedView?: React.ReactNode;
23
+ onAnalyticsEvent?: (event: string, params?: any) => void;
23
24
  }
24
25
  export type ExportAllowedParams = { collectionEntitiesCount: number, path: string, collection: EntityCollection };