@firecms/core 3.0.0-canary.6 → 3.0.0-canary.61

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 (242) hide show
  1. package/README.md +2 -2
  2. package/dist/components/ClearFilterSortButton.d.ts +5 -0
  3. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +11 -11
  4. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +2 -2
  5. package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +5 -3
  6. package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +3 -2
  7. package/dist/components/EntityCollectionTable/column_utils.d.ts +1 -2
  8. package/dist/components/EntityCollectionTable/fields/TableReferenceField.d.ts +2 -0
  9. package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +1 -4
  10. package/dist/components/EntityCollectionTable/internal/EntityTableCell.d.ts +2 -2
  11. package/dist/components/EntityCollectionTable/internal/popup_field/PopupFormField.d.ts +1 -1
  12. package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +12 -3
  13. package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +11 -0
  14. package/dist/components/EntityCollectionView/useSelectionController.d.ts +2 -0
  15. package/dist/components/EntityPreview.d.ts +26 -7
  16. package/dist/components/EntityView.d.ts +11 -0
  17. package/dist/components/FieldCaption.d.ts +5 -0
  18. package/dist/components/FireCMSAppBar.d.ts +4 -2
  19. package/dist/components/HomePage/NavigationCard.d.ts +8 -0
  20. package/dist/components/HomePage/{NavigationCollectionCard.d.ts → NavigationCardBinding.d.ts} +2 -2
  21. package/dist/components/HomePage/SmallNavigationCard.d.ts +6 -0
  22. package/dist/components/HomePage/index.d.ts +3 -1
  23. package/dist/components/ReferenceWidget.d.ts +3 -1
  24. package/dist/components/SelectableTable/SelectableTable.d.ts +1 -1
  25. package/dist/components/SelectableTable/filters/ReferenceFilterField.d.ts +2 -1
  26. package/dist/components/VirtualTable/VirtualTableProps.d.ts +6 -7
  27. package/dist/components/VirtualTable/types.d.ts +3 -3
  28. package/dist/components/{EntityCollectionTable/internal → common}/default_entity_actions.d.ts +1 -1
  29. package/dist/components/common/index.d.ts +1 -0
  30. package/dist/components/common/table_height.d.ts +5 -0
  31. package/dist/components/common/types.d.ts +4 -6
  32. package/dist/components/common/useDataSourceEntityCollectionTableController.d.ts +3 -0
  33. package/dist/components/index.d.ts +5 -2
  34. package/dist/contexts/AuthControllerContext.d.ts +1 -1
  35. package/dist/core/Drawer.d.ts +5 -12
  36. package/dist/core/DrawerNavigationItem.d.ts +9 -0
  37. package/dist/core/{EntityView.d.ts → EntityEditView.d.ts} +2 -2
  38. package/dist/core/NavigationRoutes.d.ts +1 -1
  39. package/dist/core/Scaffold.d.ts +8 -12
  40. package/dist/core/index.d.ts +3 -4
  41. package/dist/form/EntityForm.d.ts +1 -1
  42. package/dist/form/components/ErrorFocus.d.ts +1 -1
  43. package/dist/form/components/StorageItemPreview.d.ts +3 -2
  44. package/dist/form/components/StorageUploadProgress.d.ts +1 -1
  45. package/dist/form/field_bindings/KeyValueFieldBinding.d.ts +1 -1
  46. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  47. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +4 -3
  48. package/dist/form/field_bindings/TextFieldBinding.d.ts +2 -2
  49. package/dist/form/validation.d.ts +1 -1
  50. package/dist/hooks/data/delete.d.ts +2 -2
  51. package/dist/hooks/data/save.d.ts +2 -3
  52. package/dist/hooks/data/useDataSource.d.ts +2 -2
  53. package/dist/hooks/data/useEntityFetch.d.ts +3 -3
  54. package/dist/hooks/index.d.ts +2 -0
  55. package/dist/hooks/useBuildNavigationController.d.ts +6 -4
  56. package/dist/hooks/useProjectLog.d.ts +6 -2
  57. package/dist/hooks/useStorageSource.d.ts +2 -2
  58. package/dist/hooks/useValidateAuthenticator.d.ts +21 -0
  59. package/dist/index.es.js +10498 -9944
  60. package/dist/index.es.js.map +1 -1
  61. package/dist/index.umd.js +5 -5
  62. package/dist/index.umd.js.map +1 -1
  63. package/dist/internal/useBuildDataSource.d.ts +1 -16
  64. package/dist/preview/PropertyPreview.d.ts +1 -1
  65. package/dist/preview/PropertyPreviewProps.d.ts +1 -4
  66. package/dist/preview/components/BooleanPreview.d.ts +5 -1
  67. package/dist/preview/components/EnumValuesChip.d.ts +1 -1
  68. package/dist/preview/components/ReferencePreview.d.ts +3 -8
  69. package/dist/types/analytics.d.ts +1 -1
  70. package/dist/types/auth.d.ts +37 -1
  71. package/dist/types/collections.d.ts +30 -6
  72. package/dist/types/datasource.d.ts +21 -14
  73. package/dist/types/entities.d.ts +5 -1
  74. package/dist/types/entity_actions.d.ts +14 -0
  75. package/dist/types/entity_callbacks.d.ts +2 -2
  76. package/dist/types/entity_overrides.d.ts +6 -0
  77. package/dist/types/index.d.ts +2 -1
  78. package/dist/types/navigation.d.ts +15 -14
  79. package/dist/types/permissions.d.ts +5 -1
  80. package/dist/types/plugins.d.ts +20 -20
  81. package/dist/types/properties.d.ts +12 -4
  82. package/dist/types/property_config.d.ts +2 -2
  83. package/dist/types/roles.d.ts +31 -0
  84. package/dist/types/storage.d.ts +11 -3
  85. package/dist/types/user.d.ts +5 -0
  86. package/dist/util/collections.d.ts +9 -1
  87. package/dist/util/entities.d.ts +1 -1
  88. package/dist/util/icon_synonyms.d.ts +1 -97
  89. package/dist/util/icons.d.ts +8 -2
  90. package/dist/util/navigation_utils.d.ts +2 -2
  91. package/dist/util/objects.d.ts +1 -1
  92. package/dist/util/permissions.d.ts +4 -4
  93. package/dist/util/references.d.ts +4 -2
  94. package/dist/util/resolutions.d.ts +14 -14
  95. package/dist/util/useTraceUpdate.d.ts +1 -0
  96. package/package.json +139 -119
  97. package/src/components/ClearFilterSortButton.tsx +41 -0
  98. package/src/components/DeleteEntityDialog.tsx +4 -4
  99. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +4 -4
  100. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +276 -279
  101. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +9 -5
  102. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +48 -45
  103. package/src/components/EntityCollectionTable/column_utils.tsx +3 -3
  104. package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +18 -17
  105. package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +5 -5
  106. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +29 -34
  107. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +16 -12
  108. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +2 -4
  109. package/src/components/EntityCollectionView/EntityCollectionView.tsx +73 -72
  110. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +5 -6
  111. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +68 -0
  112. package/src/components/EntityCollectionView/useSelectionController.tsx +30 -0
  113. package/src/components/EntityPreview.tsx +209 -70
  114. package/src/components/EntityView.tsx +84 -0
  115. package/src/components/FieldCaption.tsx +14 -0
  116. package/src/components/FireCMSAppBar.tsx +40 -15
  117. package/src/components/HomePage/DefaultHomePage.tsx +15 -11
  118. package/src/components/HomePage/NavigationCard.tsx +69 -0
  119. package/src/components/HomePage/NavigationCardBinding.tsx +116 -0
  120. package/src/components/HomePage/SmallNavigationCard.tsx +45 -0
  121. package/src/components/HomePage/index.tsx +3 -1
  122. package/src/components/PropertyIdCopyTooltipContent.tsx +2 -3
  123. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +4 -4
  124. package/src/components/ReferenceWidget.tsx +22 -12
  125. package/src/components/SearchIconsView.tsx +5 -5
  126. package/src/components/SelectableTable/SelectableTable.tsx +5 -3
  127. package/src/components/SelectableTable/filters/BooleanFilterField.tsx +2 -3
  128. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +23 -8
  129. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +38 -24
  130. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +35 -15
  131. package/src/components/VirtualTable/VirtualTable.tsx +38 -29
  132. package/src/components/VirtualTable/VirtualTableHeader.tsx +4 -4
  133. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +2 -2
  134. package/src/components/VirtualTable/VirtualTableProps.tsx +7 -7
  135. package/src/components/VirtualTable/VirtualTableRow.tsx +4 -5
  136. package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +1 -1
  137. package/src/components/VirtualTable/types.tsx +2 -3
  138. package/src/components/{EntityCollectionTable/internal → common}/default_entity_actions.tsx +11 -7
  139. package/src/components/common/index.ts +1 -0
  140. package/src/components/{VirtualTable/common.tsx → common/table_height.tsx} +5 -2
  141. package/src/components/common/types.tsx +4 -6
  142. package/src/components/common/useColumnsIds.tsx +10 -2
  143. package/src/components/common/useDataSourceEntityCollectionTableController.tsx +12 -1
  144. package/src/components/common/useTableSearchHelper.ts +39 -9
  145. package/src/components/index.tsx +5 -2
  146. package/src/contexts/AuthControllerContext.tsx +1 -1
  147. package/src/core/Drawer.tsx +78 -103
  148. package/src/core/DrawerNavigationItem.tsx +62 -0
  149. package/src/core/{EntityView.tsx → EntityEditView.tsx} +27 -45
  150. package/src/core/EntitySidePanel.tsx +3 -3
  151. package/src/core/FireCMS.tsx +54 -43
  152. package/src/core/NavigationRoutes.tsx +11 -4
  153. package/src/core/Scaffold.tsx +80 -66
  154. package/src/core/field_configs.tsx +2 -3
  155. package/src/core/index.tsx +3 -4
  156. package/src/form/EntityForm.tsx +42 -27
  157. package/src/form/PropertyFieldBinding.tsx +0 -2
  158. package/src/form/components/StorageItemPreview.tsx +7 -5
  159. package/src/form/components/StorageUploadProgress.tsx +9 -8
  160. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +10 -12
  161. package/src/form/field_bindings/BlockFieldBinding.tsx +2 -2
  162. package/src/form/field_bindings/DateTimeFieldBinding.tsx +1 -1
  163. package/src/form/field_bindings/KeyValueFieldBinding.tsx +19 -19
  164. package/src/form/field_bindings/MapFieldBinding.tsx +15 -15
  165. package/src/form/field_bindings/MarkdownFieldBinding.tsx +2 -2
  166. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +3 -3
  167. package/src/form/field_bindings/ReferenceFieldBinding.tsx +16 -13
  168. package/src/form/field_bindings/SelectFieldBinding.tsx +3 -3
  169. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +18 -9
  170. package/src/form/field_bindings/TextFieldBinding.tsx +7 -5
  171. package/src/form/validation.ts +3 -4
  172. package/src/hooks/data/delete.ts +3 -3
  173. package/src/hooks/data/save.ts +4 -2
  174. package/src/hooks/data/useCollectionFetch.tsx +1 -1
  175. package/src/hooks/data/useDataSource.tsx +8 -3
  176. package/src/hooks/data/useEntityFetch.tsx +4 -4
  177. package/src/hooks/index.tsx +3 -0
  178. package/src/hooks/useBuildLocalConfigurationPersistence.tsx +8 -10
  179. package/src/hooks/useBuildModeController.tsx +11 -5
  180. package/src/hooks/useBuildNavigationController.tsx +200 -83
  181. package/src/hooks/useProjectLog.tsx +17 -7
  182. package/src/hooks/useReferenceDialog.tsx +2 -2
  183. package/src/hooks/useResolvedNavigationFrom.tsx +1 -1
  184. package/src/hooks/useStorageSource.tsx +7 -2
  185. package/src/hooks/useValidateAuthenticator.tsx +115 -0
  186. package/src/internal/useBuildDataSource.ts +54 -47
  187. package/src/internal/useBuildSideEntityController.tsx +88 -21
  188. package/src/preview/PropertyPreview.tsx +5 -15
  189. package/src/preview/PropertyPreviewProps.tsx +1 -11
  190. package/src/preview/components/BooleanPreview.tsx +19 -4
  191. package/src/preview/components/EnumValuesChip.tsx +2 -2
  192. package/src/preview/components/ReferencePreview.tsx +72 -165
  193. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +0 -1
  194. package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +2 -1
  195. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +0 -1
  196. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +0 -1
  197. package/src/preview/property_previews/ArrayOneOfPreview.tsx +2 -3
  198. package/src/preview/property_previews/ArrayPropertyPreview.tsx +2 -3
  199. package/src/preview/property_previews/MapPropertyPreview.tsx +5 -5
  200. package/src/preview/property_previews/StringPropertyPreview.tsx +8 -7
  201. package/src/types/analytics.ts +1 -0
  202. package/src/types/auth.tsx +50 -1
  203. package/src/types/collections.ts +37 -6
  204. package/src/types/datasource.ts +24 -17
  205. package/src/types/entities.ts +9 -1
  206. package/src/types/entity_actions.tsx +17 -0
  207. package/src/types/entity_callbacks.ts +2 -2
  208. package/src/types/entity_overrides.tsx +7 -0
  209. package/src/types/firecms.tsx +0 -1
  210. package/src/types/index.ts +2 -1
  211. package/src/types/navigation.ts +17 -17
  212. package/src/types/permissions.ts +6 -1
  213. package/src/types/plugins.tsx +26 -28
  214. package/src/types/properties.ts +18 -6
  215. package/src/types/property_config.tsx +2 -2
  216. package/src/types/roles.ts +41 -0
  217. package/src/types/side_entity_controller.tsx +1 -0
  218. package/src/types/storage.ts +12 -3
  219. package/src/types/user.ts +7 -0
  220. package/src/util/collections.ts +22 -0
  221. package/src/util/entities.ts +1 -1
  222. package/src/util/enums.ts +1 -1
  223. package/src/util/icon_list.ts +2 -2
  224. package/src/util/icon_synonyms.ts +3 -99
  225. package/src/util/icons.tsx +11 -3
  226. package/src/util/navigation_utils.ts +6 -6
  227. package/src/util/objects.ts +8 -21
  228. package/src/util/permissions.ts +11 -8
  229. package/src/util/references.ts +36 -5
  230. package/src/util/resolutions.ts +32 -31
  231. package/src/util/strings.ts +2 -2
  232. package/src/util/useTraceUpdate.tsx +2 -1
  233. package/dist/components/VirtualTable/common.d.ts +0 -2
  234. package/dist/core/SideEntityView.d.ts +0 -7
  235. package/dist/internal/useBuildCustomizationController.d.ts +0 -2
  236. package/dist/internal/useLocaleConfig.d.ts +0 -1
  237. package/dist/types/appcheck.d.ts +0 -26
  238. package/src/components/HomePage/NavigationCollectionCard.tsx +0 -146
  239. package/src/core/SideEntityView.tsx +0 -38
  240. package/src/internal/useBuildCustomizationController.tsx +0 -5
  241. package/src/internal/useLocaleConfig.tsx +0 -18
  242. package/src/types/appcheck.ts +0 -29
@@ -1,9 +1,9 @@
1
1
  import React, { useMemo } from "react";
2
2
 
3
- import { EntityCollection, FireCMSContext, FireCMSPlugin, FireCMSProps, User } from "../types";
4
- import { AuthControllerContext, ModeControllerContext } from "../contexts";
3
+ import { CustomizationController, EntityCollection, FireCMSContext, FireCMSPlugin, FireCMSProps, User } from "../types";
4
+ import { AuthControllerContext } from "../contexts";
5
5
  import { useBuildSideEntityController } from "../internal/useBuildSideEntityController";
6
- import { useCustomizationController, useFireCMSContext, useModeController } from "../hooks";
6
+ import { useCustomizationController, useFireCMSContext } from "../hooks";
7
7
  import { useBuildSideDialogsController } from "../internal/useBuildSideDialogsController";
8
8
  import { ErrorView } from "../components";
9
9
  import { StorageSourceContext } from "../contexts/StorageSourceContext";
@@ -12,11 +12,9 @@ import { DataSourceContext } from "../contexts/DataSourceContext";
12
12
  import { SideEntityControllerContext } from "../contexts/SideEntityControllerContext";
13
13
  import { NavigationContext } from "../contexts/NavigationContext";
14
14
  import { SideDialogsControllerContext } from "../contexts/SideDialogsControllerContext";
15
- import { useLocaleConfig } from "../internal/useLocaleConfig";
16
- import { CenteredView } from "@firecms/ui";
15
+ import { CenteredView, Typography, useLocaleConfig } from "@firecms/ui";
17
16
  import { DialogsProvider } from "../contexts/DialogsProvider";
18
17
  import { useBuildDataSource } from "../internal/useBuildDataSource";
19
- import { useBuildCustomizationController } from "../internal/useBuildCustomizationController";
20
18
  import { CustomizationControllerContext } from "../contexts/CustomizationControllerContext";
21
19
  import { AnalyticsContext } from "../contexts/AnalyticsContext";
22
20
  import { useProjectLog } from "../hooks/useProjectLog";
@@ -35,7 +33,6 @@ import { useProjectLog } from "../hooks/useProjectLog";
35
33
  */
36
34
  export function FireCMS<UserType extends User, EC extends EntityCollection>(props: FireCMSProps<UserType, EC>) {
37
35
 
38
- const modeController = useModeController();
39
36
  const {
40
37
  children,
41
38
  entityLinkBuilder,
@@ -71,7 +68,7 @@ export function FireCMS<UserType extends User, EC extends EntityCollection>(prop
71
68
 
72
69
  const loading = authController.initialLoading || navigationController.loading || pluginsLoading;
73
70
 
74
- const customizationController = useBuildCustomizationController({
71
+ const customizationController: CustomizationController = {
75
72
  dateTimeFormat,
76
73
  locale,
77
74
  entityLinkBuilder,
@@ -79,13 +76,13 @@ export function FireCMS<UserType extends User, EC extends EntityCollection>(prop
79
76
  entityViews: entityViews ?? [],
80
77
  propertyConfigs: propertyConfigs ?? {},
81
78
  components
82
- });
79
+ };
83
80
 
84
81
  const analyticsController = useMemo(() => ({
85
82
  onAnalyticsEvent
86
83
  }), []);
87
84
 
88
- useProjectLog(authController);
85
+ const accessResponse = useProjectLog(authController, plugins);
89
86
 
90
87
  if (navigationController.navigationLoadingError) {
91
88
  return (
@@ -107,40 +104,54 @@ export function FireCMS<UserType extends User, EC extends EntityCollection>(prop
107
104
  );
108
105
  }
109
106
 
107
+ if (accessResponse?.blocked) {
108
+ return (
109
+ <CenteredView maxWidth={"md"} fullScreen={true}>
110
+ <Typography variant={"h4"}>
111
+ Access blocked
112
+ </Typography>
113
+ <Typography>
114
+ This app has been blocked. Please reach out at <a
115
+ href={"mailto:hello@firecms.co"}>hello@firecms.co</a> for more information.
116
+ </Typography>
117
+ {accessResponse?.message &&
118
+ <Typography>Response from the server: {accessResponse?.message}</Typography>}
119
+ </CenteredView>
120
+ );
121
+ }
122
+
110
123
  return (
111
- <ModeControllerContext.Provider value={modeController}>
112
- <AnalyticsContext.Provider value={analyticsController}>
113
- <CustomizationControllerContext.Provider value={customizationController}>
114
- <UserConfigurationPersistenceContext.Provider
115
- value={userConfigPersistence}>
116
- <StorageSourceContext.Provider
117
- value={storageSource}>
118
- <DataSourceContext.Provider
119
- value={dataSource}>
120
- <AuthControllerContext.Provider
121
- value={authController}>
122
- <SideDialogsControllerContext.Provider
123
- value={sideDialogsController}>
124
- <SideEntityControllerContext.Provider
125
- value={sideEntityController}>
126
- <NavigationContext.Provider
127
- value={navigationController}>
128
- <DialogsProvider>
129
- <FireCMSInternal
130
- loading={loading}>
131
- {children}
132
- </FireCMSInternal>
133
- </DialogsProvider>
134
- </NavigationContext.Provider>
135
- </SideEntityControllerContext.Provider>
136
- </SideDialogsControllerContext.Provider>
137
- </AuthControllerContext.Provider>
138
- </DataSourceContext.Provider>
139
- </StorageSourceContext.Provider>
140
- </UserConfigurationPersistenceContext.Provider>
141
- </CustomizationControllerContext.Provider>
142
- </AnalyticsContext.Provider>
143
- </ModeControllerContext.Provider>
124
+ <AnalyticsContext.Provider value={analyticsController}>
125
+ <CustomizationControllerContext.Provider value={customizationController}>
126
+ <UserConfigurationPersistenceContext.Provider
127
+ value={userConfigPersistence}>
128
+ <StorageSourceContext.Provider
129
+ value={storageSource}>
130
+ <DataSourceContext.Provider
131
+ value={dataSource}>
132
+ <AuthControllerContext.Provider
133
+ value={authController}>
134
+ <SideDialogsControllerContext.Provider
135
+ value={sideDialogsController}>
136
+ <SideEntityControllerContext.Provider
137
+ value={sideEntityController}>
138
+ <NavigationContext.Provider
139
+ value={navigationController}>
140
+ <DialogsProvider>
141
+ <FireCMSInternal
142
+ loading={loading}>
143
+ {children}
144
+ </FireCMSInternal>
145
+ </DialogsProvider>
146
+ </NavigationContext.Provider>
147
+ </SideEntityControllerContext.Provider>
148
+ </SideDialogsControllerContext.Provider>
149
+ </AuthControllerContext.Provider>
150
+ </DataSourceContext.Provider>
151
+ </StorageSourceContext.Provider>
152
+ </UserConfigurationPersistenceContext.Provider>
153
+ </CustomizationControllerContext.Provider>
154
+ </AnalyticsContext.Provider>
144
155
  );
145
156
 
146
157
  }
@@ -13,7 +13,7 @@ export type NavigationRoutesProps = {
13
13
  /**
14
14
  * In case you need to override the home page
15
15
  */
16
- HomePage?: React.ComponentType;
16
+ homePage?: React.ReactNode;
17
17
 
18
18
  customRoutes?: React.ReactNode[]
19
19
 
@@ -28,10 +28,9 @@ export type NavigationRoutesProps = {
28
28
  * @constructor
29
29
  * @group Components
30
30
  */
31
-
32
31
  export const NavigationRoutes = React.memo<NavigationRoutesProps>(
33
32
  function NavigationRoutes({
34
- HomePage = DefaultHomePage,
33
+ homePage = <DefaultHomePage/>,
35
34
  customRoutes
36
35
  }: NavigationRoutesProps) {
37
36
 
@@ -59,6 +58,14 @@ export const NavigationRoutes = React.memo<NavigationRoutesProps>(
59
58
  cmsViews.push(buildCMSViewRoute(cmsView.path, cmsView));
60
59
  });
61
60
  }
61
+ if (navigation.adminViews) {
62
+ navigation.adminViews.forEach((cmsView) => {
63
+ if (Array.isArray(cmsView.path))
64
+ cmsViews.push(...cmsView.path.map(path => buildCMSViewRoute(path, cmsView)));
65
+ else
66
+ cmsViews.push(buildCMSViewRoute(cmsView.path, cmsView));
67
+ });
68
+ }
62
69
 
63
70
  // we reorder collections so that nested paths are included first
64
71
  const sortedCollections = [...(navigation.collections ?? [])]
@@ -85,7 +92,7 @@ export const NavigationRoutes = React.memo<NavigationRoutesProps>(
85
92
 
86
93
  const homeRoute = (
87
94
  <Route path={"/"}
88
- element={<HomePage/>}/>
95
+ element={homePage}/>
89
96
  );
90
97
 
91
98
  const notFoundRoute = <Route path={"*"}
@@ -5,19 +5,35 @@ import { Link } from "react-router-dom";
5
5
  import { Drawer as DefaultDrawer, DrawerProps } from "./Drawer";
6
6
  import { useLargeLayout, useNavigationController } from "../hooks";
7
7
  import { ErrorBoundary, FireCMSAppBar as DefaultFireCMSAppBar, FireCMSAppBarProps, FireCMSLogo } from "../components";
8
- import { ChevronLeftIcon, cn, defaultBorderMixin, IconButton, MenuIcon, Sheet, Tooltip } from "@firecms/ui";
8
+ import { ChevronLeftIcon, cls, defaultBorderMixin, IconButton, MenuIcon, Sheet, Tooltip } from "@firecms/ui";
9
9
 
10
10
  export const DRAWER_WIDTH = 280;
11
11
 
12
+ const DrawerContext = React.createContext<DrawerProps>({
13
+ hovered: false,
14
+ drawerOpen: false,
15
+ openDrawer: () => {
16
+ throw new Error("openDrawer not implemented");
17
+ },
18
+ closeDrawer: () => {
19
+ throw new Error("closeDrawer not implemented");
20
+ },
21
+ autoOpenDrawer: false
22
+ });
23
+
24
+ export function useDrawer() {
25
+ return React.useContext(DrawerContext);
26
+ }
27
+
12
28
  /**
13
29
  * @group Core
14
30
  */
15
- export interface ScaffoldProps<ExtraDrawerProps = object, ExtraAppbarProps = object> {
31
+ export interface ScaffoldProps<ExtraAppbarProps = object> {
16
32
 
17
33
  /**
18
34
  * Name of the app, displayed as the main title and in the tab title
19
35
  */
20
- name: string;
36
+ name?: React.ReactNode;
21
37
 
22
38
  /**
23
39
  * Logo to be displayed in the drawer of the CMS
@@ -30,15 +46,10 @@ export interface ScaffoldProps<ExtraDrawerProps = object, ExtraAppbarProps = obj
30
46
  includeDrawer?: boolean;
31
47
 
32
48
  /**
33
- * In case you need to override the view that gets rendered as a drawer
34
- * @see DefaultDrawer
35
- */
36
- Drawer?: React.ComponentType<DrawerProps<ExtraDrawerProps>>;
37
-
38
- /**
39
- * Additional props passed to the custom Drawer
49
+ * You can define a custom drawer to be displayed in the scaffold.
50
+ * Use the hook `useDrawer` to access the context values.
40
51
  */
41
- drawerProps?: Partial<DrawerProps> & ExtraDrawerProps;
52
+ drawer?: React.ReactNode;
42
53
 
43
54
  /**
44
55
  * Open the drawer on hover
@@ -46,8 +57,7 @@ export interface ScaffoldProps<ExtraDrawerProps = object, ExtraAppbarProps = obj
46
57
  autoOpenDrawer?: boolean;
47
58
 
48
59
  /**
49
- * A component that gets rendered on the upper side of the main toolbar.
50
- * `toolbarExtraWidget` has no effect if this is set.
60
+ * The AppBar component to be used in the scaffold.
51
61
  */
52
62
  FireCMSAppBar?: React.ComponentType<FireCMSAppBarProps<ExtraAppbarProps>>;
53
63
 
@@ -78,8 +88,7 @@ export const Scaffold = React.memo<PropsWithChildren<ScaffoldProps>>(
78
88
  logo,
79
89
  includeDrawer = true,
80
90
  autoOpenDrawer,
81
- Drawer = DefaultDrawer,
82
- drawerProps,
91
+ drawer = <DefaultDrawer/>,
83
92
  FireCMSAppBar = DefaultFireCMSAppBar,
84
93
  fireCMSAppBarProps,
85
94
  } = props;
@@ -92,60 +101,65 @@ export const Scaffold = React.memo<PropsWithChildren<ScaffoldProps>>(
92
101
  const setOnHoverTrue = useCallback(() => setOnHover(true), []);
93
102
  const setOnHoverFalse = useCallback(() => setOnHover(false), []);
94
103
 
104
+ const handleDrawerOpen = useCallback(() => {
105
+ setDrawerOpen(true);
106
+ }, []);
107
+
95
108
  const handleDrawerClose = useCallback(() => {
96
109
  setDrawerOpen(false);
97
110
  }, []);
98
111
 
99
112
  const computedDrawerOpen: boolean = drawerOpen || Boolean(largeLayout && autoOpenDrawer && onHover);
113
+
100
114
  return (
101
- <div
102
- className="flex h-screen w-screen bg-gray-50 dark:bg-gray-900 text-gray-900 dark:text-white overflow-hidden"
103
- style={{
104
- paddingTop: "env(safe-area-inset-top)",
105
- paddingLeft: "env(safe-area-inset-left)",
106
- paddingRight: "env(safe-area-inset-right)",
107
- paddingBottom: "env(safe-area-inset-bottom)",
108
- height: "100dvh"
109
- // "@supports (height: 100dvh)": {
110
- // height: "100dvh"
111
- // }
112
- }}>
113
-
114
- <FireCMSAppBar title={name}
115
- includeDrawer={includeDrawer}
116
- drawerOpen={computedDrawerOpen}
117
- {...fireCMSAppBarProps}/>
118
-
119
- <StyledDrawer
120
- displayed={includeDrawer}
121
- onMouseEnter={setOnHoverTrue}
122
- onMouseMove={setOnHoverTrue}
123
- onMouseLeave={setOnHoverFalse}
124
- open={computedDrawerOpen}
125
- logo={logo}
126
- hovered={onHover}
127
- setDrawerOpen={setDrawerOpen}>
128
- {includeDrawer && (
129
- <Drawer
130
- hovered={onHover}
131
- drawerOpen={computedDrawerOpen}
132
- closeDrawer={handleDrawerClose}
133
- {...drawerProps}/>)}
134
- </StyledDrawer>
135
-
136
- <main
137
- className="flex flex-col flex-grow overflow-auto">
138
- <DrawerHeader/>
139
- <div
140
- className={cn(defaultBorderMixin, "flex-grow overflow-auto lg:m-0 lg:mx-4 lg:mb-4 lg:rounded-lg lg:border lg:border-solid m-0 mt-1")}>
141
-
142
- <ErrorBoundary>
143
- {children}
144
- </ErrorBoundary>
145
-
146
- </div>
147
- </main>
148
- </div>
115
+ <DrawerContext.Provider value={{
116
+ hovered: onHover,
117
+ drawerOpen: computedDrawerOpen,
118
+ closeDrawer: handleDrawerClose,
119
+ openDrawer: handleDrawerOpen,
120
+ autoOpenDrawer
121
+ }}>
122
+ <div
123
+ className="flex h-screen w-screen bg-gray-50 dark:bg-gray-900 text-gray-900 dark:text-white overflow-hidden"
124
+ style={{
125
+ paddingTop: "env(safe-area-inset-top)",
126
+ paddingLeft: "env(safe-area-inset-left)",
127
+ paddingRight: "env(safe-area-inset-right)",
128
+ paddingBottom: "env(safe-area-inset-bottom)",
129
+ height: "100dvh"
130
+ }}>
131
+
132
+ <FireCMSAppBar title={name}
133
+ includeDrawer={includeDrawer}
134
+ logo={logo}
135
+ drawerOpen={computedDrawerOpen}
136
+ {...fireCMSAppBarProps}/>
137
+ <DrawerWrapper
138
+ displayed={includeDrawer}
139
+ onMouseEnter={setOnHoverTrue}
140
+ onMouseMove={setOnHoverTrue}
141
+ onMouseLeave={setOnHoverFalse}
142
+ open={computedDrawerOpen}
143
+ logo={logo}
144
+ hovered={onHover}
145
+ setDrawerOpen={setDrawerOpen}>
146
+ {includeDrawer && drawer}
147
+ </DrawerWrapper>
148
+
149
+ <main
150
+ className="flex flex-col flex-grow overflow-auto">
151
+ <DrawerHeader/>
152
+ <div
153
+ className={cls(defaultBorderMixin, "flex-grow overflow-auto lg:m-0 lg:mx-4 lg:mb-4 lg:rounded-lg lg:border lg:border-solid m-0 mt-1")}>
154
+
155
+ <ErrorBoundary>
156
+ {children}
157
+ </ErrorBoundary>
158
+
159
+ </div>
160
+ </main>
161
+ </div>
162
+ </DrawerContext.Provider>
149
163
  );
150
164
  },
151
165
  equal
@@ -157,7 +171,7 @@ const DrawerHeader = () => {
157
171
  );
158
172
  };
159
173
 
160
- function StyledDrawer(props: {
174
+ function DrawerWrapper(props: {
161
175
  children: React.ReactNode,
162
176
  displayed: boolean,
163
177
  open: boolean,
@@ -204,7 +218,7 @@ function StyledDrawer(props: {
204
218
  transition: "padding 100ms cubic-bezier(0.4, 0, 0.6, 1) 0ms",
205
219
  padding: props.open ? "32px 144px 0px 24px" : "72px 16px 0px"
206
220
  }}
207
- className={cn("cursor-pointer")}>
221
+ className={cls("cursor-pointer")}>
208
222
 
209
223
  <Tooltip title={"Home"}
210
224
  sideOffset={20}
@@ -214,7 +228,7 @@ function StyledDrawer(props: {
214
228
  {props.logo
215
229
  ? <img src={props.logo}
216
230
  alt="Logo"
217
- className={cn("max-w-full max-h-full",
231
+ className={cls("max-w-full max-h-full",
218
232
  props.open ?? "w-[112px] h-[112px]")}/>
219
233
  : <FireCMSLogo/>}
220
234
 
@@ -331,7 +331,7 @@ export function getFieldConfig(property: Property | ResolvedProperty, propertyCo
331
331
  }
332
332
  const defaultFieldConfig = DEFAULT_FIELD_CONFIGS[defaultFieldId];
333
333
  const customField = fieldId ? propertyConfigs[fieldId] : undefined;
334
- return mergeDeep(defaultFieldConfig ?? {}, customField ?? {});
334
+ return mergeDeep(defaultFieldConfig ?? {}, customField ?? {} as PropertyConfig);
335
335
  }
336
336
 
337
337
  export function getDefaultFieldId(property: Property | ResolvedProperty) {
@@ -359,8 +359,7 @@ export function getDefaultFieldId(property: Property | ResolvedProperty) {
359
359
  } else if (property.dataType === "map") {
360
360
  if (property.keyValue)
361
361
  return "key_value";
362
- if (property.properties)
363
- return "group";
362
+ return "group";
364
363
  } else if (property.dataType === "array") {
365
364
  const of = (property as ArrayProperty).of;
366
365
  const oneOf = (property as ArrayProperty).oneOf;
@@ -1,10 +1,9 @@
1
1
  export * from "./FireCMS";
2
2
 
3
- export type { ScaffoldProps } from "./Scaffold";
4
- export { Scaffold } from "./Scaffold";
3
+ export * from "./Scaffold";
5
4
 
6
- export type { DrawerProps } from "./Drawer";
7
- export { Drawer, DrawerNavigationItem } from "./Drawer";
5
+ export * from "./Drawer";
6
+ export * from "./DrawerNavigationItem";
8
7
 
9
8
  export * from "./field_configs";
10
9
 
@@ -19,8 +19,9 @@ import equal from "react-fast-compare"
19
19
  import {
20
20
  canCreateEntity,
21
21
  canDeleteEntity,
22
- fullPathToCollectionSegments,
23
22
  getDefaultValuesFor,
23
+ getEntityTitlePropertyKey,
24
+ getValueInPath,
24
25
  isHidden,
25
26
  isReadOnly,
26
27
  resolveCollection
@@ -34,12 +35,9 @@ import {
34
35
  } from "../hooks";
35
36
  import { ErrorFocus } from "./components/ErrorFocus";
36
37
  import { CustomIdField } from "./components/CustomIdField";
37
- import { Alert, Button, cn, DialogActions, IconButton, Tooltip, Typography } from "@firecms/ui";
38
- import { ErrorBoundary } from "../components";
39
- import {
40
- copyEntityAction,
41
- deleteEntityAction
42
- } from "../components/EntityCollectionTable/internal/default_entity_actions";
38
+ import { Alert, Button, CircularProgress, cls, DialogActions, IconButton, Tooltip, Typography } from "@firecms/ui";
39
+ import { CircularProgressCenter, ErrorBoundary } from "../components";
40
+ import { copyEntityAction, deleteEntityAction } from "../components/common/default_entity_actions";
43
41
  import { useAnalyticsController } from "../hooks/useAnalyticsController";
44
42
  import { ValidationError } from "yup";
45
43
  import { PropertyIdCopyTooltipContent } from "../components/PropertyIdCopyTooltipContent";
@@ -171,7 +169,7 @@ function EntityFormInternal<M extends Record<string, any>>({
171
169
  onFormContextChange,
172
170
  hideId,
173
171
  autoSave,
174
- onIdUpdateError
172
+ onIdUpdateError,
175
173
  }: EntityFormProps<M>) {
176
174
 
177
175
  const analyticsController = useAnalyticsController();
@@ -179,7 +177,7 @@ function EntityFormInternal<M extends Record<string, any>>({
179
177
  const customizationController = useCustomizationController();
180
178
 
181
179
  const context = useFireCMSContext();
182
- const dataSource = useDataSource();
180
+ const dataSource = useDataSource(inputCollection);
183
181
  const plugins = customizationController.plugins;
184
182
 
185
183
  const initialResolvedCollection = useMemo(() => resolveCollection({
@@ -187,7 +185,7 @@ function EntityFormInternal<M extends Record<string, any>>({
187
185
  path,
188
186
  values: entity?.values,
189
187
  fields: customizationController.propertyConfigs
190
- }), [entity?.values, path]);
188
+ }), [entity?.values, path, customizationController.propertyConfigs]);
191
189
 
192
190
  const mustSetCustomId: boolean = (status === "new" || status === "copy") &&
193
191
  (Boolean(initialResolvedCollection.customId) && initialResolvedCollection.customId !== "optional");
@@ -344,6 +342,9 @@ function EntityFormInternal<M extends Record<string, any>>({
344
342
  fields: customizationController.propertyConfigs
345
343
  });
346
344
 
345
+ const titlePropertyKey = getEntityTitlePropertyKey(resolvedCollection, customizationController.propertyConfigs);
346
+ const title = internalValues && titlePropertyKey ? getValueInPath(internalValues, titlePropertyKey) : undefined;
347
+
347
348
  const onIdUpdate = inputCollection.callbacks?.onIdUpdate;
348
349
 
349
350
  const doOnIdUpdate = useCallback(async () => {
@@ -389,12 +390,15 @@ function EntityFormInternal<M extends Record<string, any>>({
389
390
 
390
391
  const authController = useAuthController();
391
392
 
392
- const getActionsForEntity = useCallback(({ entity, customEntityActions }: {
393
+ const getActionsForEntity = useCallback(({
394
+ entity,
395
+ customEntityActions
396
+ }: {
393
397
  entity?: Entity<M>,
394
398
  customEntityActions?: EntityAction[]
395
399
  }): EntityAction[] => {
396
- const createEnabled = canCreateEntity(inputCollection, authController, fullPathToCollectionSegments(path), null);
397
- const deleteEnabled = entity ? canDeleteEntity(inputCollection, authController, fullPathToCollectionSegments(path), entity) : true;
400
+ const createEnabled = canCreateEntity(inputCollection, authController, path, null);
401
+ const deleteEnabled = entity ? canDeleteEntity(inputCollection, authController, path, entity) : true;
398
402
  const actions: EntityAction[] = [];
399
403
  if (createEnabled)
400
404
  actions.push(copyEntityAction);
@@ -408,7 +412,8 @@ function EntityFormInternal<M extends Record<string, any>>({
408
412
  const pluginActions: React.ReactNode[] = [];
409
413
 
410
414
  const formContext: FormContext<M> = {
411
- setFieldValue: formex.setFieldValue,
415
+ // @ts-ignore
416
+ setFieldValue: useCallback(formex.setFieldValue, []),
412
417
  values: formex.values,
413
418
  collection: resolvedCollection,
414
419
  entityId,
@@ -416,12 +421,14 @@ function EntityFormInternal<M extends Record<string, any>>({
416
421
  save
417
422
  };
418
423
 
424
+ const submittedFormContext = useRef<FormContext<M> | null>(null);
419
425
  // eslint-disable-next-line react-hooks/rules-of-hooks
420
426
  useEffect(() => {
421
- if (onFormContextChange) {
427
+ if (onFormContextChange && !formContextsEqual(submittedFormContext.current ?? undefined, formContext)) {
422
428
  onFormContextChange(formContext);
429
+ submittedFormContext.current = formContext;
423
430
  }
424
- }, [onFormContextChange, formContext]);
431
+ }, [formContext, onFormContextChange]);
425
432
 
426
433
  if (plugins && inputCollection) {
427
434
  const actionProps: PluginFormActionProps = {
@@ -436,7 +443,7 @@ function EntityFormInternal<M extends Record<string, any>>({
436
443
  pluginActions.push(...plugins.map((plugin, i) => (
437
444
  plugin.form?.Actions
438
445
  ? <plugin.form.Actions
439
- key={`actions_${plugin.name}`} {...actionProps}/>
446
+ key={`actions_${plugin.key}`} {...actionProps}/>
440
447
  : null
441
448
  )).filter(Boolean));
442
449
  }
@@ -445,7 +452,7 @@ function EntityFormInternal<M extends Record<string, any>>({
445
452
  <div className="h-full overflow-auto">
446
453
 
447
454
  {pluginActions.length > 0 && <div
448
- className={cn("w-full flex justify-end items-center sticky top-0 right-0 left-0 z-10 bg-opacity-60 bg-slate-200 dark:bg-opacity-60 dark:bg-slate-800 backdrop-blur-md")}>
455
+ className={cls("w-full flex justify-end items-center sticky top-0 right-0 left-0 z-10 bg-opacity-60 bg-slate-200 dark:bg-opacity-60 dark:bg-slate-800 backdrop-blur-md")}>
449
456
  {pluginActions}
450
457
  </div>}
451
458
 
@@ -454,8 +461,8 @@ function EntityFormInternal<M extends Record<string, any>>({
454
461
  className={`w-full py-2 flex flex-col items-start mt-${4 + (pluginActions ? 8 : 0)} lg:mt-${8 + (pluginActions ? 8 : 0)} mb-8`}>
455
462
 
456
463
  <Typography
457
- className={"mt-4 flex-grow " + inputCollection.hideIdFromForm ? "mb-2" : "mb-0"}
458
- variant={"h4"}>{inputCollection.singularName ?? inputCollection.name}
464
+ className={"mt-4 flex-grow line-clamp-1 " + inputCollection.hideIdFromForm ? "mb-2" : "mb-0"}
465
+ variant={"h4"}>{title ?? inputCollection.singularName ?? inputCollection.name}
459
466
  </Typography>
460
467
  <Alert color={"base"} className={"w-full"} size={"small"}>
461
468
  <code className={"text-xs select-all"}>{path}/{entityId}</code>
@@ -508,7 +515,7 @@ function InnerForm<M extends Record<string, any>>(props: FormexController<M> & {
508
515
  savingError?: Error,
509
516
  closeAfterSaveRef: MutableRefObject<boolean>,
510
517
  autoSave?: boolean,
511
- entityActions: EntityAction[]
518
+ entityActions: EntityAction[],
512
519
  }) {
513
520
 
514
521
  const {
@@ -530,7 +537,7 @@ function InnerForm<M extends Record<string, any>>(props: FormexController<M> & {
530
537
  dirty,
531
538
  closeAfterSaveRef,
532
539
  autoSave,
533
- entityActions
540
+ entityActions,
534
541
  } = props;
535
542
 
536
543
  const context = useFireCMSContext();
@@ -598,6 +605,7 @@ function InnerForm<M extends Record<string, any>>(props: FormexController<M> & {
598
605
  <Tooltip title={<PropertyIdCopyTooltipContent propertyId={key}/>}
599
606
  delayDuration={800}
600
607
  side={"left"}
608
+ align={"start"}
601
609
  sideOffset={16}>
602
610
  <PropertyFieldBinding {...cmsFormFieldProps}/>
603
611
  </Tooltip>
@@ -655,17 +663,17 @@ function InnerForm<M extends Record<string, any>>(props: FormexController<M> & {
655
663
  fullPath: resolvedCollection.path,
656
664
  collection: resolvedCollection,
657
665
  context,
658
- sideEntityController
666
+ sideEntityController,
659
667
  });
660
668
  }}>
661
669
  {action.icon}
662
670
  </IconButton>
663
671
  ))}
664
672
  </div>}
665
-
673
+ {isSubmitting && <CircularProgress size={"small"}/>}
666
674
  <Button
667
675
  variant="text"
668
- disabled={disabled}
676
+ disabled={disabled || isSubmitting}
669
677
  type="reset"
670
678
  >
671
679
  {status === "existing" ? "Discard" : "Clear"}
@@ -675,7 +683,7 @@ function InnerForm<M extends Record<string, any>>(props: FormexController<M> & {
675
683
  variant="text"
676
684
  color="primary"
677
685
  type="submit"
678
- disabled={disabled}
686
+ disabled={disabled || isSubmitting}
679
687
  onClick={() => {
680
688
  closeAfterSaveRef.current = false;
681
689
  }}
@@ -689,7 +697,7 @@ function InnerForm<M extends Record<string, any>>(props: FormexController<M> & {
689
697
  variant="filled"
690
698
  color="primary"
691
699
  type="submit"
692
- disabled={disabled}
700
+ disabled={disabled || isSubmitting}
693
701
  onClick={() => {
694
702
  closeAfterSaveRef.current = true;
695
703
  }}
@@ -718,3 +726,10 @@ export function yupToFormErrors(yupError: ValidationError): Record<string, any>
718
726
  }
719
727
  return errors;
720
728
  }
729
+
730
+ function formContextsEqual(a: FormContext<any> | undefined, b: FormContext<any> | undefined): boolean {
731
+ return a?.path === b?.path &&
732
+ a?.entityId === b?.entityId &&
733
+ equal(a?.values, b?.values) &&
734
+ equal(a?.collection, b?.collection);
735
+ }