@firecms/core 3.0.0-beta.11 → 3.0.0-beta.13
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/app/Scaffold.d.ts +4 -0
- package/dist/components/ArrayContainer.d.ts +14 -3
- 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 +8 -0
- package/dist/components/EntityJsonPreview.d.ts +3 -0
- package/dist/components/PropertyIdCopyTooltip.d.ts +1 -1
- package/dist/components/SelectableTable/SelectableTable.d.ts +12 -2
- package/dist/components/SelectableTable/filters/ReferenceFilterField.d.ts +1 -1
- package/dist/components/UnsavedChangesDialog.d.ts +8 -0
- package/dist/components/VirtualTable/VirtualTableProps.d.ts +13 -0
- package/dist/components/common/default_entity_actions.d.ts +0 -2
- package/dist/components/common/index.d.ts +1 -1
- package/dist/components/common/useColumnsIds.d.ts +1 -0
- 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/DefaultAppBar.d.ts +8 -2
- package/dist/core/EntityEditView.d.ts +36 -21
- package/dist/core/EntityEditViewFormActions.d.ts +2 -0
- package/dist/core/FireCMS.d.ts +2 -2
- package/dist/core/FireCMSRouter.d.ts +4 -0
- package/dist/core/NavigationRoutes.d.ts +0 -1
- package/dist/core/SideDialogs.d.ts +4 -2
- package/dist/core/index.d.ts +2 -1
- package/dist/form/EntityForm.d.ts +49 -0
- package/dist/form/EntityFormActions.d.ts +17 -0
- package/dist/form/PropertyFieldBinding.d.ts +1 -1
- package/dist/form/components/FormEntry.d.ts +6 -0
- package/dist/form/components/FormLayout.d.ts +5 -0
- package/dist/form/components/index.d.ts +2 -0
- package/dist/form/field_bindings/ArrayCustomShapedFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/ArrayOfReferencesFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/BlockFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/MarkdownEditorFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/RepeatFieldBinding.d.ts +1 -1
- package/dist/form/index.d.ts +16 -16
- package/dist/hooks/data/save.d.ts +1 -1
- package/dist/hooks/data/useEntityFetch.d.ts +2 -1
- package/dist/hooks/useBreadcrumbsController.d.ts +26 -0
- package/dist/hooks/useBuildNavigationController.d.ts +4 -1
- package/dist/hooks/useModeController.d.ts +1 -2
- package/dist/index.es.js +15842 -14396
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +15833 -14389
- package/dist/index.umd.js.map +1 -1
- package/dist/internal/useBuildDataSource.d.ts +3 -2
- package/dist/internal/useBuildSideEntityController.d.ts +3 -3
- 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 +36 -10
- package/dist/types/datasource.d.ts +2 -2
- package/dist/types/dialogs_controller.d.ts +7 -3
- package/dist/types/entities.d.ts +1 -1
- package/dist/types/entity_actions.d.ts +10 -0
- package/dist/types/fields.d.ts +13 -3
- package/dist/types/firecms.d.ts +1 -1
- package/dist/types/navigation.d.ts +33 -12
- package/dist/types/plugins.d.ts +2 -0
- package/dist/types/properties.d.ts +40 -4
- package/dist/types/side_entity_controller.d.ts +6 -1
- package/dist/util/builders.d.ts +1 -1
- package/dist/util/createFormexStub.d.ts +2 -0
- package/dist/util/entity_actions.d.ts +2 -0
- package/dist/util/entity_cache.d.ts +23 -0
- package/dist/util/index.d.ts +1 -0
- package/dist/util/navigation_from_path.d.ts +6 -1
- package/dist/util/navigation_utils.d.ts +13 -1
- package/dist/util/objects.d.ts +1 -1
- package/dist/util/property_utils.d.ts +2 -2
- package/dist/util/references.d.ts +2 -2
- package/dist/util/resolutions.d.ts +12 -2
- package/package.json +20 -21
- package/src/app/Scaffold.tsx +13 -3
- package/src/components/ArrayContainer.tsx +60 -24
- package/src/components/CircularProgressCenter.tsx +1 -1
- package/src/components/DeleteEntityDialog.tsx +5 -3
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +46 -23
- 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/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +10 -13
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +105 -47
- package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +4 -2
- package/src/components/EntityJsonPreview.tsx +66 -0
- package/src/components/EntityPreview.tsx +10 -3
- package/src/components/EntityView.tsx +4 -1
- package/src/components/NotFoundPage.tsx +2 -2
- package/src/components/PropertyIdCopyTooltip.tsx +2 -3
- package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +14 -7
- package/src/components/SelectableTable/SelectableTable.tsx +18 -3
- package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +7 -7
- package/src/components/UnsavedChangesDialog.tsx +42 -0
- package/src/components/VirtualTable/VirtualTable.tsx +48 -3
- 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 +37 -37
- package/src/components/common/index.ts +1 -1
- package/src/components/common/useColumnsIds.tsx +1 -1
- package/src/components/common/useDataSourceTableController.tsx +420 -0
- 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 +3 -2
- package/src/contexts/ModeController.tsx +1 -3
- package/src/core/DefaultAppBar.tsx +59 -17
- package/src/core/DefaultDrawer.tsx +1 -1
- package/src/core/EntityEditView.tsx +354 -1000
- package/src/core/EntityEditViewFormActions.tsx +199 -0
- package/src/core/EntitySidePanel.tsx +85 -15
- package/src/core/FireCMS.tsx +20 -16
- package/src/core/FireCMSRouter.tsx +17 -0
- package/src/core/NavigationRoutes.tsx +23 -32
- package/src/core/SideDialogs.tsx +20 -11
- package/src/core/index.tsx +4 -2
- package/src/form/EntityForm.tsx +782 -0
- package/src/form/EntityFormActions.tsx +169 -0
- package/src/form/PropertyFieldBinding.tsx +21 -16
- package/src/form/components/FormEntry.tsx +22 -0
- package/src/form/components/FormLayout.tsx +16 -0
- package/src/form/components/LabelWithIcon.tsx +6 -3
- package/src/form/components/StorageUploadProgress.tsx +1 -1
- package/src/form/components/index.tsx +2 -0
- package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +8 -5
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +5 -2
- package/src/form/field_bindings/BlockFieldBinding.tsx +5 -3
- package/src/form/field_bindings/DateTimeFieldBinding.tsx +1 -0
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +1 -1
- package/src/form/field_bindings/MapFieldBinding.tsx +14 -16
- package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +15 -8
- package/src/form/field_bindings/MultiSelectFieldBinding.tsx +3 -3
- package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +2 -2
- package/src/form/field_bindings/ReferenceFieldBinding.tsx +1 -1
- package/src/form/field_bindings/RepeatFieldBinding.tsx +13 -4
- package/src/form/field_bindings/SelectFieldBinding.tsx +2 -2
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +11 -6
- package/src/form/field_bindings/SwitchFieldBinding.tsx +1 -0
- package/src/form/field_bindings/TextFieldBinding.tsx +1 -0
- package/src/form/index.tsx +16 -32
- package/src/form/validation.ts +12 -6
- package/src/hooks/data/save.ts +25 -30
- 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/useBuildModeController.tsx +15 -28
- package/src/hooks/useBuildNavigationController.tsx +81 -24
- package/src/hooks/useFireCMSContext.tsx +0 -30
- package/src/hooks/useLargeLayout.tsx +0 -35
- package/src/hooks/useModeController.tsx +1 -2
- package/src/hooks/useResolvedNavigationFrom.tsx +4 -6
- package/src/internal/useBuildDataSource.ts +9 -5
- package/src/internal/useBuildSideDialogsController.tsx +3 -2
- package/src/internal/useBuildSideEntityController.tsx +135 -88
- package/src/internal/useUnsavedChangesDialog.tsx +126 -92
- package/src/preview/PropertyPreview.tsx +12 -10
- package/src/preview/components/UrlComponentPreview.tsx +17 -18
- package/src/preview/property_previews/ArrayOfMapsPreview.tsx +4 -3
- package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +4 -3
- package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +4 -2
- package/src/preview/property_previews/ArrayOfStringsPreview.tsx +4 -3
- package/src/preview/property_previews/ArrayOneOfPreview.tsx +4 -2
- package/src/preview/property_previews/ArrayPropertyPreview.tsx +4 -2
- package/src/preview/property_previews/MapPropertyPreview.tsx +3 -2
- package/src/routes/CustomCMSRoute.tsx +21 -0
- package/src/routes/FireCMSRoute.tsx +246 -0
- package/src/routes/HomePageRoute.tsx +17 -0
- package/src/types/collections.ts +45 -13
- package/src/types/datasource.ts +2 -1
- package/src/types/dialogs_controller.tsx +7 -3
- package/src/types/entities.ts +1 -1
- package/src/types/entity_actions.tsx +12 -0
- package/src/types/fields.tsx +18 -3
- package/src/types/firecms.tsx +1 -1
- package/src/types/navigation.ts +41 -16
- package/src/types/plugins.tsx +2 -0
- package/src/types/properties.ts +48 -4
- package/src/types/side_dialogs_controller.tsx +2 -0
- package/src/types/side_entity_controller.tsx +11 -1
- package/src/util/builders.ts +5 -3
- package/src/util/createFormexStub.tsx +62 -0
- package/src/util/entity_actions.ts +28 -0
- package/src/util/entity_cache.ts +204 -0
- package/src/util/index.ts +1 -0
- package/src/util/join_collections.ts +6 -1
- package/src/util/navigation_from_path.ts +18 -7
- package/src/util/navigation_utils.ts +115 -14
- package/src/util/objects.ts +9 -2
- package/src/util/parent_references_from_path.ts +3 -3
- package/src/util/property_utils.tsx +7 -3
- package/src/util/references.ts +8 -6
- package/src/util/resolutions.ts +41 -12
- package/src/util/useStorageUploadController.tsx +60 -23
- package/src/components/common/useDataSourceEntityCollectionTableController.tsx +0 -236
- /package/src/util/{common.tsx → common.ts} +0 -0
|
@@ -72,6 +72,21 @@ export type EntityCollectionTableProps<M extends Record<string, any>,
|
|
|
72
72
|
*/
|
|
73
73
|
onColumnResize?(params: OnColumnResizeParams): void;
|
|
74
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Initial scroll position
|
|
77
|
+
*/
|
|
78
|
+
initialScroll?: number;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Callback when the table is scrolled
|
|
82
|
+
* @param props
|
|
83
|
+
*/
|
|
84
|
+
onScroll?: (props: {
|
|
85
|
+
scrollDirection: "forward" | "backward",
|
|
86
|
+
scrollOffset: number,
|
|
87
|
+
scrollUpdateWasRequested: boolean
|
|
88
|
+
}) => void;
|
|
89
|
+
|
|
75
90
|
/**
|
|
76
91
|
* Callback when the selected size of the table is changed
|
|
77
92
|
*/
|
|
@@ -90,7 +105,7 @@ export type EntityCollectionTableProps<M extends Record<string, any>,
|
|
|
90
105
|
|
|
91
106
|
/**
|
|
92
107
|
* Controller holding the logic for the table
|
|
93
|
-
* {@link
|
|
108
|
+
* {@link useDataSourceTableController}
|
|
94
109
|
* {@link EntityTableController}
|
|
95
110
|
*/
|
|
96
111
|
tableController: EntityTableController<M>;
|
|
@@ -136,6 +151,8 @@ export type EntityCollectionTableProps<M extends Record<string, any>,
|
|
|
136
151
|
textSearchLoading?: boolean;
|
|
137
152
|
|
|
138
153
|
enablePopupIcon: boolean;
|
|
154
|
+
|
|
155
|
+
openEntityMode?: "side_panel" | "full_screen";
|
|
139
156
|
};
|
|
140
157
|
|
|
141
158
|
export type GetPropertyForProps<M extends Record<string, any>> = {
|
|
@@ -8,5 +8,5 @@ export type {
|
|
|
8
8
|
|
|
9
9
|
export * from "./PropertyTableCell";
|
|
10
10
|
export * from "./EntityCollectionRowActions";
|
|
11
|
-
export * from "../common/
|
|
11
|
+
export * from "../common/useDataSourceTableController";
|
|
12
12
|
export * from "./column_utils";
|
|
@@ -56,7 +56,7 @@ export function CollectionTableToolbar({
|
|
|
56
56
|
<Select
|
|
57
57
|
value={size as string}
|
|
58
58
|
className="w-16 h-10"
|
|
59
|
-
size={"
|
|
59
|
+
size={"small"}
|
|
60
60
|
onValueChange={(v) => onSizeChanged(v as CollectionSize)}
|
|
61
61
|
renderValue={(v) => <div className={"font-medium"}>{v.toUpperCase()}</div>}
|
|
62
62
|
>
|
|
@@ -87,9 +87,9 @@ export function CollectionTableToolbar({
|
|
|
87
87
|
|
|
88
88
|
<div className="flex items-center gap-2">
|
|
89
89
|
|
|
90
|
-
{largeLayout && <div className="w-[22px]">
|
|
90
|
+
{largeLayout && <div className="w-[22px] mr-4">
|
|
91
91
|
{loading &&
|
|
92
|
-
<CircularProgress size={"
|
|
92
|
+
<CircularProgress size={"smallest"}/>}
|
|
93
93
|
</div>}
|
|
94
94
|
|
|
95
95
|
{(onTextSearch || onTextSearchClick) &&
|
|
@@ -20,10 +20,9 @@ import { useWindowSize } from "./useWindowSize";
|
|
|
20
20
|
import { ElementResizeListener } from "./ElementResizeListener";
|
|
21
21
|
import { getPropertyInPath, isReadOnly, resolveCollection } from "../../../../util";
|
|
22
22
|
import { Button, CloseIcon, DialogActions, IconButton, Typography } from "@firecms/ui";
|
|
23
|
-
import { PropertyFieldBinding } from "../../../../form";
|
|
24
|
-
import { useCustomizationController, useDataSource, useFireCMSContext } from "../../../../hooks";
|
|
23
|
+
import { PropertyFieldBinding, yupToFormErrors } from "../../../../form";
|
|
24
|
+
import { useAuthController, useCustomizationController, useDataSource, useFireCMSContext } from "../../../../hooks";
|
|
25
25
|
import { OnCellValueChangeParams } from "../../../common";
|
|
26
|
-
import { yupToFormErrors } from "../../../../core/EntityEditView";
|
|
27
26
|
|
|
28
27
|
interface PopupFormFieldProps<M extends Record<string, any>> {
|
|
29
28
|
customFieldValidator?: CustomFieldValidator;
|
|
@@ -108,6 +107,7 @@ export function PopupFormFieldInternal<M extends Record<string, any>>({
|
|
|
108
107
|
}) {
|
|
109
108
|
|
|
110
109
|
const fireCMSContext = useFireCMSContext();
|
|
110
|
+
const authController = useAuthController();
|
|
111
111
|
const customizationController = useCustomizationController();
|
|
112
112
|
|
|
113
113
|
const [savingError, setSavingError] = React.useState<any>();
|
|
@@ -122,7 +122,8 @@ export function PopupFormFieldInternal<M extends Record<string, any>>({
|
|
|
122
122
|
path,
|
|
123
123
|
values: entity?.values,
|
|
124
124
|
entityId,
|
|
125
|
-
propertyConfigs: customizationController.propertyConfigs
|
|
125
|
+
propertyConfigs: customizationController.propertyConfigs,
|
|
126
|
+
authController
|
|
126
127
|
})
|
|
127
128
|
: undefined;
|
|
128
129
|
|
|
@@ -240,14 +241,7 @@ export function PopupFormFieldInternal<M extends Record<string, any>>({
|
|
|
240
241
|
validation: (values) => {
|
|
241
242
|
return validationSchema?.validate(values, { abortEarly: false })
|
|
242
243
|
.then(() => ({}))
|
|
243
|
-
.catch(
|
|
244
|
-
// const errors: Record<string, string> = {};
|
|
245
|
-
// e.inner.forEach((error: any) => {
|
|
246
|
-
// errors[error.path] = error.message;
|
|
247
|
-
// });
|
|
248
|
-
// return errors;
|
|
249
|
-
return yupToFormErrors(e);
|
|
250
|
-
});
|
|
244
|
+
.catch(yupToFormErrors);
|
|
251
245
|
},
|
|
252
246
|
validateOnInitialRender: true,
|
|
253
247
|
onSubmit: (values, actions) => {
|
|
@@ -278,7 +272,10 @@ export function PopupFormFieldInternal<M extends Record<string, any>>({
|
|
|
278
272
|
path,
|
|
279
273
|
setFieldValue,
|
|
280
274
|
save: saveValue,
|
|
281
|
-
formex
|
|
275
|
+
formex,
|
|
276
|
+
status: "existing",
|
|
277
|
+
openEntityMode: "side_panel",
|
|
278
|
+
disabled: false,
|
|
282
279
|
};
|
|
283
280
|
|
|
284
281
|
const property: ResolvedProperty<any> | undefined = propertyKey && getPropertyInPath(collection?.properties ?? {} as ResolvedProperties, propertyKey as string);
|
|
@@ -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";
|
|
@@ -61,6 +63,10 @@ import {
|
|
|
61
63
|
import { setIn } from "@firecms/formex";
|
|
62
64
|
import { getSubcollectionColumnId } from "../EntityCollectionTable/internal/common";
|
|
63
65
|
import {
|
|
66
|
+
COLLECTION_GROUP_PARENT_ID,
|
|
67
|
+
copyEntityAction,
|
|
68
|
+
deleteEntityAction,
|
|
69
|
+
editEntityAction,
|
|
64
70
|
OnCellValueChange,
|
|
65
71
|
OnColumnResizeParams,
|
|
66
72
|
UniqueFieldValidator,
|
|
@@ -69,14 +75,14 @@ import {
|
|
|
69
75
|
} from "../common";
|
|
70
76
|
import { PopupFormField } from "../EntityCollectionTable/internal/popup_field/PopupFormField";
|
|
71
77
|
import { GetPropertyForProps } from "../EntityCollectionTable/EntityCollectionTableProps";
|
|
72
|
-
import { copyEntityAction, deleteEntityAction, editEntityAction } from "../common/default_entity_actions";
|
|
73
78
|
import { DeleteEntityDialog } from "../DeleteEntityDialog";
|
|
74
79
|
import { useAnalyticsController } from "../../hooks/useAnalyticsController";
|
|
75
80
|
import { useSelectionController } from "./useSelectionController";
|
|
76
81
|
import { EntityCollectionViewStartActions } from "./EntityCollectionViewStartActions";
|
|
77
82
|
import { addRecentId, getRecentIds } from "./utils";
|
|
83
|
+
import { useScrollRestoration } from "../common/useScrollRestoration";
|
|
78
84
|
|
|
79
|
-
const
|
|
85
|
+
const DEFAULT_ENTITY_OPEN_MODE: "side_panel" | "full_screen" = "side_panel";
|
|
80
86
|
|
|
81
87
|
/**
|
|
82
88
|
* @group Components
|
|
@@ -87,6 +93,10 @@ export type EntityCollectionViewProps<M extends Record<string, any>> = {
|
|
|
87
93
|
* It defaults to the collection path if not provided.
|
|
88
94
|
*/
|
|
89
95
|
fullPath?: string;
|
|
96
|
+
/**
|
|
97
|
+
* Full path using navigation ids.
|
|
98
|
+
*/
|
|
99
|
+
fullIdPath?: string;
|
|
90
100
|
/**
|
|
91
101
|
* If this is a subcollection, specify the parent collection ids.
|
|
92
102
|
*/
|
|
@@ -98,6 +108,11 @@ export type EntityCollectionViewProps<M extends Record<string, any>> = {
|
|
|
98
108
|
|
|
99
109
|
className?: string;
|
|
100
110
|
|
|
111
|
+
/**
|
|
112
|
+
* If true, this view will store its filter and sorting status in the url params
|
|
113
|
+
*/
|
|
114
|
+
updateUrl?: boolean;
|
|
115
|
+
|
|
101
116
|
} & EntityCollection<M>;
|
|
102
117
|
|
|
103
118
|
/**
|
|
@@ -127,17 +142,20 @@ export type EntityCollectionViewProps<M extends Record<string, any>> = {
|
|
|
127
142
|
export const EntityCollectionView = React.memo(
|
|
128
143
|
function EntityCollectionView<M extends Record<string, any>>({
|
|
129
144
|
fullPath: fullPathProp,
|
|
145
|
+
fullIdPath,
|
|
130
146
|
parentCollectionIds,
|
|
131
147
|
isSubCollection,
|
|
132
148
|
className,
|
|
149
|
+
updateUrl,
|
|
133
150
|
...collectionProp
|
|
134
151
|
}: EntityCollectionViewProps<M>
|
|
135
152
|
) {
|
|
136
153
|
|
|
154
|
+
|
|
137
155
|
const context = useFireCMSContext();
|
|
156
|
+
const navigation = useNavigationController();
|
|
138
157
|
const fullPath = fullPathProp ?? collectionProp.path;
|
|
139
158
|
const dataSource = useDataSource(collectionProp);
|
|
140
|
-
const navigation = useNavigationController();
|
|
141
159
|
const sideEntityController = useSideEntityController();
|
|
142
160
|
const authController = useAuthController();
|
|
143
161
|
const userConfigPersistence = useUserConfigurationPersistence();
|
|
@@ -146,11 +164,15 @@ export const EntityCollectionView = React.memo(
|
|
|
146
164
|
|
|
147
165
|
const containerRef = React.useRef<HTMLDivElement>(null);
|
|
148
166
|
|
|
167
|
+
const scrollRestoration = useScrollRestoration();
|
|
168
|
+
|
|
149
169
|
const collection = useMemo(() => {
|
|
150
170
|
const userOverride = userConfigPersistence?.getCollectionConfig<M>(fullPath);
|
|
151
171
|
return (userOverride ? mergeDeep(collectionProp, userOverride) : collectionProp) as EntityCollection<M>;
|
|
152
172
|
}, [collectionProp, fullPath, userConfigPersistence?.getCollectionConfig]);
|
|
153
173
|
|
|
174
|
+
const openEntityMode = collection?.openEntityMode ?? DEFAULT_ENTITY_OPEN_MODE;
|
|
175
|
+
|
|
154
176
|
const collectionRef = React.useRef(collection);
|
|
155
177
|
useEffect(() => {
|
|
156
178
|
collectionRef.current = collection;
|
|
@@ -193,14 +215,12 @@ export const EntityCollectionView = React.memo(
|
|
|
193
215
|
setSelectedEntities
|
|
194
216
|
} = usedSelectionController;
|
|
195
217
|
|
|
196
|
-
|
|
197
|
-
// setDeleteEntityClicked(undefined);
|
|
198
|
-
// }, [selectedEntities]);
|
|
199
|
-
|
|
200
|
-
const tableController = useDataSourceEntityCollectionTableController<M>({
|
|
218
|
+
const tableController = useDataSourceTableController<M>({
|
|
201
219
|
fullPath,
|
|
202
220
|
collection,
|
|
203
|
-
lastDeleteTimestamp
|
|
221
|
+
lastDeleteTimestamp,
|
|
222
|
+
scrollRestoration,
|
|
223
|
+
updateUrl
|
|
204
224
|
});
|
|
205
225
|
|
|
206
226
|
const tableKey = React.useRef<string>(Math.random().toString(36));
|
|
@@ -217,13 +237,22 @@ export const EntityCollectionView = React.memo(
|
|
|
217
237
|
path: clickedEntity.path,
|
|
218
238
|
entityId: clickedEntity.id
|
|
219
239
|
});
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
240
|
+
|
|
241
|
+
if (collection) {
|
|
242
|
+
addRecentId(collection.id, clickedEntity.id);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const path = collection?.collectionGroup ? clickedEntity.path : (fullPath ?? clickedEntity.path);
|
|
246
|
+
navigateToEntity({
|
|
247
|
+
navigation,
|
|
248
|
+
path,
|
|
249
|
+
fullIdPath,
|
|
250
|
+
sideEntityController,
|
|
251
|
+
openEntityMode,
|
|
223
252
|
collection,
|
|
224
|
-
|
|
225
|
-
onClose: unselectNavigatedEntity,
|
|
253
|
+
entityId: clickedEntity.id
|
|
226
254
|
});
|
|
255
|
+
|
|
227
256
|
}, [unselectNavigatedEntity, sideEntityController]);
|
|
228
257
|
|
|
229
258
|
const onNewClick = useCallback(() => {
|
|
@@ -232,12 +261,16 @@ export const EntityCollectionView = React.memo(
|
|
|
232
261
|
analyticsController.onAnalyticsEvent?.("new_entity_click", {
|
|
233
262
|
path: fullPath
|
|
234
263
|
});
|
|
235
|
-
|
|
236
|
-
|
|
264
|
+
navigateToEntity({
|
|
265
|
+
openEntityMode,
|
|
237
266
|
collection,
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
267
|
+
entityId: undefined,
|
|
268
|
+
path: fullPath,
|
|
269
|
+
fullIdPath,
|
|
270
|
+
sideEntityController,
|
|
271
|
+
navigation,
|
|
272
|
+
onClose: unselectNavigatedEntity
|
|
273
|
+
})
|
|
241
274
|
}, [fullPath, sideEntityController]);
|
|
242
275
|
|
|
243
276
|
const onMultipleDeleteClick = () => {
|
|
@@ -323,7 +356,7 @@ export const EntityCollectionView = React.memo(
|
|
|
323
356
|
const updatedValues = setIn({ ...entity.values }, propertyKey, value);
|
|
324
357
|
|
|
325
358
|
const saveProps: SaveEntityProps = {
|
|
326
|
-
path: fullPath,
|
|
359
|
+
path: entity.path ?? fullPath,
|
|
327
360
|
entityId: entity.id,
|
|
328
361
|
values: updatedValues,
|
|
329
362
|
previousValues: entity.values,
|
|
@@ -349,11 +382,12 @@ export const EntityCollectionView = React.memo(
|
|
|
349
382
|
|
|
350
383
|
};
|
|
351
384
|
|
|
352
|
-
const resolvedFullPath = navigation.
|
|
385
|
+
const resolvedFullPath = navigation.resolveIdsFrom(fullPath);
|
|
353
386
|
const resolvedCollection = useMemo(() => resolveCollection<M>({
|
|
354
387
|
collection,
|
|
355
388
|
path: fullPath,
|
|
356
|
-
propertyConfigs: customizationController.propertyConfigs
|
|
389
|
+
propertyConfigs: customizationController.propertyConfigs,
|
|
390
|
+
authController,
|
|
357
391
|
}), [collection, fullPath]);
|
|
358
392
|
|
|
359
393
|
const getPropertyFor = useCallback(({
|
|
@@ -374,7 +408,8 @@ export const EntityCollectionView = React.memo(
|
|
|
374
408
|
path: entity.path,
|
|
375
409
|
values: entity.values,
|
|
376
410
|
entityId: entity.id,
|
|
377
|
-
propertyConfigs: customizationController.propertyConfigs
|
|
411
|
+
propertyConfigs: customizationController.propertyConfigs,
|
|
412
|
+
authController
|
|
378
413
|
});
|
|
379
414
|
}, [collection.properties, customizationController.propertyConfigs, resolvedCollection.properties]);
|
|
380
415
|
|
|
@@ -393,13 +428,16 @@ export const EntityCollectionView = React.memo(
|
|
|
393
428
|
startIcon={<KeyboardTabIcon size={"small"}/>}
|
|
394
429
|
onClick={(event: any) => {
|
|
395
430
|
event.stopPropagation();
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
entityId: entity.id,
|
|
399
|
-
selectedSubPath: subcollection.id ?? subcollection.path,
|
|
431
|
+
navigateToEntity({
|
|
432
|
+
openEntityMode,
|
|
400
433
|
collection,
|
|
401
|
-
|
|
402
|
-
|
|
434
|
+
entityId: entity.id,
|
|
435
|
+
selectedTab: subcollection.id ?? subcollection.path,
|
|
436
|
+
path: fullPath,
|
|
437
|
+
fullIdPath,
|
|
438
|
+
navigation,
|
|
439
|
+
sideEntityController
|
|
440
|
+
})
|
|
403
441
|
}}>
|
|
404
442
|
{subcollection.name}
|
|
405
443
|
</Button>
|
|
@@ -458,7 +496,7 @@ export const EntityCollectionView = React.memo(
|
|
|
458
496
|
if (deleteEnabled)
|
|
459
497
|
actions.push(deleteEntityAction);
|
|
460
498
|
if (customEntityActions)
|
|
461
|
-
actions
|
|
499
|
+
return mergeEntityActions(actions, customEntityActions);
|
|
462
500
|
return actions;
|
|
463
501
|
};
|
|
464
502
|
|
|
@@ -500,11 +538,12 @@ export const EntityCollectionView = React.memo(
|
|
|
500
538
|
highlightEntity={setHighlightedEntity}
|
|
501
539
|
unhighlightEntity={unselectNavigatedEntity}
|
|
502
540
|
collection={collection}
|
|
503
|
-
fullPath={fullPath}
|
|
541
|
+
fullPath={fullIdPath ?? fullPath}
|
|
504
542
|
actions={actions}
|
|
505
543
|
hideId={collection?.hideIdFromCollection}
|
|
506
544
|
onCollectionChange={updateLastDeleteTimestamp}
|
|
507
545
|
selectionController={usedSelectionController}
|
|
546
|
+
openEntityMode={openEntityMode}
|
|
508
547
|
/>
|
|
509
548
|
);
|
|
510
549
|
|
|
@@ -617,6 +656,8 @@ export const EntityCollectionView = React.memo(
|
|
|
617
656
|
properties={resolvedCollection.properties}
|
|
618
657
|
getPropertyFor={getPropertyFor}
|
|
619
658
|
onTextSearchClick={textSearchInitialised ? undefined : onTextSearchClick}
|
|
659
|
+
onScroll={tableController.onScroll}
|
|
660
|
+
initialScroll={tableController.initialScroll}
|
|
620
661
|
textSearchLoading={textSearchLoading}
|
|
621
662
|
textSearchEnabled={textSearchEnabled}
|
|
622
663
|
actionsStart={<EntityCollectionViewStartActions
|
|
@@ -661,7 +702,9 @@ export const EntityCollectionView = React.memo(
|
|
|
661
702
|
getIdColumnWidth={getIdColumnWidth}
|
|
662
703
|
additionalIDHeaderWidget={<EntityIdHeaderWidget
|
|
663
704
|
path={fullPath}
|
|
705
|
+
fullIdPath={fullIdPath ?? fullPath}
|
|
664
706
|
collection={collection}/>}
|
|
707
|
+
openEntityMode={openEntityMode}
|
|
665
708
|
/>
|
|
666
709
|
|
|
667
710
|
{popupCell && <PopupFormField
|
|
@@ -692,7 +735,7 @@ export const EntityCollectionView = React.memo(
|
|
|
692
735
|
</div>
|
|
693
736
|
);
|
|
694
737
|
}, (a, b) => {
|
|
695
|
-
return equal(a.
|
|
738
|
+
return equal(a.path, b.path) &&
|
|
696
739
|
equal(a.parentCollectionIds, b.parentCollectionIds) &&
|
|
697
740
|
equal(a.isSubCollection, b.isSubCollection) &&
|
|
698
741
|
equal(a.className, b.className) &&
|
|
@@ -709,6 +752,7 @@ export const EntityCollectionView = React.memo(
|
|
|
709
752
|
equal(a.textSearchEnabled, b.textSearchEnabled) &&
|
|
710
753
|
equal(a.additionalFields, b.additionalFields) &&
|
|
711
754
|
equal(a.sideDialogWidth, b.sideDialogWidth) &&
|
|
755
|
+
equal(a.openEntityMode, b.openEntityMode) &&
|
|
712
756
|
equal(a.forceFilter, b.forceFilter);
|
|
713
757
|
}) as React.FunctionComponent<EntityCollectionViewProps<any>>
|
|
714
758
|
|
|
@@ -733,7 +777,7 @@ function EntitiesCount({
|
|
|
733
777
|
|
|
734
778
|
const sortByProperty = sortBy ? sortBy[0] : undefined;
|
|
735
779
|
const currentSort = sortBy ? sortBy[1] : undefined;
|
|
736
|
-
const resolvedPath = useMemo(() => navigation.
|
|
780
|
+
const resolvedPath = useMemo(() => navigation.resolveIdsFrom(fullPath), [fullPath, navigation.resolveIdsFrom]);
|
|
737
781
|
|
|
738
782
|
useEffect(() => {
|
|
739
783
|
if (dataSource.countEntities)
|
|
@@ -775,16 +819,22 @@ function buildPropertyWidthOverwrite(key: string, width: number): PartialEntityC
|
|
|
775
819
|
|
|
776
820
|
function EntityIdHeaderWidget({
|
|
777
821
|
collection,
|
|
778
|
-
path
|
|
822
|
+
path,
|
|
823
|
+
fullIdPath
|
|
779
824
|
}: {
|
|
780
825
|
collection: EntityCollection,
|
|
781
|
-
path: string
|
|
826
|
+
path: string,
|
|
827
|
+
fullIdPath: string
|
|
782
828
|
}) {
|
|
829
|
+
|
|
830
|
+
const navigation = useNavigationController();
|
|
783
831
|
const [openPopup, setOpenPopup] = React.useState(false);
|
|
784
832
|
const [searchString, setSearchString] = React.useState("");
|
|
785
833
|
const [recentIds, setRecentIds] = React.useState<string[]>(getRecentIds(collection.id));
|
|
786
834
|
const sideEntityController = useSideEntityController();
|
|
787
835
|
|
|
836
|
+
const openEntityMode = collection?.openEntityMode ?? DEFAULT_ENTITY_OPEN_MODE;
|
|
837
|
+
|
|
788
838
|
return (
|
|
789
839
|
<Tooltip title={!openPopup ? "Find by ID" : undefined} asChild={false}>
|
|
790
840
|
<Popover
|
|
@@ -798,19 +848,24 @@ function EntityIdHeaderWidget({
|
|
|
798
848
|
<SearchIcon size={"small"}/>
|
|
799
849
|
</IconButton>
|
|
800
850
|
}>
|
|
801
|
-
<div
|
|
851
|
+
<div
|
|
852
|
+
className={cls("my-2 rounded-lg bg-surface-50 dark:bg-surface-950 text-surface-900 dark:text-white")}>
|
|
802
853
|
<form noValidate={true}
|
|
803
854
|
onSubmit={(e) => {
|
|
804
855
|
e.preventDefault();
|
|
805
856
|
if (!searchString) return;
|
|
806
857
|
setOpenPopup(false);
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
858
|
+
const entityId = searchString.trim();
|
|
859
|
+
setRecentIds(addRecentId(collection.id, entityId));
|
|
860
|
+
navigateToEntity({
|
|
861
|
+
openEntityMode,
|
|
811
862
|
collection,
|
|
812
|
-
|
|
813
|
-
|
|
863
|
+
entityId,
|
|
864
|
+
path,
|
|
865
|
+
fullIdPath,
|
|
866
|
+
sideEntityController,
|
|
867
|
+
navigation
|
|
868
|
+
})
|
|
814
869
|
}}
|
|
815
870
|
className={"w-96 max-w-full"}>
|
|
816
871
|
|
|
@@ -837,12 +892,15 @@ function EntityIdHeaderWidget({
|
|
|
837
892
|
hover={true}
|
|
838
893
|
onClick={() => {
|
|
839
894
|
setOpenPopup(false);
|
|
840
|
-
|
|
895
|
+
navigateToEntity({
|
|
896
|
+
openEntityMode,
|
|
897
|
+
collection,
|
|
841
898
|
entityId: id,
|
|
842
899
|
path,
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
900
|
+
fullIdPath,
|
|
901
|
+
sideEntityController,
|
|
902
|
+
navigation
|
|
903
|
+
})
|
|
846
904
|
}}
|
|
847
905
|
includeEntityLink={false}
|
|
848
906
|
size={"small"}/>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
|
-
import { canCreateEntity, canDeleteEntity
|
|
3
|
+
import { canCreateEntity, canDeleteEntity } from "../../util";
|
|
4
4
|
import { useAuthController, useCustomizationController, useFireCMSContext, useLargeLayout } from "../../hooks";
|
|
5
5
|
import { CollectionActionsProps, EntityCollection, EntityTableController, SelectionController } from "../../types";
|
|
6
6
|
import { AddIcon, Button, DeleteIcon, IconButton, Tooltip } from "@firecms/ui";
|
|
@@ -124,7 +124,9 @@ export function EntityCollectionViewActions<M extends Record<string, any>>({
|
|
|
124
124
|
|
|
125
125
|
return (
|
|
126
126
|
<>
|
|
127
|
-
|
|
127
|
+
<ErrorBoundary>
|
|
128
|
+
{actions}
|
|
129
|
+
</ErrorBoundary>
|
|
128
130
|
{multipleDeleteButton}
|
|
129
131
|
{addButton}
|
|
130
132
|
</>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React, { useRef } from "react";
|
|
2
|
+
import { Highlight, themes } from "prism-react-renderer";
|
|
3
|
+
import { useModeController } from "../hooks";
|
|
4
|
+
|
|
5
|
+
export function EntityJsonPreview({ values }: { values: object }) {
|
|
6
|
+
const code = JSON.stringify(values, null, "\t");
|
|
7
|
+
const { mode } = useModeController();
|
|
8
|
+
const preRef = useRef<HTMLPreElement>(null);
|
|
9
|
+
|
|
10
|
+
// Global keydown handler
|
|
11
|
+
// const handleGlobalKeyDown = useCallback((e: KeyboardEvent) => {
|
|
12
|
+
// // Check for Control (Windows/Linux) or Command (macOS) + "a":
|
|
13
|
+
// if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a") {
|
|
14
|
+
// // If our code view is mounted, perform selection
|
|
15
|
+
// if (preRef.current) {
|
|
16
|
+
// e.preventDefault();
|
|
17
|
+
// e.stopPropagation();
|
|
18
|
+
//
|
|
19
|
+
// const selection = window.getSelection();
|
|
20
|
+
// const range = document.createRange();
|
|
21
|
+
// range.selectNodeContents(preRef.current);
|
|
22
|
+
// if (selection) {
|
|
23
|
+
// selection.removeAllRanges();
|
|
24
|
+
// selection.addRange(range);
|
|
25
|
+
// }
|
|
26
|
+
// }
|
|
27
|
+
// }
|
|
28
|
+
// }, []);
|
|
29
|
+
|
|
30
|
+
// // Attach the global keydown listener when component mounts,
|
|
31
|
+
// // and remove it when it unmounts.
|
|
32
|
+
// useEffect(() => {
|
|
33
|
+
// document.addEventListener("keydown", handleGlobalKeyDown);
|
|
34
|
+
// return () => {
|
|
35
|
+
// document.removeEventListener("keydown", handleGlobalKeyDown);
|
|
36
|
+
// };
|
|
37
|
+
// }, [handleGlobalKeyDown]);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<Highlight
|
|
41
|
+
theme={mode === "dark" ? themes.vsDark : themes.github}
|
|
42
|
+
code={code}
|
|
43
|
+
language="json"
|
|
44
|
+
>
|
|
45
|
+
{({ style, tokens, getLineProps, getTokenProps }) => (
|
|
46
|
+
<pre
|
|
47
|
+
// Bind the ref to our pre element so we can select its contents.
|
|
48
|
+
ref={preRef}
|
|
49
|
+
style={{
|
|
50
|
+
...style,
|
|
51
|
+
backgroundColor: "inherit"
|
|
52
|
+
}}
|
|
53
|
+
className="max-w-6xl mx-auto p-8 rounded text-sm"
|
|
54
|
+
>
|
|
55
|
+
{tokens.map((line, i) => (
|
|
56
|
+
<div key={i} {...getLineProps({ line })} className="text-wrap">
|
|
57
|
+
{line.map((token, key) => (
|
|
58
|
+
<span key={key} {...getTokenProps({ token })} className="word-break" />
|
|
59
|
+
))}
|
|
60
|
+
</div>
|
|
61
|
+
))}
|
|
62
|
+
</pre>
|
|
63
|
+
)}
|
|
64
|
+
</Highlight>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
@@ -13,7 +13,12 @@ import {
|
|
|
13
13
|
} from "../util";
|
|
14
14
|
import { cls, defaultBorderMixin, IconButton, KeyboardTabIcon, Skeleton, Tooltip, Typography } from "@firecms/ui";
|
|
15
15
|
import { PreviewSize, PropertyPreview, SkeletonPropertyComponent } from "../preview";
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
useAuthController,
|
|
18
|
+
useCustomizationController,
|
|
19
|
+
useNavigationController,
|
|
20
|
+
useSideEntityController
|
|
21
|
+
} from "../hooks";
|
|
17
22
|
import { useAnalyticsController } from "../hooks/useAnalyticsController";
|
|
18
23
|
|
|
19
24
|
export type EntityPreviewProps = {
|
|
@@ -46,6 +51,7 @@ export function EntityPreview({
|
|
|
46
51
|
entity
|
|
47
52
|
}: EntityPreviewProps) {
|
|
48
53
|
|
|
54
|
+
const authController = useAuthController();
|
|
49
55
|
const analyticsController = useAnalyticsController();
|
|
50
56
|
const sideEntityController = useSideEntityController();
|
|
51
57
|
const customizationController = useCustomizationController();
|
|
@@ -62,10 +68,11 @@ export function EntityPreview({
|
|
|
62
68
|
collection,
|
|
63
69
|
path: entity.path,
|
|
64
70
|
values: entity.values,
|
|
65
|
-
propertyConfigs: customizationController.propertyConfigs
|
|
71
|
+
propertyConfigs: customizationController.propertyConfigs,
|
|
72
|
+
authController
|
|
66
73
|
}), [collection]);
|
|
67
74
|
|
|
68
|
-
const listProperties = useMemo(() => getEntityPreviewKeys(resolvedCollection, customizationController.propertyConfigs, previewProperties, size === "medium" || size === "large" ? 3 : 1),
|
|
75
|
+
const listProperties = useMemo(() => getEntityPreviewKeys(authController, resolvedCollection, customizationController.propertyConfigs, previewProperties, size === "medium" || size === "large" ? 3 : 1),
|
|
69
76
|
[previewProperties, resolvedCollection, size]);
|
|
70
77
|
|
|
71
78
|
const titleProperty = getEntityTitlePropertyKey(resolvedCollection, customizationController.propertyConfigs);
|
|
@@ -5,6 +5,7 @@ import { resolveCollection } from "../util";
|
|
|
5
5
|
import { cls, defaultBorderMixin, IconButton, OpenInNewIcon } from "@firecms/ui";
|
|
6
6
|
import { CustomizationController } from "../types/customization_controller";
|
|
7
7
|
import { useCustomizationController } from "../hooks/useCustomizationController";
|
|
8
|
+
import { useAuthController } from "../hooks";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* @group Components
|
|
@@ -24,13 +25,15 @@ export function EntityView<M extends Record<string, any>>(
|
|
|
24
25
|
className
|
|
25
26
|
}: EntityViewProps<M>) {
|
|
26
27
|
|
|
28
|
+
const authController = useAuthController();
|
|
27
29
|
const customizationController: CustomizationController = useCustomizationController();
|
|
28
30
|
const resolvedCollection: ResolvedEntityCollection<M> = useMemo(() => resolveCollection<M>({
|
|
29
31
|
collection,
|
|
30
32
|
path,
|
|
31
33
|
entityId: entity.id,
|
|
32
34
|
values: entity.values,
|
|
33
|
-
propertyConfigs: customizationController.propertyConfigs
|
|
35
|
+
propertyConfigs: customizationController.propertyConfigs,
|
|
36
|
+
authController
|
|
34
37
|
}), [collection, path, entity, customizationController.propertyConfigs]);
|
|
35
38
|
|
|
36
39
|
const properties: ResolvedProperties = resolvedCollection.properties;
|
|
@@ -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>
|