@firecms/core 3.3.0-canary.d3242eb → 3.4.0-canary.00f9be5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/app/useApp.d.ts +1 -0
- package/dist/components/EntityCollectionTable/column_utils.d.ts +4 -3
- package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +6 -1
- package/dist/components/EntityCollectionTable/internal/popup_field/PopupFormField.d.ts +3 -1
- package/dist/components/EntityCollectionView/EntityCollectionBoardView.d.ts +3 -1
- package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +8 -0
- package/dist/components/EntityCollectionView/EntityCollectionViewActions.d.ts +3 -1
- package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +3 -1
- package/dist/components/EntityCollectionView/FiltersDialog.d.ts +2 -1
- package/dist/components/EntityCollectionView/useBoardDataController.d.ts +3 -1
- package/dist/components/EntityPreview.d.ts +3 -1
- package/dist/components/ErrorBoundary.d.ts +1 -3
- package/dist/components/LicenseBanner.d.ts +23 -0
- package/dist/components/ReferenceTable/ReferenceSelectionTable.d.ts +10 -1
- package/dist/components/SelectableTable/filters/filter_text_input.d.ts +30 -0
- package/dist/components/SelectableTable/filters/filter_text_input.test.d.ts +1 -0
- package/dist/components/common/table_url_params.d.ts +24 -0
- package/dist/components/common/useDataSourceTableController.d.ts +9 -1
- package/dist/components/common/useTableSearchHelper.d.ts +9 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/contexts/LicenseStatusContext.d.ts +16 -0
- package/dist/core/DefaultDrawer.d.ts +10 -3
- package/dist/core/EntityEditView.d.ts +9 -1
- package/dist/core/EntityEditViewFormActions.d.ts +1 -1
- package/dist/core/field_configs.d.ts +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/plugin_translations.d.ts +38 -0
- package/dist/core/pro_plugins.d.ts +40 -0
- package/dist/de-BF5vcQPY.js +703 -0
- package/dist/de-BF5vcQPY.js.map +1 -0
- package/dist/editor/extensions/Image.d.ts +11 -0
- package/dist/editor/index.d.ts +2 -1
- package/dist/editor/lazy_editor.d.ts +6 -0
- package/dist/editor-BSo_aS1I.js +4563 -0
- package/dist/editor-BSo_aS1I.js.map +1 -0
- package/dist/form/EntityForm.d.ts +8 -1
- package/dist/form/EntityFormActions.d.ts +2 -0
- package/dist/form/field_bindings/GeopointFieldBinding.d.ts +5 -0
- package/dist/form/index.d.ts +1 -0
- package/dist/fr-DH9_wyFI.js +703 -0
- package/dist/fr-DH9_wyFI.js.map +1 -0
- package/dist/hi-BM8dm1Lu.js +703 -0
- package/dist/hi-BM8dm1Lu.js.map +1 -0
- package/dist/hooks/data/delete.d.ts +1 -1
- package/dist/hooks/data/save.d.ts +1 -1
- package/dist/hooks/data/useCollectionFetch.d.ts +7 -1
- package/dist/hooks/data/useEntityFetch.d.ts +9 -1
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/useLicenseStatus.d.ts +16 -0
- package/dist/hooks/useProjectLog.d.ts +11 -6
- package/dist/hooks/useTranslation.d.ts +1 -1
- package/dist/i18n/__tests__/FireCMSi18nProvider.test.d.ts +1 -0
- package/dist/i18n/__tests__/nested_provider_lifecycle.test.d.ts +1 -0
- package/dist/index.es.js +4429 -10479
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +9313 -6582
- package/dist/index.umd.js.map +1 -1
- package/dist/it-D3K1gfe4.js +703 -0
- package/dist/it-D3K1gfe4.js.map +1 -0
- package/dist/locales/pl.d.ts +2 -0
- package/dist/pl-CP1zeLzn.js +705 -0
- package/dist/pl-CP1zeLzn.js.map +1 -0
- package/dist/preview/index.d.ts +1 -0
- package/dist/preview/property_previews/GeopointPropertyPreview.d.ts +4 -0
- package/dist/pt-Cus7eKQR.js +705 -0
- package/dist/pt-Cus7eKQR.js.map +1 -0
- package/dist/types/analytics.d.ts +1 -1
- package/dist/types/collections.d.ts +31 -0
- package/dist/types/datasource.d.ts +67 -4
- package/dist/types/entities.d.ts +21 -1
- package/dist/types/entity_actions.d.ts +6 -0
- package/dist/types/entity_callbacks.d.ts +21 -0
- package/dist/types/firecms.d.ts +18 -1
- package/dist/types/firecms_context.d.ts +8 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/license.d.ts +55 -0
- package/dist/types/navigation.d.ts +34 -5
- package/dist/types/plugins.d.ts +22 -1
- package/dist/types/properties.d.ts +17 -1
- package/dist/types/side_entity_controller.d.ts +7 -0
- package/dist/types/translations.d.ts +54 -5
- package/dist/util/__tests__/collections.test.d.ts +1 -0
- package/dist/util/__tests__/urls.test.d.ts +1 -0
- package/dist/util/collections.d.ts +1 -1
- package/dist/util/date_fns_locales.d.ts +18 -0
- package/dist/util/entities.d.ts +1 -0
- package/dist/util/entity_cache.d.ts +11 -0
- package/dist/util/geopoint.d.ts +22 -0
- package/dist/util/index.d.ts +3 -0
- package/dist/util/lazy_eager.d.ts +3 -3
- package/dist/util/navigation_blocking.d.ts +22 -0
- package/dist/util/navigation_from_path.d.ts +17 -0
- package/dist/util/navigation_utils.d.ts +107 -3
- package/dist/util/parent_references_from_path.d.ts +16 -0
- package/dist/util/paths.d.ts +28 -0
- package/dist/util/permissions.d.ts +10 -4
- package/dist/util/urls.d.ts +22 -0
- package/package.json +17 -11
- package/src/app/Scaffold.tsx +54 -45
- package/src/app/useApp.tsx +1 -0
- package/src/components/DeleteEntityDialog.tsx +2 -0
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +2 -2
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +3 -1
- package/src/components/EntityCollectionTable/column_utils.tsx +11 -19
- package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +1 -1
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +7 -0
- package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +5 -1
- package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +12 -0
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +71 -17
- package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +6 -2
- package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +8 -1
- package/src/components/EntityCollectionView/FiltersDialog.tsx +39 -28
- package/src/components/EntityCollectionView/useBoardDataController.tsx +17 -1
- package/src/components/EntityPreview.tsx +45 -41
- package/src/components/ErrorBoundary.tsx +12 -18
- package/src/components/HomePage/NavigationCardBinding.tsx +6 -3
- package/src/components/LicenseBanner.tsx +207 -0
- package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +19 -2
- package/src/components/ReferenceWidget.tsx +1 -1
- package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +2 -2
- package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +33 -7
- package/src/components/SelectableTable/filters/filter_text_input.test.ts +184 -0
- package/src/components/SelectableTable/filters/filter_text_input.ts +71 -0
- package/src/components/VirtualTable/VirtualTable.tsx +19 -8
- package/src/components/common/default_entity_actions.tsx +22 -2
- package/src/components/common/table_url_params.ts +172 -0
- package/src/components/common/useDataSourceTableController.tsx +126 -163
- package/src/components/common/useTableSearchHelper.ts +26 -2
- package/src/components/index.tsx +1 -0
- package/src/contexts/LicenseStatusContext.tsx +50 -0
- package/src/contexts/SnackbarProvider.tsx +14 -1
- package/src/core/DefaultAppBar.tsx +28 -16
- package/src/core/DefaultDrawer.tsx +151 -65
- package/src/core/DrawerNavigationGroup.tsx +27 -29
- package/src/core/DrawerNavigationItem.tsx +10 -12
- package/src/core/EntityEditView.tsx +77 -35
- package/src/core/EntityEditViewFormActions.tsx +3 -2
- package/src/core/EntitySidePanel.tsx +8 -4
- package/src/core/FireCMS.tsx +73 -47
- package/src/core/SideDialogs.tsx +44 -1
- package/src/core/field_configs.tsx +15 -0
- package/src/core/index.tsx +1 -0
- package/src/core/plugin_translations.ts +87 -0
- package/src/core/pro_plugins.ts +79 -0
- package/src/editor/components/SlashCommandMenu.tsx +4 -1
- package/src/editor/extensions/Image.ts +17 -1
- package/src/editor/hooks/useProseMirror.ts +5 -0
- package/src/editor/index.ts +11 -1
- package/src/editor/lazy_editor.tsx +33 -0
- package/src/form/EntityForm.tsx +31 -10
- package/src/form/EntityFormActions.tsx +2 -0
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +1 -1
- package/src/form/field_bindings/GeopointFieldBinding.tsx +139 -0
- package/src/form/index.tsx +1 -0
- package/src/hooks/data/delete.ts +8 -0
- package/src/hooks/data/save.ts +6 -1
- package/src/hooks/data/useCollectionFetch.tsx +21 -1
- package/src/hooks/data/useEntityFetch.tsx +35 -4
- package/src/hooks/index.tsx +2 -0
- package/src/hooks/useBuildNavigationController.tsx +75 -16
- package/src/hooks/useFireCMSContext.tsx +7 -3
- package/src/hooks/useLicenseStatus.tsx +32 -0
- package/src/hooks/useProjectLog.tsx +27 -9
- package/src/hooks/useResolvedNavigationFrom.tsx +3 -1
- package/src/hooks/useTranslation.ts +3 -1
- package/src/hooks/useValidateAuthenticator.tsx +4 -0
- package/src/i18n/FireCMSi18nProvider.tsx +199 -23
- package/src/i18n/__tests__/FireCMSi18nProvider.test.tsx +91 -0
- package/src/i18n/__tests__/nested_provider_lifecycle.test.tsx +67 -0
- package/src/internal/useBuildDataSource.ts +37 -15
- package/src/internal/useBuildSideEntityController.tsx +20 -5
- package/src/locales/de.ts +37 -7
- package/src/locales/en.ts +41 -9
- package/src/locales/es.ts +37 -7
- package/src/locales/fr.ts +37 -7
- package/src/locales/hi.ts +37 -7
- package/src/locales/it.ts +37 -7
- package/src/locales/pl.ts +752 -0
- package/src/locales/pt.ts +37 -7
- package/src/preview/PropertyPreview.tsx +12 -0
- package/src/preview/components/DatePreview.tsx +2 -4
- package/src/preview/components/ReferencePreview.tsx +7 -3
- package/src/preview/components/StorageThumbnail.tsx +24 -2
- package/src/preview/index.ts +1 -0
- package/src/preview/property_previews/GeopointPropertyPreview.tsx +23 -0
- package/src/routes/FireCMSRoute.tsx +54 -27
- package/src/types/analytics.ts +3 -0
- package/src/types/collections.ts +34 -0
- package/src/types/datasource.ts +67 -4
- package/src/types/entities.ts +24 -1
- package/src/types/entity_actions.tsx +6 -0
- package/src/types/entity_callbacks.ts +24 -0
- package/src/types/firecms.tsx +19 -1
- package/src/types/firecms_context.tsx +9 -0
- package/src/types/index.ts +1 -0
- package/src/types/license.ts +63 -0
- package/src/types/navigation.ts +35 -5
- package/src/types/plugins.tsx +23 -1
- package/src/types/properties.ts +17 -0
- package/src/types/side_entity_controller.tsx +7 -0
- package/src/types/translations.ts +54 -5
- package/src/util/__tests__/collections.test.ts +32 -0
- package/src/util/__tests__/urls.test.ts +131 -0
- package/src/util/collections.ts +1 -1
- package/src/util/date_fns_locales.ts +168 -0
- package/src/util/entities.ts +16 -1
- package/src/util/entity_cache.ts +18 -0
- package/src/util/geopoint.ts +81 -0
- package/src/util/index.ts +3 -0
- package/src/util/lazy_eager.tsx +30 -8
- package/src/util/navigation_blocking.ts +45 -0
- package/src/util/navigation_from_path.ts +47 -7
- package/src/util/navigation_utils.ts +250 -5
- package/src/util/parent_references_from_path.ts +45 -4
- package/src/util/paths.ts +40 -3
- package/src/util/permissions.ts +22 -10
- package/src/util/previews.ts +8 -1
- package/src/util/resolutions.ts +11 -0
- package/src/util/urls.ts +52 -0
- package/src/util/useStorageUploadController.tsx +6 -1
|
@@ -90,6 +90,7 @@ import { useSelectionController } from "./useSelectionController";
|
|
|
90
90
|
import { EntityCollectionViewStartActions } from "./EntityCollectionViewStartActions";
|
|
91
91
|
import { addRecentId, getRecentIds } from "./utils";
|
|
92
92
|
import { useScrollRestoration } from "../common/useScrollRestoration";
|
|
93
|
+
import { entityCacheKey } from "../../util/entity_cache";
|
|
93
94
|
|
|
94
95
|
const DEFAULT_ENTITY_OPEN_MODE: "side_panel" | "full_screen" = "side_panel";
|
|
95
96
|
|
|
@@ -106,6 +107,14 @@ export type EntityCollectionViewProps<M extends Record<string, any>> = {
|
|
|
106
107
|
* Full path using navigation ids.
|
|
107
108
|
*/
|
|
108
109
|
fullIdPath?: string;
|
|
110
|
+
/**
|
|
111
|
+
* `fullPath` split at its real segment boundaries, e.g. `["nodes", "node/42", "edges"]`.
|
|
112
|
+
* Forwarded to the datasource so a parent entity id containing "/" stays unambiguous.
|
|
113
|
+
*
|
|
114
|
+
* Optional, and never derived by splitting `fullPath` — a guess would be wrong in
|
|
115
|
+
* exactly the case the field exists for. Absent means "not known here", not "no slashes".
|
|
116
|
+
*/
|
|
117
|
+
pathSegments?: string[];
|
|
109
118
|
/**
|
|
110
119
|
* If this is a subcollection, specify the parent collection ids.
|
|
111
120
|
*/
|
|
@@ -152,6 +161,7 @@ export const EntityCollectionView = React.memo(
|
|
|
152
161
|
function EntityCollectionView<M extends Record<string, any>>({
|
|
153
162
|
fullPath: fullPathProp,
|
|
154
163
|
fullIdPath,
|
|
164
|
+
pathSegments,
|
|
155
165
|
parentCollectionIds,
|
|
156
166
|
isSubCollection,
|
|
157
167
|
className,
|
|
@@ -178,7 +188,9 @@ export const EntityCollectionView = React.memo(
|
|
|
178
188
|
|
|
179
189
|
const collection = useMemo(() => {
|
|
180
190
|
const userOverride = userConfigPersistence?.getCollectionConfig<M>(fullPath);
|
|
181
|
-
|
|
191
|
+
if (!userOverride) return collectionProp;
|
|
192
|
+
const { properties, ...rest } = userOverride;
|
|
193
|
+
return mergeDeep(collectionProp, rest) as EntityCollection<M>;
|
|
182
194
|
}, [collectionProp, fullPath, userConfigPersistence?.getCollectionConfig]);
|
|
183
195
|
|
|
184
196
|
const openEntityMode = collection?.openEntityMode ?? DEFAULT_ENTITY_OPEN_MODE;
|
|
@@ -188,7 +200,7 @@ export const EntityCollectionView = React.memo(
|
|
|
188
200
|
collectionRef.current = collection;
|
|
189
201
|
}, [collection]);
|
|
190
202
|
|
|
191
|
-
const canCreateEntities = canCreateEntity(collection, authController, fullPath, null);
|
|
203
|
+
const canCreateEntities = canCreateEntity(collection, authController, fullPath, null, pathSegments);
|
|
192
204
|
const [highlightedEntity, setHighlightedEntity] = useState<Entity<M> | undefined>(undefined);
|
|
193
205
|
const [deleteEntityClicked, setDeleteEntityClicked] = React.useState<Entity<M> | Entity<M>[] | undefined>(undefined);
|
|
194
206
|
|
|
@@ -218,7 +230,7 @@ export const EntityCollectionView = React.memo(
|
|
|
218
230
|
|
|
219
231
|
const checkInlineEditing = useCallback((entity?: Entity<any>): boolean => {
|
|
220
232
|
const collection = collectionRef.current;
|
|
221
|
-
if (!canEditEntity(collection, authController, fullPath, entity ?? null)) {
|
|
233
|
+
if (!canEditEntity(collection, authController, fullPath, entity ?? null, pathSegments)) {
|
|
222
234
|
return false;
|
|
223
235
|
}
|
|
224
236
|
return collection.inlineEditing === undefined || collection.inlineEditing;
|
|
@@ -315,6 +327,7 @@ export const EntityCollectionView = React.memo(
|
|
|
315
327
|
|
|
316
328
|
const tableController = useDataSourceTableController<M>({
|
|
317
329
|
fullPath,
|
|
330
|
+
pathSegments,
|
|
318
331
|
collection,
|
|
319
332
|
lastDeleteTimestamp,
|
|
320
333
|
scrollRestoration,
|
|
@@ -340,10 +353,16 @@ export const EntityCollectionView = React.memo(
|
|
|
340
353
|
addRecentId(collection.id, clickedEntity.id);
|
|
341
354
|
}
|
|
342
355
|
|
|
343
|
-
|
|
356
|
+
// In a collection group the row's own path is the real one, so the row's segments
|
|
357
|
+
// are the matching ones; otherwise both come from this view. `path` and
|
|
358
|
+
// `pathSegments` are picked from the same source so they cannot describe
|
|
359
|
+
// different chains.
|
|
360
|
+
const isCollectionGroup = Boolean(collection?.collectionGroup);
|
|
361
|
+
const path = isCollectionGroup ? clickedEntity.path : (fullPath ?? clickedEntity.path);
|
|
344
362
|
navigateToEntity({
|
|
345
363
|
navigation,
|
|
346
364
|
path,
|
|
365
|
+
pathSegments: isCollectionGroup ? clickedEntity.pathSegments : (pathSegments ?? clickedEntity.pathSegments),
|
|
347
366
|
fullIdPath,
|
|
348
367
|
sideEntityController,
|
|
349
368
|
openEntityMode,
|
|
@@ -363,6 +382,7 @@ export const EntityCollectionView = React.memo(
|
|
|
363
382
|
collection,
|
|
364
383
|
entityId: undefined,
|
|
365
384
|
path: fullPath,
|
|
385
|
+
pathSegments,
|
|
366
386
|
fullIdPath,
|
|
367
387
|
sideEntityController,
|
|
368
388
|
navigation,
|
|
@@ -438,6 +458,7 @@ export const EntityCollectionView = React.memo(
|
|
|
438
458
|
const onViewModeChange = useCallback((mode: ViewMode) => {
|
|
439
459
|
analyticsController.onAnalyticsEvent?.("view_mode_changed", {
|
|
440
460
|
path: fullPath,
|
|
461
|
+
pathSegments,
|
|
441
462
|
from: viewMode,
|
|
442
463
|
to: mode
|
|
443
464
|
});
|
|
@@ -448,7 +469,7 @@ export const EntityCollectionView = React.memo(
|
|
|
448
469
|
}
|
|
449
470
|
}, [setViewMode, userConfigPersistence, onCollectionModifiedForUser, fullPath, analyticsController, viewMode]);
|
|
450
471
|
|
|
451
|
-
const createEnabled = canCreateEntity(collection, authController, fullPath, null);
|
|
472
|
+
const createEnabled = canCreateEntity(collection, authController, fullPath, null, pathSegments);
|
|
452
473
|
|
|
453
474
|
const uniqueFieldValidator: UniqueFieldValidator = useCallback(
|
|
454
475
|
({
|
|
@@ -456,8 +477,8 @@ export const EntityCollectionView = React.memo(
|
|
|
456
477
|
value,
|
|
457
478
|
property,
|
|
458
479
|
entityId
|
|
459
|
-
}) => dataSource.checkUniqueField(fullPath, name, value, entityId, collection),
|
|
460
|
-
[fullPath]);
|
|
480
|
+
}) => dataSource.checkUniqueField(fullPath, name, value, entityId, collection, pathSegments),
|
|
481
|
+
[fullPath, pathSegments]);
|
|
461
482
|
|
|
462
483
|
const onValueChange: OnCellValueChange<any, any> = ({
|
|
463
484
|
value,
|
|
@@ -471,6 +492,8 @@ export const EntityCollectionView = React.memo(
|
|
|
471
492
|
|
|
472
493
|
const saveProps: SaveEntityProps = {
|
|
473
494
|
path: entity.path ?? fullPath,
|
|
495
|
+
// Paired with the `path` above: the row's segments describe the row's path.
|
|
496
|
+
pathSegments: entity.path ? entity.pathSegments : pathSegments,
|
|
474
497
|
entityId: entity.id,
|
|
475
498
|
values: updatedValues,
|
|
476
499
|
previousValues: entity.values,
|
|
@@ -501,13 +524,14 @@ export const EntityCollectionView = React.memo(
|
|
|
501
524
|
|
|
502
525
|
};
|
|
503
526
|
|
|
504
|
-
const resolvedFullPath = navigation.resolveIdsFrom(fullPath);
|
|
527
|
+
const resolvedFullPath = navigation.resolveIdsFrom(fullPath, pathSegments);
|
|
505
528
|
const resolvedCollection = useMemo(() => resolveCollection<M>({
|
|
506
529
|
collection,
|
|
507
530
|
path: fullPath,
|
|
508
531
|
propertyConfigs: customizationController.propertyConfigs,
|
|
509
532
|
authController,
|
|
510
|
-
|
|
533
|
+
userConfigPersistence,
|
|
534
|
+
}), [collection, fullPath, userConfigPersistence]);
|
|
511
535
|
|
|
512
536
|
// Check if Kanban view is possible (collection has at least one string enum property)
|
|
513
537
|
const hasEnumProperty = useMemo(() => {
|
|
@@ -578,6 +602,7 @@ export const EntityCollectionView = React.memo(
|
|
|
578
602
|
const onKanbanPropertyChange = useCallback((property: string) => {
|
|
579
603
|
analyticsController.onAnalyticsEvent?.("kanban_property_changed", {
|
|
580
604
|
path: fullPath,
|
|
605
|
+
pathSegments,
|
|
581
606
|
property
|
|
582
607
|
});
|
|
583
608
|
setSelectedKanbanProperty(property);
|
|
@@ -642,6 +667,7 @@ export const EntityCollectionView = React.memo(
|
|
|
642
667
|
entityId: entity.id,
|
|
643
668
|
selectedTab: subcollection.id ?? subcollection.path,
|
|
644
669
|
path: fullPath,
|
|
670
|
+
pathSegments,
|
|
645
671
|
fullIdPath,
|
|
646
672
|
navigation,
|
|
647
673
|
sideEntityController
|
|
@@ -660,13 +686,15 @@ export const EntityCollectionView = React.memo(
|
|
|
660
686
|
width: 260,
|
|
661
687
|
dependencies: [],
|
|
662
688
|
Builder: ({ entity }) => {
|
|
663
|
-
|
|
689
|
+
// `entity.path` is a RAW datasource path, so its segments are passed:
|
|
690
|
+
// splitting it would mis-read any parent id containing "/".
|
|
691
|
+
const collectionsWithPath = navigation.getParentReferencesFromPath(entity.path, entity.pathSegments);
|
|
664
692
|
return (
|
|
665
693
|
<div className={"flex flex-col gap-2 w-full"}>
|
|
666
694
|
{collectionsWithPath.map((reference) => {
|
|
667
695
|
return (
|
|
668
696
|
<ReferencePreview
|
|
669
|
-
key={reference.path
|
|
697
|
+
key={entityCacheKey(reference.path, reference.id)}
|
|
670
698
|
reference={reference}
|
|
671
699
|
size={"small"} />
|
|
672
700
|
);
|
|
@@ -697,7 +725,7 @@ export const EntityCollectionView = React.memo(
|
|
|
697
725
|
entity?: Entity<M>,
|
|
698
726
|
customEntityActions?: EntityAction[]
|
|
699
727
|
}): EntityAction[] => {
|
|
700
|
-
const deleteEnabled = entity ? canDeleteEntity(collection, authController, fullPath, entity) : true;
|
|
728
|
+
const deleteEnabled = entity ? canDeleteEntity(collection, authController, fullPath, entity, entity.pathSegments ?? pathSegments) : true;
|
|
701
729
|
const actions: EntityAction[] = [
|
|
702
730
|
{ ...editEntityAction, name: t("edit") }
|
|
703
731
|
];
|
|
@@ -773,6 +801,7 @@ export const EntityCollectionView = React.memo(
|
|
|
773
801
|
// EntitiesCount fetches count and updates breadcrumb - no visual rendering needed here
|
|
774
802
|
const countFetcher = <EntitiesCount
|
|
775
803
|
fullPath={fullPath}
|
|
804
|
+
pathSegments={pathSegments}
|
|
776
805
|
collection={collection}
|
|
777
806
|
filter={tableController.filterValues}
|
|
778
807
|
sortBy={tableController.sortBy}
|
|
@@ -826,9 +855,14 @@ export const EntityCollectionView = React.memo(
|
|
|
826
855
|
onTextSearchClick,
|
|
827
856
|
textSearchEnabled
|
|
828
857
|
} = useTableSearchHelper({
|
|
858
|
+
pathSegments,
|
|
829
859
|
collection,
|
|
830
860
|
fullPath: resolvedFullPath,
|
|
831
|
-
parentCollectionIds
|
|
861
|
+
parentCollectionIds,
|
|
862
|
+
// When the search term comes from the URL instead of the search bar, text search
|
|
863
|
+
// has never been initialised for this collection. Initialise it so the search bar
|
|
864
|
+
// is usable (editable and clearable) right away.
|
|
865
|
+
initialSearchString: tableController.searchString
|
|
832
866
|
});
|
|
833
867
|
|
|
834
868
|
// Popover open state managed at parent level to prevent closing when view changes
|
|
@@ -878,6 +912,7 @@ export const EntityCollectionView = React.memo(
|
|
|
878
912
|
loading={tableController.dataLoading}
|
|
879
913
|
onTextSearch={textSearchEnabled && textSearchInitialised ? tableController.setSearchString : undefined}
|
|
880
914
|
onTextSearchClick={textSearchEnabled && !textSearchInitialised ? onTextSearchClick : undefined}
|
|
915
|
+
initialSearchString={tableController.searchString}
|
|
881
916
|
textSearchLoading={textSearchLoading}
|
|
882
917
|
viewModeToggle={viewModeToggleElement}
|
|
883
918
|
actionsStart={<EntityCollectionViewStartActions
|
|
@@ -885,6 +920,7 @@ export const EntityCollectionView = React.memo(
|
|
|
885
920
|
collection={collection}
|
|
886
921
|
tableController={tableController}
|
|
887
922
|
path={fullPath}
|
|
923
|
+
pathSegments={pathSegments}
|
|
888
924
|
relativePath={collection.path}
|
|
889
925
|
selectionController={usedSelectionController}
|
|
890
926
|
collectionEntitiesCount={docsCount}
|
|
@@ -896,6 +932,7 @@ export const EntityCollectionView = React.memo(
|
|
|
896
932
|
onMultipleDeleteClick={onMultipleDeleteClick}
|
|
897
933
|
onNewClick={onNewClick}
|
|
898
934
|
path={fullPath}
|
|
935
|
+
pathSegments={pathSegments}
|
|
899
936
|
relativePath={collection.path}
|
|
900
937
|
selectionController={usedSelectionController}
|
|
901
938
|
selectionEnabled={selectionEnabled}
|
|
@@ -912,6 +949,7 @@ export const EntityCollectionView = React.memo(
|
|
|
912
949
|
collection={collection}
|
|
913
950
|
tableController={tableController}
|
|
914
951
|
fullPath={fullPath}
|
|
952
|
+
pathSegments={pathSegments}
|
|
915
953
|
parentCollectionIds={parentCollectionIds}
|
|
916
954
|
columnProperty={selectedKanbanProperty}
|
|
917
955
|
onEntityClick={onEntityClick}
|
|
@@ -1003,6 +1041,7 @@ export const EntityCollectionView = React.memo(
|
|
|
1003
1041
|
getIdColumnWidth={getIdColumnWidth}
|
|
1004
1042
|
additionalIDHeaderWidget={<EntityIdHeaderWidget
|
|
1005
1043
|
path={fullPath}
|
|
1044
|
+
pathSegments={pathSegments}
|
|
1006
1045
|
fullIdPath={fullIdPath ?? fullPath}
|
|
1007
1046
|
collection={collection} />}
|
|
1008
1047
|
openEntityMode={openEntityMode}
|
|
@@ -1042,6 +1081,7 @@ export const EntityCollectionView = React.memo(
|
|
|
1042
1081
|
|
|
1043
1082
|
{popupCell && <PopupFormField
|
|
1044
1083
|
key={`popup_form_${popupCell?.propertyKey}_${popupCell?.entityId}`}
|
|
1084
|
+
pathSegments={pathSegments}
|
|
1045
1085
|
open={Boolean(popupCell)}
|
|
1046
1086
|
onClose={onPopupClose}
|
|
1047
1087
|
cellRect={popupCell?.cellRect}
|
|
@@ -1097,13 +1137,16 @@ function EntitiesCount({
|
|
|
1097
1137
|
collection,
|
|
1098
1138
|
filter,
|
|
1099
1139
|
sortBy,
|
|
1100
|
-
onCountChange
|
|
1140
|
+
onCountChange,
|
|
1141
|
+
pathSegments
|
|
1101
1142
|
}: {
|
|
1102
1143
|
fullPath: string,
|
|
1103
1144
|
collection: EntityCollection,
|
|
1104
1145
|
filter?: FilterValues<any>,
|
|
1105
1146
|
sortBy?: [string, "asc" | "desc"],
|
|
1106
1147
|
onCountChange?: (count: number) => void,
|
|
1148
|
+
/** `fullPath` split at its real segment boundaries; forwarded to countEntities. */
|
|
1149
|
+
pathSegments?: string[],
|
|
1107
1150
|
}) {
|
|
1108
1151
|
|
|
1109
1152
|
const dataSource = useDataSource(collection);
|
|
@@ -1113,18 +1156,24 @@ function EntitiesCount({
|
|
|
1113
1156
|
|
|
1114
1157
|
const sortByProperty = sortBy ? sortBy[0] : undefined;
|
|
1115
1158
|
const currentSort = sortBy ? sortBy[1] : undefined;
|
|
1116
|
-
|
|
1159
|
+
// Resolved together so the two representations always describe the same chain.
|
|
1160
|
+
// Segments are resolved, never derived (see useEntityFetch).
|
|
1161
|
+
const resolvedPath = useMemo(() => navigation.resolveIdsFrom(fullPath, pathSegments), [fullPath, pathSegments, navigation.resolveIdsFrom]);
|
|
1162
|
+
const resolvedPathSegments = useMemo(() => pathSegments
|
|
1163
|
+
? (navigation.resolveSegmentsFrom?.(pathSegments) ?? pathSegments)
|
|
1164
|
+
: undefined, [pathSegments, navigation.resolveSegmentsFrom]);
|
|
1117
1165
|
|
|
1118
1166
|
useEffect(() => {
|
|
1119
1167
|
if (dataSource.countEntities)
|
|
1120
1168
|
dataSource.countEntities({
|
|
1121
1169
|
path: resolvedPath,
|
|
1170
|
+
pathSegments: resolvedPathSegments,
|
|
1122
1171
|
collection,
|
|
1123
1172
|
filter,
|
|
1124
1173
|
orderBy: sortByProperty,
|
|
1125
1174
|
order: currentSort
|
|
1126
1175
|
}).then(setCount).catch(setError);
|
|
1127
|
-
}, [fullPath, dataSource.countEntities, resolvedPath, collection, filter, sortByProperty, currentSort]);
|
|
1176
|
+
}, [fullPath, dataSource.countEntities, resolvedPath, resolvedPathSegments, collection, filter, sortByProperty, currentSort]);
|
|
1128
1177
|
|
|
1129
1178
|
useEffect(() => {
|
|
1130
1179
|
if (onCountChange && count !== undefined) {
|
|
@@ -1153,10 +1202,13 @@ function buildPropertyWidthOverwrite(key: string, width: number): PartialEntityC
|
|
|
1153
1202
|
function EntityIdHeaderWidget({
|
|
1154
1203
|
collection,
|
|
1155
1204
|
path,
|
|
1205
|
+
pathSegments,
|
|
1156
1206
|
fullIdPath
|
|
1157
1207
|
}: {
|
|
1158
1208
|
collection: EntityCollection,
|
|
1159
1209
|
path: string,
|
|
1210
|
+
/** `path` split at its real segment boundaries, when the caller knows them. */
|
|
1211
|
+
pathSegments?: string[],
|
|
1160
1212
|
fullIdPath: string
|
|
1161
1213
|
}) {
|
|
1162
1214
|
|
|
@@ -1196,6 +1248,7 @@ function EntityIdHeaderWidget({
|
|
|
1196
1248
|
collection,
|
|
1197
1249
|
entityId,
|
|
1198
1250
|
path,
|
|
1251
|
+
pathSegments,
|
|
1199
1252
|
fullIdPath,
|
|
1200
1253
|
sideEntityController,
|
|
1201
1254
|
navigation
|
|
@@ -1221,7 +1274,7 @@ function EntityIdHeaderWidget({
|
|
|
1221
1274
|
</form>
|
|
1222
1275
|
{recentIds && recentIds.length > 0 && <div className="flex flex-col gap-2 p-2">
|
|
1223
1276
|
{recentIds.map(id => (
|
|
1224
|
-
<ReferencePreview reference={new EntityReference(id, path)}
|
|
1277
|
+
<ReferencePreview reference={new EntityReference(id, path, undefined, pathSegments)}
|
|
1225
1278
|
key={id}
|
|
1226
1279
|
hover={true}
|
|
1227
1280
|
onClick={() => {
|
|
@@ -1231,6 +1284,7 @@ function EntityIdHeaderWidget({
|
|
|
1231
1284
|
collection,
|
|
1232
1285
|
entityId: id,
|
|
1233
1286
|
path,
|
|
1287
|
+
pathSegments,
|
|
1234
1288
|
fullIdPath,
|
|
1235
1289
|
sideEntityController,
|
|
1236
1290
|
navigation
|
|
@@ -22,6 +22,8 @@ import { useTranslation } from "../../hooks/useTranslation";
|
|
|
22
22
|
export type EntityCollectionViewActionsProps<M extends Record<string, any>> = {
|
|
23
23
|
collection: EntityCollection<M>;
|
|
24
24
|
path: string;
|
|
25
|
+
/** `path` split at its real segment boundaries, when known. Never derived from `path`. */
|
|
26
|
+
pathSegments?: string[];
|
|
25
27
|
relativePath: string;
|
|
26
28
|
parentCollectionIds: string[];
|
|
27
29
|
selectionEnabled: boolean;
|
|
@@ -40,6 +42,7 @@ export function EntityCollectionViewActions<M extends Record<string, any>>({
|
|
|
40
42
|
onMultipleDeleteClick,
|
|
41
43
|
selectionEnabled,
|
|
42
44
|
path,
|
|
45
|
+
pathSegments,
|
|
43
46
|
selectionController,
|
|
44
47
|
tableController,
|
|
45
48
|
collectionEntitiesCount,
|
|
@@ -56,7 +59,7 @@ export function EntityCollectionViewActions<M extends Record<string, any>>({
|
|
|
56
59
|
|
|
57
60
|
const selectedEntities = selectionController.selectedEntities;
|
|
58
61
|
|
|
59
|
-
const addButton = canCreateEntity(collection, authController, path, null) &&
|
|
62
|
+
const addButton = canCreateEntity(collection, authController, path, null, pathSegments) &&
|
|
60
63
|
onNewClick && (largeLayout
|
|
61
64
|
? <Button
|
|
62
65
|
id={`add_entity_${path}`}
|
|
@@ -75,7 +78,7 @@ export function EntityCollectionViewActions<M extends Record<string, any>>({
|
|
|
75
78
|
<AddIcon size={"small"} />
|
|
76
79
|
</Button>);
|
|
77
80
|
|
|
78
|
-
const multipleDeleteEnabled = canDeleteEntity(collection, authController, path, null);
|
|
81
|
+
const multipleDeleteEnabled = canDeleteEntity(collection, authController, path, null, pathSegments);
|
|
79
82
|
|
|
80
83
|
let multipleDeleteButton: React.ReactNode | undefined;
|
|
81
84
|
if (selectionEnabled) {
|
|
@@ -107,6 +110,7 @@ export function EntityCollectionViewActions<M extends Record<string, any>>({
|
|
|
107
110
|
|
|
108
111
|
const actionProps: CollectionActionsProps = {
|
|
109
112
|
path,
|
|
113
|
+
pathSegments,
|
|
110
114
|
relativePath,
|
|
111
115
|
parentCollectionIds,
|
|
112
116
|
collection,
|
|
@@ -17,6 +17,8 @@ import { useTranslation } from "../../hooks/useTranslation";
|
|
|
17
17
|
export type EntityCollectionViewStartActionsProps<M extends Record<string, any>> = {
|
|
18
18
|
collection: EntityCollection<M>;
|
|
19
19
|
path: string;
|
|
20
|
+
/** `path` split at its real segment boundaries, when known. Never derived from `path`. */
|
|
21
|
+
pathSegments?: string[];
|
|
20
22
|
relativePath: string;
|
|
21
23
|
parentCollectionIds: string[];
|
|
22
24
|
selectionController: SelectionController<M>;
|
|
@@ -33,6 +35,7 @@ export function EntityCollectionViewStartActions<M extends Record<string, any>>(
|
|
|
33
35
|
relativePath,
|
|
34
36
|
parentCollectionIds,
|
|
35
37
|
path,
|
|
38
|
+
pathSegments,
|
|
36
39
|
selectionController,
|
|
37
40
|
tableController,
|
|
38
41
|
collectionEntitiesCount,
|
|
@@ -57,6 +60,7 @@ export function EntityCollectionViewStartActions<M extends Record<string, any>>(
|
|
|
57
60
|
|
|
58
61
|
const actionProps: CollectionActionsProps = {
|
|
59
62
|
path,
|
|
63
|
+
pathSegments,
|
|
60
64
|
relativePath,
|
|
61
65
|
parentCollectionIds,
|
|
62
66
|
collection,
|
|
@@ -66,8 +70,10 @@ export function EntityCollectionViewStartActions<M extends Record<string, any>>(
|
|
|
66
70
|
collectionEntitiesCount
|
|
67
71
|
};
|
|
68
72
|
|
|
73
|
+
const hasAnyAllowedFilters = !tableController.allowedFilters || tableController.allowedFilters.length > 0;
|
|
74
|
+
|
|
69
75
|
// Filters button
|
|
70
|
-
const filtersButton = resolvedProperties && tableController.setFilterValues && (
|
|
76
|
+
const filtersButton = resolvedProperties && tableController.setFilterValues && hasAnyAllowedFilters && (
|
|
71
77
|
<Tooltip title={t("filters")}
|
|
72
78
|
key={"filters_tooltip"}>
|
|
73
79
|
<Badge
|
|
@@ -131,6 +137,7 @@ export function EntityCollectionViewStartActions<M extends Record<string, any>>(
|
|
|
131
137
|
filterValues={tableController.filterValues}
|
|
132
138
|
setFilterValues={(filterValues) => tableController.setFilterValues?.(filterValues ?? {})}
|
|
133
139
|
forceFilter={collection.forceFilter}
|
|
140
|
+
allowedFilters={tableController.allowedFilters?.map(key => key.toString())}
|
|
134
141
|
/>
|
|
135
142
|
)}
|
|
136
143
|
</>
|
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
DialogActions,
|
|
13
13
|
DialogContent,
|
|
14
14
|
DialogTitle,
|
|
15
|
-
FilterListIcon,
|
|
16
15
|
Typography
|
|
17
16
|
} from "@firecms/ui";
|
|
18
17
|
import { useTranslation } from "../../hooks/useTranslation";
|
|
@@ -30,6 +29,7 @@ export interface FiltersDialogProps {
|
|
|
30
29
|
filterValues: FilterValues<any> | undefined;
|
|
31
30
|
setFilterValues: (filterValues?: FilterValues<any>) => void;
|
|
32
31
|
forceFilter?: FilterValues<any>;
|
|
32
|
+
allowedFilters?: string[];
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
/**
|
|
@@ -42,7 +42,8 @@ export function FiltersDialog({
|
|
|
42
42
|
properties,
|
|
43
43
|
filterValues,
|
|
44
44
|
setFilterValues,
|
|
45
|
-
forceFilter
|
|
45
|
+
forceFilter,
|
|
46
|
+
allowedFilters
|
|
46
47
|
}: FiltersDialogProps) {
|
|
47
48
|
const { t } = useTranslation();
|
|
48
49
|
|
|
@@ -59,18 +60,18 @@ export function FiltersDialog({
|
|
|
59
60
|
}
|
|
60
61
|
}, [open, filterValues]);
|
|
61
62
|
|
|
62
|
-
// Get list of
|
|
63
|
-
const
|
|
64
|
-
return Object.entries(properties).filter(([key
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (!baseProperty) return false;
|
|
71
|
-
return ["string", "number", "boolean", "date", "reference"].includes(baseProperty.dataType);
|
|
63
|
+
// Get list of editable filter properties
|
|
64
|
+
const editableFilterProperties = useMemo(() => {
|
|
65
|
+
return Object.entries(properties).filter(([key]) => {
|
|
66
|
+
const isFilterAllowed = !allowedFilters || allowedFilters.includes(key);
|
|
67
|
+
|
|
68
|
+
const isFilterForced = Boolean(forceFilter && Object.keys(forceFilter).includes(key));
|
|
69
|
+
|
|
70
|
+
return isFilterAllowed && !isFilterForced;
|
|
72
71
|
});
|
|
73
|
-
}, [properties, forceFilter]);
|
|
72
|
+
}, [properties, allowedFilters, forceFilter]);
|
|
73
|
+
|
|
74
|
+
const hasEditableFilterProperties = editableFilterProperties.length > 0;
|
|
74
75
|
|
|
75
76
|
const handleFilterChange = useCallback((propertyKey: string, value?: [VirtualTableWhereFilterOp, any]) => {
|
|
76
77
|
setLocalFilters(prev => {
|
|
@@ -103,7 +104,13 @@ export function FiltersDialog({
|
|
|
103
104
|
|
|
104
105
|
// Check if any reference field's dialog is currently open (should hide this dialog)
|
|
105
106
|
const isAnyFieldHidden = Object.values(hiddenFields).some(hidden => hidden);
|
|
106
|
-
|
|
107
|
+
|
|
108
|
+
const getActiveFilterCount = () => {
|
|
109
|
+
const editableLocalFilters = Object.keys(localFilters).filter((key) => !forceFilter || !(key in forceFilter));
|
|
110
|
+
return editableLocalFilters.length;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const activeFilterCount = getActiveFilterCount();
|
|
107
114
|
|
|
108
115
|
const renderFilterField = useCallback((propertyKey: string, property: ResolvedProperty) => {
|
|
109
116
|
const isArray = property.dataType === "array";
|
|
@@ -185,14 +192,14 @@ export function FiltersDialog({
|
|
|
185
192
|
</DialogTitle>
|
|
186
193
|
|
|
187
194
|
<DialogContent >
|
|
188
|
-
{
|
|
195
|
+
{!hasEditableFilterProperties ? (
|
|
189
196
|
<Typography color="secondary" className="py-8 text-center">
|
|
190
197
|
{t("no_filterable_properties")}
|
|
191
198
|
</Typography>
|
|
192
199
|
) : (
|
|
193
200
|
<table className="w-full border-collapse">
|
|
194
201
|
<tbody>
|
|
195
|
-
{
|
|
202
|
+
{editableFilterProperties.map(([propertyKey, property], index) => {
|
|
196
203
|
const hasFilter = propertyKey in localFilters;
|
|
197
204
|
|
|
198
205
|
return (
|
|
@@ -234,18 +241,22 @@ export function FiltersDialog({
|
|
|
234
241
|
{t("clear")}
|
|
235
242
|
</Button>
|
|
236
243
|
<div className="flex-grow" />
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
244
|
+
{hasEditableFilterProperties && (
|
|
245
|
+
<>
|
|
246
|
+
<Button
|
|
247
|
+
variant="text"
|
|
248
|
+
onClick={() => onOpenChange(false)}
|
|
249
|
+
>
|
|
250
|
+
{t("cancel")}
|
|
251
|
+
</Button>
|
|
252
|
+
<Button
|
|
253
|
+
variant="filled"
|
|
254
|
+
onClick={handleApply}
|
|
255
|
+
>
|
|
256
|
+
{t("apply_filters")}
|
|
257
|
+
</Button>
|
|
258
|
+
</>
|
|
259
|
+
)}
|
|
249
260
|
</DialogActions>
|
|
250
261
|
</Dialog>
|
|
251
262
|
);
|
|
@@ -45,6 +45,8 @@ export interface BoardDataController<M extends Record<string, any> = any, COLUMN
|
|
|
45
45
|
export interface UseBoardDataControllerProps<M extends Record<string, any> = any> {
|
|
46
46
|
/** Full path to the collection */
|
|
47
47
|
fullPath: string;
|
|
48
|
+
/** `fullPath` split at its real segment boundaries; forwarded to the datasource. */
|
|
49
|
+
pathSegments?: string[];
|
|
48
50
|
/** The entity collection configuration */
|
|
49
51
|
collection: EntityCollection<M>;
|
|
50
52
|
/** Property key used for column assignment */
|
|
@@ -67,6 +69,7 @@ export interface UseBoardDataControllerProps<M extends Record<string, any> = any
|
|
|
67
69
|
*/
|
|
68
70
|
export function useBoardDataController<M extends Record<string, any> = any, COLUMN extends string = string>({
|
|
69
71
|
fullPath,
|
|
72
|
+
pathSegments,
|
|
70
73
|
collection,
|
|
71
74
|
columnProperty,
|
|
72
75
|
columns,
|
|
@@ -79,7 +82,12 @@ export function useBoardDataController<M extends Record<string, any> = any, COLU
|
|
|
79
82
|
const context = useFireCMSContext();
|
|
80
83
|
const dataSource = useDataSource(collection);
|
|
81
84
|
const navigation = useNavigationController();
|
|
82
|
-
|
|
85
|
+
// Resolved together so the two representations always describe the same chain.
|
|
86
|
+
// Segments are resolved, never derived (see useEntityFetch).
|
|
87
|
+
const resolvedPath = useMemo(() => navigation.resolveIdsFrom(fullPath, pathSegments), [fullPath, pathSegments, navigation.resolveIdsFrom]);
|
|
88
|
+
const resolvedPathSegments = useMemo(() => pathSegments
|
|
89
|
+
? (navigation.resolveSegmentsFrom?.(pathSegments) ?? pathSegments)
|
|
90
|
+
: undefined, [pathSegments, navigation.resolveSegmentsFrom]);
|
|
83
91
|
|
|
84
92
|
// Stable refs for objects that shouldn't trigger re-subscriptions
|
|
85
93
|
const dataSourceRef = useRef(dataSource);
|
|
@@ -95,11 +103,13 @@ export function useBoardDataController<M extends Record<string, any> = any, COLU
|
|
|
95
103
|
const orderPropertyRef = useRef(orderProperty);
|
|
96
104
|
const searchStringRef = useRef(searchString);
|
|
97
105
|
const resolvedPathRef = useRef(resolvedPath);
|
|
106
|
+
const resolvedPathSegmentsRef = useRef(resolvedPathSegments);
|
|
98
107
|
filterValuesRef.current = filterValues;
|
|
99
108
|
columnPropertyRef.current = columnProperty;
|
|
100
109
|
orderPropertyRef.current = orderProperty;
|
|
101
110
|
searchStringRef.current = searchString;
|
|
102
111
|
resolvedPathRef.current = resolvedPath;
|
|
112
|
+
resolvedPathSegmentsRef.current = resolvedPathSegments;
|
|
103
113
|
|
|
104
114
|
// Track item count per column for pagination
|
|
105
115
|
const [columnItemCounts, setColumnItemCounts] = useState<Record<string, number>>(() => {
|
|
@@ -168,6 +178,7 @@ export function useBoardDataController<M extends Record<string, any> = any, COLU
|
|
|
168
178
|
const currentOrderProperty = orderPropertyRef.current;
|
|
169
179
|
const currentSearchString = searchStringRef.current;
|
|
170
180
|
const currentResolvedPath = resolvedPathRef.current;
|
|
181
|
+
const currentPathSegments = resolvedPathSegmentsRef.current;
|
|
171
182
|
|
|
172
183
|
// Build filter for this column
|
|
173
184
|
const columnFilter: FilterValues<string> = {
|
|
@@ -205,6 +216,7 @@ export function useBoardDataController<M extends Record<string, any> = any, COLU
|
|
|
205
216
|
currentCollection.callbacks!.onFetch!({
|
|
206
217
|
collection: currentCollection,
|
|
207
218
|
path: currentResolvedPath,
|
|
219
|
+
pathSegments: currentPathSegments,
|
|
208
220
|
entity,
|
|
209
221
|
context: currentContext
|
|
210
222
|
})
|
|
@@ -248,6 +260,7 @@ export function useBoardDataController<M extends Record<string, any> = any, COLU
|
|
|
248
260
|
if (currentDataSource.listenCollection) {
|
|
249
261
|
const unsubscribe = currentDataSource.listenCollection<M>({
|
|
250
262
|
path: currentResolvedPath,
|
|
263
|
+
pathSegments: currentPathSegments,
|
|
251
264
|
collection: currentCollection,
|
|
252
265
|
onUpdate,
|
|
253
266
|
onError,
|
|
@@ -262,6 +275,7 @@ export function useBoardDataController<M extends Record<string, any> = any, COLU
|
|
|
262
275
|
} else {
|
|
263
276
|
currentDataSource.fetchCollection<M>({
|
|
264
277
|
path: currentResolvedPath,
|
|
278
|
+
pathSegments: currentPathSegments,
|
|
265
279
|
collection: currentCollection,
|
|
266
280
|
searchString: currentSearchString,
|
|
267
281
|
filter: columnFilter,
|
|
@@ -297,6 +311,7 @@ export function useBoardDataController<M extends Record<string, any> = any, COLU
|
|
|
297
311
|
const currentColumnProperty = columnPropertyRef.current;
|
|
298
312
|
const currentSearchString = searchStringRef.current;
|
|
299
313
|
const currentResolvedPath = resolvedPathRef.current;
|
|
314
|
+
const currentPathSegments = resolvedPathSegmentsRef.current;
|
|
300
315
|
const currentColumns = columns;
|
|
301
316
|
const currentColumnItemCounts = columnItemCounts;
|
|
302
317
|
|
|
@@ -316,6 +331,7 @@ export function useBoardDataController<M extends Record<string, any> = any, COLU
|
|
|
316
331
|
};
|
|
317
332
|
currentDataSource.countEntities({
|
|
318
333
|
path: currentResolvedPath,
|
|
334
|
+
pathSegments: currentPathSegments,
|
|
319
335
|
collection: currentCollection,
|
|
320
336
|
filter: columnFilter,
|
|
321
337
|
searchString: currentSearchString
|