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