@firecms/core 3.0.1 → 3.1.0-canary.24c8270

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 (186) 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/EntityCollectionTable/internal/popup_field/useDraggable.d.ts +2 -2
  10. package/dist/components/EntityCollectionView/Board.d.ts +2 -0
  11. package/dist/components/EntityCollectionView/BoardColumn.d.ts +42 -0
  12. package/dist/components/EntityCollectionView/BoardColumnTitle.d.ts +9 -0
  13. package/dist/components/EntityCollectionView/BoardSortableList.d.ts +14 -0
  14. package/dist/components/EntityCollectionView/EntityBoardCard.d.ts +26 -0
  15. package/dist/components/EntityCollectionView/EntityCard.d.ts +19 -0
  16. package/dist/components/EntityCollectionView/EntityCollectionBoardView.d.ts +20 -0
  17. package/dist/components/EntityCollectionView/EntityCollectionCardView.d.ts +31 -0
  18. package/dist/components/EntityCollectionView/EntityCollectionViewActions.d.ts +2 -2
  19. package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +7 -3
  20. package/dist/components/EntityCollectionView/FiltersDialog.d.ts +14 -0
  21. package/dist/components/EntityCollectionView/ViewModeToggle.d.ts +44 -0
  22. package/dist/components/EntityCollectionView/board_types.d.ts +105 -0
  23. package/dist/components/EntityCollectionView/useBoardDataController.d.ts +60 -0
  24. package/dist/components/ErrorBoundary.d.ts +1 -1
  25. package/dist/components/SelectableTable/SelectableTable.d.ts +5 -1
  26. package/dist/components/SelectableTable/filters/DateTimeFilterField.d.ts +2 -1
  27. package/dist/components/VirtualTable/VirtualTableCell.d.ts +6 -0
  28. package/dist/components/VirtualTable/VirtualTableHeader.d.ts +3 -1
  29. package/dist/components/VirtualTable/VirtualTableHeaderRow.d.ts +1 -1
  30. package/dist/components/VirtualTable/VirtualTableProps.d.ts +11 -0
  31. package/dist/components/VirtualTable/fields/VirtualTableDateField.d.ts +1 -0
  32. package/dist/components/VirtualTable/types.d.ts +2 -0
  33. package/dist/components/index.d.ts +3 -0
  34. package/dist/contexts/index.d.ts +10 -0
  35. package/dist/core/DrawerNavigationGroup.d.ts +45 -0
  36. package/dist/core/index.d.ts +1 -0
  37. package/dist/form/components/ErrorFocus.d.ts +1 -1
  38. package/dist/form/validation.d.ts +3 -2
  39. package/dist/hooks/useBreadcrumbsController.d.ts +16 -0
  40. package/dist/hooks/useCollapsedGroups.d.ts +4 -1
  41. package/dist/index.es.js +5316 -1592
  42. package/dist/index.es.js.map +1 -1
  43. package/dist/index.umd.js +5309 -1586
  44. package/dist/index.umd.js.map +1 -1
  45. package/dist/internal/useRestoreScroll.d.ts +1 -1
  46. package/dist/preview/PropertyPreviewProps.d.ts +5 -0
  47. package/dist/preview/components/DatePreview.d.ts +13 -3
  48. package/dist/preview/components/ImagePreview.d.ts +5 -1
  49. package/dist/preview/components/StorageThumbnail.d.ts +2 -1
  50. package/dist/preview/components/UrlComponentPreview.d.ts +2 -1
  51. package/dist/preview/property_previews/ArrayOfStorageComponentsPreview.d.ts +1 -1
  52. package/dist/preview/property_previews/ArrayOfStringsPreview.d.ts +1 -1
  53. package/dist/preview/property_previews/SkeletonPropertyComponent.d.ts +1 -1
  54. package/dist/types/analytics.d.ts +1 -1
  55. package/dist/types/collections.d.ts +50 -2
  56. package/dist/types/datasource.d.ts +0 -1
  57. package/dist/types/plugins.d.ts +62 -1
  58. package/dist/types/properties.d.ts +259 -4
  59. package/dist/util/__tests__/conditions.test.d.ts +1 -0
  60. package/dist/util/__tests__/objects.test.d.ts +1 -0
  61. package/dist/util/conditions.d.ts +26 -0
  62. package/dist/util/entities.d.ts +2 -3
  63. package/dist/util/index.d.ts +2 -1
  64. package/dist/util/property_utils.d.ts +2 -1
  65. package/dist/util/resolutions.d.ts +3 -3
  66. package/package.json +14 -11
  67. package/src/app/Scaffold.tsx +14 -15
  68. package/src/components/AIIcon.tsx +39 -0
  69. package/src/components/ArrayContainer.tsx +1 -4
  70. package/src/components/ClearFilterSortButton.tsx +19 -16
  71. package/src/components/ConfirmationDialog.tsx +0 -2
  72. package/src/components/DeleteEntityDialog.tsx +2 -4
  73. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +74 -41
  74. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +130 -79
  75. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +121 -104
  76. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +132 -103
  77. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +20 -42
  78. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +90 -49
  79. package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +1 -1
  80. package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +11 -11
  81. package/src/components/EntityCollectionView/Board.tsx +324 -0
  82. package/src/components/EntityCollectionView/BoardColumn.tsx +158 -0
  83. package/src/components/EntityCollectionView/BoardColumnTitle.tsx +45 -0
  84. package/src/components/EntityCollectionView/BoardSortableList.tsx +172 -0
  85. package/src/components/EntityCollectionView/EntityBoardCard.tsx +212 -0
  86. package/src/components/EntityCollectionView/EntityCard.tsx +235 -0
  87. package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +733 -0
  88. package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +244 -0
  89. package/src/components/EntityCollectionView/EntityCollectionView.tsx +519 -203
  90. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +31 -19
  91. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +84 -15
  92. package/src/components/EntityCollectionView/FiltersDialog.tsx +249 -0
  93. package/src/components/EntityCollectionView/ViewModeToggle.tsx +199 -0
  94. package/src/components/EntityCollectionView/board_types.ts +113 -0
  95. package/src/components/EntityCollectionView/useBoardDataController.tsx +490 -0
  96. package/src/components/ErrorTooltip.tsx +2 -1
  97. package/src/components/HomePage/DefaultHomePage.tsx +47 -10
  98. package/src/components/HomePage/HomePageDnD.tsx +56 -41
  99. package/src/components/HomePage/NavigationCard.tsx +20 -18
  100. package/src/components/HomePage/NavigationGroup.tsx +17 -16
  101. package/src/components/HomePage/RenameGroupDialog.tsx +0 -2
  102. package/src/components/HomePage/SmallNavigationCard.tsx +10 -9
  103. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +3 -10
  104. package/src/components/ReferenceWidget.tsx +2 -4
  105. package/src/components/SelectableTable/SelectableTable.tsx +75 -67
  106. package/src/components/SelectableTable/filters/BooleanFilterField.tsx +7 -6
  107. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +39 -40
  108. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +38 -38
  109. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +49 -58
  110. package/src/components/UnsavedChangesDialog.tsx +0 -2
  111. package/src/components/UserDisplay.tsx +4 -4
  112. package/src/components/VirtualTable/VirtualTable.tsx +272 -118
  113. package/src/components/VirtualTable/VirtualTableCell.tsx +18 -2
  114. package/src/components/VirtualTable/VirtualTableHeader.tsx +59 -50
  115. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +158 -42
  116. package/src/components/VirtualTable/VirtualTableProps.tsx +14 -1
  117. package/src/components/VirtualTable/VirtualTableRow.tsx +1 -1
  118. package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +3 -0
  119. package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +19 -6
  120. package/src/components/VirtualTable/types.tsx +2 -0
  121. package/src/components/common/useColumnsIds.tsx +95 -3
  122. package/src/components/common/useDataSourceTableController.tsx +21 -4
  123. package/src/components/index.tsx +4 -0
  124. package/src/contexts/BreacrumbsContext.tsx +15 -8
  125. package/src/contexts/index.ts +10 -0
  126. package/src/core/DefaultAppBar.tsx +40 -27
  127. package/src/core/DefaultDrawer.tsx +42 -56
  128. package/src/core/DrawerNavigationGroup.tsx +118 -0
  129. package/src/core/DrawerNavigationItem.tsx +4 -3
  130. package/src/core/EntityEditView.tsx +41 -43
  131. package/src/core/EntitySidePanel.tsx +28 -26
  132. package/src/core/SideDialogs.tsx +4 -2
  133. package/src/core/field_configs.tsx +14 -9
  134. package/src/core/index.tsx +1 -0
  135. package/src/form/EntityForm.tsx +69 -60
  136. package/src/form/PropertyFieldBinding.tsx +61 -46
  137. package/src/form/components/ErrorFocus.tsx +3 -3
  138. package/src/form/components/StorageItemPreview.tsx +2 -1
  139. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +0 -1
  140. package/src/form/field_bindings/DateTimeFieldBinding.tsx +17 -16
  141. package/src/form/field_bindings/KeyValueFieldBinding.tsx +0 -1
  142. package/src/form/field_bindings/MapFieldBinding.tsx +69 -67
  143. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +22 -18
  144. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +83 -83
  145. package/src/form/field_bindings/TextFieldBinding.tsx +71 -35
  146. package/src/form/validation.ts +245 -160
  147. package/src/hooks/useBreadcrumbsController.tsx +18 -0
  148. package/src/hooks/useBuildNavigationController.tsx +71 -28
  149. package/src/hooks/useCollapsedGroups.ts +12 -4
  150. package/src/hooks/useValidateAuthenticator.tsx +1 -1
  151. package/src/internal/useBuildDataSource.ts +68 -34
  152. package/src/internal/useBuildSideDialogsController.tsx +11 -8
  153. package/src/internal/useBuildSideEntityController.tsx +24 -24
  154. package/src/internal/useRestoreScroll.tsx +26 -14
  155. package/src/preview/PropertyPreview.tsx +41 -32
  156. package/src/preview/PropertyPreviewProps.tsx +6 -0
  157. package/src/preview/components/DatePreview.tsx +72 -4
  158. package/src/preview/components/EmptyValue.tsx +1 -1
  159. package/src/preview/components/ImagePreview.tsx +37 -21
  160. package/src/preview/components/StorageThumbnail.tsx +16 -12
  161. package/src/preview/components/UrlComponentPreview.tsx +28 -25
  162. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +9 -7
  163. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +11 -9
  164. package/src/preview/property_previews/ArrayPropertyPreview.tsx +26 -24
  165. package/src/preview/property_previews/SkeletonPropertyComponent.tsx +61 -56
  166. package/src/routes/CustomCMSRoute.tsx +1 -0
  167. package/src/routes/FireCMSRoute.tsx +26 -13
  168. package/src/types/analytics.ts +10 -0
  169. package/src/types/collections.ts +57 -3
  170. package/src/types/datasource.ts +54 -56
  171. package/src/types/plugins.tsx +69 -1
  172. package/src/types/properties.ts +347 -27
  173. package/src/util/__tests__/conditions.test.ts +506 -0
  174. package/src/util/__tests__/objects.test.ts +196 -0
  175. package/src/util/callbacks.ts +6 -3
  176. package/src/util/collections.ts +51 -6
  177. package/src/util/conditions.ts +339 -0
  178. package/src/util/entities.ts +29 -30
  179. package/src/util/entity_cache.ts +2 -1
  180. package/src/util/index.ts +2 -1
  181. package/src/util/join_collections.ts +10 -8
  182. package/src/util/objects.ts +31 -13
  183. package/src/util/{references.ts → previews.ts} +16 -2
  184. package/src/util/property_utils.tsx +37 -11
  185. package/src/util/resolutions.ts +62 -58
  186. /package/dist/util/{references.d.ts → previews.d.ts} +0 -0
@@ -12,10 +12,9 @@ export function isObject(item: any) {
12
12
  return item && typeof item === "object" && !Array.isArray(item);
13
13
  }
14
14
 
15
-
16
- export function isPlainObject(obj:any) {
15
+ export function isPlainObject(obj: any) {
17
16
  // 1. Rule out non-objects, null, and arrays
18
- if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
17
+ if (typeof obj !== "object" || obj === null || Array.isArray(obj)) {
19
18
  return false;
20
19
  }
21
20
 
@@ -26,7 +25,6 @@ export function isPlainObject(obj:any) {
26
25
  return proto === Object.prototype;
27
26
  }
28
27
 
29
-
30
28
  export function mergeDeep<T extends Record<any, any>, U extends Record<any, any>>(
31
29
  target: T,
32
30
  source: U,
@@ -75,9 +73,11 @@ export function mergeDeep<T extends Record<any, any>, U extends Record<any, any>
75
73
  newArray[i] = sourceItem;
76
74
  } else if (sourceItem === null) {
77
75
  newArray[i] = targetItem;
78
- } else if (isObject(sourceItem) && isObject(targetItem)) {
76
+ } else if (isPlainObject(sourceItem) && isPlainObject(targetItem)) {
77
+ // Only recursively merge plain objects, preserve class instances
79
78
  newArray[i] = mergeDeep(targetItem, sourceItem, ignoreUndefined);
80
79
  } else {
80
+ // For class instances and primitives, use source directly
81
81
  newArray[i] = sourceItem;
82
82
  }
83
83
  }
@@ -87,17 +87,20 @@ export function mergeDeep<T extends Record<any, any>, U extends Record<any, any>
87
87
  // overwrite with a shallow copy of the source array.
88
88
  (output as any)[key] = [...sourceValue];
89
89
  }
90
- } else if (isObject(sourceValue)) {
91
- // If source value is an object:
92
- if (isObject(outputValue)) {
93
- // If the corresponding value in output (from target) is also an object, recurse.
90
+ } else if (isPlainObject(sourceValue)) {
91
+ // If source value is a plain object (not a class instance like EntityReference, GeoPoint, etc.):
92
+ if (isPlainObject(outputValue)) {
93
+ // If the corresponding value in output (from target) is also a plain object, recurse.
94
94
  // Ensure the ignoreUndefined flag is passed down.
95
95
  (output as any)[key] = mergeDeep(outputValue, sourceValue, ignoreUndefined);
96
96
  } else {
97
- // If output's value (from target) is not an object (e.g., null, primitive, or key didn't exist in original target),
97
+ // If output's value (from target) is not a plain object (e.g., null, primitive, class instance, or key didn't exist in original target),
98
98
  // overwrite with the source object.
99
99
  (output as any)[key] = sourceValue;
100
100
  }
101
+ } else if (isObject(sourceValue)) {
102
+ // If source value is a class instance (not a plain object), use it directly to preserve prototype
103
+ (output as any)[key] = sourceValue;
101
104
  } else {
102
105
  // If source value is a primitive, null, or undefined (and not ignored).
103
106
  (output as any)[key] = sourceValue;
@@ -108,7 +111,6 @@ export function mergeDeep<T extends Record<any, any>, U extends Record<any, any>
108
111
  return output as T & U;
109
112
  }
110
113
 
111
-
112
114
  export function getValueInPath(o: object | undefined, path: string): any {
113
115
  if (!o) return undefined;
114
116
  if (typeof o === "object") {
@@ -151,6 +153,14 @@ export function removeFunctions(o: object | undefined): any {
151
153
  if (o === undefined) return undefined;
152
154
  if (o === null) return null;
153
155
  if (typeof o === "object") {
156
+ // Handle arrays first - map over them recursively
157
+ if (Array.isArray(o)) {
158
+ return o.map(v => removeFunctions(v));
159
+ }
160
+ // Preserve class instances (EntityReference, GeoPoint, etc.) - don't recurse into them
161
+ if (!isPlainObject(o)) {
162
+ return o;
163
+ }
154
164
  return Object.entries(o)
155
165
  .filter(([_, value]) => typeof value !== "function")
156
166
  .map(([key, value]) => {
@@ -186,9 +196,13 @@ export function removeUndefined(value: any, removeEmptyStrings?: boolean): any {
186
196
  return value.map((v: any) => removeUndefined(v, removeEmptyStrings));
187
197
  }
188
198
  if (typeof value === "object") {
189
- const res: object = {};
190
199
  if (value === null)
191
200
  return value;
201
+ // Preserve class instances (EntityReference, GeoPoint, etc.) - don't recurse into them
202
+ if (!isPlainObject(value)) {
203
+ return value;
204
+ }
205
+ const res: object = {};
192
206
  Object.keys(value).forEach((key) => {
193
207
  if (!isEmptyObject(value)) {
194
208
  const childRes = removeUndefined(value[key], removeEmptyStrings);
@@ -211,9 +225,13 @@ export function removeNulls(value: any): any {
211
225
  return value.map((v: any) => removeNulls(v));
212
226
  }
213
227
  if (typeof value === "object") {
214
- const res: object = {};
215
228
  if (value === null)
216
229
  return value;
230
+ // Preserve class instances (EntityReference, GeoPoint, etc.) - don't recurse into them
231
+ if (!isPlainObject(value)) {
232
+ return value;
233
+ }
234
+ const res: object = {};
217
235
  Object.keys(value).forEach((key) => {
218
236
  if (value[key] !== null)
219
237
  (res as any)[key] = removeNulls(value[key]);
@@ -1,4 +1,4 @@
1
- import { AuthController, EntityCollection, PropertyConfig, ResolvedEntityCollection } from "../types";
1
+ import { AuthController, EntityCollection, Property, PropertyConfig, ResolvedEntityCollection } from "../types";
2
2
  import { isReferenceProperty } from "./property_utils";
3
3
  import { isPropertyBuilder } from "./entities";
4
4
  import { getFieldConfig } from "../core";
@@ -33,7 +33,7 @@ export function getEntityTitlePropertyKey<M extends Record<string, any>>(collect
33
33
  for (const key in collection.properties) {
34
34
  const property = collection.properties[key];
35
35
  if (!isPropertyBuilder(property)) {
36
- const field = getFieldConfig(property, propertyConfigs);
36
+ const field = getFieldConfig(property as Property, propertyConfigs);
37
37
  if (field?.key === "text_field") {
38
38
  return key;
39
39
  }
@@ -58,5 +58,19 @@ export function getEntityImagePreviewPropertyKey<M extends object>(collection: R
58
58
  return key;
59
59
  }
60
60
  }
61
+ // also check for URL properties with image preview type
62
+ for (const key in collection.properties) {
63
+ const property = collection.properties[key];
64
+ if (property.dataType === "string" && property.url === "image") {
65
+ return key;
66
+ }
67
+ }
68
+ // and arrays of URL properties with image preview type
69
+ for (const key in collection.properties) {
70
+ const property = collection.properties[key];
71
+ if (property.dataType === "array" && property.of?.dataType === "string" && property.of.url === "image") {
72
+ return key;
73
+ }
74
+ }
61
75
  return undefined;
62
76
  }
@@ -18,7 +18,7 @@ export function isReferenceProperty(
18
18
  authController: AuthController,
19
19
  propertyOrBuilder: PropertyOrBuilder,
20
20
  fields: Record<string, PropertyConfig>) {
21
- const resolvedProperty = resolveProperty({
21
+ const resolvedProperty: ResolvedProperty<any> | null = resolveProperty({
22
22
  propertyKey: "ignore", // TODO
23
23
  propertyOrBuilder,
24
24
  propertyConfigs: fields,
@@ -36,13 +36,13 @@ export function isReferenceProperty(
36
36
  }
37
37
 
38
38
  export function getIdIcon(size: "small" | "medium" | "large"): React.ReactNode {
39
- return <CircleIcon size={size}/>;
39
+ return <CircleIcon size={size} />;
40
40
  }
41
41
 
42
42
  export function getIconForWidget(widget: PropertyConfig | undefined,
43
- size: "small" | "medium" | "large") {
43
+ size: "small" | "medium" | "large") {
44
44
  const Icon = widget?.Icon ?? CircleIcon;
45
- return <Icon size={size}/>;
45
+ return <Icon size={size} />;
46
46
  }
47
47
 
48
48
  export function getIconForProperty(
@@ -52,7 +52,7 @@ export function getIconForProperty(
52
52
  ): React.ReactNode {
53
53
 
54
54
  if (isPropertyBuilder(property)) {
55
- return <FunctionsIcon size={size}/>;
55
+ return <FunctionsIcon size={size} />;
56
56
  } else {
57
57
  const widget = getFieldConfig(property, fields);
58
58
  return getIconForWidget(widget, size);
@@ -113,25 +113,51 @@ export function getBracketNotation(path: string): string {
113
113
  }
114
114
 
115
115
  /**
116
- * Get properties exclusively indexed by their order
116
+ * Get properties sorted by their order, but include ALL properties.
117
+ * Nested keys (like "data.mode") in propertiesOrder are ignored - they're for column ordering.
117
118
  * @param properties
118
119
  * @param propertiesOrder
119
120
  */
120
121
  export function getPropertiesWithPropertiesOrder<M extends Record<string, any>>(properties: PropertiesOrBuilders<M>, propertiesOrder?: Extract<keyof M, string>[]): PropertiesOrBuilders<M> {
121
122
  if (!propertiesOrder) return properties;
123
+
124
+ const propertyKeys = Object.keys(properties);
125
+
126
+ // Filter propertiesOrder to only include top-level keys (no dots) that exist
127
+ const validOrderKeys = (propertiesOrder as string[]).filter(
128
+ key => !key.includes(".") && properties[key as keyof M]
129
+ );
130
+
122
131
  const result: PropertiesOrBuilders<any> = {};
123
- propertiesOrder.filter(Boolean).forEach(path => {
124
- const property = getPropertyInPath(properties, path);
132
+
133
+ // First add properties in the specified order
134
+ validOrderKeys.forEach(key => {
135
+ const property = properties[key];
125
136
  if (typeof property === "object" && property.dataType === "map" && property.properties) {
126
- result[path] = {
137
+ result[key] = {
127
138
  ...property,
128
139
  properties: getPropertiesWithPropertiesOrder(property.properties, property.propertiesOrder ?? [])
129
140
  }
141
+ } else if (property) {
142
+ result[key] = property;
130
143
  }
131
- if (property) {
132
- result[path] = property;
144
+ });
145
+
146
+ // Then add any missing properties (so they don't disappear!)
147
+ propertyKeys.forEach(key => {
148
+ if (!result[key]) {
149
+ const property = properties[key];
150
+ if (typeof property === "object" && property.dataType === "map" && property.properties) {
151
+ result[key] = {
152
+ ...property,
153
+ properties: getPropertiesWithPropertiesOrder(property.properties, property.propertiesOrder ?? [])
154
+ }
155
+ } else if (property) {
156
+ result[key] = property;
157
+ }
133
158
  }
134
159
  });
160
+
135
161
  return result;
136
162
  }
137
163
 
@@ -13,6 +13,7 @@ import {
13
13
  Properties,
14
14
  PropertiesOrBuilders,
15
15
  Property,
16
+ PropertyBuilder,
16
17
  PropertyConfig,
17
18
  PropertyOrBuilder,
18
19
  ResolvedArrayProperty,
@@ -31,28 +32,28 @@ import { getIn } from "@firecms/formex";
31
32
  import { enumToObjectEntries } from "./enums";
32
33
  import { isDefaultFieldConfigId } from "../core";
33
34
 
34
- export const resolveCollection = <M extends Record<string, any>, >
35
- ({
36
- collection,
37
- path,
38
- entityId,
39
- values,
40
- previousValues,
41
- userConfigPersistence,
42
- propertyConfigs,
43
- ignoreMissingFields = false,
44
- authController
45
- }: {
46
- collection: EntityCollection<M> | ResolvedEntityCollection<M>;
47
- path: string,
48
- entityId?: string,
49
- values?: Partial<EntityValues<M>>,
50
- previousValues?: Partial<EntityValues<M>>,
51
- userConfigPersistence?: UserConfigurationPersistence;
52
- propertyConfigs?: Record<string, PropertyConfig>;
53
- ignoreMissingFields?: boolean;
54
- authController: AuthController;
55
- }): ResolvedEntityCollection<M> => {
35
+ export const resolveCollection = <M extends Record<string, any>,>
36
+ ({
37
+ collection,
38
+ path,
39
+ entityId,
40
+ values,
41
+ previousValues,
42
+ userConfigPersistence,
43
+ propertyConfigs,
44
+ ignoreMissingFields = false,
45
+ authController
46
+ }: {
47
+ collection: EntityCollection<M> | ResolvedEntityCollection<M>;
48
+ path: string,
49
+ entityId?: string,
50
+ values?: Partial<EntityValues<M>>,
51
+ previousValues?: Partial<EntityValues<M>>,
52
+ userConfigPersistence?: UserConfigurationPersistence;
53
+ propertyConfigs?: Record<string, PropertyConfig>;
54
+ ignoreMissingFields?: boolean;
55
+ authController: AuthController;
56
+ }): ResolvedEntityCollection<M> => {
56
57
 
57
58
  const collectionOverride = userConfigPersistence?.getCollectionConfig<M>(path);
58
59
  const storedProperties = getValueInPath(collectionOverride, "properties");
@@ -62,6 +63,7 @@ export const resolveCollection = <M extends Record<string, any>, >
62
63
  const usedPreviousValues = previousValues ?? values ?? defaultValues;
63
64
 
64
65
  const resolvedProperties = Object.entries(collection.properties)
66
+ .filter(([, propertyOrBuilder]) => propertyOrBuilder != null)
65
67
  .map(([key, propertyOrBuilder]) => {
66
68
  const childResolvedProperty = resolveProperty({
67
69
  propertyKey: key,
@@ -102,13 +104,13 @@ export const resolveCollection = <M extends Record<string, any>, >
102
104
  * @param propertyValue
103
105
  */
104
106
  export function resolveProperty<T extends CMSType = CMSType, M extends Record<string, any> = any>({
105
- propertyOrBuilder,
106
- fromBuilder = false,
107
- ignoreMissingFields = false,
108
- ...props
109
- }: {
107
+ propertyOrBuilder,
108
+ fromBuilder = false,
109
+ ignoreMissingFields = false,
110
+ ...props
111
+ }: {
110
112
  propertyKey?: string,
111
- propertyOrBuilder: PropertyOrBuilder<T, M> | ResolvedProperty<T>,
113
+ propertyOrBuilder: PropertyOrBuilder<T, M> | ResolvedProperty<T> | PropertyOrBuilder | Property | ResolvedProperty | undefined,
112
114
  values?: Partial<M>,
113
115
  previousValues?: Partial<M>,
114
116
  path?: string,
@@ -120,7 +122,7 @@ export function resolveProperty<T extends CMSType = CMSType, M extends Record<st
120
122
  authController: AuthController;
121
123
  }): ResolvedProperty<T> | null {
122
124
 
123
- if (typeof propertyOrBuilder === "object" && "resolved" in propertyOrBuilder) {
125
+ if (propertyOrBuilder !== null && typeof propertyOrBuilder === "object" && "resolved" in propertyOrBuilder) {
124
126
  return propertyOrBuilder as ResolvedProperty<T>;
125
127
  }
126
128
 
@@ -134,7 +136,7 @@ export function resolveProperty<T extends CMSType = CMSType, M extends Record<st
134
136
  throw Error("Trying to resolve a property builder without specifying the entity path");
135
137
 
136
138
  const usedPropertyValue = props.propertyKey ? getIn(props.values, props.propertyKey) : undefined;
137
- const result: Property<T> | null = propertyOrBuilder({
139
+ const result: Property<T> | null = (propertyOrBuilder as PropertyBuilder<T, M>)({
138
140
  ...props,
139
141
  path,
140
142
  propertyValue: usedPropertyValue,
@@ -223,11 +225,11 @@ export function resolveProperty<T extends CMSType = CMSType, M extends Record<st
223
225
  }
224
226
 
225
227
  export function getArrayResolvedProperties<M>({
226
- propertyKey,
227
- propertyValue,
228
- property,
229
- ...props
230
- }: {
228
+ propertyKey,
229
+ propertyValue,
230
+ property,
231
+ ...props
232
+ }: {
231
233
  propertyValue: any,
232
234
  propertyKey?: string,
233
235
  property: ArrayProperty<any> | ResolvedArrayProperty<any>,
@@ -256,11 +258,11 @@ export function getArrayResolvedProperties<M>({
256
258
  }
257
259
 
258
260
  export function resolveArrayProperty<T extends any[], M>({
259
- propertyKey,
260
- property,
261
- ignoreMissingFields = false,
262
- ...props
263
- }: {
261
+ propertyKey,
262
+ property,
263
+ ignoreMissingFields = false,
264
+ ...props
265
+ }: {
264
266
  propertyKey?: string,
265
267
  property: ArrayProperty<T> | ResolvedArrayProperty<T>,
266
268
  values?: Partial<M>,
@@ -272,7 +274,7 @@ export function resolveArrayProperty<T extends any[], M>({
272
274
  propertyConfigs?: Record<string, PropertyConfig>;
273
275
  ignoreMissingFields?: boolean;
274
276
  authController: AuthController;
275
- }): ResolvedArrayProperty {
277
+ }): ResolvedArrayProperty | null {
276
278
  const propertyValue = propertyKey ? getIn(props.values, propertyKey) : undefined;
277
279
 
278
280
  if (property.of) {
@@ -347,7 +349,8 @@ export function resolveArrayProperty<T extends any[], M>({
347
349
  resolvedProperties
348
350
  } as ResolvedArrayProperty;
349
351
  } else if (!property.Field) {
350
- throw Error("The array property needs to declare an 'of' or a 'oneOf' property, or provide a custom `Field`")
352
+ console.error("The array property needs to declare an 'of' or a 'oneOf' property, or provide a custom `Field`", property);
353
+ return null;
351
354
  } else {
352
355
  return {
353
356
  ...property,
@@ -364,11 +367,11 @@ export function resolveArrayProperty<T extends any[], M>({
364
367
  * @param value
365
368
  */
366
369
  export function resolveProperties<M extends Record<string, any>>({
367
- propertyKey,
368
- properties,
369
- ignoreMissingFields,
370
- ...props
371
- }: {
370
+ propertyKey,
371
+ properties,
372
+ ignoreMissingFields,
373
+ ...props
374
+ }: {
372
375
  propertyKey?: string,
373
376
  properties: PropertiesOrBuilders<M>,
374
377
  values?: Partial<M>,
@@ -416,16 +419,17 @@ export function resolvePropertyEnum(property: StringProperty | NumberProperty, f
416
419
  }
417
420
 
418
421
  export function resolveEnumValues(input: EnumValues): EnumValueConfig[] | undefined {
419
- if (typeof input === "object") {
420
- return Object.entries(input).map(([id, value]) =>
421
- (typeof value === "string"
422
- ? {
423
- id,
424
- label: value
425
- }
426
- : value));
427
- } else if (Array.isArray(input)) {
422
+ // Check Array.isArray first since typeof [] === "object" is true in JavaScript
423
+ if (Array.isArray(input)) {
428
424
  return input as EnumValueConfig[];
425
+ } else if (typeof input === "object" && input !== null) {
426
+ return Object.entries(input).map(([id, value]) =>
427
+ (typeof value === "string"
428
+ ? {
429
+ id,
430
+ label: value
431
+ }
432
+ : value));
429
433
  } else {
430
434
  return undefined;
431
435
  }
@@ -457,8 +461,8 @@ export function resolvedSelectedEntityView<M extends Record<string, any>>(
457
461
  canEdit?: boolean,
458
462
  ) {
459
463
  const resolvedEntityViews = customViews ? customViews
460
- .map(e => resolveEntityView(e, customizationController.entityViews))
461
- .filter((e): e is EntityCustomView<M> => Boolean(e))
464
+ .map(e => resolveEntityView(e, customizationController.entityViews))
465
+ .filter((e): e is EntityCustomView<M> => Boolean(e))
462
466
  // .filter((e) => canEdit || !e.includeActions)
463
467
  : [];
464
468
 
File without changes