@firecms/collection_editor 3.0.0-canary.7 → 3.0.0-canary.70

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 (56) hide show
  1. package/LICENSE +113 -21
  2. package/dist/ConfigControllerProvider.d.ts +2 -2
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.es.js +1944 -1890
  5. package/dist/index.es.js.map +1 -1
  6. package/dist/index.umd.js +2 -2
  7. package/dist/index.umd.js.map +1 -1
  8. package/dist/types/collection_editor_controller.d.ts +1 -1
  9. package/dist/types/persisted_collection.d.ts +1 -1
  10. package/dist/ui/EditorCollectionActionStart.d.ts +2 -0
  11. package/dist/ui/collection_editor/CollectionEditorDialog.d.ts +2 -2
  12. package/dist/ui/collection_editor/CollectionEditorWelcomeView.d.ts +1 -1
  13. package/dist/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +1 -1
  14. package/dist/ui/collection_editor/PropertyTree.d.ts +9 -9
  15. package/dist/ui/collection_editor/SubcollectionsEditTab.d.ts +1 -1
  16. package/dist/ui/collection_editor/utils/supported_fields.d.ts +2 -2
  17. package/dist/useCollectionEditorPlugin.d.ts +6 -9
  18. package/dist/utils/collections.d.ts +6 -0
  19. package/package.json +26 -26
  20. package/src/ConfigControllerProvider.tsx +53 -59
  21. package/src/index.ts +1 -0
  22. package/src/types/collection_editor_controller.tsx +1 -1
  23. package/src/types/persisted_collection.ts +1 -1
  24. package/src/ui/EditorCollectionAction.tsx +0 -51
  25. package/src/ui/EditorCollectionActionStart.tsx +87 -0
  26. package/src/ui/HomePageEditorCollectionAction.tsx +16 -11
  27. package/src/ui/MissingReferenceWidget.tsx +2 -1
  28. package/src/ui/NewCollectionButton.tsx +12 -10
  29. package/src/ui/NewCollectionCard.tsx +3 -3
  30. package/src/ui/collection_editor/CollectionDetailsForm.tsx +51 -22
  31. package/src/ui/collection_editor/CollectionEditorDialog.tsx +49 -32
  32. package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +5 -5
  33. package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +27 -24
  34. package/src/ui/collection_editor/EnumForm.tsx +3 -4
  35. package/src/ui/collection_editor/GetCodeDialog.tsx +15 -3
  36. package/src/ui/collection_editor/PropertyEditView.tsx +9 -8
  37. package/src/ui/collection_editor/PropertyFieldPreview.tsx +3 -6
  38. package/src/ui/collection_editor/PropertySelectItem.tsx +2 -2
  39. package/src/ui/collection_editor/PropertyTree.tsx +3 -3
  40. package/src/ui/collection_editor/SubcollectionsEditTab.tsx +1 -1
  41. package/src/ui/collection_editor/import/CollectionEditorImportDataPreview.tsx +25 -9
  42. package/src/ui/collection_editor/import/CollectionEditorImportMapping.tsx +9 -7
  43. package/src/ui/collection_editor/properties/BlockPropertyField.tsx +14 -8
  44. package/src/ui/collection_editor/properties/CommonPropertyFields.tsx +7 -8
  45. package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +7 -8
  46. package/src/ui/collection_editor/properties/MapPropertyField.tsx +8 -9
  47. package/src/ui/collection_editor/properties/ReferencePropertyField.tsx +3 -4
  48. package/src/ui/collection_editor/properties/RepeatPropertyField.tsx +0 -1
  49. package/src/ui/collection_editor/properties/validation/StringPropertyValidation.tsx +3 -4
  50. package/src/ui/collection_editor/utils/supported_fields.tsx +3 -3
  51. package/src/useCollectionEditorPlugin.tsx +29 -30
  52. package/src/utils/collections.ts +30 -0
  53. package/dist/ui/RootCollectionSuggestions.d.ts +0 -3
  54. package/dist/ui/collection_editor/properties/FieldHelperView.d.ts +0 -4
  55. package/src/ui/RootCollectionSuggestions.tsx +0 -63
  56. package/src/ui/collection_editor/properties/FieldHelperView.tsx +0 -13
@@ -6,7 +6,7 @@ import {
6
6
  } from "@firecms/core";
7
7
  import { DeleteIcon, IconButton, Menu, MenuItem, MoreVertIcon, SettingsIcon, } from "@firecms/ui";
8
8
  import { useCollectionEditorController } from "../useCollectionEditorController";
9
- import { useCallback, useState } from "react";
9
+ import { useState } from "react";
10
10
  import { useCollectionsConfigController } from "../useCollectionsConfigController";
11
11
 
12
12
  export function HomePageEditorCollectionAction({
@@ -24,13 +24,16 @@ export function HomePageEditorCollectionAction({
24
24
  collection
25
25
  });
26
26
 
27
- const onEditCollectionClicked = useCallback(() => {
28
- collectionEditorController?.editCollection({ id: collection.id, parentCollectionIds: [] });
29
- }, [collectionEditorController, path]);
27
+ const onEditCollectionClicked = () => {
28
+ collectionEditorController?.editCollection({
29
+ id: collection.id,
30
+ parentCollectionIds: []
31
+ });
32
+ };
30
33
 
31
34
  const [deleteRequested, setDeleteRequested] = useState(false);
32
35
 
33
- const deleteCollection = useCallback(() => {
36
+ const deleteCollection = () => {
34
37
  configController?.deleteCollection({ id: collection.id }).then(() => {
35
38
  setDeleteRequested(false);
36
39
  snackbarController.open({
@@ -38,7 +41,7 @@ export function HomePageEditorCollectionAction({
38
41
  type: "success"
39
42
  });
40
43
  });
41
- }, [path, configController]);
44
+ };
42
45
 
43
46
  return <>
44
47
 
@@ -49,11 +52,13 @@ export function HomePageEditorCollectionAction({
49
52
  <MoreVertIcon size={"small"}/>
50
53
  </IconButton>}
51
54
  >
52
- <MenuItem onClick={(event) => {
53
- event.preventDefault();
54
- event.stopPropagation();
55
- setDeleteRequested(true);
56
- }}>
55
+ <MenuItem
56
+ dense={true}
57
+ onClick={(event) => {
58
+ event.preventDefault();
59
+ event.stopPropagation();
60
+ setDeleteRequested(true);
61
+ }}>
57
62
  <DeleteIcon/>
58
63
  Delete
59
64
  </MenuItem>
@@ -11,7 +11,8 @@ export function MissingReferenceWidget({ path: pathProp }: {
11
11
  const collectionEditor = useCollectionEditorController();
12
12
  return <div className={"p-1 flex flex-col items-center"}>
13
13
  <ErrorView error={"No collection for path: " + path}/>
14
- <Button className={"mx-2"} variant={"outlined"} size={"small"}
14
+ <Button className={"mx-2"} variant={"outlined"}
15
+ size={"small"}
15
16
  onClick={() => {
16
17
  collectionEditor.createCollection({
17
18
  initialValues: { path, name: unslugify(path) },
@@ -3,14 +3,16 @@ import { useCollectionEditorController } from "../useCollectionEditorController"
3
3
 
4
4
  export function NewCollectionButton() {
5
5
  const collectionEditorController = useCollectionEditorController();
6
- return <Button className={"min-w-fit"}
7
- variant={"outlined"}
8
- onClick={() => collectionEditorController.createCollection({
9
- parentCollectionIds: [],
10
- redirect: true,
11
- sourceClick: "new_collection_button"
12
- })}>
13
- <AddIcon/>
14
- New collection
15
- </Button>
6
+ return <div className={"bg-gray-50 dark:bg-gray-900 min-w-fit rounded"}>
7
+ <Button className={"min-w-fit"}
8
+ variant={"outlined"}
9
+ onClick={() => collectionEditorController.createCollection({
10
+ parentCollectionIds: [],
11
+ redirect: true,
12
+ sourceClick: "new_collection_button"
13
+ })}>
14
+ <AddIcon/>
15
+ New collection
16
+ </Button>
17
+ </div>
16
18
  }
@@ -1,5 +1,5 @@
1
1
  import { PluginHomePageAdditionalCardsProps, useAuthController } from "@firecms/core";
2
- import { AddIcon, Card, cn, Typography } from "@firecms/ui";
2
+ import { AddIcon, Card, cls, Typography } from "@firecms/ui";
3
3
  import { useCollectionEditorController } from "../useCollectionEditorController";
4
4
 
5
5
  export function NewCollectionCard({
@@ -20,7 +20,7 @@ export function NewCollectionCard({
20
20
  : true;
21
21
 
22
22
  return (
23
- <Card className={cn("h-full p-4 min-h-[124px]")}
23
+ <Card className={cls("h-full p-4 min-h-[124px]")}
24
24
  onClick={collectionEditorController && canCreateCollections
25
25
  ? () => collectionEditorController.createCollection({
26
26
  initialValues: group ? { group } : undefined,
@@ -31,7 +31,7 @@ export function NewCollectionCard({
31
31
  : undefined}>
32
32
 
33
33
  <div
34
- className="flex flex-col items-start h-full w-full items-center justify-center h-full w-full flex-grow flex-col">
34
+ className="flex items-center justify-center h-full w-full flex-grow flex-col">
35
35
  <AddIcon color="primary" size={"large"}/>
36
36
  <Typography color="primary"
37
37
  variant={"caption"}
@@ -1,11 +1,12 @@
1
1
  import React, { useEffect, useState } from "react";
2
- import { EntityCollection, IconForView, SearchIconsView, singular, toSnakeCase, } from "@firecms/core";
2
+ import { EntityCollection, FieldCaption, IconForView, SearchIconsView, singular, toSnakeCase, } from "@firecms/core";
3
3
  import {
4
4
  Autocomplete,
5
5
  AutocompleteItem,
6
6
  BooleanSwitchWithLabel,
7
7
  Chip,
8
- cn,
8
+ ClearIcon,
9
+ cls,
9
10
  Container,
10
11
  DebouncedTextField,
11
12
  Dialog,
@@ -20,7 +21,6 @@ import {
20
21
  useAutoComplete
21
22
  } from "@firecms/ui";
22
23
 
23
- import { FieldHelperView } from "./properties/FieldHelperView";
24
24
  import { Field, getIn, useFormex } from "@firecms/formex";
25
25
 
26
26
  export function CollectionDetailsForm({
@@ -142,12 +142,12 @@ export function CollectionDetailsForm({
142
142
  label={"Name"}
143
143
  required
144
144
  error={showErrors && Boolean(errors.name)}/>
145
- <FieldHelperView error={touched.name && Boolean(errors.name)}>
145
+ <FieldCaption error={touched.name && Boolean(errors.name)}>
146
146
  {touched.name && Boolean(errors.name) ? errors.name : "Name of in this collection, usually a plural name (e.g. Products)"}
147
- </FieldHelperView>
147
+ </FieldCaption>
148
148
  </div>
149
149
 
150
- <div className={cn("col-span-12 ", isSubcollection ? "" : "sm:col-span-8")}>
150
+ <div className={cls("col-span-12 ", isSubcollection ? "" : "sm:col-span-8")}>
151
151
  <Field name={"path"}
152
152
  as={DebouncedTextField}
153
153
  label={"Path"}
@@ -155,11 +155,11 @@ export function CollectionDetailsForm({
155
155
  required
156
156
  error={showErrors && Boolean(errors.path)}/>
157
157
 
158
- <FieldHelperView error={touched.path && Boolean(errors.path)}>
158
+ <FieldCaption error={touched.path && Boolean(errors.path)}>
159
159
  {touched.path && Boolean(errors.path)
160
160
  ? errors.path
161
161
  : isSubcollection ? "Relative path to the parent (no need to include the parent path)" : "Path that this collection is stored in, in the database"}
162
- </FieldHelperView>
162
+ </FieldCaption>
163
163
 
164
164
  </div>
165
165
 
@@ -190,9 +190,9 @@ export function CollectionDetailsForm({
190
190
  </AutocompleteItem>;
191
191
  })}
192
192
  </Autocomplete>
193
- <FieldHelperView>
193
+ <FieldCaption>
194
194
  {showErrors && Boolean(errors.group) ? errors.group : "Group of the collection"}
195
- </FieldHelperView>
195
+ </FieldCaption>
196
196
  </div>}
197
197
 
198
198
  <div className={"col-span-12"}>
@@ -216,9 +216,9 @@ export function CollectionDetailsForm({
216
216
  disabled={!isNewCollection}
217
217
  label={"Collection id"}
218
218
  error={showErrors && Boolean(errors.id)}/>
219
- <FieldHelperView error={touched.id && Boolean(errors.id)}>
220
- {touched.id && Boolean(errors.id) ? errors.id : "This id identifies this collection"}
221
- </FieldHelperView>
219
+ <FieldCaption error={touched.id && Boolean(errors.id)}>
220
+ {touched.id && Boolean(errors.id) ? errors.id : "This id identifies this collection. Typically the same as the path."}
221
+ </FieldCaption>
222
222
  </div>
223
223
 
224
224
  <div className={"col-span-12"}>
@@ -232,9 +232,38 @@ export function CollectionDetailsForm({
232
232
  }}
233
233
  value={values.singularName ?? ""}
234
234
  label={"Singular name"}/>
235
- <FieldHelperView error={showErrors && Boolean(errors.singularName)}>
235
+ <FieldCaption error={showErrors && Boolean(errors.singularName)}>
236
236
  {showErrors && Boolean(errors.singularName) ? errors.singularName : "Optionally define a singular name for your entities"}
237
- </FieldHelperView>
237
+ </FieldCaption>
238
+ </div>
239
+ <div className={"col-span-12"}>
240
+ <TextField
241
+ error={showErrors && Boolean(errors.sideDialogWidth)}
242
+ name={"sideDialogWidth"}
243
+ type={"number"}
244
+ aria-describedby={"sideDialogWidth-helper"}
245
+ onChange={(e) => {
246
+ setFieldTouched("sideDialogWidth", true);
247
+ const value = e.target.value;
248
+ if (!value) {
249
+ setFieldValue("sideDialogWidth", null);
250
+ } else if (!isNaN(Number(value))) {
251
+ setFieldValue("sideDialogWidth", Number(value));
252
+ }
253
+ }}
254
+ endAdornment={<IconButton
255
+ size={"small"}
256
+ onClick={() => {
257
+ setFieldValue("sideDialogWidth", null);
258
+ }}
259
+ disabled={!values.sideDialogWidth}>
260
+ <ClearIcon size={"small"}/>
261
+ </IconButton>}
262
+ value={values.sideDialogWidth ?? ""}
263
+ label={"Side dialog width"}/>
264
+ <FieldCaption error={showErrors && Boolean(errors.singularName)}>
265
+ {showErrors && Boolean(errors.singularName) ? errors.singularName : "Optionally define the width (in pixels) of entities side dialog. Default is 768px"}
266
+ </FieldCaption>
238
267
  </div>
239
268
  <div className={"col-span-12"}>
240
269
  <TextField
@@ -247,9 +276,9 @@ export function CollectionDetailsForm({
247
276
  aria-describedby="description-helper-text"
248
277
  label="Description"
249
278
  />
250
- <FieldHelperView error={showErrors && Boolean(errors.description)}>
279
+ <FieldCaption error={showErrors && Boolean(errors.description)}>
251
280
  {showErrors && Boolean(errors.description) ? errors.description : "Description of the collection, you can use markdown"}
252
- </FieldHelperView>
281
+ </FieldCaption>
253
282
  </div>
254
283
 
255
284
  <div className={"col-span-12"}>
@@ -273,7 +302,7 @@ export function CollectionDetailsForm({
273
302
  <div className={"col-span-12"}>
274
303
  <Select
275
304
  name="customId"
276
- label="Data IDs generation"
305
+ label="Document IDs generation"
277
306
  position={"item-aligned"}
278
307
  disabled={customIdValue === "code_defined"}
279
308
  onValueChange={(v) => {
@@ -316,11 +345,11 @@ export function CollectionDetailsForm({
316
345
  onValueChange={(v) => setFieldValue("collectionGroup", v)}
317
346
  value={values.collectionGroup ?? false}
318
347
  />
319
- <FieldHelperView>
348
+ <FieldCaption>
320
349
  A collection group consists of all collections with the same path. This allows
321
350
  you
322
351
  to query over multiple collections at once.
323
- </FieldHelperView>
352
+ </FieldCaption>
324
353
  </div>
325
354
  <div className={"col-span-12"}>
326
355
  <BooleanSwitchWithLabel
@@ -329,11 +358,11 @@ export function CollectionDetailsForm({
329
358
  onValueChange={(v) => setFieldValue("textSearchEnabled", v)}
330
359
  value={values.textSearchEnabled ?? false}
331
360
  />
332
- <FieldHelperView>
361
+ <FieldCaption>
333
362
  Allow text search for this collection. If you have not specified a text search
334
363
  delegate, this will use the built-in local text search. This is not recommended
335
364
  for large collections, as it may incur in performance and cost issues.
336
- </FieldHelperView>
365
+ </FieldCaption>
337
366
  </div>
338
367
  </div>
339
368
  </ExpandablePanel>
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { useCallback, useEffect, useRef, useState } from "react";
2
+ import { useEffect, useRef, useState } from "react";
3
3
  import {
4
4
  CircularProgressCenter,
5
5
  EntityCollection,
@@ -25,7 +25,7 @@ import {
25
25
  import {
26
26
  ArrowBackIcon,
27
27
  Button,
28
- cn,
28
+ cls,
29
29
  coolIconKeys,
30
30
  defaultBorderMixin,
31
31
  Dialog,
@@ -76,7 +76,7 @@ export interface CollectionEditorDialogProps {
76
76
  icon: React.ReactNode
77
77
  };
78
78
  pathSuggestions?: (path?: string) => Promise<string[]>;
79
- getUser: (uid: string) => User | null;
79
+ getUser?: (uid: string) => User | null;
80
80
  getData?: (path: string, parentPaths: string[]) => Promise<object[]>;
81
81
  parentCollection?: PersistedCollection;
82
82
  }
@@ -88,13 +88,13 @@ export function CollectionEditorDialog(props: CollectionEditorDialogProps) {
88
88
  const [formDirty, setFormDirty] = React.useState<boolean>(false);
89
89
  const [unsavedChangesDialogOpen, setUnsavedChangesDialogOpen] = React.useState<boolean>(false);
90
90
 
91
- const handleCancel = useCallback(() => {
91
+ const handleCancel = () => {
92
92
  if (!formDirty) {
93
93
  props.handleClose(undefined);
94
94
  } else {
95
95
  setUnsavedChangesDialogOpen(true);
96
96
  }
97
- }, [formDirty, props.handleClose]);
97
+ };
98
98
 
99
99
  useEffect(() => {
100
100
  if (!open) {
@@ -136,7 +136,7 @@ type EditorView = "welcome"
136
136
  | "extra_view"
137
137
  | "subcollections";
138
138
 
139
- export function CollectionEditor<M extends Record<string, any>>(props: CollectionEditorDialogProps & {
139
+ export function CollectionEditor(props: CollectionEditorDialogProps & {
140
140
  handleCancel: () => void,
141
141
  setFormDirty: (dirty: boolean) => void
142
142
  }) {
@@ -154,14 +154,14 @@ export function CollectionEditor<M extends Record<string, any>>(props: Collectio
154
154
  const collectionsInThisLevel = (props.parentCollection ? props.parentCollection.subcollections : collections) ?? [];
155
155
  const existingPaths = collectionsInThisLevel.map(col => col.path.trim().toLowerCase());
156
156
  const existingIds = collectionsInThisLevel.map(col => col.id?.trim().toLowerCase()).filter(Boolean) as string[];
157
- const [collection, setCollection] = React.useState<PersistedCollection<M> | undefined>();
157
+ const [collection, setCollection] = React.useState<PersistedCollection<any> | undefined>();
158
158
  const [initialLoadingCompleted, setInitialLoadingCompleted] = React.useState(false);
159
159
 
160
160
  useEffect(() => {
161
161
  try {
162
162
  if (navigation.initialised) {
163
163
  if (props.editedCollectionId) {
164
- setCollection(navigation.getCollectionFromPaths<PersistedCollection<M>>([...(props.parentCollectionIds ?? []), props.editedCollectionId]));
164
+ setCollection(navigation.getCollectionFromPaths([...(props.parentCollectionIds ?? []), props.editedCollectionId]));
165
165
  } else {
166
166
  setCollection(undefined);
167
167
  }
@@ -170,7 +170,8 @@ export function CollectionEditor<M extends Record<string, any>>(props: Collectio
170
170
  } catch (e) {
171
171
  console.error(e);
172
172
  }
173
- }, [navigation.getCollectionFromPaths, props.editedCollectionId, props.parentCollectionIds, navigation.initialised]);
173
+ }, [props.editedCollectionId, props.parentCollectionIds, navigation.initialised, navigation.getCollectionFromPaths]);
174
+
174
175
  if (!topLevelNavigation) {
175
176
  throw Error("Internal: Navigation not ready in collection editor");
176
177
  }
@@ -186,14 +187,14 @@ export function CollectionEditor<M extends Record<string, any>>(props: Collectio
186
187
  }
187
188
  : undefined;
188
189
 
189
- const initialValues: PersistedCollection<M> = initialCollection
190
+ const initialValues: PersistedCollection<any> = initialCollection
190
191
  ? applyPropertyConfigs(initialCollection, propertyConfigs)
191
192
  : {
192
193
  id: initialValuesProp?.path ?? randomString(16),
193
194
  path: initialValuesProp?.path ?? "",
194
195
  name: initialValuesProp?.name ?? "",
195
196
  group: initialValuesProp?.group ?? "",
196
- properties: {} as PropertiesOrBuilders<M>,
197
+ properties: {} as PropertiesOrBuilders,
197
198
  propertiesOrder: [],
198
199
  icon: coolIconKeys[Math.floor(Math.random() * coolIconKeys.length)],
199
200
  ownerId: authController.user?.uid ?? ""
@@ -293,7 +294,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
293
294
  });
294
295
  };
295
296
 
296
- const setNextMode = useCallback(() => {
297
+ const setNextMode = () => {
297
298
  if (currentView === "details") {
298
299
  if (importConfig.inUse) {
299
300
  setCurrentView("import_data_saving");
@@ -314,14 +315,14 @@ function CollectionEditorInternal<M extends Record<string, any>>({
314
315
  setCurrentView("details");
315
316
  }
316
317
 
317
- }, [currentView, importConfig.inUse, extraView]);
318
+ };
318
319
 
319
- const doCollectionInference = useCallback((collection: PersistedCollection<any>) => {
320
+ const doCollectionInference = (collection: PersistedCollection<any>) => {
320
321
  if (!collectionInference) return undefined;
321
322
  return collectionInference?.(collection.path, collection.collectionGroup ?? false, parentCollectionIds ?? []);
322
- }, [collectionInference, parentCollectionIds]);
323
+ };
323
324
 
324
- const inferCollectionFromData = useCallback(async (newCollection: PersistedCollection<M>) => {
325
+ const inferCollectionFromData = async (newCollection: PersistedCollection<M>) => {
325
326
 
326
327
  try {
327
328
  if (!doCollectionInference) {
@@ -365,10 +366,10 @@ function CollectionEditorInternal<M extends Record<string, any>>({
365
366
  });
366
367
  return newCollection;
367
368
  }
368
- }, [parentCollectionIds, doCollectionInference]);
369
+ };
369
370
 
370
371
  const onSubmit = (newCollectionState: PersistedCollection<M>, formexController: FormexController<PersistedCollection<M>>) => {
371
- console.log("Submitting collection", newCollectionState);
372
+ console.debug("Submitting collection", newCollectionState);
372
373
  try {
373
374
 
374
375
  if (!isNewCollection) {
@@ -486,19 +487,23 @@ function CollectionEditorInternal<M extends Record<string, any>>({
486
487
  setFormDirty(dirty);
487
488
  }, [dirty]);
488
489
 
489
- function onImportDataSet(data: object[]) {
490
+ function onImportDataSet(data: object[], propertiesOrder?: string[]) {
490
491
  importConfig.setInUse(true);
491
492
  buildEntityPropertiesFromData(data, getInferenceType)
492
493
  .then((properties) => {
493
494
  const res = cleanPropertiesFromImport(properties);
494
495
 
495
- setFieldValue("properties", res.properties);
496
- setFieldValue("propertiesOrder", Object.keys(res.properties));
497
-
498
496
  importConfig.setIdColumn(res.idColumn);
499
497
  importConfig.setImportData(data);
500
498
  importConfig.setHeadersMapping(res.headersMapping);
499
+ const filteredHeadingsOrder = ((propertiesOrder ?? [])
500
+ .filter((key) => res.headersMapping[key]) as string[]) ?? Object.keys(res.properties);
501
+ importConfig.setHeadingsOrder(filteredHeadingsOrder);
501
502
  importConfig.setOriginProperties(res.properties);
503
+
504
+ const mappedHeadings = (propertiesOrder ?? []).map((key) => res.headersMapping[key]).filter(Boolean) as string[] ?? Object.keys(res.properties);
505
+ setFieldValue("properties", res.properties);
506
+ setFieldValue("propertiesOrder", mappedHeadings);
502
507
  });
503
508
  }
504
509
 
@@ -521,7 +526,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
521
526
 
522
527
  <>
523
528
  {!isNewCollection && <Tabs value={currentView}
524
- className={cn(defaultBorderMixin, "justify-end bg-gray-50 dark:bg-gray-950 border-b")}
529
+ className={cls(defaultBorderMixin, "justify-end bg-gray-50 dark:bg-gray-950 border-b")}
525
530
  onValueChange={(v) => setCurrentView(v as EditorView)}>
526
531
  <Tab value={"details"}>
527
532
  Details
@@ -536,7 +541,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
536
541
 
537
542
  <form noValidate
538
543
  onSubmit={formController.handleSubmit}
539
- className={cn(
544
+ className={cls(
540
545
  isNewCollection ? "h-full" : "h-[calc(100%-48px)]",
541
546
  "flex-grow flex flex-col relative")}>
542
547
 
@@ -551,9 +556,10 @@ function CollectionEditorInternal<M extends Record<string, any>>({
551
556
  {currentView === "welcome" &&
552
557
  <CollectionEditorWelcomeView
553
558
  path={path}
554
- onContinue={(importData) => {
559
+ onContinue={(importData, propertiesOrder) => {
560
+ // console.log("Import data", importData, propertiesOrder)
555
561
  if (importData) {
556
- onImportDataSet(importData);
562
+ onImportDataSet(importData, propertiesOrder);
557
563
  setCurrentView("import_data_mapping");
558
564
  } else {
559
565
  setCurrentView("details");
@@ -733,13 +739,21 @@ function CollectionEditorInternal<M extends Record<string, any>>({
733
739
  }
734
740
 
735
741
  function applyPropertyConfigs<M extends Record<string, any> = any>(collection: PersistedCollection<M>, propertyConfigs: Record<string, PropertyConfig<any>>): PersistedCollection<M> {
736
- const { properties, ...rest } = collection;
742
+ const {
743
+ properties,
744
+ ...rest
745
+ } = collection;
737
746
  const propertiesResult: PropertiesOrBuilders<any> = {};
738
- Object.keys(properties).forEach((key) => {
739
- propertiesResult[key] = applyPropertiesConfig(properties[key] as PropertyOrBuilder, propertyConfigs);
740
- });
747
+ if (properties) {
748
+ Object.keys(properties).forEach((key) => {
749
+ propertiesResult[key] = applyPropertiesConfig(properties[key] as PropertyOrBuilder, propertyConfigs);
750
+ });
751
+ }
741
752
 
742
- return { ...rest, properties: propertiesResult };
753
+ return {
754
+ ...rest,
755
+ properties: propertiesResult
756
+ };
743
757
  }
744
758
 
745
759
  function applyPropertiesConfig(property: PropertyOrBuilder, propertyConfigs: Record<string, PropertyConfig<any>>) {
@@ -759,7 +773,10 @@ function applyPropertiesConfig(property: PropertyOrBuilder, propertyConfigs: Rec
759
773
  Object.keys(internalProperty.properties).forEach((key) => {
760
774
  properties[key] = applyPropertiesConfig(((internalProperty as MapProperty).properties as Properties)[key] as Property, propertyConfigs);
761
775
  });
762
- internalProperty = { ...internalProperty, properties };
776
+ internalProperty = {
777
+ ...internalProperty,
778
+ properties
779
+ };
763
780
  }
764
781
 
765
782
  }
@@ -1,6 +1,6 @@
1
1
  import React, { useEffect, useState } from "react";
2
2
  import { EntityCollection, unslugify, } from "@firecms/core";
3
- import { Button, Card, Chip, CircularProgress, cn, Container, Icon, Tooltip, Typography, } from "@firecms/ui";
3
+ import { Button, Card, Chip, CircularProgress, cls, Container, Icon, Tooltip, Typography, } from "@firecms/ui";
4
4
 
5
5
  import { productsCollectionTemplate } from "./templates/products_template";
6
6
  import { blogCollectionTemplate } from "./templates/blog_template";
@@ -19,7 +19,7 @@ export function CollectionEditorWelcomeView({
19
19
  path: string;
20
20
  pathSuggestions?: (path: string) => Promise<string[]>;
21
21
  parentCollection?: EntityCollection;
22
- onContinue: (importData?: object[]) => void;
22
+ onContinue: (importData?: object[], propertiesOrder?: string[]) => void;
23
23
  existingCollectionPaths?: string[];
24
24
  }) {
25
25
 
@@ -154,7 +154,7 @@ export function CollectionEditorWelcomeView({
154
154
  ● Create a collection from a file (csv, json, xls, xslx...)
155
155
  </Typography>
156
156
 
157
- <ImportFileUpload onDataAdded={(data) => onContinue(data)}/>
157
+ <ImportFileUpload onDataAdded={(data, propertiesOrder) => onContinue(data, propertiesOrder)}/>
158
158
 
159
159
  </div>}
160
160
 
@@ -188,9 +188,9 @@ export function TemplateButton({
188
188
  <Tooltip title={subtitle}>
189
189
  <Card
190
190
  onClick={onClick}
191
- className={cn(
191
+ className={cls(
192
192
  "my-2 rounded-md border mx-0 p-6 px-4 focus:outline-none transition ease-in-out duration-150 flex flex-row gap-4 items-center",
193
- "text-gray-700 dark:text-gray-300",
193
+ "text-gray-700 dark:text-slate-300",
194
194
  "hover:border-primary-dark hover:text-primary-dark dark:hover:text-primary focus:ring-primary hover:ring-1 hover:ring-primary",
195
195
  "border-gray-400 dark:border-gray-600 "
196
196
  )}