@firecms/core 3.0.0-canary.7 → 3.0.0-canary.9
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 +1 -1
- package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +1 -1
- package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +2 -2
- package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +2 -2
- package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +1 -2
- package/dist/components/EntityCollectionView/useSelectionController.d.ts +2 -0
- package/dist/components/EntityPreview.d.ts +25 -7
- package/dist/components/EntityView.d.ts +11 -0
- package/dist/components/FieldCaption.d.ts +5 -0
- package/dist/components/HomePage/NavigationCard.d.ts +8 -0
- package/dist/components/HomePage/{NavigationCollectionCard.d.ts → NavigationCardBinding.d.ts} +2 -2
- package/dist/components/HomePage/SmallNavigationCard.d.ts +6 -0
- package/dist/components/HomePage/index.d.ts +3 -1
- package/dist/components/VirtualTable/VirtualTableProps.d.ts +1 -1
- package/dist/components/index.d.ts +4 -2
- package/dist/core/{EntityView.d.ts → EntityEditView.d.ts} +2 -2
- package/dist/core/SideEntityView.d.ts +2 -2
- package/dist/form/EntityForm.d.ts +1 -1
- package/dist/form/components/StorageItemPreview.d.ts +3 -2
- package/dist/form/components/StorageUploadProgress.d.ts +1 -1
- package/dist/form/field_bindings/KeyValueFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +4 -3
- package/dist/form/field_bindings/TextFieldBinding.d.ts +2 -2
- package/dist/form/validation.d.ts +1 -1
- package/dist/hooks/data/useDataSource.d.ts +2 -2
- package/dist/hooks/useBuildNavigationController.d.ts +5 -2
- package/dist/hooks/useProjectLog.d.ts +5 -1
- package/dist/hooks/useStorageSource.d.ts +2 -2
- package/dist/index.es.js +8333 -8060
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +5 -5
- package/dist/index.umd.js.map +1 -1
- package/dist/internal/useRestoreScroll.d.ts +1 -1
- package/dist/preview/PropertyPreview.d.ts +1 -1
- package/dist/preview/components/BooleanPreview.d.ts +5 -1
- package/dist/preview/components/EnumValuesChip.d.ts +1 -1
- package/dist/preview/components/ReferencePreview.d.ts +1 -7
- package/dist/types/analytics.d.ts +1 -1
- package/dist/types/auth.d.ts +13 -1
- package/dist/types/collections.d.ts +14 -1
- package/dist/types/entity_overrides.d.ts +6 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/navigation.d.ts +10 -9
- package/dist/types/permissions.d.ts +5 -1
- package/dist/types/plugins.d.ts +15 -17
- package/dist/types/properties.d.ts +2 -2
- package/dist/types/property_config.d.ts +2 -2
- package/dist/types/roles.d.ts +31 -0
- package/dist/types/user.d.ts +5 -0
- package/dist/util/collections.d.ts +9 -1
- package/dist/util/icons.d.ts +8 -2
- package/dist/util/permissions.d.ts +4 -4
- package/dist/util/references.d.ts +4 -2
- package/dist/util/resolutions.d.ts +1 -1
- package/package.json +23 -23
- package/src/components/DeleteEntityDialog.tsx +4 -4
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +2 -2
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +273 -277
- package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +1 -1
- package/src/components/EntityCollectionTable/PropertyTableCell.tsx +12 -13
- package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +8 -15
- package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +3 -3
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +1 -1
- package/src/components/EntityCollectionTable/internal/default_entity_actions.tsx +9 -5
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +28 -49
- package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +5 -6
- package/src/components/EntityCollectionView/useSelectionController.tsx +30 -0
- package/src/components/EntityPreview.tsx +204 -70
- package/src/components/EntityView.tsx +84 -0
- package/src/components/FieldCaption.tsx +14 -0
- package/src/components/FireCMSAppBar.tsx +8 -0
- package/src/components/HomePage/DefaultHomePage.tsx +13 -9
- package/src/components/HomePage/NavigationCard.tsx +69 -0
- package/src/components/HomePage/NavigationCardBinding.tsx +116 -0
- package/src/components/HomePage/SmallNavigationCard.tsx +45 -0
- package/src/components/HomePage/index.tsx +3 -1
- package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +3 -4
- package/src/components/ReferenceWidget.tsx +3 -3
- package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +11 -19
- package/src/components/VirtualTable/VirtualTableProps.tsx +1 -1
- package/src/components/common/useDataSourceEntityCollectionTableController.tsx +1 -1
- package/src/components/index.tsx +4 -2
- package/src/core/Drawer.tsx +66 -39
- package/src/core/{EntityView.tsx → EntityEditView.tsx} +20 -37
- package/src/core/EntitySidePanel.tsx +2 -2
- package/src/core/FireCMS.tsx +18 -2
- package/src/core/NavigationRoutes.tsx +8 -0
- package/src/core/SideEntityView.tsx +2 -2
- package/src/form/EntityForm.tsx +19 -11
- package/src/form/components/StorageItemPreview.tsx +5 -3
- package/src/form/components/StorageUploadProgress.tsx +6 -5
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +8 -12
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +15 -15
- package/src/form/field_bindings/MapFieldBinding.tsx +15 -15
- package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +1 -1
- package/src/form/field_bindings/ReferenceFieldBinding.tsx +1 -0
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +14 -5
- package/src/form/field_bindings/TextFieldBinding.tsx +7 -5
- package/src/form/validation.ts +3 -4
- package/src/hooks/data/useCollectionFetch.tsx +1 -1
- package/src/hooks/data/useDataSource.tsx +8 -3
- package/src/hooks/data/useEntityFetch.tsx +1 -1
- package/src/hooks/useBuildNavigationController.tsx +79 -38
- package/src/hooks/useProjectLog.tsx +11 -3
- package/src/hooks/useReferenceDialog.tsx +2 -2
- package/src/hooks/useStorageSource.tsx +7 -2
- package/src/preview/PropertyPreview.tsx +1 -1
- package/src/preview/components/BooleanPreview.tsx +16 -3
- package/src/preview/components/EnumValuesChip.tsx +1 -1
- package/src/preview/components/ReferencePreview.tsx +54 -146
- package/src/preview/property_previews/StringPropertyPreview.tsx +8 -7
- package/src/types/analytics.ts +1 -0
- package/src/types/auth.tsx +17 -1
- package/src/types/collections.ts +16 -1
- package/src/types/entity_actions.tsx +4 -0
- package/src/types/entity_overrides.tsx +7 -0
- package/src/types/firecms.tsx +0 -1
- package/src/types/index.ts +2 -0
- package/src/types/navigation.ts +11 -10
- package/src/types/permissions.ts +6 -1
- package/src/types/plugins.tsx +22 -25
- package/src/types/properties.ts +3 -2
- package/src/types/property_config.tsx +2 -2
- package/src/types/roles.ts +41 -0
- package/src/types/side_entity_controller.tsx +1 -0
- package/src/types/user.ts +7 -0
- package/src/util/collections.ts +22 -0
- package/src/util/icons.tsx +11 -3
- package/src/util/permissions.ts +11 -8
- package/src/util/references.ts +36 -5
- package/src/components/HomePage/NavigationCollectionCard.tsx +0 -146
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ArrowForwardIcon, cardClickableMixin, cardMixin, cn, focusedMixin, Typography, } from "@firecms/ui";
|
|
2
|
+
|
|
3
|
+
import { Link as ReactLink } from "react-router-dom";
|
|
4
|
+
|
|
5
|
+
export type SmallNavigationCardProps = {
|
|
6
|
+
name: string,
|
|
7
|
+
url: string;
|
|
8
|
+
icon: React.ReactElement;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export function SmallNavigationCard({
|
|
12
|
+
name,
|
|
13
|
+
url,
|
|
14
|
+
icon,
|
|
15
|
+
}: SmallNavigationCardProps) {
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<>
|
|
19
|
+
|
|
20
|
+
<ReactLink
|
|
21
|
+
tabIndex={0}
|
|
22
|
+
className={cn(cardMixin,
|
|
23
|
+
cardClickableMixin,
|
|
24
|
+
focusedMixin,
|
|
25
|
+
"cursor-pointer flex flex-row items-center px-4 py-2 text-inherit dark:text-inherit visited:text-inherit visited:dark:text-inherit hover:text-inherit hover:dark:text-inherit ")}
|
|
26
|
+
to={url}
|
|
27
|
+
>
|
|
28
|
+
|
|
29
|
+
<div className="flex flex-row items-center flex-grow gap-2 ">
|
|
30
|
+
{icon}
|
|
31
|
+
|
|
32
|
+
<Typography gutterBottom variant="h5"
|
|
33
|
+
component="h2"
|
|
34
|
+
className="mb-0 ml-4">
|
|
35
|
+
{name}
|
|
36
|
+
</Typography>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<div className={"p-4"}>
|
|
40
|
+
<ArrowForwardIcon color="primary"/>
|
|
41
|
+
</div>
|
|
42
|
+
</ReactLink>
|
|
43
|
+
|
|
44
|
+
</>);
|
|
45
|
+
}
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
import { ErrorView } from "../ErrorView";
|
|
18
18
|
import { AddIcon, Button, DialogActions, Typography } from "@firecms/ui";
|
|
19
19
|
import { canCreateEntity, fullPathToCollectionSegments, resolveCollection } from "../../util";
|
|
20
|
-
import { useSelectionController } from "../EntityCollectionView/
|
|
20
|
+
import { useSelectionController } from "../EntityCollectionView/useSelectionController";
|
|
21
21
|
import { useColumnIds, useTableSearchHelper } from "../common";
|
|
22
22
|
import { useSideDialogContext } from "../../core";
|
|
23
23
|
import { useAnalyticsController } from "../../hooks/useAnalyticsController";
|
|
@@ -109,7 +109,7 @@ export function ReferenceSelectionTable<M extends Record<string, any>>(
|
|
|
109
109
|
|
|
110
110
|
const fullPath = navigation.resolveAliasesFrom(pathInput);
|
|
111
111
|
|
|
112
|
-
const dataSource = useDataSource();
|
|
112
|
+
const dataSource = useDataSource(collection);
|
|
113
113
|
|
|
114
114
|
const [entitiesDisplayedFirst, setEntitiesDisplayedFirst] = useState<Entity<any>[]>([]);
|
|
115
115
|
|
|
@@ -349,7 +349,7 @@ function ReferenceDialogActions({
|
|
|
349
349
|
onNewClick();
|
|
350
350
|
}
|
|
351
351
|
: undefined;
|
|
352
|
-
const addButton = canCreateEntity(collection, authController,
|
|
352
|
+
const addButton = canCreateEntity(collection, authController, path, null) &&
|
|
353
353
|
onClick && (largeLayout
|
|
354
354
|
? <Button
|
|
355
355
|
onClick={onClick}
|
|
@@ -360,7 +360,6 @@ function ReferenceDialogActions({
|
|
|
360
360
|
</Button>
|
|
361
361
|
: <Button
|
|
362
362
|
onClick={onClick}
|
|
363
|
-
size="medium"
|
|
364
363
|
variant="outlined"
|
|
365
364
|
color="primary"
|
|
366
365
|
>
|
|
@@ -52,9 +52,9 @@ export function ReferenceWidget<M extends Record<string, any>>({
|
|
|
52
52
|
return navigationController.getCollection(path);
|
|
53
53
|
}, [path, navigationController]);
|
|
54
54
|
|
|
55
|
-
if (!collection) {
|
|
56
|
-
|
|
57
|
-
}
|
|
55
|
+
// if (!collection) {
|
|
56
|
+
// throw Error(`Couldn't find the corresponding collection for the path: ${path}`);
|
|
57
|
+
// }
|
|
58
58
|
|
|
59
59
|
const onSingleEntitySelected = useCallback((entity: Entity<M> | null) => {
|
|
60
60
|
if (disabled)
|
|
@@ -48,8 +48,6 @@ export function ReferenceFilterField({
|
|
|
48
48
|
? ["array-contains"]
|
|
49
49
|
: ["==", "!=", ">", "<", ">=", "<="];
|
|
50
50
|
|
|
51
|
-
const [onHover, setOnHover] = React.useState(false);
|
|
52
|
-
|
|
53
51
|
isArray
|
|
54
52
|
? possibleOperations.push("array-contains-any")
|
|
55
53
|
: possibleOperations.push("in", "not-in");
|
|
@@ -60,7 +58,7 @@ export function ReferenceFilterField({
|
|
|
60
58
|
|
|
61
59
|
const selectedEntityIds = internalValue
|
|
62
60
|
? (Array.isArray(internalValue) ? internalValue.map((ref) => {
|
|
63
|
-
if (!(ref
|
|
61
|
+
if (!(ref?.isEntityReference && ref?.isEntityReference())) {
|
|
64
62
|
return null;
|
|
65
63
|
}
|
|
66
64
|
return ref.id;
|
|
@@ -74,7 +72,7 @@ export function ReferenceFilterField({
|
|
|
74
72
|
let newValue = val;
|
|
75
73
|
if (prevOpIsArray !== newOpIsArray) {
|
|
76
74
|
// @ts-ignore
|
|
77
|
-
newValue = newOpIsArray ? (newValue
|
|
75
|
+
newValue = newOpIsArray ? (newValue?.isEntityReference && newValue?.isEntityReference() ? [newValue] : []) : undefined
|
|
78
76
|
}
|
|
79
77
|
|
|
80
78
|
setOperation(op);
|
|
@@ -129,21 +127,15 @@ export function ReferenceFilterField({
|
|
|
129
127
|
|
|
130
128
|
const buildEntry = (reference: EntityReference) => {
|
|
131
129
|
return (
|
|
132
|
-
<
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
onClick={doOpenDialog}
|
|
142
|
-
reference={reference}
|
|
143
|
-
onHover={onHover}
|
|
144
|
-
allowEntityNavigation={false}
|
|
145
|
-
/>
|
|
146
|
-
</div>
|
|
130
|
+
<ReferencePreview
|
|
131
|
+
disabled={!path}
|
|
132
|
+
previewProperties={previewProperties}
|
|
133
|
+
size={"medium"}
|
|
134
|
+
onClick={doOpenDialog}
|
|
135
|
+
reference={reference}
|
|
136
|
+
hover={true}
|
|
137
|
+
allowEntityNavigation={false}
|
|
138
|
+
/>
|
|
147
139
|
);
|
|
148
140
|
};
|
|
149
141
|
|
|
@@ -252,7 +252,7 @@ export type VirtualTableFilterValues<Key extends string> = Partial<Record<Key, [
|
|
|
252
252
|
|
|
253
253
|
/**
|
|
254
254
|
* Filter conditions in a `Query.where()` clause are specified using the
|
|
255
|
-
* strings
|
|
255
|
+
* strings `<`, `<=`, `==`, `>=`, `>`, `array-contains`, `in`, and `array-contains-any`.
|
|
256
256
|
* @see Table
|
|
257
257
|
* @group Models
|
|
258
258
|
*/
|
|
@@ -65,7 +65,7 @@ export function useDataSourceEntityCollectionTableController<M extends Record<st
|
|
|
65
65
|
|
|
66
66
|
const [popupCell, setPopupCell] = React.useState<SelectedCellProps<M> | undefined>(undefined);
|
|
67
67
|
const navigation = useNavigationController();
|
|
68
|
-
const dataSource = useDataSource();
|
|
68
|
+
const dataSource = useDataSource(collection);
|
|
69
69
|
const resolvedPath = useMemo(() => navigation.resolveAliasesFrom(fullPath), [fullPath, navigation.resolveAliasesFrom]);
|
|
70
70
|
|
|
71
71
|
const forceFilter = forceFilterFromProps ?? forceFilterFromCollection;
|
package/src/components/index.tsx
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export type { ErrorViewProps } from "./ErrorView";
|
|
2
2
|
export { ErrorView } from "./ErrorView";
|
|
3
3
|
|
|
4
|
-
export type {
|
|
5
|
-
export {
|
|
4
|
+
export type { EntityViewProps } from "./EntityView";
|
|
5
|
+
export { EntityView } from "./EntityView";
|
|
6
6
|
|
|
7
7
|
export type { ReferenceSelectionInnerProps } from "./ReferenceTable/ReferenceSelectionTable";
|
|
8
8
|
export { ReferenceSelectionTable } from "./ReferenceTable/ReferenceSelectionTable";
|
|
@@ -15,6 +15,7 @@ export * from "./HomePage";
|
|
|
15
15
|
export * from "./SelectableTable/SelectableTable";
|
|
16
16
|
export * from "./EntityCollectionView/EntityCollectionView";
|
|
17
17
|
export * from "./EntityCollectionView/EntityCollectionViewActions";
|
|
18
|
+
export * from "./EntityCollectionView/useSelectionController";
|
|
18
19
|
|
|
19
20
|
export * from "./PropertyConfigBadge";
|
|
20
21
|
|
|
@@ -32,3 +33,4 @@ export * from "./FireCMSAppBar";
|
|
|
32
33
|
export * from "./ArrayContainer";
|
|
33
34
|
export * from "./ReferenceWidget";
|
|
34
35
|
export * from "./SearchIconsView";
|
|
36
|
+
export * from "./FieldCaption";
|
package/src/core/Drawer.tsx
CHANGED
|
@@ -2,10 +2,10 @@ import React, { useCallback } from "react";
|
|
|
2
2
|
|
|
3
3
|
import { useLargeLayout, useNavigationController } from "../hooks";
|
|
4
4
|
|
|
5
|
-
import { NavLink } from "react-router-dom";
|
|
5
|
+
import { NavLink, useNavigate } from "react-router-dom";
|
|
6
6
|
import { CMSAnalyticsEvent, TopNavigationEntry, TopNavigationResult } from "../types";
|
|
7
7
|
import { IconForView } from "../util";
|
|
8
|
-
import { cn, Tooltip, Typography } from "@firecms/ui";
|
|
8
|
+
import { cn, IconButton, Menu, MenuItem, MoreVertIcon, Tooltip, Typography } from "@firecms/ui";
|
|
9
9
|
import { useAnalyticsController } from "../hooks/useAnalyticsController";
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -33,6 +33,9 @@ export function Drawer({
|
|
|
33
33
|
|
|
34
34
|
const tooltipsOpen = hovered && !drawerOpen;
|
|
35
35
|
const largeLayout = useLargeLayout();
|
|
36
|
+
const navigate = useNavigate();
|
|
37
|
+
|
|
38
|
+
const [adminMenuOpen, setAdminMenuOpen] = React.useState(false);
|
|
36
39
|
|
|
37
40
|
if (!navigation.topLevelNavigation)
|
|
38
41
|
throw Error("Navigation not ready in Drawer");
|
|
@@ -42,7 +45,8 @@ export function Drawer({
|
|
|
42
45
|
groups
|
|
43
46
|
}: TopNavigationResult = navigation.topLevelNavigation;
|
|
44
47
|
|
|
45
|
-
const
|
|
48
|
+
const adminViews = navigationEntries.filter(e => e.type === "admin") ?? [];
|
|
49
|
+
const groupsWithoutAdmin = groups.filter(g => g !== "Admin");
|
|
46
50
|
|
|
47
51
|
const buildGroupHeader = useCallback((group?: string) => {
|
|
48
52
|
if (!drawerOpen) return <div className="h-12 w-full"/>;
|
|
@@ -67,41 +71,64 @@ export function Drawer({
|
|
|
67
71
|
};
|
|
68
72
|
|
|
69
73
|
return (
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
{
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
74
|
+
<>
|
|
75
|
+
|
|
76
|
+
<div className={"flex-grow overflow-scroll no-scrollbar"}>
|
|
77
|
+
|
|
78
|
+
{groupsWithoutAdmin.map((group) => (
|
|
79
|
+
<React.Fragment
|
|
80
|
+
key={`drawer_group_${group}`}>
|
|
81
|
+
{buildGroupHeader(group)}
|
|
82
|
+
{Object.values(navigationEntries)
|
|
83
|
+
.filter(e => e.group === group)
|
|
84
|
+
.map((view, index) =>
|
|
85
|
+
<DrawerNavigationItem
|
|
86
|
+
key={`navigation_${index}`}
|
|
87
|
+
icon={<IconForView collectionOrView={view.collection ?? view.view}/>}
|
|
88
|
+
tooltipsOpen={tooltipsOpen}
|
|
89
|
+
drawerOpen={drawerOpen}
|
|
90
|
+
onClick={() => onClick(view)}
|
|
91
|
+
url={view.url}
|
|
92
|
+
name={view.name}/>)}
|
|
93
|
+
</React.Fragment>
|
|
94
|
+
))}
|
|
95
|
+
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
{adminViews.length > 0 && <Menu
|
|
99
|
+
open={adminMenuOpen}
|
|
100
|
+
onOpenChange={setAdminMenuOpen}
|
|
101
|
+
trigger={
|
|
102
|
+
<IconButton
|
|
103
|
+
shape={"square"}
|
|
104
|
+
className={"m-4 text-gray-900 dark:text-white w-fit"}>
|
|
105
|
+
<Tooltip title={"Admin"}
|
|
106
|
+
open={tooltipsOpen}
|
|
107
|
+
side={"right"} sideOffset={28}>
|
|
108
|
+
<MoreVertIcon/>
|
|
109
|
+
</Tooltip>
|
|
110
|
+
{drawerOpen && <div
|
|
111
|
+
className={cn(
|
|
112
|
+
drawerOpen ? "opacity-100" : "opacity-0 hidden",
|
|
113
|
+
"mx-4 font-inherit text-inherit"
|
|
114
|
+
)}>
|
|
115
|
+
ADMIN
|
|
116
|
+
</div>}
|
|
117
|
+
</IconButton>}
|
|
118
|
+
>
|
|
119
|
+
{adminViews.map((entry, index) =>
|
|
120
|
+
<MenuItem
|
|
121
|
+
onClick={(event) => {
|
|
122
|
+
event.preventDefault();
|
|
123
|
+
navigate(entry.path);
|
|
124
|
+
}}
|
|
125
|
+
key={`navigation_${index}`}>
|
|
126
|
+
{<IconForView collectionOrView={entry.view}/>}
|
|
127
|
+
{entry.name}
|
|
128
|
+
</MenuItem>)}
|
|
129
|
+
|
|
130
|
+
</Menu>}
|
|
131
|
+
</>
|
|
105
132
|
);
|
|
106
133
|
}
|
|
107
134
|
|
|
@@ -133,7 +160,7 @@ export function DrawerNavigationItem({
|
|
|
133
160
|
transition: drawerOpen ? "width 150ms ease-in" : undefined
|
|
134
161
|
}}
|
|
135
162
|
className={({ isActive }: any) => cn("rounded-r-xl truncate",
|
|
136
|
-
"hover:bg-slate-300 hover:bg-opacity-75 dark:hover:bg-gray-700 dark:hover:bg-opacity-75 text-gray-800 dark:text-gray-200 hover:text-gray-900 hover:dark:text-
|
|
163
|
+
"hover:bg-slate-300 hover:bg-opacity-75 dark:hover:bg-gray-700 dark:hover:bg-opacity-75 text-gray-800 dark:text-gray-200 hover:text-gray-900 hover:dark:text-white",
|
|
137
164
|
"flex flex-row items-center mr-8",
|
|
138
165
|
// "transition-all ease-in-out delay-100 duration-300",
|
|
139
166
|
// drawerOpen ? "w-full" : "w-18",
|
|
@@ -9,10 +9,9 @@ import {
|
|
|
9
9
|
FormContext,
|
|
10
10
|
User
|
|
11
11
|
} from "../types";
|
|
12
|
-
import { CircularProgressCenter, EntityCollectionView,
|
|
12
|
+
import { CircularProgressCenter, EntityCollectionView, EntityView, ErrorBoundary, } from "../components";
|
|
13
13
|
import {
|
|
14
14
|
canEditEntity,
|
|
15
|
-
fullPathToCollectionSegments,
|
|
16
15
|
removeInitialAndTrailingSlashes,
|
|
17
16
|
resolveDefaultSelectedView,
|
|
18
17
|
resolveEntityView,
|
|
@@ -37,7 +36,7 @@ import { useSideDialogContext } from "./index";
|
|
|
37
36
|
|
|
38
37
|
const MAIN_TAB_VALUE = "main_##Q$SC^#S6";
|
|
39
38
|
|
|
40
|
-
export interface
|
|
39
|
+
export interface EntityEditViewProps<M extends Record<string, any>> {
|
|
41
40
|
path: string;
|
|
42
41
|
collection: EntityCollection<M>;
|
|
43
42
|
entityId?: string;
|
|
@@ -56,18 +55,18 @@ export interface EntityViewProps<M extends Record<string, any>> {
|
|
|
56
55
|
* You probably don't want to use this view directly since it is bound to the
|
|
57
56
|
* side panel. Instead, you might want to use {@link EntityForm} or {@link EntityCollectionView}
|
|
58
57
|
*/
|
|
59
|
-
export function
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
58
|
+
export function EntityEditView<M extends Record<string, any>, UserType extends User>({
|
|
59
|
+
path,
|
|
60
|
+
entityId,
|
|
61
|
+
selectedSubPath,
|
|
62
|
+
copy,
|
|
63
|
+
collection,
|
|
64
|
+
parentCollectionIds,
|
|
65
|
+
onValuesAreModified,
|
|
66
|
+
formWidth,
|
|
67
|
+
onUpdate,
|
|
68
|
+
onClose,
|
|
69
|
+
}: EntityEditViewProps<M>) {
|
|
71
70
|
|
|
72
71
|
if (collection.customId && collection.formAutoSave) {
|
|
73
72
|
console.warn(`The collection ${collection.path} has customId and formAutoSave enabled. This is not supported and formAutoSave will be ignored`);
|
|
@@ -95,7 +94,7 @@ export function EntityView<M extends Record<string, any>, UserType extends User>
|
|
|
95
94
|
|
|
96
95
|
const resolvedFormWidth: string = typeof formWidth === "number" ? `${formWidth}px` : formWidth ?? FORM_CONTAINER_WIDTH;
|
|
97
96
|
|
|
98
|
-
const dataSource = useDataSource();
|
|
97
|
+
const dataSource = useDataSource(collection);
|
|
99
98
|
const sideDialogContext = useSideDialogContext();
|
|
100
99
|
const sideEntityController = useSideEntityController();
|
|
101
100
|
const snackbarController = useSnackbarController();
|
|
@@ -154,29 +153,12 @@ export function EntityView<M extends Record<string, any>, UserType extends User>
|
|
|
154
153
|
if (status === "new") {
|
|
155
154
|
setReadOnly(false);
|
|
156
155
|
} else {
|
|
157
|
-
const editEnabled = usedEntity ? canEditEntity(collection, authController,
|
|
156
|
+
const editEnabled = usedEntity ? canEditEntity(collection, authController, path, usedEntity ?? null) : false;
|
|
158
157
|
if (usedEntity)
|
|
159
158
|
setReadOnly(!editEnabled);
|
|
160
159
|
}
|
|
161
160
|
}, [authController, usedEntity, status]);
|
|
162
161
|
|
|
163
|
-
// useEffect(() => {
|
|
164
|
-
// if (largeLayoutTabSelected.current === largeLayout)
|
|
165
|
-
// return;
|
|
166
|
-
// // open first tab by default in large layouts
|
|
167
|
-
// if (selectedSubPath !== defaultSelectedView) {
|
|
168
|
-
// console.log("Replacing url 1", defaultSelectedView);
|
|
169
|
-
// sideEntityController.replace({
|
|
170
|
-
// path,
|
|
171
|
-
// entityId,
|
|
172
|
-
// selectedSubPath: defaultSelectedView,
|
|
173
|
-
// updateUrl: true,
|
|
174
|
-
// collection
|
|
175
|
-
// });
|
|
176
|
-
// }
|
|
177
|
-
// largeLayoutTabSelected.current = largeLayout;
|
|
178
|
-
// }, [defaultSelectedView, largeLayout, selectedSubPath]);
|
|
179
|
-
|
|
180
162
|
const onPreSaveHookError = useCallback((e: Error) => {
|
|
181
163
|
setSaving(false);
|
|
182
164
|
snackbarController.open({
|
|
@@ -222,7 +204,7 @@ export function EntityView<M extends Record<string, any>, UserType extends User>
|
|
|
222
204
|
entityId: updatedEntity.id,
|
|
223
205
|
selectedSubPath: selectedTabRef.current,
|
|
224
206
|
updateUrl: true,
|
|
225
|
-
collection
|
|
207
|
+
collection,
|
|
226
208
|
});
|
|
227
209
|
}
|
|
228
210
|
|
|
@@ -302,6 +284,7 @@ export function EntityView<M extends Record<string, any>, UserType extends User>
|
|
|
302
284
|
.map(e => resolveEntityView(e, customizationController.entityViews))
|
|
303
285
|
.filter(Boolean) as EntityCustomView[]
|
|
304
286
|
: [];
|
|
287
|
+
|
|
305
288
|
const customViewsView: React.ReactNode[] | undefined = customViews && resolvedEntityViews
|
|
306
289
|
.map(
|
|
307
290
|
(customView, colIndex) => {
|
|
@@ -382,7 +365,7 @@ export function EntityView<M extends Record<string, any>, UserType extends User>
|
|
|
382
365
|
entityId,
|
|
383
366
|
selectedSubPath: value === MAIN_TAB_VALUE ? undefined : value,
|
|
384
367
|
updateUrl: true,
|
|
385
|
-
collection
|
|
368
|
+
collection,
|
|
386
369
|
});
|
|
387
370
|
};
|
|
388
371
|
|
|
@@ -463,7 +446,7 @@ export function EntityView<M extends Record<string, any>, UserType extends User>
|
|
|
463
446
|
className={"mt-16 mb-8 mx-8"}
|
|
464
447
|
variant={"h4"}>{collection.singularName ?? collection.name}
|
|
465
448
|
</Typography>
|
|
466
|
-
<
|
|
449
|
+
<EntityView
|
|
467
450
|
className={"px-12"}
|
|
468
451
|
entity={usedEntity as Entity<M>}
|
|
469
452
|
path={path}
|
|
@@ -4,7 +4,7 @@ import { EntitySidePanelProps } from "../types";
|
|
|
4
4
|
import { useNavigationController } from "../hooks";
|
|
5
5
|
|
|
6
6
|
import { ErrorBoundary } from "../components";
|
|
7
|
-
import {
|
|
7
|
+
import { EntityEditView } from "./EntityEditView";
|
|
8
8
|
import { useSideDialogContext } from "./SideDialogs";
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -77,7 +77,7 @@ export function EntitySidePanel(props: EntitySidePanelProps) {
|
|
|
77
77
|
return (
|
|
78
78
|
<>
|
|
79
79
|
<ErrorBoundary>
|
|
80
|
-
<
|
|
80
|
+
<EntityEditView
|
|
81
81
|
{...props}
|
|
82
82
|
formWidth={props.width}
|
|
83
83
|
collection={collection}
|
package/src/core/FireCMS.tsx
CHANGED
|
@@ -13,7 +13,7 @@ import { SideEntityControllerContext } from "../contexts/SideEntityControllerCon
|
|
|
13
13
|
import { NavigationContext } from "../contexts/NavigationContext";
|
|
14
14
|
import { SideDialogsControllerContext } from "../contexts/SideDialogsControllerContext";
|
|
15
15
|
import { useLocaleConfig } from "../internal/useLocaleConfig";
|
|
16
|
-
import { CenteredView } from "@firecms/ui";
|
|
16
|
+
import { CenteredView, Typography } from "@firecms/ui";
|
|
17
17
|
import { DialogsProvider } from "../contexts/DialogsProvider";
|
|
18
18
|
import { useBuildDataSource } from "../internal/useBuildDataSource";
|
|
19
19
|
import { useBuildCustomizationController } from "../internal/useBuildCustomizationController";
|
|
@@ -85,7 +85,7 @@ export function FireCMS<UserType extends User, EC extends EntityCollection>(prop
|
|
|
85
85
|
onAnalyticsEvent
|
|
86
86
|
}), []);
|
|
87
87
|
|
|
88
|
-
useProjectLog(authController);
|
|
88
|
+
const accessResponse = useProjectLog(authController);
|
|
89
89
|
|
|
90
90
|
if (navigationController.navigationLoadingError) {
|
|
91
91
|
return (
|
|
@@ -107,6 +107,22 @@ export function FireCMS<UserType extends User, EC extends EntityCollection>(prop
|
|
|
107
107
|
);
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
if (accessResponse?.blocked) {
|
|
111
|
+
return (
|
|
112
|
+
<CenteredView maxWidth={"md"} fullScreen={true}>
|
|
113
|
+
<Typography variant={"h4"}>
|
|
114
|
+
Access blocked
|
|
115
|
+
</Typography>
|
|
116
|
+
<Typography>
|
|
117
|
+
This app has been blocked. Please reach out at <a
|
|
118
|
+
href={"mailto:hello@firecms.co"}>hello@firecms.co</a> for more information.
|
|
119
|
+
</Typography>
|
|
120
|
+
{accessResponse?.message &&
|
|
121
|
+
<Typography>Response from the server: {accessResponse?.message}</Typography>}
|
|
122
|
+
</CenteredView>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
110
126
|
return (
|
|
111
127
|
<ModeControllerContext.Provider value={modeController}>
|
|
112
128
|
<AnalyticsContext.Provider value={analyticsController}>
|
|
@@ -59,6 +59,14 @@ export const NavigationRoutes = React.memo<NavigationRoutesProps>(
|
|
|
59
59
|
cmsViews.push(buildCMSViewRoute(cmsView.path, cmsView));
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
|
+
if (navigation.adminViews) {
|
|
63
|
+
navigation.adminViews.forEach((cmsView) => {
|
|
64
|
+
if (Array.isArray(cmsView.path))
|
|
65
|
+
cmsViews.push(...cmsView.path.map(path => buildCMSViewRoute(path, cmsView)));
|
|
66
|
+
else
|
|
67
|
+
cmsViews.push(buildCMSViewRoute(cmsView.path, cmsView));
|
|
68
|
+
});
|
|
69
|
+
}
|
|
62
70
|
|
|
63
71
|
// we reorder collections so that nested paths are included first
|
|
64
72
|
const sortedCollections = [...(navigation.collections ?? [])]
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { EntityViewProps } from "./EntityView";
|
|
2
1
|
import { User } from "../types";
|
|
3
2
|
import { useSideDialogContext } from "./SideDialogs";
|
|
4
3
|
import { useSideEntityController } from "../hooks";
|
|
5
4
|
import { FORM_CONTAINER_WIDTH } from "../internal/common";
|
|
5
|
+
import { EntityEditViewProps } from "./EntityEditView";
|
|
6
6
|
|
|
7
|
-
export type SideEntityViewProps<M extends Record<string, any>> =
|
|
7
|
+
export type SideEntityViewProps<M extends Record<string, any>> = EntityEditViewProps<M> & {
|
|
8
8
|
formWidth?: number | string;
|
|
9
9
|
onClose?: () => void;
|
|
10
10
|
}
|