@firecms/collection_editor 3.0.0-alpha.9 → 3.0.0-beta.10

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 (149) hide show
  1. package/LICENSE +114 -21
  2. package/dist/ConfigControllerProvider.d.ts +13 -3
  3. package/dist/index.d.ts +4 -2
  4. package/dist/index.es.js +5587 -4976
  5. package/dist/index.es.js.map +1 -1
  6. package/dist/index.umd.js +6829 -1
  7. package/dist/index.umd.js.map +1 -1
  8. package/dist/types/collection_editor_controller.d.ts +36 -8
  9. package/dist/types/collection_inference.d.ts +1 -1
  10. package/dist/types/config_controller.d.ts +33 -6
  11. package/dist/types/persisted_collection.d.ts +4 -2
  12. package/dist/ui/CollectionViewHeaderAction.d.ts +11 -0
  13. package/dist/{components → ui}/EditorCollectionAction.d.ts +1 -1
  14. package/dist/ui/EditorCollectionActionStart.d.ts +2 -0
  15. package/dist/ui/MissingReferenceWidget.d.ts +3 -0
  16. package/dist/ui/NewCollectionButton.d.ts +1 -0
  17. package/dist/ui/PropertyAddColumnComponent.d.ts +8 -0
  18. package/dist/{components → ui}/collection_editor/CollectionDetailsForm.d.ts +3 -2
  19. package/dist/{components → ui}/collection_editor/CollectionEditorDialog.d.ts +15 -11
  20. package/dist/{components → ui}/collection_editor/CollectionEditorWelcomeView.d.ts +3 -3
  21. package/dist/{components → ui}/collection_editor/CollectionPropertiesEditorForm.d.ts +8 -6
  22. package/dist/{components → ui}/collection_editor/CollectionYupValidation.d.ts +3 -0
  23. package/dist/ui/collection_editor/EntityCustomViewsSelectDialog.d.ts +4 -0
  24. package/dist/{components → ui}/collection_editor/EnumForm.d.ts +1 -2
  25. package/dist/ui/collection_editor/GetCodeDialog.d.ts +5 -0
  26. package/dist/{components → ui}/collection_editor/PropertyEditView.d.ts +21 -11
  27. package/dist/{components → ui}/collection_editor/PropertyFieldPreview.d.ts +4 -3
  28. package/dist/{components → ui}/collection_editor/PropertyTree.d.ts +11 -7
  29. package/dist/{components → ui}/collection_editor/SubcollectionsEditTab.d.ts +3 -3
  30. package/dist/ui/collection_editor/SwitchControl.d.ts +8 -0
  31. package/dist/{components → ui}/collection_editor/import/CollectionEditorImportDataPreview.d.ts +1 -1
  32. package/dist/ui/collection_editor/import/CollectionEditorImportMapping.d.ts +14 -0
  33. package/dist/{components → ui}/collection_editor/import/clean_import_data.d.ts +1 -1
  34. package/dist/{components → ui}/collection_editor/properties/BlockPropertyField.d.ts +4 -1
  35. package/dist/{components → ui}/collection_editor/properties/CommonPropertyFields.d.ts +1 -1
  36. package/dist/{components → ui}/collection_editor/properties/MapPropertyField.d.ts +4 -1
  37. package/dist/ui/collection_editor/properties/MarkdownPropertyField.d.ts +4 -0
  38. package/dist/{components → ui}/collection_editor/properties/RepeatPropertyField.d.ts +4 -1
  39. package/dist/{components → ui}/collection_editor/properties/StringPropertyField.d.ts +1 -1
  40. package/dist/ui/collection_editor/properties/UrlPropertyField.d.ts +4 -0
  41. package/dist/ui/collection_editor/templates/blog_template.d.ts +2 -0
  42. package/dist/ui/collection_editor/templates/pages_template.d.ts +2 -0
  43. package/dist/ui/collection_editor/templates/products_template.d.ts +2 -0
  44. package/dist/ui/collection_editor/templates/users_template.d.ts +2 -0
  45. package/dist/{components → ui}/collection_editor/util.d.ts +1 -0
  46. package/dist/ui/collection_editor/utils/strings.d.ts +1 -0
  47. package/dist/ui/collection_editor/utils/supported_fields.d.ts +3 -0
  48. package/dist/ui/collection_editor/utils/update_property_for_widget.d.ts +2 -0
  49. package/dist/useCollectionEditorPlugin.d.ts +17 -6
  50. package/dist/utils/collections.d.ts +6 -0
  51. package/dist/utils/entities.d.ts +3 -4
  52. package/package.json +35 -37
  53. package/src/ConfigControllerProvider.tsx +350 -0
  54. package/src/index.ts +36 -0
  55. package/src/types/collection_editor_controller.tsx +53 -0
  56. package/src/types/collection_inference.ts +3 -0
  57. package/src/types/config_controller.tsx +60 -0
  58. package/src/types/config_permissions.ts +20 -0
  59. package/src/types/persisted_collection.ts +9 -0
  60. package/src/ui/CollectionViewHeaderAction.tsx +48 -0
  61. package/src/ui/EditorCollectionAction.tsx +56 -0
  62. package/src/ui/EditorCollectionActionStart.tsx +88 -0
  63. package/src/ui/HomePageEditorCollectionAction.tsx +89 -0
  64. package/src/ui/MissingReferenceWidget.tsx +37 -0
  65. package/src/ui/NewCollectionButton.tsx +18 -0
  66. package/src/ui/NewCollectionCard.tsx +48 -0
  67. package/src/ui/PropertyAddColumnComponent.tsx +47 -0
  68. package/src/ui/collection_editor/CollectionDetailsForm.tsx +426 -0
  69. package/src/ui/collection_editor/CollectionEditorDialog.tsx +826 -0
  70. package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +214 -0
  71. package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +513 -0
  72. package/src/ui/collection_editor/CollectionYupValidation.tsx +7 -0
  73. package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +37 -0
  74. package/src/ui/collection_editor/EnumForm.tsx +357 -0
  75. package/src/ui/collection_editor/GetCodeDialog.tsx +122 -0
  76. package/src/ui/collection_editor/PropertyEditView.tsx +789 -0
  77. package/src/ui/collection_editor/PropertyFieldPreview.tsx +204 -0
  78. package/src/ui/collection_editor/PropertyTree.tsx +254 -0
  79. package/src/ui/collection_editor/SubcollectionsEditTab.tsx +269 -0
  80. package/src/ui/collection_editor/SwitchControl.tsx +39 -0
  81. package/src/ui/collection_editor/UnsavedChangesDialog.tsx +47 -0
  82. package/src/ui/collection_editor/import/CollectionEditorImportDataPreview.tsx +53 -0
  83. package/src/ui/collection_editor/import/CollectionEditorImportMapping.tsx +299 -0
  84. package/src/ui/collection_editor/import/clean_import_data.ts +53 -0
  85. package/src/ui/collection_editor/properties/BlockPropertyField.tsx +144 -0
  86. package/src/ui/collection_editor/properties/BooleanPropertyField.tsx +40 -0
  87. package/src/ui/collection_editor/properties/CommonPropertyFields.tsx +110 -0
  88. package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +89 -0
  89. package/src/ui/collection_editor/properties/EnumPropertyField.tsx +114 -0
  90. package/src/ui/collection_editor/properties/KeyValuePropertyField.tsx +20 -0
  91. package/src/ui/collection_editor/properties/MapPropertyField.tsx +150 -0
  92. package/src/ui/collection_editor/properties/MarkdownPropertyField.tsx +139 -0
  93. package/src/ui/collection_editor/properties/NumberPropertyField.tsx +38 -0
  94. package/src/ui/collection_editor/properties/ReferencePropertyField.tsx +160 -0
  95. package/src/ui/collection_editor/properties/RepeatPropertyField.tsx +108 -0
  96. package/src/ui/collection_editor/properties/StoragePropertyField.tsx +215 -0
  97. package/src/ui/collection_editor/properties/StringPropertyField.tsx +70 -0
  98. package/src/ui/collection_editor/properties/UrlPropertyField.tsx +89 -0
  99. package/src/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.tsx +45 -0
  100. package/src/ui/collection_editor/properties/validation/ArrayPropertyValidation.tsx +50 -0
  101. package/src/ui/collection_editor/properties/validation/GeneralPropertyValidation.tsx +61 -0
  102. package/src/ui/collection_editor/properties/validation/NumberPropertyValidation.tsx +115 -0
  103. package/src/ui/collection_editor/properties/validation/StringPropertyValidation.tsx +150 -0
  104. package/src/ui/collection_editor/properties/validation/ValidationPanel.tsx +28 -0
  105. package/src/ui/collection_editor/templates/blog_template.ts +115 -0
  106. package/src/ui/collection_editor/templates/pages_template.ts +183 -0
  107. package/src/ui/collection_editor/templates/products_template.ts +88 -0
  108. package/src/ui/collection_editor/templates/users_template.ts +42 -0
  109. package/src/ui/collection_editor/util.ts +28 -0
  110. package/src/ui/collection_editor/utils/strings.ts +9 -0
  111. package/src/ui/collection_editor/utils/supported_fields.tsx +29 -0
  112. package/src/ui/collection_editor/utils/update_property_for_widget.ts +271 -0
  113. package/src/ui/collection_editor/utils/useTraceUpdate.tsx +23 -0
  114. package/src/useCollectionEditorController.tsx +9 -0
  115. package/src/useCollectionEditorPlugin.tsx +164 -0
  116. package/src/useCollectionsConfigController.tsx +9 -0
  117. package/src/utils/arrays.ts +3 -0
  118. package/src/utils/collections.ts +30 -0
  119. package/src/utils/entities.ts +38 -0
  120. package/src/vite-env.d.ts +1 -0
  121. package/dist/components/collection_editor/PropertySelectItem.d.ts +0 -8
  122. package/dist/components/collection_editor/SelectIcons.d.ts +0 -6
  123. package/dist/components/collection_editor/import/CollectionEditorImportMapping.d.ts +0 -4
  124. package/dist/components/collection_editor/properties/FieldHelperView.d.ts +0 -4
  125. package/dist/components/collection_editor/templates/blog_template.d.ts +0 -10
  126. package/dist/components/collection_editor/templates/products_template.d.ts +0 -12
  127. package/dist/components/collection_editor/templates/users_template.d.ts +0 -7
  128. package/dist/components/collection_editor/utils/supported_fields.d.ts +0 -3
  129. package/dist/components/collection_editor/utils/update_property_for_widget.d.ts +0 -3
  130. package/dist/types/editable_properties.d.ts +0 -10
  131. package/dist/utils/icons.d.ts +0 -2
  132. package/dist/utils/synonyms.d.ts +0 -1951
  133. /package/dist/{components → ui}/HomePageEditorCollectionAction.d.ts +0 -0
  134. /package/dist/{components → ui}/NewCollectionCard.d.ts +0 -0
  135. /package/dist/{components → ui}/collection_editor/UnsavedChangesDialog.d.ts +0 -0
  136. /package/dist/{components → ui}/collection_editor/properties/BooleanPropertyField.d.ts +0 -0
  137. /package/dist/{components → ui}/collection_editor/properties/DateTimePropertyField.d.ts +0 -0
  138. /package/dist/{components → ui}/collection_editor/properties/EnumPropertyField.d.ts +0 -0
  139. /package/dist/{components → ui}/collection_editor/properties/KeyValuePropertyField.d.ts +0 -0
  140. /package/dist/{components → ui}/collection_editor/properties/NumberPropertyField.d.ts +0 -0
  141. /package/dist/{components → ui}/collection_editor/properties/ReferencePropertyField.d.ts +0 -0
  142. /package/dist/{components → ui}/collection_editor/properties/StoragePropertyField.d.ts +0 -0
  143. /package/dist/{components → ui}/collection_editor/properties/advanced/AdvancedPropertyValidation.d.ts +0 -0
  144. /package/dist/{components → ui}/collection_editor/properties/validation/ArrayPropertyValidation.d.ts +0 -0
  145. /package/dist/{components → ui}/collection_editor/properties/validation/GeneralPropertyValidation.d.ts +0 -0
  146. /package/dist/{components → ui}/collection_editor/properties/validation/NumberPropertyValidation.d.ts +0 -0
  147. /package/dist/{components → ui}/collection_editor/properties/validation/StringPropertyValidation.d.ts +0 -0
  148. /package/dist/{components → ui}/collection_editor/properties/validation/ValidationPanel.d.ts +0 -0
  149. /package/dist/{components → ui}/collection_editor/utils/useTraceUpdate.d.ts +0 -0
@@ -0,0 +1,357 @@
1
+ import React, { useEffect } from "react";
2
+ import equal from "react-fast-compare"
3
+
4
+ import { ArrayContainer, EnumValueConfig, EnumValues, FieldCaption, } from "@firecms/core";
5
+ import {
6
+ AutoAwesomeIcon,
7
+ Badge,
8
+ Button,
9
+ CircularProgress,
10
+ DebouncedTextField,
11
+ Dialog,
12
+ DialogActions,
13
+ DialogContent,
14
+ IconButton,
15
+ ListIcon,
16
+ Paper,
17
+ SettingsIcon,
18
+ Typography
19
+ } from "@firecms/ui";
20
+ import { extractEnumFromValues } from "@firecms/schema_inference";
21
+ import { Field, Formex, getIn, useCreateFormex, useFormex } from "@firecms/formex";
22
+
23
+ type EnumFormProps = {
24
+ enumValues: EnumValueConfig[];
25
+ onValuesChanged?: (enumValues: EnumValueConfig[]) => void;
26
+ onError?: (error: boolean) => void;
27
+ updateIds: boolean;
28
+ disabled: boolean;
29
+ allowDataInference?: boolean;
30
+ getData?: () => Promise<string[]>;
31
+ };
32
+
33
+ export function EnumForm({
34
+ enumValues,
35
+ onValuesChanged,
36
+ onError,
37
+ updateIds,
38
+ disabled,
39
+ allowDataInference,
40
+ getData
41
+ }: EnumFormProps) {
42
+
43
+ const formex = useCreateFormex<{
44
+ enumValues: EnumValueConfig[]
45
+ }>({
46
+ initialValues: { enumValues },
47
+ validateOnChange: true,
48
+ validation: (values) => {
49
+ const errors: any = {};
50
+ if (values.enumValues) {
51
+ values.enumValues.forEach((enumValue, index) => {
52
+ if (!enumValue?.label) {
53
+ errors.enumValues = errors.enumValues ?? [];
54
+ errors.enumValues[index] = errors.enumValues[index] ?? {};
55
+ errors.enumValues[index].label = "You must specify a label for this enum value entry";
56
+ }
57
+ if (!enumValue?.id) {
58
+ errors.enumValues = errors.enumValues ?? [];
59
+ errors.enumValues[index] = errors.enumValues[index] ?? {};
60
+ errors.enumValues[index].id = "You must specify an ID for this enum value entry";
61
+ }
62
+ });
63
+ }
64
+ const hasError = Boolean(errors?.enumValues && Object.keys(errors?.enumValues).length > 0);
65
+ onError?.(hasError);
66
+ return errors;
67
+ }
68
+ });
69
+
70
+ const { values, errors } = formex;
71
+
72
+ useEffect(() => {
73
+ if (onValuesChanged) {
74
+ onValuesChanged(values.enumValues);
75
+ }
76
+ }, [values.enumValues]);
77
+
78
+ return <Formex value={formex}>
79
+ <EnumFormFields enumValuesPath={"enumValues"}
80
+ values={values}
81
+ errors={errors}
82
+ shouldUpdateId={updateIds}
83
+ disabled={disabled}
84
+ allowDataInference={allowDataInference}
85
+ getData={getData}/>
86
+ </Formex>
87
+
88
+ }
89
+
90
+ type EnumFormFieldsProps = {
91
+ values: {
92
+ enumValues: EnumValueConfig[]
93
+ };
94
+ errors: any;
95
+ enumValuesPath: string;
96
+ shouldUpdateId: boolean;
97
+ disabled: boolean;
98
+ getData?: () => Promise<string[]>;
99
+ allowDataInference?: boolean;
100
+ };
101
+
102
+ // const EnumFormFields = React.memo(
103
+ function EnumFormFields({
104
+ values,
105
+ errors,
106
+ disabled,
107
+ enumValuesPath,
108
+ shouldUpdateId,
109
+ allowDataInference,
110
+ getData,
111
+ }: EnumFormFieldsProps) {
112
+
113
+ const {
114
+ setFieldValue
115
+ } = useFormex();
116
+
117
+ const [lastInternalIdAdded, setLastInternalIdAdded] = React.useState<number | undefined>();
118
+ const [editDialogIndex, setEditDialogIndex] = React.useState<number | undefined>();
119
+ const [inferring, setInferring] = React.useState(false);
120
+
121
+ const inferredValuesRef = React.useRef(new Set());
122
+ const inferredValues = inferredValuesRef.current;
123
+
124
+ const buildEntry = (index: number, internalId: number) => {
125
+ const justAdded = lastInternalIdAdded === internalId;
126
+ const entryError = errors?.enumValues && errors?.enumValues[index];
127
+ return <EnumEntry index={index}
128
+ disabled={disabled}
129
+ enumValuesPath={enumValuesPath}
130
+ autoFocus={justAdded}
131
+ entryError={entryError}
132
+ shouldUpdateId={shouldUpdateId || justAdded}
133
+ onDialogOpen={() => setEditDialogIndex(index)}
134
+ inferredEntry={inferredValues.has(values.enumValues[index]?.id as string)}
135
+ key={`${internalId}`}/>;
136
+ };
137
+
138
+ const inferValues = async () => {
139
+ if (!getData)
140
+ return;
141
+ setInferring(true);
142
+ getData?.().then((data) => {
143
+ if (!data)
144
+ return;
145
+
146
+ const flatData = data.flat();
147
+
148
+ const fieldData = Array.from(new Set(flatData));
149
+
150
+ const currentEnumValues = values.enumValues;
151
+ const foundEnumValues = extractEnumFromValues(fieldData);
152
+
153
+ // add only new enum values
154
+ const newEnumValues = foundEnumValues.filter((enumValue) => {
155
+ return !currentEnumValues?.some((v: any) => v.id === enumValue.id);
156
+ });
157
+
158
+ newEnumValues.forEach((enumValue) => {
159
+ inferredValues.add(enumValue.id);
160
+ });
161
+ setFieldValue(enumValuesPath, [...newEnumValues, ...currentEnumValues], true);
162
+ }).catch(e => {
163
+ console.error(e);
164
+ })
165
+ .finally(() => setInferring(false));
166
+ }
167
+
168
+ return (
169
+ <div className={"col-span-12"}>
170
+ <div className="ml-3.5 flex flex-row items-center">
171
+ <ListIcon/>
172
+ <Typography variant={"subtitle2"}
173
+ className="ml-2 grow">
174
+ Values
175
+ </Typography>
176
+ {allowDataInference &&
177
+ <Button loading={inferring}
178
+ disabled={disabled || inferring}
179
+ variant={"text"}
180
+ size={"small"}
181
+ onClick={inferValues}>
182
+ {inferring ? <CircularProgress size={"small"}/> : <AutoAwesomeIcon/>}
183
+ Infer values from data
184
+ </Button>}
185
+ </div>
186
+
187
+ <Paper className="p-4 m-1">
188
+
189
+ <ArrayContainer droppableId={enumValuesPath}
190
+ addLabel={"Add enum value"}
191
+ value={values.enumValues}
192
+ disabled={disabled}
193
+ size={"small"}
194
+ buildEntry={buildEntry}
195
+ onInternalIdAdded={setLastInternalIdAdded}
196
+ includeAddButton={true}
197
+ onValueChange={(value) => setFieldValue(enumValuesPath, value)}
198
+ newDefaultEntry={{ id: "", label: "" }}/>
199
+
200
+ <EnumEntryDialog index={editDialogIndex}
201
+ open={editDialogIndex !== undefined}
202
+ enumValuesPath={enumValuesPath}
203
+ onClose={() => setEditDialogIndex(undefined)}/>
204
+ </Paper>
205
+ </div>
206
+ );
207
+ }
208
+
209
+ type EnumEntryProps = {
210
+ index: number,
211
+ enumValuesPath: string,
212
+ shouldUpdateId: boolean,
213
+ autoFocus: boolean,
214
+ onDialogOpen: () => void;
215
+ disabled: boolean;
216
+ inferredEntry?: boolean;
217
+ entryError?: { label?: string, id?: string }
218
+ };
219
+
220
+ const EnumEntry = React.memo(
221
+ function EnumEntryInternal({
222
+ index,
223
+ shouldUpdateId: updateId,
224
+ enumValuesPath,
225
+ autoFocus,
226
+ onDialogOpen,
227
+ disabled,
228
+ inferredEntry,
229
+ entryError
230
+ }: EnumEntryProps) {
231
+
232
+ const {
233
+ values,
234
+ handleChange,
235
+ errors,
236
+ setFieldValue,
237
+ touched
238
+ } = useFormex<EnumValues>();
239
+
240
+ const shouldUpdateIdRef = React.useRef(!getIn(values, `${enumValuesPath}[${index}].id`));
241
+ const shouldUpdateId = updateId || shouldUpdateIdRef.current;
242
+
243
+ const idValue = getIn(values, `${enumValuesPath}[${index}].id`);
244
+ const labelValue = getIn(values, `${enumValuesPath}[${index}].label`);
245
+
246
+ const currentLabelRef = React.useRef(labelValue);
247
+
248
+ React.useEffect(() => {
249
+ if ((currentLabelRef.current === idValue || !idValue) && shouldUpdateId) {
250
+ setFieldValue(`${enumValuesPath}[${index}].id`, labelValue);
251
+ }
252
+ currentLabelRef.current = labelValue;
253
+ }, [labelValue]);
254
+
255
+ return (
256
+ <>
257
+ <div className={"flex w-full align-center justify-center"}>
258
+ <Field name={`${enumValuesPath}[${index}].label`}
259
+ as={DebouncedTextField}
260
+ className={"flex-grow"}
261
+ required
262
+ disabled={disabled}
263
+ size="small"
264
+ autoFocus={autoFocus}
265
+ autoComplete="off"
266
+ endAdornment={inferredEntry && <AutoAwesomeIcon size={"small"}/>}
267
+ error={Boolean(entryError?.label)}/>
268
+
269
+ {!disabled &&
270
+ <Badge color={"error"} invisible={!entryError?.id}>
271
+ <IconButton
272
+ size="small"
273
+ aria-label="edit"
274
+ className={"m-1"}
275
+ onClick={() => onDialogOpen()}>
276
+ <SettingsIcon size={"small"}/>
277
+ </IconButton>
278
+ </Badge>}
279
+
280
+ </div>
281
+
282
+ {entryError?.label && <Typography variant={"caption"}
283
+ className={"ml-3.5 text-red-500 dark:text-red-500"}>
284
+ {entryError?.label}
285
+ </Typography>}
286
+
287
+ {entryError?.id && <Typography variant={"caption"}
288
+ className={"ml-3.5 text-red-500 dark:text-red-500"}>
289
+ {entryError?.id}
290
+ </Typography>}
291
+
292
+ </>);
293
+ },
294
+ function areEqual(prevProps: EnumEntryProps, nextProps: EnumEntryProps) {
295
+ return prevProps.index === nextProps.index &&
296
+ prevProps.enumValuesPath === nextProps.enumValuesPath &&
297
+ prevProps.shouldUpdateId === nextProps.shouldUpdateId &&
298
+ prevProps.inferredEntry === nextProps.inferredEntry &&
299
+ equal(prevProps.entryError, nextProps.entryError) &&
300
+ prevProps.autoFocus === nextProps.autoFocus;
301
+ }
302
+ );
303
+
304
+ function EnumEntryDialog({
305
+ index,
306
+ open,
307
+ onClose,
308
+ enumValuesPath
309
+ }: {
310
+ index?: number;
311
+ open: boolean;
312
+ enumValuesPath: string;
313
+ onClose: () => void;
314
+ }) {
315
+
316
+ const {
317
+ errors,
318
+ } = useFormex<EnumValues>();
319
+
320
+ const idError = index !== undefined ? getIn(errors, `${enumValuesPath}[${index}].id`) : undefined;
321
+ return <Dialog
322
+ maxWidth="md"
323
+ aria-labelledby="enum-edit-dialog"
324
+ open={open}
325
+ onOpenChange={(open) => !open ? onClose() : undefined}
326
+ >
327
+
328
+ <DialogContent>
329
+ {index !== undefined &&
330
+ <div>
331
+ <Field name={`${enumValuesPath}[${index}].id`}
332
+ as={DebouncedTextField}
333
+ required
334
+ label={"ID"}
335
+ size="small"
336
+ autoComplete="off"
337
+ error={Boolean(idError)}/>
338
+
339
+ <FieldCaption error={Boolean(idError)}>
340
+ {idError ?? "Value saved in the data source"}
341
+ </FieldCaption>
342
+ </div>}
343
+ </DialogContent>
344
+
345
+ <DialogActions>
346
+ <Button
347
+ autoFocus
348
+ variant="outlined"
349
+ onClick={onClose}
350
+ color="primary">
351
+ Ok
352
+ </Button>
353
+ </DialogActions>
354
+
355
+ </Dialog>
356
+ }
357
+
@@ -0,0 +1,122 @@
1
+ import { EntityCollection, useSnackbarController } from "@firecms/core";
2
+ import { Button, ContentCopyIcon, Dialog, DialogActions, DialogContent, Typography, } from "@firecms/ui";
3
+ import React from "react";
4
+ import JSON5 from "json5";
5
+ import { Highlight, themes } from "prism-react-renderer"
6
+ import { camelCase } from "./utils/strings";
7
+
8
+ export function GetCodeDialog({
9
+ collection,
10
+ onOpenChange,
11
+ open
12
+ }: { onOpenChange: (open: boolean) => void, collection: any, open: any }) {
13
+
14
+ const snackbarController = useSnackbarController();
15
+
16
+ const code = collection
17
+ ? "import { EntityCollection } from \"@firecms/core\";\n\nconst " + (collection?.name ? camelCase(collection.name) : "my") + "Collection:EntityCollection = " + JSON5.stringify(collectionToCode(collection), null, "\t")
18
+ : "No collection selected";
19
+ return <Dialog open={open}
20
+ onOpenChange={onOpenChange}
21
+ maxWidth={"4xl"}>
22
+ <DialogContent>
23
+ <Typography variant={"h6"} className={"my-4"}>
24
+ Code for {collection.name}
25
+ </Typography>
26
+ <Typography variant={"body2"} className={"my-4 mb-8"}>
27
+ If you want to customise the collection in code, you can add this collection code to your CMS
28
+ app configuration.
29
+ More info in the <a
30
+ rel="noopener noreferrer"
31
+ href={"https://firecms.co/docs/customization_quickstart"}>docs</a>.
32
+ </Typography>
33
+ <Highlight
34
+ theme={themes.vsDark}
35
+ code={code}
36
+ language="typescript"
37
+ >
38
+ {({
39
+ className,
40
+ style,
41
+ tokens,
42
+ getLineProps,
43
+ getTokenProps
44
+ }) => (
45
+ <pre style={style} className={"p-4 rounded text-sm"}>
46
+ {tokens.map((line, i) => (
47
+ <div key={i} {...getLineProps({ line })}>
48
+ {line.map((token, key) => (
49
+ <span key={key} {...getTokenProps({ token })} />
50
+ ))}
51
+ </div>
52
+ ))}
53
+ </pre>
54
+ )}
55
+ </Highlight>
56
+
57
+ </DialogContent>
58
+ <DialogActions>
59
+ <Button
60
+ variant={"text"}
61
+ size={"small"}
62
+ onClick={(e) => {
63
+ e.stopPropagation();
64
+ e.preventDefault();
65
+ snackbarController.open({
66
+ type: "success",
67
+ message: `Copied`
68
+ })
69
+ return navigator.clipboard.writeText(code);
70
+ }}>
71
+ <ContentCopyIcon size={"small"}/>
72
+ Copy to clipboard
73
+ </Button>
74
+ <Button onClick={() => onOpenChange(false)}>Close</Button>
75
+ </DialogActions>
76
+ </Dialog>;
77
+ }
78
+
79
+ function collectionToCode(collection: EntityCollection): object {
80
+
81
+ const propertyCleanup = (property: any) => {
82
+
83
+ const updatedProperty = {
84
+ ...property
85
+ };
86
+
87
+ delete updatedProperty.fromBuilder;
88
+ delete updatedProperty.resolved;
89
+ delete updatedProperty.propertiesOrder;
90
+ delete updatedProperty.editable;
91
+
92
+ if (updatedProperty.type === "map") {
93
+ return {
94
+ ...updatedProperty,
95
+ properties: updatedProperty.properties.map(propertyCleanup)
96
+ }
97
+ }
98
+ return updatedProperty;
99
+ }
100
+
101
+ return {
102
+ id: collection.id,
103
+ name: collection.name,
104
+ singularName: collection.singularName,
105
+ path: collection.path,
106
+ description: collection.description,
107
+ editable: true,
108
+ collectionGroup: collection.collectionGroup,
109
+ icon: collection.icon,
110
+ group: collection.group,
111
+ customId: collection.customId,
112
+ initialFilter: collection.initialFilter,
113
+ initialSort: collection.initialSort,
114
+ properties: Object.entries(collection.properties ?? {})
115
+ .map(([key, value]) => ({
116
+ [key]: propertyCleanup(value)
117
+ }))
118
+ .reduce((a, b) => ({ ...a, ...b }), {}),
119
+ subcollections: (collection.subcollections ?? []).map(collectionToCode)
120
+ }
121
+
122
+ }