@firecms/core 3.0.1 → 3.1.0-canary.1df3b2c

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 (170) hide show
  1. package/README.md +1 -1
  2. package/dist/components/AIIcon.d.ts +16 -0
  3. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +7 -1
  4. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +1 -1
  5. package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +14 -0
  6. package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +6 -0
  7. package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +5 -4
  8. package/dist/components/EntityCollectionTable/internal/EntityTableCell.d.ts +6 -0
  9. package/dist/components/EntityCollectionView/Board.d.ts +2 -0
  10. package/dist/components/EntityCollectionView/BoardColumn.d.ts +42 -0
  11. package/dist/components/EntityCollectionView/BoardColumnTitle.d.ts +9 -0
  12. package/dist/components/EntityCollectionView/BoardSortableList.d.ts +14 -0
  13. package/dist/components/EntityCollectionView/EntityBoardCard.d.ts +26 -0
  14. package/dist/components/EntityCollectionView/EntityCard.d.ts +19 -0
  15. package/dist/components/EntityCollectionView/EntityCollectionBoardView.d.ts +20 -0
  16. package/dist/components/EntityCollectionView/EntityCollectionCardView.d.ts +31 -0
  17. package/dist/components/EntityCollectionView/EntityCollectionViewActions.d.ts +2 -2
  18. package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +7 -3
  19. package/dist/components/EntityCollectionView/FiltersDialog.d.ts +14 -0
  20. package/dist/components/EntityCollectionView/ViewModeToggle.d.ts +49 -0
  21. package/dist/components/EntityCollectionView/board_types.d.ts +105 -0
  22. package/dist/components/EntityCollectionView/useBoardDataController.d.ts +60 -0
  23. package/dist/components/SelectableTable/SelectableTable.d.ts +5 -1
  24. package/dist/components/SelectableTable/filters/DateTimeFilterField.d.ts +2 -1
  25. package/dist/components/VirtualTable/VirtualTableCell.d.ts +6 -0
  26. package/dist/components/VirtualTable/VirtualTableHeader.d.ts +2 -0
  27. package/dist/components/VirtualTable/VirtualTableHeaderRow.d.ts +1 -1
  28. package/dist/components/VirtualTable/VirtualTableProps.d.ts +11 -0
  29. package/dist/components/VirtualTable/fields/VirtualTableDateField.d.ts +1 -0
  30. package/dist/components/VirtualTable/types.d.ts +2 -0
  31. package/dist/components/index.d.ts +3 -0
  32. package/dist/contexts/index.d.ts +10 -0
  33. package/dist/core/DrawerNavigationGroup.d.ts +45 -0
  34. package/dist/core/index.d.ts +1 -0
  35. package/dist/form/validation.d.ts +3 -2
  36. package/dist/hooks/useBreadcrumbsController.d.ts +16 -0
  37. package/dist/hooks/useCollapsedGroups.d.ts +4 -1
  38. package/dist/index.es.js +5239 -1590
  39. package/dist/index.es.js.map +1 -1
  40. package/dist/index.umd.js +5233 -1585
  41. package/dist/index.umd.js.map +1 -1
  42. package/dist/preview/PropertyPreviewProps.d.ts +5 -0
  43. package/dist/preview/components/DatePreview.d.ts +13 -3
  44. package/dist/preview/components/ImagePreview.d.ts +5 -1
  45. package/dist/preview/components/StorageThumbnail.d.ts +2 -1
  46. package/dist/preview/components/UrlComponentPreview.d.ts +2 -1
  47. package/dist/preview/property_previews/ArrayOfStorageComponentsPreview.d.ts +1 -1
  48. package/dist/preview/property_previews/ArrayOfStringsPreview.d.ts +1 -1
  49. package/dist/preview/property_previews/SkeletonPropertyComponent.d.ts +1 -1
  50. package/dist/types/collections.d.ts +42 -2
  51. package/dist/types/datasource.d.ts +0 -1
  52. package/dist/types/plugins.d.ts +46 -1
  53. package/dist/types/properties.d.ts +259 -4
  54. package/dist/util/__tests__/conditions.test.d.ts +1 -0
  55. package/dist/util/__tests__/objects.test.d.ts +1 -0
  56. package/dist/util/conditions.d.ts +26 -0
  57. package/dist/util/entities.d.ts +1 -2
  58. package/dist/util/index.d.ts +2 -1
  59. package/dist/util/property_utils.d.ts +2 -1
  60. package/dist/util/resolutions.d.ts +1 -1
  61. package/package.json +10 -7
  62. package/src/app/Scaffold.tsx +14 -15
  63. package/src/components/AIIcon.tsx +39 -0
  64. package/src/components/ArrayContainer.tsx +1 -4
  65. package/src/components/ClearFilterSortButton.tsx +19 -16
  66. package/src/components/ConfirmationDialog.tsx +0 -2
  67. package/src/components/DeleteEntityDialog.tsx +2 -4
  68. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +74 -41
  69. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +130 -79
  70. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +121 -104
  71. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +132 -103
  72. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +20 -42
  73. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +90 -49
  74. package/src/components/EntityCollectionView/Board.tsx +324 -0
  75. package/src/components/EntityCollectionView/BoardColumn.tsx +158 -0
  76. package/src/components/EntityCollectionView/BoardColumnTitle.tsx +45 -0
  77. package/src/components/EntityCollectionView/BoardSortableList.tsx +172 -0
  78. package/src/components/EntityCollectionView/EntityBoardCard.tsx +212 -0
  79. package/src/components/EntityCollectionView/EntityCard.tsx +231 -0
  80. package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +713 -0
  81. package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +244 -0
  82. package/src/components/EntityCollectionView/EntityCollectionView.tsx +485 -203
  83. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +31 -19
  84. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +84 -15
  85. package/src/components/EntityCollectionView/FiltersDialog.tsx +249 -0
  86. package/src/components/EntityCollectionView/ViewModeToggle.tsx +202 -0
  87. package/src/components/EntityCollectionView/board_types.ts +113 -0
  88. package/src/components/EntityCollectionView/useBoardDataController.tsx +490 -0
  89. package/src/components/ErrorTooltip.tsx +2 -1
  90. package/src/components/HomePage/DefaultHomePage.tsx +47 -10
  91. package/src/components/HomePage/HomePageDnD.tsx +56 -41
  92. package/src/components/HomePage/NavigationCard.tsx +20 -18
  93. package/src/components/HomePage/NavigationGroup.tsx +17 -16
  94. package/src/components/HomePage/RenameGroupDialog.tsx +0 -2
  95. package/src/components/HomePage/SmallNavigationCard.tsx +10 -9
  96. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +3 -10
  97. package/src/components/ReferenceWidget.tsx +2 -4
  98. package/src/components/SelectableTable/SelectableTable.tsx +75 -67
  99. package/src/components/SelectableTable/filters/BooleanFilterField.tsx +7 -6
  100. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +39 -40
  101. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +38 -38
  102. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +49 -58
  103. package/src/components/UnsavedChangesDialog.tsx +0 -2
  104. package/src/components/UserDisplay.tsx +4 -4
  105. package/src/components/VirtualTable/VirtualTable.tsx +170 -19
  106. package/src/components/VirtualTable/VirtualTableCell.tsx +18 -2
  107. package/src/components/VirtualTable/VirtualTableHeader.tsx +20 -11
  108. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +158 -42
  109. package/src/components/VirtualTable/VirtualTableProps.tsx +14 -1
  110. package/src/components/VirtualTable/VirtualTableRow.tsx +1 -1
  111. package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +3 -0
  112. package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +17 -4
  113. package/src/components/VirtualTable/types.tsx +2 -0
  114. package/src/components/common/useColumnsIds.tsx +95 -3
  115. package/src/components/index.tsx +4 -0
  116. package/src/contexts/BreacrumbsContext.tsx +15 -8
  117. package/src/contexts/index.ts +10 -0
  118. package/src/core/DefaultAppBar.tsx +39 -26
  119. package/src/core/DefaultDrawer.tsx +42 -56
  120. package/src/core/DrawerNavigationGroup.tsx +118 -0
  121. package/src/core/DrawerNavigationItem.tsx +4 -3
  122. package/src/core/EntityEditView.tsx +41 -43
  123. package/src/core/SideDialogs.tsx +4 -2
  124. package/src/core/index.tsx +1 -0
  125. package/src/form/PropertyFieldBinding.tsx +58 -43
  126. package/src/form/components/StorageItemPreview.tsx +2 -1
  127. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +0 -1
  128. package/src/form/field_bindings/DateTimeFieldBinding.tsx +17 -16
  129. package/src/form/field_bindings/KeyValueFieldBinding.tsx +0 -1
  130. package/src/form/field_bindings/MapFieldBinding.tsx +69 -67
  131. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +21 -17
  132. package/src/form/field_bindings/TextFieldBinding.tsx +71 -35
  133. package/src/form/validation.ts +245 -160
  134. package/src/hooks/useBreadcrumbsController.tsx +18 -0
  135. package/src/hooks/useBuildNavigationController.tsx +42 -19
  136. package/src/hooks/useCollapsedGroups.ts +12 -4
  137. package/src/internal/useBuildDataSource.ts +69 -34
  138. package/src/internal/useBuildSideDialogsController.tsx +11 -8
  139. package/src/internal/useBuildSideEntityController.tsx +2 -4
  140. package/src/internal/useRestoreScroll.tsx +26 -14
  141. package/src/preview/PropertyPreview.tsx +40 -32
  142. package/src/preview/PropertyPreviewProps.tsx +6 -0
  143. package/src/preview/components/DatePreview.tsx +72 -4
  144. package/src/preview/components/EmptyValue.tsx +1 -1
  145. package/src/preview/components/ImagePreview.tsx +37 -21
  146. package/src/preview/components/StorageThumbnail.tsx +16 -12
  147. package/src/preview/components/UrlComponentPreview.tsx +28 -25
  148. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +9 -7
  149. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +11 -9
  150. package/src/preview/property_previews/ArrayPropertyPreview.tsx +26 -24
  151. package/src/preview/property_previews/SkeletonPropertyComponent.tsx +61 -56
  152. package/src/routes/CustomCMSRoute.tsx +1 -0
  153. package/src/routes/FireCMSRoute.tsx +26 -13
  154. package/src/types/collections.ts +48 -3
  155. package/src/types/datasource.ts +54 -56
  156. package/src/types/plugins.tsx +51 -1
  157. package/src/types/properties.ts +347 -27
  158. package/src/util/__tests__/conditions.test.ts +506 -0
  159. package/src/util/__tests__/objects.test.ts +196 -0
  160. package/src/util/callbacks.ts +6 -3
  161. package/src/util/collections.ts +51 -6
  162. package/src/util/conditions.ts +339 -0
  163. package/src/util/entities.ts +28 -29
  164. package/src/util/entity_cache.ts +2 -1
  165. package/src/util/index.ts +2 -1
  166. package/src/util/objects.ts +31 -13
  167. package/src/util/{references.ts → previews.ts} +14 -0
  168. package/src/util/property_utils.tsx +36 -10
  169. package/src/util/resolutions.ts +57 -55
  170. /package/dist/util/{references.d.ts → previews.d.ts} +0 -0
@@ -0,0 +1,118 @@
1
+ import React from "react";
2
+ import { cls, ExpandMoreIcon, Typography } from "@firecms/ui";
3
+ import { NavigationEntry } from "../types";
4
+ import { IconForView } from "../util";
5
+ import { DrawerNavigationItem } from "./DrawerNavigationItem";
6
+
7
+ export interface DrawerNavigationGroupProps {
8
+ /**
9
+ * Group name to display in header
10
+ */
11
+ group: string;
12
+ /**
13
+ * Navigation entries in this group
14
+ */
15
+ entries: NavigationEntry[];
16
+ /**
17
+ * Whether the group is collapsed
18
+ */
19
+ collapsed: boolean;
20
+ /**
21
+ * Callback when collapse state should toggle
22
+ */
23
+ onToggleCollapsed: () => void;
24
+ /**
25
+ * Whether the drawer is in open (expanded) state
26
+ */
27
+ drawerOpen: boolean;
28
+ /**
29
+ * Whether tooltips should be shown (drawer closed + hovered)
30
+ */
31
+ tooltipsOpen: boolean;
32
+ /**
33
+ * Whether admin menu is open (used to control tooltip visibility)
34
+ */
35
+ adminMenuOpen?: boolean;
36
+ /**
37
+ * Optional actions to render in the group header (e.g., "Add collection" button)
38
+ */
39
+ headerActions?: React.ReactNode;
40
+ /**
41
+ * Optional callback when a navigation item is clicked
42
+ */
43
+ onItemClick?: (entry: NavigationEntry) => void;
44
+ }
45
+
46
+ /**
47
+ * Shared drawer navigation group component used by both DefaultDrawer and FireCMSCloudDrawer.
48
+ * Renders a collapsible group with header and navigation items.
49
+ */
50
+ export function DrawerNavigationGroup({
51
+ group,
52
+ entries,
53
+ collapsed,
54
+ onToggleCollapsed,
55
+ drawerOpen,
56
+ tooltipsOpen,
57
+ adminMenuOpen,
58
+ headerActions,
59
+ onItemClick
60
+ }: DrawerNavigationGroupProps) {
61
+ return (
62
+ <div
63
+ className={"bg-surface-50 dark:bg-surface-800/30 my-4 rounded-lg ml-3 mr-1"}
64
+ key={`drawer_group_${group}`}
65
+ >
66
+ {/* Group Header */}
67
+ {drawerOpen ? (
68
+ <div
69
+ className="pl-4 pr-2 py-2 flex flex-row items-center cursor-pointer hover:bg-surface-100 dark:hover:bg-surface-700/50 rounded-t-lg transition-colors"
70
+ onClick={onToggleCollapsed}
71
+ >
72
+ <ExpandMoreIcon
73
+ size={"smallest"}
74
+ className={cls(
75
+ "text-surface-500 dark:text-surface-400 transition-transform duration-200 mr-1",
76
+ collapsed ? "-rotate-90" : "rotate-0"
77
+ )}
78
+ />
79
+ <Typography
80
+ variant={"caption"}
81
+ color={"secondary"}
82
+ className="font-medium flex-grow line-clamp-1"
83
+ >
84
+ {(group || "Views").toUpperCase()}
85
+ </Typography>
86
+ {headerActions && (
87
+ <div onClick={(e) => e.stopPropagation()}>
88
+ {headerActions}
89
+ </div>
90
+ )}
91
+ </div>
92
+ ) : (
93
+ <div className="w-full" />
94
+ )}
95
+
96
+ {/* Collapsible Content */}
97
+ <div
98
+ className={cls(
99
+ "overflow-hidden transition-all duration-200 ease-in-out",
100
+ collapsed ? "max-h-0 opacity-0" : "max-h-[2000px] opacity-100"
101
+ )}
102
+ >
103
+ {entries.map((entry) => (
104
+ <DrawerNavigationItem
105
+ key={entry.id}
106
+ icon={<IconForView collectionOrView={entry.collection ?? entry.view} size={18} />}
107
+ tooltipsOpen={!collapsed && tooltipsOpen}
108
+ adminMenuOpen={adminMenuOpen}
109
+ drawerOpen={drawerOpen}
110
+ onClick={() => onItemClick?.(entry)}
111
+ url={entry.url}
112
+ name={entry.name}
113
+ />
114
+ ))}
115
+ </div>
116
+ </div>
117
+ );
118
+ }
@@ -34,13 +34,13 @@ export function DrawerNavigationItem({
34
34
  transition: drawerOpen ? "width 150ms ease-in" : undefined
35
35
  }}
36
36
  className={({ isActive }: any) => cls("rounded-lg truncate",
37
- "hover:bg-surface-accent-300 hover:bg-opacity-75 dark:hover:bg-surface-accent-800 dark:hover:bg-opacity-75 text-text-primary dark:text-surface-200 hover:text-surface-900 hover:dark:text-white",
37
+ "hover:bg-surface-accent-300 hover:bg-opacity-75 hover:bg-surface-accent-300/75 dark:hover:bg-surface-accent-800 dark:hover:bg-opacity-75 dark:hover:bg-surface-accent-800/75 text-text-primary dark:text-surface-200 hover:text-surface-900 hover:dark:text-white hover:bg-surface-accent-300/75 dark:hover:bg-surface-accent-800/75",
38
38
  "flex flex-row items-center mr-8",
39
39
  // "transition-all ease-in-out delay-100 duration-300",
40
40
  // drawerOpen ? "w-full" : "w-18",
41
41
  drawerOpen ? "pl-4 h-10" : "pl-4 h-9",
42
42
  "font-semibold text-xs",
43
- isActive ? "bg-surface-accent-200 bg-opacity-60 dark:bg-surface-800 dark:bg-opacity-50" : ""
43
+ isActive ? "bg-surface-accent-200 bg-opacity-60 dark:bg-surface-800 dark:bg-opacity-50 bg-surface-accent-200/60 dark:bg-surface-800/50" : ""
44
44
  )}
45
45
  to={url}
46
46
  >
@@ -49,8 +49,9 @@ export function DrawerNavigationItem({
49
49
 
50
50
  <div
51
51
  className={cls(
52
+ "text-text-primary dark:text-surface-200",
52
53
  drawerOpen ? "opacity-100" : "opacity-0 hidden",
53
- "ml-4 font-inherit text-inherit"
54
+ "ml-4 font-inherit"
54
55
  )}>
55
56
  {name.toUpperCase()}
56
57
  </div>
@@ -75,7 +75,7 @@ export interface EntityEditViewProps<M extends Record<string, any>> {
75
75
  copy?: boolean;
76
76
  selectedTab?: string;
77
77
  parentCollectionIds: string[];
78
- onValuesModified?: (modified: boolean, values:M) => void;
78
+ onValuesModified?: (modified: boolean, values: M) => void;
79
79
  onSaved?: (params: OnUpdateParams) => void;
80
80
  onTabChange?: (props: OnTabChangeParams<M>) => void;
81
81
  layout?: "side_panel" | "full_screen";
@@ -88,9 +88,9 @@ export interface EntityEditViewProps<M extends Record<string, any>> {
88
88
  * an entity is opened.
89
89
  */
90
90
  export function EntityEditView<M extends Record<string, any>, USER extends User>({
91
- entityId,
92
- ...props
93
- }: EntityEditViewProps<M>) {
91
+ entityId,
92
+ ...props
93
+ }: EntityEditViewProps<M>) {
94
94
 
95
95
  const {
96
96
  entity,
@@ -123,7 +123,7 @@ export function EntityEditView<M extends Record<string, any>, USER extends User>
123
123
  }, [authController, entity, status]);
124
124
 
125
125
  if ((dataLoading && !initialDirtyValues) || (!entity || canEdit === undefined) && (status === "existing" || status === "copy")) {
126
- return <CircularProgressCenter/>;
126
+ return <CircularProgressCenter />;
127
127
  }
128
128
 
129
129
  if (entityId && !entity && !initialDirtyValues) {
@@ -131,36 +131,36 @@ export function EntityEditView<M extends Record<string, any>, USER extends User>
131
131
  }
132
132
 
133
133
  return <EntityEditViewInner<M> {...props}
134
- entityId={entityId}
135
- entity={entity}
136
- initialDirtyValues={initialDirtyValues as Partial<M>}
137
- dataLoading={dataLoading}
138
- status={status}
139
- setStatus={setStatus}
140
- canEdit={canEdit}
134
+ entityId={entityId}
135
+ entity={entity}
136
+ initialDirtyValues={initialDirtyValues as Partial<M>}
137
+ dataLoading={dataLoading}
138
+ status={status}
139
+ setStatus={setStatus}
140
+ canEdit={canEdit}
141
141
  />;
142
142
  }
143
143
 
144
144
  export function EntityEditViewInner<M extends Record<string, any>>({
145
- path,
146
- fullIdPath,
147
- entityId,
148
- selectedTab: selectedTabProp,
149
- collection,
150
- parentCollectionIds,
151
- onValuesModified,
152
- onSaved,
153
- onTabChange,
154
- entity,
155
- initialDirtyValues,
156
- dataLoading,
157
- layout = "side_panel",
158
- barActions,
159
- status,
160
- setStatus,
161
- formProps,
162
- canEdit
163
- }: EntityEditViewProps<M> & {
145
+ path,
146
+ fullIdPath,
147
+ entityId,
148
+ selectedTab: selectedTabProp,
149
+ collection,
150
+ parentCollectionIds,
151
+ onValuesModified,
152
+ onSaved,
153
+ onTabChange,
154
+ entity,
155
+ initialDirtyValues,
156
+ dataLoading,
157
+ layout = "side_panel",
158
+ barActions,
159
+ status,
160
+ setStatus,
161
+ formProps,
162
+ canEdit
163
+ }: EntityEditViewProps<M> & {
164
164
  entity?: Entity<M>,
165
165
  initialDirtyValues?: Partial<M>, // dirty cached entity in memory
166
166
  dataLoading: boolean,
@@ -312,7 +312,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
312
312
  role="tabpanel">
313
313
  <ErrorBoundary>
314
314
  <EntityJsonPreview
315
- values={formContext?.values ?? entity?.values ?? {}}/>
315
+ values={formContext?.values ?? entity?.values ?? {}} />
316
316
  </ErrorBoundary>
317
317
  </div>;
318
318
 
@@ -328,7 +328,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
328
328
  key={`subcol_${subcollectionId}`}
329
329
  role="tabpanel">
330
330
 
331
- {globalLoading && <CircularProgressCenter/>}
331
+ {globalLoading && <CircularProgressCenter />}
332
332
 
333
333
  {!globalLoading &&
334
334
  (usedEntity && newFullPath
@@ -339,7 +339,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
339
339
  isSubCollection={true}
340
340
  updateUrl={false}
341
341
  {...subcollection}
342
- openEntityMode={layout}/>
342
+ openEntityMode={layout} />
343
343
  : <div className="flex items-center justify-center w-full h-full p-3">
344
344
  <Typography variant={"label"}>
345
345
  You need to save your entity before
@@ -375,8 +375,8 @@ export function EntityEditViewInner<M extends Record<string, any>>({
375
375
  className={"px-8 h-full overflow-auto"}
376
376
  entity={entity}
377
377
  path={path}
378
- collection={collection}/>
379
- <div className="h-16"/>
378
+ collection={collection} />
379
+ <div className="h-16" />
380
380
  </div>
381
381
  </div> : null;
382
382
 
@@ -396,7 +396,6 @@ export function EntityEditViewInner<M extends Record<string, any>>({
396
396
  disabled={!canEdit}
397
397
  {...formProps}
398
398
  onEntityChange={(entity) => {
399
- console.log("333 EntityEditView onEntityChange:", entity);
400
399
  setUsedEntity(entity);
401
400
  formProps?.onEntityChange?.(entity);
402
401
  }}
@@ -452,7 +451,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
452
451
  let result = <div className="relative flex flex-col h-full w-full bg-white dark:bg-surface-900">
453
452
 
454
453
  {shouldShowTopBar && <div
455
- className={cls("h-14 items-center flex overflow-visible overflow-x-scroll w-full no-scrollbar h-14 border-b pl-2 pr-2 pt-1 flex bg-surface-50 dark:bg-surface-900", defaultBorderMixin)}>
454
+ className={cls("h-14 items-center overflow-visible overflow-x-scroll w-full no-scrollbar border-b pl-2 pr-2 flex gap-2 bg-surface-50 dark:bg-surface-900", defaultBorderMixin)}>
456
455
 
457
456
  {barActions?.({
458
457
  path: fullIdPath ?? path,
@@ -461,16 +460,15 @@ export function EntityEditViewInner<M extends Record<string, any>>({
461
460
  status
462
461
  })}
463
462
 
464
- <div className={"flex-grow"}/>
463
+ <div className={"flex-grow"} />
465
464
 
466
465
  {pluginActionsTop}
467
466
 
468
467
  {globalLoading && <div className="self-center">
469
- <CircularProgress size={"small"}/>
468
+ <CircularProgress size={"small"} />
470
469
  </div>}
471
470
 
472
471
  {hasAdditionalViews && <Tabs
473
- className={"self-end"}
474
472
  value={selectedTab}
475
473
  onValueChange={(value) => {
476
474
  onSideTabClick(value);
@@ -480,7 +478,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
480
478
  disabled={!hasAdditionalViews}
481
479
  value={JSON_TAB_VALUE}
482
480
  className={"text-sm"}>
483
- <CodeIcon size={"small"}/>
481
+ <CodeIcon size={"small"} />
484
482
  </Tab>}
485
483
 
486
484
  {customViewTabsStart}
@@ -501,7 +499,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
501
499
 
502
500
  {globalLoading
503
501
  ? <div className="w-full pt-12 pb-16 px-4 sm:px-8 md:px-10">
504
- <CircularProgressCenter/>
502
+ <CircularProgressCenter />
505
503
  </div>
506
504
  : <>
507
505
  {entityReadOnlyView}
@@ -1,10 +1,11 @@
1
1
  import React, { useContext, useEffect, useState } from "react";
2
2
  import { useSideDialogsController } from "../hooks";
3
- import { SideDialogPanelProps } from "../types";
3
+ import { EntitySidePanelProps, SideDialogPanelProps } from "../types";
4
4
  import { Sheet } from "@firecms/ui";
5
5
  import { useNavigationUnsavedChangesDialog } from "../internal/useUnsavedChangesDialog";
6
6
  import { ErrorBoundary } from "../components";
7
7
  import { UnsavedChangesDialog } from "../components/UnsavedChangesDialog";
8
+ import { EntitySidePanel } from "./EntitySidePanel";
8
9
 
9
10
  export type SideDialogController = {
10
11
  blocked: boolean,
@@ -157,7 +158,8 @@ function SideDialogView({
157
158
  }}
158
159
  >
159
160
  <ErrorBoundary>
160
- {panel.component}
161
+ {/* Lazy render EntitySidePanel from props for better performance */}
162
+ {panel.component ?? (panel.additional ? <EntitySidePanel {...(panel.additional as EntitySidePanelProps)} /> : null)}
161
163
  </ErrorBoundary>
162
164
  </div>}
163
165
 
@@ -2,6 +2,7 @@ export * from "./FireCMS";
2
2
 
3
3
  export * from "./DefaultDrawer";
4
4
  export * from "./DrawerNavigationItem";
5
+ export * from "./DrawerNavigationGroup";
5
6
 
6
7
  export * from "./field_configs";
7
8
 
@@ -75,21 +75,21 @@ export const PropertyFieldBinding = React.memo(PropertyFieldBindingInternal, (a:
75
75
  }) as typeof PropertyFieldBindingInternal;
76
76
 
77
77
  function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Record<string, any> = any>
78
- ({
79
- propertyKey,
80
- property,
81
- context,
82
- includeDescription,
83
- underlyingValueHasChanged,
84
- disabled: disabledProp,
85
- partOfArray,
86
- partOfBlock,
87
- minimalistView,
88
- autoFocus,
89
- index,
90
- size,
91
- onPropertyChange,
92
- }: PropertyFieldBindingProps<T, M>): ReactElement<PropertyFieldBindingProps<T, M>> {
78
+ ({
79
+ propertyKey,
80
+ property,
81
+ context,
82
+ includeDescription,
83
+ underlyingValueHasChanged,
84
+ disabled: disabledProp,
85
+ partOfArray,
86
+ partOfBlock,
87
+ minimalistView,
88
+ autoFocus,
89
+ index,
90
+ size,
91
+ onPropertyChange,
92
+ }: PropertyFieldBindingProps<T, M>): ReactElement<PropertyFieldBindingProps<T, M>> {
93
93
 
94
94
  const authController = useAuthController();
95
95
  const customizationController = useCustomizationController();
@@ -175,7 +175,7 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Rec
175
175
  return <FieldInternal
176
176
  Component={Component as ComponentType<FieldProps>}
177
177
  componentProps={componentProps}
178
- formexFieldProps={fieldProps}/>;
178
+ formexFieldProps={fieldProps} />;
179
179
  }}
180
180
  </Field>
181
181
  );
@@ -185,39 +185,54 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Rec
185
185
  type ResolvedPropertyFieldBindingProps<T extends CMSType = CMSType, M extends Record<string, any> = any> =
186
186
  Omit<PropertyFieldBindingProps<T, M>, "property">
187
187
  & {
188
- property: ResolvedProperty<T>
189
- };
188
+ property: ResolvedProperty<T>
189
+ };
190
190
 
191
191
  function FieldInternal<T extends CMSType, CustomProps, M extends Record<string, any>>
192
- ({
193
- Component,
194
- componentProps: {
195
- propertyKey,
196
- property,
197
- includeDescription,
198
- underlyingValueHasChanged,
199
- partOfArray,
200
- partOfBlock,
201
- minimalistView,
202
- autoFocus,
203
- context,
204
- disabled,
205
- size,
206
- onPropertyChange
207
- },
208
- formexFieldProps
209
- }:
210
- {
211
- Component: ComponentType<FieldProps<T, any, M>>,
212
- componentProps: ResolvedPropertyFieldBindingProps<T, M>,
213
- formexFieldProps: FormexFieldProps<T, any>
214
- }) {
192
+ ({
193
+ Component,
194
+ componentProps: {
195
+ propertyKey,
196
+ property,
197
+ includeDescription,
198
+ underlyingValueHasChanged,
199
+ partOfArray,
200
+ partOfBlock,
201
+ minimalistView,
202
+ autoFocus,
203
+ context,
204
+ disabled,
205
+ size,
206
+ onPropertyChange
207
+ },
208
+ formexFieldProps
209
+ }:
210
+ {
211
+ Component: ComponentType<FieldProps<T, any, M>>,
212
+ componentProps: ResolvedPropertyFieldBindingProps<T, M>,
213
+ formexFieldProps: FormexFieldProps<T, any>
214
+ }) {
215
215
 
216
216
  const { plugins } = useCustomizationController();
217
217
 
218
218
  const customFieldProps: any = property.customProps;
219
219
  const value = formexFieldProps.field.value;
220
- const error = getIn(formexFieldProps.form.errors, propertyKey);
220
+
221
+ // Get error for this field path, but avoid string indexing issues
222
+ // When an array has a string error like "Tags should have unique values",
223
+ // accessing errors["tags"]["0"] returns "T" (string indexing).
224
+ // We traverse the path manually and stop if we hit a string.
225
+ let error: any = formexFieldProps.form.errors;
226
+ for (const part of propertyKey.split(".")) {
227
+ if (error === undefined || error === null) break;
228
+ if (typeof error === "string") {
229
+ // Parent is a string error, children shouldn't inherit individual characters
230
+ error = undefined;
231
+ break;
232
+ }
233
+ error = error[part];
234
+ }
235
+
221
236
  const touched = getIn(formexFieldProps.form.touched, propertyKey);
222
237
 
223
238
  const showError: boolean = error &&
@@ -272,7 +287,7 @@ function FieldInternal<T extends CMSType, CustomProps, M extends Record<string,
272
287
  return (
273
288
  <ErrorBoundary>
274
289
 
275
- <UsedComponent {...cmsFieldProps}/>
290
+ <UsedComponent {...cmsFieldProps} />
276
291
 
277
292
  {underlyingValueHasChanged && !isSubmitting &&
278
293
  <Typography variant={"caption"} className={"ml-3.5"}>
@@ -29,9 +29,10 @@ export function StorageItemPreview({
29
29
  }: StorageItemPreviewProps) {
30
30
 
31
31
  return (
32
- <div className={cls(paperMixin,
32
+ <div className={cls(
33
33
  "relative border-box flex items-center justify-center",
34
34
  size === "large" ? "min-w-[220px] min-h-[220px] max-w-[220px]" : "min-w-[118px] min-h-[118px] max-w-[118px]",
35
+ paperMixin,
35
36
  className)}>
36
37
 
37
38
  {!placeholder && !disabled &&
@@ -129,7 +129,6 @@ export function ArrayOfReferencesFieldBinding({
129
129
  <Button
130
130
  className="ml-3.5 my-4 justify-center text-left"
131
131
  variant="text"
132
- color="primary"
133
132
  disabled={isSubmitting}
134
133
  onClick={onEntryClick}>
135
134
  <EditIcon size={"small"}/>
@@ -19,17 +19,17 @@ type DateTimeFieldProps = FieldProps<Date>;
19
19
  * @group Form fields
20
20
  */
21
21
  export function DateTimeFieldBinding({
22
- propertyKey,
23
- value,
24
- setValue,
25
- autoFocus,
26
- error,
27
- showError,
28
- disabled,
29
- touched,
30
- property,
31
- includeDescription
32
- }: DateTimeFieldProps) {
22
+ propertyKey,
23
+ value,
24
+ setValue,
25
+ autoFocus,
26
+ error,
27
+ showError,
28
+ disabled,
29
+ touched,
30
+ property,
31
+ includeDescription
32
+ }: DateTimeFieldProps) {
33
33
 
34
34
  const { locale } = useCustomizationController();
35
35
  const internalValue = value || null;
@@ -50,21 +50,22 @@ export function DateTimeFieldBinding({
50
50
  mode={property.mode}
51
51
  clearable={property.clearable}
52
52
  locale={locale}
53
+ timezone={property.timezone}
53
54
  error={showError}
54
55
  disabled={disabled}
55
56
  label={<LabelWithIcon
56
57
  icon={getIconForProperty(property, "small")}
57
58
  required={property.validation?.required}
58
59
  className={showError ? "text-red-500 dark:text-red-500" : "text-text-secondary dark:text-text-secondary-dark"}
59
- title={property.name}/>}
60
+ title={property.name} />}
60
61
  />
61
62
  </PropertyIdCopyTooltip>
62
63
 
63
64
  <FieldHelperText includeDescription={includeDescription}
64
- showError={showError}
65
- error={error}
66
- disabled={disabled}
67
- property={property}/>
65
+ showError={showError}
66
+ error={error}
67
+ disabled={disabled}
68
+ property={property} />
68
69
 
69
70
  </>
70
71
  );
@@ -215,7 +215,6 @@ function MapEditView<T extends Record<string, any>>({
215
215
 
216
216
  <Button variant={"text"}
217
217
  size={"small"}
218
- color="primary"
219
218
  className="w-full"
220
219
  disabled={disabled}
221
220
  startIcon={<AddIcon/>}