@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.
- 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/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 +49 -0
- package/dist/components/EntityCollectionView/board_types.d.ts +105 -0
- package/dist/components/EntityCollectionView/useBoardDataController.d.ts +60 -0
- 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 +2 -0
- 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/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 +5239 -1590
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +5233 -1585
- package/dist/index.umd.js.map +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/collections.d.ts +42 -2
- package/dist/types/datasource.d.ts +0 -1
- package/dist/types/plugins.d.ts +46 -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 +1 -2
- package/dist/util/index.d.ts +2 -1
- package/dist/util/property_utils.d.ts +2 -1
- package/dist/util/resolutions.d.ts +1 -1
- package/package.json +10 -7
- 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/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 +231 -0
- package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +713 -0
- package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +244 -0
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +485 -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 +202 -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 +170 -19
- package/src/components/VirtualTable/VirtualTableCell.tsx +18 -2
- package/src/components/VirtualTable/VirtualTableHeader.tsx +20 -11
- 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 +17 -4
- 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 +39 -26
- 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/SideDialogs.tsx +4 -2
- package/src/core/index.tsx +1 -0
- package/src/form/PropertyFieldBinding.tsx +58 -43
- 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 +21 -17
- 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 +42 -19
- package/src/hooks/useCollapsedGroups.ts +12 -4
- package/src/internal/useBuildDataSource.ts +69 -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 +40 -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/collections.ts +48 -3
- package/src/types/datasource.ts +54 -56
- package/src/types/plugins.tsx +51 -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 +28 -29
- package/src/util/entity_cache.ts +2 -1
- package/src/util/index.ts +2 -1
- package/src/util/objects.ts +31 -13
- package/src/util/{references.ts → previews.ts} +14 -0
- package/src/util/property_utils.tsx +36 -10
- package/src/util/resolutions.ts +57 -55
- /package/dist/util/{references.d.ts → previews.d.ts} +0 -0
package/src/form/validation.ts
CHANGED
|
@@ -14,8 +14,8 @@ import { enumToObjectEntries, getValueInPath, hydrateRegExp, isPropertyBuilder }
|
|
|
14
14
|
// Add custom unique function for array values
|
|
15
15
|
declare module "yup" {
|
|
16
16
|
// tslint:disable-next-line
|
|
17
|
-
interface ArraySchema<
|
|
18
|
-
uniqueInArray(mapper: (a:
|
|
17
|
+
interface ArraySchema<TIn extends any[] | null | undefined, TContext, TDefault = undefined, TFlags extends yup.Flags = ""> {
|
|
18
|
+
uniqueInArray(mapper: (a: any) => any, message: string): ArraySchema<TIn, TContext, TDefault, TFlags>;
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
yup.addMethod(yup.array, "uniqueInArray", function (
|
|
@@ -50,12 +50,21 @@ export function getYupEntitySchema<M extends Record<string, any>>(
|
|
|
50
50
|
const objectSchema: any = {};
|
|
51
51
|
Object.entries(properties as Record<string, ResolvedProperty>)
|
|
52
52
|
.forEach(([name, property]) => {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
try {
|
|
54
|
+
objectSchema[name] = mapPropertyToYup({
|
|
55
|
+
property: property as ResolvedProperty<any>,
|
|
56
|
+
customFieldValidator,
|
|
57
|
+
name,
|
|
58
|
+
entityId
|
|
59
|
+
});
|
|
60
|
+
} catch (e: any) {
|
|
61
|
+
console.error(`Error creating validation schema for property ${name}:`, e);
|
|
62
|
+
objectSchema[name] = yup.mixed().test(
|
|
63
|
+
"validation-error",
|
|
64
|
+
`Validation error: ${e?.message ?? "Unknown error"}`,
|
|
65
|
+
() => false
|
|
66
|
+
);
|
|
67
|
+
}
|
|
59
68
|
});
|
|
60
69
|
return yup.object().shape(objectSchema);
|
|
61
70
|
}
|
|
@@ -65,7 +74,12 @@ export function mapPropertyToYup<T extends CMSType>(propertyContext: PropertyCon
|
|
|
65
74
|
const property = propertyContext.property;
|
|
66
75
|
if (isPropertyBuilder(property)) {
|
|
67
76
|
console.error("Error in property", propertyContext);
|
|
68
|
-
|
|
77
|
+
// Return a permissive schema with an error message instead of crashing
|
|
78
|
+
return yup.mixed().test(
|
|
79
|
+
"property-builder-error",
|
|
80
|
+
"Invalid property configuration: property builder should be resolved",
|
|
81
|
+
() => false
|
|
82
|
+
);
|
|
69
83
|
}
|
|
70
84
|
|
|
71
85
|
if (property.dataType === "string") {
|
|
@@ -85,60 +99,93 @@ export function mapPropertyToYup<T extends CMSType>(propertyContext: PropertyCon
|
|
|
85
99
|
} else if (property.dataType === "reference") {
|
|
86
100
|
return getYupReferenceSchema(propertyContext as PropertyContext<EntityReference>);
|
|
87
101
|
}
|
|
88
|
-
|
|
89
|
-
|
|
102
|
+
|
|
103
|
+
// Log the error but don't crash the form - return a permissive schema with an error message
|
|
104
|
+
console.error("Unsupported data type in yup mapping", property);
|
|
105
|
+
const dataType = (property as any).dataType ?? "unknown";
|
|
106
|
+
return yup.mixed().test(
|
|
107
|
+
"unsupported-data-type",
|
|
108
|
+
`Unsupported data type: ${dataType}`,
|
|
109
|
+
() => false
|
|
110
|
+
);
|
|
90
111
|
}
|
|
91
112
|
|
|
92
113
|
export function getYupMapObjectSchema({
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
114
|
+
property,
|
|
115
|
+
entityId,
|
|
116
|
+
customFieldValidator,
|
|
117
|
+
name
|
|
118
|
+
}: PropertyContext<Record<string, any>>): ObjectSchema<any> {
|
|
98
119
|
const objectSchema: any = {};
|
|
99
120
|
const validation = property.validation;
|
|
100
121
|
if (property.properties)
|
|
101
122
|
Object.entries(property.properties).forEach(([childName, childProperty]: [string, ResolvedProperty]) => {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
123
|
+
try {
|
|
124
|
+
objectSchema[childName] = mapPropertyToYup<any>({
|
|
125
|
+
property: childProperty,
|
|
126
|
+
parentProperty: property as ResolvedMapProperty,
|
|
127
|
+
customFieldValidator,
|
|
128
|
+
name: `${name}[${childName}]`,
|
|
129
|
+
entityId
|
|
130
|
+
});
|
|
131
|
+
} catch (e: any) {
|
|
132
|
+
console.error(`Error creating validation schema for property ${childName}:`, e);
|
|
133
|
+
objectSchema[childName] = yup.mixed().test(
|
|
134
|
+
"validation-error",
|
|
135
|
+
`Validation error: ${e?.message ?? "Unknown error"}`,
|
|
136
|
+
() => false
|
|
137
|
+
);
|
|
138
|
+
}
|
|
109
139
|
});
|
|
110
140
|
|
|
111
141
|
const shape = yup.object().shape(objectSchema);
|
|
112
142
|
if (validation?.required) {
|
|
113
|
-
|
|
143
|
+
// In yup v0.x, .required().nullable(true) allowed null values
|
|
144
|
+
// To match this behavior: reject undefined but allow null
|
|
145
|
+
return shape.nullable().test(
|
|
146
|
+
"required",
|
|
147
|
+
validation?.requiredMessage ? validation.requiredMessage : "Required",
|
|
148
|
+
(value) => value !== undefined
|
|
149
|
+
) as any;
|
|
114
150
|
}
|
|
115
|
-
return yup.object().shape(shape.fields).default(undefined).
|
|
151
|
+
return yup.object().shape(shape.fields).default(undefined).nullable().optional() as any;
|
|
116
152
|
}
|
|
117
153
|
|
|
118
154
|
function getYupStringSchema({
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
let
|
|
155
|
+
property,
|
|
156
|
+
parentProperty,
|
|
157
|
+
customFieldValidator,
|
|
158
|
+
name,
|
|
159
|
+
entityId
|
|
160
|
+
}: PropertyContext<string>): StringSchema {
|
|
161
|
+
let schema: StringSchema<any> = yup.string().nullable();
|
|
126
162
|
const validation = property.validation;
|
|
163
|
+
|
|
127
164
|
if (property.enumValues) {
|
|
128
|
-
if (validation?.required)
|
|
129
|
-
|
|
165
|
+
if (validation?.required) {
|
|
166
|
+
schema = schema.test(
|
|
167
|
+
"required",
|
|
168
|
+
validation?.requiredMessage ? validation.requiredMessage : "Required",
|
|
169
|
+
(value) => value !== undefined && value !== null && value !== ""
|
|
170
|
+
);
|
|
171
|
+
}
|
|
130
172
|
const entries = enumToObjectEntries(property.enumValues);
|
|
131
|
-
|
|
173
|
+
schema = schema.oneOf(
|
|
132
174
|
(validation?.required ? entries : [...entries, null])
|
|
133
175
|
.map((enumValueConfig) => enumValueConfig?.id ?? null)
|
|
134
|
-
)
|
|
176
|
+
);
|
|
135
177
|
}
|
|
178
|
+
|
|
136
179
|
if (validation) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
180
|
+
if (validation.required) {
|
|
181
|
+
schema = schema.test(
|
|
182
|
+
"required",
|
|
183
|
+
validation?.requiredMessage ? validation.requiredMessage : "Required",
|
|
184
|
+
(value) => value !== undefined && value !== null && value !== ""
|
|
185
|
+
);
|
|
186
|
+
}
|
|
140
187
|
if (validation.unique && customFieldValidator && name)
|
|
141
|
-
|
|
188
|
+
schema = schema.test("unique", "This value already exists and should be unique",
|
|
142
189
|
(value, context) =>
|
|
143
190
|
customFieldValidator({
|
|
144
191
|
name,
|
|
@@ -147,46 +194,49 @@ function getYupStringSchema({
|
|
|
147
194
|
value,
|
|
148
195
|
entityId
|
|
149
196
|
}));
|
|
150
|
-
if (validation.min || validation.min === 0)
|
|
151
|
-
if (validation.max || validation.max === 0)
|
|
197
|
+
if (validation.min || validation.min === 0) schema = schema.min(validation.min, `${property.name} must be min ${validation.min} characters long`);
|
|
198
|
+
if (validation.max || validation.max === 0) schema = schema.max(validation.max, `${property.name} must be max ${validation.max} characters long`);
|
|
152
199
|
if (validation.matches) {
|
|
153
200
|
const regExp = typeof validation.matches === "string" ? hydrateRegExp(validation.matches) : validation.matches;
|
|
154
201
|
if (regExp) {
|
|
155
|
-
|
|
202
|
+
schema = schema.matches(regExp, validation.matchesMessage ? { message: validation.matchesMessage } : undefined)
|
|
156
203
|
}
|
|
157
204
|
}
|
|
158
|
-
if (validation.trim)
|
|
159
|
-
if (validation.lowercase)
|
|
160
|
-
if (validation.uppercase)
|
|
161
|
-
if (property.email)
|
|
205
|
+
if (validation.trim) schema = schema.trim();
|
|
206
|
+
if (validation.lowercase) schema = schema.lowercase();
|
|
207
|
+
if (validation.uppercase) schema = schema.uppercase();
|
|
208
|
+
if (property.email) schema = schema.email(`${property.name} must be an email`);
|
|
162
209
|
if (property.url) {
|
|
163
210
|
if (!property.storage || property.storage?.storeUrl) {
|
|
164
|
-
|
|
211
|
+
schema = schema.url(`${property.name} must be a url`);
|
|
165
212
|
} else {
|
|
166
213
|
console.warn(`Property ${property.name} has a url validation but its storage configuration is not set to store urls`);
|
|
167
214
|
}
|
|
168
215
|
}
|
|
169
|
-
} else {
|
|
170
|
-
collection = collection.notRequired().nullable(true);
|
|
171
216
|
}
|
|
172
|
-
return
|
|
217
|
+
return schema;
|
|
173
218
|
}
|
|
174
219
|
|
|
175
220
|
function getYupNumberSchema({
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
221
|
+
property,
|
|
222
|
+
parentProperty,
|
|
223
|
+
customFieldValidator,
|
|
224
|
+
name,
|
|
225
|
+
entityId
|
|
226
|
+
}: PropertyContext<number>): NumberSchema {
|
|
182
227
|
const validation = property.validation;
|
|
183
|
-
let
|
|
228
|
+
let schema: NumberSchema<any> = yup.number().nullable().typeError("Must be a number");
|
|
229
|
+
|
|
184
230
|
if (validation) {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
231
|
+
if (validation.required) {
|
|
232
|
+
schema = schema.test(
|
|
233
|
+
"required",
|
|
234
|
+
validation.requiredMessage ? validation.requiredMessage : "Required",
|
|
235
|
+
(value) => value !== undefined && value !== null
|
|
236
|
+
);
|
|
237
|
+
}
|
|
188
238
|
if (validation.unique && customFieldValidator && name)
|
|
189
|
-
|
|
239
|
+
schema = schema.test("unique",
|
|
190
240
|
"This value already exists and should be unique",
|
|
191
241
|
(value) => customFieldValidator({
|
|
192
242
|
name,
|
|
@@ -195,30 +245,29 @@ function getYupNumberSchema({
|
|
|
195
245
|
value,
|
|
196
246
|
entityId
|
|
197
247
|
}));
|
|
198
|
-
if (validation.min || validation.min === 0)
|
|
199
|
-
if (validation.max || validation.max === 0)
|
|
200
|
-
if (validation.lessThan || validation.lessThan === 0)
|
|
201
|
-
if (validation.moreThan || validation.moreThan === 0)
|
|
202
|
-
if (validation.positive)
|
|
203
|
-
if (validation.negative)
|
|
204
|
-
if (validation.integer)
|
|
205
|
-
} else {
|
|
206
|
-
collection = collection.notRequired().nullable(true);
|
|
248
|
+
if (validation.min || validation.min === 0) schema = schema.min(validation.min, `${property.name} must be higher or equal to ${validation.min}`);
|
|
249
|
+
if (validation.max || validation.max === 0) schema = schema.max(validation.max, `${property.name} must be lower or equal to ${validation.max}`);
|
|
250
|
+
if (validation.lessThan || validation.lessThan === 0) schema = schema.lessThan(validation.lessThan, `${property.name} must be higher than ${validation.lessThan}`);
|
|
251
|
+
if (validation.moreThan || validation.moreThan === 0) schema = schema.moreThan(validation.moreThan, `${property.name} must be lower than ${validation.moreThan}`);
|
|
252
|
+
if (validation.positive) schema = schema.positive(`${property.name} must be positive`);
|
|
253
|
+
if (validation.negative) schema = schema.negative(`${property.name} must be negative`);
|
|
254
|
+
if (validation.integer) schema = schema.integer(`${property.name} must be an integer`);
|
|
207
255
|
}
|
|
208
|
-
return
|
|
256
|
+
return schema;
|
|
209
257
|
}
|
|
210
258
|
|
|
211
259
|
function getYupGeoPointSchema({
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
let
|
|
260
|
+
property,
|
|
261
|
+
parentProperty,
|
|
262
|
+
customFieldValidator,
|
|
263
|
+
name,
|
|
264
|
+
entityId
|
|
265
|
+
}: PropertyContext<GeoPoint>): AnySchema {
|
|
266
|
+
let schema: ObjectSchema<any> = yup.object().nullable() as ObjectSchema<any>;
|
|
219
267
|
const validation = property.validation;
|
|
268
|
+
|
|
220
269
|
if (validation?.unique && customFieldValidator && name)
|
|
221
|
-
|
|
270
|
+
schema = schema.test("unique",
|
|
222
271
|
"This value already exists and should be unique",
|
|
223
272
|
(value) => customFieldValidator({
|
|
224
273
|
name,
|
|
@@ -228,31 +277,38 @@ function getYupGeoPointSchema({
|
|
|
228
277
|
entityId
|
|
229
278
|
}));
|
|
230
279
|
if (validation?.required) {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
280
|
+
schema = schema.test(
|
|
281
|
+
"required",
|
|
282
|
+
validation.requiredMessage ? validation.requiredMessage : "Required",
|
|
283
|
+
(value) => value !== undefined && value !== null
|
|
284
|
+
);
|
|
234
285
|
}
|
|
235
|
-
return
|
|
286
|
+
return schema;
|
|
236
287
|
}
|
|
237
288
|
|
|
238
289
|
function getYupDateSchema({
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
290
|
+
property,
|
|
291
|
+
parentProperty,
|
|
292
|
+
customFieldValidator,
|
|
293
|
+
name,
|
|
294
|
+
entityId
|
|
295
|
+
}: PropertyContext<Date>): AnySchema | DateSchema {
|
|
245
296
|
if (property.autoValue) {
|
|
246
|
-
return yup.
|
|
297
|
+
return yup.date().nullable();
|
|
247
298
|
}
|
|
248
|
-
let
|
|
299
|
+
let schema: DateSchema<any> = yup.date().nullable();
|
|
249
300
|
const validation = property.validation;
|
|
301
|
+
|
|
250
302
|
if (validation) {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
303
|
+
if (validation.required) {
|
|
304
|
+
schema = schema.test(
|
|
305
|
+
"required",
|
|
306
|
+
validation?.requiredMessage ? validation.requiredMessage : "Required",
|
|
307
|
+
(value) => value !== undefined && value !== null
|
|
308
|
+
);
|
|
309
|
+
}
|
|
254
310
|
if (validation.unique && customFieldValidator && name)
|
|
255
|
-
|
|
311
|
+
schema = schema.test("unique",
|
|
256
312
|
"This value already exists and should be unique",
|
|
257
313
|
(value) => customFieldValidator({
|
|
258
314
|
name,
|
|
@@ -261,31 +317,32 @@ function getYupDateSchema({
|
|
|
261
317
|
value,
|
|
262
318
|
entityId
|
|
263
319
|
}));
|
|
264
|
-
if (validation.min)
|
|
265
|
-
if (validation.max)
|
|
266
|
-
} else {
|
|
267
|
-
collection = collection.notRequired();
|
|
320
|
+
if (validation.min) schema = schema.min(validation.min, `${property.name} must be after ${validation.min}`);
|
|
321
|
+
if (validation.max) schema = schema.max(validation.max, `${property.name} must be before ${validation.min}`);
|
|
268
322
|
}
|
|
269
|
-
return
|
|
270
|
-
.transform((v: any) => (v instanceof Date ? v : null))
|
|
271
|
-
.nullable();
|
|
323
|
+
return schema.transform((v: any) => (v instanceof Date ? v : null));
|
|
272
324
|
}
|
|
273
325
|
|
|
274
326
|
function getYupReferenceSchema({
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
let
|
|
327
|
+
property,
|
|
328
|
+
parentProperty,
|
|
329
|
+
customFieldValidator,
|
|
330
|
+
name,
|
|
331
|
+
entityId
|
|
332
|
+
}: PropertyContext<EntityReference>): AnySchema {
|
|
333
|
+
let schema: ObjectSchema<any> = yup.object().nullable() as ObjectSchema<any>;
|
|
282
334
|
const validation = property.validation;
|
|
335
|
+
|
|
283
336
|
if (validation) {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
337
|
+
if (validation.required) {
|
|
338
|
+
schema = schema.test(
|
|
339
|
+
"required",
|
|
340
|
+
validation?.requiredMessage ? validation.requiredMessage : "Required",
|
|
341
|
+
(value) => value !== undefined && value !== null
|
|
342
|
+
);
|
|
343
|
+
}
|
|
287
344
|
if (validation.unique && customFieldValidator && name)
|
|
288
|
-
|
|
345
|
+
schema = schema.test("unique",
|
|
289
346
|
"This value already exists and should be unique",
|
|
290
347
|
(value) => customFieldValidator({
|
|
291
348
|
name,
|
|
@@ -294,27 +351,30 @@ function getYupReferenceSchema({
|
|
|
294
351
|
value,
|
|
295
352
|
entityId
|
|
296
353
|
}));
|
|
297
|
-
} else {
|
|
298
|
-
collection = collection.notRequired().nullable(true);
|
|
299
354
|
}
|
|
300
|
-
return
|
|
355
|
+
return schema;
|
|
301
356
|
}
|
|
302
357
|
|
|
303
358
|
function getYupBooleanSchema({
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
let
|
|
359
|
+
property,
|
|
360
|
+
parentProperty,
|
|
361
|
+
customFieldValidator,
|
|
362
|
+
name,
|
|
363
|
+
entityId
|
|
364
|
+
}: PropertyContext<boolean>): BooleanSchema {
|
|
365
|
+
let schema: BooleanSchema<any> = yup.boolean().nullable();
|
|
311
366
|
const validation = property.validation;
|
|
367
|
+
|
|
312
368
|
if (validation) {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
369
|
+
if (validation.required) {
|
|
370
|
+
schema = schema.test(
|
|
371
|
+
"required",
|
|
372
|
+
validation?.requiredMessage ? validation.requiredMessage : "Required",
|
|
373
|
+
(value) => value !== undefined && value !== null
|
|
374
|
+
);
|
|
375
|
+
}
|
|
316
376
|
if (validation.unique && customFieldValidator && name)
|
|
317
|
-
|
|
377
|
+
schema = schema.test("unique",
|
|
318
378
|
"This value already exists and should be unique",
|
|
319
379
|
(value) => customFieldValidator({
|
|
320
380
|
name,
|
|
@@ -323,10 +383,8 @@ function getYupBooleanSchema({
|
|
|
323
383
|
value,
|
|
324
384
|
entityId
|
|
325
385
|
}));
|
|
326
|
-
} else {
|
|
327
|
-
collection = collection.notRequired().nullable(true);
|
|
328
386
|
}
|
|
329
|
-
return
|
|
387
|
+
return schema;
|
|
330
388
|
}
|
|
331
389
|
|
|
332
390
|
function hasUniqueInArrayModifier(property: ResolvedProperty): boolean | [string, ResolvedProperty][] {
|
|
@@ -340,25 +398,38 @@ function hasUniqueInArrayModifier(property: ResolvedProperty): boolean | [string
|
|
|
340
398
|
}
|
|
341
399
|
|
|
342
400
|
function getYupArraySchema({
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
401
|
+
property,
|
|
402
|
+
parentProperty,
|
|
403
|
+
customFieldValidator,
|
|
404
|
+
name,
|
|
405
|
+
entityId
|
|
406
|
+
}: PropertyContext<any[]>): AnySchema<any> {
|
|
349
407
|
|
|
350
|
-
let arraySchema:
|
|
408
|
+
let arraySchema: any = yup.array().nullable();
|
|
351
409
|
|
|
352
410
|
if (property.of) {
|
|
353
411
|
if (Array.isArray(property.of)) {
|
|
354
|
-
const yupProperties = (property.of as ResolvedProperty[]).map((p, index) =>
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
412
|
+
const yupProperties = (property.of as ResolvedProperty[]).map((p, index) => {
|
|
413
|
+
try {
|
|
414
|
+
return {
|
|
415
|
+
[`${name}[${index}]`]: mapPropertyToYup({
|
|
416
|
+
property: p as ResolvedProperty<any>,
|
|
417
|
+
parentProperty: property,
|
|
418
|
+
entityId
|
|
419
|
+
})
|
|
420
|
+
};
|
|
421
|
+
} catch (e: any) {
|
|
422
|
+
console.error(`Error creating validation schema for array item ${index}:`, e);
|
|
423
|
+
return {
|
|
424
|
+
[`${name}[${index}]`]: yup.mixed().test(
|
|
425
|
+
"validation-error",
|
|
426
|
+
`Validation error: ${e?.message ?? "Unknown error"}`,
|
|
427
|
+
() => false
|
|
428
|
+
)
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
}).reduce((a, b) => ({ ...a, ...b }), {});
|
|
432
|
+
return yup.array().nullable().of(
|
|
362
433
|
yup.mixed().test(
|
|
363
434
|
"Dynamic object validation",
|
|
364
435
|
"Dynamic object validation error",
|
|
@@ -369,20 +440,28 @@ function getYupArraySchema({
|
|
|
369
440
|
)
|
|
370
441
|
);
|
|
371
442
|
} else {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
443
|
+
try {
|
|
444
|
+
arraySchema = arraySchema.of(mapPropertyToYup({
|
|
445
|
+
property: property.of,
|
|
446
|
+
parentProperty: property,
|
|
447
|
+
entityId
|
|
448
|
+
}));
|
|
449
|
+
} catch (e: any) {
|
|
450
|
+
console.error(`Error creating validation schema for array of property:`, e);
|
|
451
|
+
arraySchema = arraySchema.of(yup.mixed().test(
|
|
452
|
+
"validation-error",
|
|
453
|
+
`Validation error: ${e?.message ?? "Unknown error"}`,
|
|
454
|
+
() => false
|
|
455
|
+
));
|
|
456
|
+
}
|
|
377
457
|
const arrayUniqueFields = hasUniqueInArrayModifier(property.of);
|
|
378
458
|
if (arrayUniqueFields) {
|
|
379
459
|
if (typeof arrayUniqueFields === "boolean") {
|
|
380
|
-
arraySchema = arraySchema.uniqueInArray(v => v, `${property.name} should have unique values within the array`);
|
|
460
|
+
arraySchema = arraySchema.uniqueInArray((v: any) => v, `${property.name} should have unique values within the array`);
|
|
381
461
|
} else if (Array.isArray(arrayUniqueFields)) {
|
|
382
462
|
arrayUniqueFields.forEach(([name, childProperty]) => {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
);
|
|
463
|
+
arraySchema = arraySchema.uniqueInArray((v: any) => v && v[name], `${property.name} → ${childProperty.name ?? name}: should have unique values within the array`);
|
|
464
|
+
});
|
|
386
465
|
}
|
|
387
466
|
}
|
|
388
467
|
}
|
|
@@ -390,13 +469,19 @@ function getYupArraySchema({
|
|
|
390
469
|
const validation = property.validation;
|
|
391
470
|
|
|
392
471
|
if (validation) {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
472
|
+
if (validation.required) {
|
|
473
|
+
arraySchema = arraySchema.test(
|
|
474
|
+
"required",
|
|
475
|
+
validation?.requiredMessage ? validation.requiredMessage : "Required",
|
|
476
|
+
(value: any) => value !== undefined && value !== null && value.length > 0
|
|
477
|
+
);
|
|
478
|
+
}
|
|
396
479
|
if (validation.min || validation.min === 0) arraySchema = arraySchema.min(validation.min, `${property.name} should be min ${validation.min} entries long`);
|
|
397
480
|
if (validation.max) arraySchema = arraySchema.max(validation.max, `${property.name} should be max ${validation.max} entries long`);
|
|
398
|
-
|
|
399
|
-
|
|
481
|
+
// Handle uniqueInArray at the array level (in addition to the of.validation check above)
|
|
482
|
+
if (validation.uniqueInArray) {
|
|
483
|
+
arraySchema = arraySchema.uniqueInArray((v: any) => v, `${property.name} should have unique values within the array`);
|
|
484
|
+
}
|
|
400
485
|
}
|
|
401
486
|
return arraySchema;
|
|
402
487
|
}
|
|
@@ -9,16 +9,34 @@ export interface BreadcrumbsController {
|
|
|
9
9
|
set: (props: {
|
|
10
10
|
breadcrumbs: BreadcrumbEntry[];
|
|
11
11
|
}) => void;
|
|
12
|
+
/**
|
|
13
|
+
* Update the count for a specific breadcrumb by ID.
|
|
14
|
+
*/
|
|
15
|
+
updateCount: (id: string, count: number | null | undefined) => void;
|
|
12
16
|
}
|
|
13
17
|
|
|
18
|
+
|
|
14
19
|
/**
|
|
15
20
|
* @group Hooks and utilities
|
|
16
21
|
*/
|
|
17
22
|
export interface BreadcrumbEntry {
|
|
18
23
|
title: string;
|
|
19
24
|
url: string;
|
|
25
|
+
/**
|
|
26
|
+
* Optional entity count for collection breadcrumbs.
|
|
27
|
+
* - undefined: not applicable (e.g., entity breadcrumb, custom view)
|
|
28
|
+
* - null: loading
|
|
29
|
+
* - number: loaded count
|
|
30
|
+
*/
|
|
31
|
+
count?: number | null;
|
|
32
|
+
/**
|
|
33
|
+
* Unique identifier for this breadcrumb (e.g., collection path).
|
|
34
|
+
* Used to update count without replacing entire breadcrumb array.
|
|
35
|
+
*/
|
|
36
|
+
id?: string;
|
|
20
37
|
}
|
|
21
38
|
|
|
39
|
+
|
|
22
40
|
/**
|
|
23
41
|
* Hook to retrieve the BreadcrumbsController.
|
|
24
42
|
*
|