@firecms/collection_editor 3.0.1 → 3.1.0-canary.24c8270
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.
- package/dist/ConfigControllerProvider.d.ts +6 -0
- package/dist/api/generateCollectionApi.d.ts +71 -0
- package/dist/api/index.d.ts +1 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.es.js +9466 -5588
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +9461 -5583
- package/dist/index.umd.js.map +1 -1
- package/dist/types/collection_editor_controller.d.ts +14 -0
- package/dist/types/collection_inference.d.ts +8 -2
- package/dist/types/config_controller.d.ts +23 -2
- package/dist/ui/AddKanbanColumnAction.d.ts +11 -0
- package/dist/ui/KanbanSetupAction.d.ts +10 -0
- package/dist/ui/collection_editor/AICollectionGeneratorPopover.d.ts +37 -0
- package/dist/ui/collection_editor/AIModifiedPathsContext.d.ts +20 -0
- package/dist/ui/collection_editor/CollectionDetailsForm.d.ts +2 -3
- package/dist/ui/collection_editor/CollectionEditorDialog.d.ts +24 -0
- package/dist/ui/collection_editor/CollectionEditorWelcomeView.d.ts +4 -1
- package/dist/ui/collection_editor/CollectionJsonImportDialog.d.ts +7 -0
- package/dist/ui/collection_editor/CollectionYupValidation.d.ts +9 -13
- package/dist/ui/collection_editor/DisplaySettingsForm.d.ts +3 -0
- package/dist/ui/collection_editor/EntityActionsEditTab.d.ts +2 -1
- package/dist/ui/collection_editor/ExtendSettingsForm.d.ts +14 -0
- package/dist/ui/collection_editor/GeneralSettingsForm.d.ts +7 -0
- package/dist/ui/collection_editor/KanbanConfigSection.d.ts +4 -0
- package/dist/ui/collection_editor/PropertyEditView.d.ts +6 -1
- package/dist/ui/collection_editor/PropertyTree.d.ts +2 -1
- package/dist/ui/collection_editor/SubcollectionsEditTab.d.ts +2 -1
- package/dist/ui/collection_editor/ViewModeSwitch.d.ts +6 -0
- package/dist/ui/collection_editor/properties/EnumPropertyField.d.ts +2 -1
- package/dist/ui/collection_editor/properties/conditions/ConditionsEditor.d.ts +10 -0
- package/dist/ui/collection_editor/properties/conditions/ConditionsPanel.d.ts +2 -0
- package/dist/ui/collection_editor/properties/conditions/EnumConditionsEditor.d.ts +6 -0
- package/dist/ui/collection_editor/properties/conditions/index.d.ts +6 -0
- package/dist/ui/collection_editor/properties/conditions/property_paths.d.ts +19 -0
- package/dist/useCollectionEditorPlugin.d.ts +7 -1
- package/dist/utils/validateCollectionJson.d.ts +22 -0
- package/package.json +15 -15
- package/src/ConfigControllerProvider.tsx +82 -47
- package/src/api/generateCollectionApi.ts +119 -0
- package/src/api/index.ts +1 -0
- package/src/index.ts +28 -1
- package/src/types/collection_editor_controller.tsx +16 -3
- package/src/types/collection_inference.ts +15 -2
- package/src/types/config_controller.tsx +27 -2
- package/src/ui/AddKanbanColumnAction.tsx +203 -0
- package/src/ui/EditorCollectionActionStart.tsx +1 -2
- package/src/ui/HomePageEditorCollectionAction.tsx +41 -13
- package/src/ui/KanbanSetupAction.tsx +38 -0
- package/src/ui/MissingReferenceWidget.tsx +1 -1
- package/src/ui/NewCollectionButton.tsx +1 -1
- package/src/ui/PropertyAddColumnComponent.tsx +1 -1
- package/src/ui/collection_editor/AICollectionGeneratorPopover.tsx +242 -0
- package/src/ui/collection_editor/AIModifiedPathsContext.tsx +88 -0
- package/src/ui/collection_editor/CollectionDetailsForm.tsx +212 -259
- package/src/ui/collection_editor/CollectionEditorDialog.tsx +237 -169
- package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +133 -67
- package/src/ui/collection_editor/CollectionJsonImportDialog.tsx +171 -0
- package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +190 -91
- package/src/ui/collection_editor/DisplaySettingsForm.tsx +333 -0
- package/src/ui/collection_editor/EntityActionsEditTab.tsx +106 -96
- package/src/ui/collection_editor/EntityActionsSelectDialog.tsx +6 -7
- package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +1 -3
- package/src/ui/collection_editor/EnumForm.tsx +147 -100
- package/src/ui/collection_editor/ExtendSettingsForm.tsx +93 -0
- package/src/ui/collection_editor/GeneralSettingsForm.tsx +337 -0
- package/src/ui/collection_editor/GetCodeDialog.tsx +57 -36
- package/src/ui/collection_editor/KanbanConfigSection.tsx +207 -0
- package/src/ui/collection_editor/LayoutModeSwitch.tsx +22 -41
- package/src/ui/collection_editor/PropertyEditView.tsx +206 -142
- package/src/ui/collection_editor/PropertyFieldPreview.tsx +1 -1
- package/src/ui/collection_editor/PropertyTree.tsx +130 -58
- package/src/ui/collection_editor/SubcollectionsEditTab.tsx +171 -162
- package/src/ui/collection_editor/UnsavedChangesDialog.tsx +0 -2
- package/src/ui/collection_editor/ViewModeSwitch.tsx +41 -0
- package/src/ui/collection_editor/properties/BlockPropertyField.tsx +0 -2
- package/src/ui/collection_editor/properties/BooleanPropertyField.tsx +1 -0
- package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +117 -35
- package/src/ui/collection_editor/properties/EnumPropertyField.tsx +28 -21
- package/src/ui/collection_editor/properties/MapPropertyField.tsx +0 -2
- package/src/ui/collection_editor/properties/MarkdownPropertyField.tsx +115 -39
- package/src/ui/collection_editor/properties/StoragePropertyField.tsx +1 -1
- package/src/ui/collection_editor/properties/conditions/ConditionsEditor.tsx +861 -0
- package/src/ui/collection_editor/properties/conditions/ConditionsPanel.tsx +28 -0
- package/src/ui/collection_editor/properties/conditions/EnumConditionsEditor.tsx +599 -0
- package/src/ui/collection_editor/properties/conditions/index.ts +6 -0
- package/src/ui/collection_editor/properties/conditions/property_paths.ts +92 -0
- package/src/ui/collection_editor/properties/validation/ValidationPanel.tsx +1 -1
- package/src/useCollectionEditorPlugin.tsx +32 -17
- 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 {
|
|
45
|
+
import { GeneralSettingsForm } from "./GeneralSettingsForm";
|
|
46
|
+
import { DisplaySettingsForm } from "./DisplaySettingsForm";
|
|
46
47
|
import { CollectionPropertiesEditorForm } from "./CollectionPropertiesEditorForm";
|
|
47
48
|
import { UnsavedChangesDialog } from "./UnsavedChangesDialog";
|
|
48
|
-
import {
|
|
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 {
|
|
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,24 @@ 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;
|
|
109
|
+
/**
|
|
110
|
+
* Optional analytics callback
|
|
111
|
+
*/
|
|
112
|
+
onAnalyticsEvent?: (event: string, params?: object) => void;
|
|
87
113
|
}
|
|
88
114
|
|
|
89
115
|
export function CollectionEditorDialog(props: CollectionEditorDialogProps) {
|
|
@@ -118,30 +144,31 @@ export function CollectionEditorDialog(props: CollectionEditorDialogProps) {
|
|
|
118
144
|
onOpenChange={(open) => !open ? handleCancel() : undefined}
|
|
119
145
|
>
|
|
120
146
|
<DialogTitle hidden>Collection editor</DialogTitle>
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
147
|
+
<AIModifiedPathsProvider>
|
|
148
|
+
{open && <CollectionEditor {...props}
|
|
149
|
+
handleCancel={handleCancel}
|
|
150
|
+
setFormDirty={setFormDirty} />}
|
|
151
|
+
|
|
152
|
+
<UnsavedChangesDialog
|
|
153
|
+
open={unsavedChangesDialogOpen}
|
|
154
|
+
handleOk={() => props.handleClose(undefined)}
|
|
155
|
+
handleCancel={() => setUnsavedChangesDialogOpen(false)}
|
|
156
|
+
body={"There are unsaved changes in this collection"} />
|
|
157
|
+
</AIModifiedPathsProvider>
|
|
131
158
|
</Dialog>
|
|
132
159
|
);
|
|
133
160
|
}
|
|
134
161
|
|
|
135
162
|
type EditorView = "welcome"
|
|
136
|
-
| "
|
|
163
|
+
| "general"
|
|
164
|
+
| "display"
|
|
137
165
|
| "import_data_mapping"
|
|
138
166
|
| "import_data_preview"
|
|
139
167
|
| "import_data_saving"
|
|
140
168
|
| "properties"
|
|
141
169
|
| "loading"
|
|
142
170
|
| "extra_view"
|
|
143
|
-
| "
|
|
144
|
-
| "custom_actions";
|
|
171
|
+
| "extend";
|
|
145
172
|
|
|
146
173
|
export function CollectionEditor(props: CollectionEditorDialogProps & {
|
|
147
174
|
handleCancel: () => void,
|
|
@@ -157,7 +184,9 @@ export function CollectionEditor(props: CollectionEditorDialogProps & {
|
|
|
157
184
|
} = navigation;
|
|
158
185
|
|
|
159
186
|
const initialValuesProp = props.initialValues;
|
|
160
|
-
const
|
|
187
|
+
const copyFromProp = props.copyFrom;
|
|
188
|
+
// Skip templates when duplicating (copyFrom is provided)
|
|
189
|
+
const includeTemplates = !copyFromProp && !initialValuesProp?.path && (props.parentCollectionIds ?? []).length === 0;
|
|
161
190
|
const collectionsInThisLevel = (props.parentCollection ? props.parentCollection.subcollections : collections) ?? [];
|
|
162
191
|
const existingPaths = collectionsInThisLevel.map(col => col.path.trim().toLowerCase());
|
|
163
192
|
const existingIds = collectionsInThisLevel.map(col => col.id?.trim().toLowerCase()).filter(Boolean) as string[];
|
|
@@ -194,25 +223,36 @@ export function CollectionEditor(props: CollectionEditorDialogProps & {
|
|
|
194
223
|
}
|
|
195
224
|
: undefined;
|
|
196
225
|
|
|
226
|
+
// Build initial values - handle copyFrom for duplication
|
|
197
227
|
const initialValues: PersistedCollection<any> = initialCollection
|
|
198
228
|
? applyPropertyConfigs(initialCollection, propertyConfigs)
|
|
199
|
-
:
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
229
|
+
: copyFromProp
|
|
230
|
+
? {
|
|
231
|
+
// When duplicating, copy all properties but clear identifiers
|
|
232
|
+
...copyFromProp,
|
|
233
|
+
id: randomString(16),
|
|
234
|
+
path: "",
|
|
235
|
+
name: "",
|
|
236
|
+
subcollections: undefined, // Don't copy subcollections
|
|
237
|
+
ownerId: authController.user?.uid ?? ""
|
|
238
|
+
}
|
|
239
|
+
: {
|
|
240
|
+
id: initialValuesProp?.path ?? randomString(16),
|
|
241
|
+
path: initialValuesProp?.path ?? "",
|
|
242
|
+
name: initialValuesProp?.name ?? "",
|
|
243
|
+
group: initialValuesProp?.group ?? "",
|
|
244
|
+
properties: {} as PropertiesOrBuilders,
|
|
245
|
+
propertiesOrder: [],
|
|
246
|
+
icon: coolIconKeys[Math.floor(Math.random() * coolIconKeys.length)],
|
|
247
|
+
ownerId: authController.user?.uid ?? ""
|
|
248
|
+
};
|
|
209
249
|
|
|
210
250
|
if (!initialLoadingCompleted) {
|
|
211
|
-
return <CircularProgressCenter/>;
|
|
251
|
+
return <CircularProgressCenter />;
|
|
212
252
|
}
|
|
213
253
|
|
|
214
254
|
if (!props.isNewCollection && (!navigation.initialised || !initialLoadingCompleted)) {
|
|
215
|
-
return <CircularProgressCenter/>;
|
|
255
|
+
return <CircularProgressCenter />;
|
|
216
256
|
}
|
|
217
257
|
|
|
218
258
|
return <CollectionEditorInternal
|
|
@@ -224,46 +264,50 @@ export function CollectionEditor(props: CollectionEditorDialogProps & {
|
|
|
224
264
|
collection={collection}
|
|
225
265
|
setCollection={setCollection}
|
|
226
266
|
groups={groups}
|
|
227
|
-
propertyConfigs={propertyConfigs}/>
|
|
267
|
+
propertyConfigs={propertyConfigs} />
|
|
228
268
|
|
|
229
269
|
}
|
|
230
270
|
|
|
231
271
|
function CollectionEditorInternal<M extends Record<string, any>>({
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
272
|
+
isNewCollection,
|
|
273
|
+
configController,
|
|
274
|
+
editedCollectionId,
|
|
275
|
+
parentCollectionIds,
|
|
276
|
+
fullPath,
|
|
277
|
+
collectionInference,
|
|
278
|
+
handleClose,
|
|
279
|
+
reservedGroups,
|
|
280
|
+
extraView,
|
|
281
|
+
handleCancel,
|
|
282
|
+
setFormDirty,
|
|
283
|
+
getUser,
|
|
284
|
+
parentCollection,
|
|
285
|
+
getData,
|
|
286
|
+
existingPaths,
|
|
287
|
+
existingIds,
|
|
288
|
+
includeTemplates,
|
|
289
|
+
collection,
|
|
290
|
+
setCollection,
|
|
291
|
+
initialValues,
|
|
292
|
+
propertyConfigs,
|
|
293
|
+
groups,
|
|
294
|
+
existingEntities,
|
|
295
|
+
initialView: initialViewProp,
|
|
296
|
+
expandKanban,
|
|
297
|
+
generateCollection,
|
|
298
|
+
onAnalyticsEvent
|
|
299
|
+
}: CollectionEditorDialogProps & {
|
|
300
|
+
handleCancel: () => void,
|
|
301
|
+
setFormDirty: (dirty: boolean) => void,
|
|
302
|
+
initialValues: PersistedCollection<M>,
|
|
303
|
+
existingPaths: string[],
|
|
304
|
+
existingIds: string[],
|
|
305
|
+
includeTemplates: boolean,
|
|
306
|
+
collection: PersistedCollection<M> | undefined,
|
|
307
|
+
setCollection: (collection: PersistedCollection<M>) => void,
|
|
308
|
+
propertyConfigs: Record<string, PropertyConfig<any>>,
|
|
309
|
+
groups: string[],
|
|
310
|
+
}
|
|
267
311
|
) {
|
|
268
312
|
|
|
269
313
|
const importConfig = useImportConfig();
|
|
@@ -273,7 +317,9 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
273
317
|
// Use this ref to store which properties have errors
|
|
274
318
|
const propertyErrorsRef = useRef({});
|
|
275
319
|
|
|
276
|
-
const initialView = isNewCollection
|
|
320
|
+
const initialView = isNewCollection
|
|
321
|
+
? (includeTemplates ? "welcome" : "general")
|
|
322
|
+
: (initialViewProp ?? "properties");
|
|
277
323
|
const [currentView, setCurrentView] = useState<EditorView>(initialView); // this view can edit either the details view or the properties one
|
|
278
324
|
|
|
279
325
|
const [error, setError] = React.useState<Error | undefined>();
|
|
@@ -303,7 +349,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
303
349
|
};
|
|
304
350
|
|
|
305
351
|
const setNextMode = () => {
|
|
306
|
-
if (currentView === "
|
|
352
|
+
if (currentView === "general") {
|
|
307
353
|
if (importConfig.inUse) {
|
|
308
354
|
setCurrentView("import_data_saving");
|
|
309
355
|
} else if (extraView) {
|
|
@@ -312,22 +358,29 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
312
358
|
setCurrentView("properties");
|
|
313
359
|
}
|
|
314
360
|
} else if (currentView === "welcome") {
|
|
315
|
-
setCurrentView("
|
|
361
|
+
setCurrentView("general");
|
|
316
362
|
} else if (currentView === "import_data_mapping") {
|
|
317
363
|
setCurrentView("import_data_preview");
|
|
318
364
|
} else if (currentView === "import_data_preview") {
|
|
319
|
-
setCurrentView("
|
|
365
|
+
setCurrentView("general");
|
|
320
366
|
} else if (currentView === "extra_view") {
|
|
321
367
|
setCurrentView("properties");
|
|
322
368
|
} else {
|
|
323
|
-
setCurrentView("
|
|
369
|
+
setCurrentView("general");
|
|
324
370
|
}
|
|
325
371
|
|
|
326
372
|
};
|
|
327
373
|
|
|
328
374
|
const doCollectionInference = collectionInference ? (collection: PersistedCollection<any>) => {
|
|
329
375
|
if (!collectionInference) return undefined;
|
|
330
|
-
return collectionInference?.(
|
|
376
|
+
return collectionInference?.(
|
|
377
|
+
collection.path,
|
|
378
|
+
collection.collectionGroup ?? false,
|
|
379
|
+
parentPaths ?? [],
|
|
380
|
+
collection.databaseId,
|
|
381
|
+
collection.initialFilter,
|
|
382
|
+
collection.initialSort
|
|
383
|
+
);
|
|
331
384
|
} : undefined;
|
|
332
385
|
|
|
333
386
|
const inferCollectionFromData = async (newCollection: PersistedCollection<M>) => {
|
|
@@ -382,6 +435,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
382
435
|
|
|
383
436
|
if (!isNewCollection) {
|
|
384
437
|
saveCollection(newCollectionState).then(() => {
|
|
438
|
+
aiModifiedPaths?.clearAllPaths();
|
|
385
439
|
formexController.resetForm();
|
|
386
440
|
handleClose(newCollectionState);
|
|
387
441
|
});
|
|
@@ -391,7 +445,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
391
445
|
if (currentView === "welcome") {
|
|
392
446
|
setNextMode();
|
|
393
447
|
formexController.resetForm({ values: newCollectionState });
|
|
394
|
-
} else if (currentView === "
|
|
448
|
+
} else if (currentView === "general") {
|
|
395
449
|
if (extraView || importConfig.inUse) {
|
|
396
450
|
formexController.resetForm({ values: newCollectionState });
|
|
397
451
|
setNextMode();
|
|
@@ -406,8 +460,8 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
406
460
|
}
|
|
407
461
|
});
|
|
408
462
|
}).finally(() => {
|
|
409
|
-
|
|
410
|
-
|
|
463
|
+
setNextMode();
|
|
464
|
+
});
|
|
411
465
|
} else {
|
|
412
466
|
formexController.resetForm({ values: newCollectionState });
|
|
413
467
|
setNextMode();
|
|
@@ -442,7 +496,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
442
496
|
const validation = (col: PersistedCollection) => {
|
|
443
497
|
|
|
444
498
|
let errors: Record<string, any> = {};
|
|
445
|
-
const schema = (currentView === "properties" || currentView === "
|
|
499
|
+
const schema = (currentView === "properties" || currentView === "extend" || currentView === "general") && YupSchema;
|
|
446
500
|
if (schema) {
|
|
447
501
|
try {
|
|
448
502
|
schema.validateSync(col, { abortEarly: false });
|
|
@@ -455,7 +509,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
455
509
|
if (currentView === "properties") {
|
|
456
510
|
errors = { ...errors, ...propertyErrorsRef.current };
|
|
457
511
|
}
|
|
458
|
-
if (currentView === "
|
|
512
|
+
if (currentView === "general") {
|
|
459
513
|
const pathError = validatePath(col.path, isNewCollection, existingPaths, col.id);
|
|
460
514
|
if (pathError) {
|
|
461
515
|
errors.path = pathError;
|
|
@@ -483,15 +537,15 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
483
537
|
submitCount
|
|
484
538
|
} = formController;
|
|
485
539
|
|
|
486
|
-
// TODO: getting data is only working in root collections with this code
|
|
487
540
|
const path = values.path;
|
|
488
541
|
const updatedFullPath = fullPath?.includes("/") ? fullPath?.split("/").slice(0, -1).join("/") + "/" + path : path; // TODO: this path is wrong
|
|
489
542
|
const pathError = validatePath(path, isNewCollection, existingPaths, values.id);
|
|
490
543
|
|
|
491
544
|
const parentPaths = !pathError && parentCollectionIds ? navigation.convertIdsToPaths(parentCollectionIds) : undefined;
|
|
492
545
|
const resolvedPath = !pathError ? navigation.resolveIdsFrom(updatedFullPath) : undefined;
|
|
546
|
+
|
|
493
547
|
const getDataWithPath = resolvedPath && getData ? async () => {
|
|
494
|
-
const data = await getData(resolvedPath, parentPaths ?? []);
|
|
548
|
+
const data = await getData!(resolvedPath, parentPaths ?? []);
|
|
495
549
|
if (existingEntities) {
|
|
496
550
|
const existingData = existingEntities.map(e => e.values);
|
|
497
551
|
data.push(...existingData);
|
|
@@ -558,7 +612,16 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
558
612
|
onImportDataSet(importData, propertiesOrder);
|
|
559
613
|
setCurrentView("import_data_mapping");
|
|
560
614
|
} else {
|
|
561
|
-
setCurrentView("
|
|
615
|
+
setCurrentView("general");
|
|
616
|
+
}
|
|
617
|
+
};
|
|
618
|
+
|
|
619
|
+
const aiModifiedPaths = useAIModifiedPaths();
|
|
620
|
+
|
|
621
|
+
const handleAIGenerated = (generatedCollection: EntityCollection, operations?: CollectionOperation[]) => {
|
|
622
|
+
formController.setValues(generatedCollection as PersistedCollection<M>);
|
|
623
|
+
if (operations && aiModifiedPaths) {
|
|
624
|
+
aiModifiedPaths.addModifiedPaths(operations);
|
|
562
625
|
}
|
|
563
626
|
};
|
|
564
627
|
|
|
@@ -566,99 +629,102 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
566
629
|
<Formex value={formController}>
|
|
567
630
|
|
|
568
631
|
<>
|
|
569
|
-
{!isNewCollection && <
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
<
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
632
|
+
{!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)}>
|
|
633
|
+
{generateCollection && (
|
|
634
|
+
<AICollectionGeneratorPopover
|
|
635
|
+
existingCollection={values}
|
|
636
|
+
onGenerated={handleAIGenerated}
|
|
637
|
+
generateCollection={generateCollection}
|
|
638
|
+
onAnalyticsEvent={onAnalyticsEvent}
|
|
639
|
+
/>
|
|
640
|
+
)}
|
|
641
|
+
<Tabs value={currentView}
|
|
642
|
+
onValueChange={(v) => setCurrentView(v as EditorView)}>
|
|
643
|
+
<Tab value={"general"}>
|
|
644
|
+
General
|
|
645
|
+
</Tab>
|
|
646
|
+
<Tab value={"display"}>
|
|
647
|
+
Display
|
|
648
|
+
</Tab>
|
|
649
|
+
<Tab value={"properties"}>
|
|
650
|
+
Properties
|
|
651
|
+
</Tab>
|
|
652
|
+
<Tab value={"extend"}>
|
|
653
|
+
Extend
|
|
654
|
+
</Tab>
|
|
655
|
+
</Tabs>
|
|
656
|
+
</div>}
|
|
585
657
|
|
|
586
658
|
<form noValidate
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
659
|
+
onSubmit={formController.handleSubmit}
|
|
660
|
+
className={cls(
|
|
661
|
+
isNewCollection ? "h-full" : "h-[calc(100%-48px)]",
|
|
662
|
+
"flex-grow flex flex-col relative")}>
|
|
591
663
|
|
|
592
664
|
{currentView === "loading" &&
|
|
593
|
-
<CircularProgressCenter/>}
|
|
665
|
+
<CircularProgressCenter />}
|
|
594
666
|
|
|
595
667
|
{currentView === "extra_view" &&
|
|
596
668
|
path &&
|
|
597
669
|
extraView?.View &&
|
|
598
|
-
<extraView.View path={path}/>}
|
|
670
|
+
<extraView.View path={path} />}
|
|
599
671
|
|
|
600
672
|
{currentView === "welcome" &&
|
|
601
673
|
<CollectionEditorWelcomeView
|
|
602
674
|
path={path}
|
|
603
675
|
onContinue={onWelcomeScreenContinue}
|
|
604
676
|
existingCollectionPaths={existingPaths}
|
|
605
|
-
parentCollection={parentCollection}
|
|
677
|
+
parentCollection={parentCollection}
|
|
678
|
+
generateCollection={generateCollection}
|
|
679
|
+
onAnalyticsEvent={onAnalyticsEvent} />}
|
|
606
680
|
|
|
607
681
|
{currentView === "import_data_mapping" && importConfig &&
|
|
608
682
|
<CollectionEditorImportMapping importConfig={importConfig}
|
|
609
|
-
|
|
610
|
-
|
|
683
|
+
collectionEditable={collectionEditable}
|
|
684
|
+
propertyConfigs={propertyConfigs} />}
|
|
611
685
|
|
|
612
686
|
{currentView === "import_data_preview" && importConfig &&
|
|
613
687
|
<CollectionEditorImportDataPreview importConfig={importConfig}
|
|
614
|
-
|
|
615
|
-
|
|
688
|
+
properties={values.properties as Properties}
|
|
689
|
+
propertiesOrder={values.propertiesOrder as string[]} />}
|
|
616
690
|
|
|
617
691
|
{currentView === "import_data_saving" && importConfig &&
|
|
618
692
|
<ImportSaveInProgress importConfig={importConfig}
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
693
|
+
collection={values}
|
|
694
|
+
path={path}
|
|
695
|
+
onImportSuccess={async (importedCollection) => {
|
|
696
|
+
snackbarController.open({
|
|
697
|
+
type: "info",
|
|
698
|
+
message: "Data imported successfully"
|
|
699
|
+
});
|
|
700
|
+
await saveCollection(values);
|
|
701
|
+
handleClose(importedCollection);
|
|
702
|
+
}}
|
|
629
703
|
/>}
|
|
630
704
|
|
|
631
|
-
{currentView === "
|
|
632
|
-
<
|
|
705
|
+
{currentView === "general" &&
|
|
706
|
+
<GeneralSettingsForm
|
|
633
707
|
existingPaths={existingPaths}
|
|
634
708
|
existingIds={existingIds}
|
|
635
|
-
groups={groups}
|
|
636
|
-
parentCollectionIds={parentCollectionIds}
|
|
637
709
|
parentCollection={parentCollection}
|
|
638
|
-
isNewCollection={isNewCollection}
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
</div>}
|
|
649
|
-
</CollectionDetailsForm>}
|
|
650
|
-
|
|
651
|
-
{currentView === "custom_actions" && collection &&
|
|
652
|
-
<EntityActionsEditTab collection={collection}/>}
|
|
653
|
-
|
|
654
|
-
{currentView === "subcollections" && collection &&
|
|
655
|
-
<SubcollectionsEditTab
|
|
710
|
+
isNewCollection={isNewCollection} />
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
{currentView === "display" &&
|
|
714
|
+
<DisplaySettingsForm expandKanban={expandKanban} />
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
{currentView === "extend" && collection &&
|
|
718
|
+
<ExtendSettingsForm
|
|
719
|
+
collection={collection}
|
|
656
720
|
parentCollection={parentCollection}
|
|
657
721
|
configController={configController}
|
|
658
|
-
getUser={getUser}
|
|
659
722
|
collectionInference={collectionInference}
|
|
723
|
+
getUser={getUser}
|
|
660
724
|
parentCollectionIds={parentCollectionIds}
|
|
661
|
-
|
|
725
|
+
isMergedCollection={!isNewCollection && isMergedCollection}
|
|
726
|
+
onResetToCode={() => setDeleteRequested(true)} />
|
|
727
|
+
}
|
|
662
728
|
|
|
663
729
|
{currentView === "properties" &&
|
|
664
730
|
<CollectionPropertiesEditorForm
|
|
@@ -683,52 +749,52 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
683
749
|
color={"primary"}
|
|
684
750
|
onClick={() => setCurrentView("extra_view")}>
|
|
685
751
|
{extraView.icon}
|
|
686
|
-
</IconButton>}/>
|
|
752
|
+
</IconButton>} />
|
|
687
753
|
}
|
|
688
754
|
|
|
689
755
|
<DialogActions
|
|
690
756
|
position={"absolute"}>
|
|
691
|
-
{error && <ErrorView error={error}/>}
|
|
757
|
+
{error && <ErrorView error={error} />}
|
|
692
758
|
|
|
693
759
|
{isNewCollection && includeTemplates && currentView === "import_data_mapping" &&
|
|
694
760
|
<Button variant={"text"}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
761
|
+
type="button"
|
|
762
|
+
onClick={() => {
|
|
763
|
+
importConfig.setInUse(false);
|
|
764
|
+
return setCurrentView("welcome");
|
|
765
|
+
}}>
|
|
700
766
|
Back
|
|
701
767
|
</Button>}
|
|
702
768
|
|
|
703
769
|
{isNewCollection && includeTemplates && currentView === "import_data_preview" &&
|
|
704
770
|
<Button variant={"text"}
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
771
|
+
type="button"
|
|
772
|
+
onClick={() => {
|
|
773
|
+
setCurrentView("import_data_mapping");
|
|
774
|
+
}}>
|
|
709
775
|
Back
|
|
710
776
|
</Button>}
|
|
711
777
|
|
|
712
|
-
{isNewCollection && includeTemplates && currentView === "
|
|
778
|
+
{isNewCollection && includeTemplates && currentView === "general" &&
|
|
713
779
|
<Button variant={"text"}
|
|
714
|
-
|
|
715
|
-
|
|
780
|
+
type="button"
|
|
781
|
+
onClick={() => setCurrentView("welcome")}>
|
|
716
782
|
Back
|
|
717
783
|
</Button>}
|
|
718
784
|
|
|
719
785
|
{isNewCollection && currentView === "properties" && <Button variant={"text"}
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
<ArrowBackIcon/>
|
|
786
|
+
type="button"
|
|
787
|
+
color={"neutral"}
|
|
788
|
+
onClick={() => setCurrentView("general")}>
|
|
789
|
+
<ArrowBackIcon />
|
|
724
790
|
Back
|
|
725
791
|
</Button>}
|
|
726
792
|
|
|
727
793
|
<Button variant={"text"}
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
794
|
+
color={"neutral"}
|
|
795
|
+
onClick={() => {
|
|
796
|
+
handleCancel();
|
|
797
|
+
}}>
|
|
732
798
|
Cancel
|
|
733
799
|
</Button>
|
|
734
800
|
|
|
@@ -757,18 +823,18 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
757
823
|
Next
|
|
758
824
|
</Button>}
|
|
759
825
|
|
|
760
|
-
{isNewCollection && (currentView === "
|
|
826
|
+
{isNewCollection && (currentView === "general" || currentView === "properties") &&
|
|
761
827
|
<LoadingButton
|
|
762
828
|
variant={"filled"}
|
|
763
829
|
color="primary"
|
|
764
830
|
type="submit"
|
|
765
831
|
loading={isSubmitting}
|
|
766
|
-
disabled={isSubmitting || (currentView === "
|
|
832
|
+
disabled={isSubmitting || (currentView === "general" && !validValues)}
|
|
767
833
|
startIcon={currentView === "properties"
|
|
768
|
-
? <CheckIcon/>
|
|
834
|
+
? <CheckIcon />
|
|
769
835
|
: undefined}
|
|
770
836
|
>
|
|
771
|
-
{currentView === "
|
|
837
|
+
{currentView === "general" && "Next"}
|
|
772
838
|
{currentView === "properties" && "Create collection"}
|
|
773
839
|
</LoadingButton>}
|
|
774
840
|
|
|
@@ -794,7 +860,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
794
860
|
title={<>Delete the stored config?</>}
|
|
795
861
|
body={<> This will <b>not
|
|
796
862
|
delete any data</b>, only
|
|
797
|
-
the stored config, and reset to the code state.</>}/>
|
|
863
|
+
the stored config, and reset to the code state.</>} />
|
|
798
864
|
|
|
799
865
|
</DialogContent>
|
|
800
866
|
|
|
@@ -808,7 +874,9 @@ function applyPropertyConfigs<M extends Record<string, any> = any>(collection: P
|
|
|
808
874
|
const propertiesResult: PropertiesOrBuilders<any> = {};
|
|
809
875
|
if (properties) {
|
|
810
876
|
Object.keys(properties).forEach((key) => {
|
|
811
|
-
|
|
877
|
+
const prop = properties[key];
|
|
878
|
+
if (prop == null) return;
|
|
879
|
+
propertiesResult[key] = applyPropertiesConfig(prop as PropertyOrBuilder, propertyConfigs);
|
|
812
880
|
});
|
|
813
881
|
}
|
|
814
882
|
|
|
@@ -820,7 +888,7 @@ function applyPropertyConfigs<M extends Record<string, any> = any>(collection: P
|
|
|
820
888
|
|
|
821
889
|
function applyPropertiesConfig(property: PropertyOrBuilder, propertyConfigs: Record<string, PropertyConfig<any>>) {
|
|
822
890
|
let internalProperty = property;
|
|
823
|
-
if (propertyConfigs && typeof internalProperty === "object" && internalProperty.propertyConfig) {
|
|
891
|
+
if (propertyConfigs && internalProperty && typeof internalProperty === "object" && internalProperty.propertyConfig) {
|
|
824
892
|
const propertyConfig = propertyConfigs[internalProperty.propertyConfig];
|
|
825
893
|
if (propertyConfig && isPropertyBuilder(propertyConfig.property)) {
|
|
826
894
|
internalProperty = propertyConfig.property;
|