@firecms/core 3.0.0-canary.5 → 3.0.0-canary.50

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 (210) hide show
  1. package/README.md +2 -2
  2. package/dist/components/ClearFilterSortButton.d.ts +5 -0
  3. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +11 -11
  4. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +2 -2
  5. package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +5 -3
  6. package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +3 -2
  7. package/dist/components/EntityCollectionTable/column_utils.d.ts +1 -2
  8. package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +1 -4
  9. package/dist/components/EntityCollectionTable/internal/popup_field/PopupFormField.d.ts +1 -1
  10. package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +12 -3
  11. package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +11 -0
  12. package/dist/components/EntityCollectionView/useSelectionController.d.ts +2 -0
  13. package/dist/components/EntityPreview.d.ts +25 -7
  14. package/dist/components/EntityView.d.ts +11 -0
  15. package/dist/components/FieldCaption.d.ts +5 -0
  16. package/dist/components/FireCMSAppBar.d.ts +3 -2
  17. package/dist/components/HomePage/NavigationCard.d.ts +8 -0
  18. package/dist/components/HomePage/{NavigationCollectionCard.d.ts → NavigationCardBinding.d.ts} +2 -2
  19. package/dist/components/HomePage/SmallNavigationCard.d.ts +6 -0
  20. package/dist/components/HomePage/index.d.ts +3 -1
  21. package/dist/components/SelectableTable/SelectableTable.d.ts +1 -1
  22. package/dist/components/VirtualTable/VirtualTableProps.d.ts +1 -1
  23. package/dist/components/common/types.d.ts +4 -6
  24. package/dist/components/common/useDataSourceEntityCollectionTableController.d.ts +3 -0
  25. package/dist/components/index.d.ts +4 -2
  26. package/dist/contexts/AuthControllerContext.d.ts +1 -1
  27. package/dist/core/{EntityView.d.ts → EntityEditView.d.ts} +2 -2
  28. package/dist/core/NavigationRoutes.d.ts +1 -1
  29. package/dist/core/Scaffold.d.ts +1 -1
  30. package/dist/form/EntityForm.d.ts +1 -1
  31. package/dist/form/components/ErrorFocus.d.ts +1 -1
  32. package/dist/form/components/StorageItemPreview.d.ts +3 -2
  33. package/dist/form/components/StorageUploadProgress.d.ts +1 -1
  34. package/dist/form/field_bindings/KeyValueFieldBinding.d.ts +1 -1
  35. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  36. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +4 -3
  37. package/dist/form/field_bindings/TextFieldBinding.d.ts +2 -2
  38. package/dist/form/validation.d.ts +1 -1
  39. package/dist/hooks/data/delete.d.ts +2 -2
  40. package/dist/hooks/data/save.d.ts +2 -3
  41. package/dist/hooks/data/useDataSource.d.ts +2 -2
  42. package/dist/hooks/data/useEntityFetch.d.ts +3 -3
  43. package/dist/hooks/index.d.ts +1 -0
  44. package/dist/hooks/useBuildNavigationController.d.ts +6 -4
  45. package/dist/hooks/useProjectLog.d.ts +6 -2
  46. package/dist/hooks/useStorageSource.d.ts +2 -2
  47. package/dist/hooks/useValidateAuthenticator.d.ts +21 -0
  48. package/dist/index.es.js +10402 -9898
  49. package/dist/index.es.js.map +1 -1
  50. package/dist/index.umd.js +5 -5
  51. package/dist/index.umd.js.map +1 -1
  52. package/dist/internal/useBuildDataSource.d.ts +1 -12
  53. package/dist/preview/PropertyPreview.d.ts +1 -1
  54. package/dist/preview/PropertyPreviewProps.d.ts +1 -4
  55. package/dist/preview/components/BooleanPreview.d.ts +5 -1
  56. package/dist/preview/components/EnumValuesChip.d.ts +1 -1
  57. package/dist/preview/components/ReferencePreview.d.ts +1 -7
  58. package/dist/types/analytics.d.ts +1 -1
  59. package/dist/types/auth.d.ts +37 -1
  60. package/dist/types/collections.d.ts +29 -5
  61. package/dist/types/datasource.d.ts +3 -6
  62. package/dist/types/entities.d.ts +5 -1
  63. package/dist/types/entity_actions.d.ts +14 -0
  64. package/dist/types/entity_callbacks.d.ts +2 -2
  65. package/dist/types/entity_overrides.d.ts +6 -0
  66. package/dist/types/index.d.ts +2 -1
  67. package/dist/types/navigation.d.ts +14 -13
  68. package/dist/types/permissions.d.ts +5 -1
  69. package/dist/types/plugins.d.ts +20 -20
  70. package/dist/types/properties.d.ts +4 -4
  71. package/dist/types/property_config.d.ts +2 -2
  72. package/dist/types/roles.d.ts +31 -0
  73. package/dist/types/storage.d.ts +11 -3
  74. package/dist/types/user.d.ts +5 -0
  75. package/dist/util/collections.d.ts +9 -1
  76. package/dist/util/entities.d.ts +1 -1
  77. package/dist/util/icon_synonyms.d.ts +1 -4
  78. package/dist/util/icons.d.ts +8 -2
  79. package/dist/util/navigation_utils.d.ts +2 -2
  80. package/dist/util/permissions.d.ts +4 -4
  81. package/dist/util/references.d.ts +4 -2
  82. package/dist/util/resolutions.d.ts +9 -13
  83. package/dist/util/useTraceUpdate.d.ts +1 -0
  84. package/package.json +139 -119
  85. package/src/components/ClearFilterSortButton.tsx +41 -0
  86. package/src/components/DeleteEntityDialog.tsx +4 -4
  87. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +2 -2
  88. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +275 -278
  89. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +9 -5
  90. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +44 -44
  91. package/src/components/EntityCollectionTable/column_utils.tsx +3 -3
  92. package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +9 -16
  93. package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +3 -3
  94. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +27 -32
  95. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +11 -6
  96. package/src/components/EntityCollectionTable/internal/default_entity_actions.tsx +9 -5
  97. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +2 -4
  98. package/src/components/EntityCollectionView/EntityCollectionView.tsx +69 -64
  99. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +5 -6
  100. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +68 -0
  101. package/src/components/EntityCollectionView/useSelectionController.tsx +30 -0
  102. package/src/components/EntityPreview.tsx +207 -70
  103. package/src/components/EntityView.tsx +84 -0
  104. package/src/components/FieldCaption.tsx +14 -0
  105. package/src/components/FireCMSAppBar.tsx +33 -11
  106. package/src/components/HomePage/DefaultHomePage.tsx +15 -11
  107. package/src/components/HomePage/NavigationCard.tsx +69 -0
  108. package/src/components/HomePage/NavigationCardBinding.tsx +116 -0
  109. package/src/components/HomePage/SmallNavigationCard.tsx +45 -0
  110. package/src/components/HomePage/index.tsx +3 -1
  111. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +4 -4
  112. package/src/components/ReferenceWidget.tsx +4 -4
  113. package/src/components/SearchIconsView.tsx +4 -4
  114. package/src/components/SelectableTable/SelectableTable.tsx +1 -1
  115. package/src/components/SelectableTable/filters/BooleanFilterField.tsx +2 -3
  116. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +23 -8
  117. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +35 -24
  118. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +35 -15
  119. package/src/components/VirtualTable/VirtualTable.tsx +28 -20
  120. package/src/components/VirtualTable/VirtualTableProps.tsx +1 -1
  121. package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +1 -1
  122. package/src/components/common/types.tsx +4 -6
  123. package/src/components/common/useDataSourceEntityCollectionTableController.tsx +12 -1
  124. package/src/components/index.tsx +4 -2
  125. package/src/contexts/AuthControllerContext.tsx +1 -1
  126. package/src/core/Drawer.tsx +66 -39
  127. package/src/core/{EntityView.tsx → EntityEditView.tsx} +21 -40
  128. package/src/core/EntitySidePanel.tsx +2 -2
  129. package/src/core/FireCMS.tsx +18 -3
  130. package/src/core/NavigationRoutes.tsx +11 -4
  131. package/src/core/Scaffold.tsx +5 -4
  132. package/src/core/field_configs.tsx +1 -2
  133. package/src/form/EntityForm.tsx +40 -21
  134. package/src/form/PropertyFieldBinding.tsx +0 -2
  135. package/src/form/components/StorageItemPreview.tsx +5 -3
  136. package/src/form/components/StorageUploadProgress.tsx +7 -6
  137. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +8 -12
  138. package/src/form/field_bindings/DateTimeFieldBinding.tsx +1 -1
  139. package/src/form/field_bindings/KeyValueFieldBinding.tsx +15 -15
  140. package/src/form/field_bindings/MapFieldBinding.tsx +15 -15
  141. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +1 -1
  142. package/src/form/field_bindings/ReferenceFieldBinding.tsx +1 -0
  143. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +14 -5
  144. package/src/form/field_bindings/TextFieldBinding.tsx +7 -5
  145. package/src/form/validation.ts +3 -4
  146. package/src/hooks/data/delete.ts +3 -3
  147. package/src/hooks/data/save.ts +2 -2
  148. package/src/hooks/data/useCollectionFetch.tsx +1 -1
  149. package/src/hooks/data/useDataSource.tsx +8 -3
  150. package/src/hooks/data/useEntityFetch.tsx +4 -4
  151. package/src/hooks/index.tsx +2 -0
  152. package/src/hooks/useBuildLocalConfigurationPersistence.tsx +9 -10
  153. package/src/hooks/useBuildModeController.tsx +11 -5
  154. package/src/hooks/useBuildNavigationController.tsx +199 -81
  155. package/src/hooks/useProjectLog.tsx +17 -7
  156. package/src/hooks/useReferenceDialog.tsx +2 -2
  157. package/src/hooks/useStorageSource.tsx +7 -2
  158. package/src/hooks/useValidateAuthenticator.tsx +115 -0
  159. package/src/internal/useBuildDataSource.ts +42 -44
  160. package/src/internal/useBuildSideEntityController.tsx +86 -20
  161. package/src/preview/PropertyPreview.tsx +3 -14
  162. package/src/preview/PropertyPreviewProps.tsx +1 -11
  163. package/src/preview/components/BooleanPreview.tsx +19 -4
  164. package/src/preview/components/EnumValuesChip.tsx +1 -1
  165. package/src/preview/components/ReferencePreview.tsx +55 -147
  166. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +0 -1
  167. package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +0 -1
  168. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +0 -1
  169. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +0 -1
  170. package/src/preview/property_previews/ArrayOneOfPreview.tsx +0 -1
  171. package/src/preview/property_previews/ArrayPropertyPreview.tsx +0 -1
  172. package/src/preview/property_previews/StringPropertyPreview.tsx +8 -7
  173. package/src/types/analytics.ts +1 -0
  174. package/src/types/auth.tsx +50 -1
  175. package/src/types/collections.ts +33 -5
  176. package/src/types/datasource.ts +8 -5
  177. package/src/types/entities.ts +9 -1
  178. package/src/types/entity_actions.tsx +17 -0
  179. package/src/types/entity_callbacks.ts +2 -2
  180. package/src/types/entity_overrides.tsx +7 -0
  181. package/src/types/firecms.tsx +0 -1
  182. package/src/types/index.ts +2 -1
  183. package/src/types/navigation.ts +17 -16
  184. package/src/types/permissions.ts +6 -1
  185. package/src/types/plugins.tsx +26 -28
  186. package/src/types/properties.ts +8 -6
  187. package/src/types/property_config.tsx +2 -2
  188. package/src/types/roles.ts +41 -0
  189. package/src/types/side_entity_controller.tsx +1 -0
  190. package/src/types/storage.ts +12 -3
  191. package/src/types/user.ts +7 -0
  192. package/src/util/collections.ts +22 -0
  193. package/src/util/entities.ts +1 -1
  194. package/src/util/icon_list.ts +2 -2
  195. package/src/util/icon_synonyms.ts +1 -4
  196. package/src/util/icons.tsx +11 -3
  197. package/src/util/navigation_utils.ts +6 -6
  198. package/src/util/objects.ts +0 -14
  199. package/src/util/permissions.ts +11 -8
  200. package/src/util/references.ts +36 -5
  201. package/src/util/resolutions.ts +6 -24
  202. package/src/util/strings.ts +2 -2
  203. package/src/util/useTraceUpdate.tsx +2 -1
  204. package/dist/core/SideEntityView.d.ts +0 -7
  205. package/dist/internal/useLocaleConfig.d.ts +0 -1
  206. package/dist/types/appcheck.d.ts +0 -26
  207. package/src/components/HomePage/NavigationCollectionCard.tsx +0 -146
  208. package/src/core/SideEntityView.tsx +0 -38
  209. package/src/internal/useLocaleConfig.tsx +0 -18
  210. package/src/types/appcheck.ts +0 -29
@@ -12,8 +12,7 @@ import {
12
12
  PartialEntityCollection,
13
13
  PropertyOrBuilder,
14
14
  ResolvedProperty,
15
- SaveEntityProps,
16
- SelectionController
15
+ SaveEntityProps
17
16
  } from "../../types";
18
17
  import {
19
18
  EntityCollectionRowActions,
@@ -25,7 +24,6 @@ import {
25
24
  canCreateEntity,
26
25
  canDeleteEntity,
27
26
  canEditEntity,
28
- fullPathToCollectionSegments,
29
27
  getPropertyInPath,
30
28
  mergeDeep,
31
29
  resolveCollection,
@@ -37,6 +35,7 @@ import {
37
35
  useAuthController,
38
36
  useCustomizationController,
39
37
  useDataSource,
38
+ useFireCMSContext,
40
39
  useLargeLayout,
41
40
  useNavigationController,
42
41
  useSideEntityController
@@ -74,6 +73,8 @@ import {
74
73
  } from "../EntityCollectionTable/internal/default_entity_actions";
75
74
  import { DeleteEntityDialog } from "../DeleteEntityDialog";
76
75
  import { useAnalyticsController } from "../../hooks/useAnalyticsController";
76
+ import { useSelectionController } from "./useSelectionController";
77
+ import { EntityCollectionViewStartActions } from "./EntityCollectionViewStartActions";
77
78
 
78
79
  const COLLECTION_GROUP_PARENT_ID = "collectionGroupParent";
79
80
 
@@ -81,10 +82,22 @@ const COLLECTION_GROUP_PARENT_ID = "collectionGroupParent";
81
82
  * @group Components
82
83
  */
83
84
  export type EntityCollectionViewProps<M extends Record<string, any>> = {
84
- fullPath: string;
85
+ /**
86
+ * Complete path where this collection is located.
87
+ * It defaults to the collection path if not provided.
88
+ */
89
+ fullPath?: string;
90
+ /**
91
+ * If this is a subcollection, specify the parent collection ids.
92
+ */
85
93
  parentCollectionIds?: string[];
94
+ /**
95
+ * Whether this is a subcollection or not.
96
+ */
86
97
  isSubCollection?: boolean;
98
+
87
99
  className?: string;
100
+
88
101
  } & EntityCollection<M>;
89
102
 
90
103
  /**
@@ -113,7 +126,7 @@ export type EntityCollectionViewProps<M extends Record<string, any>> = {
113
126
  */
114
127
  export const EntityCollectionView = React.memo(
115
128
  function EntityCollectionView<M extends Record<string, any>>({
116
- fullPath,
129
+ fullPath: fullPathProp,
117
130
  parentCollectionIds,
118
131
  isSubCollection,
119
132
  className,
@@ -121,7 +134,9 @@ export const EntityCollectionView = React.memo(
121
134
  }: EntityCollectionViewProps<M>
122
135
  ) {
123
136
 
124
- const dataSource = useDataSource();
137
+ const context = useFireCMSContext();
138
+ const fullPath = fullPathProp ?? collectionProp.path;
139
+ const dataSource = useDataSource(collectionProp);
125
140
  const navigation = useNavigationController();
126
141
  const sideEntityController = useSideEntityController();
127
142
  const authController = useAuthController();
@@ -141,7 +156,7 @@ export const EntityCollectionView = React.memo(
141
156
  collectionRef.current = collection;
142
157
  }, [collection]);
143
158
 
144
- const canCreateEntities = canCreateEntity(collection, authController, fullPathToCollectionSegments(fullPath), null);
159
+ const canCreateEntities = canCreateEntity(collection, authController, fullPath, null);
145
160
  const [selectedNavigationEntity, setSelectedNavigationEntity] = useState<Entity<M> | undefined>(undefined);
146
161
  const [deleteEntityClicked, setDeleteEntityClicked] = React.useState<Entity<M> | Entity<M>[] | undefined>(undefined);
147
162
 
@@ -160,7 +175,7 @@ export const EntityCollectionView = React.memo(
160
175
 
161
176
  const checkInlineEditing = useCallback((entity?: Entity<any>): boolean => {
162
177
  const collection = collectionRef.current;
163
- if (!canEditEntity(collection, authController, fullPathToCollectionSegments(fullPath), entity ?? null)) {
178
+ if (!canEditEntity(collection, authController, fullPath, entity ?? null)) {
164
179
  return false;
165
180
  }
166
181
  return collection.inlineEditing === undefined || collection.inlineEditing;
@@ -175,7 +190,6 @@ export const EntityCollectionView = React.memo(
175
190
  const usedSelectionController = collection.selectionController ?? selectionController;
176
191
  const {
177
192
  selectedEntities,
178
- toggleEntitySelection,
179
193
  isEntitySelected,
180
194
  setSelectedEntities
181
195
  } = usedSelectionController;
@@ -186,8 +200,7 @@ export const EntityCollectionView = React.memo(
186
200
 
187
201
  const tableController = useDataSourceEntityCollectionTableController<M>({
188
202
  fullPath,
189
- collection: collectionRef.current,
190
- entitiesDisplayedFirst: [],
203
+ collection,
191
204
  lastDeleteTimestamp
192
205
  });
193
206
 
@@ -199,6 +212,7 @@ export const EntityCollectionView = React.memo(
199
212
  }, [tableController.setPopupCell]);
200
213
 
201
214
  const onEntityClick = useCallback((clickedEntity: Entity<M>) => {
215
+ console.log("Entity clicked", clickedEntity)
202
216
  const collection = collectionRef.current;
203
217
  setSelectedNavigationEntity(clickedEntity);
204
218
  analyticsController.onAnalyticsEvent?.("edit_entity_clicked", {
@@ -210,9 +224,9 @@ export const EntityCollectionView = React.memo(
210
224
  path: clickedEntity.path,
211
225
  collection,
212
226
  updateUrl: true,
213
- onClose: unselectNavigatedEntity
227
+ onClose: unselectNavigatedEntity,
214
228
  });
215
- }, [unselectNavigatedEntity]);
229
+ }, [unselectNavigatedEntity, sideEntityController]);
216
230
 
217
231
  const onNewClick = useCallback(() => {
218
232
 
@@ -224,9 +238,9 @@ export const EntityCollectionView = React.memo(
224
238
  path: fullPath,
225
239
  collection,
226
240
  updateUrl: true,
227
- onClose: unselectNavigatedEntity
241
+ onClose: unselectNavigatedEntity,
228
242
  });
229
- }, [fullPath]);
243
+ }, [fullPath, sideEntityController]);
230
244
 
231
245
  const onMultipleDeleteClick = () => {
232
246
  analyticsController.onAnalyticsEvent?.("multiple_delete_dialog_open", {
@@ -288,7 +302,7 @@ export const EntityCollectionView = React.memo(
288
302
  onCollectionModifiedForUser(fullPath, { defaultSize: size })
289
303
  }, [onCollectionModifiedForUser, fullPath, userConfigPersistence]);
290
304
 
291
- const createEnabled = canCreateEntity(collection, authController, fullPathToCollectionSegments(fullPath), null);
305
+ const createEnabled = canCreateEntity(collection, authController, fullPath, null);
292
306
 
293
307
  const uniqueFieldValidator: UniqueFieldValidator = useCallback(
294
308
  ({
@@ -300,13 +314,11 @@ export const EntityCollectionView = React.memo(
300
314
  [fullPath]);
301
315
 
302
316
  const onValueChange: OnCellValueChange<any, any> = ({
303
- fullPath,
304
- context,
305
317
  value,
306
318
  propertyKey,
307
319
  onValueUpdated,
308
320
  setError,
309
- entity,
321
+ data: entity,
310
322
  }) => {
311
323
 
312
324
  const updatedValues = setIn({ ...entity.values }, propertyKey, value);
@@ -323,10 +335,12 @@ export const EntityCollectionView = React.memo(
323
335
  return saveEntityWithCallbacks({
324
336
  ...saveProps,
325
337
  collection,
326
- callbacks: collection.callbacks,
327
338
  dataSource,
328
339
  context,
329
- onSaveSuccess: () => onValueUpdated(),
340
+ onSaveSuccess: () => {
341
+ setError(undefined);
342
+ onValueUpdated();
343
+ },
330
344
  onSaveFailure: (e: Error) => {
331
345
  console.error("Save failure");
332
346
  console.error(e);
@@ -345,7 +359,6 @@ export const EntityCollectionView = React.memo(
345
359
 
346
360
  const getPropertyFor = useCallback(({
347
361
  propertyKey,
348
- propertyValue,
349
362
  entity
350
363
  }: GetPropertyForProps<M>) => {
351
364
  let propertyOrBuilder: PropertyOrBuilder<any, M> | undefined = getPropertyInPath<M>(collection.properties, propertyKey);
@@ -360,7 +373,6 @@ export const EntityCollectionView = React.memo(
360
373
  propertyKey,
361
374
  propertyOrBuilder,
362
375
  path: fullPath,
363
- propertyValue,
364
376
  values: entity.values,
365
377
  entityId: entity.id,
366
378
  fields: customizationController.propertyConfigs
@@ -387,7 +399,7 @@ export const EntityCollectionView = React.memo(
387
399
  entityId: entity.id,
388
400
  selectedSubPath: subcollection.id ?? subcollection.path,
389
401
  collection,
390
- updateUrl: true
402
+ updateUrl: true,
391
403
  });
392
404
  }}>
393
405
  {subcollection.name}
@@ -425,7 +437,7 @@ export const EntityCollectionView = React.memo(
425
437
  ...subcollectionColumns,
426
438
  ...collectionGroupParentCollections
427
439
  ];
428
- }, [collection, fullPath]);
440
+ }, [collection, fullPath, sideEntityController]);
429
441
 
430
442
  const updateLastDeleteTimestamp = useCallback(() => {
431
443
  setLastDeleteTimestamp(Date.now());
@@ -433,11 +445,14 @@ export const EntityCollectionView = React.memo(
433
445
 
434
446
  const largeLayout = useLargeLayout();
435
447
 
436
- const getActionsForEntity = ({ entity, customEntityActions }: {
448
+ const getActionsForEntity = ({
449
+ entity,
450
+ customEntityActions
451
+ }: {
437
452
  entity?: Entity<M>,
438
453
  customEntityActions?: EntityAction[]
439
454
  }): EntityAction[] => {
440
- const deleteEnabled = entity ? canDeleteEntity(collection, authController, fullPathToCollectionSegments(fullPath), entity) : true;
455
+ const deleteEnabled = entity ? canDeleteEntity(collection, authController, fullPath, entity) : true;
441
456
  const actions: EntityAction[] = [editEntityAction];
442
457
  if (createEnabled)
443
458
  actions.push(copyEntityAction);
@@ -448,13 +463,13 @@ export const EntityCollectionView = React.memo(
448
463
  return actions;
449
464
  };
450
465
 
451
- const getIdColumnWidth = useCallback(() => {
466
+ const getIdColumnWidth = () => {
452
467
  const entityActions = getActionsForEntity({});
453
468
  const collapsedActions = entityActions.filter(a => a.collapsed !== false);
454
469
  const uncollapsedActions = entityActions.filter(a => a.collapsed === false);
455
470
  const actionsWidth = uncollapsedActions.length * (largeLayout ? 40 : 30);
456
471
  return (largeLayout ? (80 + actionsWidth) : (70 + actionsWidth)) + (collapsedActions.length > 0 ? (largeLayout ? 40 : 30) : 0);
457
- }, [largeLayout]);
472
+ };
458
473
 
459
474
  const tableRowActionsBuilder = ({
460
475
  entity,
@@ -470,7 +485,10 @@ export const EntityCollectionView = React.memo(
470
485
 
471
486
  const isSelected = isEntitySelected(entity);
472
487
 
473
- const actions = getActionsForEntity({ entity, customEntityActions: collection.entityActions });
488
+ const actions = getActionsForEntity({
489
+ entity,
490
+ customEntityActions: collection.entityActions
491
+ });
474
492
 
475
493
  return (
476
494
  <EntityCollectionRowActions
@@ -577,12 +595,13 @@ export const EntityCollectionView = React.memo(
577
595
  });
578
596
 
579
597
  return (
580
- <div className={cn("overflow-hidden h-full w-full", className)}
598
+ <div className={cn("overflow-hidden h-full w-full rounded-md", className)}
581
599
  ref={containerRef}>
582
600
  <EntityCollectionTable
583
601
  key={`collection_table_${fullPath}`}
584
602
  additionalFields={additionalFields}
585
603
  tableController={tableController}
604
+ enablePopupIcon={true}
586
605
  displayedColumnIds={displayedColumnIds}
587
606
  onSizeChanged={onSizeChanged}
588
607
  onEntityClick={onEntityClick}
@@ -599,6 +618,14 @@ export const EntityCollectionView = React.memo(
599
618
  onTextSearchClick={textSearchInitialised ? undefined : onTextSearchClick}
600
619
  textSearchLoading={textSearchLoading}
601
620
  textSearchEnabled={textSearchEnabled}
621
+ actionsStart={<EntityCollectionViewStartActions
622
+ parentCollectionIds={parentCollectionIds ?? []}
623
+ collection={collection}
624
+ tableController={tableController}
625
+ path={fullPath}
626
+ relativePath={collection.path}
627
+ selectionController={usedSelectionController}
628
+ collectionEntitiesCount={docsCount}/>}
602
629
  actions={<EntityCollectionViewActions
603
630
  parentCollectionIds={parentCollectionIds ?? []}
604
631
  collection={collection}
@@ -676,39 +703,14 @@ export const EntityCollectionView = React.memo(
676
703
  equal(a.selectionController, b.selectionController) &&
677
704
  equal(a.Actions, b.Actions) &&
678
705
  equal(a.defaultSize, b.defaultSize) &&
706
+ equal(a.initialFilter, b.initialFilter) &&
707
+ equal(a.initialSort, b.initialSort) &&
679
708
  equal(a.textSearchEnabled, b.textSearchEnabled) &&
680
709
  equal(a.additionalFields, b.additionalFields) &&
710
+ equal(a.sideDialogWidth, b.sideDialogWidth) &&
681
711
  equal(a.forceFilter, b.forceFilter);
682
712
  }) as React.FunctionComponent<EntityCollectionViewProps<any>>
683
713
 
684
- export function useSelectionController<M extends Record<string, any> = any>(
685
- onSelectionChange?: (entity: Entity<M>, selected: boolean) => void
686
- ): SelectionController<M> {
687
-
688
- const [selectedEntities, setSelectedEntities] = useState<Entity<M>[]>([]);
689
-
690
- const toggleEntitySelection = useCallback((entity: Entity<M>) => {
691
- let newValue;
692
- if (selectedEntities.map(e => e.id).includes(entity.id)) {
693
- onSelectionChange?.(entity, false);
694
- newValue = selectedEntities.filter((item: Entity<M>) => item.id !== entity.id);
695
- } else {
696
- onSelectionChange?.(entity, true);
697
- newValue = [...selectedEntities, entity];
698
- }
699
- setSelectedEntities(newValue);
700
- }, [selectedEntities]);
701
-
702
- const isEntitySelected = useCallback((entity: Entity<M>) => selectedEntities.map(e => e.id).includes(entity.id), [selectedEntities]);
703
-
704
- return {
705
- selectedEntities,
706
- setSelectedEntities,
707
- isEntitySelected,
708
- toggleEntitySelection
709
- };
710
- }
711
-
712
714
  function EntitiesCount({
713
715
  fullPath,
714
716
  collection,
@@ -723,7 +725,7 @@ function EntitiesCount({
723
725
  onCountChange?: (count: number) => void,
724
726
  }) {
725
727
 
726
- const dataSource = useDataSource();
728
+ const dataSource = useDataSource(collection);
727
729
  const navigation = useNavigationController();
728
730
  const [count, setCount] = useState<number | undefined>(undefined);
729
731
  const [error, setError] = useState<Error | undefined>(undefined);
@@ -745,6 +747,7 @@ function EntitiesCount({
745
747
 
746
748
  useEffect(() => {
747
749
  if (onCountChange) {
750
+ setError(undefined);
748
751
  onCountChange(count ?? 0);
749
752
  }
750
753
  }, [onCountChange, count]);
@@ -796,10 +799,10 @@ function EntityIdHeaderWidget({
796
799
  if (!searchString) return;
797
800
  setOpenPopup(false);
798
801
  return sideEntityController.open({
799
- entityId: searchString,
802
+ entityId: searchString.trim(),
800
803
  path,
801
804
  collection,
802
- updateUrl: true
805
+ updateUrl: true,
803
806
  });
804
807
  }}
805
808
  className={"text-gray-900 dark:text-white w-96 max-w-full"}>
@@ -809,11 +812,13 @@ function EntityIdHeaderWidget({
809
812
  autoFocus={openPopup}
810
813
  placeholder={"Find entity by ID"}
811
814
  // size={"small"}
812
- onChange={(e) => setSearchString(e.target.value)}
815
+ onChange={(e) => {
816
+ setSearchString(e.target.value);
817
+ }}
813
818
  value={searchString}
814
819
  className={"flex-grow bg-transparent outline-none p-1"}/>
815
820
  <Button variant={"outlined"}
816
- disabled={!searchString}
821
+ disabled={!(searchString.trim())}
817
822
  type={"submit"}
818
823
  >Go</Button>
819
824
  </div>
@@ -44,7 +44,7 @@ export function EntityCollectionViewActions<M extends Record<string, any>>({
44
44
 
45
45
  const selectedEntities = selectionController.selectedEntities;
46
46
 
47
- const addButton = canCreateEntity(collection, authController, fullPathToCollectionSegments(path), null) &&
47
+ const addButton = canCreateEntity(collection, authController, path, null) &&
48
48
  onNewClick && (largeLayout
49
49
  ? <Button
50
50
  id={`add_entity_${path}`}
@@ -57,14 +57,13 @@ export function EntityCollectionViewActions<M extends Record<string, any>>({
57
57
  : <Button
58
58
  id={`add_entity_${path}`}
59
59
  onClick={onNewClick}
60
- size="medium"
61
60
  variant="filled"
62
61
  color="primary"
63
62
  >
64
63
  <AddIcon/>
65
64
  </Button>);
66
65
 
67
- const multipleDeleteEnabled = canDeleteEntity(collection, authController, fullPathToCollectionSegments(path), null);
66
+ const multipleDeleteEnabled = canDeleteEntity(collection, authController, path, null);
68
67
 
69
68
  let multipleDeleteButton: React.ReactNode | undefined;
70
69
  if (selectionEnabled) {
@@ -112,11 +111,11 @@ export function EntityCollectionViewActions<M extends Record<string, any>>({
112
111
 
113
112
  if (plugins) {
114
113
  plugins.forEach((plugin, i) => {
115
- if (plugin.collections?.CollectionActions) {
116
- actions.push(...toArray(plugin.collections?.CollectionActions)
114
+ if (plugin.collectionView?.CollectionActions) {
115
+ actions.push(...toArray(plugin.collectionView?.CollectionActions)
117
116
  .map((Action, j) => (
118
117
  <ErrorBoundary key={`plugin_actions_${i}_${j}`}>
119
- <Action {...actionProps} {...plugin.collections?.collectionActionsProps}/>
118
+ <Action {...actionProps} {...plugin.collectionView?.collectionActionsProps}/>
120
119
  </ErrorBoundary>
121
120
  )));
122
121
  }
@@ -0,0 +1,68 @@
1
+ import React from "react";
2
+ import { useCustomizationController, useFireCMSContext } from "../../hooks";
3
+ import { CollectionActionsProps, EntityCollection, EntityTableController, SelectionController } from "../../types";
4
+ import { toArray } from "../../util/arrays";
5
+ import { ErrorBoundary } from "../ErrorBoundary";
6
+ import { ClearFilterSortButton } from "../ClearFilterSortButton";
7
+
8
+ export type EntityCollectionViewStartActionsProps<M extends Record<string, any>> = {
9
+ collection: EntityCollection<M>;
10
+ path: string;
11
+ relativePath: string;
12
+ parentCollectionIds: string[];
13
+ selectionController: SelectionController<M>;
14
+ tableController: EntityTableController<M>;
15
+ collectionEntitiesCount: number;
16
+ }
17
+
18
+ export function EntityCollectionViewStartActions<M extends Record<string, any>>({
19
+ collection,
20
+ relativePath,
21
+ parentCollectionIds,
22
+ path,
23
+ selectionController,
24
+ tableController,
25
+ collectionEntitiesCount
26
+ }: EntityCollectionViewStartActionsProps<M>) {
27
+
28
+ const context = useFireCMSContext();
29
+
30
+ const customizationController = useCustomizationController();
31
+ const plugins = customizationController.plugins ?? [];
32
+
33
+ const actionProps: CollectionActionsProps = {
34
+ path,
35
+ relativePath,
36
+ parentCollectionIds,
37
+ collection,
38
+ selectionController,
39
+ context,
40
+ tableController,
41
+ collectionEntitiesCount
42
+ };
43
+ const actions: React.ReactNode[] = [
44
+ <ClearFilterSortButton
45
+ key={"clear_filter"}
46
+ tableController={tableController}
47
+ enabled={!collection.forceFilter}/>
48
+ ];
49
+
50
+ if (plugins) {
51
+ plugins.forEach((plugin, i) => {
52
+ if (plugin.collectionView?.CollectionActionsStart) {
53
+ actions.push(...toArray(plugin.collectionView?.CollectionActionsStart)
54
+ .map((Action, j) => (
55
+ <ErrorBoundary key={`plugin_actions_${i}_${j}`}>
56
+ <Action {...actionProps} {...plugin.collectionView?.collectionActionsStartProps}/>
57
+ </ErrorBoundary>
58
+ )));
59
+ }
60
+ });
61
+ }
62
+
63
+ return (
64
+ <>
65
+ {actions}
66
+ </>
67
+ );
68
+ }
@@ -0,0 +1,30 @@
1
+ import { useCallback, useState } from "react";
2
+ import { Entity, SelectionController } from "../../types";
3
+
4
+ export function useSelectionController<M extends Record<string, any> = any>(
5
+ onSelectionChange?: (entity: Entity<M>, selected: boolean) => void
6
+ ): SelectionController<M> {
7
+
8
+ const [selectedEntities, setSelectedEntities] = useState<Entity<M>[]>([]);
9
+
10
+ const toggleEntitySelection = useCallback((entity: Entity<M>) => {
11
+ let newValue;
12
+ if (selectedEntities.map(e => e.id).includes(entity.id)) {
13
+ onSelectionChange?.(entity, false);
14
+ newValue = selectedEntities.filter((item: Entity<M>) => item.id !== entity.id);
15
+ } else {
16
+ onSelectionChange?.(entity, true);
17
+ newValue = [...selectedEntities, entity];
18
+ }
19
+ setSelectedEntities(newValue);
20
+ }, [selectedEntities]);
21
+
22
+ const isEntitySelected = useCallback((entity: Entity<M>) => selectedEntities.map(e => e.id).includes(entity.id), [selectedEntities]);
23
+
24
+ return {
25
+ selectedEntities,
26
+ setSelectedEntities,
27
+ isEntitySelected,
28
+ toggleEntitySelection
29
+ };
30
+ }