@firecms/core 3.4.0-canary.8635253 → 3.4.0-canary.ce97da7
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/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/useBoardDataController.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/EntityEditView.d.ts +9 -1
- package/dist/core/EntityEditViewFormActions.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-DMp6cIY1.js +702 -0
- package/dist/de-DMp6cIY1.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/fr-Cckz4IkR.js +702 -0
- package/dist/fr-Cckz4IkR.js.map +1 -0
- package/dist/hi-CDCoIqbu.js +702 -0
- package/dist/hi-CDCoIqbu.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 +3921 -11331
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +8950 -7585
- package/dist/index.umd.js.map +1 -1
- package/dist/it-BJCUqixj.js +702 -0
- package/dist/it-BJCUqixj.js.map +1 -0
- package/dist/pl-DgT_joFf.js +704 -0
- package/dist/pl-DgT_joFf.js.map +1 -0
- package/dist/pt-B3dN3x0X.js +704 -0
- package/dist/pt-B3dN3x0X.js.map +1 -0
- package/dist/types/analytics.d.ts +1 -1
- package/dist/types/collections.d.ts +14 -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 +54 -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 +41 -2
- 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/entity_cache.d.ts +11 -0
- package/dist/util/index.d.ts +2 -0
- package/dist/util/lazy_eager.d.ts +3 -3
- package/dist/util/navigation_from_path.d.ts +7 -0
- package/dist/util/navigation_utils.d.ts +87 -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 +5 -5
- package/src/app/Scaffold.tsx +7 -0
- package/src/components/DeleteEntityDialog.tsx +2 -0
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +2 -2
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +1 -0
- 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 +66 -15
- package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +6 -2
- package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +4 -0
- package/src/components/EntityCollectionView/useBoardDataController.tsx +17 -1
- package/src/components/EntityPreview.tsx +4 -1
- package/src/components/ErrorBoundary.tsx +12 -18
- package/src/components/LicenseBanner.tsx +209 -0
- package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +19 -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/common/default_entity_actions.tsx +22 -2
- package/src/components/common/table_url_params.ts +172 -0
- package/src/components/common/useDataSourceTableController.tsx +86 -179
- 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/EntityEditView.tsx +20 -3
- 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/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/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 +70 -15
- 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 -25
- 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 +19 -5
- package/src/locales/de.ts +23 -2
- package/src/locales/en.ts +26 -3
- package/src/locales/es.ts +23 -2
- package/src/locales/fr.ts +23 -2
- package/src/locales/hi.ts +23 -2
- package/src/locales/it.ts +23 -2
- package/src/locales/pl.ts +23 -2
- package/src/locales/pt.ts +23 -2
- 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/routes/FireCMSRoute.tsx +11 -3
- package/src/types/analytics.ts +3 -0
- package/src/types/collections.ts +16 -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 +62 -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 +41 -2
- 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 +3 -1
- package/src/util/entity_cache.ts +18 -0
- package/src/util/index.ts +2 -0
- package/src/util/lazy_eager.tsx +30 -8
- package/src/util/navigation_from_path.ts +25 -2
- package/src/util/navigation_utils.ts +214 -3
- package/src/util/parent_references_from_path.ts +42 -3
- 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 +8 -0
- package/src/util/urls.ts +52 -0
- package/src/util/useStorageUploadController.tsx +6 -1
|
@@ -96,6 +96,8 @@ export function DeleteEntityDialog<M extends Record<string, any>>({
|
|
|
96
96
|
deleteEntityWithCallbacks({
|
|
97
97
|
dataSource,
|
|
98
98
|
entity,
|
|
99
|
+
// The entity is the authority on where it lives; stated rather than left implicit.
|
|
100
|
+
pathSegments: entity.pathSegments,
|
|
99
101
|
collection: resolvedCollection,
|
|
100
102
|
callbacks,
|
|
101
103
|
onDeleteSuccess,
|
|
@@ -3,7 +3,7 @@ import React, { MouseEvent, useCallback } from "react";
|
|
|
3
3
|
import { CollectionSize, Entity, EntityAction, EntityCollection, SelectionController } from "../../types";
|
|
4
4
|
import { Badge, Checkbox, cls, IconButton, Menu, MenuItem, MoreVertIcon, Skeleton, Tooltip } from "@firecms/ui";
|
|
5
5
|
import { useFireCMSContext, useLargeLayout } from "../../hooks";
|
|
6
|
-
import { getEntityFromCache } from "../../util/entity_cache";
|
|
6
|
+
import { entityCacheKey, getEntityFromCache } from "../../util/entity_cache";
|
|
7
7
|
import { getLocalChangesBackup } from "../../util";
|
|
8
8
|
import { getChanges } from "../../form/EntityForm";
|
|
9
9
|
|
|
@@ -82,7 +82,7 @@ export const EntityCollectionRowActions = function EntityCollectionRowActions({
|
|
|
82
82
|
const collapsedActions = actions.filter(a => a.collapsed || a.collapsed === undefined);
|
|
83
83
|
const uncollapsedActions = actions.filter(a => a.collapsed === false);
|
|
84
84
|
const enableLocalChangesBackup = collection ? getLocalChangesBackup(collection) : false;
|
|
85
|
-
const cachedData = enableLocalChangesBackup ? getEntityFromCache(fullPath
|
|
85
|
+
const cachedData = enableLocalChangesBackup ? getEntityFromCache(entityCacheKey(fullPath, entity.id)) : undefined;
|
|
86
86
|
const hasDraft = (() => {
|
|
87
87
|
if (!cachedData || typeof cachedData !== "object" || Object.keys(cachedData).length === 0) return false;
|
|
88
88
|
const realChanges = getChanges(cachedData as any, (entity?.values ?? {}) as any);
|
|
@@ -354,6 +354,7 @@ export const EntityCollectionTable = function EntityCollectionTable<M extends Re
|
|
|
354
354
|
onTextSearch={textSearchEnabled ? onTextSearch : undefined}
|
|
355
355
|
textSearchLoading={textSearchLoading}
|
|
356
356
|
onTextSearchClick={textSearchEnabled ? onTextSearchClick : undefined}
|
|
357
|
+
initialSearchString={tableController.searchString}
|
|
357
358
|
title={title}
|
|
358
359
|
actionsStart={actionsStart}
|
|
359
360
|
actions={actions}
|
|
@@ -20,6 +20,11 @@ interface CollectionTableToolbarProps {
|
|
|
20
20
|
onTextSearchClick?: () => void;
|
|
21
21
|
onTextSearch?: (searchString?: string) => void;
|
|
22
22
|
textSearchLoading?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Search term the search bar should start with, typically the one restored from the
|
|
25
|
+
* URL query params by the table controller.
|
|
26
|
+
*/
|
|
27
|
+
initialSearchString?: string;
|
|
23
28
|
}
|
|
24
29
|
|
|
25
30
|
export function CollectionTableToolbar({
|
|
@@ -29,6 +34,7 @@ export function CollectionTableToolbar({
|
|
|
29
34
|
onTextSearch,
|
|
30
35
|
onTextSearchClick,
|
|
31
36
|
textSearchLoading,
|
|
37
|
+
initialSearchString,
|
|
32
38
|
title,
|
|
33
39
|
viewModeToggle
|
|
34
40
|
}: CollectionTableToolbarProps) {
|
|
@@ -79,6 +85,7 @@ export function CollectionTableToolbar({
|
|
|
79
85
|
disabled={Boolean(onTextSearchClick)}
|
|
80
86
|
onClick={onTextSearchClick}
|
|
81
87
|
onTextSearch={onTextSearchClick ? undefined : onTextSearch}
|
|
88
|
+
initialValue={initialSearchString}
|
|
82
89
|
placeholder={t("search")}
|
|
83
90
|
expandable={true} />}
|
|
84
91
|
|
|
@@ -26,6 +26,8 @@ import { OnCellValueChangeParams } from "../../../common";
|
|
|
26
26
|
interface PopupFormFieldProps<M extends Record<string, any>> {
|
|
27
27
|
customFieldValidator?: CustomFieldValidator;
|
|
28
28
|
path: string;
|
|
29
|
+
/** `path` split at its real segment boundaries; forwarded to the datasource. */
|
|
30
|
+
pathSegments?: string[];
|
|
29
31
|
entityId: string;
|
|
30
32
|
tableKey: string;
|
|
31
33
|
propertyKey?: Extract<keyof M, string>;
|
|
@@ -54,6 +56,7 @@ export function PopupFormFieldLoading<M extends Record<string, any>>({
|
|
|
54
56
|
propertyKey,
|
|
55
57
|
collection: inputCollection,
|
|
56
58
|
path,
|
|
59
|
+
pathSegments,
|
|
57
60
|
cellRect,
|
|
58
61
|
open,
|
|
59
62
|
onClose,
|
|
@@ -66,11 +69,12 @@ export function PopupFormFieldLoading<M extends Record<string, any>>({
|
|
|
66
69
|
if (entityId && inputCollection) {
|
|
67
70
|
dataSource.fetchEntity({
|
|
68
71
|
path,
|
|
72
|
+
pathSegments,
|
|
69
73
|
entityId,
|
|
70
74
|
collection: inputCollection
|
|
71
75
|
}).then(setEntity);
|
|
72
76
|
}
|
|
73
|
-
}, [entityId, inputCollection, dataSource, path]);
|
|
77
|
+
}, [entityId, inputCollection, dataSource, path, pathSegments]);
|
|
74
78
|
|
|
75
79
|
if (!entity) return null;
|
|
76
80
|
return <PopupFormFieldInternal {...{
|
|
@@ -42,6 +42,8 @@ export type EntityCollectionBoardViewProps<M extends Record<string, any> = any>
|
|
|
42
42
|
collection: EntityCollection<M>;
|
|
43
43
|
tableController: EntityTableController<M>;
|
|
44
44
|
fullPath: string;
|
|
45
|
+
/** `fullPath` split at its real segment boundaries; forwarded to the datasource. */
|
|
46
|
+
pathSegments?: string[];
|
|
45
47
|
parentCollectionIds?: string[];
|
|
46
48
|
columnProperty: string;
|
|
47
49
|
onEntityClick?: (entity: Entity<M>) => void;
|
|
@@ -60,6 +62,7 @@ export function EntityCollectionBoardView<M extends Record<string, any> = any>({
|
|
|
60
62
|
collection,
|
|
61
63
|
tableController,
|
|
62
64
|
fullPath,
|
|
65
|
+
pathSegments,
|
|
63
66
|
parentCollectionIds = [],
|
|
64
67
|
columnProperty,
|
|
65
68
|
onEntityClick,
|
|
@@ -169,6 +172,7 @@ export function EntityCollectionBoardView<M extends Record<string, any> = any>({
|
|
|
169
172
|
// Use the new per-column data controller
|
|
170
173
|
const boardDataController = useBoardDataController<M>({
|
|
171
174
|
fullPath,
|
|
175
|
+
pathSegments,
|
|
172
176
|
collection,
|
|
173
177
|
columnProperty,
|
|
174
178
|
columns,
|
|
@@ -270,6 +274,7 @@ export function EntityCollectionBoardView<M extends Record<string, any> = any>({
|
|
|
270
274
|
|
|
271
275
|
currentDataSource.countEntities({
|
|
272
276
|
path: fullPath,
|
|
277
|
+
pathSegments,
|
|
273
278
|
collection: currentCollection
|
|
274
279
|
}).then(count => {
|
|
275
280
|
totalCount = count;
|
|
@@ -281,6 +286,7 @@ export function EntityCollectionBoardView<M extends Record<string, any> = any>({
|
|
|
281
286
|
|
|
282
287
|
currentDataSource.countEntities({
|
|
283
288
|
path: fullPath,
|
|
289
|
+
pathSegments,
|
|
284
290
|
collection: currentCollection,
|
|
285
291
|
filter: { [orderProperty]: ["!=", null] } as FilterValues<string>
|
|
286
292
|
}).then(count => {
|
|
@@ -432,6 +438,8 @@ export function EntityCollectionBoardView<M extends Record<string, any> = any>({
|
|
|
432
438
|
|
|
433
439
|
const saveProps: SaveEntityProps = {
|
|
434
440
|
path: entity.path,
|
|
441
|
+
// Paired with `entity.path`: the segments the entity was loaded with.
|
|
442
|
+
pathSegments: entity.pathSegments,
|
|
435
443
|
entityId: entity.id,
|
|
436
444
|
values: updatedValues as M,
|
|
437
445
|
previousValues: entity.values,
|
|
@@ -472,6 +480,7 @@ export function EntityCollectionBoardView<M extends Record<string, any> = any>({
|
|
|
472
480
|
console.log("Fetching all documents from collection...");
|
|
473
481
|
const allDocs = await dataSource.fetchCollection<M>({
|
|
474
482
|
path: fullPath,
|
|
483
|
+
pathSegments,
|
|
475
484
|
collection,
|
|
476
485
|
limit: 10000 // Fetch all
|
|
477
486
|
});
|
|
@@ -492,6 +501,8 @@ export function EntityCollectionBoardView<M extends Record<string, any> = any>({
|
|
|
492
501
|
|
|
493
502
|
const saveProps: SaveEntityProps = {
|
|
494
503
|
path: entity.path,
|
|
504
|
+
// Paired with `entity.path`: the segments the entity was loaded with.
|
|
505
|
+
pathSegments: entity.pathSegments,
|
|
495
506
|
entityId: entity.id,
|
|
496
507
|
values: updatedValues as M,
|
|
497
508
|
previousValues: entity.values,
|
|
@@ -663,6 +674,7 @@ export function EntityCollectionBoardView<M extends Record<string, any> = any>({
|
|
|
663
674
|
});
|
|
664
675
|
sideEntityController.open({
|
|
665
676
|
path: fullPath,
|
|
677
|
+
pathSegments,
|
|
666
678
|
collection,
|
|
667
679
|
entityId: undefined,
|
|
668
680
|
updateUrl: true,
|
|
@@ -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,
|
|
@@ -190,7 +200,7 @@ export const EntityCollectionView = React.memo(
|
|
|
190
200
|
collectionRef.current = collection;
|
|
191
201
|
}, [collection]);
|
|
192
202
|
|
|
193
|
-
const canCreateEntities = canCreateEntity(collection, authController, fullPath, null);
|
|
203
|
+
const canCreateEntities = canCreateEntity(collection, authController, fullPath, null, pathSegments);
|
|
194
204
|
const [highlightedEntity, setHighlightedEntity] = useState<Entity<M> | undefined>(undefined);
|
|
195
205
|
const [deleteEntityClicked, setDeleteEntityClicked] = React.useState<Entity<M> | Entity<M>[] | undefined>(undefined);
|
|
196
206
|
|
|
@@ -220,7 +230,7 @@ export const EntityCollectionView = React.memo(
|
|
|
220
230
|
|
|
221
231
|
const checkInlineEditing = useCallback((entity?: Entity<any>): boolean => {
|
|
222
232
|
const collection = collectionRef.current;
|
|
223
|
-
if (!canEditEntity(collection, authController, fullPath, entity ?? null)) {
|
|
233
|
+
if (!canEditEntity(collection, authController, fullPath, entity ?? null, pathSegments)) {
|
|
224
234
|
return false;
|
|
225
235
|
}
|
|
226
236
|
return collection.inlineEditing === undefined || collection.inlineEditing;
|
|
@@ -317,6 +327,7 @@ export const EntityCollectionView = React.memo(
|
|
|
317
327
|
|
|
318
328
|
const tableController = useDataSourceTableController<M>({
|
|
319
329
|
fullPath,
|
|
330
|
+
pathSegments,
|
|
320
331
|
collection,
|
|
321
332
|
lastDeleteTimestamp,
|
|
322
333
|
scrollRestoration,
|
|
@@ -342,10 +353,16 @@ export const EntityCollectionView = React.memo(
|
|
|
342
353
|
addRecentId(collection.id, clickedEntity.id);
|
|
343
354
|
}
|
|
344
355
|
|
|
345
|
-
|
|
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);
|
|
346
362
|
navigateToEntity({
|
|
347
363
|
navigation,
|
|
348
364
|
path,
|
|
365
|
+
pathSegments: isCollectionGroup ? clickedEntity.pathSegments : (pathSegments ?? clickedEntity.pathSegments),
|
|
349
366
|
fullIdPath,
|
|
350
367
|
sideEntityController,
|
|
351
368
|
openEntityMode,
|
|
@@ -365,6 +382,7 @@ export const EntityCollectionView = React.memo(
|
|
|
365
382
|
collection,
|
|
366
383
|
entityId: undefined,
|
|
367
384
|
path: fullPath,
|
|
385
|
+
pathSegments,
|
|
368
386
|
fullIdPath,
|
|
369
387
|
sideEntityController,
|
|
370
388
|
navigation,
|
|
@@ -440,6 +458,7 @@ export const EntityCollectionView = React.memo(
|
|
|
440
458
|
const onViewModeChange = useCallback((mode: ViewMode) => {
|
|
441
459
|
analyticsController.onAnalyticsEvent?.("view_mode_changed", {
|
|
442
460
|
path: fullPath,
|
|
461
|
+
pathSegments,
|
|
443
462
|
from: viewMode,
|
|
444
463
|
to: mode
|
|
445
464
|
});
|
|
@@ -450,7 +469,7 @@ export const EntityCollectionView = React.memo(
|
|
|
450
469
|
}
|
|
451
470
|
}, [setViewMode, userConfigPersistence, onCollectionModifiedForUser, fullPath, analyticsController, viewMode]);
|
|
452
471
|
|
|
453
|
-
const createEnabled = canCreateEntity(collection, authController, fullPath, null);
|
|
472
|
+
const createEnabled = canCreateEntity(collection, authController, fullPath, null, pathSegments);
|
|
454
473
|
|
|
455
474
|
const uniqueFieldValidator: UniqueFieldValidator = useCallback(
|
|
456
475
|
({
|
|
@@ -458,8 +477,8 @@ export const EntityCollectionView = React.memo(
|
|
|
458
477
|
value,
|
|
459
478
|
property,
|
|
460
479
|
entityId
|
|
461
|
-
}) => dataSource.checkUniqueField(fullPath, name, value, entityId, collection),
|
|
462
|
-
[fullPath]);
|
|
480
|
+
}) => dataSource.checkUniqueField(fullPath, name, value, entityId, collection, pathSegments),
|
|
481
|
+
[fullPath, pathSegments]);
|
|
463
482
|
|
|
464
483
|
const onValueChange: OnCellValueChange<any, any> = ({
|
|
465
484
|
value,
|
|
@@ -473,6 +492,8 @@ export const EntityCollectionView = React.memo(
|
|
|
473
492
|
|
|
474
493
|
const saveProps: SaveEntityProps = {
|
|
475
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,
|
|
476
497
|
entityId: entity.id,
|
|
477
498
|
values: updatedValues,
|
|
478
499
|
previousValues: entity.values,
|
|
@@ -503,7 +524,7 @@ export const EntityCollectionView = React.memo(
|
|
|
503
524
|
|
|
504
525
|
};
|
|
505
526
|
|
|
506
|
-
const resolvedFullPath = navigation.resolveIdsFrom(fullPath);
|
|
527
|
+
const resolvedFullPath = navigation.resolveIdsFrom(fullPath, pathSegments);
|
|
507
528
|
const resolvedCollection = useMemo(() => resolveCollection<M>({
|
|
508
529
|
collection,
|
|
509
530
|
path: fullPath,
|
|
@@ -581,6 +602,7 @@ export const EntityCollectionView = React.memo(
|
|
|
581
602
|
const onKanbanPropertyChange = useCallback((property: string) => {
|
|
582
603
|
analyticsController.onAnalyticsEvent?.("kanban_property_changed", {
|
|
583
604
|
path: fullPath,
|
|
605
|
+
pathSegments,
|
|
584
606
|
property
|
|
585
607
|
});
|
|
586
608
|
setSelectedKanbanProperty(property);
|
|
@@ -645,6 +667,7 @@ export const EntityCollectionView = React.memo(
|
|
|
645
667
|
entityId: entity.id,
|
|
646
668
|
selectedTab: subcollection.id ?? subcollection.path,
|
|
647
669
|
path: fullPath,
|
|
670
|
+
pathSegments,
|
|
648
671
|
fullIdPath,
|
|
649
672
|
navigation,
|
|
650
673
|
sideEntityController
|
|
@@ -663,13 +686,15 @@ export const EntityCollectionView = React.memo(
|
|
|
663
686
|
width: 260,
|
|
664
687
|
dependencies: [],
|
|
665
688
|
Builder: ({ entity }) => {
|
|
666
|
-
|
|
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);
|
|
667
692
|
return (
|
|
668
693
|
<div className={"flex flex-col gap-2 w-full"}>
|
|
669
694
|
{collectionsWithPath.map((reference) => {
|
|
670
695
|
return (
|
|
671
696
|
<ReferencePreview
|
|
672
|
-
key={reference.path
|
|
697
|
+
key={entityCacheKey(reference.path, reference.id)}
|
|
673
698
|
reference={reference}
|
|
674
699
|
size={"small"} />
|
|
675
700
|
);
|
|
@@ -700,7 +725,7 @@ export const EntityCollectionView = React.memo(
|
|
|
700
725
|
entity?: Entity<M>,
|
|
701
726
|
customEntityActions?: EntityAction[]
|
|
702
727
|
}): EntityAction[] => {
|
|
703
|
-
const deleteEnabled = entity ? canDeleteEntity(collection, authController, fullPath, entity) : true;
|
|
728
|
+
const deleteEnabled = entity ? canDeleteEntity(collection, authController, fullPath, entity, entity.pathSegments ?? pathSegments) : true;
|
|
704
729
|
const actions: EntityAction[] = [
|
|
705
730
|
{ ...editEntityAction, name: t("edit") }
|
|
706
731
|
];
|
|
@@ -776,6 +801,7 @@ export const EntityCollectionView = React.memo(
|
|
|
776
801
|
// EntitiesCount fetches count and updates breadcrumb - no visual rendering needed here
|
|
777
802
|
const countFetcher = <EntitiesCount
|
|
778
803
|
fullPath={fullPath}
|
|
804
|
+
pathSegments={pathSegments}
|
|
779
805
|
collection={collection}
|
|
780
806
|
filter={tableController.filterValues}
|
|
781
807
|
sortBy={tableController.sortBy}
|
|
@@ -829,9 +855,14 @@ export const EntityCollectionView = React.memo(
|
|
|
829
855
|
onTextSearchClick,
|
|
830
856
|
textSearchEnabled
|
|
831
857
|
} = useTableSearchHelper({
|
|
858
|
+
pathSegments,
|
|
832
859
|
collection,
|
|
833
860
|
fullPath: resolvedFullPath,
|
|
834
|
-
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
|
|
835
866
|
});
|
|
836
867
|
|
|
837
868
|
// Popover open state managed at parent level to prevent closing when view changes
|
|
@@ -881,6 +912,7 @@ export const EntityCollectionView = React.memo(
|
|
|
881
912
|
loading={tableController.dataLoading}
|
|
882
913
|
onTextSearch={textSearchEnabled && textSearchInitialised ? tableController.setSearchString : undefined}
|
|
883
914
|
onTextSearchClick={textSearchEnabled && !textSearchInitialised ? onTextSearchClick : undefined}
|
|
915
|
+
initialSearchString={tableController.searchString}
|
|
884
916
|
textSearchLoading={textSearchLoading}
|
|
885
917
|
viewModeToggle={viewModeToggleElement}
|
|
886
918
|
actionsStart={<EntityCollectionViewStartActions
|
|
@@ -888,6 +920,7 @@ export const EntityCollectionView = React.memo(
|
|
|
888
920
|
collection={collection}
|
|
889
921
|
tableController={tableController}
|
|
890
922
|
path={fullPath}
|
|
923
|
+
pathSegments={pathSegments}
|
|
891
924
|
relativePath={collection.path}
|
|
892
925
|
selectionController={usedSelectionController}
|
|
893
926
|
collectionEntitiesCount={docsCount}
|
|
@@ -899,6 +932,7 @@ export const EntityCollectionView = React.memo(
|
|
|
899
932
|
onMultipleDeleteClick={onMultipleDeleteClick}
|
|
900
933
|
onNewClick={onNewClick}
|
|
901
934
|
path={fullPath}
|
|
935
|
+
pathSegments={pathSegments}
|
|
902
936
|
relativePath={collection.path}
|
|
903
937
|
selectionController={usedSelectionController}
|
|
904
938
|
selectionEnabled={selectionEnabled}
|
|
@@ -915,6 +949,7 @@ export const EntityCollectionView = React.memo(
|
|
|
915
949
|
collection={collection}
|
|
916
950
|
tableController={tableController}
|
|
917
951
|
fullPath={fullPath}
|
|
952
|
+
pathSegments={pathSegments}
|
|
918
953
|
parentCollectionIds={parentCollectionIds}
|
|
919
954
|
columnProperty={selectedKanbanProperty}
|
|
920
955
|
onEntityClick={onEntityClick}
|
|
@@ -1006,6 +1041,7 @@ export const EntityCollectionView = React.memo(
|
|
|
1006
1041
|
getIdColumnWidth={getIdColumnWidth}
|
|
1007
1042
|
additionalIDHeaderWidget={<EntityIdHeaderWidget
|
|
1008
1043
|
path={fullPath}
|
|
1044
|
+
pathSegments={pathSegments}
|
|
1009
1045
|
fullIdPath={fullIdPath ?? fullPath}
|
|
1010
1046
|
collection={collection} />}
|
|
1011
1047
|
openEntityMode={openEntityMode}
|
|
@@ -1045,6 +1081,7 @@ export const EntityCollectionView = React.memo(
|
|
|
1045
1081
|
|
|
1046
1082
|
{popupCell && <PopupFormField
|
|
1047
1083
|
key={`popup_form_${popupCell?.propertyKey}_${popupCell?.entityId}`}
|
|
1084
|
+
pathSegments={pathSegments}
|
|
1048
1085
|
open={Boolean(popupCell)}
|
|
1049
1086
|
onClose={onPopupClose}
|
|
1050
1087
|
cellRect={popupCell?.cellRect}
|
|
@@ -1100,13 +1137,16 @@ function EntitiesCount({
|
|
|
1100
1137
|
collection,
|
|
1101
1138
|
filter,
|
|
1102
1139
|
sortBy,
|
|
1103
|
-
onCountChange
|
|
1140
|
+
onCountChange,
|
|
1141
|
+
pathSegments
|
|
1104
1142
|
}: {
|
|
1105
1143
|
fullPath: string,
|
|
1106
1144
|
collection: EntityCollection,
|
|
1107
1145
|
filter?: FilterValues<any>,
|
|
1108
1146
|
sortBy?: [string, "asc" | "desc"],
|
|
1109
1147
|
onCountChange?: (count: number) => void,
|
|
1148
|
+
/** `fullPath` split at its real segment boundaries; forwarded to countEntities. */
|
|
1149
|
+
pathSegments?: string[],
|
|
1110
1150
|
}) {
|
|
1111
1151
|
|
|
1112
1152
|
const dataSource = useDataSource(collection);
|
|
@@ -1116,18 +1156,24 @@ function EntitiesCount({
|
|
|
1116
1156
|
|
|
1117
1157
|
const sortByProperty = sortBy ? sortBy[0] : undefined;
|
|
1118
1158
|
const currentSort = sortBy ? sortBy[1] : undefined;
|
|
1119
|
-
|
|
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]);
|
|
1120
1165
|
|
|
1121
1166
|
useEffect(() => {
|
|
1122
1167
|
if (dataSource.countEntities)
|
|
1123
1168
|
dataSource.countEntities({
|
|
1124
1169
|
path: resolvedPath,
|
|
1170
|
+
pathSegments: resolvedPathSegments,
|
|
1125
1171
|
collection,
|
|
1126
1172
|
filter,
|
|
1127
1173
|
orderBy: sortByProperty,
|
|
1128
1174
|
order: currentSort
|
|
1129
1175
|
}).then(setCount).catch(setError);
|
|
1130
|
-
}, [fullPath, dataSource.countEntities, resolvedPath, collection, filter, sortByProperty, currentSort]);
|
|
1176
|
+
}, [fullPath, dataSource.countEntities, resolvedPath, resolvedPathSegments, collection, filter, sortByProperty, currentSort]);
|
|
1131
1177
|
|
|
1132
1178
|
useEffect(() => {
|
|
1133
1179
|
if (onCountChange && count !== undefined) {
|
|
@@ -1156,10 +1202,13 @@ function buildPropertyWidthOverwrite(key: string, width: number): PartialEntityC
|
|
|
1156
1202
|
function EntityIdHeaderWidget({
|
|
1157
1203
|
collection,
|
|
1158
1204
|
path,
|
|
1205
|
+
pathSegments,
|
|
1159
1206
|
fullIdPath
|
|
1160
1207
|
}: {
|
|
1161
1208
|
collection: EntityCollection,
|
|
1162
1209
|
path: string,
|
|
1210
|
+
/** `path` split at its real segment boundaries, when the caller knows them. */
|
|
1211
|
+
pathSegments?: string[],
|
|
1163
1212
|
fullIdPath: string
|
|
1164
1213
|
}) {
|
|
1165
1214
|
|
|
@@ -1199,6 +1248,7 @@ function EntityIdHeaderWidget({
|
|
|
1199
1248
|
collection,
|
|
1200
1249
|
entityId,
|
|
1201
1250
|
path,
|
|
1251
|
+
pathSegments,
|
|
1202
1252
|
fullIdPath,
|
|
1203
1253
|
sideEntityController,
|
|
1204
1254
|
navigation
|
|
@@ -1224,7 +1274,7 @@ function EntityIdHeaderWidget({
|
|
|
1224
1274
|
</form>
|
|
1225
1275
|
{recentIds && recentIds.length > 0 && <div className="flex flex-col gap-2 p-2">
|
|
1226
1276
|
{recentIds.map(id => (
|
|
1227
|
-
<ReferencePreview reference={new EntityReference(id, path)}
|
|
1277
|
+
<ReferencePreview reference={new EntityReference(id, path, undefined, pathSegments)}
|
|
1228
1278
|
key={id}
|
|
1229
1279
|
hover={true}
|
|
1230
1280
|
onClick={() => {
|
|
@@ -1234,6 +1284,7 @@ function EntityIdHeaderWidget({
|
|
|
1234
1284
|
collection,
|
|
1235
1285
|
entityId: id,
|
|
1236
1286
|
path,
|
|
1287
|
+
pathSegments,
|
|
1237
1288
|
fullIdPath,
|
|
1238
1289
|
sideEntityController,
|
|
1239
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,
|
|
@@ -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
|
|
@@ -63,7 +63,7 @@ export function EntityPreview({
|
|
|
63
63
|
|
|
64
64
|
const navigationController = useNavigationController();
|
|
65
65
|
|
|
66
|
-
const collection = collectionProp ?? navigationController.getCollection(entity.path);
|
|
66
|
+
const collection = collectionProp ?? navigationController.getCollection(entity.path, false, entity.pathSegments);
|
|
67
67
|
|
|
68
68
|
if (!collection) {
|
|
69
69
|
throw Error(`Couldn't find the corresponding collection view for the path: ${entity.path}`);
|
|
@@ -177,6 +177,9 @@ export function EntityPreview({
|
|
|
177
177
|
sideEntityController.open({
|
|
178
178
|
entityId: entity.id,
|
|
179
179
|
path: entity.path,
|
|
180
|
+
// Paired with `entity.path` above; undefined if the entity was
|
|
181
|
+
// loaded without them.
|
|
182
|
+
pathSegments: entity.pathSegments,
|
|
180
183
|
collection,
|
|
181
184
|
updateUrl: true
|
|
182
185
|
});
|