@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.
Files changed (132) hide show
  1. package/README.md +1 -1
  2. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +1 -1
  3. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +2 -2
  4. package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +2 -2
  5. package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +1 -2
  6. package/dist/components/EntityCollectionView/useSelectionController.d.ts +2 -0
  7. package/dist/components/EntityPreview.d.ts +25 -7
  8. package/dist/components/EntityView.d.ts +11 -0
  9. package/dist/components/FieldCaption.d.ts +5 -0
  10. package/dist/components/HomePage/NavigationCard.d.ts +8 -0
  11. package/dist/components/HomePage/{NavigationCollectionCard.d.ts → NavigationCardBinding.d.ts} +2 -2
  12. package/dist/components/HomePage/SmallNavigationCard.d.ts +6 -0
  13. package/dist/components/HomePage/index.d.ts +3 -1
  14. package/dist/components/VirtualTable/VirtualTableProps.d.ts +1 -1
  15. package/dist/components/index.d.ts +4 -2
  16. package/dist/core/{EntityView.d.ts → EntityEditView.d.ts} +2 -2
  17. package/dist/core/SideEntityView.d.ts +2 -2
  18. package/dist/form/EntityForm.d.ts +1 -1
  19. package/dist/form/components/StorageItemPreview.d.ts +3 -2
  20. package/dist/form/components/StorageUploadProgress.d.ts +1 -1
  21. package/dist/form/field_bindings/KeyValueFieldBinding.d.ts +1 -1
  22. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  23. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +4 -3
  24. package/dist/form/field_bindings/TextFieldBinding.d.ts +2 -2
  25. package/dist/form/validation.d.ts +1 -1
  26. package/dist/hooks/data/useDataSource.d.ts +2 -2
  27. package/dist/hooks/useBuildNavigationController.d.ts +5 -2
  28. package/dist/hooks/useProjectLog.d.ts +5 -1
  29. package/dist/hooks/useStorageSource.d.ts +2 -2
  30. package/dist/index.es.js +8333 -8060
  31. package/dist/index.es.js.map +1 -1
  32. package/dist/index.umd.js +5 -5
  33. package/dist/index.umd.js.map +1 -1
  34. package/dist/internal/useRestoreScroll.d.ts +1 -1
  35. package/dist/preview/PropertyPreview.d.ts +1 -1
  36. package/dist/preview/components/BooleanPreview.d.ts +5 -1
  37. package/dist/preview/components/EnumValuesChip.d.ts +1 -1
  38. package/dist/preview/components/ReferencePreview.d.ts +1 -7
  39. package/dist/types/analytics.d.ts +1 -1
  40. package/dist/types/auth.d.ts +13 -1
  41. package/dist/types/collections.d.ts +14 -1
  42. package/dist/types/entity_overrides.d.ts +6 -0
  43. package/dist/types/index.d.ts +2 -0
  44. package/dist/types/navigation.d.ts +10 -9
  45. package/dist/types/permissions.d.ts +5 -1
  46. package/dist/types/plugins.d.ts +15 -17
  47. package/dist/types/properties.d.ts +2 -2
  48. package/dist/types/property_config.d.ts +2 -2
  49. package/dist/types/roles.d.ts +31 -0
  50. package/dist/types/user.d.ts +5 -0
  51. package/dist/util/collections.d.ts +9 -1
  52. package/dist/util/icons.d.ts +8 -2
  53. package/dist/util/permissions.d.ts +4 -4
  54. package/dist/util/references.d.ts +4 -2
  55. package/dist/util/resolutions.d.ts +1 -1
  56. package/package.json +23 -23
  57. package/src/components/DeleteEntityDialog.tsx +4 -4
  58. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +2 -2
  59. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +273 -277
  60. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +1 -1
  61. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +12 -13
  62. package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +8 -15
  63. package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +3 -3
  64. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +1 -1
  65. package/src/components/EntityCollectionTable/internal/default_entity_actions.tsx +9 -5
  66. package/src/components/EntityCollectionView/EntityCollectionView.tsx +28 -49
  67. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +5 -6
  68. package/src/components/EntityCollectionView/useSelectionController.tsx +30 -0
  69. package/src/components/EntityPreview.tsx +204 -70
  70. package/src/components/EntityView.tsx +84 -0
  71. package/src/components/FieldCaption.tsx +14 -0
  72. package/src/components/FireCMSAppBar.tsx +8 -0
  73. package/src/components/HomePage/DefaultHomePage.tsx +13 -9
  74. package/src/components/HomePage/NavigationCard.tsx +69 -0
  75. package/src/components/HomePage/NavigationCardBinding.tsx +116 -0
  76. package/src/components/HomePage/SmallNavigationCard.tsx +45 -0
  77. package/src/components/HomePage/index.tsx +3 -1
  78. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +3 -4
  79. package/src/components/ReferenceWidget.tsx +3 -3
  80. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +11 -19
  81. package/src/components/VirtualTable/VirtualTableProps.tsx +1 -1
  82. package/src/components/common/useDataSourceEntityCollectionTableController.tsx +1 -1
  83. package/src/components/index.tsx +4 -2
  84. package/src/core/Drawer.tsx +66 -39
  85. package/src/core/{EntityView.tsx → EntityEditView.tsx} +20 -37
  86. package/src/core/EntitySidePanel.tsx +2 -2
  87. package/src/core/FireCMS.tsx +18 -2
  88. package/src/core/NavigationRoutes.tsx +8 -0
  89. package/src/core/SideEntityView.tsx +2 -2
  90. package/src/form/EntityForm.tsx +19 -11
  91. package/src/form/components/StorageItemPreview.tsx +5 -3
  92. package/src/form/components/StorageUploadProgress.tsx +6 -5
  93. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +8 -12
  94. package/src/form/field_bindings/KeyValueFieldBinding.tsx +15 -15
  95. package/src/form/field_bindings/MapFieldBinding.tsx +15 -15
  96. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +1 -1
  97. package/src/form/field_bindings/ReferenceFieldBinding.tsx +1 -0
  98. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +14 -5
  99. package/src/form/field_bindings/TextFieldBinding.tsx +7 -5
  100. package/src/form/validation.ts +3 -4
  101. package/src/hooks/data/useCollectionFetch.tsx +1 -1
  102. package/src/hooks/data/useDataSource.tsx +8 -3
  103. package/src/hooks/data/useEntityFetch.tsx +1 -1
  104. package/src/hooks/useBuildNavigationController.tsx +79 -38
  105. package/src/hooks/useProjectLog.tsx +11 -3
  106. package/src/hooks/useReferenceDialog.tsx +2 -2
  107. package/src/hooks/useStorageSource.tsx +7 -2
  108. package/src/preview/PropertyPreview.tsx +1 -1
  109. package/src/preview/components/BooleanPreview.tsx +16 -3
  110. package/src/preview/components/EnumValuesChip.tsx +1 -1
  111. package/src/preview/components/ReferencePreview.tsx +54 -146
  112. package/src/preview/property_previews/StringPropertyPreview.tsx +8 -7
  113. package/src/types/analytics.ts +1 -0
  114. package/src/types/auth.tsx +17 -1
  115. package/src/types/collections.ts +16 -1
  116. package/src/types/entity_actions.tsx +4 -0
  117. package/src/types/entity_overrides.tsx +7 -0
  118. package/src/types/firecms.tsx +0 -1
  119. package/src/types/index.ts +2 -0
  120. package/src/types/navigation.ts +11 -10
  121. package/src/types/permissions.ts +6 -1
  122. package/src/types/plugins.tsx +22 -25
  123. package/src/types/properties.ts +3 -2
  124. package/src/types/property_config.tsx +2 -2
  125. package/src/types/roles.ts +41 -0
  126. package/src/types/side_entity_controller.tsx +1 -0
  127. package/src/types/user.ts +7 -0
  128. package/src/util/collections.ts +22 -0
  129. package/src/util/icons.tsx +11 -3
  130. package/src/util/permissions.ts +11 -8
  131. package/src/util/references.ts +36 -5
  132. 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
+ }
@@ -1,3 +1,5 @@
1
1
  export * from "./DefaultHomePage";
2
- export * from "./NavigationCollectionCard";
2
+ export * from "./NavigationCardBinding";
3
3
  export * from "./NavigationGroup";
4
+ export * from "./NavigationCard";
5
+ export * from "./SmallNavigationCard";
@@ -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/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, fullPathToCollectionSegments(path), null) &&
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
- throw Error(`Couldn't find the corresponding collection for the path: ${path}`);
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.isEntityReference && ref.isEntityReference())) {
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.isEntityReference && newValue.isEntityReference() ? [newValue] : []) : undefined
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
- <div
133
- className="mb-0.5"
134
- onMouseEnter={() => setOnHover(true)}
135
- onMouseMove={() => setOnHover(true)}
136
- onMouseLeave={() => setOnHover(false)}>
137
- <ReferencePreview
138
- disabled={!path}
139
- previewProperties={previewProperties}
140
- size={"medium"}
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 '<', '<=', '==', '>=', '>', 'array-contains', 'in', 'not-in', and 'array-contains-any'.
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;
@@ -1,8 +1,8 @@
1
1
  export type { ErrorViewProps } from "./ErrorView";
2
2
  export { ErrorView } from "./ErrorView";
3
3
 
4
- export type { EntityPreviewProps } from "./EntityPreview";
5
- export { EntityPreview } from "./EntityPreview";
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";
@@ -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 ungroupedNavigationViews = Object.values(navigationEntries).filter(e => !e.group);
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
- <div className={"flex-grow overflow-scroll no-scrollbar"}>
71
-
72
- {groups.map((group) => (
73
- <React.Fragment
74
- key={`drawer_group_${group}`}>
75
- {buildGroupHeader(group)}
76
- {Object.values(navigationEntries)
77
- .filter(e => e.group === group)
78
- .map((view, index) =>
79
- <DrawerNavigationItem
80
- key={`navigation_${index}`}
81
- icon={<IconForView collectionOrView={view.collection ?? view.view}/>}
82
- tooltipsOpen={tooltipsOpen}
83
- drawerOpen={drawerOpen}
84
- onClick={() => onClick(view)}
85
- url={view.url}
86
- name={view.name}/>)}
87
- </React.Fragment>
88
- ))}
89
-
90
- {ungroupedNavigationViews.length > 0 && buildGroupHeader()}
91
-
92
- {ungroupedNavigationViews.map((view, index) => {
93
-
94
- return <DrawerNavigationItem
95
- key={`navigation_${index}`}
96
- icon={<IconForView collectionOrView={view.collection ?? view.view}/>}
97
- tooltipsOpen={tooltipsOpen}
98
- onClick={() => onClick(view)}
99
- drawerOpen={drawerOpen}
100
- url={view.url}
101
- name={view.name}/>;
102
- })}
103
-
104
- </div>
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-gray-100",
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, EntityPreview, ErrorBoundary, } from "../components";
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 EntityViewProps<M extends Record<string, any>> {
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 EntityView<M extends Record<string, any>, UserType extends User>({
60
- path,
61
- entityId,
62
- selectedSubPath,
63
- copy,
64
- collection,
65
- parentCollectionIds,
66
- onValuesAreModified,
67
- formWidth,
68
- onUpdate,
69
- onClose
70
- }: EntityViewProps<M>) {
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, fullPathToCollectionSegments(path), usedEntity ?? null) : false;
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
- <EntityPreview
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 { EntityView } from "./EntityView";
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
- <EntityView
80
+ <EntityEditView
81
81
  {...props}
82
82
  formWidth={props.width}
83
83
  collection={collection}
@@ -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>> = EntityViewProps<M> & {
7
+ export type SideEntityViewProps<M extends Record<string, any>> = EntityEditViewProps<M> & {
8
8
  formWidth?: number | string;
9
9
  onClose?: () => void;
10
10
  }