@firecms/collection_editor 3.0.1 → 3.1.0-canary.9e89e98

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 (90) hide show
  1. package/dist/ConfigControllerProvider.d.ts +6 -0
  2. package/dist/api/generateCollectionApi.d.ts +71 -0
  3. package/dist/api/index.d.ts +1 -0
  4. package/dist/index.d.ts +5 -1
  5. package/dist/index.es.js +9418 -5587
  6. package/dist/index.es.js.map +1 -1
  7. package/dist/index.umd.js +9413 -5582
  8. package/dist/index.umd.js.map +1 -1
  9. package/dist/types/collection_editor_controller.d.ts +14 -0
  10. package/dist/types/collection_inference.d.ts +8 -2
  11. package/dist/types/config_controller.d.ts +23 -2
  12. package/dist/ui/AddKanbanColumnAction.d.ts +11 -0
  13. package/dist/ui/KanbanSetupAction.d.ts +10 -0
  14. package/dist/ui/collection_editor/AICollectionGeneratorPopover.d.ts +33 -0
  15. package/dist/ui/collection_editor/AIModifiedPathsContext.d.ts +20 -0
  16. package/dist/ui/collection_editor/CollectionDetailsForm.d.ts +2 -3
  17. package/dist/ui/collection_editor/CollectionEditorDialog.d.ts +20 -0
  18. package/dist/ui/collection_editor/CollectionEditorWelcomeView.d.ts +3 -1
  19. package/dist/ui/collection_editor/CollectionJsonImportDialog.d.ts +7 -0
  20. package/dist/ui/collection_editor/CollectionYupValidation.d.ts +9 -13
  21. package/dist/ui/collection_editor/DisplaySettingsForm.d.ts +3 -0
  22. package/dist/ui/collection_editor/EntityActionsEditTab.d.ts +2 -1
  23. package/dist/ui/collection_editor/ExtendSettingsForm.d.ts +14 -0
  24. package/dist/ui/collection_editor/GeneralSettingsForm.d.ts +7 -0
  25. package/dist/ui/collection_editor/KanbanConfigSection.d.ts +4 -0
  26. package/dist/ui/collection_editor/PropertyEditView.d.ts +6 -1
  27. package/dist/ui/collection_editor/PropertyTree.d.ts +2 -1
  28. package/dist/ui/collection_editor/SubcollectionsEditTab.d.ts +2 -1
  29. package/dist/ui/collection_editor/ViewModeSwitch.d.ts +6 -0
  30. package/dist/ui/collection_editor/properties/EnumPropertyField.d.ts +2 -1
  31. package/dist/ui/collection_editor/properties/conditions/ConditionsEditor.d.ts +10 -0
  32. package/dist/ui/collection_editor/properties/conditions/ConditionsPanel.d.ts +2 -0
  33. package/dist/ui/collection_editor/properties/conditions/EnumConditionsEditor.d.ts +6 -0
  34. package/dist/ui/collection_editor/properties/conditions/index.d.ts +6 -0
  35. package/dist/ui/collection_editor/properties/conditions/property_paths.d.ts +19 -0
  36. package/dist/useCollectionEditorPlugin.d.ts +7 -1
  37. package/dist/utils/validateCollectionJson.d.ts +22 -0
  38. package/package.json +11 -11
  39. package/src/ConfigControllerProvider.tsx +81 -47
  40. package/src/api/generateCollectionApi.ts +119 -0
  41. package/src/api/index.ts +1 -0
  42. package/src/index.ts +28 -1
  43. package/src/types/collection_editor_controller.tsx +16 -3
  44. package/src/types/collection_inference.ts +15 -2
  45. package/src/types/config_controller.tsx +27 -2
  46. package/src/ui/AddKanbanColumnAction.tsx +203 -0
  47. package/src/ui/EditorCollectionActionStart.tsx +1 -2
  48. package/src/ui/HomePageEditorCollectionAction.tsx +41 -13
  49. package/src/ui/KanbanSetupAction.tsx +38 -0
  50. package/src/ui/MissingReferenceWidget.tsx +1 -1
  51. package/src/ui/NewCollectionButton.tsx +1 -1
  52. package/src/ui/PropertyAddColumnComponent.tsx +1 -1
  53. package/src/ui/collection_editor/AICollectionGeneratorPopover.tsx +225 -0
  54. package/src/ui/collection_editor/AIModifiedPathsContext.tsx +88 -0
  55. package/src/ui/collection_editor/CollectionDetailsForm.tsx +209 -257
  56. package/src/ui/collection_editor/CollectionEditorDialog.tsx +226 -167
  57. package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +130 -67
  58. package/src/ui/collection_editor/CollectionJsonImportDialog.tsx +171 -0
  59. package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +190 -91
  60. package/src/ui/collection_editor/DisplaySettingsForm.tsx +333 -0
  61. package/src/ui/collection_editor/EntityActionsEditTab.tsx +106 -96
  62. package/src/ui/collection_editor/EntityActionsSelectDialog.tsx +6 -7
  63. package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +1 -3
  64. package/src/ui/collection_editor/EnumForm.tsx +147 -100
  65. package/src/ui/collection_editor/ExtendSettingsForm.tsx +93 -0
  66. package/src/ui/collection_editor/GeneralSettingsForm.tsx +335 -0
  67. package/src/ui/collection_editor/GetCodeDialog.tsx +57 -36
  68. package/src/ui/collection_editor/KanbanConfigSection.tsx +207 -0
  69. package/src/ui/collection_editor/LayoutModeSwitch.tsx +22 -41
  70. package/src/ui/collection_editor/PropertyEditView.tsx +205 -141
  71. package/src/ui/collection_editor/PropertyFieldPreview.tsx +1 -1
  72. package/src/ui/collection_editor/PropertyTree.tsx +130 -58
  73. package/src/ui/collection_editor/SubcollectionsEditTab.tsx +171 -162
  74. package/src/ui/collection_editor/UnsavedChangesDialog.tsx +0 -2
  75. package/src/ui/collection_editor/ViewModeSwitch.tsx +41 -0
  76. package/src/ui/collection_editor/properties/BlockPropertyField.tsx +0 -2
  77. package/src/ui/collection_editor/properties/BooleanPropertyField.tsx +1 -0
  78. package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +117 -35
  79. package/src/ui/collection_editor/properties/EnumPropertyField.tsx +28 -21
  80. package/src/ui/collection_editor/properties/MapPropertyField.tsx +0 -2
  81. package/src/ui/collection_editor/properties/MarkdownPropertyField.tsx +115 -39
  82. package/src/ui/collection_editor/properties/StoragePropertyField.tsx +1 -1
  83. package/src/ui/collection_editor/properties/conditions/ConditionsEditor.tsx +861 -0
  84. package/src/ui/collection_editor/properties/conditions/ConditionsPanel.tsx +28 -0
  85. package/src/ui/collection_editor/properties/conditions/EnumConditionsEditor.tsx +599 -0
  86. package/src/ui/collection_editor/properties/conditions/index.ts +6 -0
  87. package/src/ui/collection_editor/properties/conditions/property_paths.ts +92 -0
  88. package/src/ui/collection_editor/properties/validation/ValidationPanel.tsx +1 -1
  89. package/src/useCollectionEditorPlugin.tsx +32 -17
  90. package/src/utils/validateCollectionJson.ts +380 -0
@@ -42,10 +42,11 @@ import {
42
42
  Typography
43
43
  } from "@firecms/ui";
44
44
  import { YupSchema } from "./CollectionYupValidation";
45
- import { CollectionDetailsForm } from "./CollectionDetailsForm";
45
+ import { GeneralSettingsForm } from "./GeneralSettingsForm";
46
+ import { DisplaySettingsForm } from "./DisplaySettingsForm";
46
47
  import { CollectionPropertiesEditorForm } from "./CollectionPropertiesEditorForm";
47
48
  import { UnsavedChangesDialog } from "./UnsavedChangesDialog";
48
- import { SubcollectionsEditTab } from "./SubcollectionsEditTab";
49
+ import { ExtendSettingsForm } from "./ExtendSettingsForm";
49
50
  import { CollectionsConfigController } from "../../types/config_controller";
50
51
  import { CollectionEditorWelcomeView } from "./CollectionEditorWelcomeView";
51
52
  import { CollectionInference } from "../../types/collection_inference";
@@ -57,7 +58,9 @@ import { cleanPropertiesFromImport } from "./import/clean_import_data";
57
58
  import { PersistedCollection } from "../../types/persisted_collection";
58
59
  import { Formex, FormexController, useCreateFormex } from "@firecms/formex";
59
60
  import { getFullIdPath } from "./util";
60
- import { EntityActionsEditTab } from "./EntityActionsEditTab";
61
+ import { AICollectionGeneratorPopover } from "./AICollectionGeneratorPopover";
62
+ import { AIModifiedPathsProvider, useAIModifiedPaths } from "./AIModifiedPathsContext";
63
+ import { CollectionOperation, CollectionGenerationCallback } from "../../api/generateCollectionApi";
61
64
 
62
65
  export interface CollectionEditorDialogProps {
63
66
  open: boolean;
@@ -67,6 +70,11 @@ export interface CollectionEditorDialogProps {
67
70
  path?: string,
68
71
  name?: string,
69
72
  }
73
+ /**
74
+ * A collection to duplicate from. If provided, the new collection will be
75
+ * pre-populated with the same properties (but with empty name, path, and id).
76
+ */
77
+ copyFrom?: PersistedCollection;
70
78
  editedCollectionId?: string;
71
79
  fullPath?: string; // full path of this particular collection, like `products/123/locales`
72
80
  parentCollectionIds?: string[]; // path ids of the parent collection, like [`products`]
@@ -84,6 +92,20 @@ export interface CollectionEditorDialogProps {
84
92
  getData?: (path: string, parentPaths: string[]) => Promise<object[]>;
85
93
  parentCollection?: PersistedCollection;
86
94
  existingEntities?: Entity<any>[];
95
+ /**
96
+ * Initial view to open when editing: "general", "display", or "properties".
97
+ * For new collections, this is ignored.
98
+ */
99
+ initialView?: "general" | "display" | "properties";
100
+ /**
101
+ * If true, auto-expand the Kanban configuration section.
102
+ */
103
+ expandKanban?: boolean;
104
+ /**
105
+ * Callback function for generating/modifying collections.
106
+ * The plugin is API-agnostic - the consumer provides the implementation.
107
+ */
108
+ generateCollection?: CollectionGenerationCallback;
87
109
  }
88
110
 
89
111
  export function CollectionEditorDialog(props: CollectionEditorDialogProps) {
@@ -118,30 +140,31 @@ export function CollectionEditorDialog(props: CollectionEditorDialogProps) {
118
140
  onOpenChange={(open) => !open ? handleCancel() : undefined}
119
141
  >
120
142
  <DialogTitle hidden>Collection editor</DialogTitle>
121
- {open && <CollectionEditor {...props}
122
- handleCancel={handleCancel}
123
- setFormDirty={setFormDirty}/>}
124
-
125
- <UnsavedChangesDialog
126
- open={unsavedChangesDialogOpen}
127
- handleOk={() => props.handleClose(undefined)}
128
- handleCancel={() => setUnsavedChangesDialogOpen(false)}
129
- body={"There are unsaved changes in this collection"}/>
130
-
143
+ <AIModifiedPathsProvider>
144
+ {open && <CollectionEditor {...props}
145
+ handleCancel={handleCancel}
146
+ setFormDirty={setFormDirty} />}
147
+
148
+ <UnsavedChangesDialog
149
+ open={unsavedChangesDialogOpen}
150
+ handleOk={() => props.handleClose(undefined)}
151
+ handleCancel={() => setUnsavedChangesDialogOpen(false)}
152
+ body={"There are unsaved changes in this collection"} />
153
+ </AIModifiedPathsProvider>
131
154
  </Dialog>
132
155
  );
133
156
  }
134
157
 
135
158
  type EditorView = "welcome"
136
- | "details"
159
+ | "general"
160
+ | "display"
137
161
  | "import_data_mapping"
138
162
  | "import_data_preview"
139
163
  | "import_data_saving"
140
164
  | "properties"
141
165
  | "loading"
142
166
  | "extra_view"
143
- | "subcollections"
144
- | "custom_actions";
167
+ | "extend";
145
168
 
146
169
  export function CollectionEditor(props: CollectionEditorDialogProps & {
147
170
  handleCancel: () => void,
@@ -157,7 +180,9 @@ export function CollectionEditor(props: CollectionEditorDialogProps & {
157
180
  } = navigation;
158
181
 
159
182
  const initialValuesProp = props.initialValues;
160
- const includeTemplates = !initialValuesProp?.path && (props.parentCollectionIds ?? []).length === 0;
183
+ const copyFromProp = props.copyFrom;
184
+ // Skip templates when duplicating (copyFrom is provided)
185
+ const includeTemplates = !copyFromProp && !initialValuesProp?.path && (props.parentCollectionIds ?? []).length === 0;
161
186
  const collectionsInThisLevel = (props.parentCollection ? props.parentCollection.subcollections : collections) ?? [];
162
187
  const existingPaths = collectionsInThisLevel.map(col => col.path.trim().toLowerCase());
163
188
  const existingIds = collectionsInThisLevel.map(col => col.id?.trim().toLowerCase()).filter(Boolean) as string[];
@@ -194,25 +219,36 @@ export function CollectionEditor(props: CollectionEditorDialogProps & {
194
219
  }
195
220
  : undefined;
196
221
 
222
+ // Build initial values - handle copyFrom for duplication
197
223
  const initialValues: PersistedCollection<any> = initialCollection
198
224
  ? applyPropertyConfigs(initialCollection, propertyConfigs)
199
- : {
200
- id: initialValuesProp?.path ?? randomString(16),
201
- path: initialValuesProp?.path ?? "",
202
- name: initialValuesProp?.name ?? "",
203
- group: initialValuesProp?.group ?? "",
204
- properties: {} as PropertiesOrBuilders,
205
- propertiesOrder: [],
206
- icon: coolIconKeys[Math.floor(Math.random() * coolIconKeys.length)],
207
- ownerId: authController.user?.uid ?? ""
208
- };
225
+ : copyFromProp
226
+ ? {
227
+ // When duplicating, copy all properties but clear identifiers
228
+ ...copyFromProp,
229
+ id: randomString(16),
230
+ path: "",
231
+ name: "",
232
+ subcollections: undefined, // Don't copy subcollections
233
+ ownerId: authController.user?.uid ?? ""
234
+ }
235
+ : {
236
+ id: initialValuesProp?.path ?? randomString(16),
237
+ path: initialValuesProp?.path ?? "",
238
+ name: initialValuesProp?.name ?? "",
239
+ group: initialValuesProp?.group ?? "",
240
+ properties: {} as PropertiesOrBuilders,
241
+ propertiesOrder: [],
242
+ icon: coolIconKeys[Math.floor(Math.random() * coolIconKeys.length)],
243
+ ownerId: authController.user?.uid ?? ""
244
+ };
209
245
 
210
246
  if (!initialLoadingCompleted) {
211
- return <CircularProgressCenter/>;
247
+ return <CircularProgressCenter />;
212
248
  }
213
249
 
214
250
  if (!props.isNewCollection && (!navigation.initialised || !initialLoadingCompleted)) {
215
- return <CircularProgressCenter/>;
251
+ return <CircularProgressCenter />;
216
252
  }
217
253
 
218
254
  return <CollectionEditorInternal
@@ -224,46 +260,49 @@ export function CollectionEditor(props: CollectionEditorDialogProps & {
224
260
  collection={collection}
225
261
  setCollection={setCollection}
226
262
  groups={groups}
227
- propertyConfigs={propertyConfigs}/>
263
+ propertyConfigs={propertyConfigs} />
228
264
 
229
265
  }
230
266
 
231
267
  function CollectionEditorInternal<M extends Record<string, any>>({
232
- isNewCollection,
233
- configController,
234
- editedCollectionId,
235
- parentCollectionIds,
236
- fullPath,
237
- collectionInference,
238
- handleClose,
239
- reservedGroups,
240
- extraView,
241
- handleCancel,
242
- setFormDirty,
243
- getUser,
244
- parentCollection,
245
- getData,
246
- existingPaths,
247
- existingIds,
248
- includeTemplates,
249
- collection,
250
- setCollection,
251
- initialValues,
252
- propertyConfigs,
253
- groups,
254
- existingEntities
255
- }: CollectionEditorDialogProps & {
256
- handleCancel: () => void,
257
- setFormDirty: (dirty: boolean) => void,
258
- initialValues: PersistedCollection<M>,
259
- existingPaths: string[],
260
- existingIds: string[],
261
- includeTemplates: boolean,
262
- collection: PersistedCollection<M> | undefined,
263
- setCollection: (collection: PersistedCollection<M>) => void,
264
- propertyConfigs: Record<string, PropertyConfig<any>>,
265
- groups: string[],
266
- }
268
+ isNewCollection,
269
+ configController,
270
+ editedCollectionId,
271
+ parentCollectionIds,
272
+ fullPath,
273
+ collectionInference,
274
+ handleClose,
275
+ reservedGroups,
276
+ extraView,
277
+ handleCancel,
278
+ setFormDirty,
279
+ getUser,
280
+ parentCollection,
281
+ getData,
282
+ existingPaths,
283
+ existingIds,
284
+ includeTemplates,
285
+ collection,
286
+ setCollection,
287
+ initialValues,
288
+ propertyConfigs,
289
+ groups,
290
+ existingEntities,
291
+ initialView: initialViewProp,
292
+ expandKanban,
293
+ generateCollection
294
+ }: CollectionEditorDialogProps & {
295
+ handleCancel: () => void,
296
+ setFormDirty: (dirty: boolean) => void,
297
+ initialValues: PersistedCollection<M>,
298
+ existingPaths: string[],
299
+ existingIds: string[],
300
+ includeTemplates: boolean,
301
+ collection: PersistedCollection<M> | undefined,
302
+ setCollection: (collection: PersistedCollection<M>) => void,
303
+ propertyConfigs: Record<string, PropertyConfig<any>>,
304
+ groups: string[],
305
+ }
267
306
  ) {
268
307
 
269
308
  const importConfig = useImportConfig();
@@ -273,7 +312,9 @@ function CollectionEditorInternal<M extends Record<string, any>>({
273
312
  // Use this ref to store which properties have errors
274
313
  const propertyErrorsRef = useRef({});
275
314
 
276
- const initialView = isNewCollection ? (includeTemplates ? "welcome" : "details") : "properties";
315
+ const initialView = isNewCollection
316
+ ? (includeTemplates ? "welcome" : "general")
317
+ : (initialViewProp ?? "properties");
277
318
  const [currentView, setCurrentView] = useState<EditorView>(initialView); // this view can edit either the details view or the properties one
278
319
 
279
320
  const [error, setError] = React.useState<Error | undefined>();
@@ -303,7 +344,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
303
344
  };
304
345
 
305
346
  const setNextMode = () => {
306
- if (currentView === "details") {
347
+ if (currentView === "general") {
307
348
  if (importConfig.inUse) {
308
349
  setCurrentView("import_data_saving");
309
350
  } else if (extraView) {
@@ -312,22 +353,29 @@ function CollectionEditorInternal<M extends Record<string, any>>({
312
353
  setCurrentView("properties");
313
354
  }
314
355
  } else if (currentView === "welcome") {
315
- setCurrentView("details");
356
+ setCurrentView("general");
316
357
  } else if (currentView === "import_data_mapping") {
317
358
  setCurrentView("import_data_preview");
318
359
  } else if (currentView === "import_data_preview") {
319
- setCurrentView("details");
360
+ setCurrentView("general");
320
361
  } else if (currentView === "extra_view") {
321
362
  setCurrentView("properties");
322
363
  } else {
323
- setCurrentView("details");
364
+ setCurrentView("general");
324
365
  }
325
366
 
326
367
  };
327
368
 
328
369
  const doCollectionInference = collectionInference ? (collection: PersistedCollection<any>) => {
329
370
  if (!collectionInference) return undefined;
330
- return collectionInference?.(collection.path, collection.collectionGroup ?? false, parentPaths ?? [], collection.databaseId);
371
+ return collectionInference?.(
372
+ collection.path,
373
+ collection.collectionGroup ?? false,
374
+ parentPaths ?? [],
375
+ collection.databaseId,
376
+ collection.initialFilter,
377
+ collection.initialSort
378
+ );
331
379
  } : undefined;
332
380
 
333
381
  const inferCollectionFromData = async (newCollection: PersistedCollection<M>) => {
@@ -382,6 +430,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
382
430
 
383
431
  if (!isNewCollection) {
384
432
  saveCollection(newCollectionState).then(() => {
433
+ aiModifiedPaths?.clearAllPaths();
385
434
  formexController.resetForm();
386
435
  handleClose(newCollectionState);
387
436
  });
@@ -391,7 +440,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
391
440
  if (currentView === "welcome") {
392
441
  setNextMode();
393
442
  formexController.resetForm({ values: newCollectionState });
394
- } else if (currentView === "details") {
443
+ } else if (currentView === "general") {
395
444
  if (extraView || importConfig.inUse) {
396
445
  formexController.resetForm({ values: newCollectionState });
397
446
  setNextMode();
@@ -406,8 +455,8 @@ function CollectionEditorInternal<M extends Record<string, any>>({
406
455
  }
407
456
  });
408
457
  }).finally(() => {
409
- setNextMode();
410
- });
458
+ setNextMode();
459
+ });
411
460
  } else {
412
461
  formexController.resetForm({ values: newCollectionState });
413
462
  setNextMode();
@@ -442,7 +491,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
442
491
  const validation = (col: PersistedCollection) => {
443
492
 
444
493
  let errors: Record<string, any> = {};
445
- const schema = (currentView === "properties" || currentView === "subcollections" || currentView === "details") && YupSchema;
494
+ const schema = (currentView === "properties" || currentView === "extend" || currentView === "general") && YupSchema;
446
495
  if (schema) {
447
496
  try {
448
497
  schema.validateSync(col, { abortEarly: false });
@@ -455,7 +504,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
455
504
  if (currentView === "properties") {
456
505
  errors = { ...errors, ...propertyErrorsRef.current };
457
506
  }
458
- if (currentView === "details") {
507
+ if (currentView === "general") {
459
508
  const pathError = validatePath(col.path, isNewCollection, existingPaths, col.id);
460
509
  if (pathError) {
461
510
  errors.path = pathError;
@@ -483,15 +532,15 @@ function CollectionEditorInternal<M extends Record<string, any>>({
483
532
  submitCount
484
533
  } = formController;
485
534
 
486
- // TODO: getting data is only working in root collections with this code
487
535
  const path = values.path;
488
536
  const updatedFullPath = fullPath?.includes("/") ? fullPath?.split("/").slice(0, -1).join("/") + "/" + path : path; // TODO: this path is wrong
489
537
  const pathError = validatePath(path, isNewCollection, existingPaths, values.id);
490
538
 
491
539
  const parentPaths = !pathError && parentCollectionIds ? navigation.convertIdsToPaths(parentCollectionIds) : undefined;
492
540
  const resolvedPath = !pathError ? navigation.resolveIdsFrom(updatedFullPath) : undefined;
541
+
493
542
  const getDataWithPath = resolvedPath && getData ? async () => {
494
- const data = await getData(resolvedPath, parentPaths ?? []);
543
+ const data = await getData!(resolvedPath, parentPaths ?? []);
495
544
  if (existingEntities) {
496
545
  const existingData = existingEntities.map(e => e.values);
497
546
  data.push(...existingData);
@@ -558,7 +607,16 @@ function CollectionEditorInternal<M extends Record<string, any>>({
558
607
  onImportDataSet(importData, propertiesOrder);
559
608
  setCurrentView("import_data_mapping");
560
609
  } else {
561
- setCurrentView("details");
610
+ setCurrentView("general");
611
+ }
612
+ };
613
+
614
+ const aiModifiedPaths = useAIModifiedPaths();
615
+
616
+ const handleAIGenerated = (generatedCollection: EntityCollection, operations?: CollectionOperation[]) => {
617
+ formController.setValues(generatedCollection as PersistedCollection<M>);
618
+ if (operations && aiModifiedPaths) {
619
+ aiModifiedPaths.addModifiedPaths(operations);
562
620
  }
563
621
  };
564
622
 
@@ -566,99 +624,100 @@ function CollectionEditorInternal<M extends Record<string, any>>({
566
624
  <Formex value={formController}>
567
625
 
568
626
  <>
569
- {!isNewCollection && <Tabs value={currentView}
570
- innerClassName={cls(defaultBorderMixin, "px-4 h-14 w-full justify-end bg-surface-50 dark:bg-surface-950 border-b")}
571
- onValueChange={(v) => setCurrentView(v as EditorView)}>
572
- <Tab value={"details"}>
573
- Details
574
- </Tab>
575
- <Tab value={"properties"}>
576
- Properties
577
- </Tab>
578
- <Tab value={"subcollections"}>
579
- Additional views
580
- </Tab>
581
- <Tab value={"custom_actions"}>
582
- Custom actions
583
- </Tab>
584
- </Tabs>}
627
+ {!isNewCollection && <div className={cls("px-4 py-2 w-full flex items-center justify-end gap-2 bg-surface-50 dark:bg-surface-950 border-b", defaultBorderMixin)}>
628
+ {generateCollection && (
629
+ <AICollectionGeneratorPopover
630
+ existingCollection={values}
631
+ onGenerated={handleAIGenerated}
632
+ generateCollection={generateCollection}
633
+ />
634
+ )}
635
+ <Tabs value={currentView}
636
+ onValueChange={(v) => setCurrentView(v as EditorView)}>
637
+ <Tab value={"general"}>
638
+ General
639
+ </Tab>
640
+ <Tab value={"display"}>
641
+ Display
642
+ </Tab>
643
+ <Tab value={"properties"}>
644
+ Properties
645
+ </Tab>
646
+ <Tab value={"extend"}>
647
+ Extend
648
+ </Tab>
649
+ </Tabs>
650
+ </div>}
585
651
 
586
652
  <form noValidate
587
- onSubmit={formController.handleSubmit}
588
- className={cls(
589
- isNewCollection ? "h-full" : "h-[calc(100%-48px)]",
590
- "flex-grow flex flex-col relative")}>
653
+ onSubmit={formController.handleSubmit}
654
+ className={cls(
655
+ isNewCollection ? "h-full" : "h-[calc(100%-48px)]",
656
+ "flex-grow flex flex-col relative")}>
591
657
 
592
658
  {currentView === "loading" &&
593
- <CircularProgressCenter/>}
659
+ <CircularProgressCenter />}
594
660
 
595
661
  {currentView === "extra_view" &&
596
662
  path &&
597
663
  extraView?.View &&
598
- <extraView.View path={path}/>}
664
+ <extraView.View path={path} />}
599
665
 
600
666
  {currentView === "welcome" &&
601
667
  <CollectionEditorWelcomeView
602
668
  path={path}
603
669
  onContinue={onWelcomeScreenContinue}
604
670
  existingCollectionPaths={existingPaths}
605
- parentCollection={parentCollection}/>}
671
+ parentCollection={parentCollection}
672
+ generateCollection={generateCollection} />}
606
673
 
607
674
  {currentView === "import_data_mapping" && importConfig &&
608
675
  <CollectionEditorImportMapping importConfig={importConfig}
609
- collectionEditable={collectionEditable}
610
- propertyConfigs={propertyConfigs}/>}
676
+ collectionEditable={collectionEditable}
677
+ propertyConfigs={propertyConfigs} />}
611
678
 
612
679
  {currentView === "import_data_preview" && importConfig &&
613
680
  <CollectionEditorImportDataPreview importConfig={importConfig}
614
- properties={values.properties as Properties}
615
- propertiesOrder={values.propertiesOrder as string[]}/>}
681
+ properties={values.properties as Properties}
682
+ propertiesOrder={values.propertiesOrder as string[]} />}
616
683
 
617
684
  {currentView === "import_data_saving" && importConfig &&
618
685
  <ImportSaveInProgress importConfig={importConfig}
619
- collection={values}
620
- path={path}
621
- onImportSuccess={async (importedCollection) => {
622
- snackbarController.open({
623
- type: "info",
624
- message: "Data imported successfully"
625
- });
626
- await saveCollection(values);
627
- handleClose(importedCollection);
628
- }}
686
+ collection={values}
687
+ path={path}
688
+ onImportSuccess={async (importedCollection) => {
689
+ snackbarController.open({
690
+ type: "info",
691
+ message: "Data imported successfully"
692
+ });
693
+ await saveCollection(values);
694
+ handleClose(importedCollection);
695
+ }}
629
696
  />}
630
697
 
631
- {currentView === "details" &&
632
- <CollectionDetailsForm
698
+ {currentView === "general" &&
699
+ <GeneralSettingsForm
633
700
  existingPaths={existingPaths}
634
701
  existingIds={existingIds}
635
- groups={groups}
636
- parentCollectionIds={parentCollectionIds}
637
702
  parentCollection={parentCollection}
638
- isNewCollection={isNewCollection}>
639
- {!isNewCollection && isMergedCollection && <div className={"flex flex-col gap-4 mt-8"}>
640
- <Typography variant={"body2"} color={"secondary"}>This collection is defined in code.
641
- The changes done in this editor will override the properties defined in code.
642
- You can delete the overridden values to revert to the state defined in code.
643
- </Typography>
644
- <Button color={"neutral"}
645
- onClick={() => {
646
- setDeleteRequested(true);
647
- }}>Reset to code</Button>
648
- </div>}
649
- </CollectionDetailsForm>}
650
-
651
- {currentView === "custom_actions" && collection &&
652
- <EntityActionsEditTab collection={collection}/>}
653
-
654
- {currentView === "subcollections" && collection &&
655
- <SubcollectionsEditTab
703
+ isNewCollection={isNewCollection} />
704
+ }
705
+
706
+ {currentView === "display" &&
707
+ <DisplaySettingsForm expandKanban={expandKanban} />
708
+ }
709
+
710
+ {currentView === "extend" && collection &&
711
+ <ExtendSettingsForm
712
+ collection={collection}
656
713
  parentCollection={parentCollection}
657
714
  configController={configController}
658
- getUser={getUser}
659
715
  collectionInference={collectionInference}
716
+ getUser={getUser}
660
717
  parentCollectionIds={parentCollectionIds}
661
- collection={collection}/>}
718
+ isMergedCollection={!isNewCollection && isMergedCollection}
719
+ onResetToCode={() => setDeleteRequested(true)} />
720
+ }
662
721
 
663
722
  {currentView === "properties" &&
664
723
  <CollectionPropertiesEditorForm
@@ -683,52 +742,52 @@ function CollectionEditorInternal<M extends Record<string, any>>({
683
742
  color={"primary"}
684
743
  onClick={() => setCurrentView("extra_view")}>
685
744
  {extraView.icon}
686
- </IconButton>}/>
745
+ </IconButton>} />
687
746
  }
688
747
 
689
748
  <DialogActions
690
749
  position={"absolute"}>
691
- {error && <ErrorView error={error}/>}
750
+ {error && <ErrorView error={error} />}
692
751
 
693
752
  {isNewCollection && includeTemplates && currentView === "import_data_mapping" &&
694
753
  <Button variant={"text"}
695
- type="button"
696
- onClick={() => {
697
- importConfig.setInUse(false);
698
- return setCurrentView("welcome");
699
- }}>
754
+ type="button"
755
+ onClick={() => {
756
+ importConfig.setInUse(false);
757
+ return setCurrentView("welcome");
758
+ }}>
700
759
  Back
701
760
  </Button>}
702
761
 
703
762
  {isNewCollection && includeTemplates && currentView === "import_data_preview" &&
704
763
  <Button variant={"text"}
705
- type="button"
706
- onClick={() => {
707
- setCurrentView("import_data_mapping");
708
- }}>
764
+ type="button"
765
+ onClick={() => {
766
+ setCurrentView("import_data_mapping");
767
+ }}>
709
768
  Back
710
769
  </Button>}
711
770
 
712
- {isNewCollection && includeTemplates && currentView === "details" &&
771
+ {isNewCollection && includeTemplates && currentView === "general" &&
713
772
  <Button variant={"text"}
714
- type="button"
715
- onClick={() => setCurrentView("welcome")}>
773
+ type="button"
774
+ onClick={() => setCurrentView("welcome")}>
716
775
  Back
717
776
  </Button>}
718
777
 
719
778
  {isNewCollection && currentView === "properties" && <Button variant={"text"}
720
- type="button"
721
- color={"neutral"}
722
- onClick={() => setCurrentView("details")}>
723
- <ArrowBackIcon/>
779
+ type="button"
780
+ color={"neutral"}
781
+ onClick={() => setCurrentView("general")}>
782
+ <ArrowBackIcon />
724
783
  Back
725
784
  </Button>}
726
785
 
727
786
  <Button variant={"text"}
728
- color={"neutral"}
729
- onClick={() => {
730
- handleCancel();
731
- }}>
787
+ color={"neutral"}
788
+ onClick={() => {
789
+ handleCancel();
790
+ }}>
732
791
  Cancel
733
792
  </Button>
734
793
 
@@ -757,18 +816,18 @@ function CollectionEditorInternal<M extends Record<string, any>>({
757
816
  Next
758
817
  </Button>}
759
818
 
760
- {isNewCollection && (currentView === "details" || currentView === "properties") &&
819
+ {isNewCollection && (currentView === "general" || currentView === "properties") &&
761
820
  <LoadingButton
762
821
  variant={"filled"}
763
822
  color="primary"
764
823
  type="submit"
765
824
  loading={isSubmitting}
766
- disabled={isSubmitting || (currentView === "details" && !validValues)}
825
+ disabled={isSubmitting || (currentView === "general" && !validValues)}
767
826
  startIcon={currentView === "properties"
768
- ? <CheckIcon/>
827
+ ? <CheckIcon />
769
828
  : undefined}
770
829
  >
771
- {currentView === "details" && "Next"}
830
+ {currentView === "general" && "Next"}
772
831
  {currentView === "properties" && "Create collection"}
773
832
  </LoadingButton>}
774
833
 
@@ -794,7 +853,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
794
853
  title={<>Delete the stored config?</>}
795
854
  body={<> This will <b>not
796
855
  delete any data</b>, only
797
- the stored config, and reset to the code state.</>}/>
856
+ the stored config, and reset to the code state.</>} />
798
857
 
799
858
  </DialogContent>
800
859