@firecms/collection_editor 3.0.0-3.0.0-beta.4.pre.1.0

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/LICENSE +21 -0
  2. package/README.md +1 -0
  3. package/dist/ConfigControllerProvider.d.ts +37 -0
  4. package/dist/index.d.ts +11 -0
  5. package/dist/index.es.js +5454 -0
  6. package/dist/index.es.js.map +1 -0
  7. package/dist/index.umd.js +4 -0
  8. package/dist/index.umd.js.map +1 -0
  9. package/dist/types/collection_editor_controller.d.ts +36 -0
  10. package/dist/types/collection_inference.d.ts +2 -0
  11. package/dist/types/config_controller.d.ts +51 -0
  12. package/dist/types/config_permissions.d.ts +19 -0
  13. package/dist/types/persisted_collection.d.ts +6 -0
  14. package/dist/ui/CollectionViewHeaderAction.d.ts +10 -0
  15. package/dist/ui/EditorCollectionAction.d.ts +2 -0
  16. package/dist/ui/HomePageEditorCollectionAction.d.ts +2 -0
  17. package/dist/ui/MissingReferenceWidget.d.ts +3 -0
  18. package/dist/ui/NewCollectionButton.d.ts +1 -0
  19. package/dist/ui/NewCollectionCard.d.ts +2 -0
  20. package/dist/ui/PropertyAddColumnComponent.d.ts +6 -0
  21. package/dist/ui/RootCollectionSuggestions.d.ts +3 -0
  22. package/dist/ui/collection_editor/CollectionDetailsForm.d.ts +10 -0
  23. package/dist/ui/collection_editor/CollectionEditorDialog.d.ts +36 -0
  24. package/dist/ui/collection_editor/CollectionEditorWelcomeView.d.ts +15 -0
  25. package/dist/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +19 -0
  26. package/dist/ui/collection_editor/CollectionYupValidation.d.ts +14 -0
  27. package/dist/ui/collection_editor/EntityCustomViewsSelectDialog.d.ts +4 -0
  28. package/dist/ui/collection_editor/EnumForm.d.ts +12 -0
  29. package/dist/ui/collection_editor/GetCodeDialog.d.ts +5 -0
  30. package/dist/ui/collection_editor/PropertyEditView.d.ts +40 -0
  31. package/dist/ui/collection_editor/PropertyFieldPreview.d.ts +15 -0
  32. package/dist/ui/collection_editor/PropertySelectItem.d.ts +8 -0
  33. package/dist/ui/collection_editor/PropertyTree.d.ts +33 -0
  34. package/dist/ui/collection_editor/SubcollectionsEditTab.d.ts +12 -0
  35. package/dist/ui/collection_editor/SwitchControl.d.ts +8 -0
  36. package/dist/ui/collection_editor/UnsavedChangesDialog.d.ts +9 -0
  37. package/dist/ui/collection_editor/import/CollectionEditorImportDataPreview.d.ts +7 -0
  38. package/dist/ui/collection_editor/import/CollectionEditorImportMapping.d.ts +7 -0
  39. package/dist/ui/collection_editor/import/clean_import_data.d.ts +7 -0
  40. package/dist/ui/collection_editor/properties/BlockPropertyField.d.ts +8 -0
  41. package/dist/ui/collection_editor/properties/BooleanPropertyField.d.ts +3 -0
  42. package/dist/ui/collection_editor/properties/CommonPropertyFields.d.ts +10 -0
  43. package/dist/ui/collection_editor/properties/DateTimePropertyField.d.ts +3 -0
  44. package/dist/ui/collection_editor/properties/EnumPropertyField.d.ts +8 -0
  45. package/dist/ui/collection_editor/properties/KeyValuePropertyField.d.ts +3 -0
  46. package/dist/ui/collection_editor/properties/MapPropertyField.d.ts +8 -0
  47. package/dist/ui/collection_editor/properties/NumberPropertyField.d.ts +3 -0
  48. package/dist/ui/collection_editor/properties/ReferencePropertyField.d.ts +13 -0
  49. package/dist/ui/collection_editor/properties/RepeatPropertyField.d.ts +10 -0
  50. package/dist/ui/collection_editor/properties/StoragePropertyField.d.ts +5 -0
  51. package/dist/ui/collection_editor/properties/StringPropertyField.d.ts +5 -0
  52. package/dist/ui/collection_editor/properties/UrlPropertyField.d.ts +4 -0
  53. package/dist/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.d.ts +3 -0
  54. package/dist/ui/collection_editor/properties/validation/ArrayPropertyValidation.d.ts +5 -0
  55. package/dist/ui/collection_editor/properties/validation/GeneralPropertyValidation.d.ts +4 -0
  56. package/dist/ui/collection_editor/properties/validation/NumberPropertyValidation.d.ts +3 -0
  57. package/dist/ui/collection_editor/properties/validation/StringPropertyValidation.d.ts +11 -0
  58. package/dist/ui/collection_editor/properties/validation/ValidationPanel.d.ts +2 -0
  59. package/dist/ui/collection_editor/templates/blog_template.d.ts +2 -0
  60. package/dist/ui/collection_editor/templates/pages_template.d.ts +2 -0
  61. package/dist/ui/collection_editor/templates/products_template.d.ts +2 -0
  62. package/dist/ui/collection_editor/templates/users_template.d.ts +2 -0
  63. package/dist/ui/collection_editor/util.d.ts +5 -0
  64. package/dist/ui/collection_editor/utils/strings.d.ts +1 -0
  65. package/dist/ui/collection_editor/utils/supported_fields.d.ts +3 -0
  66. package/dist/ui/collection_editor/utils/update_property_for_widget.d.ts +2 -0
  67. package/dist/ui/collection_editor/utils/useTraceUpdate.d.ts +1 -0
  68. package/dist/useCollectionEditorController.d.ts +6 -0
  69. package/dist/useCollectionEditorPlugin.d.ts +49 -0
  70. package/dist/useCollectionsConfigController.d.ts +6 -0
  71. package/dist/utils/arrays.d.ts +1 -0
  72. package/dist/utils/entities.d.ts +3 -0
  73. package/package.json +85 -0
  74. package/src/ConfigControllerProvider.tsx +338 -0
  75. package/src/index.ts +35 -0
  76. package/src/types/collection_editor_controller.tsx +43 -0
  77. package/src/types/collection_inference.ts +3 -0
  78. package/src/types/config_controller.tsx +60 -0
  79. package/src/types/config_permissions.ts +20 -0
  80. package/src/types/persisted_collection.ts +9 -0
  81. package/src/ui/CollectionViewHeaderAction.tsx +43 -0
  82. package/src/ui/EditorCollectionAction.tsx +109 -0
  83. package/src/ui/HomePageEditorCollectionAction.tsx +84 -0
  84. package/src/ui/MissingReferenceWidget.tsx +37 -0
  85. package/src/ui/NewCollectionButton.tsx +16 -0
  86. package/src/ui/NewCollectionCard.tsx +48 -0
  87. package/src/ui/PropertyAddColumnComponent.tsx +42 -0
  88. package/src/ui/RootCollectionSuggestions.tsx +63 -0
  89. package/src/ui/collection_editor/CollectionDetailsForm.tsx +365 -0
  90. package/src/ui/collection_editor/CollectionEditorDialog.tsx +801 -0
  91. package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +213 -0
  92. package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +506 -0
  93. package/src/ui/collection_editor/CollectionYupValidation.tsx +7 -0
  94. package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +37 -0
  95. package/src/ui/collection_editor/EnumForm.tsx +357 -0
  96. package/src/ui/collection_editor/GetCodeDialog.tsx +110 -0
  97. package/src/ui/collection_editor/PropertyEditView.tsx +615 -0
  98. package/src/ui/collection_editor/PropertyFieldPreview.tsx +207 -0
  99. package/src/ui/collection_editor/PropertySelectItem.tsx +32 -0
  100. package/src/ui/collection_editor/PropertyTree.tsx +252 -0
  101. package/src/ui/collection_editor/SubcollectionsEditTab.tsx +262 -0
  102. package/src/ui/collection_editor/SwitchControl.tsx +39 -0
  103. package/src/ui/collection_editor/UnsavedChangesDialog.tsx +47 -0
  104. package/src/ui/collection_editor/import/CollectionEditorImportDataPreview.tsx +37 -0
  105. package/src/ui/collection_editor/import/CollectionEditorImportMapping.tsx +268 -0
  106. package/src/ui/collection_editor/import/clean_import_data.ts +53 -0
  107. package/src/ui/collection_editor/properties/BlockPropertyField.tsx +138 -0
  108. package/src/ui/collection_editor/properties/BooleanPropertyField.tsx +40 -0
  109. package/src/ui/collection_editor/properties/CommonPropertyFields.tsx +110 -0
  110. package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +86 -0
  111. package/src/ui/collection_editor/properties/EnumPropertyField.tsx +114 -0
  112. package/src/ui/collection_editor/properties/KeyValuePropertyField.tsx +20 -0
  113. package/src/ui/collection_editor/properties/MapPropertyField.tsx +150 -0
  114. package/src/ui/collection_editor/properties/NumberPropertyField.tsx +38 -0
  115. package/src/ui/collection_editor/properties/ReferencePropertyField.tsx +160 -0
  116. package/src/ui/collection_editor/properties/RepeatPropertyField.tsx +109 -0
  117. package/src/ui/collection_editor/properties/StoragePropertyField.tsx +200 -0
  118. package/src/ui/collection_editor/properties/StringPropertyField.tsx +79 -0
  119. package/src/ui/collection_editor/properties/UrlPropertyField.tsx +89 -0
  120. package/src/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.tsx +45 -0
  121. package/src/ui/collection_editor/properties/validation/ArrayPropertyValidation.tsx +50 -0
  122. package/src/ui/collection_editor/properties/validation/GeneralPropertyValidation.tsx +61 -0
  123. package/src/ui/collection_editor/properties/validation/NumberPropertyValidation.tsx +115 -0
  124. package/src/ui/collection_editor/properties/validation/StringPropertyValidation.tsx +150 -0
  125. package/src/ui/collection_editor/properties/validation/ValidationPanel.tsx +28 -0
  126. package/src/ui/collection_editor/templates/blog_template.ts +115 -0
  127. package/src/ui/collection_editor/templates/pages_template.ts +188 -0
  128. package/src/ui/collection_editor/templates/products_template.ts +88 -0
  129. package/src/ui/collection_editor/templates/users_template.ts +42 -0
  130. package/src/ui/collection_editor/util.ts +28 -0
  131. package/src/ui/collection_editor/utils/strings.ts +9 -0
  132. package/src/ui/collection_editor/utils/supported_fields.tsx +29 -0
  133. package/src/ui/collection_editor/utils/update_property_for_widget.ts +271 -0
  134. package/src/ui/collection_editor/utils/useTraceUpdate.tsx +23 -0
  135. package/src/useCollectionEditorController.tsx +9 -0
  136. package/src/useCollectionEditorPlugin.tsx +154 -0
  137. package/src/useCollectionsConfigController.tsx +9 -0
  138. package/src/utils/arrays.ts +3 -0
  139. package/src/utils/entities.ts +38 -0
  140. package/src/vite-env.d.ts +1 -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,110 @@
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({ collection, onOpenChange, open }: { onOpenChange: (open: boolean) => void, collection: any, open: any }) {
9
+
10
+ const snackbarController = useSnackbarController();
11
+
12
+ const code = "import { EntityCollection } from \"firecms\";\n\nconst " + (collection.name ? camelCase(collection.name) : "my") + "Collection:EntityCollection = " + JSON5.stringify(collectionToCode(collection), null, "\t");
13
+ return <Dialog open={open}
14
+ onOpenChange={onOpenChange}
15
+ maxWidth={"4xl"}>
16
+ <DialogContent>
17
+ <Typography variant={"h6"} className={"my-4"}>
18
+ Code for {collection.name}
19
+ </Typography>
20
+ <Typography variant={"body2"} className={"my-4 mb-8"}>
21
+ If you want to customise the collection in code, you can add this collection code to your CMS
22
+ app configuration.
23
+ More info in the <a
24
+ rel="noopener noreferrer"
25
+ href={"https://firecms.co/docs/customization_quickstart"}>docs</a>.
26
+ </Typography>
27
+ <Highlight
28
+ theme={themes.vsDark}
29
+ code={code}
30
+ language="typescript"
31
+ >
32
+ {({ className, style, tokens, getLineProps, getTokenProps }) => (
33
+ <pre style={style} className={"p-4 rounded text-sm"}>
34
+ {tokens.map((line, i) => (
35
+ <div key={i} {...getLineProps({ line })}>
36
+ {line.map((token, key) => (
37
+ <span key={key} {...getTokenProps({ token })} />
38
+ ))}
39
+ </div>
40
+ ))}
41
+ </pre>
42
+ )}
43
+ </Highlight>
44
+
45
+ </DialogContent>
46
+ <DialogActions>
47
+ <Button
48
+ variant={"text"}
49
+ size={"small"}
50
+ onClick={(e) => {
51
+ e.stopPropagation();
52
+ e.preventDefault();
53
+ snackbarController.open({
54
+ type: "success",
55
+ message: `Copied`
56
+ })
57
+ return navigator.clipboard.writeText(code);
58
+ }}>
59
+ <ContentCopyIcon size={"small"}/>
60
+ Copy to clipboard
61
+ </Button>
62
+ <Button onClick={() => onOpenChange(false)}>Close</Button>
63
+ </DialogActions>
64
+ </Dialog>;
65
+ }
66
+
67
+ function collectionToCode(collection: EntityCollection): object {
68
+
69
+ const propertyCleanup = (property: any) => {
70
+
71
+ const updatedProperty = {
72
+ ...property
73
+ };
74
+
75
+ delete updatedProperty.fromBuilder;
76
+ delete updatedProperty.resolved;
77
+ delete updatedProperty.propertiesOrder;
78
+ delete updatedProperty.editable;
79
+
80
+ if (updatedProperty.type === "map") {
81
+ return {
82
+ ...updatedProperty,
83
+ properties: updatedProperty.properties.map(propertyCleanup)
84
+ }
85
+ }
86
+ return updatedProperty;
87
+ }
88
+
89
+ return {
90
+ id: collection.id,
91
+ name: collection.name,
92
+ singularName: collection.singularName,
93
+ path: collection.path,
94
+ description: collection.description,
95
+ editable: true,
96
+ collectionGroup: collection.collectionGroup,
97
+ icon: collection.icon,
98
+ group: collection.group,
99
+ customId: collection.customId,
100
+ initialFilter: collection.initialFilter,
101
+ initialSort: collection.initialSort,
102
+ properties: Object.entries(collection.properties ?? {})
103
+ .map(([key, value]) => ({
104
+ [key]: propertyCleanup(value)
105
+ }))
106
+ .reduce((a, b) => ({ ...a, ...b }), {}),
107
+ subcollections: (collection.subcollections ?? []).map(collectionToCode)
108
+ }
109
+
110
+ }