@firecms/collection_editor 3.0.0-canary.28 → 3.0.0-canary.280

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 (91) hide show
  1. package/LICENSE +114 -21
  2. package/README.md +165 -1
  3. package/dist/ConfigControllerProvider.d.ts +1 -2
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.es.js +10792 -4791
  6. package/dist/index.es.js.map +1 -1
  7. package/dist/index.umd.js +11458 -3
  8. package/dist/index.umd.js.map +1 -1
  9. package/dist/types/collection_editor_controller.d.ts +3 -2
  10. package/dist/types/collection_inference.d.ts +4 -1
  11. package/dist/types/config_controller.d.ts +3 -1
  12. package/dist/types/config_permissions.d.ts +2 -2
  13. package/dist/types/persisted_collection.d.ts +1 -1
  14. package/dist/ui/CollectionViewHeaderAction.d.ts +3 -2
  15. package/dist/ui/EditorCollectionActionStart.d.ts +2 -0
  16. package/dist/ui/EditorEntityAction.d.ts +2 -0
  17. package/dist/ui/PropertyAddColumnComponent.d.ts +3 -1
  18. package/dist/ui/collection_editor/CollectionDetailsForm.d.ts +3 -1
  19. package/dist/ui/collection_editor/CollectionEditorDialog.d.ts +3 -2
  20. package/dist/ui/collection_editor/CollectionEditorWelcomeView.d.ts +2 -2
  21. package/dist/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +2 -2
  22. package/dist/ui/collection_editor/EntityActionsEditTab.d.ts +4 -0
  23. package/dist/ui/collection_editor/EntityActionsSelectDialog.d.ts +4 -0
  24. package/dist/ui/collection_editor/LayoutModeSwitch.d.ts +5 -0
  25. package/dist/ui/collection_editor/PropertyEditView.d.ts +8 -0
  26. package/dist/ui/collection_editor/PropertyTree.d.ts +11 -12
  27. package/dist/ui/collection_editor/SubcollectionsEditTab.d.ts +1 -1
  28. package/dist/ui/collection_editor/import/CollectionEditorImportDataPreview.d.ts +1 -1
  29. package/dist/ui/collection_editor/import/CollectionEditorImportMapping.d.ts +8 -1
  30. package/dist/ui/collection_editor/import/clean_import_data.d.ts +1 -1
  31. package/dist/ui/collection_editor/properties/MarkdownPropertyField.d.ts +4 -0
  32. package/dist/ui/collection_editor/properties/ReferencePropertyField.d.ts +2 -1
  33. package/dist/ui/collection_editor/properties/StringPropertyField.d.ts +1 -1
  34. package/dist/useCollectionEditorPlugin.d.ts +8 -11
  35. package/dist/utils/collections.d.ts +6 -0
  36. package/package.json +25 -37
  37. package/src/ConfigControllerProvider.tsx +64 -66
  38. package/src/index.ts +1 -0
  39. package/src/types/collection_editor_controller.tsx +6 -5
  40. package/src/types/collection_inference.ts +4 -1
  41. package/src/types/config_controller.tsx +4 -1
  42. package/src/types/config_permissions.ts +1 -1
  43. package/src/types/persisted_collection.ts +2 -3
  44. package/src/ui/CollectionViewHeaderAction.tsx +10 -5
  45. package/src/ui/EditorCollectionAction.tsx +12 -70
  46. package/src/ui/EditorCollectionActionStart.tsx +87 -0
  47. package/src/ui/EditorEntityAction.tsx +51 -0
  48. package/src/ui/HomePageEditorCollectionAction.tsx +21 -14
  49. package/src/ui/NewCollectionButton.tsx +1 -1
  50. package/src/ui/NewCollectionCard.tsx +3 -3
  51. package/src/ui/PropertyAddColumnComponent.tsx +11 -6
  52. package/src/ui/collection_editor/CollectionDetailsForm.tsx +157 -50
  53. package/src/ui/collection_editor/CollectionEditorDialog.tsx +119 -39
  54. package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +24 -33
  55. package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +46 -41
  56. package/src/ui/collection_editor/EntityActionsEditTab.tsx +163 -0
  57. package/src/ui/collection_editor/EntityActionsSelectDialog.tsx +41 -0
  58. package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +11 -7
  59. package/src/ui/collection_editor/EnumForm.tsx +11 -7
  60. package/src/ui/collection_editor/GetCodeDialog.tsx +60 -28
  61. package/src/ui/collection_editor/LayoutModeSwitch.tsx +54 -0
  62. package/src/ui/collection_editor/PropertyEditView.tsx +266 -79
  63. package/src/ui/collection_editor/PropertyFieldPreview.tsx +8 -10
  64. package/src/ui/collection_editor/PropertyTree.tsx +184 -138
  65. package/src/ui/collection_editor/SubcollectionsEditTab.tsx +26 -19
  66. package/src/ui/collection_editor/UnsavedChangesDialog.tsx +9 -7
  67. package/src/ui/collection_editor/import/CollectionEditorImportDataPreview.tsx +41 -9
  68. package/src/ui/collection_editor/import/CollectionEditorImportMapping.tsx +43 -10
  69. package/src/ui/collection_editor/import/clean_import_data.ts +1 -1
  70. package/src/ui/collection_editor/properties/BlockPropertyField.tsx +32 -20
  71. package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +54 -47
  72. package/src/ui/collection_editor/properties/EnumPropertyField.tsx +3 -1
  73. package/src/ui/collection_editor/properties/MapPropertyField.tsx +8 -7
  74. package/src/ui/collection_editor/properties/MarkdownPropertyField.tsx +139 -0
  75. package/src/ui/collection_editor/properties/ReferencePropertyField.tsx +7 -3
  76. package/src/ui/collection_editor/properties/RepeatPropertyField.tsx +0 -1
  77. package/src/ui/collection_editor/properties/StoragePropertyField.tsx +34 -19
  78. package/src/ui/collection_editor/properties/StringPropertyField.tsx +4 -9
  79. package/src/ui/collection_editor/properties/UrlPropertyField.tsx +1 -0
  80. package/src/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.tsx +2 -0
  81. package/src/ui/collection_editor/properties/validation/ValidationPanel.tsx +2 -2
  82. package/src/ui/collection_editor/templates/pages_template.ts +1 -6
  83. package/src/ui/collection_editor/utils/strings.ts +13 -6
  84. package/src/ui/collection_editor/utils/supported_fields.tsx +2 -0
  85. package/src/ui/collection_editor/utils/update_property_for_widget.ts +37 -6
  86. package/src/useCollectionEditorPlugin.tsx +38 -32
  87. package/src/utils/collections.ts +46 -0
  88. package/dist/ui/RootCollectionSuggestions.d.ts +0 -3
  89. package/dist/ui/collection_editor/PropertySelectItem.d.ts +0 -8
  90. package/src/ui/RootCollectionSuggestions.tsx +0 -63
  91. package/src/ui/collection_editor/PropertySelectItem.tsx +0 -32
@@ -1,12 +1,15 @@
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
+ ConfirmationDialog,
6
+ Entity,
5
7
  EntityCollection,
6
8
  ErrorView,
7
9
  isPropertyBuilder,
8
10
  MapProperty,
9
11
  mergeDeep,
12
+ NavigationResult,
10
13
  Properties,
11
14
  PropertiesOrBuilders,
12
15
  Property,
@@ -15,7 +18,6 @@ import {
15
18
  randomString,
16
19
  removeInitialAndTrailingSlashes,
17
20
  removeUndefined,
18
- TopNavigationResult,
19
21
  useAuthController,
20
22
  useCustomizationController,
21
23
  useNavigationController,
@@ -25,17 +27,19 @@ import {
25
27
  import {
26
28
  ArrowBackIcon,
27
29
  Button,
28
- cn,
30
+ CheckIcon,
31
+ cls,
29
32
  coolIconKeys,
30
33
  defaultBorderMixin,
31
34
  Dialog,
32
35
  DialogActions,
33
36
  DialogContent,
34
- DoneIcon,
37
+ DialogTitle,
35
38
  IconButton,
36
39
  LoadingButton,
37
40
  Tab,
38
- Tabs
41
+ Tabs,
42
+ Typography
39
43
  } from "@firecms/ui";
40
44
  import { YupSchema } from "./CollectionYupValidation";
41
45
  import { CollectionDetailsForm } from "./CollectionDetailsForm";
@@ -45,7 +49,7 @@ import { SubcollectionsEditTab } from "./SubcollectionsEditTab";
45
49
  import { CollectionsConfigController } from "../../types/config_controller";
46
50
  import { CollectionEditorWelcomeView } from "./CollectionEditorWelcomeView";
47
51
  import { CollectionInference } from "../../types/collection_inference";
48
- import { getInferenceType, ImportSaveInProgress, useImportConfig } from "@firecms/data_import_export";
52
+ import { getInferenceType, ImportSaveInProgress, useImportConfig } from "@firecms/data_import";
49
53
  import { buildEntityPropertiesFromData } from "@firecms/schema_inference";
50
54
  import { CollectionEditorImportMapping } from "./import/CollectionEditorImportMapping";
51
55
  import { CollectionEditorImportDataPreview } from "./import/CollectionEditorImportDataPreview";
@@ -53,6 +57,7 @@ import { cleanPropertiesFromImport } from "./import/clean_import_data";
53
57
  import { PersistedCollection } from "../../types/persisted_collection";
54
58
  import { Formex, FormexController, useCreateFormex } from "@firecms/formex";
55
59
  import { getFullIdPath } from "./util";
60
+ import { EntityActionsEditTab } from "./EntityActionsEditTab";
56
61
 
57
62
  export interface CollectionEditorDialogProps {
58
63
  open: boolean;
@@ -76,9 +81,10 @@ export interface CollectionEditorDialogProps {
76
81
  icon: React.ReactNode
77
82
  };
78
83
  pathSuggestions?: (path?: string) => Promise<string[]>;
79
- getUser: (uid: string) => User | null;
84
+ getUser?: (uid: string) => User | null;
80
85
  getData?: (path: string, parentPaths: string[]) => Promise<object[]>;
81
86
  parentCollection?: PersistedCollection;
87
+ existingEntities?: Entity<any>[];
82
88
  }
83
89
 
84
90
  export function CollectionEditorDialog(props: CollectionEditorDialogProps) {
@@ -88,13 +94,13 @@ export function CollectionEditorDialog(props: CollectionEditorDialogProps) {
88
94
  const [formDirty, setFormDirty] = React.useState<boolean>(false);
89
95
  const [unsavedChangesDialogOpen, setUnsavedChangesDialogOpen] = React.useState<boolean>(false);
90
96
 
91
- const handleCancel = useCallback(() => {
97
+ const handleCancel = () => {
92
98
  if (!formDirty) {
93
99
  props.handleClose(undefined);
94
100
  } else {
95
101
  setUnsavedChangesDialogOpen(true);
96
102
  }
97
- }, [formDirty, props.handleClose]);
103
+ };
98
104
 
99
105
  useEffect(() => {
100
106
  if (!open) {
@@ -112,6 +118,7 @@ export function CollectionEditorDialog(props: CollectionEditorDialogProps) {
112
118
  maxWidth={"7xl"}
113
119
  onOpenChange={(open) => !open ? handleCancel() : undefined}
114
120
  >
121
+ <DialogTitle hidden>Collection editor</DialogTitle>
115
122
  {open && <CollectionEditor {...props}
116
123
  handleCancel={handleCancel}
117
124
  setFormDirty={setFormDirty}/>}
@@ -134,7 +141,8 @@ type EditorView = "welcome"
134
141
  | "properties"
135
142
  | "loading"
136
143
  | "extra_view"
137
- | "subcollections";
144
+ | "subcollections"
145
+ | "custom_actions";
138
146
 
139
147
  export function CollectionEditor(props: CollectionEditorDialogProps & {
140
148
  handleCancel: () => void,
@@ -170,14 +178,15 @@ export function CollectionEditor(props: CollectionEditorDialogProps & {
170
178
  } catch (e) {
171
179
  console.error(e);
172
180
  }
173
- }, [navigation.getCollectionFromPaths, props.editedCollectionId, props.parentCollectionIds, navigation.initialised]);
181
+ }, [props.editedCollectionId, props.parentCollectionIds, navigation.initialised, navigation.getCollectionFromPaths]);
182
+
174
183
  if (!topLevelNavigation) {
175
184
  throw Error("Internal: Navigation not ready in collection editor");
176
185
  }
177
186
 
178
187
  const {
179
188
  groups
180
- }: TopNavigationResult = topLevelNavigation;
189
+ }: NavigationResult = topLevelNavigation;
181
190
 
182
191
  const initialCollection = collection
183
192
  ? {
@@ -243,7 +252,8 @@ function CollectionEditorInternal<M extends Record<string, any>>({
243
252
  setCollection,
244
253
  initialValues,
245
254
  propertyConfigs,
246
- groups
255
+ groups,
256
+ existingEntities
247
257
  }: CollectionEditorDialogProps & {
248
258
  handleCancel: () => void,
249
259
  setFormDirty: (dirty: boolean) => void,
@@ -272,6 +282,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
272
282
 
273
283
  const saveCollection = (updatedCollection: PersistedCollection<M>): Promise<boolean> => {
274
284
  const id = updatedCollection.id || updatedCollection.path;
285
+
275
286
  return configController.saveCollection({
276
287
  id,
277
288
  collectionData: updatedCollection,
@@ -293,7 +304,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
293
304
  });
294
305
  };
295
306
 
296
- const setNextMode = useCallback(() => {
307
+ const setNextMode = () => {
297
308
  if (currentView === "details") {
298
309
  if (importConfig.inUse) {
299
310
  setCurrentView("import_data_saving");
@@ -314,14 +325,14 @@ function CollectionEditorInternal<M extends Record<string, any>>({
314
325
  setCurrentView("details");
315
326
  }
316
327
 
317
- }, [currentView, importConfig.inUse, extraView]);
328
+ };
318
329
 
319
- const doCollectionInference = useCallback((collection: PersistedCollection<any>) => {
330
+ const doCollectionInference = collectionInference ? (collection: PersistedCollection<any>) => {
320
331
  if (!collectionInference) return undefined;
321
- return collectionInference?.(collection.path, collection.collectionGroup ?? false, parentCollectionIds ?? []);
322
- }, [collectionInference, parentCollectionIds]);
332
+ return collectionInference?.(collection.path, collection.collectionGroup ?? false, parentPaths ?? [], collection.databaseId);
333
+ } : undefined;
323
334
 
324
- const inferCollectionFromData = useCallback(async (newCollection: PersistedCollection<M>) => {
335
+ const inferCollectionFromData = async (newCollection: PersistedCollection<M>) => {
325
336
 
326
337
  try {
327
338
  if (!doCollectionInference) {
@@ -365,15 +376,15 @@ function CollectionEditorInternal<M extends Record<string, any>>({
365
376
  });
366
377
  return newCollection;
367
378
  }
368
- }, [parentCollectionIds, doCollectionInference]);
379
+ };
369
380
 
370
381
  const onSubmit = (newCollectionState: PersistedCollection<M>, formexController: FormexController<PersistedCollection<M>>) => {
371
- console.log("Submitting collection", newCollectionState);
382
+ console.debug("Submitting collection", newCollectionState);
372
383
  try {
373
384
 
374
385
  if (!isNewCollection) {
375
386
  saveCollection(newCollectionState).then(() => {
376
- formexController.resetForm({ values: initialValues });
387
+ formexController.resetForm();
377
388
  handleClose(newCollectionState);
378
389
  });
379
390
  return;
@@ -462,7 +473,8 @@ function CollectionEditorInternal<M extends Record<string, any>>({
462
473
  const formController = useCreateFormex<PersistedCollection<M>>({
463
474
  initialValues,
464
475
  onSubmit,
465
- validation
476
+ validation,
477
+ debugId: "COLLECTION_EDITOR"
466
478
  });
467
479
 
468
480
  const {
@@ -479,26 +491,37 @@ function CollectionEditorInternal<M extends Record<string, any>>({
479
491
  const pathError = validatePath(path, isNewCollection, existingPaths, values.id);
480
492
 
481
493
  const parentPaths = !pathError && parentCollectionIds ? navigation.convertIdsToPaths(parentCollectionIds) : undefined;
482
- const resolvedPath = !pathError ? navigation.resolveAliasesFrom(updatedFullPath) : undefined;
483
- const getDataWithPath = resolvedPath && getData ? () => getData(resolvedPath, parentPaths ?? []) : undefined;
494
+ const resolvedPath = !pathError ? navigation.resolveIdsFrom(updatedFullPath) : undefined;
495
+ const getDataWithPath = resolvedPath && getData ? async () => {
496
+ const data = await getData(resolvedPath, parentPaths ?? []);
497
+ if (existingEntities) {
498
+ const existingData = existingEntities.map(e => e.values);
499
+ data.push(...existingData);
500
+ }
501
+ return data;
502
+ } : undefined;
484
503
 
485
504
  useEffect(() => {
486
505
  setFormDirty(dirty);
487
506
  }, [dirty]);
488
507
 
489
- function onImportDataSet(data: object[]) {
508
+ function onImportDataSet(data: object[], propertiesOrder?: string[]) {
490
509
  importConfig.setInUse(true);
491
510
  buildEntityPropertiesFromData(data, getInferenceType)
492
- .then((properties) => {
511
+ .then((properties: Properties) => {
493
512
  const res = cleanPropertiesFromImport(properties);
494
513
 
495
- setFieldValue("properties", res.properties);
496
- setFieldValue("propertiesOrder", Object.keys(res.properties));
497
-
498
514
  importConfig.setIdColumn(res.idColumn);
499
515
  importConfig.setImportData(data);
500
516
  importConfig.setHeadersMapping(res.headersMapping);
517
+ const filteredHeadingsOrder = ((propertiesOrder ?? [])
518
+ .filter((key) => res.headersMapping[key]) as string[]) ?? Object.keys(res.properties);
519
+ importConfig.setHeadingsOrder(filteredHeadingsOrder);
501
520
  importConfig.setOriginProperties(res.properties);
521
+
522
+ const mappedHeadings = (propertiesOrder ?? []).map((key) => res.headersMapping[key]).filter(Boolean) as string[] ?? Object.keys(res.properties);
523
+ setFieldValue("properties", res.properties);
524
+ setFieldValue("propertiesOrder", mappedHeadings);
502
525
  });
503
526
  }
504
527
 
@@ -514,14 +537,30 @@ function CollectionEditorInternal<M extends Record<string, any>>({
514
537
  };
515
538
 
516
539
  const editable = collection?.editable === undefined || collection?.editable === true;
540
+ // @ts-ignore
541
+ const isMergedCollection = collection?.merged ?? false;
517
542
  const collectionEditable = editable || isNewCollection;
518
543
 
544
+ const [deleteRequested, setDeleteRequested] = useState(false);
545
+
546
+ const deleteCollection = () => {
547
+ if (!collection) return;
548
+ configController?.deleteCollection({ id: collection.id }).then(() => {
549
+ setDeleteRequested(false);
550
+ handleCancel();
551
+ snackbarController.open({
552
+ message: "Collection deleted",
553
+ type: "success"
554
+ });
555
+ });
556
+ };
557
+
519
558
  return <DialogContent fullHeight={true}>
520
559
  <Formex value={formController}>
521
560
 
522
561
  <>
523
562
  {!isNewCollection && <Tabs value={currentView}
524
- className={cn(defaultBorderMixin, "justify-end bg-gray-50 dark:bg-gray-950 border-b")}
563
+ innerClassName={cls(defaultBorderMixin, "px-4 h-14 w-full justify-end bg-surface-50 dark:bg-surface-950 border-b")}
525
564
  onValueChange={(v) => setCurrentView(v as EditorView)}>
526
565
  <Tab value={"details"}>
527
566
  Details
@@ -532,11 +571,14 @@ function CollectionEditorInternal<M extends Record<string, any>>({
532
571
  <Tab value={"subcollections"}>
533
572
  Additional views
534
573
  </Tab>
574
+ <Tab value={"custom_actions"}>
575
+ Custom actions
576
+ </Tab>
535
577
  </Tabs>}
536
578
 
537
579
  <form noValidate
538
580
  onSubmit={formController.handleSubmit}
539
- className={cn(
581
+ className={cls(
540
582
  isNewCollection ? "h-full" : "h-[calc(100%-48px)]",
541
583
  "flex-grow flex flex-col relative")}>
542
584
 
@@ -551,9 +593,10 @@ function CollectionEditorInternal<M extends Record<string, any>>({
551
593
  {currentView === "welcome" &&
552
594
  <CollectionEditorWelcomeView
553
595
  path={path}
554
- onContinue={(importData) => {
596
+ onContinue={(importData, propertiesOrder) => {
597
+ // console.log("Import data", importData, propertiesOrder)
555
598
  if (importData) {
556
- onImportDataSet(importData);
599
+ onImportDataSet(importData, propertiesOrder);
557
600
  setCurrentView("import_data_mapping");
558
601
  } else {
559
602
  setCurrentView("details");
@@ -594,7 +637,21 @@ function CollectionEditorInternal<M extends Record<string, any>>({
594
637
  groups={groups}
595
638
  parentCollectionIds={parentCollectionIds}
596
639
  parentCollection={parentCollection}
597
- isNewCollection={isNewCollection}/>}
640
+ isNewCollection={isNewCollection}>
641
+ {!isNewCollection && isMergedCollection && <div className={"flex flex-col gap-4 mt-8"}>
642
+ <Typography variant={"body2"} color={"secondary"}>This collection is defined in code.
643
+ The changes done in this editor will override the properties defined in code.
644
+ You can delete the overridden values to revert to the state defined in code.
645
+ </Typography>
646
+ <Button color={"neutral"}
647
+ onClick={() => {
648
+ setDeleteRequested(true);
649
+ }}>Reset to code</Button>
650
+ </div>}
651
+ </CollectionDetailsForm>}
652
+
653
+ {currentView === "custom_actions" && collection &&
654
+ <EntityActionsEditTab collection={collection}/>}
598
655
 
599
656
  {currentView === "subcollections" && collection &&
600
657
  <SubcollectionsEditTab
@@ -638,6 +695,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
638
695
  {isNewCollection && includeTemplates && currentView === "import_data_mapping" &&
639
696
  <Button variant={"text"}
640
697
  type="button"
698
+ color={"primary"}
641
699
  onClick={() => {
642
700
  importConfig.setInUse(false);
643
701
  return setCurrentView("welcome");
@@ -649,6 +707,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
649
707
  {isNewCollection && includeTemplates && currentView === "import_data_preview" &&
650
708
  <Button variant={"text"}
651
709
  type="button"
710
+ color={"primary"}
652
711
  onClick={() => {
653
712
  setCurrentView("import_data_mapping");
654
713
  }}>
@@ -658,6 +717,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
658
717
 
659
718
  {isNewCollection && includeTemplates && currentView === "details" &&
660
719
  <Button variant={"text"}
720
+ color={"primary"}
661
721
  type="button"
662
722
  onClick={() => setCurrentView("welcome")}>
663
723
  <ArrowBackIcon/>
@@ -666,12 +726,14 @@ function CollectionEditorInternal<M extends Record<string, any>>({
666
726
 
667
727
  {isNewCollection && currentView === "properties" && <Button variant={"text"}
668
728
  type="button"
729
+ color={"primary"}
669
730
  onClick={() => setCurrentView("details")}>
670
731
  <ArrowBackIcon/>
671
732
  Back
672
733
  </Button>}
673
734
 
674
735
  <Button variant={"text"}
736
+ color={"primary"}
675
737
  onClick={() => {
676
738
  handleCancel();
677
739
  }}>
@@ -706,7 +768,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
706
768
  loading={isSubmitting}
707
769
  disabled={isSubmitting || (currentView === "details" && !validValues)}
708
770
  startIcon={currentView === "properties"
709
- ? <DoneIcon/>
771
+ ? <CheckIcon/>
710
772
  : undefined}
711
773
  >
712
774
  {currentView === "details" && "Next"}
@@ -728,12 +790,24 @@ function CollectionEditorInternal<M extends Record<string, any>>({
728
790
 
729
791
  </Formex>
730
792
 
793
+ <ConfirmationDialog
794
+ open={deleteRequested}
795
+ onAccept={deleteCollection}
796
+ onCancel={() => setDeleteRequested(false)}
797
+ title={<>Delete the stored config?</>}
798
+ body={<> This will <b>not
799
+ delete any data</b>, only
800
+ the stored config, and reset to the code state.</>}/>
801
+
731
802
  </DialogContent>
732
803
 
733
804
  }
734
805
 
735
806
  function applyPropertyConfigs<M extends Record<string, any> = any>(collection: PersistedCollection<M>, propertyConfigs: Record<string, PropertyConfig<any>>): PersistedCollection<M> {
736
- const { properties, ...rest } = collection;
807
+ const {
808
+ properties,
809
+ ...rest
810
+ } = collection;
737
811
  const propertiesResult: PropertiesOrBuilders<any> = {};
738
812
  if (properties) {
739
813
  Object.keys(properties).forEach((key) => {
@@ -741,7 +815,10 @@ function applyPropertyConfigs<M extends Record<string, any> = any>(collection: P
741
815
  });
742
816
  }
743
817
 
744
- return { ...rest, properties: propertiesResult };
818
+ return {
819
+ ...rest,
820
+ properties: propertiesResult
821
+ };
745
822
  }
746
823
 
747
824
  function applyPropertiesConfig(property: PropertyOrBuilder, propertyConfigs: Record<string, PropertyConfig<any>>) {
@@ -761,7 +838,10 @@ function applyPropertiesConfig(property: PropertyOrBuilder, propertyConfigs: Rec
761
838
  Object.keys(internalProperty.properties).forEach((key) => {
762
839
  properties[key] = applyPropertiesConfig(((internalProperty as MapProperty).properties as Properties)[key] as Property, propertyConfigs);
763
840
  });
764
- internalProperty = { ...internalProperty, properties };
841
+ internalProperty = {
842
+ ...internalProperty,
843
+ properties
844
+ };
765
845
  }
766
846
 
767
847
  }
@@ -1,11 +1,11 @@
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";
7
7
  import { usersCollectionTemplate } from "./templates/users_template";
8
- import { ImportFileUpload } from "@firecms/data_import_export";
8
+ import { ImportFileUpload } from "@firecms/data_import";
9
9
  import { pagesCollectionTemplate } from "./templates/pages_template";
10
10
  import { useFormex } from "@firecms/formex";
11
11
 
@@ -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
 
@@ -37,18 +37,6 @@ export function CollectionEditorWelcomeView({
37
37
  }
38
38
  }, [existingCollectionPaths, path, pathSuggestions]);
39
39
 
40
- // const {
41
- // values,
42
- // setFieldValue,
43
- // setValues,
44
- // handleChange,
45
- // touched,
46
- // errors,
47
- // setFieldTouched,
48
- // isSubmitting,
49
- // submitCount
50
- // } = useFormex<EntityCollection>();
51
-
52
40
  const {
53
41
  values,
54
42
  setFieldValue,
@@ -56,6 +44,11 @@ export function CollectionEditorWelcomeView({
56
44
  submitCount
57
45
  } = useFormex<EntityCollection>();
58
46
 
47
+ const noSuggestions = !loadingPathSuggestions && (filteredPathSuggestions ?? [])?.length === 0;
48
+ if (!noSuggestions) {
49
+ return null;
50
+ }
51
+
59
52
  return (
60
53
  <div className={"overflow-auto my-auto"}>
61
54
  <Container maxWidth={"4xl"} className={"flex flex-col gap-4 p-8 m-auto"}>
@@ -96,12 +89,11 @@ export function CollectionEditorWelcomeView({
96
89
  {suggestion}
97
90
  </Chip>
98
91
  ))}
99
-
100
- {!loadingPathSuggestions && (filteredPathSuggestions ?? [])?.length === 0 &&
101
- <Typography variant={"caption"}>
102
- No suggestions
103
- </Typography>
104
- }
92
+ {(filteredPathSuggestions ?? []).length === 0 && !loadingPathSuggestions && <Typography
93
+ variant={"caption"}
94
+ color={"secondary"}>
95
+ No existing paths found
96
+ </Typography>}
105
97
 
106
98
  </div>
107
99
 
@@ -116,28 +108,29 @@ export function CollectionEditorWelcomeView({
116
108
  <div className={"flex gap-4"}>
117
109
  <TemplateButton title={"Products"}
118
110
  subtitle={"A collection of products with images, prices and stock"}
119
- icon={<Icon size={"small"} iconKey={productsCollectionTemplate.icon!}/>}
111
+ icon={<Icon size={"small"}
112
+ iconKey={productsCollectionTemplate.icon! as string}/>}
120
113
  onClick={() => {
121
114
  setValues(productsCollectionTemplate);
122
115
  onContinue();
123
116
  }}/>
124
117
  <TemplateButton title={"Users"}
125
118
  subtitle={"A collection of users with emails, names and roles"}
126
- icon={<Icon size={"small"} iconKey={usersCollectionTemplate.icon!}/>}
119
+ icon={<Icon size={"small"} iconKey={usersCollectionTemplate.icon! as string}/>}
127
120
  onClick={() => {
128
121
  setValues(usersCollectionTemplate);
129
122
  onContinue();
130
123
  }}/>
131
124
  <TemplateButton title={"Blog posts"}
132
125
  subtitle={"A collection of blog posts with images, authors and complex content"}
133
- icon={<Icon size={"small"} iconKey={blogCollectionTemplate.icon!}/>}
126
+ icon={<Icon size={"small"} iconKey={blogCollectionTemplate.icon! as string}/>}
134
127
  onClick={() => {
135
128
  setValues(blogCollectionTemplate);
136
129
  onContinue();
137
130
  }}/>
138
131
  <TemplateButton title={"Pages"}
139
132
  subtitle={"A collection of pages with images, authors and complex content"}
140
- icon={<Icon size={"small"} iconKey={pagesCollectionTemplate.icon!}/>}
133
+ icon={<Icon size={"small"} iconKey={pagesCollectionTemplate.icon! as string}/>}
141
134
  onClick={() => {
142
135
  setValues(pagesCollectionTemplate);
143
136
  onContinue();
@@ -154,7 +147,7 @@ export function CollectionEditorWelcomeView({
154
147
  ● Create a collection from a file (csv, json, xls, xslx...)
155
148
  </Typography>
156
149
 
157
- <ImportFileUpload onDataAdded={(data) => onContinue(data)}/>
150
+ <ImportFileUpload onDataAdded={(data, propertiesOrder) => onContinue(data, propertiesOrder)}/>
158
151
 
159
152
  </div>}
160
153
 
@@ -185,14 +178,15 @@ export function TemplateButton({
185
178
  }) {
186
179
 
187
180
  return (
188
- <Tooltip title={subtitle}>
181
+ <Tooltip title={subtitle}
182
+ asChild={true}>
189
183
  <Card
190
184
  onClick={onClick}
191
- className={cn(
185
+ className={cls(
192
186
  "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-slate-300",
187
+ "text-surface-700 dark:text-surface-accent-300",
194
188
  "hover:border-primary-dark hover:text-primary-dark dark:hover:text-primary focus:ring-primary hover:ring-1 hover:ring-primary",
195
- "border-gray-400 dark:border-gray-600 "
189
+ "border-surface-400 dark:border-surface-600 "
196
190
  )}
197
191
  >
198
192
  {icon}
@@ -201,9 +195,6 @@ export function TemplateButton({
201
195
  <Typography variant={"subtitle1"}>
202
196
  {title}
203
197
  </Typography>
204
- {/*<Typography>*/}
205
- {/* {subtitle}*/}
206
- {/*</Typography>*/}
207
198
 
208
199
  </div>
209
200
  </Card>