@firecms/core 3.0.1 → 3.1.0-canary.7d91b7c
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.
- package/README.md +1 -1
- package/dist/components/AIIcon.d.ts +16 -0
- package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +7 -1
- package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +1 -1
- package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +14 -0
- package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +6 -0
- package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +5 -4
- package/dist/components/EntityCollectionTable/internal/EntityTableCell.d.ts +6 -0
- package/dist/components/EntityCollectionTable/internal/popup_field/useDraggable.d.ts +2 -2
- package/dist/components/EntityCollectionView/Board.d.ts +2 -0
- package/dist/components/EntityCollectionView/BoardColumn.d.ts +42 -0
- package/dist/components/EntityCollectionView/BoardColumnTitle.d.ts +9 -0
- package/dist/components/EntityCollectionView/BoardSortableList.d.ts +14 -0
- package/dist/components/EntityCollectionView/EntityBoardCard.d.ts +26 -0
- package/dist/components/EntityCollectionView/EntityCard.d.ts +19 -0
- package/dist/components/EntityCollectionView/EntityCollectionBoardView.d.ts +20 -0
- package/dist/components/EntityCollectionView/EntityCollectionCardView.d.ts +31 -0
- package/dist/components/EntityCollectionView/EntityCollectionViewActions.d.ts +2 -2
- package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +7 -3
- package/dist/components/EntityCollectionView/FiltersDialog.d.ts +14 -0
- package/dist/components/EntityCollectionView/ViewModeToggle.d.ts +44 -0
- package/dist/components/EntityCollectionView/board_types.d.ts +105 -0
- package/dist/components/EntityCollectionView/useBoardDataController.d.ts +60 -0
- package/dist/components/ErrorBoundary.d.ts +1 -1
- package/dist/components/SelectableTable/SelectableTable.d.ts +5 -1
- package/dist/components/SelectableTable/filters/DateTimeFilterField.d.ts +2 -1
- package/dist/components/VirtualTable/VirtualTableCell.d.ts +6 -0
- package/dist/components/VirtualTable/VirtualTableHeader.d.ts +3 -1
- package/dist/components/VirtualTable/VirtualTableHeaderRow.d.ts +1 -1
- package/dist/components/VirtualTable/VirtualTableProps.d.ts +11 -0
- package/dist/components/VirtualTable/fields/VirtualTableDateField.d.ts +1 -0
- package/dist/components/VirtualTable/types.d.ts +2 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/contexts/index.d.ts +10 -0
- package/dist/core/DrawerNavigationGroup.d.ts +45 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/form/components/ErrorFocus.d.ts +1 -1
- package/dist/form/validation.d.ts +3 -2
- package/dist/hooks/useBreadcrumbsController.d.ts +16 -0
- package/dist/hooks/useCollapsedGroups.d.ts +4 -1
- package/dist/index.es.js +5266 -1578
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +5260 -1573
- package/dist/index.umd.js.map +1 -1
- package/dist/internal/useRestoreScroll.d.ts +1 -1
- package/dist/preview/PropertyPreviewProps.d.ts +5 -0
- package/dist/preview/components/DatePreview.d.ts +13 -3
- package/dist/preview/components/ImagePreview.d.ts +5 -1
- package/dist/preview/components/StorageThumbnail.d.ts +2 -1
- package/dist/preview/components/UrlComponentPreview.d.ts +2 -1
- package/dist/preview/property_previews/ArrayOfStorageComponentsPreview.d.ts +1 -1
- package/dist/preview/property_previews/ArrayOfStringsPreview.d.ts +1 -1
- package/dist/preview/property_previews/SkeletonPropertyComponent.d.ts +1 -1
- package/dist/types/analytics.d.ts +1 -1
- package/dist/types/collections.d.ts +50 -2
- package/dist/types/datasource.d.ts +0 -1
- package/dist/types/plugins.d.ts +62 -1
- package/dist/types/properties.d.ts +259 -4
- package/dist/util/__tests__/conditions.test.d.ts +1 -0
- package/dist/util/__tests__/objects.test.d.ts +1 -0
- package/dist/util/conditions.d.ts +26 -0
- package/dist/util/entities.d.ts +2 -3
- package/dist/util/index.d.ts +2 -1
- package/dist/util/property_utils.d.ts +2 -1
- package/dist/util/resolutions.d.ts +3 -3
- package/package.json +14 -11
- package/src/app/Scaffold.tsx +14 -15
- package/src/components/AIIcon.tsx +39 -0
- package/src/components/ArrayContainer.tsx +1 -4
- package/src/components/ClearFilterSortButton.tsx +19 -16
- package/src/components/ConfirmationDialog.tsx +0 -2
- package/src/components/DeleteEntityDialog.tsx +2 -4
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +74 -41
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +130 -79
- package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +121 -104
- package/src/components/EntityCollectionTable/PropertyTableCell.tsx +132 -103
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +20 -42
- package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +90 -49
- package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +1 -1
- package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +11 -11
- package/src/components/EntityCollectionView/Board.tsx +324 -0
- package/src/components/EntityCollectionView/BoardColumn.tsx +158 -0
- package/src/components/EntityCollectionView/BoardColumnTitle.tsx +45 -0
- package/src/components/EntityCollectionView/BoardSortableList.tsx +172 -0
- package/src/components/EntityCollectionView/EntityBoardCard.tsx +212 -0
- package/src/components/EntityCollectionView/EntityCard.tsx +235 -0
- package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +733 -0
- package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +244 -0
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +519 -203
- package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +31 -19
- package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +84 -15
- package/src/components/EntityCollectionView/FiltersDialog.tsx +249 -0
- package/src/components/EntityCollectionView/ViewModeToggle.tsx +199 -0
- package/src/components/EntityCollectionView/board_types.ts +113 -0
- package/src/components/EntityCollectionView/useBoardDataController.tsx +490 -0
- package/src/components/ErrorTooltip.tsx +2 -1
- package/src/components/HomePage/DefaultHomePage.tsx +47 -10
- package/src/components/HomePage/HomePageDnD.tsx +56 -41
- package/src/components/HomePage/NavigationCard.tsx +20 -18
- package/src/components/HomePage/NavigationGroup.tsx +17 -16
- package/src/components/HomePage/RenameGroupDialog.tsx +0 -2
- package/src/components/HomePage/SmallNavigationCard.tsx +10 -9
- package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +3 -10
- package/src/components/ReferenceWidget.tsx +2 -4
- package/src/components/SelectableTable/SelectableTable.tsx +75 -67
- package/src/components/SelectableTable/filters/BooleanFilterField.tsx +7 -6
- package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +39 -40
- package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +38 -38
- package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +49 -58
- package/src/components/UnsavedChangesDialog.tsx +0 -2
- package/src/components/UserDisplay.tsx +4 -4
- package/src/components/VirtualTable/VirtualTable.tsx +272 -118
- package/src/components/VirtualTable/VirtualTableCell.tsx +18 -2
- package/src/components/VirtualTable/VirtualTableHeader.tsx +59 -50
- package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +158 -42
- package/src/components/VirtualTable/VirtualTableProps.tsx +14 -1
- package/src/components/VirtualTable/VirtualTableRow.tsx +1 -1
- package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +3 -0
- package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +19 -6
- package/src/components/VirtualTable/types.tsx +2 -0
- package/src/components/common/useColumnsIds.tsx +95 -3
- package/src/components/index.tsx +4 -0
- package/src/contexts/BreacrumbsContext.tsx +15 -8
- package/src/contexts/index.ts +10 -0
- package/src/core/DefaultAppBar.tsx +40 -27
- package/src/core/DefaultDrawer.tsx +42 -56
- package/src/core/DrawerNavigationGroup.tsx +118 -0
- package/src/core/DrawerNavigationItem.tsx +4 -3
- package/src/core/EntityEditView.tsx +41 -43
- package/src/core/EntitySidePanel.tsx +28 -26
- package/src/core/SideDialogs.tsx +4 -2
- package/src/core/field_configs.tsx +14 -9
- package/src/core/index.tsx +1 -0
- package/src/form/EntityForm.tsx +69 -60
- package/src/form/PropertyFieldBinding.tsx +61 -46
- package/src/form/components/ErrorFocus.tsx +3 -3
- package/src/form/components/StorageItemPreview.tsx +2 -1
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +0 -1
- package/src/form/field_bindings/DateTimeFieldBinding.tsx +17 -16
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +0 -1
- package/src/form/field_bindings/MapFieldBinding.tsx +69 -67
- package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +22 -18
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +83 -83
- package/src/form/field_bindings/TextFieldBinding.tsx +71 -35
- package/src/form/validation.ts +245 -160
- package/src/hooks/useBreadcrumbsController.tsx +18 -0
- package/src/hooks/useBuildNavigationController.tsx +46 -23
- package/src/hooks/useCollapsedGroups.ts +12 -4
- package/src/hooks/useValidateAuthenticator.tsx +1 -1
- package/src/internal/useBuildDataSource.ts +68 -34
- package/src/internal/useBuildSideDialogsController.tsx +11 -8
- package/src/internal/useBuildSideEntityController.tsx +2 -4
- package/src/internal/useRestoreScroll.tsx +26 -14
- package/src/preview/PropertyPreview.tsx +41 -32
- package/src/preview/PropertyPreviewProps.tsx +6 -0
- package/src/preview/components/DatePreview.tsx +72 -4
- package/src/preview/components/EmptyValue.tsx +1 -1
- package/src/preview/components/ImagePreview.tsx +37 -21
- package/src/preview/components/StorageThumbnail.tsx +16 -12
- package/src/preview/components/UrlComponentPreview.tsx +28 -25
- package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +9 -7
- package/src/preview/property_previews/ArrayOfStringsPreview.tsx +11 -9
- package/src/preview/property_previews/ArrayPropertyPreview.tsx +26 -24
- package/src/preview/property_previews/SkeletonPropertyComponent.tsx +61 -56
- package/src/routes/CustomCMSRoute.tsx +1 -0
- package/src/routes/FireCMSRoute.tsx +26 -13
- package/src/types/analytics.ts +10 -0
- package/src/types/collections.ts +57 -3
- package/src/types/datasource.ts +54 -56
- package/src/types/plugins.tsx +69 -1
- package/src/types/properties.ts +347 -27
- package/src/util/__tests__/conditions.test.ts +506 -0
- package/src/util/__tests__/objects.test.ts +196 -0
- package/src/util/callbacks.ts +6 -3
- package/src/util/collections.ts +51 -6
- package/src/util/conditions.ts +339 -0
- package/src/util/entities.ts +29 -30
- package/src/util/entity_cache.ts +2 -1
- package/src/util/index.ts +2 -1
- package/src/util/join_collections.ts +10 -8
- package/src/util/objects.ts +31 -13
- package/src/util/{references.ts → previews.ts} +16 -2
- package/src/util/property_utils.tsx +37 -11
- package/src/util/resolutions.ts +62 -58
- /package/dist/util/{references.d.ts → previews.d.ts} +0 -0
package/src/util/objects.ts
CHANGED
|
@@ -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 !==
|
|
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 (
|
|
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 (
|
|
91
|
-
// If source value is
|
|
92
|
-
if (
|
|
93
|
-
// If the corresponding value in output (from target) is also
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
124
|
-
|
|
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[
|
|
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
|
-
|
|
132
|
-
|
|
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
|
|
package/src/util/resolutions.ts
CHANGED
|
@@ -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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
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
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
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
|
-
|
|
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
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
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
|
-
|
|
420
|
-
|
|
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
|
-
|
|
461
|
-
|
|
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
|