@firecms/collection_editor 3.0.1 → 3.1.0-canary.02232f4
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/dist/ConfigControllerProvider.d.ts +6 -0
- package/dist/api/generateCollectionApi.d.ts +71 -0
- package/dist/api/index.d.ts +1 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.es.js +15260 -8173
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +15257 -8170
- package/dist/index.umd.js.map +1 -1
- package/dist/locales/de.d.ts +120 -0
- package/dist/locales/en.d.ts +120 -0
- package/dist/locales/es.d.ts +120 -0
- package/dist/locales/fr.d.ts +120 -0
- package/dist/locales/hi.d.ts +120 -0
- package/dist/locales/it.d.ts +120 -0
- package/dist/locales/pt.d.ts +120 -0
- package/dist/types/collection_editor_controller.d.ts +14 -0
- package/dist/types/collection_inference.d.ts +8 -2
- package/dist/types/config_controller.d.ts +23 -2
- package/dist/ui/AddKanbanColumnAction.d.ts +11 -0
- package/dist/ui/KanbanSetupAction.d.ts +10 -0
- package/dist/ui/collection_editor/AICollectionGeneratorPopover.d.ts +37 -0
- package/dist/ui/collection_editor/AIModifiedPathsContext.d.ts +20 -0
- package/dist/ui/collection_editor/CollectionDetailsForm.d.ts +2 -3
- package/dist/ui/collection_editor/CollectionEditorDialog.d.ts +24 -0
- package/dist/ui/collection_editor/CollectionEditorWelcomeView.d.ts +4 -1
- package/dist/ui/collection_editor/CollectionJsonImportDialog.d.ts +7 -0
- package/dist/ui/collection_editor/CollectionYupValidation.d.ts +9 -13
- package/dist/ui/collection_editor/DisplaySettingsForm.d.ts +3 -0
- package/dist/ui/collection_editor/EntityActionsEditTab.d.ts +2 -1
- package/dist/ui/collection_editor/ExtendSettingsForm.d.ts +14 -0
- package/dist/ui/collection_editor/GeneralSettingsForm.d.ts +7 -0
- package/dist/ui/collection_editor/KanbanConfigSection.d.ts +4 -0
- package/dist/ui/collection_editor/PropertyEditView.d.ts +6 -1
- package/dist/ui/collection_editor/PropertyTree.d.ts +2 -1
- package/dist/ui/collection_editor/SubcollectionsEditTab.d.ts +2 -1
- package/dist/ui/collection_editor/ViewModeSwitch.d.ts +6 -0
- package/dist/ui/collection_editor/properties/EnumPropertyField.d.ts +2 -1
- package/dist/ui/collection_editor/properties/conditions/ConditionsEditor.d.ts +10 -0
- package/dist/ui/collection_editor/properties/conditions/ConditionsPanel.d.ts +2 -0
- package/dist/ui/collection_editor/properties/conditions/EnumConditionsEditor.d.ts +6 -0
- package/dist/ui/collection_editor/properties/conditions/index.d.ts +6 -0
- package/dist/ui/collection_editor/properties/conditions/property_paths.d.ts +19 -0
- package/dist/useCollectionEditorPlugin.d.ts +7 -1
- package/dist/utils/validateCollectionJson.d.ts +22 -0
- package/package.json +15 -15
- package/src/ConfigControllerProvider.tsx +82 -47
- package/src/api/generateCollectionApi.ts +119 -0
- package/src/api/index.ts +1 -0
- package/src/index.ts +28 -1
- package/src/locales/de.ts +125 -0
- package/src/locales/en.ts +145 -0
- package/src/locales/es.ts +125 -0
- package/src/locales/fr.ts +125 -0
- package/src/locales/hi.ts +125 -0
- package/src/locales/it.ts +125 -0
- package/src/locales/pt.ts +125 -0
- package/src/types/collection_editor_controller.tsx +16 -3
- package/src/types/collection_inference.ts +15 -2
- package/src/types/config_controller.tsx +27 -2
- package/src/ui/AddKanbanColumnAction.tsx +203 -0
- package/src/ui/EditorCollectionAction.tsx +3 -3
- package/src/ui/EditorCollectionActionStart.tsx +1 -2
- package/src/ui/EditorEntityAction.tsx +3 -2
- package/src/ui/HomePageEditorCollectionAction.tsx +41 -13
- package/src/ui/KanbanSetupAction.tsx +38 -0
- package/src/ui/MissingReferenceWidget.tsx +1 -1
- package/src/ui/NewCollectionButton.tsx +4 -2
- package/src/ui/NewCollectionCard.tsx +7 -4
- package/src/ui/PropertyAddColumnComponent.tsx +4 -3
- package/src/ui/collection_editor/AICollectionGeneratorPopover.tsx +243 -0
- package/src/ui/collection_editor/AIModifiedPathsContext.tsx +88 -0
- package/src/ui/collection_editor/CollectionDetailsForm.tsx +222 -267
- package/src/ui/collection_editor/CollectionEditorDialog.tsx +270 -198
- package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +138 -71
- package/src/ui/collection_editor/CollectionJsonImportDialog.tsx +171 -0
- package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +202 -101
- package/src/ui/collection_editor/DisplaySettingsForm.tsx +335 -0
- package/src/ui/collection_editor/EntityActionsEditTab.tsx +106 -97
- package/src/ui/collection_editor/EntityActionsSelectDialog.tsx +8 -10
- package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +5 -7
- package/src/ui/collection_editor/EnumForm.tsx +153 -102
- package/src/ui/collection_editor/ExtendSettingsForm.tsx +94 -0
- package/src/ui/collection_editor/GeneralSettingsForm.tsx +335 -0
- package/src/ui/collection_editor/GetCodeDialog.tsx +63 -41
- package/src/ui/collection_editor/KanbanConfigSection.tsx +209 -0
- package/src/ui/collection_editor/LayoutModeSwitch.tsx +27 -43
- package/src/ui/collection_editor/PropertyEditView.tsx +272 -199
- package/src/ui/collection_editor/PropertyFieldPreview.tsx +1 -1
- package/src/ui/collection_editor/PropertyTree.tsx +130 -58
- package/src/ui/collection_editor/SubcollectionsEditTab.tsx +169 -163
- package/src/ui/collection_editor/UnsavedChangesDialog.tsx +0 -2
- package/src/ui/collection_editor/ViewModeSwitch.tsx +43 -0
- package/src/ui/collection_editor/import/CollectionEditorImportDataPreview.tsx +6 -3
- package/src/ui/collection_editor/import/CollectionEditorImportMapping.tsx +5 -2
- package/src/ui/collection_editor/properties/BlockPropertyField.tsx +0 -2
- package/src/ui/collection_editor/properties/BooleanPropertyField.tsx +4 -1
- package/src/ui/collection_editor/properties/CommonPropertyFields.tsx +6 -4
- package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +126 -42
- package/src/ui/collection_editor/properties/EnumPropertyField.tsx +32 -24
- package/src/ui/collection_editor/properties/MapPropertyField.tsx +8 -9
- package/src/ui/collection_editor/properties/MarkdownPropertyField.tsx +128 -53
- package/src/ui/collection_editor/properties/NumberPropertyField.tsx +3 -1
- package/src/ui/collection_editor/properties/ReferencePropertyField.tsx +5 -4
- package/src/ui/collection_editor/properties/StoragePropertyField.tsx +47 -52
- package/src/ui/collection_editor/properties/StringPropertyField.tsx +3 -1
- package/src/ui/collection_editor/properties/UrlPropertyField.tsx +12 -10
- package/src/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.tsx +23 -4
- package/src/ui/collection_editor/properties/conditions/ConditionsEditor.tsx +866 -0
- package/src/ui/collection_editor/properties/conditions/ConditionsPanel.tsx +28 -0
- package/src/ui/collection_editor/properties/conditions/EnumConditionsEditor.tsx +599 -0
- package/src/ui/collection_editor/properties/conditions/index.ts +6 -0
- package/src/ui/collection_editor/properties/conditions/property_paths.ts +92 -0
- package/src/ui/collection_editor/properties/validation/ArrayPropertyValidation.tsx +5 -2
- package/src/ui/collection_editor/properties/validation/GeneralPropertyValidation.tsx +7 -5
- package/src/ui/collection_editor/properties/validation/NumberPropertyValidation.tsx +10 -7
- package/src/ui/collection_editor/properties/validation/StringPropertyValidation.tsx +11 -9
- package/src/ui/collection_editor/properties/validation/ValidationPanel.tsx +5 -2
- package/src/useCollectionEditorPlugin.tsx +53 -22
- package/src/utils/validateCollectionJson.ts +380 -0
|
@@ -10,10 +10,12 @@ import {
|
|
|
10
10
|
isPropertyBuilder,
|
|
11
11
|
isValidRegExp,
|
|
12
12
|
mergeDeep,
|
|
13
|
+
Properties,
|
|
13
14
|
Property,
|
|
14
15
|
PropertyConfig,
|
|
15
16
|
PropertyConfigBadge,
|
|
16
17
|
PropertyConfigId,
|
|
18
|
+
useTranslation,
|
|
17
19
|
} from "@firecms/core";
|
|
18
20
|
import {
|
|
19
21
|
Button,
|
|
@@ -45,6 +47,7 @@ import { NumberPropertyField } from "./properties/NumberPropertyField";
|
|
|
45
47
|
import { ReferencePropertyField } from "./properties/ReferencePropertyField";
|
|
46
48
|
import { DateTimePropertyField } from "./properties/DateTimePropertyField";
|
|
47
49
|
import { AdvancedPropertyValidation } from "./properties/advanced/AdvancedPropertyValidation";
|
|
50
|
+
import { ConditionsPanel, ConditionsEditor, EnumConditionsEditor } from "./properties/conditions";
|
|
48
51
|
import { editableProperty } from "../../utils/entities";
|
|
49
52
|
import { KeyValuePropertyField } from "./properties/KeyValuePropertyField";
|
|
50
53
|
import { updatePropertyFromWidget } from "./utils/update_property_for_widget";
|
|
@@ -85,6 +88,11 @@ export type PropertyFormProps = {
|
|
|
85
88
|
getController?: (formex: FormexController<PropertyWithId>) => void;
|
|
86
89
|
propertyConfigs: Record<string, PropertyConfig>;
|
|
87
90
|
collectionEditable: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Collection properties for populating the conditions field selector.
|
|
93
|
+
* Includes nested map properties.
|
|
94
|
+
*/
|
|
95
|
+
collectionProperties?: Properties;
|
|
88
96
|
};
|
|
89
97
|
|
|
90
98
|
export const PropertyForm = React.memo(
|
|
@@ -108,10 +116,11 @@ export const PropertyForm = React.memo(
|
|
|
108
116
|
initialErrors,
|
|
109
117
|
forceShowErrors,
|
|
110
118
|
allowDataInference,
|
|
111
|
-
getController,
|
|
112
119
|
getData,
|
|
120
|
+
getController,
|
|
113
121
|
propertyConfigs,
|
|
114
|
-
collectionEditable
|
|
122
|
+
collectionEditable,
|
|
123
|
+
collectionProperties
|
|
115
124
|
} = props;
|
|
116
125
|
|
|
117
126
|
const initialValue: PropertyWithId = {
|
|
@@ -119,6 +128,8 @@ export const PropertyForm = React.memo(
|
|
|
119
128
|
name: ""
|
|
120
129
|
} as PropertyWithId;
|
|
121
130
|
|
|
131
|
+
const { t } = useTranslation();
|
|
132
|
+
|
|
122
133
|
const disabled = (Boolean(property && !editableProperty(property)) || !collectionEditable);
|
|
123
134
|
|
|
124
135
|
const lastSubmittedProperty = useRef<OnPropertyChangedParams | undefined>(property ? {
|
|
@@ -128,9 +139,9 @@ export const PropertyForm = React.memo(
|
|
|
128
139
|
} : undefined);
|
|
129
140
|
|
|
130
141
|
const doOnPropertyChanged = ({
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
142
|
+
id,
|
|
143
|
+
property
|
|
144
|
+
}: OnPropertyChangedParams) => {
|
|
134
145
|
const params = {
|
|
135
146
|
id,
|
|
136
147
|
previousId: lastSubmittedProperty.current?.id,
|
|
@@ -168,16 +179,18 @@ export const PropertyForm = React.memo(
|
|
|
168
179
|
const errors: Record<string, any> = {};
|
|
169
180
|
if (includeIdAndName) {
|
|
170
181
|
if (!values.name) {
|
|
171
|
-
errors.name = "
|
|
182
|
+
errors.name = t("required");
|
|
172
183
|
} else {
|
|
173
|
-
const nameError = validateName(values.name);
|
|
184
|
+
const nameError = validateName(values.name, t);
|
|
174
185
|
if (nameError)
|
|
175
186
|
errors.name = nameError;
|
|
176
187
|
}
|
|
177
188
|
if (!values.id) {
|
|
178
|
-
errors.id = "
|
|
189
|
+
errors.id = t("required");
|
|
179
190
|
} else {
|
|
180
|
-
|
|
191
|
+
// Exclude the current property key when editing to avoid false duplicate error
|
|
192
|
+
const keysToCheck = existingPropertyKeys?.filter(key => key !== propertyKey);
|
|
193
|
+
const idError = validateId(values.id, keysToCheck, t);
|
|
181
194
|
if (idError)
|
|
182
195
|
errors.id = idError;
|
|
183
196
|
}
|
|
@@ -186,23 +199,67 @@ export const PropertyForm = React.memo(
|
|
|
186
199
|
if (values.dataType === "string") {
|
|
187
200
|
if (values.validation?.matches && !isValidRegExp(values.validation?.matches.toString())) {
|
|
188
201
|
errors.validation = {
|
|
189
|
-
matches: "
|
|
202
|
+
matches: t("invalid_regular_expression")
|
|
190
203
|
}
|
|
191
204
|
}
|
|
192
205
|
}
|
|
193
206
|
if (values.dataType === "reference" && !values.path) {
|
|
194
|
-
errors.path = "
|
|
207
|
+
errors.path = t("must_specify_target_collection");
|
|
195
208
|
}
|
|
196
209
|
if (values.propertyConfig === "repeat") {
|
|
197
210
|
if (!(values as any).of) {
|
|
198
|
-
errors.of = "
|
|
211
|
+
errors.of = t("need_specify_repeat_field");
|
|
199
212
|
}
|
|
200
213
|
}
|
|
201
214
|
if (values.propertyConfig === "block") {
|
|
202
215
|
if (!(values as any).oneOf) {
|
|
203
|
-
errors.oneOf = "
|
|
216
|
+
errors.oneOf = t("need_specify_block_properties");
|
|
204
217
|
}
|
|
205
218
|
}
|
|
219
|
+
|
|
220
|
+
// Validate conditions - check for incomplete condition rules
|
|
221
|
+
const conditions = (values as any).conditions;
|
|
222
|
+
if (conditions) {
|
|
223
|
+
const conditionErrors: Record<string, string> = {};
|
|
224
|
+
const conditionTypes = ["disabled", "hidden", "required", "readOnly"];
|
|
225
|
+
|
|
226
|
+
// Helper to check if a JSON Logic rule is incomplete (placeholder or empty keys)
|
|
227
|
+
const isIncompleteRule = (rule: any): boolean => {
|
|
228
|
+
if (!rule || typeof rule !== "object") return false;
|
|
229
|
+
const ruleStr = JSON.stringify(rule);
|
|
230
|
+
// Check for placeholder pattern used when field is not selected
|
|
231
|
+
if (ruleStr.includes("values._placeholder")) return true;
|
|
232
|
+
// Check for empty string keys (invalid operators)
|
|
233
|
+
if (Object.keys(rule).some(k => k === "")) return true;
|
|
234
|
+
// Recursively check nested objects
|
|
235
|
+
for (const key of Object.keys(rule)) {
|
|
236
|
+
if (typeof rule[key] === "object" && isIncompleteRule(rule[key])) return true;
|
|
237
|
+
}
|
|
238
|
+
return false;
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
for (const type of conditionTypes) {
|
|
242
|
+
const rule = conditions[type];
|
|
243
|
+
if (rule && isIncompleteRule(rule)) {
|
|
244
|
+
conditionErrors[type] = t("incomplete_condition");
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Validate enum conditions (allowedEnumValues, excludedEnumValues)
|
|
249
|
+
for (const enumType of ["allowedEnumValues", "excludedEnumValues"]) {
|
|
250
|
+
const rule = conditions[enumType];
|
|
251
|
+
if (rule && typeof rule === "object" && rule.if) {
|
|
252
|
+
if (isIncompleteRule(rule)) {
|
|
253
|
+
conditionErrors[enumType] = t("incomplete_condition");
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (Object.keys(conditionErrors).length > 0) {
|
|
259
|
+
errors.conditions = conditionErrors;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
206
263
|
return errors;
|
|
207
264
|
}
|
|
208
265
|
});
|
|
@@ -231,33 +288,37 @@ export const PropertyForm = React.memo(
|
|
|
231
288
|
allowDataInference={allowDataInference}
|
|
232
289
|
propertyConfigs={propertyConfigs}
|
|
233
290
|
collectionEditable={collectionEditable}
|
|
234
|
-
{
|
|
291
|
+
collectionProperties={collectionProperties}
|
|
292
|
+
{...formexController} />
|
|
235
293
|
</Formex>;
|
|
236
294
|
}, (a, b) =>
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
295
|
+
a.getData === b.getData &&
|
|
296
|
+
a.propertyKey === b.propertyKey &&
|
|
297
|
+
a.propertyNamespace === b.propertyNamespace &&
|
|
298
|
+
a.includeIdAndName === b.includeIdAndName &&
|
|
299
|
+
a.autoOpenTypeSelect === b.autoOpenTypeSelect &&
|
|
300
|
+
a.autoUpdateId === b.autoUpdateId &&
|
|
301
|
+
a.existingPropertyKeys === b.existingPropertyKeys &&
|
|
302
|
+
a.existingProperty === b.existingProperty &&
|
|
303
|
+
equal(a.property, b.property)
|
|
245
304
|
);
|
|
246
305
|
|
|
247
306
|
export function PropertyFormDialog({
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
307
|
+
open,
|
|
308
|
+
onCancel,
|
|
309
|
+
onOkClicked,
|
|
310
|
+
onPropertyChanged,
|
|
311
|
+
getData,
|
|
312
|
+
collectionEditable,
|
|
313
|
+
...formProps
|
|
314
|
+
}: PropertyFormProps & {
|
|
256
315
|
open?: boolean;
|
|
257
316
|
onOkClicked?: () => void;
|
|
258
317
|
onCancel?: () => void;
|
|
259
318
|
}) {
|
|
260
|
-
const
|
|
319
|
+
const { t } = useTranslation();
|
|
320
|
+
|
|
321
|
+
const formexRef = useRef<FormexController<PropertyWithId>>(undefined);
|
|
261
322
|
const getController = (helpers: FormexController<PropertyWithId>) => {
|
|
262
323
|
formexRef.current = helpers;
|
|
263
324
|
};
|
|
@@ -268,25 +329,25 @@ export function PropertyFormDialog({
|
|
|
268
329
|
fullWidth={true}
|
|
269
330
|
>
|
|
270
331
|
<form noValidate={true}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
<DialogTitle hidden>
|
|
332
|
+
autoComplete={"off"}
|
|
333
|
+
onSubmit={(e) => {
|
|
334
|
+
e.preventDefault();
|
|
335
|
+
e.stopPropagation();
|
|
336
|
+
formexRef.current?.handleSubmit(e)
|
|
337
|
+
}}>
|
|
338
|
+
<DialogTitle hidden>{t("property_edit_view")}</DialogTitle>
|
|
278
339
|
<DialogContent>
|
|
279
340
|
|
|
280
341
|
<PropertyForm {...formProps}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
342
|
+
onDismiss={onCancel}
|
|
343
|
+
onPropertyChanged={(params) => {
|
|
344
|
+
onPropertyChanged?.(params);
|
|
345
|
+
onOkClicked?.();
|
|
346
|
+
}}
|
|
347
|
+
collectionEditable={collectionEditable}
|
|
348
|
+
onPropertyChangedImmediate={false}
|
|
349
|
+
getController={getController}
|
|
350
|
+
getData={getData}
|
|
290
351
|
/>
|
|
291
352
|
</DialogContent>
|
|
292
353
|
|
|
@@ -294,7 +355,6 @@ export function PropertyFormDialog({
|
|
|
294
355
|
|
|
295
356
|
{onCancel && <Button
|
|
296
357
|
variant={"text"}
|
|
297
|
-
color={"primary"}
|
|
298
358
|
onClick={() => {
|
|
299
359
|
onCancel();
|
|
300
360
|
formexRef.current?.resetForm();
|
|
@@ -302,9 +362,7 @@ export function PropertyFormDialog({
|
|
|
302
362
|
Cancel
|
|
303
363
|
</Button>}
|
|
304
364
|
|
|
305
|
-
<Button
|
|
306
|
-
type={"submit"}
|
|
307
|
-
color="primary">
|
|
365
|
+
<Button type={"submit"}>
|
|
308
366
|
Ok
|
|
309
367
|
</Button>
|
|
310
368
|
</DialogActions>
|
|
@@ -314,26 +372,27 @@ export function PropertyFormDialog({
|
|
|
314
372
|
}
|
|
315
373
|
|
|
316
374
|
function PropertyEditFormFields({
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
375
|
+
values,
|
|
376
|
+
errors,
|
|
377
|
+
setValues,
|
|
378
|
+
existing,
|
|
379
|
+
autoUpdateId = false,
|
|
380
|
+
autoOpenTypeSelect,
|
|
381
|
+
includeIdAndTitle,
|
|
382
|
+
onPropertyChanged,
|
|
383
|
+
onDelete,
|
|
384
|
+
propertyNamespace,
|
|
385
|
+
onDismiss,
|
|
386
|
+
onError,
|
|
387
|
+
showErrors,
|
|
388
|
+
disabled,
|
|
389
|
+
inArray,
|
|
390
|
+
getData,
|
|
391
|
+
allowDataInference,
|
|
392
|
+
propertyConfigs,
|
|
393
|
+
collectionEditable,
|
|
394
|
+
collectionProperties
|
|
395
|
+
}: {
|
|
337
396
|
includeIdAndTitle?: boolean;
|
|
338
397
|
existing: boolean;
|
|
339
398
|
autoUpdateId?: boolean;
|
|
@@ -350,8 +409,11 @@ function PropertyEditFormFields({
|
|
|
350
409
|
allowDataInference: boolean;
|
|
351
410
|
propertyConfigs: Record<string, PropertyConfig>;
|
|
352
411
|
collectionEditable: boolean;
|
|
412
|
+
collectionProperties?: Properties;
|
|
353
413
|
} & FormexController<PropertyWithId>) {
|
|
354
414
|
|
|
415
|
+
const { t } = useTranslation();
|
|
416
|
+
|
|
355
417
|
const [selectOpen, setSelectOpen] = useState(autoOpenTypeSelect);
|
|
356
418
|
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
|
357
419
|
const [selectedFieldConfigId, setSelectedFieldConfigId] = useState<string | undefined>(values?.dataType ? getFieldId(values) : undefined);
|
|
@@ -404,16 +466,16 @@ function PropertyEditFormFields({
|
|
|
404
466
|
selectedFieldConfigId === "email") {
|
|
405
467
|
childComponent =
|
|
406
468
|
<StringPropertyField widgetId={selectedFieldConfigId}
|
|
407
|
-
|
|
408
|
-
|
|
469
|
+
disabled={disabled}
|
|
470
|
+
showErrors={showErrors} />;
|
|
409
471
|
} else if (selectedFieldConfigId === "url") {
|
|
410
472
|
childComponent =
|
|
411
473
|
<UrlPropertyField disabled={disabled}
|
|
412
|
-
|
|
474
|
+
showErrors={showErrors} />;
|
|
413
475
|
} else if (selectedFieldConfigId === "markdown") {
|
|
414
476
|
childComponent =
|
|
415
477
|
<MarkdownPropertyField disabled={disabled}
|
|
416
|
-
|
|
478
|
+
showErrors={showErrors} />;
|
|
417
479
|
} else if (selectedFieldConfigId === "select" ||
|
|
418
480
|
selectedFieldConfigId === "number_select") {
|
|
419
481
|
childComponent = <EnumPropertyField
|
|
@@ -422,7 +484,8 @@ function PropertyEditFormFields({
|
|
|
422
484
|
updateIds={!existing}
|
|
423
485
|
disabled={disabled}
|
|
424
486
|
getData={getData}
|
|
425
|
-
|
|
487
|
+
propertyNamespace={propertyNamespace}
|
|
488
|
+
showErrors={showErrors} />;
|
|
426
489
|
} else if (selectedFieldConfigId === "multi_select" ||
|
|
427
490
|
selectedFieldConfigId === "multi_number_select") {
|
|
428
491
|
childComponent = <EnumPropertyField
|
|
@@ -431,64 +494,65 @@ function PropertyEditFormFields({
|
|
|
431
494
|
disabled={disabled}
|
|
432
495
|
allowDataInference={allowDataInference}
|
|
433
496
|
getData={getData}
|
|
434
|
-
|
|
497
|
+
propertyNamespace={propertyNamespace}
|
|
498
|
+
showErrors={showErrors} />;
|
|
435
499
|
} else if (selectedFieldConfigId === "file_upload") {
|
|
436
500
|
childComponent =
|
|
437
501
|
<StoragePropertyField existing={existing}
|
|
438
|
-
|
|
439
|
-
|
|
502
|
+
multiple={false}
|
|
503
|
+
disabled={disabled} />;
|
|
440
504
|
} else if (selectedFieldConfigId === "multi_file_upload") {
|
|
441
505
|
childComponent =
|
|
442
506
|
<StoragePropertyField existing={existing}
|
|
443
|
-
|
|
444
|
-
|
|
507
|
+
multiple={true}
|
|
508
|
+
disabled={disabled} />;
|
|
445
509
|
} else if (selectedFieldConfigId === "switch") {
|
|
446
|
-
childComponent = <BooleanPropertyField disabled={disabled}/>;
|
|
510
|
+
childComponent = <BooleanPropertyField disabled={disabled} />;
|
|
447
511
|
} else if (selectedFieldConfigId === "number_input") {
|
|
448
|
-
childComponent = <NumberPropertyField disabled={disabled}/>;
|
|
512
|
+
childComponent = <NumberPropertyField disabled={disabled} />;
|
|
449
513
|
} else if (selectedFieldConfigId === "group") {
|
|
450
514
|
childComponent =
|
|
451
515
|
<MapPropertyField disabled={disabled} getData={getData} allowDataInference={allowDataInference}
|
|
452
|
-
|
|
453
|
-
|
|
516
|
+
collectionEditable={collectionEditable}
|
|
517
|
+
propertyConfigs={propertyConfigs} />;
|
|
454
518
|
} else if (selectedFieldConfigId === "block") {
|
|
455
519
|
childComponent =
|
|
456
520
|
<BlockPropertyField disabled={disabled} getData={getData} allowDataInference={allowDataInference}
|
|
457
|
-
|
|
458
|
-
|
|
521
|
+
collectionEditable={collectionEditable}
|
|
522
|
+
propertyConfigs={propertyConfigs} />;
|
|
459
523
|
} else if (selectedFieldConfigId === "reference") {
|
|
460
524
|
childComponent =
|
|
461
525
|
<ReferencePropertyField showErrors={showErrors}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
526
|
+
existing={existing}
|
|
527
|
+
multiple={false}
|
|
528
|
+
disabled={disabled} />;
|
|
465
529
|
} else if (selectedFieldConfigId === "reference_as_string") {
|
|
466
530
|
childComponent =
|
|
467
531
|
<ReferencePropertyField showErrors={showErrors}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
532
|
+
existing={existing}
|
|
533
|
+
asString={true}
|
|
534
|
+
multiple={false}
|
|
535
|
+
disabled={disabled} />;
|
|
472
536
|
} else if (selectedFieldConfigId === "date_time") {
|
|
473
|
-
childComponent = <DateTimePropertyField disabled={disabled}/>;
|
|
537
|
+
childComponent = <DateTimePropertyField disabled={disabled} />;
|
|
474
538
|
} else if (selectedFieldConfigId === "multi_references") {
|
|
475
539
|
childComponent =
|
|
476
540
|
<ReferencePropertyField showErrors={showErrors}
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
541
|
+
existing={existing}
|
|
542
|
+
multiple={true}
|
|
543
|
+
disabled={disabled} />;
|
|
480
544
|
} else if (selectedFieldConfigId === "repeat") {
|
|
481
545
|
childComponent =
|
|
482
546
|
<RepeatPropertyField showErrors={showErrors}
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
547
|
+
existing={existing}
|
|
548
|
+
getData={getData}
|
|
549
|
+
allowDataInference={allowDataInference}
|
|
550
|
+
disabled={disabled}
|
|
551
|
+
collectionEditable={collectionEditable}
|
|
552
|
+
propertyConfigs={propertyConfigs} />;
|
|
489
553
|
} else if (selectedFieldConfigId === "key_value") {
|
|
490
554
|
childComponent =
|
|
491
|
-
<KeyValuePropertyField disabled={disabled}/>;
|
|
555
|
+
<KeyValuePropertyField disabled={disabled} />;
|
|
492
556
|
} else {
|
|
493
557
|
childComponent = null;
|
|
494
558
|
}
|
|
@@ -520,54 +584,59 @@ function PropertyEditFormFields({
|
|
|
520
584
|
showError={Boolean(selectedWidgetError)}
|
|
521
585
|
existing={existing}
|
|
522
586
|
propertyConfigs={propertyConfigs}
|
|
523
|
-
inArray={inArray}/>
|
|
587
|
+
inArray={inArray} />
|
|
524
588
|
|
|
525
589
|
{selectedWidgetError &&
|
|
526
590
|
<Typography variant="caption"
|
|
527
|
-
|
|
528
|
-
|
|
591
|
+
className={"ml-3.5"}
|
|
592
|
+
color={"error"}>{t("required")}</Typography>}
|
|
529
593
|
|
|
530
594
|
{/*<Typography variant="caption" className={"ml-3.5"}>Define your own custom properties and*/}
|
|
531
595
|
{/* components</Typography>*/}
|
|
532
596
|
|
|
533
597
|
</div>
|
|
534
598
|
|
|
535
|
-
{onDelete && values?.id &&
|
|
599
|
+
{onDelete && existing && values?.id &&
|
|
536
600
|
<IconButton
|
|
537
601
|
variant={"ghost"}
|
|
538
602
|
className="m-4"
|
|
539
603
|
disabled={disabled}
|
|
540
604
|
onClick={() => setDeleteDialogOpen(true)}>
|
|
541
|
-
<DeleteIcon/>
|
|
605
|
+
<DeleteIcon />
|
|
542
606
|
</IconButton>}
|
|
543
607
|
</div>
|
|
544
608
|
|
|
545
609
|
<div className={"grid grid-cols-12 gap-y-12 mt-8 mb-8"}>
|
|
546
610
|
{includeIdAndTitle &&
|
|
547
611
|
<CommonPropertyFields showErrors={showErrors}
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
612
|
+
disabledId={existing}
|
|
613
|
+
isNewProperty={!existing}
|
|
614
|
+
disabled={disabled}
|
|
615
|
+
autoUpdateId={autoUpdateId}
|
|
616
|
+
ref={nameFieldRef} />}
|
|
553
617
|
|
|
554
618
|
{childComponent}
|
|
555
619
|
|
|
556
620
|
<div className={"col-span-12"}>
|
|
557
|
-
<AdvancedPropertyValidation disabled={disabled}/>
|
|
621
|
+
<AdvancedPropertyValidation disabled={disabled} />
|
|
622
|
+
</div>
|
|
623
|
+
|
|
624
|
+
<div className={"col-span-12"}>
|
|
625
|
+
<ConditionsPanel>
|
|
626
|
+
<ConditionsEditor disabled={disabled} collectionProperties={collectionProperties} />
|
|
627
|
+
<EnumConditionsEditor disabled={disabled} collectionProperties={collectionProperties} />
|
|
628
|
+
</ConditionsPanel>
|
|
558
629
|
</div>
|
|
559
630
|
</div>
|
|
560
631
|
|
|
561
632
|
{onDelete &&
|
|
562
633
|
<ConfirmationDialog open={deleteDialogOpen}
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
collection.</div>
|
|
570
|
-
}/>}
|
|
634
|
+
onAccept={() => onDelete(values?.id, propertyNamespace)}
|
|
635
|
+
onCancel={() => setDeleteDialogOpen(false)}
|
|
636
|
+
title={<div>{t("delete_this_property")}</div>}
|
|
637
|
+
body={
|
|
638
|
+
<div>{t("delete_property_warning")}</div>
|
|
639
|
+
} />}
|
|
571
640
|
|
|
572
641
|
</>
|
|
573
642
|
);
|
|
@@ -575,67 +644,67 @@ function PropertyEditFormFields({
|
|
|
575
644
|
|
|
576
645
|
const idRegEx = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
577
646
|
|
|
578
|
-
function validateId(value
|
|
647
|
+
function validateId(value: string | undefined, existingPropertyKeys: string[] | undefined, t: any) {
|
|
579
648
|
|
|
580
649
|
let error;
|
|
581
650
|
if (!value) {
|
|
582
|
-
error = "
|
|
651
|
+
error = t("error_must_specify_id");
|
|
583
652
|
}
|
|
584
653
|
if (value && !value.match(idRegEx)) {
|
|
585
|
-
error = "
|
|
654
|
+
error = t("error_id_format");
|
|
586
655
|
}
|
|
587
656
|
if (value && existingPropertyKeys && existingPropertyKeys.includes(value)) {
|
|
588
|
-
error = "
|
|
657
|
+
error = t("error_id_already_exists");
|
|
589
658
|
}
|
|
590
659
|
return error;
|
|
591
660
|
}
|
|
592
661
|
|
|
593
|
-
function validateName(value: string) {
|
|
662
|
+
function validateName(value: string, t: any) {
|
|
594
663
|
let error;
|
|
595
664
|
if (!value) {
|
|
596
|
-
error = "
|
|
665
|
+
error = t("error_must_specify_title");
|
|
597
666
|
}
|
|
598
667
|
return error;
|
|
599
668
|
}
|
|
600
669
|
|
|
601
670
|
const WIDGET_TYPE_MAP: Record<PropertyConfigId, string> = {
|
|
602
|
-
text_field: "
|
|
603
|
-
multiline: "
|
|
604
|
-
markdown: "
|
|
605
|
-
url: "
|
|
606
|
-
email: "
|
|
607
|
-
switch: "
|
|
608
|
-
user_select: "
|
|
609
|
-
select: "
|
|
610
|
-
multi_select: "
|
|
611
|
-
number_input: "
|
|
612
|
-
number_select: "
|
|
613
|
-
multi_number_select: "
|
|
614
|
-
file_upload: "
|
|
615
|
-
multi_file_upload: "
|
|
616
|
-
reference: "
|
|
617
|
-
reference_as_string: "
|
|
618
|
-
multi_references: "
|
|
619
|
-
date_time: "
|
|
620
|
-
group: "
|
|
621
|
-
key_value: "
|
|
622
|
-
repeat: "
|
|
623
|
-
custom_array: "
|
|
624
|
-
block: "
|
|
671
|
+
text_field: "widget_group_text",
|
|
672
|
+
multiline: "widget_group_text",
|
|
673
|
+
markdown: "widget_group_text",
|
|
674
|
+
url: "widget_group_text",
|
|
675
|
+
email: "widget_group_text",
|
|
676
|
+
switch: "widget_group_boolean",
|
|
677
|
+
user_select: "widget_group_users",
|
|
678
|
+
select: "widget_group_select",
|
|
679
|
+
multi_select: "widget_group_select",
|
|
680
|
+
number_input: "widget_group_number",
|
|
681
|
+
number_select: "widget_group_select",
|
|
682
|
+
multi_number_select: "widget_group_select",
|
|
683
|
+
file_upload: "widget_group_file",
|
|
684
|
+
multi_file_upload: "widget_group_file",
|
|
685
|
+
reference: "widget_group_reference",
|
|
686
|
+
reference_as_string: "widget_group_text",
|
|
687
|
+
multi_references: "widget_group_reference",
|
|
688
|
+
date_time: "widget_group_date",
|
|
689
|
+
group: "widget_group_group",
|
|
690
|
+
key_value: "widget_group_group",
|
|
691
|
+
repeat: "widget_group_array",
|
|
692
|
+
custom_array: "widget_group_array",
|
|
693
|
+
block: "widget_group_group"
|
|
625
694
|
};
|
|
626
695
|
|
|
627
696
|
function WidgetSelectView({
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
697
|
+
initialProperty,
|
|
698
|
+
value,
|
|
699
|
+
onValueChange,
|
|
700
|
+
open,
|
|
701
|
+
onOpenChange,
|
|
702
|
+
disabled,
|
|
703
|
+
showError,
|
|
704
|
+
existing,
|
|
705
|
+
propertyConfigs,
|
|
706
|
+
inArray
|
|
707
|
+
}: {
|
|
639
708
|
initialProperty?: PropertyWithId,
|
|
640
709
|
value?: PropertyConfigId,
|
|
641
710
|
onValueChange: (value: string) => void,
|
|
@@ -648,6 +717,8 @@ function WidgetSelectView({
|
|
|
648
717
|
inArray?: boolean
|
|
649
718
|
}) {
|
|
650
719
|
|
|
720
|
+
const { t } = useTranslation();
|
|
721
|
+
|
|
651
722
|
const allSupportedFields = Object.entries(supportedFields).concat(Object.entries(propertyConfigs));
|
|
652
723
|
|
|
653
724
|
const displayedWidgets = (inArray
|
|
@@ -670,47 +741,47 @@ function WidgetSelectView({
|
|
|
670
741
|
const computedFieldConfig = baseFieldConfig && propertyConfig ? mergeDeep(baseFieldConfig, propertyConfig) : propertyConfig;
|
|
671
742
|
|
|
672
743
|
const groups: string[] = [...new Set(Object.keys(displayedWidgets).map(key => {
|
|
673
|
-
const
|
|
674
|
-
if (
|
|
675
|
-
return
|
|
744
|
+
const groupKey = WIDGET_TYPE_MAP[key as PropertyConfigId];
|
|
745
|
+
if (groupKey) {
|
|
746
|
+
return t(groupKey as any);
|
|
676
747
|
}
|
|
677
|
-
return "
|
|
748
|
+
return t("custom_or_other")
|
|
678
749
|
}))];
|
|
679
750
|
|
|
680
751
|
return <>
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
752
|
+
<div
|
|
753
|
+
onClick={() => {
|
|
754
|
+
if (!disabled) {
|
|
755
|
+
onOpenChange(!open, Boolean(value));
|
|
756
|
+
}
|
|
757
|
+
}}
|
|
758
|
+
className={cls(
|
|
759
|
+
"select-none rounded-md text-sm p-4",
|
|
760
|
+
fieldBackgroundMixin,
|
|
761
|
+
disabled ? fieldBackgroundDisabledMixin : fieldBackgroundHoverMixin,
|
|
762
|
+
"relative flex items-center",
|
|
763
|
+
)}>
|
|
764
|
+
{!value && <em>{t("select_property_widget")}</em>}
|
|
694
765
|
{value && computedFieldConfig && <div
|
|
695
766
|
className={cls(
|
|
696
767
|
"flex items-center")}>
|
|
697
768
|
<div className={"mr-8"}>
|
|
698
|
-
<PropertyConfigBadge propertyConfig={computedFieldConfig}/>
|
|
769
|
+
<PropertyConfigBadge propertyConfig={computedFieldConfig} />
|
|
699
770
|
</div>
|
|
700
771
|
<div className={"flex flex-col items-start text-base text-left"}>
|
|
701
772
|
<div>{computedFieldConfig.name}</div>
|
|
702
773
|
<Typography variant={"caption"}
|
|
703
|
-
|
|
774
|
+
color={"secondary"}>
|
|
704
775
|
{computedFieldConfig.description}
|
|
705
776
|
</Typography>
|
|
706
777
|
</div>
|
|
707
778
|
</div>}
|
|
708
779
|
</div>
|
|
709
780
|
<Dialog open={open}
|
|
710
|
-
|
|
711
|
-
|
|
781
|
+
onOpenChange={(open) => onOpenChange(open, Boolean(value))}
|
|
782
|
+
maxWidth={"4xl"}>
|
|
712
783
|
<DialogTitle>
|
|
713
|
-
|
|
784
|
+
{t("select_property_widget")}
|
|
714
785
|
</DialogTitle>
|
|
715
786
|
<DialogContent>
|
|
716
787
|
<div>
|
|
@@ -720,7 +791,8 @@ function WidgetSelectView({
|
|
|
720
791
|
<div className={"grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-2 mt-4"}>
|
|
721
792
|
{Object.entries(displayedWidgets).map(([key, propertyConfig]) => {
|
|
722
793
|
const groupKey = WIDGET_TYPE_MAP[key as PropertyConfigId];
|
|
723
|
-
|
|
794
|
+
const translatedGroup = groupKey ? t(groupKey as any) : t("custom_or_other");
|
|
795
|
+
if (translatedGroup === group) {
|
|
724
796
|
return <WidgetSelectViewItem
|
|
725
797
|
key={key}
|
|
726
798
|
initialProperty={initialProperty}
|
|
@@ -729,7 +801,7 @@ function WidgetSelectView({
|
|
|
729
801
|
onOpenChange(false, true);
|
|
730
802
|
}}
|
|
731
803
|
propertyConfig={propertyConfig}
|
|
732
|
-
existing={existing}/>;
|
|
804
|
+
existing={existing} />;
|
|
733
805
|
}
|
|
734
806
|
return null;
|
|
735
807
|
})}
|
|
@@ -761,12 +833,13 @@ export interface PropertySelectItemProps {
|
|
|
761
833
|
}
|
|
762
834
|
|
|
763
835
|
export function WidgetSelectViewItem({
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
836
|
+
onClick,
|
|
837
|
+
initialProperty,
|
|
838
|
+
// optionDisabled,
|
|
839
|
+
propertyConfig,
|
|
840
|
+
existing
|
|
841
|
+
}: PropertySelectItemProps) {
|
|
842
|
+
const { t } = useTranslation();
|
|
770
843
|
const baseProperty = propertyConfig.property;
|
|
771
844
|
const shouldWarnChangingDataType = existing && !isPropertyBuilder(baseProperty) && baseProperty.dataType !== initialProperty?.dataType;
|
|
772
845
|
|
|
@@ -778,13 +851,13 @@ export function WidgetSelectViewItem({
|
|
|
778
851
|
"flex flex-row items-center text-base min-h-[48px]",
|
|
779
852
|
)}>
|
|
780
853
|
<div className={"mr-8"}>
|
|
781
|
-
<PropertyConfigBadge propertyConfig={propertyConfig} disabled={shouldWarnChangingDataType}/>
|
|
854
|
+
<PropertyConfigBadge propertyConfig={propertyConfig} disabled={shouldWarnChangingDataType} />
|
|
782
855
|
</div>
|
|
783
856
|
<div>
|
|
784
857
|
<div className={"flex flex-row gap-2 items-center"}>
|
|
785
858
|
{shouldWarnChangingDataType && <Tooltip
|
|
786
|
-
title={"
|
|
787
|
-
<WarningIcon size="smallest" className={"w-4"}/>
|
|
859
|
+
title={t("error_changing_data_type")}>
|
|
860
|
+
<WarningIcon size="smallest" className={"w-4"} />
|
|
788
861
|
</Tooltip>}
|
|
789
862
|
<Typography
|
|
790
863
|
variant={"label"}
|
|
@@ -792,8 +865,8 @@ export function WidgetSelectViewItem({
|
|
|
792
865
|
</div>
|
|
793
866
|
|
|
794
867
|
<Typography variant={"caption"}
|
|
795
|
-
|
|
796
|
-
|
|
868
|
+
color={"secondary"}
|
|
869
|
+
className={"max-w-sm"}>
|
|
797
870
|
{propertyConfig.description}
|
|
798
871
|
</Typography>
|
|
799
872
|
|