@firecms/collection_editor 3.0.0-canary.18 → 3.0.0-canary.182

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 (74) hide show
  1. package/LICENSE +114 -21
  2. package/dist/ConfigControllerProvider.d.ts +11 -2
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.es.js +10069 -4770
  5. package/dist/index.es.js.map +1 -1
  6. package/dist/index.umd.js +10759 -3
  7. package/dist/index.umd.js.map +1 -1
  8. package/dist/types/collection_editor_controller.d.ts +14 -2
  9. package/dist/types/collection_inference.d.ts +1 -1
  10. package/dist/types/config_permissions.d.ts +2 -2
  11. package/dist/types/persisted_collection.d.ts +1 -1
  12. package/dist/ui/CollectionViewHeaderAction.d.ts +3 -2
  13. package/dist/ui/EditorCollectionActionStart.d.ts +2 -0
  14. package/dist/ui/PropertyAddColumnComponent.d.ts +3 -1
  15. package/dist/ui/collection_editor/CollectionDetailsForm.d.ts +3 -1
  16. package/dist/ui/collection_editor/CollectionEditorDialog.d.ts +3 -2
  17. package/dist/ui/collection_editor/CollectionEditorWelcomeView.d.ts +1 -1
  18. package/dist/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +1 -1
  19. package/dist/ui/collection_editor/LayoutModeSwitch.d.ts +5 -0
  20. package/dist/ui/collection_editor/PropertyEditView.d.ts +8 -0
  21. package/dist/ui/collection_editor/PropertyTree.d.ts +9 -9
  22. package/dist/ui/collection_editor/SubcollectionsEditTab.d.ts +1 -1
  23. package/dist/ui/collection_editor/import/CollectionEditorImportMapping.d.ts +7 -0
  24. package/dist/ui/collection_editor/properties/MarkdownPropertyField.d.ts +4 -0
  25. package/dist/ui/collection_editor/properties/StringPropertyField.d.ts +1 -1
  26. package/dist/useCollectionEditorPlugin.d.ts +17 -11
  27. package/dist/utils/collections.d.ts +6 -0
  28. package/package.json +24 -35
  29. package/src/ConfigControllerProvider.tsx +76 -64
  30. package/src/index.ts +1 -0
  31. package/src/types/collection_editor_controller.tsx +14 -4
  32. package/src/types/collection_inference.ts +1 -1
  33. package/src/types/config_permissions.ts +1 -1
  34. package/src/types/persisted_collection.ts +2 -3
  35. package/src/ui/CollectionViewHeaderAction.tsx +10 -5
  36. package/src/ui/EditorCollectionAction.tsx +10 -63
  37. package/src/ui/EditorCollectionActionStart.tsx +88 -0
  38. package/src/ui/HomePageEditorCollectionAction.tsx +19 -13
  39. package/src/ui/NewCollectionButton.tsx +1 -1
  40. package/src/ui/NewCollectionCard.tsx +3 -3
  41. package/src/ui/PropertyAddColumnComponent.tsx +11 -6
  42. package/src/ui/collection_editor/CollectionDetailsForm.tsx +90 -11
  43. package/src/ui/collection_editor/CollectionEditorDialog.tsx +101 -34
  44. package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +8 -7
  45. package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +39 -36
  46. package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +6 -5
  47. package/src/ui/collection_editor/EnumForm.tsx +10 -6
  48. package/src/ui/collection_editor/GetCodeDialog.tsx +56 -26
  49. package/src/ui/collection_editor/LayoutModeSwitch.tsx +54 -0
  50. package/src/ui/collection_editor/PropertyEditView.tsx +257 -80
  51. package/src/ui/collection_editor/PropertyFieldPreview.tsx +7 -10
  52. package/src/ui/collection_editor/PropertyTree.tsx +9 -7
  53. package/src/ui/collection_editor/SubcollectionsEditTab.tsx +26 -19
  54. package/src/ui/collection_editor/UnsavedChangesDialog.tsx +3 -5
  55. package/src/ui/collection_editor/import/CollectionEditorImportDataPreview.tsx +26 -9
  56. package/src/ui/collection_editor/import/CollectionEditorImportMapping.tsx +42 -9
  57. package/src/ui/collection_editor/properties/BlockPropertyField.tsx +32 -20
  58. package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +54 -47
  59. package/src/ui/collection_editor/properties/EnumPropertyField.tsx +3 -1
  60. package/src/ui/collection_editor/properties/MapPropertyField.tsx +7 -6
  61. package/src/ui/collection_editor/properties/MarkdownPropertyField.tsx +139 -0
  62. package/src/ui/collection_editor/properties/ReferencePropertyField.tsx +2 -0
  63. package/src/ui/collection_editor/properties/RepeatPropertyField.tsx +0 -1
  64. package/src/ui/collection_editor/properties/StoragePropertyField.tsx +34 -19
  65. package/src/ui/collection_editor/properties/StringPropertyField.tsx +1 -10
  66. package/src/ui/collection_editor/properties/UrlPropertyField.tsx +1 -0
  67. package/src/ui/collection_editor/properties/validation/ValidationPanel.tsx +2 -2
  68. package/src/ui/collection_editor/templates/pages_template.ts +1 -6
  69. package/src/useCollectionEditorPlugin.tsx +41 -31
  70. package/src/utils/collections.ts +36 -0
  71. package/dist/ui/RootCollectionSuggestions.d.ts +0 -3
  72. package/dist/ui/collection_editor/PropertySelectItem.d.ts +0 -8
  73. package/src/ui/RootCollectionSuggestions.tsx +0 -63
  74. 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,14 +49,21 @@ export interface ConfigControllerProviderProps {
48
49
  icon: React.ReactNode
49
50
  };
50
51
 
51
- pathSuggestions?: (path?: string) => Promise<string[]>;
52
+ getPathSuggestions?: (path?: string) => Promise<string[]>;
52
53
 
53
- getUser: (uid: string) => User | null
54
+ getUser?: (uid: string) => User | null
54
55
 
55
56
  getData?: (path: string, parentPaths: string[]) => Promise<object[]>;
56
57
 
57
58
  onAnalyticsEvent?: (event: string, params?: object) => void;
58
59
 
60
+ components?: {
61
+ /**
62
+ * Custom component to render the database field
63
+ */
64
+ DatabaseField?: React.ComponentType<{ databaseId?: string, onDatabaseIdUpdate: (databaseId:string) => void }>;
65
+ };
66
+
59
67
  }
60
68
 
61
69
  export const ConfigControllerProvider = React.memo(
@@ -66,10 +74,11 @@ export const ConfigControllerProvider = React.memo(
66
74
  reservedGroups,
67
75
  collectionInference,
68
76
  extraView,
69
- pathSuggestions,
77
+ getPathSuggestions,
70
78
  getUser,
71
79
  getData,
72
- onAnalyticsEvent
80
+ onAnalyticsEvent,
81
+ components
73
82
  }: PropsWithChildren<ConfigControllerProviderProps>) {
74
83
 
75
84
  const navigation = useNavigationController();
@@ -77,20 +86,6 @@ export const ConfigControllerProvider = React.memo(
77
86
  const snackbarController = useSnackbarController();
78
87
  const { propertyConfigs } = useCustomizationController();
79
88
 
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
89
  const [currentDialog, setCurrentDialog] = React.useState<{
95
90
  isNewCollection: boolean,
96
91
  parentCollection?: PersistedCollection,
@@ -102,7 +97,8 @@ export const ConfigControllerProvider = React.memo(
102
97
  group?: string,
103
98
  name?: string
104
99
  },
105
- redirect: boolean
100
+ redirect: boolean,
101
+ existingEntities?: Entity<any>[]
106
102
  }>();
107
103
 
108
104
  const [currentPropertyDialog, setCurrentPropertyDialog] = React.useState<{
@@ -115,6 +111,7 @@ export const ConfigControllerProvider = React.memo(
115
111
  fullPath?: string,
116
112
  parentCollectionIds: string[],
117
113
  collectionEditable: boolean;
114
+ existingEntities?: Entity<any>[]
118
115
  }>();
119
116
 
120
117
  const defaultConfigPermissions: CollectionEditorPermissionsBuilder = useCallback(() => ({
@@ -123,46 +120,57 @@ export const ConfigControllerProvider = React.memo(
123
120
  deleteCollections: true
124
121
  }), []);
125
122
 
126
- const editCollection = useCallback(({
127
- id,
128
- fullPath,
129
- parentCollectionIds,
130
- parentCollection
131
- }: {
123
+ const editCollection = ({
124
+ id,
125
+ fullPath,
126
+ parentCollectionIds,
127
+ parentCollection,
128
+ existingEntities
129
+ }: {
132
130
  id?: string,
133
131
  fullPath?: string,
134
132
  parentCollectionIds: string[],
135
- parentCollection?: PersistedCollection
133
+ parentCollection?: PersistedCollection,
134
+ existingEntities?: Entity<any>[]
136
135
  }) => {
137
136
  console.debug("Edit collection", id, fullPath, parentCollectionIds, parentCollection);
138
- onAnalyticsEvent?.("edit_collection", { id, fullPath });
137
+ onAnalyticsEvent?.("edit_collection", {
138
+ id,
139
+ fullPath
140
+ });
139
141
  setCurrentDialog({
140
142
  editedCollectionId: id,
141
143
  fullPath,
142
144
  parentCollectionIds,
143
145
  isNewCollection: false,
144
146
  parentCollection,
145
- redirect: false
147
+ redirect: false,
148
+ existingEntities
146
149
  });
147
- }, []);
150
+ };
148
151
 
149
- const editProperty = useCallback(({
150
- propertyKey,
151
- property,
152
- editedCollectionId,
153
- currentPropertiesOrder,
154
- parentCollectionIds,
155
- collection
156
- }: {
152
+ const editProperty = ({
153
+ propertyKey,
154
+ property,
155
+ editedCollectionId,
156
+ currentPropertiesOrder,
157
+ parentCollectionIds,
158
+ collection,
159
+ existingEntities
160
+ }: {
157
161
  propertyKey?: string,
158
162
  property?: Property,
159
163
  currentPropertiesOrder?: string[],
160
164
  editedCollectionId: string,
161
165
  parentCollectionIds: string[],
162
166
  collection: PersistedCollection,
167
+ existingEntities?: Entity<any>[]
163
168
  }) => {
164
169
  console.debug("Edit property", propertyKey, property, editedCollectionId, currentPropertiesOrder, parentCollectionIds, collection);
165
- onAnalyticsEvent?.("edit_property", { propertyKey, editedCollectionId });
170
+ onAnalyticsEvent?.("edit_property", {
171
+ propertyKey,
172
+ editedCollectionId
173
+ });
166
174
  // namespace is all the path until the last dot
167
175
  const namespace = propertyKey && propertyKey.includes(".")
168
176
  ? propertyKey.substring(0, propertyKey.lastIndexOf("."))
@@ -175,19 +183,20 @@ export const ConfigControllerProvider = React.memo(
175
183
  property,
176
184
  namespace,
177
185
  currentPropertiesOrder,
178
- editedCollectionId: editedCollectionId,
186
+ editedCollectionId,
179
187
  parentCollectionIds,
180
- collectionEditable: collection?.editable ?? false
188
+ collectionEditable: collection?.editable ?? false,
189
+ existingEntities
181
190
  });
182
- }, []);
191
+ };
183
192
 
184
- const createCollection = React.useCallback(({
185
- parentCollectionIds,
186
- parentCollection,
187
- initialValues,
188
- redirect,
189
- sourceClick
190
- }: {
193
+ const createCollection = ({
194
+ parentCollectionIds,
195
+ parentCollection,
196
+ initialValues,
197
+ redirect,
198
+ sourceClick
199
+ }: {
191
200
  parentCollectionIds: string[],
192
201
  parentCollection?: PersistedCollection
193
202
  initialValues?: {
@@ -198,8 +207,20 @@ export const ConfigControllerProvider = React.memo(
198
207
  redirect: boolean,
199
208
  sourceClick?: string
200
209
  }) => {
201
- console.debug("Create collection", { parentCollectionIds, parentCollection, initialValues, redirect, sourceClick });
202
- onAnalyticsEvent?.("create_collection", { parentCollectionIds, parentCollection, initialValues, redirect, sourceClick });
210
+ console.debug("Create collection", {
211
+ parentCollectionIds,
212
+ parentCollection,
213
+ initialValues,
214
+ redirect,
215
+ sourceClick
216
+ });
217
+ onAnalyticsEvent?.("create_collection", {
218
+ parentCollectionIds,
219
+ parentCollection,
220
+ initialValues,
221
+ redirect,
222
+ sourceClick
223
+ });
203
224
  setCurrentDialog({
204
225
  isNewCollection: true,
205
226
  parentCollectionIds,
@@ -207,17 +228,7 @@ export const ConfigControllerProvider = React.memo(
207
228
  initialValues,
208
229
  redirect
209
230
  });
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
- }
231
+ };
221
232
 
222
233
  return (
223
234
  <ConfigControllerContext.Provider value={collectionConfigController}>
@@ -227,7 +238,8 @@ export const ConfigControllerProvider = React.memo(
227
238
  createCollection,
228
239
  editProperty,
229
240
  configPermissions: configPermissions ?? defaultConfigPermissions,
230
- rootPathSuggestions
241
+ getPathSuggestions,
242
+ components
231
243
  }}>
232
244
 
233
245
  {children}
@@ -265,7 +277,7 @@ export const ConfigControllerProvider = React.memo(
265
277
  getData={getData && currentPropertyDialog?.editedCollectionId
266
278
  ? () => {
267
279
  console.debug("get data for property", currentPropertyDialog?.editedCollectionId);
268
- const resolvedPath = navigation.resolveAliasesFrom(currentPropertyDialog.editedCollectionId!)
280
+ const resolvedPath = navigation.resolveIdsFrom(currentPropertyDialog.editedCollectionId!)
269
281
  return getData(resolvedPath, []);
270
282
  }
271
283
  : 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,19 @@ 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[];
44
+ getPathSuggestions?: (path: string) => Promise<string[]>;
45
+
46
+ components?: {
47
+ /**
48
+ * Custom component to render the database field
49
+ */
50
+ DatabaseField?: React.ComponentType<{ databaseId?: string, onDatabaseIdUpdate: (databaseId: string) => void }>;
51
+ };
42
52
 
43
53
  }
@@ -1,3 +1,3 @@
1
1
  import { EntityCollection } from "@firecms/core";
2
2
 
3
- export type CollectionInference = (path: string, collectionGroup: boolean, parentCollectionIds: string[]) => Promise<Partial<EntityCollection> | null>;
3
+ export type CollectionInference = (path: string, collectionGroup: boolean, parentCollectionPaths: string[]) => Promise<Partial<EntityCollection> | null>;
@@ -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,68 +24,26 @@ 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
89
31
  color={"primary"}
90
32
  disabled={!canEditCollection}
91
33
  onClick={canEditCollection
92
- ? () => collectionEditorController?.editCollection({ id: collection.id, fullPath, parentCollectionIds, parentCollection: parentCollection as PersistedCollection })
34
+ ? () => collectionEditorController?.editCollection({
35
+ id: collection.id,
36
+ fullPath,
37
+ parentCollectionIds,
38
+ parentCollection: parentCollection as PersistedCollection,
39
+ existingEntities: tableController?.data ?? []
40
+ })
93
41
  : undefined}>
94
42
  <SettingsIcon/>
95
43
  </IconButton>
96
44
  </Tooltip>;
97
45
 
98
46
  return <>
99
- {canEditCollection && saveDefaultFilterButton}
100
47
  {editorButton}
101
48
  </>
102
49
 
@@ -0,0 +1,88 @@
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
+ color={"primary"}
38
+ size={"small"}
39
+ variant={"outlined"}
40
+ onClick={() => configController
41
+ ?.saveCollection({
42
+ id: collection.id,
43
+ parentCollectionIds,
44
+ collectionData: mergeDeep(collection as PersistedCollection,
45
+ {
46
+ initialFilter: tableController.filterValues ?? null,
47
+ initialSort: tableController.sortBy ?? null
48
+ })
49
+ }).then(() => {
50
+ snackbarController.open({
51
+ type: "success",
52
+ message: "Default config saved"
53
+ });
54
+ })}>
55
+ <SaveIcon/>
56
+ </Button>
57
+ </Tooltip>
58
+
59
+ {(collection.initialFilter || collection.initialSort) && <Tooltip
60
+ title={"Reset to default filter and sort"}>
61
+ <Button
62
+ color={"primary"}
63
+ size={"small"}
64
+ variant={"text"}
65
+ onClick={() => {
66
+ tableController.clearFilter?.();
67
+ if (collection?.initialFilter)
68
+ tableController.setFilterValues?.(collection?.initialFilter);
69
+ if (collection?.initialSort)
70
+ tableController.setSortBy?.(collection?.initialSort);
71
+ }}>
72
+ <UndoIcon/>
73
+ </Button>
74
+ </Tooltip>}
75
+ </>;
76
+ }
77
+
78
+ return <>
79
+ {canEditCollection && saveDefaultFilterButton}
80
+ </>
81
+
82
+ }
83
+
84
+ function getObjectOrNull(o?: object): object | null {
85
+ if (o && Object.keys(o).length === 0)
86
+ return o
87
+ return o ?? null;
88
+ }
@@ -1,12 +1,12 @@
1
1
  import {
2
- DeleteConfirmationDialog,
2
+ ConfirmationDialog,
3
3
  PluginHomePageActionsProps,
4
4
  useAuthController,
5
5
  useSnackbarController
6
6
  } from "@firecms/core";
7
7
  import { DeleteIcon, IconButton, Menu, MenuItem, MoreVertIcon, SettingsIcon, } from "@firecms/ui";
8
8
  import { useCollectionEditorController } from "../useCollectionEditorController";
9
- import { useCallback, useState } from "react";
9
+ import { useState } from "react";
10
10
  import { useCollectionsConfigController } from "../useCollectionsConfigController";
11
11
 
12
12
  export function HomePageEditorCollectionAction({
@@ -14,6 +14,7 @@ export function HomePageEditorCollectionAction({
14
14
  collection
15
15
  }: PluginHomePageActionsProps) {
16
16
 
17
+
17
18
  const snackbarController = useSnackbarController();
18
19
  const authController = useAuthController();
19
20
  const configController = useCollectionsConfigController();
@@ -24,13 +25,16 @@ export function HomePageEditorCollectionAction({
24
25
  collection
25
26
  });
26
27
 
27
- const onEditCollectionClicked = useCallback(() => {
28
- collectionEditorController?.editCollection({ id: collection.id, parentCollectionIds: [] });
29
- }, [collectionEditorController, path]);
28
+ const onEditCollectionClicked = () => {
29
+ collectionEditorController?.editCollection({
30
+ id: collection.id,
31
+ parentCollectionIds: []
32
+ });
33
+ };
30
34
 
31
35
  const [deleteRequested, setDeleteRequested] = useState(false);
32
36
 
33
- const deleteCollection = useCallback(() => {
37
+ const deleteCollection = () => {
34
38
  configController?.deleteCollection({ id: collection.id }).then(() => {
35
39
  setDeleteRequested(false);
36
40
  snackbarController.open({
@@ -38,7 +42,7 @@ export function HomePageEditorCollectionAction({
38
42
  type: "success"
39
43
  });
40
44
  });
41
- }, [path, configController]);
45
+ };
42
46
 
43
47
  return <>
44
48
 
@@ -49,11 +53,13 @@ export function HomePageEditorCollectionAction({
49
53
  <MoreVertIcon size={"small"}/>
50
54
  </IconButton>}
51
55
  >
52
- <MenuItem onClick={(event) => {
53
- event.preventDefault();
54
- event.stopPropagation();
55
- setDeleteRequested(true);
56
- }}>
56
+ <MenuItem
57
+ dense={true}
58
+ onClick={(event) => {
59
+ event.preventDefault();
60
+ event.stopPropagation();
61
+ setDeleteRequested(true);
62
+ }}>
57
63
  <DeleteIcon/>
58
64
  Delete
59
65
  </MenuItem>
@@ -71,7 +77,7 @@ export function HomePageEditorCollectionAction({
71
77
  </IconButton>}
72
78
  </div>
73
79
 
74
- <DeleteConfirmationDialog
80
+ <ConfirmationDialog
75
81
  open={deleteRequested}
76
82
  onAccept={deleteCollection}
77
83
  onCancel={() => setDeleteRequested(false)}
@@ -3,7 +3,7 @@ import { useCollectionEditorController } from "../useCollectionEditorController"
3
3
 
4
4
  export function NewCollectionButton() {
5
5
  const collectionEditorController = useCollectionEditorController();
6
- return <div className={"bg-gray-50 dark:bg-gray-900 min-w-fit rounded"}>
6
+ return <div className={"bg-surface-50 dark:bg-surface-900 min-w-fit rounded"}>
7
7
  <Button className={"min-w-fit"}
8
8
  variant={"outlined"}
9
9
  onClick={() => collectionEditorController.createCollection({