@firecms/core 3.0.0-canary.167 → 3.0.0-canary.169
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/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +2 -1
- package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +2 -2
- package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +15 -1
- package/dist/components/EntityCollectionTable/index.d.ts +1 -1
- package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +4 -0
- package/dist/components/SelectableTable/SelectableTable.d.ts +12 -2
- package/dist/components/UnsavedChangesDialog.d.ts +8 -0
- package/dist/components/VirtualTable/VirtualTableProps.d.ts +13 -0
- package/dist/components/common/index.d.ts +1 -1
- package/dist/components/common/{useDataSourceEntityCollectionTableController.d.ts → useDataSourceTableController.d.ts} +10 -2
- package/dist/components/common/useDebouncedCallback.d.ts +1 -0
- package/dist/components/common/useScrollRestoration.d.ts +14 -0
- package/dist/contexts/BreacrumbsContext.d.ts +8 -0
- package/dist/core/EntityEditView.d.ts +25 -7
- package/dist/core/FireCMSRouter.d.ts +4 -0
- package/dist/core/NavigationRoutes.d.ts +0 -1
- package/dist/core/index.d.ts +2 -1
- package/dist/hooks/data/useEntityFetch.d.ts +2 -1
- package/dist/hooks/useBreadcrumbsController.d.ts +26 -0
- package/dist/hooks/useBuildNavigationController.d.ts +0 -1
- package/dist/index.es.js +2344 -1305
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +2344 -1306
- package/dist/index.umd.js.map +1 -1
- package/dist/internal/useUnsavedChangesDialog.d.ts +7 -9
- package/dist/routes/CustomCMSRoute.d.ts +4 -0
- package/dist/routes/FireCMSRoute.d.ts +1 -0
- package/dist/routes/HomePageRoute.d.ts +3 -0
- package/dist/types/collections.d.ts +18 -6
- package/dist/types/datasource.d.ts +2 -2
- package/dist/types/dialogs_controller.d.ts +2 -6
- package/dist/types/entities.d.ts +1 -1
- package/dist/types/entity_actions.d.ts +1 -6
- package/dist/types/navigation.d.ts +28 -12
- package/dist/types/plugins.d.ts +1 -0
- package/dist/types/side_entity_controller.d.ts +1 -1
- package/dist/util/entity_cache.d.ts +23 -0
- package/dist/util/navigation_from_path.d.ts +5 -1
- package/dist/util/navigation_utils.d.ts +12 -1
- package/package.json +5 -5
- package/src/components/CircularProgressCenter.tsx +1 -1
- package/src/components/DeleteEntityDialog.tsx +1 -1
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +40 -19
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +10 -4
- package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +18 -1
- package/src/components/EntityCollectionTable/index.tsx +1 -1
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +3 -3
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +79 -38
- package/src/components/NotFoundPage.tsx +2 -2
- package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +9 -5
- package/src/components/SelectableTable/SelectableTable.tsx +18 -3
- package/src/components/UnsavedChangesDialog.tsx +42 -0
- package/src/components/VirtualTable/VirtualTable.tsx +19 -2
- package/src/components/VirtualTable/VirtualTableProps.tsx +15 -0
- package/src/components/VirtualTable/fields/VirtualTableInput.tsx +1 -1
- package/src/components/common/default_entity_actions.tsx +24 -10
- package/src/components/common/index.ts +1 -1
- package/src/components/common/{useDataSourceEntityCollectionTableController.tsx → useDataSourceTableController.tsx} +122 -13
- package/src/components/common/useDebouncedCallback.tsx +20 -0
- package/src/components/common/useScrollRestoration.tsx +68 -0
- package/src/contexts/BreacrumbsContext.tsx +38 -0
- package/src/contexts/DialogsProvider.tsx +0 -1
- package/src/core/DefaultAppBar.tsx +28 -4
- package/src/core/EntityEditView.tsx +457 -296
- package/src/core/EntitySidePanel.tsx +72 -6
- package/src/core/FireCMS.tsx +7 -4
- package/src/core/FireCMSRouter.tsx +17 -0
- package/src/core/NavigationRoutes.tsx +15 -28
- package/src/core/SideDialogs.tsx +10 -5
- package/src/core/index.tsx +4 -2
- package/src/hooks/data/save.ts +1 -1
- package/src/hooks/data/useCollectionFetch.tsx +1 -1
- package/src/hooks/data/useEntityFetch.tsx +5 -1
- package/src/hooks/useBreadcrumbsController.tsx +31 -0
- package/src/hooks/useBuildNavigationController.tsx +59 -21
- package/src/hooks/useLargeLayout.tsx +0 -35
- package/src/hooks/useResolvedNavigationFrom.tsx +4 -6
- package/src/internal/useBuildSideDialogsController.tsx +4 -2
- package/src/internal/useBuildSideEntityController.tsx +157 -77
- package/src/internal/useUnsavedChangesDialog.tsx +126 -92
- package/src/routes/CustomCMSRoute.tsx +21 -0
- package/src/routes/FireCMSRoute.tsx +230 -0
- package/src/routes/HomePageRoute.tsx +17 -0
- package/src/types/collections.ts +19 -6
- package/src/types/datasource.ts +2 -1
- package/src/types/dialogs_controller.tsx +2 -6
- package/src/types/entities.ts +1 -1
- package/src/types/entity_actions.tsx +1 -7
- package/src/types/navigation.ts +35 -16
- package/src/types/plugins.tsx +1 -0
- package/src/types/side_entity_controller.tsx +1 -1
- package/src/util/entity_cache.ts +196 -0
- package/src/util/navigation_from_path.ts +10 -2
- package/src/util/navigation_utils.ts +53 -1
- package/src/util/parent_references_from_path.ts +3 -3
- /package/src/util/{common.tsx → common.ts} +0 -0
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
import {
|
|
20
20
|
EntityCollectionRowActions,
|
|
21
21
|
EntityCollectionTable,
|
|
22
|
-
|
|
22
|
+
useDataSourceTableController
|
|
23
23
|
} from "../EntityCollectionTable";
|
|
24
24
|
|
|
25
25
|
import {
|
|
@@ -28,6 +28,8 @@ import {
|
|
|
28
28
|
canEditEntity,
|
|
29
29
|
getPropertyInPath,
|
|
30
30
|
mergeDeep,
|
|
31
|
+
mergeEntityActions,
|
|
32
|
+
navigateToEntity,
|
|
31
33
|
resolveCollection,
|
|
32
34
|
resolveProperty
|
|
33
35
|
} from "../../util";
|
|
@@ -62,6 +64,9 @@ import { setIn } from "@firecms/formex";
|
|
|
62
64
|
import { getSubcollectionColumnId } from "../EntityCollectionTable/internal/common";
|
|
63
65
|
import {
|
|
64
66
|
COLLECTION_GROUP_PARENT_ID,
|
|
67
|
+
copyEntityAction,
|
|
68
|
+
deleteEntityAction,
|
|
69
|
+
editEntityAction,
|
|
65
70
|
OnCellValueChange,
|
|
66
71
|
OnColumnResizeParams,
|
|
67
72
|
UniqueFieldValidator,
|
|
@@ -70,13 +75,14 @@ import {
|
|
|
70
75
|
} from "../common";
|
|
71
76
|
import { PopupFormField } from "../EntityCollectionTable/internal/popup_field/PopupFormField";
|
|
72
77
|
import { GetPropertyForProps } from "../EntityCollectionTable/EntityCollectionTableProps";
|
|
73
|
-
import { copyEntityAction, deleteEntityAction, editEntityAction } from "../common/default_entity_actions";
|
|
74
78
|
import { DeleteEntityDialog } from "../DeleteEntityDialog";
|
|
75
79
|
import { useAnalyticsController } from "../../hooks/useAnalyticsController";
|
|
76
80
|
import { useSelectionController } from "./useSelectionController";
|
|
77
81
|
import { EntityCollectionViewStartActions } from "./EntityCollectionViewStartActions";
|
|
78
82
|
import { addRecentId, getRecentIds } from "./utils";
|
|
79
|
-
import {
|
|
83
|
+
import { useScrollRestoration } from "../common/useScrollRestoration";
|
|
84
|
+
|
|
85
|
+
const DEFAULT_ENTITY_OPEN_MODE: "side_panel" | "full_screen" = "side_panel";
|
|
80
86
|
|
|
81
87
|
/**
|
|
82
88
|
* @group Components
|
|
@@ -98,6 +104,11 @@ export type EntityCollectionViewProps<M extends Record<string, any>> = {
|
|
|
98
104
|
|
|
99
105
|
className?: string;
|
|
100
106
|
|
|
107
|
+
/**
|
|
108
|
+
* If true, this view will store its filter and sorting status in the url params
|
|
109
|
+
*/
|
|
110
|
+
updateUrl?: boolean;
|
|
111
|
+
|
|
101
112
|
} & EntityCollection<M>;
|
|
102
113
|
|
|
103
114
|
/**
|
|
@@ -130,6 +141,7 @@ export const EntityCollectionView = React.memo(
|
|
|
130
141
|
parentCollectionIds,
|
|
131
142
|
isSubCollection,
|
|
132
143
|
className,
|
|
144
|
+
updateUrl,
|
|
133
145
|
...collectionProp
|
|
134
146
|
}: EntityCollectionViewProps<M>
|
|
135
147
|
) {
|
|
@@ -146,11 +158,15 @@ export const EntityCollectionView = React.memo(
|
|
|
146
158
|
|
|
147
159
|
const containerRef = React.useRef<HTMLDivElement>(null);
|
|
148
160
|
|
|
161
|
+
const scrollRestoration = useScrollRestoration();
|
|
162
|
+
|
|
149
163
|
const collection = useMemo(() => {
|
|
150
164
|
const userOverride = userConfigPersistence?.getCollectionConfig<M>(fullPath);
|
|
151
165
|
return (userOverride ? mergeDeep(collectionProp, userOverride) : collectionProp) as EntityCollection<M>;
|
|
152
166
|
}, [collectionProp, fullPath, userConfigPersistence?.getCollectionConfig]);
|
|
153
167
|
|
|
168
|
+
const openEntityMode = collection?.openEntityMode ?? DEFAULT_ENTITY_OPEN_MODE;
|
|
169
|
+
|
|
154
170
|
const collectionRef = React.useRef(collection);
|
|
155
171
|
useEffect(() => {
|
|
156
172
|
collectionRef.current = collection;
|
|
@@ -193,14 +209,12 @@ export const EntityCollectionView = React.memo(
|
|
|
193
209
|
setSelectedEntities
|
|
194
210
|
} = usedSelectionController;
|
|
195
211
|
|
|
196
|
-
|
|
197
|
-
// setDeleteEntityClicked(undefined);
|
|
198
|
-
// }, [selectedEntities]);
|
|
199
|
-
|
|
200
|
-
const tableController = useDataSourceEntityCollectionTableController<M>({
|
|
212
|
+
const tableController = useDataSourceTableController<M>({
|
|
201
213
|
fullPath,
|
|
202
214
|
collection,
|
|
203
|
-
lastDeleteTimestamp
|
|
215
|
+
lastDeleteTimestamp,
|
|
216
|
+
scrollRestoration,
|
|
217
|
+
updateUrl
|
|
204
218
|
});
|
|
205
219
|
|
|
206
220
|
const tableKey = React.useRef<string>(Math.random().toString(36));
|
|
@@ -217,13 +231,21 @@ export const EntityCollectionView = React.memo(
|
|
|
217
231
|
path: clickedEntity.path,
|
|
218
232
|
entityId: clickedEntity.id
|
|
219
233
|
});
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
234
|
+
|
|
235
|
+
if (collection) {
|
|
236
|
+
addRecentId(collection.id, clickedEntity.id);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const path = collection?.collectionGroup ? clickedEntity.path : (fullPath ?? clickedEntity.path);
|
|
240
|
+
navigateToEntity({
|
|
241
|
+
navigation,
|
|
242
|
+
path,
|
|
243
|
+
sideEntityController,
|
|
244
|
+
openEntityMode,
|
|
223
245
|
collection,
|
|
224
|
-
|
|
225
|
-
onClose: unselectNavigatedEntity,
|
|
246
|
+
entityId: clickedEntity.id
|
|
226
247
|
});
|
|
248
|
+
|
|
227
249
|
}, [unselectNavigatedEntity, sideEntityController]);
|
|
228
250
|
|
|
229
251
|
const onNewClick = useCallback(() => {
|
|
@@ -232,12 +254,15 @@ export const EntityCollectionView = React.memo(
|
|
|
232
254
|
analyticsController.onAnalyticsEvent?.("new_entity_click", {
|
|
233
255
|
path: fullPath
|
|
234
256
|
});
|
|
235
|
-
|
|
236
|
-
|
|
257
|
+
navigateToEntity({
|
|
258
|
+
openEntityMode,
|
|
237
259
|
collection,
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
260
|
+
entityId: undefined,
|
|
261
|
+
path: fullPath,
|
|
262
|
+
sideEntityController,
|
|
263
|
+
navigation,
|
|
264
|
+
onClose: unselectNavigatedEntity
|
|
265
|
+
})
|
|
241
266
|
}, [fullPath, sideEntityController]);
|
|
242
267
|
|
|
243
268
|
const onMultipleDeleteClick = () => {
|
|
@@ -349,7 +374,7 @@ export const EntityCollectionView = React.memo(
|
|
|
349
374
|
|
|
350
375
|
};
|
|
351
376
|
|
|
352
|
-
const resolvedFullPath = navigation.
|
|
377
|
+
const resolvedFullPath = navigation.resolveIdsFrom(fullPath);
|
|
353
378
|
const resolvedCollection = useMemo(() => resolveCollection<M>({
|
|
354
379
|
collection,
|
|
355
380
|
path: fullPath,
|
|
@@ -393,13 +418,15 @@ export const EntityCollectionView = React.memo(
|
|
|
393
418
|
startIcon={<KeyboardTabIcon size={"small"}/>}
|
|
394
419
|
onClick={(event: any) => {
|
|
395
420
|
event.stopPropagation();
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
entityId: entity.id,
|
|
399
|
-
selectedSubPath: subcollection.id ?? subcollection.path,
|
|
421
|
+
navigateToEntity({
|
|
422
|
+
openEntityMode,
|
|
400
423
|
collection,
|
|
401
|
-
|
|
402
|
-
|
|
424
|
+
entityId: entity.id,
|
|
425
|
+
selectedTab: subcollection.id ?? subcollection.path,
|
|
426
|
+
path: fullPath,
|
|
427
|
+
navigation,
|
|
428
|
+
sideEntityController
|
|
429
|
+
})
|
|
403
430
|
}}>
|
|
404
431
|
{subcollection.name}
|
|
405
432
|
</Button>
|
|
@@ -505,6 +532,7 @@ export const EntityCollectionView = React.memo(
|
|
|
505
532
|
hideId={collection?.hideIdFromCollection}
|
|
506
533
|
onCollectionChange={updateLastDeleteTimestamp}
|
|
507
534
|
selectionController={usedSelectionController}
|
|
535
|
+
openEntityMode={openEntityMode}
|
|
508
536
|
/>
|
|
509
537
|
);
|
|
510
538
|
|
|
@@ -617,6 +645,8 @@ export const EntityCollectionView = React.memo(
|
|
|
617
645
|
properties={resolvedCollection.properties}
|
|
618
646
|
getPropertyFor={getPropertyFor}
|
|
619
647
|
onTextSearchClick={textSearchInitialised ? undefined : onTextSearchClick}
|
|
648
|
+
onScroll={tableController.onScroll}
|
|
649
|
+
initialScroll={tableController.initialScroll}
|
|
620
650
|
textSearchLoading={textSearchLoading}
|
|
621
651
|
textSearchEnabled={textSearchEnabled}
|
|
622
652
|
actionsStart={<EntityCollectionViewStartActions
|
|
@@ -662,6 +692,7 @@ export const EntityCollectionView = React.memo(
|
|
|
662
692
|
additionalIDHeaderWidget={<EntityIdHeaderWidget
|
|
663
693
|
path={fullPath}
|
|
664
694
|
collection={collection}/>}
|
|
695
|
+
openEntityMode={openEntityMode}
|
|
665
696
|
/>
|
|
666
697
|
|
|
667
698
|
{popupCell && <PopupFormField
|
|
@@ -692,7 +723,7 @@ export const EntityCollectionView = React.memo(
|
|
|
692
723
|
</div>
|
|
693
724
|
);
|
|
694
725
|
}, (a, b) => {
|
|
695
|
-
return equal(a.
|
|
726
|
+
return equal(a.path, b.path) &&
|
|
696
727
|
equal(a.parentCollectionIds, b.parentCollectionIds) &&
|
|
697
728
|
equal(a.isSubCollection, b.isSubCollection) &&
|
|
698
729
|
equal(a.className, b.className) &&
|
|
@@ -709,6 +740,7 @@ export const EntityCollectionView = React.memo(
|
|
|
709
740
|
equal(a.textSearchEnabled, b.textSearchEnabled) &&
|
|
710
741
|
equal(a.additionalFields, b.additionalFields) &&
|
|
711
742
|
equal(a.sideDialogWidth, b.sideDialogWidth) &&
|
|
743
|
+
equal(a.openEntityMode, b.openEntityMode) &&
|
|
712
744
|
equal(a.forceFilter, b.forceFilter);
|
|
713
745
|
}) as React.FunctionComponent<EntityCollectionViewProps<any>>
|
|
714
746
|
|
|
@@ -733,7 +765,7 @@ function EntitiesCount({
|
|
|
733
765
|
|
|
734
766
|
const sortByProperty = sortBy ? sortBy[0] : undefined;
|
|
735
767
|
const currentSort = sortBy ? sortBy[1] : undefined;
|
|
736
|
-
const resolvedPath = useMemo(() => navigation.
|
|
768
|
+
const resolvedPath = useMemo(() => navigation.resolveIdsFrom(fullPath), [fullPath, navigation.resolveIdsFrom]);
|
|
737
769
|
|
|
738
770
|
useEffect(() => {
|
|
739
771
|
if (dataSource.countEntities)
|
|
@@ -780,11 +812,15 @@ function EntityIdHeaderWidget({
|
|
|
780
812
|
collection: EntityCollection,
|
|
781
813
|
path: string
|
|
782
814
|
}) {
|
|
815
|
+
|
|
816
|
+
const navigation = useNavigationController();
|
|
783
817
|
const [openPopup, setOpenPopup] = React.useState(false);
|
|
784
818
|
const [searchString, setSearchString] = React.useState("");
|
|
785
819
|
const [recentIds, setRecentIds] = React.useState<string[]>(getRecentIds(collection.id));
|
|
786
820
|
const sideEntityController = useSideEntityController();
|
|
787
821
|
|
|
822
|
+
const openEntityMode = collection?.openEntityMode ?? DEFAULT_ENTITY_OPEN_MODE;
|
|
823
|
+
|
|
788
824
|
return (
|
|
789
825
|
<Tooltip title={!openPopup ? "Find by ID" : undefined} asChild={false}>
|
|
790
826
|
<Popover
|
|
@@ -805,13 +841,16 @@ function EntityIdHeaderWidget({
|
|
|
805
841
|
e.preventDefault();
|
|
806
842
|
if (!searchString) return;
|
|
807
843
|
setOpenPopup(false);
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
844
|
+
const entityId = searchString.trim();
|
|
845
|
+
setRecentIds(addRecentId(collection.id, entityId));
|
|
846
|
+
navigateToEntity({
|
|
847
|
+
openEntityMode,
|
|
812
848
|
collection,
|
|
813
|
-
|
|
814
|
-
|
|
849
|
+
entityId,
|
|
850
|
+
path,
|
|
851
|
+
sideEntityController,
|
|
852
|
+
navigation
|
|
853
|
+
})
|
|
815
854
|
}}
|
|
816
855
|
className={"w-96 max-w-full"}>
|
|
817
856
|
|
|
@@ -838,12 +877,14 @@ function EntityIdHeaderWidget({
|
|
|
838
877
|
hover={true}
|
|
839
878
|
onClick={() => {
|
|
840
879
|
setOpenPopup(false);
|
|
841
|
-
|
|
880
|
+
navigateToEntity({
|
|
881
|
+
openEntityMode,
|
|
882
|
+
collection,
|
|
842
883
|
entityId: id,
|
|
843
884
|
path,
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
})
|
|
885
|
+
sideEntityController,
|
|
886
|
+
navigation
|
|
887
|
+
})
|
|
847
888
|
}}
|
|
848
889
|
includeEntityLink={false}
|
|
849
890
|
size={"small"}/>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { Link
|
|
2
|
+
import { Link } from "react-router-dom";
|
|
3
3
|
import { Button, Typography } from "@firecms/ui";
|
|
4
4
|
|
|
5
5
|
export function NotFoundPage() {
|
|
@@ -17,7 +17,7 @@ export function NotFoundPage() {
|
|
|
17
17
|
</Typography>
|
|
18
18
|
<Button
|
|
19
19
|
variant={"text"}
|
|
20
|
-
component={
|
|
20
|
+
component={Link}
|
|
21
21
|
to={"/"}>Back to home</Button>
|
|
22
22
|
</div>
|
|
23
23
|
</div>
|
|
@@ -4,7 +4,7 @@ import { CollectionSize, Entity, EntityCollection, FilterValues } from "../../ty
|
|
|
4
4
|
import {
|
|
5
5
|
EntityCollectionRowActions,
|
|
6
6
|
EntityCollectionTable,
|
|
7
|
-
|
|
7
|
+
useDataSourceTableController
|
|
8
8
|
} from "../EntityCollectionTable";
|
|
9
9
|
import {
|
|
10
10
|
useAuthController,
|
|
@@ -107,7 +107,7 @@ export function ReferenceSelectionTable<M extends Record<string, any>>(
|
|
|
107
107
|
const analyticsController = useAnalyticsController();
|
|
108
108
|
const customizationController = useCustomizationController();
|
|
109
109
|
|
|
110
|
-
const fullPath = navigation.
|
|
110
|
+
const fullPath = navigation.resolveIdsFrom(pathInput);
|
|
111
111
|
|
|
112
112
|
const dataSource = useDataSource(collection);
|
|
113
113
|
|
|
@@ -233,7 +233,9 @@ export function ReferenceSelectionTable<M extends Record<string, any>>(
|
|
|
233
233
|
selectionEnabled={multiselect}
|
|
234
234
|
hideId={collection?.hideIdFromCollection}
|
|
235
235
|
fullPath={fullPath}
|
|
236
|
-
selectionController={selectionController}
|
|
236
|
+
selectionController={selectionController}
|
|
237
|
+
openEntityMode={"side_panel"}
|
|
238
|
+
/>;
|
|
237
239
|
|
|
238
240
|
};
|
|
239
241
|
|
|
@@ -256,7 +258,7 @@ export function ReferenceSelectionTable<M extends Record<string, any>>(
|
|
|
256
258
|
|
|
257
259
|
const displayedColumnIds = useColumnIds(resolvedCollection, false);
|
|
258
260
|
|
|
259
|
-
const tableController =
|
|
261
|
+
const tableController = useDataSourceTableController<M>({
|
|
260
262
|
fullPath,
|
|
261
263
|
collection,
|
|
262
264
|
entitiesDisplayedFirst,
|
|
@@ -289,12 +291,14 @@ export function ReferenceSelectionTable<M extends Record<string, any>>(
|
|
|
289
291
|
tableController={tableController}
|
|
290
292
|
enablePopupIcon={false}
|
|
291
293
|
tableRowActionsBuilder={tableRowActionsBuilder}
|
|
294
|
+
openEntityMode={"side_panel"}
|
|
292
295
|
title={<Typography variant={"subtitle2"} className={"flex flex-row gap-2"}>
|
|
293
296
|
<IconForView
|
|
294
297
|
size={"small"}
|
|
295
298
|
collectionOrView={collection}
|
|
296
299
|
className={"text-surface-300 dark:text-surface-600"}/>
|
|
297
|
-
{collection.singularName ? `Select ${collection.singularName}` : `Select
|
|
300
|
+
{collection.singularName ? `Select ${collection.singularName}` : `Select
|
|
301
|
+
from ${collection.name}`}
|
|
298
302
|
</Typography>}
|
|
299
303
|
defaultSize={collection.defaultSize}
|
|
300
304
|
properties={resolvedCollection.properties}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useRef } from "react";
|
|
2
|
-
import equal from "react-fast-compare";
|
|
3
2
|
import {
|
|
4
3
|
CollectionSize,
|
|
5
4
|
Entity,
|
|
@@ -60,7 +59,7 @@ export type SelectableTableProps<M extends Record<string, any>> = {
|
|
|
60
59
|
|
|
61
60
|
/**
|
|
62
61
|
* Controller holding the logic for the table
|
|
63
|
-
* {@link
|
|
62
|
+
* {@link useDataSourceTableController}
|
|
64
63
|
* {@link EntityTableController}
|
|
65
64
|
*/
|
|
66
65
|
tableController: EntityTableController<M>;
|
|
@@ -77,6 +76,18 @@ export type SelectableTableProps<M extends Record<string, any>> = {
|
|
|
77
76
|
|
|
78
77
|
size?: CollectionSize;
|
|
79
78
|
|
|
79
|
+
initialScroll?: number;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Callback when the table is scrolled
|
|
83
|
+
* @param props
|
|
84
|
+
*/
|
|
85
|
+
onScroll?: (props: {
|
|
86
|
+
scrollDirection: "forward" | "backward",
|
|
87
|
+
scrollOffset: number,
|
|
88
|
+
scrollUpdateWasRequested: boolean
|
|
89
|
+
}) => void;
|
|
90
|
+
|
|
80
91
|
emptyComponent?: React.ReactNode;
|
|
81
92
|
|
|
82
93
|
endAdornment?: React.ReactNode;
|
|
@@ -101,7 +112,7 @@ export type SelectableTableProps<M extends Record<string, any>> = {
|
|
|
101
112
|
*
|
|
102
113
|
* The data displayed in the table is managed by a {@link EntityTableController}.
|
|
103
114
|
* You can build the default, bound to a path in the datasource, by using the hook
|
|
104
|
-
* {@link
|
|
115
|
+
* {@link useDataSourceTableController}
|
|
105
116
|
*
|
|
106
117
|
* @see EntityCollectionTableProps
|
|
107
118
|
* @see EntityCollectionView
|
|
@@ -136,6 +147,8 @@ export const SelectableTable = React.memo<SelectableTableProps<any>>(
|
|
|
136
147
|
setPopupCell
|
|
137
148
|
},
|
|
138
149
|
filterable = true,
|
|
150
|
+
onScroll,
|
|
151
|
+
initialScroll,
|
|
139
152
|
emptyComponent,
|
|
140
153
|
columns,
|
|
141
154
|
forceFilter,
|
|
@@ -229,6 +242,8 @@ export const SelectableTable = React.memo<SelectableTableProps<any>>(
|
|
|
229
242
|
sortBy={sortBy}
|
|
230
243
|
onSortByUpdate={setSortBy as ((sortBy?: [string, "asc" | "desc"]) => void)}
|
|
231
244
|
hoverRow={hoverRow}
|
|
245
|
+
initialScroll={initialScroll}
|
|
246
|
+
onScroll={onScroll}
|
|
232
247
|
checkFilterCombination={checkFilterCombination}
|
|
233
248
|
createFilterField={filterable ? createFilterField : undefined}
|
|
234
249
|
rowClassName={useCallback((entity: Entity<M>) => {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Typography } from "@firecms/ui";
|
|
2
|
+
|
|
3
|
+
export interface UnsavedChangesDialogProps {
|
|
4
|
+
open: boolean;
|
|
5
|
+
body?: React.ReactNode;
|
|
6
|
+
title?: string;
|
|
7
|
+
handleOk: () => void;
|
|
8
|
+
handleCancel: () => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function UnsavedChangesDialog({
|
|
12
|
+
open,
|
|
13
|
+
handleOk,
|
|
14
|
+
handleCancel,
|
|
15
|
+
body,
|
|
16
|
+
title
|
|
17
|
+
}: UnsavedChangesDialogProps) {
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<Dialog
|
|
21
|
+
onEscapeKeyDown={() => {
|
|
22
|
+
handleCancel();
|
|
23
|
+
}}
|
|
24
|
+
open={open}
|
|
25
|
+
>
|
|
26
|
+
<DialogTitle variant={"h6"}>{title}</DialogTitle>
|
|
27
|
+
<DialogContent>
|
|
28
|
+
|
|
29
|
+
{body}
|
|
30
|
+
|
|
31
|
+
<Typography>
|
|
32
|
+
Are you sure you want to leave this page?
|
|
33
|
+
</Typography>
|
|
34
|
+
|
|
35
|
+
</DialogContent>
|
|
36
|
+
<DialogActions>
|
|
37
|
+
<Button variant="text" onClick={handleCancel} autoFocus> Cancel </Button>
|
|
38
|
+
<Button onClick={handleOk}> Ok </Button>
|
|
39
|
+
</DialogActions>
|
|
40
|
+
</Dialog>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -20,6 +20,7 @@ import { VirtualTableHeaderRow } from "./VirtualTableHeaderRow";
|
|
|
20
20
|
import { VirtualTableRow } from "./VirtualTableRow";
|
|
21
21
|
import { VirtualTableCell } from "./VirtualTableCell";
|
|
22
22
|
import { AssignmentIcon, CenteredView, cls, Typography } from "@firecms/ui";
|
|
23
|
+
import { useDebounceCallback } from "../common/useDebouncedCallback";
|
|
23
24
|
|
|
24
25
|
const VirtualListContext = createContext<VirtualTableContextProps<any>>({} as any);
|
|
25
26
|
VirtualListContext.displayName = "VirtualListContext";
|
|
@@ -103,6 +104,7 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
|
|
|
103
104
|
error,
|
|
104
105
|
emptyComponent,
|
|
105
106
|
onSortByUpdate,
|
|
107
|
+
onScroll: onScrollProp,
|
|
106
108
|
loading,
|
|
107
109
|
cellRenderer,
|
|
108
110
|
hoverRow,
|
|
@@ -112,6 +114,7 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
|
|
|
112
114
|
className,
|
|
113
115
|
endAdornment,
|
|
114
116
|
AddColumnComponent,
|
|
117
|
+
initialScroll = 0,
|
|
115
118
|
debug
|
|
116
119
|
}: VirtualTableProps<T>) {
|
|
117
120
|
|
|
@@ -123,6 +126,15 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
|
|
|
123
126
|
const tableRef = useRef<HTMLDivElement>(null);
|
|
124
127
|
const endReachCallbackThreshold = useRef<number>(0);
|
|
125
128
|
|
|
129
|
+
const debouncedScroll = useDebounceCallback(onScrollProp, 200);
|
|
130
|
+
|
|
131
|
+
// Set initial scroll position
|
|
132
|
+
useEffect(() => {
|
|
133
|
+
if (tableRef.current && initialScroll) {
|
|
134
|
+
tableRef.current.scrollTo(0, initialScroll);
|
|
135
|
+
}
|
|
136
|
+
}, [tableRef, initialScroll]);
|
|
137
|
+
|
|
126
138
|
useEffect(() => {
|
|
127
139
|
setColumns(columnsProp);
|
|
128
140
|
}, [columnsProp]);
|
|
@@ -158,7 +170,6 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
|
|
|
158
170
|
console.log("scrollToTop");
|
|
159
171
|
endReachCallbackThreshold.current = 0;
|
|
160
172
|
if (tableRef.current) {
|
|
161
|
-
// scrollRef.current = [scrollRef.current[0], 0];
|
|
162
173
|
tableRef.current.scrollTo(tableRef.current?.scrollLeft, 0);
|
|
163
174
|
}
|
|
164
175
|
}, []);
|
|
@@ -222,6 +233,13 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
|
|
|
222
233
|
scrollOffset,
|
|
223
234
|
scrollUpdateWasRequested
|
|
224
235
|
});
|
|
236
|
+
if (onScrollProp) {
|
|
237
|
+
debouncedScroll({
|
|
238
|
+
scrollDirection,
|
|
239
|
+
scrollOffset,
|
|
240
|
+
scrollUpdateWasRequested
|
|
241
|
+
})
|
|
242
|
+
}
|
|
225
243
|
if (!scrollUpdateWasRequested && (scrollOffset >= maxScroll - endOffset))
|
|
226
244
|
onEndReachedInternal(scrollOffset);
|
|
227
245
|
}, [maxScroll, onEndReachedInternal]);
|
|
@@ -294,7 +312,6 @@ export const VirtualTable = React.memo<VirtualTableProps<any>>(
|
|
|
294
312
|
if (debug)
|
|
295
313
|
console.log("VirtualTable render", virtualListController);
|
|
296
314
|
|
|
297
|
-
// useTraceUpdate(virtualListController);
|
|
298
315
|
return (
|
|
299
316
|
<div
|
|
300
317
|
ref={measureRef}
|
|
@@ -82,6 +82,16 @@ export interface VirtualTableProps<T extends Record<string, any>> {
|
|
|
82
82
|
*/
|
|
83
83
|
onFilterUpdate?: (filter?: VirtualTableFilterValues<any> | undefined) => void;
|
|
84
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Callback when the table is scrolled
|
|
87
|
+
* @param props
|
|
88
|
+
*/
|
|
89
|
+
onScroll?: (props: {
|
|
90
|
+
scrollDirection: "forward" | "backward",
|
|
91
|
+
scrollOffset: number,
|
|
92
|
+
scrollUpdateWasRequested: boolean
|
|
93
|
+
}) => void;
|
|
94
|
+
|
|
85
95
|
/**
|
|
86
96
|
* Default sort applied to this collection
|
|
87
97
|
*/
|
|
@@ -147,6 +157,11 @@ export interface VirtualTableProps<T extends Record<string, any>> {
|
|
|
147
157
|
*/
|
|
148
158
|
AddColumnComponent?: React.ComponentType;
|
|
149
159
|
|
|
160
|
+
/**
|
|
161
|
+
* Initial scroll position
|
|
162
|
+
*/
|
|
163
|
+
initialScroll?: number;
|
|
164
|
+
|
|
150
165
|
/**
|
|
151
166
|
* Debug mode
|
|
152
167
|
*/
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DeleteIcon, EditIcon, FileCopyIcon } from "@firecms/ui";
|
|
2
2
|
import { EntityAction } from "../../types";
|
|
3
3
|
import { DeleteEntityDialog } from "../DeleteEntityDialog";
|
|
4
4
|
import { addRecentId } from "../EntityCollectionView/utils";
|
|
5
|
+
import { navigateToEntity } from "../../util";
|
|
5
6
|
|
|
6
7
|
export const editEntityAction: EntityAction = {
|
|
7
8
|
icon: <EditIcon/>,
|
|
@@ -15,23 +16,31 @@ export const editEntityAction: EntityAction = {
|
|
|
15
16
|
context,
|
|
16
17
|
highlightEntity,
|
|
17
18
|
unhighlightEntity,
|
|
19
|
+
openEntityMode
|
|
18
20
|
}): Promise<void> {
|
|
21
|
+
|
|
19
22
|
highlightEntity?.(entity);
|
|
23
|
+
|
|
20
24
|
context.analyticsController?.onAnalyticsEvent?.("entity_click", {
|
|
21
25
|
path: entity.path,
|
|
22
26
|
entityId: entity.id
|
|
23
27
|
});
|
|
28
|
+
|
|
24
29
|
if (collection) {
|
|
25
30
|
addRecentId(collection.id, entity.id);
|
|
26
31
|
}
|
|
27
|
-
|
|
28
|
-
|
|
32
|
+
|
|
33
|
+
const path = collection?.collectionGroup ? entity.path : (fullPath ?? entity.path)
|
|
34
|
+
navigateToEntity({
|
|
35
|
+
openEntityMode,
|
|
36
|
+
collection,
|
|
29
37
|
entityId: entity.id,
|
|
30
38
|
path,
|
|
31
|
-
|
|
32
|
-
updateUrl: true,
|
|
39
|
+
sideEntityController: context.sideEntityController,
|
|
33
40
|
onClose: () => unhighlightEntity?.(entity),
|
|
41
|
+
navigation: context.navigation
|
|
34
42
|
});
|
|
43
|
+
|
|
35
44
|
return Promise.resolve(undefined);
|
|
36
45
|
}
|
|
37
46
|
}
|
|
@@ -44,27 +53,32 @@ export const copyEntityAction: EntityAction = {
|
|
|
44
53
|
entity,
|
|
45
54
|
collection,
|
|
46
55
|
context,
|
|
56
|
+
fullPath,
|
|
47
57
|
highlightEntity,
|
|
48
58
|
unhighlightEntity,
|
|
59
|
+
openEntityMode
|
|
49
60
|
}): Promise<void> {
|
|
50
61
|
highlightEntity?.(entity);
|
|
51
62
|
context.analyticsController?.onAnalyticsEvent?.("copy_entity_click", {
|
|
52
63
|
path: entity.path,
|
|
53
64
|
entityId: entity.id
|
|
54
65
|
});
|
|
55
|
-
|
|
66
|
+
const path = collection?.collectionGroup ? entity.path : (fullPath ?? entity.path)
|
|
67
|
+
navigateToEntity({
|
|
68
|
+
openEntityMode,
|
|
69
|
+
collection,
|
|
56
70
|
entityId: entity.id,
|
|
57
|
-
path
|
|
71
|
+
path,
|
|
58
72
|
copy: true,
|
|
59
|
-
|
|
60
|
-
updateUrl: true,
|
|
73
|
+
sideEntityController: context.sideEntityController,
|
|
61
74
|
onClose: () => unhighlightEntity?.(entity),
|
|
75
|
+
navigation: context.navigation
|
|
62
76
|
});
|
|
77
|
+
|
|
63
78
|
return Promise.resolve(undefined);
|
|
64
79
|
}
|
|
65
80
|
}
|
|
66
81
|
|
|
67
|
-
|
|
68
82
|
export const deleteEntityAction: EntityAction = {
|
|
69
83
|
icon: <DeleteIcon/>,
|
|
70
84
|
name: "Delete",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export * from "./types";
|
|
2
2
|
export * from "./useDebouncedData";
|
|
3
3
|
export * from "./useColumnsIds";
|
|
4
|
-
export * from "./
|
|
4
|
+
export * from "./useDataSourceTableController";
|
|
5
5
|
export * from "./useTableSearchHelper";
|
|
6
6
|
export * from "./default_entity_actions";
|