@firecms/collection_editor 3.0.0-alpha.5 → 3.0.0-alpha.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/dist/ConfigControllerProvider.d.ts +36 -0
  2. package/dist/index.d.ts +11 -0
  3. package/dist/index.es.js +6995 -0
  4. package/dist/index.es.js.map +1 -0
  5. package/dist/index.umd.js +4 -0
  6. package/dist/index.umd.js.map +1 -0
  7. package/dist/types/collection_editor_controller.d.ts +35 -0
  8. package/dist/types/collection_inference.d.ts +2 -0
  9. package/dist/types/config_controller.d.ts +41 -0
  10. package/dist/types/config_permissions.d.ts +19 -0
  11. package/dist/types/persisted_collection.d.ts +6 -0
  12. package/dist/ui/CollectionViewHeaderAction.d.ts +10 -0
  13. package/dist/ui/EditorCollectionAction.d.ts +2 -0
  14. package/dist/ui/HomePageEditorCollectionAction.d.ts +2 -0
  15. package/dist/ui/MissingReferenceWidget.d.ts +3 -0
  16. package/dist/ui/NewCollectionCard.d.ts +2 -0
  17. package/dist/ui/PropertyAddColumnComponent.d.ts +6 -0
  18. package/dist/ui/RootCollectionSuggestions.d.ts +1 -0
  19. package/dist/ui/collection_editor/CollectionDetailsForm.d.ts +9 -0
  20. package/dist/ui/collection_editor/CollectionEditorDialog.d.ts +38 -0
  21. package/dist/ui/collection_editor/CollectionEditorWelcomeView.d.ts +15 -0
  22. package/dist/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +20 -0
  23. package/dist/ui/collection_editor/CollectionYupValidation.d.ts +14 -0
  24. package/dist/ui/collection_editor/EntityCustomViewsSelectDialog.d.ts +4 -0
  25. package/dist/ui/collection_editor/EnumForm.d.ts +13 -0
  26. package/dist/ui/collection_editor/GetCodeDialog.d.ts +5 -0
  27. package/dist/ui/collection_editor/PropertyEditView.d.ts +40 -0
  28. package/dist/ui/collection_editor/PropertyFieldPreview.d.ts +15 -0
  29. package/dist/ui/collection_editor/PropertySelectItem.d.ts +8 -0
  30. package/dist/ui/collection_editor/PropertyTree.d.ts +32 -0
  31. package/dist/ui/collection_editor/SelectIcons.d.ts +6 -0
  32. package/dist/ui/collection_editor/SubcollectionsEditTab.d.ts +12 -0
  33. package/dist/ui/collection_editor/UnsavedChangesDialog.d.ts +9 -0
  34. package/dist/ui/collection_editor/import/CollectionEditorImportDataPreview.d.ts +7 -0
  35. package/dist/ui/collection_editor/import/CollectionEditorImportMapping.d.ts +7 -0
  36. package/dist/ui/collection_editor/import/clean_import_data.d.ts +7 -0
  37. package/dist/ui/collection_editor/properties/BlockPropertyField.d.ts +8 -0
  38. package/dist/ui/collection_editor/properties/BooleanPropertyField.d.ts +3 -0
  39. package/dist/ui/collection_editor/properties/CommonPropertyFields.d.ts +10 -0
  40. package/dist/ui/collection_editor/properties/DateTimePropertyField.d.ts +3 -0
  41. package/dist/ui/collection_editor/properties/EnumPropertyField.d.ts +8 -0
  42. package/dist/ui/collection_editor/properties/FieldHelperView.d.ts +4 -0
  43. package/dist/ui/collection_editor/properties/KeyValuePropertyField.d.ts +3 -0
  44. package/dist/ui/collection_editor/properties/MapPropertyField.d.ts +8 -0
  45. package/dist/ui/collection_editor/properties/NumberPropertyField.d.ts +3 -0
  46. package/dist/ui/collection_editor/properties/ReferencePropertyField.d.ts +13 -0
  47. package/dist/ui/collection_editor/properties/RepeatPropertyField.d.ts +10 -0
  48. package/dist/ui/collection_editor/properties/StoragePropertyField.d.ts +5 -0
  49. package/dist/ui/collection_editor/properties/StringPropertyField.d.ts +5 -0
  50. package/dist/ui/collection_editor/properties/UrlPropertyField.d.ts +4 -0
  51. package/dist/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.d.ts +3 -0
  52. package/dist/ui/collection_editor/properties/validation/ArrayPropertyValidation.d.ts +5 -0
  53. package/dist/ui/collection_editor/properties/validation/GeneralPropertyValidation.d.ts +4 -0
  54. package/dist/ui/collection_editor/properties/validation/NumberPropertyValidation.d.ts +3 -0
  55. package/dist/ui/collection_editor/properties/validation/StringPropertyValidation.d.ts +11 -0
  56. package/dist/ui/collection_editor/properties/validation/ValidationPanel.d.ts +2 -0
  57. package/dist/ui/collection_editor/templates/blog_template.d.ts +2 -0
  58. package/dist/ui/collection_editor/templates/products_template.d.ts +2 -0
  59. package/dist/ui/collection_editor/templates/users_template.d.ts +2 -0
  60. package/dist/ui/collection_editor/util.d.ts +4 -0
  61. package/dist/ui/collection_editor/utils/strings.d.ts +1 -0
  62. package/dist/ui/collection_editor/utils/supported_fields.d.ts +3 -0
  63. package/dist/ui/collection_editor/utils/update_property_for_widget.d.ts +2 -0
  64. package/dist/ui/collection_editor/utils/useTraceUpdate.d.ts +1 -0
  65. package/dist/useCollectionEditorController.d.ts +6 -0
  66. package/dist/useCollectionEditorPlugin.d.ts +45 -0
  67. package/dist/useCollectionsConfigController.d.ts +6 -0
  68. package/dist/utils/arrays.d.ts +1 -0
  69. package/dist/utils/entities.d.ts +3 -0
  70. package/dist/utils/icons.d.ts +1 -0
  71. package/dist/utils/synonyms.d.ts +1951 -0
  72. package/package.json +26 -23
  73. package/src/ConfigControllerProvider.tsx +321 -0
  74. package/src/index.ts +35 -0
  75. package/src/types/collection_editor_controller.tsx +42 -0
  76. package/src/types/collection_inference.ts +3 -0
  77. package/src/types/config_controller.tsx +50 -0
  78. package/src/types/config_permissions.ts +20 -0
  79. package/src/types/persisted_collection.ts +9 -0
  80. package/src/ui/CollectionViewHeaderAction.tsx +42 -0
  81. package/src/ui/EditorCollectionAction.tsx +95 -0
  82. package/src/ui/HomePageEditorCollectionAction.tsx +88 -0
  83. package/src/ui/MissingReferenceWidget.tsx +34 -0
  84. package/src/ui/NewCollectionCard.tsx +46 -0
  85. package/src/ui/PropertyAddColumnComponent.tsx +41 -0
  86. package/src/ui/RootCollectionSuggestions.tsx +62 -0
  87. package/src/ui/collection_editor/CollectionDetailsForm.tsx +353 -0
  88. package/src/ui/collection_editor/CollectionEditorDialog.tsx +744 -0
  89. package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +212 -0
  90. package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +480 -0
  91. package/src/ui/collection_editor/CollectionYupValidation.tsx +7 -0
  92. package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +36 -0
  93. package/src/ui/collection_editor/EnumForm.tsx +356 -0
  94. package/src/ui/collection_editor/GetCodeDialog.tsx +118 -0
  95. package/src/ui/collection_editor/PropertyEditView.tsx +565 -0
  96. package/src/ui/collection_editor/PropertyFieldPreview.tsx +201 -0
  97. package/src/ui/collection_editor/PropertySelectItem.tsx +31 -0
  98. package/src/ui/collection_editor/PropertyTree.tsx +238 -0
  99. package/src/ui/collection_editor/SelectIcons.tsx +72 -0
  100. package/src/ui/collection_editor/SubcollectionsEditTab.tsx +252 -0
  101. package/src/ui/collection_editor/UnsavedChangesDialog.tsx +47 -0
  102. package/src/ui/collection_editor/import/CollectionEditorImportDataPreview.tsx +37 -0
  103. package/src/ui/collection_editor/import/CollectionEditorImportMapping.tsx +275 -0
  104. package/src/ui/collection_editor/import/clean_import_data.ts +53 -0
  105. package/src/ui/collection_editor/properties/BlockPropertyField.tsx +134 -0
  106. package/src/ui/collection_editor/properties/BooleanPropertyField.tsx +36 -0
  107. package/src/ui/collection_editor/properties/CommonPropertyFields.tsx +111 -0
  108. package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +86 -0
  109. package/src/ui/collection_editor/properties/EnumPropertyField.tsx +116 -0
  110. package/src/ui/collection_editor/properties/FieldHelperView.tsx +13 -0
  111. package/src/ui/collection_editor/properties/KeyValuePropertyField.tsx +20 -0
  112. package/src/ui/collection_editor/properties/MapPropertyField.tsx +157 -0
  113. package/src/ui/collection_editor/properties/NumberPropertyField.tsx +38 -0
  114. package/src/ui/collection_editor/properties/ReferencePropertyField.tsx +184 -0
  115. package/src/ui/collection_editor/properties/RepeatPropertyField.tsx +107 -0
  116. package/src/ui/collection_editor/properties/StoragePropertyField.tsx +194 -0
  117. package/src/ui/collection_editor/properties/StringPropertyField.tsx +79 -0
  118. package/src/ui/collection_editor/properties/UrlPropertyField.tsx +89 -0
  119. package/src/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.tsx +36 -0
  120. package/src/ui/collection_editor/properties/validation/ArrayPropertyValidation.tsx +50 -0
  121. package/src/ui/collection_editor/properties/validation/GeneralPropertyValidation.tsx +49 -0
  122. package/src/ui/collection_editor/properties/validation/NumberPropertyValidation.tsx +99 -0
  123. package/src/ui/collection_editor/properties/validation/StringPropertyValidation.tsx +131 -0
  124. package/src/ui/collection_editor/properties/validation/ValidationPanel.tsx +28 -0
  125. package/src/ui/collection_editor/templates/blog_template.ts +115 -0
  126. package/src/ui/collection_editor/templates/products_template.ts +88 -0
  127. package/src/ui/collection_editor/templates/users_template.ts +34 -0
  128. package/src/ui/collection_editor/util.ts +21 -0
  129. package/src/ui/collection_editor/utils/strings.ts +8 -0
  130. package/src/ui/collection_editor/utils/supported_fields.tsx +29 -0
  131. package/src/ui/collection_editor/utils/update_property_for_widget.ts +271 -0
  132. package/src/ui/collection_editor/utils/useTraceUpdate.tsx +23 -0
  133. package/src/useCollectionEditorController.tsx +9 -0
  134. package/src/useCollectionEditorPlugin.tsx +128 -0
  135. package/src/useCollectionsConfigController.tsx +9 -0
  136. package/src/utils/arrays.ts +3 -0
  137. package/src/utils/entities.ts +38 -0
  138. package/src/utils/icons.ts +17 -0
  139. package/src/utils/synonyms.ts +1952 -0
  140. package/src/vite-env.d.ts +1 -0
@@ -0,0 +1,565 @@
1
+ import React, { useDeferredValue, useEffect, useRef, useState } from "react";
2
+ import equal from "react-fast-compare"
3
+
4
+ import { Formik, FormikErrors, FormikProps, getIn } from "formik";
5
+ import {
6
+ Button,
7
+ cn,
8
+ DEFAULT_FIELD_CONFIGS,
9
+ DeleteConfirmationDialog,
10
+ DeleteIcon,
11
+ Dialog,
12
+ DialogActions,
13
+ DialogContent,
14
+ FieldConfigBadge,
15
+ FieldConfigId,
16
+ getFieldConfig,
17
+ getFieldId,
18
+ IconButton,
19
+ InfoLabel,
20
+ isPropertyBuilder,
21
+ mergeDeep,
22
+ Property,
23
+ PropertyConfig,
24
+ Select,
25
+ toSnakeCase,
26
+ Typography
27
+ } from "@firecms/core";
28
+ import { EnumPropertyField } from "./properties/EnumPropertyField";
29
+ import { StoragePropertyField } from "./properties/StoragePropertyField";
30
+ import { MapPropertyField } from "./properties/MapPropertyField";
31
+ import { RepeatPropertyField } from "./properties/RepeatPropertyField";
32
+ import { CommonPropertyFields } from "./properties/CommonPropertyFields";
33
+ import { StringPropertyField } from "./properties/StringPropertyField";
34
+ import { BooleanPropertyField } from "./properties/BooleanPropertyField";
35
+ import { BlockPropertyField } from "./properties/BlockPropertyField";
36
+ import { NumberPropertyField } from "./properties/NumberPropertyField";
37
+ import { ReferencePropertyField } from "./properties/ReferencePropertyField";
38
+ import { DateTimePropertyField } from "./properties/DateTimePropertyField";
39
+ import { AdvancedPropertyValidation } from "./properties/advanced/AdvancedPropertyValidation";
40
+ import { editableProperty } from "../../utils/entities";
41
+ import { KeyValuePropertyField } from "./properties/KeyValuePropertyField";
42
+ import { updatePropertyFromWidget } from "./utils/update_property_for_widget";
43
+ import { PropertySelectItem } from "./PropertySelectItem";
44
+ import { UrlPropertyField } from "./properties/UrlPropertyField";
45
+ import { supportedFields } from "./utils/supported_fields";
46
+
47
+ export type PropertyWithId = Property & {
48
+ id?: string
49
+ };
50
+
51
+ export type OnPropertyChangedParams = {
52
+ id?: string,
53
+ property: Property,
54
+ namespace?: string,
55
+ previousId?: string
56
+ };
57
+
58
+ export type PropertyFormProps = {
59
+ includeIdAndName?: boolean;
60
+ existingProperty: boolean;
61
+ autoUpdateId?: boolean;
62
+ autoOpenTypeSelect: boolean;
63
+ inArray: boolean;
64
+ propertyKey?: string;
65
+ propertyNamespace?: string;
66
+ property?: Property;
67
+ onPropertyChanged?: (params: OnPropertyChangedParams) => void;
68
+ onPropertyChangedImmediate?: boolean;
69
+ onDelete?: (id?: string, namespace?: string) => void;
70
+ onError?: (id: string, namespace?: string, error?: FormikErrors<any>) => void;
71
+ initialErrors?: FormikErrors<any>;
72
+ forceShowErrors?: boolean;
73
+ existingPropertyKeys?: string[];
74
+ allowDataInference: boolean;
75
+ getData?: () => Promise<object[]>;
76
+ getHelpers?: (formikProps: FormikProps<PropertyWithId>) => void;
77
+ propertyConfigs: Record<string, PropertyConfig>;
78
+ collectionEditable: boolean;
79
+ };
80
+
81
+ export const PropertyForm = React.memo(
82
+ function PropertyForm({
83
+ includeIdAndName = true,
84
+ autoOpenTypeSelect,
85
+ existingProperty,
86
+ autoUpdateId,
87
+ inArray,
88
+ propertyKey,
89
+ propertyNamespace,
90
+ property,
91
+ onPropertyChanged,
92
+ onPropertyChangedImmediate = true,
93
+ onDelete,
94
+ onError,
95
+ initialErrors,
96
+ forceShowErrors,
97
+ existingPropertyKeys,
98
+ allowDataInference,
99
+ getHelpers,
100
+ getData,
101
+ propertyConfigs,
102
+ collectionEditable
103
+ }: PropertyFormProps) {
104
+
105
+ const initialValue: PropertyWithId = {
106
+ id: "",
107
+ name: ""
108
+ } as PropertyWithId;
109
+
110
+ const disabled = (Boolean(property && !editableProperty(property)) && !collectionEditable);
111
+
112
+ const lastSubmittedProperty = useRef<OnPropertyChangedParams | undefined>(property ? {
113
+ id: propertyKey,
114
+ previousId: propertyKey,
115
+ property
116
+ } : undefined);
117
+
118
+ const doOnPropertyChanged = ({
119
+ id,
120
+ property
121
+ }: OnPropertyChangedParams) => {
122
+ const params = {
123
+ id,
124
+ previousId: lastSubmittedProperty.current?.id,
125
+ property,
126
+ namespace: propertyNamespace
127
+ };
128
+ lastSubmittedProperty.current = params;
129
+ onPropertyChanged?.(params);
130
+ };
131
+
132
+ return <Formik
133
+ key={`property_view_${propertyKey}`}
134
+ initialErrors={initialErrors}
135
+ initialValues={property
136
+ ? { id: propertyKey, ...property } as PropertyWithId
137
+ : initialValue}
138
+ onSubmit={(newPropertyWithId: PropertyWithId, helpers) => {
139
+ console.log("Submitting property", newPropertyWithId)
140
+ const {
141
+ id,
142
+ ...property
143
+ } = newPropertyWithId;
144
+ doOnPropertyChanged({
145
+ id,
146
+ property: { ...property, editable: property.editable ?? true }
147
+ });
148
+ if (!existingProperty)
149
+ helpers.resetForm({ values: initialValue });
150
+ }}
151
+ // validate={(values) => {
152
+ // console.log("validate property", values)
153
+ // const errors: any = {};
154
+ // if (!values?.dataType || !getFieldConfig(values)) {
155
+ // errors.selectedWidget = "Required";
156
+ // }
157
+ // if (existingPropertyKeys && values?.id && existingPropertyKeys.includes(values?.id)) {
158
+ // errors.id = "";
159
+ // }
160
+ // console.log("errors", errors)
161
+ // return errors;
162
+ // }}
163
+ >
164
+ {(props) => {
165
+
166
+ // eslint-disable-next-line react-hooks/rules-of-hooks
167
+ useEffect(() => {
168
+ getHelpers?.(props);
169
+ }, [props]);
170
+
171
+ return <PropertyEditView
172
+ onPropertyChanged={onPropertyChangedImmediate
173
+ ? doOnPropertyChanged
174
+ : undefined}
175
+ onDelete={onDelete}
176
+ includeIdAndTitle={includeIdAndName}
177
+ propertyNamespace={propertyNamespace}
178
+ onError={onError}
179
+ showErrors={forceShowErrors || props.submitCount > 0}
180
+ existing={existingProperty}
181
+ autoUpdateId={autoUpdateId}
182
+ inArray={inArray}
183
+ autoOpenTypeSelect={autoOpenTypeSelect}
184
+ existingPropertyKeys={existingPropertyKeys}
185
+ disabled={disabled}
186
+ getData={getData}
187
+ allowDataInference={allowDataInference}
188
+ propertyConfigs={propertyConfigs}
189
+ collectionEditable={collectionEditable}
190
+ {...props}/>;
191
+
192
+ }}
193
+
194
+ </Formik>
195
+ }, (a, b) =>
196
+ a.getData === b.getData &&
197
+ a.includeIdAndName === b.includeIdAndName &&
198
+ a.autoOpenTypeSelect === b.autoOpenTypeSelect &&
199
+ a.autoUpdateId === b.autoUpdateId &&
200
+ a.existingProperty === b.existingProperty
201
+ );
202
+
203
+ export function PropertyFormDialog({
204
+ open,
205
+ onCancel,
206
+ onOkClicked,
207
+ onPropertyChanged,
208
+ getData,
209
+ collectionEditable,
210
+ ...formProps
211
+ }: PropertyFormProps & {
212
+ open?: boolean;
213
+ onOkClicked?: () => void;
214
+ onCancel?: () => void;
215
+ }) {
216
+ const helpersRef = useRef<FormikProps<PropertyWithId>>();
217
+ const getHelpers = (helpers: FormikProps<PropertyWithId>) => {
218
+ helpersRef.current = helpers;
219
+ };
220
+
221
+ return <Dialog
222
+ open={open ?? false}
223
+ maxWidth={"xl"}
224
+ fullWidth={true}
225
+ >
226
+
227
+ <DialogContent>
228
+ <PropertyForm {...formProps}
229
+ onPropertyChanged={(params) => {
230
+ onPropertyChanged?.(params);
231
+ onOkClicked?.();
232
+ }}
233
+ collectionEditable={collectionEditable}
234
+ onPropertyChangedImmediate={false}
235
+ getHelpers={getHelpers}
236
+ getData={getData}
237
+ />
238
+ </DialogContent>
239
+
240
+ <DialogActions>
241
+
242
+ {onCancel && <Button
243
+ variant={"text"}
244
+ onClick={() => {
245
+ onCancel();
246
+ helpersRef.current?.resetForm();
247
+ }}>
248
+ Cancel
249
+ </Button>}
250
+
251
+ <Button variant="outlined"
252
+ color="primary"
253
+ onClick={() => helpersRef.current?.submitForm()}>
254
+ Ok
255
+ </Button>
256
+ </DialogActions>
257
+ </Dialog>;
258
+
259
+ }
260
+
261
+ function PropertyEditView({
262
+ values,
263
+ errors,
264
+ touched,
265
+ setValues,
266
+ setFieldValue,
267
+ existing,
268
+ autoUpdateId = false,
269
+ autoOpenTypeSelect,
270
+ includeIdAndTitle,
271
+ onPropertyChanged,
272
+ onDelete,
273
+ propertyNamespace,
274
+ onError,
275
+ showErrors,
276
+ disabled,
277
+ inArray,
278
+ existingPropertyKeys,
279
+ getData,
280
+ allowDataInference,
281
+ propertyConfigs,
282
+ collectionEditable
283
+ }: {
284
+ includeIdAndTitle?: boolean;
285
+ existing: boolean;
286
+ autoUpdateId?: boolean;
287
+ autoOpenTypeSelect: boolean;
288
+ propertyNamespace?: string;
289
+ onPropertyChanged?: (params: OnPropertyChangedParams) => void;
290
+ onDelete?: (id?: string, namespace?: string) => void;
291
+ onError?: (id: string, namespace?: string, error?: FormikErrors<any>) => void;
292
+ showErrors: boolean;
293
+ inArray: boolean;
294
+ disabled: boolean;
295
+ existingPropertyKeys?: string[];
296
+ getData?: () => Promise<object[]>;
297
+ allowDataInference: boolean;
298
+ propertyConfigs: Record<string, PropertyConfig>;
299
+ collectionEditable: boolean;
300
+ } & FormikProps<PropertyWithId>) {
301
+
302
+ const [selectOpen, setSelectOpen] = useState(autoOpenTypeSelect);
303
+ const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
304
+ const [selectedFieldConfigId, setSelectedFieldConfigId] = useState<string | undefined>(values?.dataType ? getFieldId(values) : undefined);
305
+
306
+ const allSupportedFields = Object.entries(supportedFields).concat(Object.entries(propertyConfigs));
307
+
308
+ const displayedWidgets = inArray
309
+ ? allSupportedFields.filter(([_, propertyConfig]) => !isPropertyBuilder(propertyConfig.property) && propertyConfig.property?.dataType !== "array")
310
+ : allSupportedFields;
311
+
312
+ const deferredValues = useDeferredValue(values);
313
+ const nameFieldRef = useRef<HTMLInputElement>(null);
314
+
315
+ const lastSubmittedProperty = useRef<object>(values);
316
+
317
+ const id = "id";
318
+
319
+ const selectedWidgetError = showErrors && getIn(errors, "selectedWidget");
320
+
321
+ useEffect(() => {
322
+ const idTouched = getIn(touched, id);
323
+ if (!idTouched && autoUpdateId && values?.name) {
324
+ setFieldValue(id, toSnakeCase(values.name))
325
+ }
326
+ }, [autoUpdateId, touched, values?.name]);
327
+
328
+ useEffect(() => {
329
+ if (onPropertyChanged) {
330
+ if ((!includeIdAndTitle || deferredValues.id)) {
331
+ const {
332
+ id,
333
+ ...property
334
+ } = deferredValues;
335
+ if (!equal(deferredValues, lastSubmittedProperty.current)) {
336
+ onPropertyChanged({
337
+ id,
338
+ property,
339
+ namespace: propertyNamespace
340
+ });
341
+ lastSubmittedProperty.current = deferredValues;
342
+ }
343
+ }
344
+ }
345
+ }, [deferredValues, includeIdAndTitle, onPropertyChanged, propertyNamespace]);
346
+
347
+ useEffect(() => {
348
+ if (values?.id && onError && Object.keys(errors).length > 0) {
349
+ onError(values?.id, propertyNamespace, errors);
350
+ }
351
+ }, [errors, onError, propertyNamespace, values?.id]);
352
+
353
+ const onWidgetSelectChanged = (newSelectedWidgetId: FieldConfigId) => {
354
+ setSelectedFieldConfigId(newSelectedWidgetId);
355
+ setValues(updatePropertyFromWidget(values, newSelectedWidgetId, propertyConfigs));
356
+ // Ugly hack to autofocus the name field
357
+ setTimeout(() => {
358
+ nameFieldRef.current?.focus();
359
+ }, 0);
360
+ };
361
+
362
+ let childComponent;
363
+ if (selectedFieldConfigId === "text_field" ||
364
+ selectedFieldConfigId === "multiline" ||
365
+ selectedFieldConfigId === "markdown" ||
366
+ selectedFieldConfigId === "email") {
367
+ childComponent =
368
+ <StringPropertyField widgetId={selectedFieldConfigId}
369
+ disabled={disabled}
370
+ showErrors={showErrors}/>;
371
+ } else if (selectedFieldConfigId === "url") {
372
+ childComponent =
373
+ <UrlPropertyField disabled={disabled}
374
+ showErrors={showErrors}/>;
375
+ } else if (selectedFieldConfigId === "select" ||
376
+ selectedFieldConfigId === "number_select") {
377
+ childComponent = <EnumPropertyField
378
+ multiselect={false}
379
+ allowDataInference={allowDataInference}
380
+ updateIds={!existing}
381
+ disabled={disabled}
382
+ getData={getData}
383
+ showErrors={showErrors}/>;
384
+ } else if (selectedFieldConfigId === "multi_select" ||
385
+ selectedFieldConfigId === "multi_number_select") {
386
+ childComponent = <EnumPropertyField
387
+ multiselect={true}
388
+ updateIds={!existing}
389
+ disabled={disabled}
390
+ allowDataInference={allowDataInference}
391
+ getData={getData}
392
+ showErrors={showErrors}/>;
393
+ } else if (selectedFieldConfigId === "file_upload") {
394
+ childComponent =
395
+ <StoragePropertyField existing={existing}
396
+ multiple={false}
397
+ disabled={disabled}/>;
398
+ } else if (selectedFieldConfigId === "multi_file_upload") {
399
+ childComponent =
400
+ <StoragePropertyField existing={existing}
401
+ multiple={true}
402
+ disabled={disabled}/>;
403
+ } else if (selectedFieldConfigId === "switch") {
404
+ childComponent = <BooleanPropertyField disabled={disabled}/>;
405
+ } else if (selectedFieldConfigId === "number_input") {
406
+ childComponent = <NumberPropertyField disabled={disabled}/>;
407
+ } else if (selectedFieldConfigId === "group") {
408
+ childComponent =
409
+ <MapPropertyField disabled={disabled} getData={getData} allowDataInference={allowDataInference}
410
+ collectionEditable={collectionEditable}
411
+ propertyConfigs={propertyConfigs}/>;
412
+ } else if (selectedFieldConfigId === "block") {
413
+ childComponent =
414
+ <BlockPropertyField disabled={disabled} getData={getData} allowDataInference={allowDataInference}
415
+ collectionEditable={collectionEditable}
416
+ propertyConfigs={propertyConfigs}/>;
417
+ } else if (selectedFieldConfigId === "reference") {
418
+ childComponent =
419
+ <ReferencePropertyField showErrors={showErrors}
420
+ existing={existing}
421
+ multiple={false}
422
+ disabled={disabled}/>;
423
+ } else if (selectedFieldConfigId === "date_time") {
424
+ childComponent = <DateTimePropertyField disabled={disabled}/>;
425
+ } else if (selectedFieldConfigId === "multi_references") {
426
+ childComponent =
427
+ <ReferencePropertyField showErrors={showErrors}
428
+ existing={existing}
429
+ multiple={true}
430
+ disabled={disabled}/>;
431
+ } else if (selectedFieldConfigId === "repeat") {
432
+ childComponent =
433
+ <RepeatPropertyField showErrors={showErrors}
434
+ existing={existing}
435
+ getData={getData}
436
+ allowDataInference={allowDataInference}
437
+ disabled={disabled}
438
+ collectionEditable={collectionEditable}
439
+ propertyConfigs={propertyConfigs}/>;
440
+ } else if (selectedFieldConfigId === "key_value") {
441
+ childComponent =
442
+ <KeyValuePropertyField disabled={disabled}/>;
443
+ } else {
444
+ childComponent = null;
445
+ }
446
+
447
+ return (
448
+ <>
449
+ {disabled && <InfoLabel mode={"warn"}>
450
+ <Typography>This property can&apos;t be edited</Typography>
451
+ <Typography variant={"caption"}>
452
+ You may not have permission to
453
+ edit it or it is defined in code with no <code>editable</code> flag
454
+ </Typography>
455
+ </InfoLabel>}
456
+
457
+ <div className="flex mt-2 justify-between">
458
+ <div className={"w-full flex flex-col gap-2"}>
459
+ <Select
460
+ // className={"w-full"}
461
+ error={Boolean(selectedWidgetError)}
462
+ value={selectedFieldConfigId ?? ""}
463
+ placeholder={"Select a property widget"}
464
+ open={selectOpen}
465
+ onOpenChange={setSelectOpen}
466
+ position={"item-aligned"}
467
+ disabled={disabled}
468
+ renderValue={(value) => {
469
+ if (!value) {
470
+ return <em>Select a property
471
+ widget</em>;
472
+ }
473
+ const key = value as FieldConfigId;
474
+ const propertyConfig = DEFAULT_FIELD_CONFIGS[key] ?? propertyConfigs[key];
475
+ const baseProperty = propertyConfig.property;
476
+ const baseFieldConfig = baseProperty && !isPropertyBuilder(baseProperty) ? getFieldConfig(baseProperty, propertyConfigs) : undefined;
477
+ const optionDisabled = isPropertyBuilder(baseProperty) || (existing && baseProperty.dataType !== values?.dataType);
478
+ const computedFieldConfig = baseFieldConfig ? mergeDeep(baseFieldConfig, propertyConfig) : propertyConfig;
479
+ return <div
480
+ onClick={(e) => {
481
+ if (optionDisabled) {
482
+ e.stopPropagation();
483
+ e.preventDefault();
484
+ }
485
+ }}
486
+ className={cn(
487
+ "flex items-center",
488
+ optionDisabled ? "w-full pointer-events-none opacity-50" : "")}>
489
+ <div className={"mr-8"}>
490
+ <FieldConfigBadge propertyConfig={computedFieldConfig}/>
491
+ </div>
492
+ <div className={"flex flex-col items-start text-base text-left"}>
493
+ <div>{computedFieldConfig.name}</div>
494
+ <Typography variant={"caption"}
495
+ color={"disabled"}>
496
+ {optionDisabled ? "You can only switch to widgets that use the same data type" : computedFieldConfig.description}
497
+ </Typography>
498
+ </div>
499
+ </div>
500
+ }}
501
+ onValueChange={(value) => {
502
+ onWidgetSelectChanged(value as FieldConfigId);
503
+ }}>
504
+ {displayedWidgets.map(([key, propertyConfig]) => {
505
+ const baseProperty = propertyConfig.property;
506
+ const optionDisabled = existing && !isPropertyBuilder(baseProperty) && baseProperty.dataType !== values?.dataType;
507
+ return <PropertySelectItem
508
+ key={key}
509
+ value={key}
510
+ optionDisabled={optionDisabled}
511
+ propertyConfig={propertyConfig}
512
+ existing={existing}/>;
513
+ })}
514
+ </Select>
515
+
516
+ {selectedWidgetError &&
517
+ <Typography variant="caption"
518
+ className={"ml-3.5"}
519
+ color={"error"}>Required</Typography>}
520
+
521
+ {/*<Typography variant="caption" className={"ml-3.5"}>Define your own custom properties and*/}
522
+ {/* components</Typography>*/}
523
+
524
+ </div>
525
+
526
+ {onDelete && values?.id &&
527
+ <IconButton
528
+ variant={"ghost"}
529
+ className="m-4"
530
+ disabled={disabled}
531
+ onClick={() => setDeleteDialogOpen(true)}>
532
+ <DeleteIcon/>
533
+ </IconButton>}
534
+ </div>
535
+
536
+ <div className={"grid grid-cols-12 gap-y-12 mt-8 mb-8"}>
537
+ {includeIdAndTitle &&
538
+ <CommonPropertyFields showErrors={showErrors}
539
+ disabledId={existing}
540
+ isNewProperty={!existing}
541
+ existingPropertyKeys={existingPropertyKeys}
542
+ disabled={disabled}
543
+ ref={nameFieldRef}/>}
544
+
545
+ {childComponent}
546
+
547
+ <div className={"col-span-12"}>
548
+ <AdvancedPropertyValidation disabled={disabled}/>
549
+ </div>
550
+ </div>
551
+
552
+ {onDelete &&
553
+ <DeleteConfirmationDialog open={deleteDialogOpen}
554
+ onAccept={() => onDelete(values?.id, propertyNamespace)}
555
+ onCancel={() => setDeleteDialogOpen(false)}
556
+ title={<div>Delete this property?</div>}
557
+ body={
558
+ <div> This will <b>not delete any
559
+ data</b>, only modify the
560
+ collection.</div>
561
+ }/>}
562
+
563
+ </>
564
+ );
565
+ }