@firecms/collection_editor 3.0.0-canary.26 → 3.0.0-canary.261

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 (88) 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 +10742 -4787
  6. package/dist/index.es.js.map +1 -1
  7. package/dist/index.umd.js +11412 -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/CollectionEditorImportMapping.d.ts +7 -0
  29. package/dist/ui/collection_editor/properties/MarkdownPropertyField.d.ts +4 -0
  30. package/dist/ui/collection_editor/properties/ReferencePropertyField.d.ts +2 -1
  31. package/dist/ui/collection_editor/properties/StringPropertyField.d.ts +1 -1
  32. package/dist/useCollectionEditorPlugin.d.ts +8 -11
  33. package/dist/utils/collections.d.ts +6 -0
  34. package/package.json +23 -35
  35. package/src/ConfigControllerProvider.tsx +64 -66
  36. package/src/index.ts +1 -0
  37. package/src/types/collection_editor_controller.tsx +6 -5
  38. package/src/types/collection_inference.ts +4 -1
  39. package/src/types/config_controller.tsx +4 -1
  40. package/src/types/config_permissions.ts +1 -1
  41. package/src/types/persisted_collection.ts +2 -3
  42. package/src/ui/CollectionViewHeaderAction.tsx +10 -5
  43. package/src/ui/EditorCollectionAction.tsx +12 -70
  44. package/src/ui/EditorCollectionActionStart.tsx +87 -0
  45. package/src/ui/EditorEntityAction.tsx +51 -0
  46. package/src/ui/HomePageEditorCollectionAction.tsx +21 -14
  47. package/src/ui/NewCollectionButton.tsx +1 -1
  48. package/src/ui/NewCollectionCard.tsx +3 -3
  49. package/src/ui/PropertyAddColumnComponent.tsx +11 -6
  50. package/src/ui/collection_editor/CollectionDetailsForm.tsx +157 -50
  51. package/src/ui/collection_editor/CollectionEditorDialog.tsx +117 -37
  52. package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +23 -32
  53. package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +46 -41
  54. package/src/ui/collection_editor/EntityActionsEditTab.tsx +163 -0
  55. package/src/ui/collection_editor/EntityActionsSelectDialog.tsx +41 -0
  56. package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +11 -7
  57. package/src/ui/collection_editor/EnumForm.tsx +11 -7
  58. package/src/ui/collection_editor/GetCodeDialog.tsx +60 -28
  59. package/src/ui/collection_editor/LayoutModeSwitch.tsx +54 -0
  60. package/src/ui/collection_editor/PropertyEditView.tsx +264 -78
  61. package/src/ui/collection_editor/PropertyFieldPreview.tsx +8 -10
  62. package/src/ui/collection_editor/PropertyTree.tsx +184 -138
  63. package/src/ui/collection_editor/SubcollectionsEditTab.tsx +26 -19
  64. package/src/ui/collection_editor/UnsavedChangesDialog.tsx +9 -7
  65. package/src/ui/collection_editor/import/CollectionEditorImportDataPreview.tsx +33 -9
  66. package/src/ui/collection_editor/import/CollectionEditorImportMapping.tsx +42 -9
  67. package/src/ui/collection_editor/properties/BlockPropertyField.tsx +32 -20
  68. package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +54 -47
  69. package/src/ui/collection_editor/properties/EnumPropertyField.tsx +3 -1
  70. package/src/ui/collection_editor/properties/MapPropertyField.tsx +8 -7
  71. package/src/ui/collection_editor/properties/MarkdownPropertyField.tsx +139 -0
  72. package/src/ui/collection_editor/properties/ReferencePropertyField.tsx +7 -3
  73. package/src/ui/collection_editor/properties/RepeatPropertyField.tsx +0 -1
  74. package/src/ui/collection_editor/properties/StoragePropertyField.tsx +34 -19
  75. package/src/ui/collection_editor/properties/StringPropertyField.tsx +1 -10
  76. package/src/ui/collection_editor/properties/UrlPropertyField.tsx +1 -0
  77. package/src/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.tsx +2 -0
  78. package/src/ui/collection_editor/properties/validation/ValidationPanel.tsx +2 -2
  79. package/src/ui/collection_editor/templates/pages_template.ts +1 -6
  80. package/src/ui/collection_editor/utils/strings.ts +13 -6
  81. package/src/ui/collection_editor/utils/supported_fields.tsx +1 -0
  82. package/src/ui/collection_editor/utils/update_property_for_widget.ts +9 -0
  83. package/src/useCollectionEditorPlugin.tsx +38 -32
  84. package/src/utils/collections.ts +46 -0
  85. package/dist/ui/RootCollectionSuggestions.d.ts +0 -3
  86. package/dist/ui/collection_editor/PropertySelectItem.d.ts +0 -8
  87. package/src/ui/RootCollectionSuggestions.tsx +0 -63
  88. package/src/ui/collection_editor/PropertySelectItem.tsx +0 -32
@@ -1,8 +1,9 @@
1
- import React, { PropsWithChildren, useCallback, useEffect } from "react";
1
+ import React, { PropsWithChildren, useCallback } from "react";
2
2
  import equal from "react-fast-compare"
3
3
 
4
4
  import { CollectionsConfigController } from "./types/config_controller";
5
5
  import {
6
+ Entity,
6
7
  Property,
7
8
  useCustomizationController,
8
9
  useNavigationController,
@@ -48,9 +49,7 @@ export interface ConfigControllerProviderProps {
48
49
  icon: React.ReactNode
49
50
  };
50
51
 
51
- pathSuggestions?: (path?: string) => Promise<string[]>;
52
-
53
- getUser: (uid: string) => User | null
52
+ getUser?: (uid: string) => User | null
54
53
 
55
54
  getData?: (path: string, parentPaths: string[]) => Promise<object[]>;
56
55
 
@@ -66,10 +65,9 @@ export const ConfigControllerProvider = React.memo(
66
65
  reservedGroups,
67
66
  collectionInference,
68
67
  extraView,
69
- pathSuggestions,
70
68
  getUser,
71
69
  getData,
72
- onAnalyticsEvent
70
+ onAnalyticsEvent,
73
71
  }: PropsWithChildren<ConfigControllerProviderProps>) {
74
72
 
75
73
  const navigation = useNavigationController();
@@ -77,20 +75,6 @@ export const ConfigControllerProvider = React.memo(
77
75
  const snackbarController = useSnackbarController();
78
76
  const { propertyConfigs } = useCustomizationController();
79
77
 
80
- const {
81
- collections
82
- } = navigation;
83
- const existingPaths = (collections ?? []).map(col => col.path.trim().toLowerCase());
84
-
85
- const [rootPathSuggestions, setRootPathSuggestions] = React.useState<string[] | undefined>();
86
- useEffect(() => {
87
- if (pathSuggestions) {
88
- pathSuggestions().then((paths) => {
89
- setRootPathSuggestions(paths.filter(p => !existingPaths.includes(p.trim().toLowerCase())));
90
- });
91
- }
92
- }, [pathSuggestions]);
93
-
94
78
  const [currentDialog, setCurrentDialog] = React.useState<{
95
79
  isNewCollection: boolean,
96
80
  parentCollection?: PersistedCollection,
@@ -102,7 +86,8 @@ export const ConfigControllerProvider = React.memo(
102
86
  group?: string,
103
87
  name?: string
104
88
  },
105
- redirect: boolean
89
+ redirect: boolean,
90
+ existingEntities?: Entity<any>[]
106
91
  }>();
107
92
 
108
93
  const [currentPropertyDialog, setCurrentPropertyDialog] = React.useState<{
@@ -115,6 +100,7 @@ export const ConfigControllerProvider = React.memo(
115
100
  fullPath?: string,
116
101
  parentCollectionIds: string[],
117
102
  collectionEditable: boolean;
103
+ existingEntities?: Entity<any>[]
118
104
  }>();
119
105
 
120
106
  const defaultConfigPermissions: CollectionEditorPermissionsBuilder = useCallback(() => ({
@@ -123,46 +109,57 @@ export const ConfigControllerProvider = React.memo(
123
109
  deleteCollections: true
124
110
  }), []);
125
111
 
126
- const editCollection = useCallback(({
127
- id,
128
- fullPath,
129
- parentCollectionIds,
130
- parentCollection
131
- }: {
112
+ const editCollection = ({
113
+ id,
114
+ fullPath,
115
+ parentCollectionIds,
116
+ parentCollection,
117
+ existingEntities
118
+ }: {
132
119
  id?: string,
133
120
  fullPath?: string,
134
121
  parentCollectionIds: string[],
135
- parentCollection?: PersistedCollection
122
+ parentCollection?: PersistedCollection,
123
+ existingEntities?: Entity<any>[]
136
124
  }) => {
137
125
  console.debug("Edit collection", id, fullPath, parentCollectionIds, parentCollection);
138
- onAnalyticsEvent?.("edit_collection", { id, fullPath });
126
+ onAnalyticsEvent?.("edit_collection", {
127
+ id,
128
+ fullPath
129
+ });
139
130
  setCurrentDialog({
140
131
  editedCollectionId: id,
141
132
  fullPath,
142
133
  parentCollectionIds,
143
134
  isNewCollection: false,
144
135
  parentCollection,
145
- redirect: false
136
+ redirect: false,
137
+ existingEntities
146
138
  });
147
- }, []);
139
+ };
148
140
 
149
- const editProperty = useCallback(({
150
- propertyKey,
151
- property,
152
- editedCollectionId,
153
- currentPropertiesOrder,
154
- parentCollectionIds,
155
- collection
156
- }: {
141
+ const editProperty = ({
142
+ propertyKey,
143
+ property,
144
+ editedCollectionId,
145
+ currentPropertiesOrder,
146
+ parentCollectionIds,
147
+ collection,
148
+ existingEntities
149
+ }: {
157
150
  propertyKey?: string,
158
151
  property?: Property,
159
152
  currentPropertiesOrder?: string[],
160
153
  editedCollectionId: string,
161
154
  parentCollectionIds: string[],
162
155
  collection: PersistedCollection,
156
+ existingEntities?: Entity<any>[]
163
157
  }) => {
164
158
  console.debug("Edit property", propertyKey, property, editedCollectionId, currentPropertiesOrder, parentCollectionIds, collection);
165
- onAnalyticsEvent?.("edit_property", { propertyKey, editedCollectionId });
159
+ onAnalyticsEvent?.("edit_property", {
160
+ propertyKey,
161
+ editedCollectionId
162
+ });
166
163
  // namespace is all the path until the last dot
167
164
  const namespace = propertyKey && propertyKey.includes(".")
168
165
  ? propertyKey.substring(0, propertyKey.lastIndexOf("."))
@@ -175,19 +172,20 @@ export const ConfigControllerProvider = React.memo(
175
172
  property,
176
173
  namespace,
177
174
  currentPropertiesOrder,
178
- editedCollectionId: editedCollectionId,
175
+ editedCollectionId,
179
176
  parentCollectionIds,
180
- collectionEditable: collection?.editable ?? false
177
+ collectionEditable: collection?.editable ?? false,
178
+ existingEntities
181
179
  });
182
- }, []);
180
+ };
183
181
 
184
- const createCollection = React.useCallback(({
185
- parentCollectionIds,
186
- parentCollection,
187
- initialValues,
188
- redirect,
189
- sourceClick
190
- }: {
182
+ const createCollection = ({
183
+ parentCollectionIds,
184
+ parentCollection,
185
+ initialValues,
186
+ redirect,
187
+ sourceClick
188
+ }: {
191
189
  parentCollectionIds: string[],
192
190
  parentCollection?: PersistedCollection
193
191
  initialValues?: {
@@ -198,8 +196,20 @@ export const ConfigControllerProvider = React.memo(
198
196
  redirect: boolean,
199
197
  sourceClick?: string
200
198
  }) => {
201
- console.debug("Create collection", { parentCollectionIds, parentCollection, initialValues, redirect, sourceClick });
202
- onAnalyticsEvent?.("create_collection", { parentCollectionIds, parentCollection, initialValues, redirect, sourceClick });
199
+ console.debug("Create collection", {
200
+ parentCollectionIds,
201
+ parentCollection,
202
+ initialValues,
203
+ redirect,
204
+ sourceClick
205
+ });
206
+ onAnalyticsEvent?.("create_collection", {
207
+ parentCollectionIds,
208
+ parentCollection,
209
+ initialValues,
210
+ redirect,
211
+ sourceClick
212
+ });
203
213
  setCurrentDialog({
204
214
  isNewCollection: true,
205
215
  parentCollectionIds,
@@ -207,17 +217,7 @@ export const ConfigControllerProvider = React.memo(
207
217
  initialValues,
208
218
  redirect
209
219
  });
210
- }, []);
211
-
212
- const getPathSuggestions = !pathSuggestions
213
- ? undefined
214
- : (path?: string) => {
215
- if (!path && rootPathSuggestions)
216
- return Promise.resolve(rootPathSuggestions);
217
- else {
218
- return pathSuggestions?.(path);
219
- }
220
- }
220
+ };
221
221
 
222
222
  return (
223
223
  <ConfigControllerContext.Provider value={collectionConfigController}>
@@ -227,7 +227,6 @@ export const ConfigControllerProvider = React.memo(
227
227
  createCollection,
228
228
  editProperty,
229
229
  configPermissions: configPermissions ?? defaultConfigPermissions,
230
- rootPathSuggestions
231
230
  }}>
232
231
 
233
232
  {children}
@@ -241,7 +240,6 @@ export const ConfigControllerProvider = React.memo(
241
240
  getData={getData}
242
241
  reservedGroups={reservedGroups}
243
242
  extraView={extraView}
244
- pathSuggestions={getPathSuggestions}
245
243
  getUser={getUser}
246
244
  handleClose={(collection) => {
247
245
  if (currentDialog?.redirect) {
@@ -265,7 +263,7 @@ export const ConfigControllerProvider = React.memo(
265
263
  getData={getData && currentPropertyDialog?.editedCollectionId
266
264
  ? () => {
267
265
  console.debug("get data for property", currentPropertyDialog?.editedCollectionId);
268
- const resolvedPath = navigation.resolveAliasesFrom(currentPropertyDialog.editedCollectionId!)
266
+ const resolvedPath = navigation.resolveIdsFrom(currentPropertyDialog.editedCollectionId!)
269
267
  return getData(resolvedPath, []);
270
268
  }
271
269
  : undefined}
package/src/index.ts CHANGED
@@ -12,6 +12,7 @@ export {
12
12
  export {
13
13
  editableProperty, removeNonEditableProperties
14
14
  } from "./utils/entities";
15
+ export * from "./utils/collections";
15
16
 
16
17
  export type {
17
18
  CollectionsConfigController, DeleteCollectionParams, SaveCollectionParams, UpdateCollectionParams
@@ -1,5 +1,6 @@
1
+ import React from "react";
1
2
  import { CollectionEditorPermissionsBuilder } from "./config_permissions";
2
- import { Property } from "@firecms/core";
3
+ import { Entity, Property } from "@firecms/core";
3
4
  import { PersistedCollection } from "./persisted_collection";
4
5
 
5
6
  /**
@@ -12,7 +13,8 @@ export interface CollectionEditorController {
12
13
  id?: string,
13
14
  fullPath?: string,
14
15
  parentCollectionIds: string[],
15
- parentCollection?: PersistedCollection
16
+ parentCollection?: PersistedCollection,
17
+ existingEntities?: Entity<any>[]
16
18
  }) => void;
17
19
 
18
20
  createCollection: (props: {
@@ -33,11 +35,10 @@ export interface CollectionEditorController {
33
35
  currentPropertiesOrder?: string[],
34
36
  editedCollectionId: string,
35
37
  parentCollectionIds: string[],
36
- collection: PersistedCollection
38
+ collection: PersistedCollection,
39
+ existingEntities: Entity<any>[]
37
40
  }) => void;
38
41
 
39
42
  configPermissions: CollectionEditorPermissionsBuilder;
40
43
 
41
- rootPathSuggestions?: string[];
42
-
43
44
  }
@@ -1,3 +1,6 @@
1
1
  import { EntityCollection } from "@firecms/core";
2
2
 
3
- export type CollectionInference = (path: string, collectionGroup: boolean, parentCollectionIds: string[]) => Promise<Partial<EntityCollection> | null>;
3
+ /**
4
+ * This function is used to infer the configuration of a collection given its path.
5
+ */
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>> = {
@@ -1,6 +1,6 @@
1
1
  import { EntityCollection } from "@firecms/core";
2
2
 
3
- export type CollectionEditorPermissionsBuilder<UserType = any, EC extends EntityCollection = EntityCollection> = (params: { user: UserType | null, collection?: EC }) => CollectionEditorPermissions;
3
+ export type CollectionEditorPermissionsBuilder<USER = any, EC extends EntityCollection = EntityCollection> = (params: { user: USER | null, collection?: EC }) => CollectionEditorPermissions;
4
4
 
5
5
  export type CollectionEditorPermissions = {
6
6
  /**
@@ -1,8 +1,7 @@
1
1
  import { EntityCollection, User } from "@firecms/core";
2
2
 
3
- export type PersistedCollection<M extends Record<string, any> = any, UserType extends User = User>
4
- = Omit<EntityCollection<M, UserType>, "subcollections"> & {
5
- // properties: Properties<M>;
3
+ export type PersistedCollection<M extends Record<string, any> = any, USER extends User = User>
4
+ = Omit<EntityCollection<M, USER>, "subcollections"> & {
6
5
  ownerId?: string;
7
6
  subcollections?: PersistedCollection<any, any>[];
8
7
  editable?: boolean;
@@ -1,4 +1,4 @@
1
- import { ResolvedProperty } from "@firecms/core";
1
+ import { EntityTableController, ResolvedProperty } from "@firecms/core";
2
2
  import { IconButton, SettingsIcon, Tooltip } from "@firecms/ui";
3
3
  import React from "react";
4
4
  import { useCollectionEditorController } from "../useCollectionEditorController";
@@ -10,7 +10,8 @@ export function CollectionViewHeaderAction({
10
10
  property,
11
11
  fullPath,
12
12
  parentCollectionIds,
13
- collection
13
+ collection,
14
+ tableController
14
15
  }: {
15
16
  property: ResolvedProperty,
16
17
  propertyKey: string,
@@ -18,21 +19,25 @@ export function CollectionViewHeaderAction({
18
19
  fullPath: string,
19
20
  parentCollectionIds: string[],
20
21
  collection: PersistedCollection;
22
+ tableController: EntityTableController;
21
23
  }) {
22
24
 
23
25
  const collectionEditorController = useCollectionEditorController();
24
26
 
25
27
  return (
26
- <Tooltip title={"Edit"}>
28
+ <Tooltip
29
+ asChild={true}
30
+ title={"Edit"}>
27
31
  <IconButton
28
- className={onHover ? "bg-white dark:bg-gray-950" : "hidden"}
32
+ className={onHover ? "bg-white dark:bg-surface-950" : "hidden"}
29
33
  onClick={() => {
30
34
  collectionEditorController.editProperty({
31
35
  propertyKey,
32
36
  property,
33
37
  editedCollectionId: collection.id,
34
38
  parentCollectionIds,
35
- collection
39
+ collection,
40
+ existingEntities: tableController.data ?? []
36
41
  });
37
42
  }}
38
43
  size={"small"}>
@@ -1,16 +1,7 @@
1
- import equal from "react-fast-compare"
2
-
3
- import {
4
- CollectionActionsProps,
5
- mergeDeep,
6
- useAuthController,
7
- useNavigationController,
8
- useSnackbarController
9
- } from "@firecms/core";
10
- import { Button, IconButton, SaveIcon, SettingsIcon, Tooltip, UndoIcon, } from "@firecms/ui";
1
+ import { CollectionActionsProps, useAuthController, useNavigationController } from "@firecms/core";
2
+ import { IconButton, SettingsIcon, Tooltip, } from "@firecms/ui";
11
3
 
12
4
  import { useCollectionEditorController } from "../useCollectionEditorController";
13
- import { useCollectionsConfigController } from "../useCollectionsConfigController";
14
5
  import { PersistedCollection } from "../types/persisted_collection";
15
6
 
16
7
  export function EditorCollectionAction({
@@ -23,8 +14,6 @@ export function EditorCollectionAction({
23
14
  const authController = useAuthController();
24
15
  const navigationController = useNavigationController();
25
16
  const collectionEditorController = useCollectionEditorController();
26
- const configController = useCollectionsConfigController();
27
- const snackbarController = useSnackbarController();
28
17
 
29
18
  const parentCollection = navigationController.getCollectionFromIds(parentCollectionIds);
30
19
 
@@ -35,75 +24,28 @@ export function EditorCollectionAction({
35
24
  }).editCollections
36
25
  : true;
37
26
 
38
- let saveDefaultFilterButton = null;
39
- if (!equal(getObjectOrNull(tableController.filterValues), getObjectOrNull(collection.initialFilter)) ||
40
- !equal(getObjectOrNull(tableController.sortBy), getObjectOrNull(collection.initialSort))) {
41
- saveDefaultFilterButton = <>
42
- {(collection.initialFilter || collection.initialSort) && <Tooltip
43
- title={"Reset to default filter and sort"}>
44
- <Button
45
- color={"primary"}
46
- size={"small"}
47
- variant={"text"}
48
- onClick={() => {
49
- tableController.clearFilter?.();
50
- if (collection?.initialFilter)
51
- tableController.setFilterValues?.(collection?.initialFilter);
52
- if (collection?.initialSort)
53
- tableController.setSortBy?.(collection?.initialSort);
54
- }}>
55
- <UndoIcon/>
56
- </Button>
57
- </Tooltip>}
58
-
59
- <Tooltip
60
- title={tableController.sortBy || tableController.filterValues ? "Save default filter and sort" : "Clear default filter and sort"}>
61
- <Button
62
- color={"primary"}
63
- size={"small"}
64
- variant={"outlined"}
65
- onClick={() => configController
66
- ?.saveCollection({
67
- id: collection.id,
68
- parentCollectionIds,
69
- collectionData: mergeDeep(collection as PersistedCollection,
70
- {
71
- initialFilter: tableController.filterValues ?? null,
72
- initialSort: tableController.sortBy ?? null
73
- })
74
- }).then(() => {
75
- snackbarController.open({
76
- type: "success",
77
- message: "Default config saved"
78
- });
79
- })}>
80
- <SaveIcon/>
81
- </Button>
82
- </Tooltip>
83
- </>;
84
- }
85
-
86
27
  const editorButton = <Tooltip
28
+ asChild={true}
87
29
  title={canEditCollection ? "Edit collection" : "You don't have permissions to edit this collection"}>
88
30
  <IconButton
31
+ size={"small"}
89
32
  color={"primary"}
90
33
  disabled={!canEditCollection}
91
34
  onClick={canEditCollection
92
- ? () => collectionEditorController?.editCollection({ id: collection.id, fullPath, parentCollectionIds, parentCollection: parentCollection as PersistedCollection })
35
+ ? () => collectionEditorController?.editCollection({
36
+ id: collection.id,
37
+ fullPath,
38
+ parentCollectionIds,
39
+ parentCollection: parentCollection as PersistedCollection,
40
+ existingEntities: tableController?.data ?? []
41
+ })
93
42
  : undefined}>
94
- <SettingsIcon/>
43
+ <SettingsIcon size={"small"}/>
95
44
  </IconButton>
96
45
  </Tooltip>;
97
46
 
98
47
  return <>
99
- {canEditCollection && saveDefaultFilterButton}
100
48
  {editorButton}
101
49
  </>
102
50
 
103
51
  }
104
-
105
- function getObjectOrNull(o?: object): object | null {
106
- if (o && Object.keys(o).length === 0)
107
- return o
108
- return o ?? null;
109
- }
@@ -0,0 +1,87 @@
1
+ import equal from "react-fast-compare"
2
+
3
+ import { CollectionActionsProps, mergeDeep, useAuthController, useSnackbarController } from "@firecms/core";
4
+ import { Button, SaveIcon, Tooltip, UndoIcon, } from "@firecms/ui";
5
+
6
+ import { useCollectionEditorController } from "../useCollectionEditorController";
7
+ import { useCollectionsConfigController } from "../useCollectionsConfigController";
8
+ import { PersistedCollection } from "../types/persisted_collection";
9
+
10
+ export function EditorCollectionActionStart({
11
+ path: fullPath,
12
+ parentCollectionIds,
13
+ collection,
14
+ tableController
15
+ }: CollectionActionsProps) {
16
+
17
+ const authController = useAuthController();
18
+ const collectionEditorController = useCollectionEditorController();
19
+ const configController = useCollectionsConfigController();
20
+ const snackbarController = useSnackbarController();
21
+
22
+ const canEditCollection = collectionEditorController.configPermissions
23
+ ? collectionEditorController.configPermissions({
24
+ user: authController.user,
25
+ collection
26
+ }).editCollections
27
+ : true;
28
+
29
+ let saveDefaultFilterButton = null;
30
+ if (!equal(getObjectOrNull(tableController.filterValues), getObjectOrNull(collection.initialFilter)) ||
31
+ !equal(getObjectOrNull(tableController.sortBy), getObjectOrNull(collection.initialSort))) {
32
+ saveDefaultFilterButton = <>
33
+ <Tooltip
34
+ asChild={true}
35
+ title={tableController.sortBy || tableController.filterValues ? "Save default filter and sort" : "Clear default filter and sort"}>
36
+ <Button
37
+ size={"small"}
38
+ variant={"outlined"}
39
+ onClick={() => configController
40
+ ?.saveCollection({
41
+ id: collection.id,
42
+ parentCollectionIds,
43
+ collectionData: mergeDeep(collection as PersistedCollection,
44
+ {
45
+ initialFilter: tableController.filterValues ?? null,
46
+ initialSort: tableController.sortBy ?? null
47
+ })
48
+ }).then(() => {
49
+ snackbarController.open({
50
+ type: "success",
51
+ message: "Default config saved"
52
+ });
53
+ })}>
54
+ <SaveIcon/>
55
+ </Button>
56
+ </Tooltip>
57
+
58
+ {(collection.initialFilter || collection.initialSort) && <Tooltip
59
+ title={"Reset to default filter and sort"}>
60
+ <Button
61
+ color={"primary"}
62
+ size={"small"}
63
+ variant={"text"}
64
+ onClick={() => {
65
+ tableController.clearFilter?.();
66
+ if (collection?.initialFilter)
67
+ tableController.setFilterValues?.(collection?.initialFilter);
68
+ if (collection?.initialSort)
69
+ tableController.setSortBy?.(collection?.initialSort);
70
+ }}>
71
+ <UndoIcon/>
72
+ </Button>
73
+ </Tooltip>}
74
+ </>;
75
+ }
76
+
77
+ return <>
78
+ {canEditCollection && saveDefaultFilterButton}
79
+ </>
80
+
81
+ }
82
+
83
+ function getObjectOrNull(o?: object): object | null {
84
+ if (o && Object.keys(o).length === 0)
85
+ return o
86
+ return o ?? null;
87
+ }
@@ -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
+ }