@firecms/core 3.0.0-beta.11 → 3.0.0-beta.12

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 (173) hide show
  1. package/dist/components/ArrayContainer.d.ts +7 -3
  2. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +2 -1
  3. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +2 -2
  4. package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +15 -1
  5. package/dist/components/EntityCollectionTable/index.d.ts +1 -1
  6. package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +4 -0
  7. package/dist/components/PropertyIdCopyTooltip.d.ts +1 -1
  8. package/dist/components/SelectableTable/SelectableTable.d.ts +12 -2
  9. package/dist/components/SelectableTable/filters/ReferenceFilterField.d.ts +1 -1
  10. package/dist/components/UnsavedChangesDialog.d.ts +8 -0
  11. package/dist/components/VirtualTable/VirtualTableProps.d.ts +13 -0
  12. package/dist/components/common/default_entity_actions.d.ts +0 -2
  13. package/dist/components/common/index.d.ts +1 -1
  14. package/dist/components/common/useColumnsIds.d.ts +1 -0
  15. package/dist/components/common/{useDataSourceEntityCollectionTableController.d.ts → useDataSourceTableController.d.ts} +10 -2
  16. package/dist/components/common/useDebouncedCallback.d.ts +1 -0
  17. package/dist/components/common/useScrollRestoration.d.ts +14 -0
  18. package/dist/contexts/BreacrumbsContext.d.ts +8 -0
  19. package/dist/core/EntityEditView.d.ts +29 -21
  20. package/dist/core/EntityEditViewFormActions.d.ts +2 -0
  21. package/dist/core/FireCMSRouter.d.ts +4 -0
  22. package/dist/core/NavigationRoutes.d.ts +0 -1
  23. package/dist/core/SideDialogs.d.ts +4 -2
  24. package/dist/core/index.d.ts +2 -1
  25. package/dist/form/EntityForm.d.ts +45 -0
  26. package/dist/form/EntityFormActions.d.ts +17 -0
  27. package/dist/form/PropertyFieldBinding.d.ts +1 -1
  28. package/dist/form/components/FormEntry.d.ts +6 -0
  29. package/dist/form/components/FormLayout.d.ts +5 -0
  30. package/dist/form/components/index.d.ts +2 -0
  31. package/dist/form/field_bindings/ArrayCustomShapedFieldBinding.d.ts +1 -1
  32. package/dist/form/field_bindings/ArrayOfReferencesFieldBinding.d.ts +1 -1
  33. package/dist/form/field_bindings/BlockFieldBinding.d.ts +1 -1
  34. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  35. package/dist/form/field_bindings/MarkdownEditorFieldBinding.d.ts +1 -1
  36. package/dist/form/field_bindings/RepeatFieldBinding.d.ts +1 -1
  37. package/dist/form/index.d.ts +16 -16
  38. package/dist/hooks/data/useEntityFetch.d.ts +2 -1
  39. package/dist/hooks/useBreadcrumbsController.d.ts +26 -0
  40. package/dist/hooks/useBuildNavigationController.d.ts +4 -1
  41. package/dist/hooks/useModeController.d.ts +1 -2
  42. package/dist/index.es.js +18213 -16819
  43. package/dist/index.es.js.map +1 -1
  44. package/dist/index.umd.js +18164 -16771
  45. package/dist/index.umd.js.map +1 -1
  46. package/dist/internal/useBuildSideEntityController.d.ts +2 -2
  47. package/dist/internal/useUnsavedChangesDialog.d.ts +7 -9
  48. package/dist/routes/CustomCMSRoute.d.ts +4 -0
  49. package/dist/routes/FireCMSRoute.d.ts +1 -0
  50. package/dist/routes/HomePageRoute.d.ts +3 -0
  51. package/dist/types/collections.d.ts +30 -10
  52. package/dist/types/datasource.d.ts +2 -2
  53. package/dist/types/dialogs_controller.d.ts +7 -3
  54. package/dist/types/entities.d.ts +1 -1
  55. package/dist/types/entity_actions.d.ts +10 -0
  56. package/dist/types/fields.d.ts +9 -2
  57. package/dist/types/navigation.d.ts +29 -12
  58. package/dist/types/plugins.d.ts +1 -0
  59. package/dist/types/properties.d.ts +18 -3
  60. package/dist/types/side_entity_controller.d.ts +6 -1
  61. package/dist/util/builders.d.ts +1 -1
  62. package/dist/util/entity_actions.d.ts +2 -0
  63. package/dist/util/entity_cache.d.ts +23 -0
  64. package/dist/util/index.d.ts +1 -0
  65. package/dist/util/navigation_from_path.d.ts +6 -1
  66. package/dist/util/navigation_utils.d.ts +12 -1
  67. package/dist/util/resolutions.d.ts +6 -1
  68. package/package.json +19 -21
  69. package/src/components/ArrayContainer.tsx +48 -29
  70. package/src/components/CircularProgressCenter.tsx +1 -1
  71. package/src/components/DeleteEntityDialog.tsx +1 -1
  72. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +40 -19
  73. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +10 -4
  74. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +18 -1
  75. package/src/components/EntityCollectionTable/index.tsx +1 -1
  76. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +3 -3
  77. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +5 -11
  78. package/src/components/EntityCollectionView/EntityCollectionView.tsx +83 -41
  79. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +4 -2
  80. package/src/components/NotFoundPage.tsx +2 -2
  81. package/src/components/PropertyIdCopyTooltip.tsx +2 -3
  82. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +11 -6
  83. package/src/components/SelectableTable/SelectableTable.tsx +18 -3
  84. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +7 -7
  85. package/src/components/UnsavedChangesDialog.tsx +42 -0
  86. package/src/components/VirtualTable/VirtualTable.tsx +19 -2
  87. package/src/components/VirtualTable/VirtualTableProps.tsx +15 -0
  88. package/src/components/VirtualTable/fields/VirtualTableInput.tsx +1 -1
  89. package/src/components/common/default_entity_actions.tsx +26 -37
  90. package/src/components/common/index.ts +1 -1
  91. package/src/components/common/useColumnsIds.tsx +1 -1
  92. package/src/components/common/useDataSourceTableController.tsx +420 -0
  93. package/src/components/common/useDebouncedCallback.tsx +20 -0
  94. package/src/components/common/useScrollRestoration.tsx +68 -0
  95. package/src/contexts/BreacrumbsContext.tsx +38 -0
  96. package/src/contexts/DialogsProvider.tsx +3 -2
  97. package/src/contexts/ModeController.tsx +1 -3
  98. package/src/core/DefaultAppBar.tsx +44 -14
  99. package/src/core/DefaultDrawer.tsx +1 -1
  100. package/src/core/EntityEditView.tsx +278 -1000
  101. package/src/core/EntityEditViewFormActions.tsx +199 -0
  102. package/src/core/EntitySidePanel.tsx +85 -15
  103. package/src/core/FireCMS.tsx +7 -4
  104. package/src/core/FireCMSRouter.tsx +17 -0
  105. package/src/core/NavigationRoutes.tsx +23 -32
  106. package/src/core/SideDialogs.tsx +20 -11
  107. package/src/core/index.tsx +4 -2
  108. package/src/form/EntityForm.tsx +774 -0
  109. package/src/form/EntityFormActions.tsx +169 -0
  110. package/src/form/PropertyFieldBinding.tsx +13 -11
  111. package/src/form/components/FormEntry.tsx +22 -0
  112. package/src/form/components/FormLayout.tsx +16 -0
  113. package/src/form/components/LabelWithIcon.tsx +6 -3
  114. package/src/form/components/StorageUploadProgress.tsx +1 -1
  115. package/src/form/components/index.tsx +2 -0
  116. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +4 -4
  117. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +4 -2
  118. package/src/form/field_bindings/BlockFieldBinding.tsx +4 -2
  119. package/src/form/field_bindings/DateTimeFieldBinding.tsx +1 -0
  120. package/src/form/field_bindings/MapFieldBinding.tsx +14 -16
  121. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +9 -6
  122. package/src/form/field_bindings/MultiSelectFieldBinding.tsx +1 -1
  123. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +2 -2
  124. package/src/form/field_bindings/ReferenceFieldBinding.tsx +1 -1
  125. package/src/form/field_bindings/RepeatFieldBinding.tsx +5 -2
  126. package/src/form/field_bindings/SelectFieldBinding.tsx +1 -1
  127. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +6 -4
  128. package/src/form/field_bindings/SwitchFieldBinding.tsx +1 -0
  129. package/src/form/field_bindings/TextFieldBinding.tsx +1 -0
  130. package/src/form/index.tsx +16 -32
  131. package/src/form/validation.ts +12 -6
  132. package/src/hooks/data/save.ts +1 -1
  133. package/src/hooks/data/useCollectionFetch.tsx +1 -1
  134. package/src/hooks/data/useEntityFetch.tsx +5 -1
  135. package/src/hooks/useBreadcrumbsController.tsx +31 -0
  136. package/src/hooks/useBuildModeController.tsx +15 -28
  137. package/src/hooks/useBuildNavigationController.tsx +70 -24
  138. package/src/hooks/useLargeLayout.tsx +0 -35
  139. package/src/hooks/useModeController.tsx +1 -2
  140. package/src/hooks/useResolvedNavigationFrom.tsx +4 -6
  141. package/src/internal/useBuildSideDialogsController.tsx +3 -2
  142. package/src/internal/useBuildSideEntityController.tsx +124 -83
  143. package/src/internal/useUnsavedChangesDialog.tsx +126 -92
  144. package/src/preview/PropertyPreview.tsx +8 -8
  145. package/src/preview/components/UrlComponentPreview.tsx +17 -18
  146. package/src/preview/property_previews/MapPropertyPreview.tsx +3 -2
  147. package/src/routes/CustomCMSRoute.tsx +21 -0
  148. package/src/routes/FireCMSRoute.tsx +235 -0
  149. package/src/routes/HomePageRoute.tsx +17 -0
  150. package/src/types/collections.ts +38 -13
  151. package/src/types/datasource.ts +2 -1
  152. package/src/types/dialogs_controller.tsx +7 -3
  153. package/src/types/entities.ts +1 -1
  154. package/src/types/entity_actions.tsx +12 -0
  155. package/src/types/fields.tsx +13 -2
  156. package/src/types/navigation.ts +36 -16
  157. package/src/types/plugins.tsx +1 -0
  158. package/src/types/properties.ts +21 -3
  159. package/src/types/side_dialogs_controller.tsx +2 -0
  160. package/src/types/side_entity_controller.tsx +6 -1
  161. package/src/util/builders.ts +5 -3
  162. package/src/util/entity_actions.ts +28 -0
  163. package/src/util/entity_cache.ts +204 -0
  164. package/src/util/index.ts +1 -0
  165. package/src/util/join_collections.ts +3 -0
  166. package/src/util/navigation_from_path.ts +13 -6
  167. package/src/util/navigation_utils.ts +53 -1
  168. package/src/util/objects.ts +4 -1
  169. package/src/util/parent_references_from_path.ts +3 -3
  170. package/src/util/resolutions.ts +26 -5
  171. package/src/util/useStorageUploadController.tsx +39 -21
  172. package/src/components/common/useDataSourceEntityCollectionTableController.tsx +0 -236
  173. /package/src/util/{common.tsx → common.ts} +0 -0
@@ -0,0 +1,235 @@
1
+ import { Blocker, useBlocker, useLocation } from "react-router";
2
+ import { EntityEditView } from "../core/EntityEditView";
3
+ import { useNavigationController } from "../hooks";
4
+ import { useEffect, useRef, useState } from "react";
5
+ import { useNavigate } from "react-router-dom";
6
+ import {
7
+ getNavigationEntriesFromPath,
8
+ NavigationViewCollectionInternal,
9
+ NavigationViewEntityCustomInternal,
10
+ NavigationViewInternal
11
+ } from "../util/navigation_from_path";
12
+ import { useBreadcrumbsController } from "../hooks/useBreadcrumbsController";
13
+ import { toArray } from "../util/arrays";
14
+ import { EntityCollectionView, NotFoundPage } from "../components";
15
+ import { UnsavedChangesDialog } from "../components/UnsavedChangesDialog";
16
+
17
+ export function FireCMSRoute() {
18
+
19
+ const location = useLocation();
20
+ const navigation = useNavigationController();
21
+ const breadcrumbs = useBreadcrumbsController();
22
+
23
+ const hash = location.hash;
24
+ const isSidePanel = hash.includes("#side");
25
+ const isNew = hash.includes("#new") || hash.includes("#new_side");
26
+ const isCopy = hash.includes("#copy");
27
+
28
+ const pathname = location.pathname;
29
+ const navigationPath = navigation.urlPathToDataPath(pathname);
30
+
31
+ const navigationEntries = getNavigationEntriesFromPath({
32
+ path: navigationPath,
33
+ collections: navigation.collections ?? []
34
+ });
35
+
36
+ useEffect(() => {
37
+ breadcrumbs.set({
38
+ breadcrumbs: navigationEntries.map(entry => {
39
+ if (entry.type === "entity") {
40
+ return ({
41
+ title: entry.entityId,
42
+ url: navigation.buildUrlCollectionPath(entry.fullPath)
43
+ });
44
+ } else if (entry.type === "custom_view") {
45
+ return ({
46
+ title: entry.view.name,
47
+ url: navigation.buildUrlCollectionPath(entry.fullPath)
48
+ });
49
+ } else if (entry.type === "collection") {
50
+ return ({
51
+ title: entry.collection.name,
52
+ url: navigation.buildUrlCollectionPath(entry.fullPath)
53
+ });
54
+ } else {
55
+ throw new Error("Unexpected navigation entry type");
56
+ }
57
+ })
58
+ });
59
+ }, [navigationEntries.map(entry => entry.path).join(",")]);
60
+
61
+ if (isNew) {
62
+ return <EntityFullScreenRoute
63
+ pathname={pathname}
64
+ navigationEntries={navigationEntries}
65
+ isNew={true}
66
+ isCopy={false}
67
+ />;
68
+ }
69
+
70
+ if (navigationEntries.length === 1 && navigationEntries[0].type === "collection") {
71
+ const collection = navigation.getCollection(navigationEntries[0].path);
72
+ if (!collection)
73
+ return null;
74
+ return <EntityCollectionView
75
+ key={`collection_view_${collection.id ?? collection.path}`}
76
+ isSubCollection={false}
77
+ parentCollectionIds={[]}
78
+ fullPath={collection.id}
79
+ updateUrl={true}
80
+ {...collection}
81
+ Actions={toArray(collection.Actions)}/>
82
+ }
83
+
84
+ if (isSidePanel) {
85
+ const lastCollectionEntry = navigationEntries.findLast((entry) => entry.type === "collection");
86
+ if (lastCollectionEntry) {
87
+ const collection = navigation.getCollection(lastCollectionEntry.path);
88
+ if (!collection)
89
+ return null;
90
+ return <EntityCollectionView
91
+ key={`collection_view_${collection.id ?? collection.path}`}
92
+ isSubCollection={false}
93
+ parentCollectionIds={[]}
94
+ fullPath={collection.id}
95
+ updateUrl={true}
96
+ {...collection}
97
+ Actions={toArray(collection.Actions)}/>;
98
+ }
99
+ }
100
+
101
+ return <EntityFullScreenRoute
102
+ pathname={pathname}
103
+ navigationEntries={navigationEntries}
104
+ isNew={isNew}
105
+ isCopy={isCopy}
106
+ />;
107
+
108
+ }
109
+
110
+ function getSelectedTabFromUrl(isNew: boolean, lastCustomView: NavigationViewCollectionInternal<any> | NavigationViewEntityCustomInternal<any> | undefined) {
111
+ if (isNew) {
112
+ return undefined;
113
+ } else if (lastCustomView) {
114
+ if (lastCustomView.type === "custom_view") {
115
+ return lastCustomView.view.key;
116
+ } else if (lastCustomView.type === "collection") {
117
+ return lastCustomView.id ?? lastCustomView.path;
118
+ }
119
+ }
120
+ return undefined;
121
+ }
122
+
123
+ function EntityFullScreenRoute({
124
+ pathname,
125
+ navigationEntries,
126
+ isNew,
127
+ isCopy
128
+ }: {
129
+ pathname: string;
130
+ navigationEntries: NavigationViewInternal[],
131
+ isNew: boolean,
132
+ isCopy: boolean
133
+ }) {
134
+
135
+ const navigation = useNavigationController();
136
+ const navigate = useNavigate();
137
+
138
+ const navigationPath = navigation.urlPathToDataPath(pathname);
139
+
140
+ // is navigating away blocked
141
+ const blocked = useRef(false);
142
+
143
+ const lastEntityEntry = navigationEntries.findLast((entry) => entry.type === "entity");
144
+ const navigationEntriesAfterEntity = lastEntityEntry ? navigationEntries.slice(navigationEntries.indexOf(lastEntityEntry) + 1) : [];
145
+
146
+ const lastCustomView = navigationEntriesAfterEntity.findLast(
147
+ (entry) => entry.type === "custom_view" || entry.type === "collection"
148
+ ) as NavigationViewCollectionInternal<any> | NavigationViewEntityCustomInternal<any> | undefined;
149
+
150
+ const entityId = lastEntityEntry?.entityId;
151
+
152
+ const urlTab = getSelectedTabFromUrl(isNew, lastCustomView);
153
+ const [selectedTab, setSelectedTab] = useState<string | undefined>(urlTab);
154
+
155
+ const parentCollectionIds = navigation.getParentCollectionIds(navigationPath);
156
+ useEffect(() => {
157
+ if (urlTab !== selectedTab) {
158
+ setSelectedTab(urlTab);
159
+ }
160
+ }, [urlTab]);
161
+
162
+ const basePath = !entityId || isNew
163
+ ? pathname
164
+ : pathname.substring(0, pathname.lastIndexOf(`/${entityId}`));
165
+
166
+ const entityPath = basePath + `/${entityId}`;
167
+
168
+ let blocker: Blocker | undefined = undefined;
169
+ try {
170
+ blocker = useBlocker(({
171
+ nextLocation
172
+ }) => {
173
+ if (nextLocation.pathname.startsWith(entityPath))
174
+ return false;
175
+ return blocked.current;
176
+ });
177
+ } catch (e) {
178
+ console.warn("Blocker not available, navigation will not be blocked");
179
+ }
180
+
181
+ const lastCollectionEntry = navigationEntries.findLast((entry) => entry.type === "collection");
182
+
183
+ if (isNew && !lastCollectionEntry) {
184
+ throw new Error("INTERNAL: No collection found in the navigation");
185
+ }
186
+
187
+ if (!isNew && !lastEntityEntry) {
188
+ return <NotFoundPage/>;
189
+ }
190
+
191
+ const collection = isNew ? lastCollectionEntry!.collection : lastEntityEntry!.parentCollection;
192
+ const collectionPath = navigation.resolveIdsFrom(isNew ? lastCollectionEntry!.path : lastEntityEntry!.path);
193
+
194
+ return <>
195
+ <EntityEditView
196
+ key={collection.id + "_" + (isNew ? "new" : (isCopy ? entityId + "_copy" : entityId))}
197
+ entityId={isNew ? undefined : entityId}
198
+ collection={collection}
199
+ layout={"full_screen"}
200
+ path={collectionPath}
201
+ copy={isCopy}
202
+ selectedTab={selectedTab ?? undefined}
203
+ onValuesModified={(modified) => blocked.current = modified}
204
+ onSaved={(params) => {
205
+ const newSelectedTab = params.selectedTab;
206
+ const newEntityId = params.entityId;
207
+ if (newSelectedTab) {
208
+ navigate(`${basePath}/${newEntityId}/${newSelectedTab}`, { replace: true });
209
+ } else {
210
+ navigate(`${basePath}/${newEntityId}`, { replace: true });
211
+ }
212
+ }}
213
+ onTabChange={(params) => {
214
+ setSelectedTab(params.selectedTab);
215
+ if (isNew) {
216
+ return;
217
+ }
218
+ const newSelectedTab = params.selectedTab;
219
+ if (newSelectedTab) {
220
+ navigate(`${basePath}/${entityId}/${newSelectedTab}`, { replace: true });
221
+ } else {
222
+ navigate(`${basePath}/${entityId}`, { replace: true });
223
+ }
224
+ }}
225
+ parentCollectionIds={parentCollectionIds}
226
+ />
227
+
228
+ <UnsavedChangesDialog
229
+ open={blocker?.state === "blocked"}
230
+ handleOk={() => blocker?.proceed?.()}
231
+ handleCancel={() => blocker?.reset?.()}
232
+ body={"You have unsaved changes in this entity."}/>
233
+
234
+ </>;
235
+ }
@@ -0,0 +1,17 @@
1
+ import { useBreadcrumbsController } from "../hooks/useBreadcrumbsController";
2
+ import { useEffect } from "react";
3
+
4
+ export function HomePageRoute({ children }: {
5
+ children: React.ReactNode;
6
+ }) {
7
+
8
+ const breadcrumbs = useBreadcrumbsController();
9
+
10
+ useEffect(() => {
11
+ breadcrumbs.set({
12
+ breadcrumbs: []
13
+ });
14
+ }, []);
15
+
16
+ return children;
17
+ }
@@ -84,6 +84,11 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
84
84
  */
85
85
  properties: PropertiesOrBuilders<M>;
86
86
 
87
+ /**
88
+ * Default preview properties displayed when this collection is referenced to.
89
+ */
90
+ previewProperties?: string[];
91
+
87
92
  /**
88
93
  * Title property of the entity. This is the property that will be used
89
94
  * as the title in entity related views and references.
@@ -92,11 +97,10 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
92
97
  titleProperty?: keyof M;
93
98
 
94
99
  /**
95
- * Can this collection be edited by the end user.
96
- * Defaults to `true`.
97
- * Keep in mind that you can also set this prop to individual properties.
100
+ * When editing an entity, you can choose to open the entity in a side dialog
101
+ * or in a full screen dialog. Defaults to `full_screen`.
98
102
  */
99
- editable?: boolean;
103
+ openEntityMode?: "side_panel" | "full_screen";
100
104
 
101
105
  /**
102
106
  * Order in which the properties are displayed.
@@ -119,7 +123,7 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
119
123
  * `hidden` in the property definition,will be ignored.
120
124
  * `propertiesOrder` has precedence over `hidden`.
121
125
  */
122
- propertiesOrder?: (Extract<keyof M, string> | `subcollection:${string}`)[];
126
+ propertiesOrder?: (Extract<keyof M, string> | string | `subcollection:${string}` | "collectionGroupParent")[];
123
127
 
124
128
  /**
125
129
  * If enabled, content is loaded in batches. If `false` all entities in the
@@ -313,9 +317,19 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
313
317
  sideDialogWidth?: number | string;
314
318
 
315
319
  /**
316
- * Default preview properties displayed when this collection is referenced to.
320
+ * Can this collection configuration be edited by the end user.
321
+ * Defaults to `true`.
322
+ * Keep in mind that you can also set this prop to individual properties.
323
+ * This prop has only effect if you are using the collection editor.
317
324
  */
318
- previewProperties?: string[];
325
+ editable?: boolean;
326
+
327
+ /**
328
+ * If set to true, the default values of the properties will be applied
329
+ * to the entity every time the entity is updated (not only when created).
330
+ * Defaults to false.
331
+ */
332
+ alwaysApplyDefaultValues?: boolean;
319
333
  }
320
334
 
321
335
  /**
@@ -491,21 +505,26 @@ export type EntityCustomView<M extends Record<string, any> = any> =
491
505
  /**
492
506
  * Key of this custom view.
493
507
  */
494
- key: string,
508
+ key: string;
509
+
495
510
  /**
496
511
  * Name of this custom view.
497
512
  */
498
- name: string,
513
+ name: string;
514
+
499
515
  /**
500
- * If set to true, the actions of the entity will be included in the
501
- * bottom of the panel (save buttons, delete buttons, etc.)
516
+ * If set to true, the actions of the entity (save, discard,delete) will be
517
+ * included in the view. By default the actions are located in the right or bottom,
518
+ * based on the screen size. You can force the actions to be located at the bottom
519
+ * by setting this prop to "bottom".
502
520
  */
503
- includeActions?: boolean;
521
+ includeActions?: boolean | "bottom";
522
+
504
523
  /**
505
524
  * Builder for rendering the custom view
506
525
  */
507
526
  Builder?: React.ComponentType<EntityCustomViewParams<M>>;
508
- }
527
+ };
509
528
 
510
529
  /**
511
530
  * Parameters passed to the builder in charge of rendering a custom panel for
@@ -570,6 +589,12 @@ export type EntityTableController<M extends Record<string, any> = any> = {
570
589
  clearFilter?: () => void;
571
590
  itemCount?: number;
572
591
  setItemCount?: (itemCount: number) => void;
592
+ initialScroll?: number;
593
+ onScroll?: (props: {
594
+ scrollDirection: "forward" | "backward",
595
+ scrollOffset: number,
596
+ scrollUpdateWasRequested: boolean
597
+ }) => void;
573
598
  paginationEnabled?: boolean;
574
599
  pageSize?: number;
575
600
  checkFilterCombination?: (filterValues: FilterValues<any>,
@@ -9,6 +9,7 @@ import { FireCMSContext } from "./firecms_context";
9
9
  export interface FetchEntityProps<M extends Record<string, any> = any> {
10
10
  path: string;
11
11
  entityId: string;
12
+ databaseId?: string;
12
13
  collection?: EntityCollection<M, any>
13
14
  }
14
15
 
@@ -18,7 +19,6 @@ export interface FetchEntityProps<M extends Record<string, any> = any> {
18
19
  export type ListenEntityProps<M extends Record<string, any> = any> =
19
20
  FetchEntityProps<M>
20
21
  & {
21
- databaseId?: string;
22
22
  onUpdate: (entity: Entity<M>) => void,
23
23
  onError?: (error: Error) => void,
24
24
  }
@@ -139,6 +139,7 @@ export interface DataSource {
139
139
  fetchEntity<M extends Record<string, any> = any>({
140
140
  path,
141
141
  entityId,
142
+ databaseId,
142
143
  collection
143
144
  }: FetchEntityProps<M>
144
145
  ): Promise<Entity<M> | undefined>;
@@ -15,19 +15,23 @@ export interface DialogsController {
15
15
  * Open a dialog
16
16
  * @param props
17
17
  */
18
- open: (props: DialogControllerEntryProps) => { closeDialog: () => void };
18
+ open: <T extends object = object>(props: DialogControllerEntryProps<T>) => { closeDialog: () => void };
19
19
  }
20
20
 
21
21
  /**
22
22
  * Props used to open a side dialog
23
23
  * @group Hooks and utilities
24
24
  */
25
- export interface DialogControllerEntryProps {
25
+ export interface DialogControllerEntryProps<T extends object = object> {
26
26
 
27
27
  key: string;
28
28
  /**
29
29
  * The component type that will be rendered
30
30
  */
31
- Component: React.ComponentType<{ open: boolean, closeDialog: () => void }>;
31
+ Component: React.ComponentType<{ open: boolean, closeDialog: () => void } & T>;
32
+ /**
33
+ * Props to pass to the dialog component
34
+ */
35
+ props?: T;
32
36
 
33
37
  }
@@ -8,7 +8,7 @@ export type EntityStatus = "new" | "existing" | "copy";
8
8
  * Representation of an entity fetched from the datasource
9
9
  * @group Models
10
10
  */
11
- export interface Entity<M extends object> {
11
+ export interface Entity<M extends object = any> {
12
12
 
13
13
  /**
14
14
  * ID of the entity
@@ -15,6 +15,16 @@ export type EntityAction<M extends object = any, USER extends User = User> = {
15
15
  */
16
16
  name: string;
17
17
 
18
+ /**
19
+ * Key of the action. You only need to provide this if you want to
20
+ * override the default actions.
21
+ * The default actions are:
22
+ * - edit
23
+ * - delete
24
+ * - copy
25
+ */
26
+ key?: string;
27
+
18
28
  /**
19
29
  * Icon of the action
20
30
  */
@@ -53,4 +63,6 @@ export type EntityActionClickProps<M extends object, USER extends User = User> =
53
63
  * If this actions is being called from a side dialog
54
64
  */
55
65
  sideEntityController?: SideEntityController;
66
+
67
+ openEntityMode: "side_panel" | "full_screen";
56
68
  };
@@ -1,6 +1,7 @@
1
1
  import { CMSType, Property, PropertyOrBuilder } from "./properties";
2
2
  import { ResolvedEntityCollection, ResolvedProperty } from "./resolved_entities";
3
3
  import { FormexController } from "@firecms/formex";
4
+ import { Entity } from "./entities";
4
5
 
5
6
  /**
6
7
  * When building a custom field you need to create a React component that takes
@@ -81,7 +82,8 @@ export interface FieldProps<T extends CMSType = any, CustomProps = any, M extend
81
82
  partOfArray?: boolean;
82
83
 
83
84
  /**
84
- * Should this field render with the minimal amount of UI elements
85
+ * Display the child properties directly, without being wrapped in an
86
+ * extendable panel. Note that this will also hide the title of this property.
85
87
  */
86
88
  minimalistView?: boolean;
87
89
 
@@ -160,6 +162,14 @@ export interface FormContext<M extends Record<string, any> = any> {
160
162
  */
161
163
  path?: string;
162
164
 
165
+ status: "new" | "existing" | "copy";
166
+
167
+ entity?: Entity<M>;
168
+
169
+ savingError?: Error;
170
+
171
+ openEntityMode: "side_panel" | "full_screen";
172
+
163
173
  /**
164
174
  * This is the underlying formex controller that powers the form
165
175
  */
@@ -207,7 +217,8 @@ export interface PropertyFieldBindingProps<T extends CMSType, M extends Record<s
207
217
  partOfArray?: boolean;
208
218
 
209
219
  /**
210
- * Is this field part of a block (oneOf array)
220
+ * Display the child properties directly, without being wrapped in an
221
+ * extendable panel. Note that this will also hide the title of this property.
211
222
  */
212
223
  minimalistView?: boolean;
213
224
 
@@ -5,6 +5,7 @@ import { EntityReference } from "./entities";
5
5
  /**
6
6
  * Controller that includes the resolved navigation and utility methods and
7
7
  * attributes.
8
+ * This controller holds the state of the navigation including the collections.
8
9
  * @group Models
9
10
  */
10
11
  export type NavigationController<EC extends EntityCollection = EntityCollection<any>> = {
@@ -56,8 +57,8 @@ export type NavigationController<EC extends EntityCollection = EntityCollection<
56
57
  * Get the collection configuration for a given path.
57
58
  * The collection is resolved from the given path or alias.
58
59
  */
59
- getCollection: (pathOrId: string,
60
- includeUserOverride?: boolean) => EC | undefined;
60
+ getCollection: (pathOrId: string, includeUserOverride?: boolean) => EC | undefined;
61
+
61
62
  /**
62
63
  * Get the collection configuration from its parent ids.
63
64
  */
@@ -69,12 +70,14 @@ export type NavigationController<EC extends EntityCollection = EntityCollection<
69
70
  getCollectionFromPaths: (pathSegments: string[]) => EC | undefined;
70
71
 
71
72
  /**
72
- * Default path under the navigation routes of the CMS will be created
73
+ * Default path under the navigation routes of the CMS will be created.
74
+ * Defaults to '/'. You may want to change this `basepath` to 'admin' for example.
73
75
  */
74
76
  basePath: string;
75
77
 
76
78
  /**
77
- * Default path under the collection routes of the CMS will be created
79
+ * Default path under the collection routes of the CMS will be created.
80
+ * It defaults to '/c'
78
81
  */
79
82
  baseCollectionPath: string;
80
83
 
@@ -87,16 +90,6 @@ export type NavigationController<EC extends EntityCollection = EntityCollection<
87
90
  */
88
91
  urlPathToDataPath: (cmsPath: string) => string;
89
92
 
90
- /**
91
- * Convert a collection or entity path to a URL path
92
- * @param path
93
- */
94
- buildCMSUrlPath: (path: string) => string;
95
-
96
- buildUrlEditCollectionPath: (props: {
97
- path: string
98
- }) => string;
99
-
100
93
  /**
101
94
  * Base url path for the home screen
102
95
  */
@@ -117,10 +110,11 @@ export type NavigationController<EC extends EntityCollection = EntityCollection<
117
110
  buildUrlCollectionPath: (path: string) => string;
118
111
 
119
112
  /**
120
- * Turn a path with aliases into a resolved path
113
+ * Turn a path with collection ids into a resolved path.
114
+ * The ids (typically used in urls) will be replaced with relative paths (typically used in database paths)
121
115
  * @param pathWithAliases
122
116
  */
123
- resolveAliasesFrom: (pathWithAliases: string) => string;
117
+ resolveIdsFrom: (pathWithAliases: string) => string;
124
118
 
125
119
  /**
126
120
  * Call this method to recalculate the navigation
@@ -144,8 +138,34 @@ export type NavigationController<EC extends EntityCollection = EntityCollection<
144
138
  * @param ids
145
139
  */
146
140
  convertIdsToPaths: (ids: string[]) => string[];
141
+
142
+ /**
143
+ * A function to navigate to a specified route or URL.
144
+ *
145
+ * @param {string} to - The target route or URL to navigate to.
146
+ * @param {NavigateOptions} [options] - Optional configuration settings for navigation, such as replace behavior or state data.
147
+ */
148
+ navigate: (to: string, options?: NavigateOptions) => void;
149
+
147
150
  }
148
151
 
152
+ export interface NavigateOptions {
153
+ replace?: boolean;
154
+ state?: any;
155
+ preventScrollReset?: boolean;
156
+ relative?: "route" | "path";
157
+ flushSync?: boolean;
158
+ viewTransition?: boolean;
159
+ }
160
+
161
+ // currently not used, in favor of a single blocker in `FireCMSRoute`
162
+ export type NavigationBlocker = {
163
+ updateBlockListener: (path: string, block: boolean, basePath?: string) => () => void;
164
+ isBlocked: (path: string) => boolean;
165
+ proceed?: () => void;
166
+ reset?: () => void;
167
+ };
168
+
149
169
  /**
150
170
  * Custom additional views created by the developer, added to the main
151
171
  * navigation.
@@ -195,6 +195,7 @@ export interface PluginFormActionProps<USER extends User = User, EC extends Enti
195
195
  formContext?: FormContext<any>;
196
196
  context: FireCMSContext<USER>;
197
197
  currentEntityId?: string;
198
+ openEntityMode: "side_panel" | "full_screen";
198
199
  }
199
200
 
200
201
  export type PluginFieldBuilderParams<T extends CMSType = CMSType, M extends Record<string, any> = any, EC extends EntityCollection<M> = EntityCollection<M>> = {
@@ -156,6 +156,12 @@ export interface BaseProperty<T extends CMSType, CustomProps = any> {
156
156
  * save the new config. The saved config will then become the source of truth.
157
157
  */
158
158
  editable?: boolean;
159
+
160
+ /**
161
+ * A number between 0 and 100 that indicates the width of the field in the form view.
162
+ * It defaults to 100, but you can set it to 50 to have two fields in the same row.
163
+ */
164
+ widthPercentage?: number;
159
165
  }
160
166
 
161
167
  /**
@@ -285,14 +291,14 @@ export type PropertyBuilder<T extends CMSType = any, M extends Record<string, an
285
291
  /**
286
292
  * @group Entity properties
287
293
  */
288
- export type PropertyOrBuilder<T extends CMSType = CMSType, M extends Record<string, any> = Record<string, any>> =
294
+ export type PropertyOrBuilder<T extends CMSType = CMSType, M extends Record<string, any> = any> =
289
295
  Property<T>
290
296
  | PropertyBuilder<T, M>;
291
297
 
292
298
  /**
293
299
  * @group Entity properties
294
300
  */
295
- export type PropertiesOrBuilders<M extends Record<string, any> = Record<string, any>> =
301
+ export type PropertiesOrBuilders<M extends Record<string, any> = any> =
296
302
  {
297
303
  [k in keyof M]: PropertyOrBuilder<M[k], M>;
298
304
  };
@@ -371,7 +377,7 @@ export interface StringProperty extends BaseProperty<string> {
371
377
 
372
378
  /**
373
379
  * You can specify a `Storage` configuration. It is used to
374
- * indicate that this string refers to a path in Google Cloud Storage.
380
+ * indicate that this string refers to a path in your storage provider.
375
381
  */
376
382
  storage?: StorageConfig;
377
383
 
@@ -469,6 +475,12 @@ export interface ArrayProperty<T extends ArrayT[] = any[], ArrayT extends CMSTyp
469
475
  */
470
476
  expanded?: boolean;
471
477
 
478
+ /**
479
+ * Display the child properties directly, without being wrapped in an
480
+ * extendable panel.
481
+ */
482
+ minimalistView?: boolean;
483
+
472
484
  }
473
485
 
474
486
  /**
@@ -517,6 +529,12 @@ export interface MapProperty<T extends Record<string, CMSType> = Record<string,
517
529
  */
518
530
  spreadChildren?: boolean;
519
531
 
532
+ /**
533
+ * Display the child properties directly, without being wrapped in an
534
+ * extendable panel. Note that this will also hide the title of this property.
535
+ */
536
+ minimalistView?: boolean;
537
+
520
538
  /**
521
539
  * Should the field be initially expanded. Defaults to `true`
522
540
  */
@@ -1,4 +1,5 @@
1
1
  import React from "react";
2
+ import { EntityFormProps } from "../form";
2
3
 
3
4
  /**
4
5
  * Controller to open the side dialog
@@ -78,4 +79,5 @@ export interface SideDialogPanelProps {
78
79
  * Use this prop to store additional data in the panel
79
80
  */
80
81
  additional?: any;
82
+
81
83
  }