@firecms/data_import_export 3.0.0-canary.41 → 3.0.0-canary.43

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.
@@ -1,3 +0,0 @@
1
- import { Properties } from "@firecms/core";
2
- import { DataTypeMapping } from "../types";
3
- export declare function getPropertiesMapping(originProperties: Properties, newProperties: Properties): Record<string, DataTypeMapping>;
@@ -1,4 +1,3 @@
1
1
  export * from "./file_to_json";
2
2
  export * from "./data";
3
3
  export * from "./get_import_inference_type";
4
- export * from "./get_properties_mapping";
package/package.json CHANGED
@@ -1,15 +1,17 @@
1
1
  {
2
2
  "name": "@firecms/data_import_export",
3
3
  "type": "module",
4
- "version": "3.0.0-canary.41",
4
+ "version": "3.0.0-canary.43",
5
5
  "access": "public",
6
6
  "main": "./dist/index.umd.js",
7
7
  "module": "./dist/index.es.js",
8
8
  "types": "./dist/index.d.ts",
9
9
  "source": "src/index.ts",
10
10
  "dependencies": {
11
- "@firecms/core": "^3.0.0-canary.41",
12
- "@firecms/schema_inference": "^3.0.0-canary.41",
11
+ "@firecms/core": "^3.0.0-canary.43",
12
+ "@firecms/formex": "^3.0.0-canary.43",
13
+ "@firecms/schema_inference": "^3.0.0-canary.43",
14
+ "@firecms/ui": "^3.0.0-canary.43",
13
15
  "xlsx": "^0.18.5"
14
16
  },
15
17
  "peerDependencies": {
@@ -56,10 +58,10 @@
56
58
  "@jest/globals": "^29.7.0",
57
59
  "@testing-library/jest-dom": "^6.4.2",
58
60
  "@types/jest": "^29.5.12",
59
- "@types/react": "^18.2.67",
60
- "@types/react-dom": "^18.2.22",
61
- "@typescript-eslint/eslint-plugin": "^7.3.1",
62
- "@typescript-eslint/parser": "^7.3.1",
61
+ "@types/react": "^18.2.79",
62
+ "@types/react-dom": "^18.2.25",
63
+ "@typescript-eslint/eslint-plugin": "^7.7.0",
64
+ "@typescript-eslint/parser": "^7.7.0",
63
65
  "@vitejs/plugin-react": "^4.2.1",
64
66
  "babel-jest": "^29.7.0",
65
67
  "eslint": "^8.57.0",
@@ -71,8 +73,8 @@
71
73
  "eslint-plugin-react-hooks": "^4.6.0",
72
74
  "jest": "^29.7.0",
73
75
  "ts-jest": "^29.1.2",
74
- "typescript": "^5.4.2",
75
- "vite": "^5.2.3",
76
+ "typescript": "^5.4.5",
77
+ "vite": "^5.2.9",
76
78
  "vite-plugin-fonts": "^0.7.0"
77
79
  },
78
80
  "jest": {
@@ -99,5 +101,5 @@
99
101
  "publishConfig": {
100
102
  "access": "public"
101
103
  },
102
- "gitHead": "d1ffa185f8930bab4e7b9941ba551c53f947aa1f"
104
+ "gitHead": "fedcb0d43c504245dd76b702e4ab4479fa8592df"
103
105
  }
@@ -1,6 +1,9 @@
1
- import { getPropertyInPath, Property, } from "@firecms/core";
1
+ import { getPropertyInPath, PropertiesOrBuilders, Property } from "@firecms/core";
2
2
  import {
3
+ BooleanSwitchWithLabel,
3
4
  ChevronRightIcon,
5
+ DateTimeField,
6
+ ExpandablePanel,
4
7
  Select,
5
8
  SelectItem,
6
9
  Table,
@@ -8,15 +11,15 @@ import {
8
11
  TableCell,
9
12
  TableHeader,
10
13
  TableRow,
14
+ TextField,
11
15
  Typography
12
16
  } from "@firecms/ui";
17
+ import { ImportConfig } from "../types";
18
+ import { getIn, setIn } from "@firecms/formex";
13
19
 
14
20
  export interface DataPropertyMappingProps {
15
- idColumn?: string;
16
- headersMapping: Record<string, string | null>;
17
- originProperties: Record<string, Property>;
21
+ importConfig: ImportConfig;
18
22
  destinationProperties: Record<string, Property>;
19
- onIdPropertyChanged: (value: string | null) => void;
20
23
  buildPropertyView?: (props: {
21
24
  isIdColumn: boolean,
22
25
  property: Property | null,
@@ -26,20 +29,24 @@ export interface DataPropertyMappingProps {
26
29
  }
27
30
 
28
31
  export function DataNewPropertiesMapping({
29
- idColumn,
30
- headersMapping,
31
- originProperties,
32
+ importConfig,
32
33
  destinationProperties,
33
- onIdPropertyChanged,
34
- buildPropertyView,
34
+ buildPropertyView
35
35
  }: DataPropertyMappingProps) {
36
36
 
37
+ const headersMapping = importConfig.headersMapping;
38
+ const headingsOrder = importConfig.headingsOrder;
39
+ const idColumn = importConfig.idColumn;
40
+ const originProperties = importConfig.originProperties;
41
+
37
42
  return (
38
43
  <>
39
44
 
40
45
  <IdSelectField idColumn={idColumn}
41
46
  headersMapping={headersMapping}
42
- onChange={onIdPropertyChanged}/>
47
+ onChange={(value) => importConfig.setIdColumn(value ?? undefined)}/>
48
+
49
+ <div className={"h-4"}/>
43
50
 
44
51
  <Table style={{
45
52
  tableLayout: "fixed"
@@ -51,51 +58,113 @@ export function DataNewPropertiesMapping({
51
58
  <TableCell header={true}>
52
59
  </TableCell>
53
60
  <TableCell header={true} style={{ width: "75%" }}>
54
- Property
61
+ Map to Property
55
62
  </TableCell>
56
63
  </TableHeader>
57
64
  <TableBody>
58
65
  {destinationProperties &&
59
- Object.entries(headersMapping)
60
- .map(([importKey, mappedKey]) => {
61
- const propertyKey = headersMapping[importKey];
62
- const property = mappedKey ? getPropertyInPath(destinationProperties, mappedKey) as Property : null;
66
+ headingsOrder.map((importKey) => {
67
+ const mappedKey = headersMapping[importKey];
68
+ const propertyKey = headersMapping[importKey];
69
+ const property = mappedKey ? getPropertyInPath(destinationProperties, mappedKey) as Property : null;
63
70
 
64
- const originProperty = getPropertyInPath(originProperties, importKey) as Property | undefined;
65
- const originDataType = originProperty ? (originProperty.dataType === "array" && typeof originProperty.of === "object"
66
- ? `${originProperty.dataType} - ${(originProperty.of as Property).dataType}`
67
- : originProperty.dataType)
68
- : undefined;
69
- return <TableRow key={importKey} style={{ height: "90px" }}>
71
+ const originProperty = getPropertyInPath(originProperties, importKey) as Property | undefined;
72
+ const originDataType = originProperty
73
+ ? (originProperty.dataType === "array" && typeof originProperty.of === "object"
74
+ ? `${originProperty.dataType} - ${(originProperty.of as Property).dataType}`
75
+ : originProperty.dataType)
76
+ : undefined;
77
+ return <TableRow key={importKey} style={{ height: "90px" }}>
78
+ <TableCell style={{ width: "20%" }}>
79
+ <Typography variant={"body2"}>{importKey}</Typography>
80
+ {originProperty && <Typography
81
+ variant={"caption"}
82
+ color={"secondary"}
83
+ >{originDataType}</Typography>}
84
+ </TableCell>
85
+ <TableCell>
86
+ <ChevronRightIcon/>
87
+ </TableCell>
88
+ <TableCell className={importKey === idColumn ? "text-center" : undefined}
89
+ style={{ width: "75%" }}>
90
+ {buildPropertyView?.({
91
+ isIdColumn: importKey === idColumn,
92
+ property,
93
+ propertyKey,
94
+ importKey
95
+ })}
96
+ </TableCell>
97
+ </TableRow>;
98
+ }
99
+ )}
100
+ </TableBody>
101
+ </Table>
102
+
103
+ <ExpandablePanel title="Default values" initiallyExpanded={false} className={"p-4 mt-4"}>
104
+
105
+ <div className={"text-sm text-slate-500 dark:text-slate-300 font-medium ml-3.5 mb-1"}>
106
+ You can select a default value for unmapped columns and empty values:
107
+ </div>
108
+ <Table style={{
109
+ tableLayout: "fixed"
110
+ }}>
111
+ <TableHeader>
112
+ <TableCell header={true} style={{ width: "30%" }}>
113
+ Property
114
+ </TableCell>
115
+ <TableCell header={true}>
116
+ </TableCell>
117
+ <TableCell header={true} style={{ width: "65%" }}>
118
+ Default value
119
+ </TableCell>
120
+ </TableHeader>
121
+ <TableBody>
122
+ {destinationProperties &&
123
+ getAllPropertyKeys(destinationProperties).map((key) => {
124
+ const property = getPropertyInPath(destinationProperties, key);
125
+ if (typeof property !== "object" || property === null) {
126
+ return null;
127
+ }
128
+ if (!["number", "string", "boolean", "map"].includes(property.dataType)) {
129
+ return null;
130
+ }
131
+ return <TableRow key={key} style={{ height: "70px" }}>
70
132
  <TableCell style={{ width: "20%" }}>
71
- <Typography variant={"body2"}>{importKey}</Typography>
72
- {originProperty && <Typography
73
- variant={"caption"}
74
- color={"secondary"}
75
- >{originDataType}</Typography>}
133
+ <Typography variant={"body2"}>{key}</Typography>
76
134
  </TableCell>
77
135
  <TableCell>
78
136
  <ChevronRightIcon/>
79
137
  </TableCell>
80
- <TableCell className={importKey === idColumn ? "text-center" : undefined}
138
+ <TableCell className={key === idColumn ? "text-center" : undefined}
81
139
  style={{ width: "75%" }}>
82
- {buildPropertyView?.({
83
- isIdColumn: importKey === idColumn,
84
- property,
85
- propertyKey,
86
- importKey
87
- })
88
- }
140
+ <DefaultValuesField property={property}
141
+ defaultValue={getIn(importConfig.defaultValues, key)}
142
+ onValueChange={(value) => {
143
+ const newValues = setIn(importConfig.defaultValues, key, value);
144
+ importConfig.setDefaultValues(newValues);
145
+ }}/>
89
146
  </TableCell>
90
147
  </TableRow>;
91
148
  }
92
149
  )}
93
- </TableBody>
94
- </Table>
150
+ </TableBody>
151
+ </Table>
152
+ </ExpandablePanel>
95
153
  </>
96
154
  );
97
155
  }
98
156
 
157
+ function getAllPropertyKeys(properties: PropertiesOrBuilders, currentKey?: string): string[] {
158
+ return Object.entries(properties).reduce((acc, [key, property]) => {
159
+ const accumulatedKey = currentKey ? `${currentKey}.${key}` : key;
160
+ if (typeof property !== "function" && property.dataType === "map" && property.properties) {
161
+ const childProperties = getAllPropertyKeys(property.properties, accumulatedKey);
162
+ return [...acc, ...childProperties];
163
+ }
164
+ return [...acc, accumulatedKey];
165
+ }, [] as string[]);
166
+ }
167
+
99
168
  function IdSelectField({
100
169
  idColumn,
101
170
  headersMapping,
@@ -111,18 +180,62 @@ function IdSelectField({
111
180
  value={idColumn ?? ""}
112
181
  onChange={(event) => {
113
182
  const value = event.target.value;
114
- onChange(value === "none" ? null : value);
183
+ onChange(value === "__none__" ? null : value);
115
184
  }}
185
+ placeholder={"Autogenerate ID"}
116
186
  renderValue={(value) => {
117
187
  return <Typography variant={"body2"}>
118
- {value !== "" ? value : "Autogenerate ID"}
188
+ {value !== "__none__" ? value : "Autogenerate ID"}
119
189
  </Typography>;
120
190
  }}
121
191
  label={"Column that will be used as ID for each document"}>
122
- <SelectItem value={"none"}>Autogenerate ID</SelectItem>
192
+ <SelectItem value={"__none__"}>Autogenerate ID</SelectItem>
123
193
  {Object.entries(headersMapping).map(([key, value]) => {
124
194
  return <SelectItem key={key} value={key}>{key}</SelectItem>;
125
195
  })}
126
196
  </Select>
127
197
  </div>;
128
198
  }
199
+
200
+ function DefaultValuesField({
201
+ property,
202
+ onValueChange,
203
+ defaultValue
204
+ }: { property: Property, onValueChange: (value: any) => void, defaultValue?: any }) {
205
+ if (property.dataType === "string") {
206
+ return <TextField size={"small"}
207
+ placeholder={"Default value"}
208
+ value={defaultValue ?? ""}
209
+ onChange={(event) => onValueChange(event.target.value)}/>;
210
+ } else if (property.dataType === "number") {
211
+ return <TextField size={"small"}
212
+ type={"number"}
213
+ value={defaultValue ?? ""}
214
+ placeholder={"Default value"}
215
+ onChange={(event) => onValueChange(event.target.value)}/>;
216
+ } else if (property.dataType === "boolean") {
217
+ return <BooleanSwitchWithLabel
218
+ value={defaultValue ?? null}
219
+ allowIndeterminate={true}
220
+ size={"small"}
221
+ onValueChange={(v: boolean | null) => onValueChange(v === null ? undefined : v)}
222
+ label={defaultValue === undefined
223
+ ? "Do not set value"
224
+ : defaultValue === true
225
+ ? "Set value to true"
226
+ : "Set value to false"}
227
+ />
228
+ } else if (property.dataType === "date") {
229
+ return <DateTimeField
230
+ mode={property.mode ?? "date"}
231
+ size={"small"}
232
+ value={defaultValue ?? undefined}
233
+ onChange={(dateValue: Date | undefined) => {
234
+ onValueChange(dateValue);
235
+ }}
236
+ clearable={true}
237
+ />
238
+ }
239
+
240
+ return null;
241
+ }
@@ -2,7 +2,9 @@ import { FileUpload, UploadIcon } from "@firecms/ui";
2
2
  import { convertFileToJson } from "../utils/file_to_json";
3
3
  import { useSnackbarController } from "@firecms/core";
4
4
 
5
- export function ImportFileUpload({ onDataAdded }: { onDataAdded: (data: object[]) => void }) {
5
+ export function ImportFileUpload({ onDataAdded }: {
6
+ onDataAdded: (data: object[], propertiesOrder?: string[]) => void
7
+ }) {
6
8
  const snackbarController = useSnackbarController();
7
9
  return <FileUpload
8
10
  accept={{
@@ -22,12 +24,18 @@ export function ImportFileUpload({ onDataAdded }: { onDataAdded: (data: object[]
22
24
  onFilesAdded={(files: File[]) => {
23
25
  if (files.length > 0) {
24
26
  convertFileToJson(files[0])
25
- .then((jsonData) => {
26
- onDataAdded(jsonData);
27
+ .then(({
28
+ data,
29
+ propertiesOrder
30
+ }) => {
31
+ onDataAdded(data, propertiesOrder);
27
32
  })
28
33
  .catch((error) => {
29
34
  console.error("Error parsing file", error);
30
- snackbarController.open({ type: "error", message: error.message });
35
+ snackbarController.open({
36
+ type: "error",
37
+ message: error.message
38
+ });
31
39
  });
32
40
  }
33
41
  }}/>
@@ -1,5 +1,11 @@
1
1
  import React from "react";
2
- import { ErrorBoundary, PropertyConfigBadge, getFieldConfig, Property, useCustomizationController } from "@firecms/core";
2
+ import {
3
+ ErrorBoundary,
4
+ getFieldConfig,
5
+ Property,
6
+ PropertyConfigBadge,
7
+ useCustomizationController
8
+ } from "@firecms/core";
3
9
  import { EditIcon, IconButton, TextField, } from "@firecms/ui";
4
10
 
5
11
  export function ImportNewPropertyFieldPreview({
@@ -49,7 +55,6 @@ export function ImportNewPropertyFieldPreview({
49
55
 
50
56
  </div>
51
57
 
52
-
53
58
  </div>
54
59
  </ErrorBoundary>
55
60
  }
@@ -36,6 +36,7 @@ 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>> & {
@@ -123,6 +124,9 @@ export function ExportCollectionAction<M extends Record<string, any>, UserType e
123
124
  const doDownload = useCallback(async (collection: ResolvedEntityCollection<M>,
124
125
  exportConfig: ExportConfig<any> | undefined) => {
125
126
 
127
+ onAnalyticsEvent?.("export_collection", {
128
+ collection: collection.path
129
+ });
126
130
  setDataLoading(true);
127
131
  dataSource.fetchCollection<M>({
128
132
  path,
@@ -136,6 +140,9 @@ export function ExportCollectionAction<M extends Record<string, any>, UserType e
136
140
  ...collection.additionalFields?.map(field => field.key) ?? []
137
141
  ];
138
142
  downloadExport(data, additionalData, collection, flattenArrays, additionalHeaders, exportType, dateExportType);
143
+ onAnalyticsEvent?.("export_collection_success", {
144
+ collection: collection.path
145
+ });
139
146
  })
140
147
  .catch((e) => {
141
148
  console.error("Error loading export data", e);
@@ -143,7 +150,7 @@ export function ExportCollectionAction<M extends Record<string, any>, UserType e
143
150
  })
144
151
  .finally(() => setDataLoading(false));
145
152
 
146
- }, [dataSource, path, fetchAdditionalFields, flattenArrays, exportType, dateExportType]);
153
+ }, [onAnalyticsEvent, dataSource, path, fetchAdditionalFields, flattenArrays, exportType, dateExportType]);
147
154
 
148
155
  const onOkClicked = useCallback(() => {
149
156
  doDownload(collection, exportConfig);
@@ -32,7 +32,7 @@ import {
32
32
  } from "@firecms/ui";
33
33
  import { buildEntityPropertiesFromData } from "@firecms/schema_inference";
34
34
  import { useImportConfig } from "../hooks";
35
- import { convertDataToEntity, getInferenceType, getPropertiesMapping } from "../utils";
35
+ import { convertDataToEntity, getInferenceType } from "../utils";
36
36
  import { DataNewPropertiesMapping, ImportFileUpload, ImportSaveInProgress } from "../components";
37
37
  import { ImportConfig } from "../types";
38
38
 
@@ -60,20 +60,23 @@ export function ImportCollectionAction<M extends Record<string, any>, UserType e
60
60
 
61
61
  const handleClickOpen = useCallback(() => {
62
62
  setOpen(true);
63
+ onAnalyticsEvent?.("import_open");
63
64
  setStep("initial");
64
- }, [setOpen]);
65
+ }, [onAnalyticsEvent]);
65
66
 
66
67
  const handleClose = useCallback(() => {
67
68
  setOpen(false);
68
69
  }, [setOpen]);
69
70
 
70
71
  const onMappingComplete = useCallback(() => {
72
+ onAnalyticsEvent?.("import_mapping_complete");
71
73
  setStep("preview");
72
- }, []);
74
+ }, [onAnalyticsEvent]);
73
75
 
74
76
  const onPreviewComplete = useCallback(() => {
77
+ onAnalyticsEvent?.("import_data_save");
75
78
  setStep("import_data_saving");
76
- }, []);
79
+ }, [onAnalyticsEvent]);
77
80
 
78
81
  const onDataAdded = async (data: object[]) => {
79
82
  importConfig.setImportData(data);
@@ -90,6 +93,7 @@ export function ImportCollectionAction<M extends Record<string, any>, UserType e
90
93
  }
91
94
  }
92
95
  setTimeout(() => {
96
+ onAnalyticsEvent?.("import_data_added");
93
97
  setStep("mapping");
94
98
  }, 100);
95
99
  // setStep("mapping");
@@ -109,6 +113,7 @@ export function ImportCollectionAction<M extends Record<string, any>, UserType e
109
113
  if (collection.collectionGroup) {
110
114
  return null;
111
115
  }
116
+
112
117
  return <>
113
118
 
114
119
  <Tooltip title={"Import"}>
@@ -131,17 +136,14 @@ export function ImportCollectionAction<M extends Record<string, any>, UserType e
131
136
  </>}
132
137
 
133
138
  {step === "mapping" && <>
134
- <Typography variant={"h6"}>Map fields</Typography>
135
- <DataNewPropertiesMapping headersMapping={importConfig.headersMapping}
136
- idColumn={importConfig.idColumn}
137
- originProperties={importConfig.originProperties}
139
+ <Typography variant={"h6"} className={"ml-3.5"}>Map fields</Typography>
140
+ <DataNewPropertiesMapping importConfig={importConfig}
138
141
  destinationProperties={properties}
139
- onIdPropertyChanged={(value) => importConfig.setIdColumn(value ?? undefined)}
140
142
  buildPropertyView={({
141
143
  isIdColumn,
142
144
  property,
143
145
  propertyKey,
144
- importKey
146
+ importKey,
145
147
  }) => {
146
148
  return <PropertyTreeSelect
147
149
  selectedPropertyKey={propertyKey ?? ""}
@@ -153,6 +155,7 @@ export function ImportCollectionAction<M extends Record<string, any>, UserType e
153
155
  }}
154
156
  onPropertySelected={(newPropertyKey) => {
155
157
 
158
+ onAnalyticsEvent?.("import_mapping_field_updated");
156
159
  const newHeadersMapping: Record<string, string | null> = Object.entries(importConfig.headersMapping)
157
160
  .map(([currentImportKey, currentPropertyKey]) => {
158
161
  if (currentPropertyKey === newPropertyKey) {
@@ -253,14 +256,15 @@ function PropertyTreeSelect({
253
256
  }
254
257
 
255
258
  if (!selectedPropertyKey || !selectedProperty) {
256
- 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>;
257
261
  }
258
262
 
259
263
  return <PropertySelectEntry propertyKey={selectedPropertyKey}
260
264
  property={selectedProperty as Property}/>;
261
265
  }, [selectedProperty]);
262
266
 
263
- const onSelectValueChange = useCallback((value: string) => {
267
+ const onSelectValueChange = (value: string) => {
264
268
  if (value === internalIDValue) {
265
269
  onIdSelected();
266
270
  onPropertySelected(null);
@@ -269,14 +273,14 @@ function PropertyTreeSelect({
269
273
  } else {
270
274
  onPropertySelected(value);
271
275
  }
272
- }, []);
276
+ };
273
277
 
274
278
  return <Select value={isIdColumn ? internalIDValue : (selectedPropertyKey ?? undefined)}
275
279
  onValueChange={onSelectValueChange}
276
280
  renderValue={renderValue}>
277
281
 
278
282
  <SelectItem value={"__do_not_import"}>
279
- <Typography variant={"body2"} className={"p-4"}>Do not import this property</Typography>
283
+ <Typography variant={"body2"} color={"disabled"} className={"p-4"}>Do not import this property</Typography>
280
284
  </SelectItem>
281
285
 
282
286
  <SelectItem value={internalIDValue}>
@@ -379,8 +383,11 @@ export function ImportDataPreview<M extends Record<string, any>>({
379
383
  }) {
380
384
 
381
385
  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"));
386
+ const mappedData = importConfig.importData.map(d => convertDataToEntity(d, importConfig.idColumn, importConfig.headersMapping, properties, "TEMP_PATH", importConfig.defaultValues));
387
+ console.log("Mapped data", {
388
+ importConfig,
389
+ mappedData
390
+ })
384
391
  importConfig.setEntities(mappedData);
385
392
  }, []);
386
393
 
@@ -400,10 +407,6 @@ export function ImportDataPreview<M extends Record<string, any>>({
400
407
  filterable={false}
401
408
  sortable={false}
402
409
  selectionController={selectionController}
403
- displayedColumnIds={propertiesOrder.map(p => ({
404
- key: p,
405
- disabled: false
406
- }))}
407
410
  properties={properties}/>
408
411
 
409
412
  }
@@ -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
  };
@@ -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
  }