@firecms/collection_editor 3.0.0-beta.13 → 3.0.0-beta.15

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 (44) hide show
  1. package/README.md +165 -1
  2. package/dist/ConfigControllerProvider.d.ts +0 -1
  3. package/dist/index.es.js +1620 -948
  4. package/dist/index.es.js.map +1 -1
  5. package/dist/index.umd.js +1616 -947
  6. package/dist/index.umd.js.map +1 -1
  7. package/dist/types/collection_editor_controller.d.ts +0 -1
  8. package/dist/types/collection_inference.d.ts +3 -0
  9. package/dist/types/config_controller.d.ts +3 -1
  10. package/dist/ui/EditorEntityAction.d.ts +2 -0
  11. package/dist/ui/collection_editor/CollectionEditorWelcomeView.d.ts +1 -1
  12. package/dist/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +1 -1
  13. package/dist/ui/collection_editor/EntityActionsEditTab.d.ts +4 -0
  14. package/dist/ui/collection_editor/EntityActionsSelectDialog.d.ts +4 -0
  15. package/dist/ui/collection_editor/PropertyTree.d.ts +2 -3
  16. package/dist/ui/collection_editor/properties/ReferencePropertyField.d.ts +2 -1
  17. package/dist/useCollectionEditorPlugin.d.ts +3 -3
  18. package/package.json +8 -9
  19. package/src/ConfigControllerProvider.tsx +0 -5
  20. package/src/types/collection_editor_controller.tsx +0 -2
  21. package/src/types/collection_inference.ts +3 -0
  22. package/src/types/config_controller.tsx +4 -1
  23. package/src/ui/EditorCollectionAction.tsx +2 -7
  24. package/src/ui/EditorEntityAction.tsx +51 -0
  25. package/src/ui/HomePageEditorCollectionAction.tsx +2 -1
  26. package/src/ui/collection_editor/CollectionDetailsForm.tsx +69 -37
  27. package/src/ui/collection_editor/CollectionEditorDialog.tsx +18 -5
  28. package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +15 -25
  29. package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +8 -6
  30. package/src/ui/collection_editor/EntityActionsEditTab.tsx +163 -0
  31. package/src/ui/collection_editor/EntityActionsSelectDialog.tsx +41 -0
  32. package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +5 -2
  33. package/src/ui/collection_editor/GetCodeDialog.tsx +5 -3
  34. package/src/ui/collection_editor/PropertyEditView.tsx +11 -3
  35. package/src/ui/collection_editor/PropertyFieldPreview.tsx +1 -0
  36. package/src/ui/collection_editor/PropertyTree.tsx +183 -139
  37. package/src/ui/collection_editor/UnsavedChangesDialog.tsx +6 -2
  38. package/src/ui/collection_editor/properties/MapPropertyField.tsx +1 -1
  39. package/src/ui/collection_editor/properties/ReferencePropertyField.tsx +5 -3
  40. package/src/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.tsx +2 -0
  41. package/src/ui/collection_editor/utils/supported_fields.tsx +1 -0
  42. package/src/ui/collection_editor/utils/update_property_for_widget.ts +9 -0
  43. package/src/useCollectionEditorPlugin.tsx +12 -7
  44. package/src/utils/collections.ts +15 -5
@@ -34,5 +34,4 @@ export interface CollectionEditorController {
34
34
  existingEntities: Entity<any>[];
35
35
  }) => void;
36
36
  configPermissions: CollectionEditorPermissionsBuilder;
37
- getPathSuggestions?: (path: string) => Promise<string[]>;
38
37
  }
@@ -1,2 +1,5 @@
1
1
  import { EntityCollection } from "@firecms/core";
2
+ /**
3
+ * This function is used to infer the configuration of a collection given its path.
4
+ */
2
5
  export type CollectionInference = (path: string, collectionGroup: boolean, parentCollectionPaths: string[]) => Promise<Partial<EntityCollection> | null>;
@@ -1,4 +1,4 @@
1
- import { CMSType, Property } from "@firecms/core";
1
+ import { CMSType, NavigationGroupMapping, Property } from "@firecms/core";
2
2
  import { PersistedCollection } from "./persisted_collection";
3
3
  /**
4
4
  * Use this controller to access the configuration that is stored externally,
@@ -17,6 +17,8 @@ export interface CollectionsConfigController {
17
17
  saveProperty: (params: SavePropertyParams) => Promise<void>;
18
18
  deleteProperty: (params: DeletePropertyParams) => Promise<void>;
19
19
  deleteCollection: (props: DeleteCollectionParams) => Promise<void>;
20
+ navigationEntries: NavigationGroupMapping[];
21
+ saveNavigationEntries: (entries: NavigationGroupMapping[]) => Promise<void>;
20
22
  }
21
23
  export type UpdateCollectionParams<M extends Record<string, any>> = {
22
24
  id: string;
@@ -0,0 +1,2 @@
1
+ import { PluginFormActionProps } from "@firecms/core";
2
+ export declare function EditorEntityAction({ path: fullPath, parentCollectionIds, collection, formContext }: PluginFormActionProps): import("react/jsx-runtime").JSX.Element;
@@ -6,7 +6,7 @@ export declare function CollectionEditorWelcomeView({ path, pathSuggestions, par
6
6
  parentCollection?: EntityCollection;
7
7
  onContinue: (importData?: object[], propertiesOrder?: string[]) => void;
8
8
  existingCollectionPaths?: string[];
9
- }): import("react/jsx-runtime").JSX.Element;
9
+ }): import("react/jsx-runtime").JSX.Element | null;
10
10
  export declare function TemplateButton({ title, subtitle, icon, onClick }: {
11
11
  title: string;
12
12
  icon: React.ReactNode;
@@ -11,7 +11,7 @@ type CollectionEditorFormProps = {
11
11
  extraIcon: React.ReactNode;
12
12
  getUser?: (uid: string) => User | null;
13
13
  getData?: () => Promise<object[]>;
14
- doCollectionInference: (collection: PersistedCollection) => Promise<Partial<EntityCollection> | null> | undefined;
14
+ doCollectionInference?: (collection: PersistedCollection) => Promise<Partial<EntityCollection> | null> | undefined;
15
15
  propertyConfigs: Record<string, PropertyConfig>;
16
16
  collectionEditable: boolean;
17
17
  };
@@ -0,0 +1,4 @@
1
+ import { PersistedCollection } from "../../types/persisted_collection";
2
+ export declare function EntityActionsEditTab({ collection, }: {
3
+ collection: PersistedCollection;
4
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,4 @@
1
+ export declare function EntityActionsSelectDialog({ open, onClose }: {
2
+ open: boolean;
3
+ onClose: (selectedActionKey?: string) => void;
4
+ }): import("react/jsx-runtime").JSX.Element;
@@ -1,6 +1,5 @@
1
1
  import React from "react";
2
2
  import { AdditionalFieldDelegate, CMSType, PropertiesOrBuilders, PropertyOrBuilder } from "@firecms/core";
3
- import { DraggableProvided } from "@hello-pangea/dnd";
4
3
  export declare const PropertyTree: React.MemoExoticComponent<(<M extends {
5
4
  [Key: string]: CMSType;
6
5
  }>({ namespace, selectedPropertyKey, onPropertyClick, properties, propertiesOrder: propertiesOrderProp, additionalFields, errors, onPropertyMove, onPropertyRemove, className, inferredPropertyKeys, collectionEditable }: {
@@ -17,13 +16,13 @@ export declare const PropertyTree: React.MemoExoticComponent<(<M extends {
17
16
  inferredPropertyKeys?: string[];
18
17
  collectionEditable: boolean;
19
18
  }) => import("react/jsx-runtime").JSX.Element)>;
20
- export declare function PropertyTreeEntry({ propertyKey, namespace, propertyOrBuilder, additionalField, provided, selectedPropertyKey, errors, onPropertyClick, onPropertyMove, onPropertyRemove, inferredPropertyKeys, collectionEditable }: {
19
+ export declare function PropertyTreeEntry({ id, propertyKey, namespace, propertyOrBuilder, additionalField, selectedPropertyKey, errors, onPropertyClick, onPropertyMove, onPropertyRemove, inferredPropertyKeys, collectionEditable }: {
20
+ id: string;
21
21
  propertyKey: string;
22
22
  namespace?: string;
23
23
  propertyOrBuilder: PropertyOrBuilder;
24
24
  additionalField?: AdditionalFieldDelegate<any>;
25
25
  selectedPropertyKey?: string;
26
- provided: DraggableProvided;
27
26
  errors: Record<string, any>;
28
27
  onPropertyClick?: (propertyKey: string, namespace?: string) => void;
29
28
  onPropertyMove?: (propertiesOrder: string[], namespace?: string) => void;
@@ -1,8 +1,9 @@
1
- export declare function ReferencePropertyField({ existing, multiple, disabled, showErrors }: {
1
+ export declare function ReferencePropertyField({ existing, multiple, disabled, showErrors, asString }: {
2
2
  existing: boolean;
3
3
  multiple: boolean;
4
4
  disabled: boolean;
5
5
  showErrors: boolean;
6
+ asString?: boolean;
6
7
  }): import("react/jsx-runtime").JSX.Element;
7
8
  export declare function CollectionsSelect({ disabled, pathPath, value, handleChange, error, ...props }: {
8
9
  disabled: boolean;
@@ -25,11 +25,11 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
25
25
  }>;
26
26
  icon: React.ReactNode;
27
27
  };
28
- getPathSuggestions?: (path?: string) => Promise<string[]>;
29
28
  collectionInference?: CollectionInference;
30
29
  getData?: (path: string, parentPaths: string[]) => Promise<object[]>;
31
30
  getUser?: (uid: string) => USER | null;
32
31
  onAnalyticsEvent?: (event: string, params?: object) => void;
32
+ includeIntroView?: boolean;
33
33
  }
34
34
  /**
35
35
  * Use this hook to initialise the Collection Editor plugin.
@@ -42,5 +42,5 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
42
42
  * @param getUser
43
43
  * @param collectionInference
44
44
  */
45
- export declare function useCollectionEditorPlugin<EC extends PersistedCollection = PersistedCollection, USER extends User = User>({ collectionConfigController, configPermissions, reservedGroups, extraView, getPathSuggestions, getUser, collectionInference, getData, onAnalyticsEvent, }: CollectionConfigControllerProps<EC, USER>): FireCMSPlugin<any, any, PersistedCollection>;
46
- export declare function IntroWidget({}: {}): import("react/jsx-runtime").JSX.Element | null;
45
+ export declare function useCollectionEditorPlugin<EC extends PersistedCollection = PersistedCollection, USER extends User = User>({ collectionConfigController, configPermissions, reservedGroups, extraView, getUser, collectionInference, getData, onAnalyticsEvent, includeIntroView }: CollectionConfigControllerProps<EC, USER>): FireCMSPlugin<any, any, PersistedCollection>;
46
+ export declare function IntroWidget(): import("react/jsx-runtime").JSX.Element | null;
package/package.json CHANGED
@@ -1,19 +1,18 @@
1
1
  {
2
2
  "name": "@firecms/collection_editor",
3
3
  "type": "module",
4
- "version": "3.0.0-beta.13",
4
+ "version": "3.0.0-beta.15",
5
5
  "main": "./dist/index.umd.js",
6
6
  "module": "./dist/index.es.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "source": "src/index.ts",
9
9
  "dependencies": {
10
- "@firecms/data_export": "^3.0.0-beta.13",
11
- "@firecms/data_import": "^3.0.0-beta.13",
12
- "@firecms/data_import_export": "^3.0.0-beta.13",
13
- "@firecms/formex": "^3.0.0-beta.13",
14
- "@firecms/schema_inference": "^3.0.0-beta.13",
15
- "@firecms/ui": "^3.0.0-beta.13",
16
- "@hello-pangea/dnd": "^17.0.0",
10
+ "@firecms/data_export": "^3.0.0-beta.15",
11
+ "@firecms/data_import": "^3.0.0-beta.15",
12
+ "@firecms/data_import_export": "^3.0.0-beta.15",
13
+ "@firecms/formex": "^3.0.0-beta.15",
14
+ "@firecms/schema_inference": "^3.0.0-beta.15",
15
+ "@firecms/ui": "^3.0.0-beta.15",
17
16
  "json5": "^2.2.3",
18
17
  "prism-react-renderer": "^2.4.1"
19
18
  },
@@ -70,5 +69,5 @@
70
69
  "publishConfig": {
71
70
  "access": "public"
72
71
  },
73
- "gitHead": "26d5e1f33a7ac00c78e45cd3cb3c397f4ba00821"
72
+ "gitHead": "0abe2ca034f396e389db595f07ef4b24b439c648"
74
73
  }
@@ -49,8 +49,6 @@ export interface ConfigControllerProviderProps {
49
49
  icon: React.ReactNode
50
50
  };
51
51
 
52
- getPathSuggestions?: (path?: string) => Promise<string[]>;
53
-
54
52
  getUser?: (uid: string) => User | null
55
53
 
56
54
  getData?: (path: string, parentPaths: string[]) => Promise<object[]>;
@@ -67,7 +65,6 @@ export const ConfigControllerProvider = React.memo(
67
65
  reservedGroups,
68
66
  collectionInference,
69
67
  extraView,
70
- getPathSuggestions,
71
68
  getUser,
72
69
  getData,
73
70
  onAnalyticsEvent,
@@ -230,7 +227,6 @@ export const ConfigControllerProvider = React.memo(
230
227
  createCollection,
231
228
  editProperty,
232
229
  configPermissions: configPermissions ?? defaultConfigPermissions,
233
- getPathSuggestions,
234
230
  }}>
235
231
 
236
232
  {children}
@@ -244,7 +240,6 @@ export const ConfigControllerProvider = React.memo(
244
240
  getData={getData}
245
241
  reservedGroups={reservedGroups}
246
242
  extraView={extraView}
247
- pathSuggestions={getPathSuggestions}
248
243
  getUser={getUser}
249
244
  handleClose={(collection) => {
250
245
  if (currentDialog?.redirect) {
@@ -41,6 +41,4 @@ export interface CollectionEditorController {
41
41
 
42
42
  configPermissions: CollectionEditorPermissionsBuilder;
43
43
 
44
- getPathSuggestions?: (path: string) => Promise<string[]>;
45
-
46
44
  }
@@ -1,3 +1,6 @@
1
1
  import { EntityCollection } from "@firecms/core";
2
2
 
3
+ /**
4
+ * This function is used to infer the configuration of a collection given its path.
5
+ */
3
6
  export type CollectionInference = (path: string, collectionGroup: boolean, parentCollectionPaths: string[]) => Promise<Partial<EntityCollection> | null>;
@@ -1,4 +1,4 @@
1
- import { CMSType, Property } from "@firecms/core";
1
+ import { CMSType, NavigationGroupMapping, Property } from "@firecms/core";
2
2
  import { PersistedCollection } from "./persisted_collection";
3
3
 
4
4
  /**
@@ -21,6 +21,9 @@ export interface CollectionsConfigController {
21
21
 
22
22
  deleteCollection: (props: DeleteCollectionParams) => Promise<void>;
23
23
 
24
+ navigationEntries: NavigationGroupMapping[];
25
+ saveNavigationEntries: (entries: NavigationGroupMapping[]) => Promise<void>;
26
+
24
27
  }
25
28
 
26
29
  export type UpdateCollectionParams<M extends Record<string, any>> = {
@@ -28,6 +28,7 @@ export function EditorCollectionAction({
28
28
  asChild={true}
29
29
  title={canEditCollection ? "Edit collection" : "You don't have permissions to edit this collection"}>
30
30
  <IconButton
31
+ size={"small"}
31
32
  color={"primary"}
32
33
  disabled={!canEditCollection}
33
34
  onClick={canEditCollection
@@ -39,7 +40,7 @@ export function EditorCollectionAction({
39
40
  existingEntities: tableController?.data ?? []
40
41
  })
41
42
  : undefined}>
42
- <SettingsIcon/>
43
+ <SettingsIcon size={"small"}/>
43
44
  </IconButton>
44
45
  </Tooltip>;
45
46
 
@@ -48,9 +49,3 @@ export function EditorCollectionAction({
48
49
  </>
49
50
 
50
51
  }
51
-
52
- function getObjectOrNull(o?: object): object | null {
53
- if (o && Object.keys(o).length === 0)
54
- return o
55
- return o ?? null;
56
- }
@@ -0,0 +1,51 @@
1
+ import { PluginFormActionProps, useAuthController, useNavigationController } from "@firecms/core";
2
+ import { IconButton, SettingsIcon, Tooltip, } from "@firecms/ui";
3
+
4
+ import { useCollectionEditorController } from "../useCollectionEditorController";
5
+ import { PersistedCollection } from "../types/persisted_collection";
6
+
7
+ export function EditorEntityAction({
8
+ path: fullPath,
9
+ parentCollectionIds,
10
+ collection,
11
+ formContext
12
+ }: PluginFormActionProps) {
13
+
14
+ const authController = useAuthController();
15
+ const navigationController = useNavigationController();
16
+ const collectionEditorController = useCollectionEditorController();
17
+
18
+ const parentCollection = navigationController.getCollectionFromIds(parentCollectionIds);
19
+
20
+ const canEditCollection = collectionEditorController.configPermissions
21
+ ? collectionEditorController.configPermissions({
22
+ user: authController.user,
23
+ collection
24
+ }).editCollections
25
+ : true;
26
+
27
+ const isDirty = formContext?.formex.dirty ?? false;
28
+
29
+ const editorButton = <Tooltip
30
+ asChild={true}
31
+ title={canEditCollection ? (isDirty ? "You need to save the document before changing the schema" : "Edit schema for this form") : "You don't have permissions to edit this collection"}>
32
+ <IconButton
33
+ color={"primary"}
34
+ disabled={!canEditCollection || isDirty}
35
+ onClick={canEditCollection
36
+ ? () => collectionEditorController?.editCollection({
37
+ id: collection.id,
38
+ fullPath,
39
+ parentCollectionIds,
40
+ parentCollection: parentCollection as PersistedCollection,
41
+ })
42
+ : undefined}>
43
+ <SettingsIcon size={"small"}/>
44
+ </IconButton>
45
+ </Tooltip>;
46
+
47
+ return <>
48
+ {editorButton}
49
+ </>
50
+
51
+ }
@@ -49,7 +49,7 @@ export function HomePageEditorCollectionAction({
49
49
  <div>
50
50
  {permissions.deleteCollections &&
51
51
  <Menu
52
- trigger={<IconButton>
52
+ trigger={<IconButton size={"small"}>
53
53
  <MoreVertIcon size={"small"}/>
54
54
  </IconButton>}
55
55
  >
@@ -70,6 +70,7 @@ export function HomePageEditorCollectionAction({
70
70
 
71
71
  {permissions.editCollections &&
72
72
  <IconButton
73
+ size={"small"}
73
74
  onClick={(event) => {
74
75
  onEditCollectionClicked();
75
76
  }}>
@@ -1,8 +1,6 @@
1
1
  import React, { useEffect, useState } from "react";
2
2
  import { EntityCollection, FieldCaption, IconForView, SearchIconsView, singular, toSnakeCase, } from "@firecms/core";
3
3
  import {
4
- Autocomplete,
5
- AutocompleteItem,
6
4
  BooleanSwitchWithLabel,
7
5
  Chip,
8
6
  CloseIcon,
@@ -163,7 +161,7 @@ export function CollectionDetailsForm({
163
161
  </FieldCaption>
164
162
  </div>
165
163
 
166
- <div className={cls("col-span-12 ", isSubcollection ? "" : "sm:col-span-8")}>
164
+ <div className={cls("col-span-12 ")}>
167
165
  <Field name={"path"}
168
166
  as={DebouncedTextField}
169
167
  label={"Path"}
@@ -179,45 +177,65 @@ export function CollectionDetailsForm({
179
177
 
180
178
  </div>
181
179
 
182
- {!isSubcollection && <div className={"col-span-12 sm:col-span-4 relative"}>
183
-
184
- <TextField error={showErrors && Boolean(errors.group)}
185
- disabled={isSubmitting}
186
- value={values.group ?? ""}
187
- autoComplete="off"
188
- onChange={(event) => setFieldValue("group", event.target.value)}
189
- name={"group"}
190
- inputRef={groupRef}
191
- label="Group"/>
192
- <Autocomplete
193
- open={autoCompleteOpen && (groupOptions ?? []).length > 0}
194
- setOpen={setAutoCompleteOpen}>
195
- {groupOptions?.map((group, index) => {
196
- return <AutocompleteItem
197
- key={index + "_" + group}
198
- onClick={() => {
199
- setAutoCompleteOpen(false);
200
- setFieldValue("group", group ?? null);
201
- }}
202
- >
203
- <div className={"flex-grow"}>
204
- {group}
205
- </div>
206
- </AutocompleteItem>;
207
- })}
208
- </Autocomplete>
209
- <FieldCaption>
210
- {showErrors && Boolean(errors.group) ? errors.group : "Group in the home page"}
211
- </FieldCaption>
212
-
213
-
214
- </div>}
180
+ {/*{!isSubcollection && <div className={"col-span-12 sm:col-span-4 relative"}>*/}
181
+
182
+ {/* <TextField error={showErrors && Boolean(errors.group)}*/}
183
+ {/* disabled={isSubmitting}*/}
184
+ {/* value={values.group ?? ""}*/}
185
+ {/* autoComplete="off"*/}
186
+ {/* onChange={(event) => setFieldValue("group", event.target.value)}*/}
187
+ {/* name={"group"}*/}
188
+ {/* inputRef={groupRef}*/}
189
+ {/* label="Group"/>*/}
190
+ {/* <Autocomplete*/}
191
+ {/* open={autoCompleteOpen && (groupOptions ?? []).length > 0}*/}
192
+ {/* setOpen={setAutoCompleteOpen}>*/}
193
+ {/* {groupOptions?.map((group, index) => {*/}
194
+ {/* return <AutocompleteItem*/}
195
+ {/* key={index + "_" + group}*/}
196
+ {/* className={"pr-6 pl-14"}*/}
197
+ {/* onClick={() => {*/}
198
+ {/* setAutoCompleteOpen(false);*/}
199
+ {/* setFieldValue("group", group ?? null);*/}
200
+ {/* }}*/}
201
+ {/* >*/}
202
+ {/* <div className={"flex-grow"}>*/}
203
+ {/* {group}*/}
204
+ {/* </div>*/}
205
+ {/* </AutocompleteItem>;*/}
206
+ {/* })}*/}
207
+ {/* </Autocomplete>*/}
208
+ {/* <FieldCaption>*/}
209
+ {/* {showErrors && Boolean(errors.group) ? errors.group : "Group in the home page"}*/}
210
+ {/* </FieldCaption>*/}
211
+
212
+
213
+ {/*</div>}*/}
215
214
 
216
215
  <LayoutModeSwitch
217
216
  className={"col-span-12"}
218
217
  value={values.openEntityMode ?? "side_panel"}
219
218
  onChange={(value) => setFieldValue("openEntityMode", value)}/>
220
219
 
220
+ <div className={"col-span-12"}>
221
+ <BooleanSwitchWithLabel
222
+ position={"start"}
223
+ size={"large"}
224
+ allowIndeterminate={true}
225
+ label={values.history === null || values.history === undefined ? "Document history revisions enabled if enabled globally" : (
226
+ values.history ? "Document history revisions ENABLED" : "Document history revisions NOT enabled"
227
+ )}
228
+ onValueChange={(v) => setFieldValue("history", v)}
229
+ value={values.history === undefined ? null : values.history}
230
+ />
231
+ <FieldCaption>
232
+ When enabled, each document in this collection will have a history of changes.
233
+ This is useful for auditing purposes. The data is stored in a subcollection of the document
234
+ in your database, called <b>__history</b>.
235
+ </FieldCaption>
236
+ </div>
237
+
238
+
221
239
  <div className={"col-span-12 mt-8"}>
222
240
  <ExpandablePanel
223
241
  expanded={advancedPanelExpanded}
@@ -324,6 +342,20 @@ export function CollectionDetailsForm({
324
342
  ))}
325
343
  </Select>
326
344
  </div>
345
+
346
+ <div className={"col-span-12"}>
347
+ <BooleanSwitchWithLabel
348
+ position={"start"}
349
+ size={"large"}
350
+ label={values.includeJsonView === undefined || values.includeJsonView ? "Include JSON view" : "Do not include JSON view"}
351
+ onValueChange={(v) => setFieldValue("includeJsonView", v)}
352
+ value={values.includeJsonView === undefined ? true : values.includeJsonView}
353
+ />
354
+ <FieldCaption>
355
+ Include the JSON representation of the document.
356
+ </FieldCaption>
357
+ </div>
358
+
327
359
  <div className={"col-span-12"}>
328
360
  <Select
329
361
  name="customId"
@@ -408,7 +440,7 @@ export function CollectionDetailsForm({
408
440
  fullWidth
409
441
  >
410
442
  <div className={"p-4 overflow-auto min-h-[200px]"}>
411
- <SearchIconsView selectedIcon={values.icon}
443
+ <SearchIconsView selectedIcon={typeof values.icon === "string" ? values.icon : undefined}
412
444
  onIconSelected={(icon: string) => {
413
445
  setIconDialogOpen(false);
414
446
  setFieldValue("icon", icon);
@@ -9,6 +9,7 @@ import {
9
9
  isPropertyBuilder,
10
10
  MapProperty,
11
11
  mergeDeep,
12
+ NavigationResult,
12
13
  Properties,
13
14
  PropertiesOrBuilders,
14
15
  Property,
@@ -17,7 +18,6 @@ import {
17
18
  randomString,
18
19
  removeInitialAndTrailingSlashes,
19
20
  removeUndefined,
20
- TopNavigationResult,
21
21
  useAuthController,
22
22
  useCustomizationController,
23
23
  useNavigationController,
@@ -57,6 +57,7 @@ import { cleanPropertiesFromImport } from "./import/clean_import_data";
57
57
  import { PersistedCollection } from "../../types/persisted_collection";
58
58
  import { Formex, FormexController, useCreateFormex } from "@firecms/formex";
59
59
  import { getFullIdPath } from "./util";
60
+ import { EntityActionsEditTab } from "./EntityActionsEditTab";
60
61
 
61
62
  export interface CollectionEditorDialogProps {
62
63
  open: boolean;
@@ -140,7 +141,8 @@ type EditorView = "welcome"
140
141
  | "properties"
141
142
  | "loading"
142
143
  | "extra_view"
143
- | "subcollections";
144
+ | "subcollections"
145
+ | "custom_actions";
144
146
 
145
147
  export function CollectionEditor(props: CollectionEditorDialogProps & {
146
148
  handleCancel: () => void,
@@ -184,7 +186,7 @@ export function CollectionEditor(props: CollectionEditorDialogProps & {
184
186
 
185
187
  const {
186
188
  groups
187
- }: TopNavigationResult = topLevelNavigation;
189
+ }: NavigationResult = topLevelNavigation;
188
190
 
189
191
  const initialCollection = collection
190
192
  ? {
@@ -325,10 +327,10 @@ function CollectionEditorInternal<M extends Record<string, any>>({
325
327
 
326
328
  };
327
329
 
328
- const doCollectionInference = (collection: PersistedCollection<any>) => {
330
+ const doCollectionInference = collectionInference ? (collection: PersistedCollection<any>) => {
329
331
  if (!collectionInference) return undefined;
330
332
  return collectionInference?.(collection.path, collection.collectionGroup ?? false, parentPaths ?? []);
331
- };
333
+ } : undefined;
332
334
 
333
335
  const inferCollectionFromData = async (newCollection: PersistedCollection<M>) => {
334
336
 
@@ -569,6 +571,9 @@ function CollectionEditorInternal<M extends Record<string, any>>({
569
571
  <Tab value={"subcollections"}>
570
572
  Additional views
571
573
  </Tab>
574
+ <Tab value={"custom_actions"}>
575
+ Custom actions
576
+ </Tab>
572
577
  </Tabs>}
573
578
 
574
579
  <form noValidate
@@ -645,6 +650,9 @@ function CollectionEditorInternal<M extends Record<string, any>>({
645
650
  </div>}
646
651
  </CollectionDetailsForm>}
647
652
 
653
+ {currentView === "custom_actions" && collection &&
654
+ <EntityActionsEditTab collection={collection}/>}
655
+
648
656
  {currentView === "subcollections" && collection &&
649
657
  <SubcollectionsEditTab
650
658
  parentCollection={parentCollection}
@@ -687,6 +695,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
687
695
  {isNewCollection && includeTemplates && currentView === "import_data_mapping" &&
688
696
  <Button variant={"text"}
689
697
  type="button"
698
+ color={"primary"}
690
699
  onClick={() => {
691
700
  importConfig.setInUse(false);
692
701
  return setCurrentView("welcome");
@@ -698,6 +707,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
698
707
  {isNewCollection && includeTemplates && currentView === "import_data_preview" &&
699
708
  <Button variant={"text"}
700
709
  type="button"
710
+ color={"primary"}
701
711
  onClick={() => {
702
712
  setCurrentView("import_data_mapping");
703
713
  }}>
@@ -707,6 +717,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
707
717
 
708
718
  {isNewCollection && includeTemplates && currentView === "details" &&
709
719
  <Button variant={"text"}
720
+ color={"primary"}
710
721
  type="button"
711
722
  onClick={() => setCurrentView("welcome")}>
712
723
  <ArrowBackIcon/>
@@ -715,12 +726,14 @@ function CollectionEditorInternal<M extends Record<string, any>>({
715
726
 
716
727
  {isNewCollection && currentView === "properties" && <Button variant={"text"}
717
728
  type="button"
729
+ color={"primary"}
718
730
  onClick={() => setCurrentView("details")}>
719
731
  <ArrowBackIcon/>
720
732
  Back
721
733
  </Button>}
722
734
 
723
735
  <Button variant={"text"}
736
+ color={"primary"}
724
737
  onClick={() => {
725
738
  handleCancel();
726
739
  }}>