@firecms/core 3.0.0-beta.8 → 3.0.0-beta.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 (190) hide show
  1. package/dist/app/Drawer.d.ts +1 -1
  2. package/dist/app/Scaffold.d.ts +1 -1
  3. package/dist/components/ArrayContainer.d.ts +2 -1
  4. package/dist/components/CircularProgressCenter.d.ts +1 -1
  5. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +0 -1
  6. package/dist/components/EntityCollectionTable/fields/TableReferenceField.d.ts +1 -1
  7. package/dist/components/EntityCollectionTable/internal/popup_field/PopupFormField.d.ts +1 -1
  8. package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +1 -1
  9. package/dist/components/EntityPreview.d.ts +1 -1
  10. package/dist/components/ErrorView.d.ts +1 -1
  11. package/dist/components/HomePage/DefaultHomePage.d.ts +1 -1
  12. package/dist/components/HomePage/NavigationCardBinding.d.ts +1 -1
  13. package/dist/components/PropertyIdCopyTooltip.d.ts +8 -0
  14. package/dist/components/VirtualTable/VirtualTableProps.d.ts +10 -6
  15. package/dist/components/common/useColumnsIds.d.ts +2 -1
  16. package/dist/components/index.d.ts +1 -0
  17. package/dist/core/DefaultAppBar.d.ts +1 -1
  18. package/dist/core/DefaultDrawer.d.ts +1 -1
  19. package/dist/core/DrawerNavigationItem.d.ts +2 -1
  20. package/dist/core/EntityEditView.d.ts +3 -3
  21. package/dist/core/FireCMS.d.ts +1 -1
  22. package/dist/core/NavigationRoutes.d.ts +1 -1
  23. package/dist/form/PropertyFieldBinding.d.ts +1 -1
  24. package/dist/form/components/FormikArrayContainer.d.ts +2 -1
  25. package/dist/form/components/LabelWithIcon.d.ts +1 -1
  26. package/dist/form/components/LabelWithIconAndTooltip.d.ts +15 -0
  27. package/dist/form/components/index.d.ts +1 -0
  28. package/dist/form/field_bindings/ArrayCustomShapedFieldBinding.d.ts +1 -1
  29. package/dist/form/field_bindings/ArrayOfReferencesFieldBinding.d.ts +1 -1
  30. package/dist/form/field_bindings/BlockFieldBinding.d.ts +1 -1
  31. package/dist/form/field_bindings/KeyValueFieldBinding.d.ts +1 -1
  32. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  33. package/dist/form/field_bindings/MarkdownEditorFieldBinding.d.ts +11 -0
  34. package/dist/form/field_bindings/{MultiSelectBinding.d.ts → MultiSelectFieldBinding.d.ts} +1 -1
  35. package/dist/form/field_bindings/ReadOnlyFieldBinding.d.ts +1 -1
  36. package/dist/form/field_bindings/RepeatFieldBinding.d.ts +1 -1
  37. package/dist/form/field_bindings/SelectFieldBinding.d.ts +1 -1
  38. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +1 -1
  39. package/dist/form/field_bindings/TextFieldBinding.d.ts +1 -1
  40. package/dist/form/index.d.ts +3 -3
  41. package/dist/form/useClearRestoreValue.d.ts +2 -2
  42. package/dist/hooks/useProjectLog.d.ts +2 -2
  43. package/dist/index.es.js +14127 -11014
  44. package/dist/index.es.js.map +1 -1
  45. package/dist/index.umd.js +19987 -587
  46. package/dist/index.umd.js.map +1 -1
  47. package/dist/preview/PropertyPreviewProps.d.ts +1 -1
  48. package/dist/preview/components/EnumValuesChip.d.ts +1 -1
  49. package/dist/preview/components/ReferencePreview.d.ts +1 -1
  50. package/dist/types/auth.d.ts +1 -1
  51. package/dist/types/collections.d.ts +12 -3
  52. package/dist/types/datasource.d.ts +35 -22
  53. package/dist/types/entities.d.ts +1 -0
  54. package/dist/types/entity_overrides.d.ts +2 -2
  55. package/dist/types/fields.d.ts +20 -15
  56. package/dist/types/navigation.d.ts +1 -0
  57. package/dist/types/properties.d.ts +18 -18
  58. package/dist/types/side_dialogs_controller.d.ts +10 -0
  59. package/dist/types/storage.d.ts +75 -0
  60. package/dist/util/entities.d.ts +1 -1
  61. package/dist/util/icon_list.d.ts +5 -1
  62. package/dist/util/icons.d.ts +1 -0
  63. package/dist/util/index.d.ts +1 -0
  64. package/dist/util/plurals.d.ts +0 -2
  65. package/dist/util/property_utils.d.ts +1 -1
  66. package/dist/util/resolutions.d.ts +15 -1
  67. package/dist/util/storage.d.ts +1 -1
  68. package/dist/util/useStorageUploadController.d.ts +2 -2
  69. package/package.json +15 -17
  70. package/src/app/Drawer.tsx +1 -1
  71. package/src/app/Scaffold.tsx +22 -27
  72. package/src/components/ArrayContainer.tsx +15 -10
  73. package/src/components/CircularProgressCenter.tsx +1 -1
  74. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +4 -9
  75. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +2 -2
  76. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +4 -2
  77. package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +21 -14
  78. package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +12 -4
  79. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +17 -19
  80. package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +19 -7
  81. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +3 -5
  82. package/src/components/EntityCollectionView/EntityCollectionView.tsx +26 -25
  83. package/src/components/EntityCollectionView/useSelectionController.tsx +19 -7
  84. package/src/components/EntityPreview.tsx +30 -31
  85. package/src/components/ErrorView.tsx +1 -1
  86. package/src/components/HomePage/DefaultHomePage.tsx +24 -18
  87. package/src/components/HomePage/NavigationCardBinding.tsx +1 -1
  88. package/src/components/HomePage/SmallNavigationCard.tsx +1 -2
  89. package/src/components/PropertyIdCopyTooltip.tsx +48 -0
  90. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +7 -6
  91. package/src/components/SearchIconsView.tsx +5 -2
  92. package/src/components/SelectableTable/SelectableTable.tsx +2 -4
  93. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +1 -1
  94. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +54 -7
  95. package/src/components/VirtualTable/VirtualTable.tsx +33 -9
  96. package/src/components/VirtualTable/VirtualTableCell.tsx +1 -9
  97. package/src/components/VirtualTable/VirtualTableProps.tsx +12 -8
  98. package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +3 -3
  99. package/src/components/VirtualTable/fields/VirtualTableInput.tsx +2 -1
  100. package/src/components/VirtualTable/fields/VirtualTableNumberInput.tsx +2 -1
  101. package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +14 -28
  102. package/src/components/common/useColumnsIds.tsx +13 -0
  103. package/src/components/common/useDataSourceEntityCollectionTableController.tsx +12 -12
  104. package/src/components/common/useTableSearchHelper.ts +1 -0
  105. package/src/components/index.tsx +1 -0
  106. package/src/core/DefaultAppBar.tsx +3 -3
  107. package/src/core/DefaultDrawer.tsx +18 -12
  108. package/src/core/DrawerNavigationItem.tsx +31 -27
  109. package/src/core/EntityEditView.tsx +136 -109
  110. package/src/core/FireCMS.tsx +2 -2
  111. package/src/core/NavigationRoutes.tsx +1 -1
  112. package/src/core/SideDialogs.tsx +1 -0
  113. package/src/core/field_configs.tsx +5 -5
  114. package/src/form/PropertyFieldBinding.tsx +24 -14
  115. package/src/form/components/CustomIdField.tsx +4 -2
  116. package/src/form/components/FieldHelperText.tsx +1 -1
  117. package/src/form/components/FormikArrayContainer.tsx +4 -1
  118. package/src/form/components/LabelWithIcon.tsx +27 -19
  119. package/src/form/components/LabelWithIconAndTooltip.tsx +28 -0
  120. package/src/form/components/StorageItemPreview.tsx +1 -0
  121. package/src/form/components/StorageUploadProgress.tsx +0 -1
  122. package/src/form/components/index.tsx +1 -0
  123. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +22 -14
  124. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +24 -22
  125. package/src/form/field_bindings/BlockFieldBinding.tsx +13 -11
  126. package/src/form/field_bindings/DateTimeFieldBinding.tsx +17 -14
  127. package/src/form/field_bindings/KeyValueFieldBinding.tsx +8 -7
  128. package/src/form/field_bindings/MapFieldBinding.tsx +16 -24
  129. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +150 -0
  130. package/src/form/field_bindings/{MultiSelectBinding.tsx → MultiSelectFieldBinding.tsx} +25 -20
  131. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +9 -7
  132. package/src/form/field_bindings/ReferenceFieldBinding.tsx +27 -18
  133. package/src/form/field_bindings/RepeatFieldBinding.tsx +27 -17
  134. package/src/form/field_bindings/SelectFieldBinding.tsx +17 -10
  135. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +36 -17
  136. package/src/form/field_bindings/SwitchFieldBinding.tsx +9 -5
  137. package/src/form/field_bindings/TextFieldBinding.tsx +26 -23
  138. package/src/form/index.tsx +4 -9
  139. package/src/form/useClearRestoreValue.tsx +2 -2
  140. package/src/hooks/data/delete.ts +2 -1
  141. package/src/hooks/data/save.ts +5 -2
  142. package/src/hooks/data/useDataSource.tsx +11 -3
  143. package/src/hooks/useBuildNavigationController.tsx +10 -3
  144. package/src/hooks/useProjectLog.tsx +18 -7
  145. package/src/internal/useBuildDataSource.ts +59 -76
  146. package/src/internal/useBuildSideDialogsController.tsx +1 -0
  147. package/src/internal/useBuildSideEntityController.tsx +17 -4
  148. package/src/internal/useUnsavedChangesDialog.tsx +3 -1
  149. package/src/preview/PropertyPreview.tsx +2 -2
  150. package/src/preview/PropertyPreviewProps.tsx +1 -1
  151. package/src/preview/components/BooleanPreview.tsx +1 -1
  152. package/src/preview/components/EnumValuesChip.tsx +1 -1
  153. package/src/preview/components/ImagePreview.tsx +4 -2
  154. package/src/preview/components/ReferencePreview.tsx +2 -13
  155. package/src/preview/components/UrlComponentPreview.tsx +1 -1
  156. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +1 -1
  157. package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +1 -1
  158. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +1 -1
  159. package/src/preview/property_previews/ArrayOneOfPreview.tsx +2 -2
  160. package/src/preview/property_previews/ArrayPropertyPreview.tsx +1 -1
  161. package/src/preview/property_previews/MapPropertyPreview.tsx +1 -1
  162. package/src/preview/property_previews/SkeletonPropertyComponent.tsx +2 -2
  163. package/src/preview/property_previews/StringPropertyPreview.tsx +2 -2
  164. package/src/preview/util.ts +2 -2
  165. package/src/types/auth.tsx +1 -1
  166. package/src/types/collections.ts +15 -4
  167. package/src/types/datasource.ts +42 -27
  168. package/src/types/entities.ts +2 -0
  169. package/src/types/entity_overrides.tsx +2 -2
  170. package/src/types/fields.tsx +23 -17
  171. package/src/types/navigation.ts +1 -0
  172. package/src/types/properties.ts +18 -17
  173. package/src/types/side_dialogs_controller.tsx +13 -0
  174. package/src/types/storage.ts +82 -0
  175. package/src/util/entities.ts +1 -1
  176. package/src/util/icon_list.ts +14 -9
  177. package/src/util/icons.tsx +8 -2
  178. package/src/util/index.ts +1 -0
  179. package/src/util/plurals.ts +0 -2
  180. package/src/util/property_utils.tsx +1 -1
  181. package/src/util/references.ts +3 -0
  182. package/src/util/resolutions.ts +43 -11
  183. package/src/util/storage.ts +6 -2
  184. package/src/util/useStorageUploadController.tsx +15 -7
  185. package/dist/components/PropertyIdCopyTooltipContent.d.ts +0 -3
  186. package/dist/form/PropertiesForm.d.ts +0 -8
  187. package/dist/form/field_bindings/MarkdownFieldBinding.d.ts +0 -9
  188. package/src/components/PropertyIdCopyTooltipContent.tsx +0 -27
  189. package/src/form/PropertiesForm.tsx +0 -81
  190. package/src/form/field_bindings/MarkdownFieldBinding.tsx +0 -695
@@ -7,6 +7,7 @@ export function DrawerNavigationItem({
7
7
  name,
8
8
  icon,
9
9
  drawerOpen,
10
+ adminMenuOpen,
10
11
  tooltipsOpen,
11
12
  url,
12
13
  onClick
@@ -15,6 +16,7 @@ export function DrawerNavigationItem({
15
16
  name: string,
16
17
  tooltipsOpen: boolean,
17
18
  drawerOpen: boolean,
19
+ adminMenuOpen?: boolean,
18
20
  url: string,
19
21
  onClick?: () => void,
20
22
  }) {
@@ -24,37 +26,39 @@ export function DrawerNavigationItem({
24
26
  {icon}
25
27
  </div>;
26
28
 
27
- const listItem = <NavLink
28
- onClick={onClick}
29
- style={{
30
- width: !drawerOpen ? "72px" : "280px",
31
- transition: drawerOpen ? "width 150ms ease-in" : undefined
32
- }}
33
- className={({ isActive }: any) => cls("rounded-r-lg truncate",
34
- "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",
35
- "flex flex-row items-center mr-8",
36
- // "transition-all ease-in-out delay-100 duration-300",
37
- // drawerOpen ? "w-full" : "w-18",
38
- drawerOpen ? "pl-8 h-12" : "pl-6 h-11",
39
- "font-medium text-sm",
40
- isActive ? "bg-slate-200 bg-opacity-60 dark:bg-gray-800 dark:bg-opacity-30" : ""
41
- )}
42
- to={url}
43
- >
29
+ const listItem = <div>
30
+ <NavLink
31
+ onClick={onClick}
32
+ style={{
33
+ width: "100%",
34
+ transition: drawerOpen ? "width 150ms ease-in" : undefined
35
+ }}
36
+ className={({ isActive }: any) => cls("rounded-lg truncate",
37
+ "hover:bg-slate-300 hover:bg-opacity-75 dark:hover:bg-slate-800 dark:hover:bg-opacity-75 text-gray-800 dark:text-gray-200 hover:text-gray-900 hover:dark:text-white",
38
+ "flex flex-row items-center mr-8",
39
+ // "transition-all ease-in-out delay-100 duration-300",
40
+ // drawerOpen ? "w-full" : "w-18",
41
+ drawerOpen ? "pl-4 h-12" : "pl-4 h-11",
42
+ "font-medium text-sm",
43
+ isActive ? "bg-slate-200 bg-opacity-60 dark:bg-gray-800 dark:bg-opacity-50" : ""
44
+ )}
45
+ to={url}
46
+ >
44
47
 
45
- {iconWrap}
48
+ {iconWrap}
46
49
 
47
- <div
48
- className={cls(
49
- drawerOpen ? "opacity-100" : "opacity-0 hidden",
50
- "ml-4 font-inherit text-inherit"
51
- )}>
52
- {name.toUpperCase()}
53
- </div>
54
- </NavLink>;
50
+ <div
51
+ className={cls(
52
+ drawerOpen ? "opacity-100" : "opacity-0 hidden",
53
+ "ml-4 font-inherit text-inherit"
54
+ )}>
55
+ {name.toUpperCase()}
56
+ </div>
57
+ </NavLink>
58
+ </div>;
55
59
 
56
60
  return <Tooltip
57
- open={drawerOpen ? false : tooltipsOpen}
61
+ open={drawerOpen || adminMenuOpen ? false : tooltipsOpen}
58
62
  side="right"
59
63
  title={name}>
60
64
  {listItem}
@@ -23,6 +23,7 @@ import {
23
23
  EntityCollectionView,
24
24
  EntityView,
25
25
  ErrorBoundary,
26
+ getFormFieldKeys,
26
27
  } from "../components";
27
28
  import {
28
29
  canCreateEntity,
@@ -59,9 +60,10 @@ import {
59
60
  defaultBorderMixin,
60
61
  DialogActions,
61
62
  IconButton,
63
+ NotesIcon,
64
+ paperMixin,
62
65
  Tab,
63
66
  Tabs,
64
- Tooltip,
65
67
  Typography
66
68
  } from "@firecms/ui";
67
69
  import { useSideDialogContext } from "./index";
@@ -70,8 +72,7 @@ import { useAnalyticsController } from "../hooks/useAnalyticsController";
70
72
  import { CustomIdField } from "../form/components/CustomIdField";
71
73
  import { CustomFieldValidator, getYupEntitySchema } from "../form/validation";
72
74
  import { ErrorFocus } from "../form/components/ErrorFocus";
73
- import { PropertyIdCopyTooltipContent } from "../components/PropertyIdCopyTooltipContent";
74
- import { PropertyFieldBinding } from "../form";
75
+ import { LabelWithIconAndTooltip, PropertyFieldBinding } from "../form";
75
76
  import { ValidationError } from "yup";
76
77
 
77
78
  const MAIN_TAB_VALUE = "main_##Q$SC^#S6";
@@ -92,10 +93,10 @@ export interface EntityEditViewProps<M extends Record<string, any>> {
92
93
  * This is the default view that is used as the content of a side panel when
93
94
  * an entity is opened.
94
95
  * You probably don't want to use this view directly since it is bound to the
95
- * side panel. Instead, you might want to use {@link EntityForm} or {@link EntityCollectionView}
96
+ * side panel.
96
97
  */
97
98
  export function EntityEditView<M extends Record<string, any>, UserType extends User>({
98
- entityId: entityIdProp,
99
+ entityId,
99
100
  ...props
100
101
  }: EntityEditViewProps<M>) {
101
102
  const {
@@ -105,7 +106,7 @@ export function EntityEditView<M extends Record<string, any>, UserType extends U
105
106
  dataLoadingError
106
107
  } = useEntityFetch<M, UserType>({
107
108
  path: props.path,
108
- entityId: entityIdProp,
109
+ entityId: entityId,
109
110
  collection: props.collection,
110
111
  useCache: false
111
112
  });
@@ -114,8 +115,12 @@ export function EntityEditView<M extends Record<string, any>, UserType extends U
114
115
  return <CircularProgressCenter/>
115
116
  }
116
117
 
118
+ if (entityId && !entity) {
119
+ console.error(`Entity with id ${entityId} not found in collection ${props.collection.path}`);
120
+ }
121
+
117
122
  return <EntityEditViewInner<M> {...props}
118
- entityId={entityIdProp}
123
+ entityId={entityId}
119
124
  entity={entity}
120
125
  dataLoading={dataLoading}/>;
121
126
  }
@@ -131,7 +136,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
131
136
  onUpdate,
132
137
  onClose,
133
138
  entity,
134
- dataLoading,
139
+ dataLoading
135
140
  }: EntityEditViewProps<M> & {
136
141
  entity?: Entity<M>,
137
142
  dataLoading: boolean
@@ -185,14 +190,16 @@ export function EntityEditViewInner<M extends Record<string, any>>({
185
190
 
186
191
  const initialStatus = copy ? "copy" : (entityIdProp ? "existing" : "new");
187
192
  const [status, setStatus] = useState<EntityStatus>(initialStatus);
193
+
188
194
  const mustSetCustomId: boolean = (status === "new" || status === "copy") &&
189
195
  (Boolean(initialResolvedCollection.customId) && initialResolvedCollection.customId !== "optional");
196
+
190
197
  const initialEntityId: string | undefined = useMemo((): string | undefined => {
191
198
  if (status === "new" || status === "copy") {
192
199
  if (mustSetCustomId) {
193
200
  return undefined;
194
201
  } else {
195
- return dataSource.generateEntityId(path);
202
+ return dataSource.generateEntityId(path, collection);
196
203
  }
197
204
  } else {
198
205
  return entityIdProp;
@@ -224,16 +231,9 @@ export function EntityEditViewInner<M extends Record<string, any>>({
224
231
  }
225
232
  );
226
233
 
227
- const selectedTabRef = useRef<string>(defaultSelectedView ?? MAIN_TAB_VALUE);
228
- const baseDataSourceValuesRef = useRef<Partial<EntityValues<M>>>(getDataSourceEntityValues(initialResolvedCollection, status, entity));
229
-
230
- const mainViewVisible = selectedTabRef.current === MAIN_TAB_VALUE;
234
+ const [selectedTab, setSelectedTab] = useState<string>(defaultSelectedView ?? MAIN_TAB_VALUE);
231
235
 
232
- // const initialValuesRef = useRef<EntityValues<M>>(entity?.values ?? baseDataSourceValues as EntityValues<M>);
233
- // const [internalValues, setInternalValues] = useState<EntityValues<M> | undefined>(entity?.values ?? baseDataSourceValuesRef.current as EntityValues<M>);
234
-
235
- // const modifiedValuesRef = useRef<EntityValues<M> | undefined>(undefined);
236
- // const modifiedValues = modifiedValuesRef.current;
236
+ const mainViewVisible = selectedTab === MAIN_TAB_VALUE;
237
237
 
238
238
  const subcollections = (collection.subcollections ?? []).filter(c => !c.hideFromNavigation);
239
239
  const subcollectionsCount = subcollections?.length ?? 0;
@@ -246,6 +246,8 @@ export function EntityEditViewInner<M extends Record<string, any>>({
246
246
  const [usedEntity, setUsedEntity] = useState<Entity<M> | undefined>(entity);
247
247
  const [readOnly, setReadOnly] = useState<boolean | undefined>(undefined);
248
248
 
249
+ const baseDataSourceValuesRef = useRef<Partial<EntityValues<M>>>(getDataSourceEntityValues(initialResolvedCollection, status, usedEntity));
250
+
249
251
  useEffect(() => {
250
252
  if (entity)
251
253
  setUsedEntity(entity);
@@ -297,7 +299,6 @@ export function EntityEditViewInner<M extends Record<string, any>>({
297
299
  onUpdate({ entity: updatedEntity });
298
300
 
299
301
  if (closeAfterSave) {
300
- console.log("Closing side dialog")
301
302
  sideDialogContext.setBlocked(false);
302
303
  sideDialogContext.close(true);
303
304
  onClose?.();
@@ -305,7 +306,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
305
306
  sideEntityController.replace({
306
307
  path,
307
308
  entityId: updatedEntity.id,
308
- selectedSubPath: selectedTabRef.current,
309
+ selectedSubPath: MAIN_TAB_VALUE === selectedTab ? undefined : selectedTab,
309
310
  updateUrl: true,
310
311
  collection,
311
312
  });
@@ -478,7 +479,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
478
479
  setFieldValue: useCallback(formex.setFieldValue, []),
479
480
  values: formex.values,
480
481
  collection: resolvedCollection,
481
- entityId,
482
+ entityId: entityId as string,
482
483
  path,
483
484
  save,
484
485
  formex
@@ -489,15 +490,15 @@ export function EntityEditViewInner<M extends Record<string, any>>({
489
490
  .filter(Boolean) as EntityCustomView[]
490
491
  : [];
491
492
 
492
- const selectedEntityView = resolvedEntityViews.find(e => e.key === selectedTabRef.current);
493
- const shouldShowEntityActions = !autoSave && (selectedTabRef.current === MAIN_TAB_VALUE || selectedEntityView?.includeActions);
493
+ const selectedEntityView = resolvedEntityViews.find(e => e.key === selectedTab);
494
+ const shouldShowEntityActions = !autoSave && (selectedTab === MAIN_TAB_VALUE || selectedEntityView?.includeActions);
494
495
 
495
496
  const customViewsView: React.ReactNode[] | undefined = customViews && resolvedEntityViews
496
497
  .map(
497
498
  (customView, colIndex) => {
498
499
  if (!customView)
499
500
  return null;
500
- if (selectedTabRef.current !== customView.key)
501
+ if (selectedTab !== customView.key)
501
502
  return null;
502
503
  const Builder = customView.Builder;
503
504
  if (!Builder) {
@@ -530,7 +531,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
530
531
  (subcollection, colIndex) => {
531
532
  const subcollectionId = subcollection.id ?? subcollection.path;
532
533
  const fullPath = usedEntity ? `${path}/${usedEntity?.id}/${removeInitialAndTrailingSlashes(subcollectionId)}` : undefined;
533
- if (selectedTabRef.current !== subcollectionId)
534
+ if (selectedTab !== subcollectionId)
534
535
  return null;
535
536
  return (
536
537
  <div
@@ -566,21 +567,18 @@ export function EntityEditViewInner<M extends Record<string, any>>({
566
567
  }, []);
567
568
 
568
569
  const onSideTabClick = (value: string) => {
569
- selectedTabRef.current = value;
570
- sideEntityController.replace({
571
- path,
572
- entityId,
573
- selectedSubPath: value === MAIN_TAB_VALUE ? undefined : value,
574
- updateUrl: true,
575
- collection,
576
- });
570
+ setSelectedTab(value);
571
+ if (status === "existing") {
572
+ sideEntityController.replace({
573
+ path,
574
+ entityId,
575
+ selectedSubPath: value === MAIN_TAB_VALUE ? undefined : value,
576
+ updateUrl: true,
577
+ collection,
578
+ });
579
+ }
577
580
  };
578
581
 
579
- // const onValuesChanged = useCallback((values?: EntityValues<M>) => {
580
- // modifiedValuesRef.current = values;
581
- // }, []);
582
-
583
- // eslint-disable-next-line n/handle-callback-err
584
582
  const onIdUpdateError = useCallback((error: any) => {
585
583
  snackbarController.open({
586
584
  type: "error",
@@ -678,7 +676,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
678
676
  name,
679
677
  value,
680
678
  property
681
- }) => dataSource.checkUniqueField(path, name, value, entityId),
679
+ }) => dataSource.checkUniqueField(path, name, value, entityId, collection),
682
680
  [dataSource, path, entityId]);
683
681
 
684
682
  const validationSchema = useMemo(() => entityId
@@ -735,50 +733,76 @@ export function EntityEditViewInner<M extends Record<string, any>>({
735
733
 
736
734
  const formFields = (
737
735
  <>
738
- {(resolvedCollection.propertiesOrder ?? Object.keys(resolvedCollection.properties))
736
+ {(getFormFieldKeys(resolvedCollection))
739
737
  .map((key) => {
740
738
 
741
739
  const property = resolvedCollection.properties[key];
742
- if (!property) {
743
- console.warn(`Property ${key} not found in collection ${resolvedCollection.name}`);
744
- return null;
740
+ if (property) {
741
+
742
+ const underlyingValueHasChanged: boolean =
743
+ !!underlyingChanges &&
744
+ Object.keys(underlyingChanges).includes(key) &&
745
+ formex.touched[key];
746
+
747
+ const disabled = (!autoSave && formex.isSubmitting) || isReadOnly(property) || Boolean(property.disabled);
748
+ const hidden = isHidden(property);
749
+ if (hidden) return null;
750
+ const cmsFormFieldProps: PropertyFieldBindingProps<any, M> = {
751
+ propertyKey: key,
752
+ disabled,
753
+ property,
754
+ includeDescription: property.description || property.longDescription,
755
+ underlyingValueHasChanged: underlyingValueHasChanged && !autoSave,
756
+ context: formContext,
757
+ partOfArray: false,
758
+ minimalistView: false,
759
+ autoFocus: false
760
+ };
761
+
762
+ return (
763
+ <div id={`form_field_${key}`}
764
+ key={`field_${resolvedCollection.name}_${key}`}>
765
+ <ErrorBoundary>
766
+ <PropertyFieldBinding {...cmsFormFieldProps}/>
767
+ </ErrorBoundary>
768
+ </div>
769
+ );
745
770
  }
746
771
 
747
- const underlyingValueHasChanged: boolean =
748
- !!underlyingChanges &&
749
- Object.keys(underlyingChanges).includes(key) &&
750
- !!formex.touched[key];
751
-
752
- const disabled = (!autoSave && formex.isSubmitting) || isReadOnly(property) || Boolean(property.disabled);
753
- const hidden = isHidden(property);
754
- if (hidden) return null;
755
- const cmsFormFieldProps: PropertyFieldBindingProps<any, M> = {
756
- propertyKey: key,
757
- disabled,
758
- property,
759
- includeDescription: property.description || property.longDescription,
760
- underlyingValueHasChanged: underlyingValueHasChanged && !autoSave,
761
- context: formContext,
762
- tableMode: false,
763
- partOfArray: false,
764
- partOfBlock: false,
765
- autoFocus: false
766
- };
767
-
768
- return (
769
- <div id={`form_field_${key}`}
770
- key={`field_${resolvedCollection.name}_${key}`}>
771
- <ErrorBoundary>
772
- <Tooltip title={<PropertyIdCopyTooltipContent propertyId={key}/>}
773
- delayDuration={800}
774
- side={"left"}
775
- align={"start"}
776
- sideOffset={16}>
777
- <PropertyFieldBinding {...cmsFormFieldProps}/>
778
- </Tooltip>
779
- </ErrorBoundary>
780
- </div>
781
- );
772
+ const additionalField = resolvedCollection.additionalFields?.find(f => f.key === key);
773
+ if (additionalField && entity) {
774
+ const Builder = additionalField.Builder;
775
+ if (!Builder && !additionalField.value) {
776
+ throw new Error("When using additional fields you need to provide a Builder or a value");
777
+ }
778
+
779
+ const child = Builder
780
+ ? <Builder entity={entity} context={context}/>
781
+ : <>{additionalField.value?.({
782
+ entity,
783
+ context
784
+ })}</>;
785
+ return (
786
+ <div>
787
+ <LabelWithIconAndTooltip
788
+ propertyKey={key}
789
+ icon={<NotesIcon size={"small"}/>}
790
+ title={additionalField.name}
791
+ className={"text-text-secondary dark:text-text-secondary-dark ml-3.5"}/>
792
+ <div
793
+ className={cls(paperMixin, "min-h-14 p-4 md:p-6 overflow-x-scroll no-scrollbar")}>
794
+
795
+ <ErrorBoundary>
796
+ {child}
797
+ </ErrorBoundary>
798
+
799
+ </div>
800
+ </div>
801
+ );
802
+ }
803
+
804
+ console.warn(`Property ${key} not found in collection ${resolvedCollection.name} in properties or additional fields. Skipping.`);
805
+ return null;
782
806
  })
783
807
  .filter(Boolean)}
784
808
 
@@ -861,51 +885,54 @@ export function EntityEditViewInner<M extends Record<string, any>>({
861
885
 
862
886
  function buildForm() {
863
887
 
864
- let form = <div className="h-full overflow-auto">
888
+ let form = <>
865
889
 
866
890
  {pluginActions.length > 0 && <div
867
891
  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")}>
868
892
  {pluginActions}
869
893
  </div>}
870
894
 
871
- <div className="pt-12 pb-16 pl-8 pr-8 md:pl-10 md:pr-10">
872
- <div
873
- className={`w-full py-2 flex flex-col items-start mt-${4 + (pluginActions ? 8 : 0)} lg:mt-${8 + (pluginActions ? 8 : 0)} mb-8`}>
895
+ <div className="h-full overflow-auto">
874
896
 
875
- <Typography
876
- className={"mt-4 flex-grow line-clamp-1 " + inputCollection.hideIdFromForm ? "mb-2" : "mb-0"}
877
- variant={"h4"}>{title ?? inputCollection.singularName ?? inputCollection.name}
878
- </Typography>
879
- <Alert color={"base"} className={"w-full"} size={"small"}>
880
- <code className={"text-xs select-all"}>{path}/{entityId}</code>
881
- </Alert>
882
- </div>
897
+ <div className="pt-12 pb-16 pl-8 pr-8 md:pl-10 md:pr-10">
898
+ <div
899
+ className={`w-full py-2 flex flex-col items-start mt-${4 + (pluginActions ? 8 : 0)} lg:mt-${8 + (pluginActions ? 8 : 0)} mb-8`}>
900
+
901
+ <Typography
902
+ className={"mt-4 flex-grow line-clamp-1 " + inputCollection.hideIdFromForm ? "mb-2" : "mb-0"}
903
+ variant={"h4"}>{title ?? inputCollection.singularName ?? inputCollection.name}
904
+ </Typography>
905
+ <Alert color={"base"} className={"w-full"} size={"small"}>
906
+ <code className={"text-xs select-all"}>{path}/{entityId}</code>
907
+ </Alert>
908
+ </div>
883
909
 
884
- {!collection.hideIdFromForm &&
885
- <CustomIdField customId={inputCollection.customId}
886
- entityId={entityId}
887
- status={status}
888
- onChange={setEntityId}
889
- error={entityIdError}
890
- loading={customIdLoading}
891
- entity={entity}/>}
910
+ {!collection.hideIdFromForm &&
911
+ <CustomIdField customId={inputCollection.customId}
912
+ entityId={entityId}
913
+ status={status}
914
+ onChange={setEntityId}
915
+ error={entityIdError}
916
+ loading={customIdLoading}
917
+ entity={entity}/>}
892
918
 
893
- {entityId && formContext && <>
894
- <div className="mt-12 flex flex-col gap-8"
895
- ref={formRef}>
919
+ {entityId && formContext && <>
920
+ <div className="mt-12 flex flex-col gap-8"
921
+ ref={formRef}>
896
922
 
897
- {formFields}
923
+ {formFields}
898
924
 
899
- <ErrorFocus containerRef={formRef}/>
925
+ <ErrorFocus containerRef={formRef}/>
900
926
 
901
- </div>
927
+ </div>
902
928
 
903
- <div className="h-14"/>
929
+ <div className="h-14"/>
904
930
 
905
- </>}
931
+ </>}
906
932
 
933
+ </div>
907
934
  </div>
908
- </div>;
935
+ </>;
909
936
 
910
937
  if (plugins) {
911
938
  plugins.forEach((plugin: FireCMSPlugin) => {
@@ -1001,7 +1028,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
1001
1028
  </div>}
1002
1029
 
1003
1030
  <Tabs
1004
- value={selectedTabRef.current}
1031
+ value={selectedTab}
1005
1032
  onValueChange={(value) => {
1006
1033
  onSideTabClick(value);
1007
1034
  }}
@@ -1035,7 +1062,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
1035
1062
  role="tabpanel"
1036
1063
  hidden={!mainViewVisible}
1037
1064
  id={`form_${path}`}
1038
- className={" w-full"}>
1065
+ className={"relative w-full"}>
1039
1066
 
1040
1067
  {globalLoading
1041
1068
  ? <CircularProgressCenter/>
@@ -28,7 +28,7 @@ import { useProjectLog } from "../hooks/useProjectLog";
28
28
  *
29
29
  * You only need to use this component if you are building a custom app.
30
30
  *
31
- * @constructor
31
+
32
32
  * @group Core
33
33
  */
34
34
  export function FireCMS<UserType extends User, EC extends EntityCollection>(props: FireCMSProps<UserType, EC>) {
@@ -82,7 +82,7 @@ export function FireCMS<UserType extends User, EC extends EntityCollection>(prop
82
82
  onAnalyticsEvent
83
83
  }), []);
84
84
 
85
- const accessResponse = useProjectLog(authController, plugins);
85
+ const accessResponse = useProjectLog(authController, dataSourceDelegate, plugins);
86
86
 
87
87
  if (navigationController.navigationLoadingError) {
88
88
  return (
@@ -25,7 +25,7 @@ export type NavigationRoutesProps = {
25
25
  * or the home route) related to a {@link NavigationController}.
26
26
  * This component needs a parent {@link FireCMS}
27
27
  *
28
- * @constructor
28
+
29
29
  * @group Components
30
30
  */
31
31
  export const NavigationRoutes = React.memo<NavigationRoutesProps>(
@@ -126,6 +126,7 @@ function SideDialogView({
126
126
  <Sheet
127
127
  open={Boolean(panel)}
128
128
  onOpenChange={(open) => !open && onCloseRequest()}
129
+ title={"Side dialog " + panel?.key}
129
130
  >
130
131
  {panel &&
131
132
  <div
@@ -8,8 +8,8 @@ import {
8
8
  DateTimeFieldBinding,
9
9
  KeyValueFieldBinding,
10
10
  MapFieldBinding,
11
- MarkdownFieldBinding,
12
- MultiSelectBinding,
11
+ MarkdownEditorFieldBinding,
12
+ MultiSelectFieldBinding,
13
13
  ReferenceFieldBinding,
14
14
  RepeatFieldBinding,
15
15
  SelectFieldBinding,
@@ -77,7 +77,7 @@ export const DEFAULT_FIELD_CONFIGS: Record<string, PropertyConfig<any>> = {
77
77
  property: {
78
78
  dataType: "string",
79
79
  markdown: true,
80
- Field: MarkdownFieldBinding
80
+ Field: MarkdownEditorFieldBinding
81
81
  }
82
82
  },
83
83
  url: {
@@ -139,7 +139,7 @@ export const DEFAULT_FIELD_CONFIGS: Record<string, PropertyConfig<any>> = {
139
139
  dataType: "string",
140
140
  enumValues: [],
141
141
  },
142
- Field: MultiSelectBinding
142
+ Field: MultiSelectFieldBinding
143
143
  }
144
144
  },
145
145
  number_input: {
@@ -177,7 +177,7 @@ export const DEFAULT_FIELD_CONFIGS: Record<string, PropertyConfig<any>> = {
177
177
  dataType: "number",
178
178
  enumValues: [],
179
179
  },
180
- Field: MultiSelectBinding
180
+ Field: MultiSelectFieldBinding
181
181
  }
182
182
  },
183
183
  file_upload: {