@firecms/collection_editor 3.0.1 → 3.1.0-canary.7d91b7c

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 (90) hide show
  1. package/dist/ConfigControllerProvider.d.ts +6 -0
  2. package/dist/api/generateCollectionApi.d.ts +71 -0
  3. package/dist/api/index.d.ts +1 -0
  4. package/dist/index.d.ts +5 -1
  5. package/dist/index.es.js +9466 -5588
  6. package/dist/index.es.js.map +1 -1
  7. package/dist/index.umd.js +9461 -5583
  8. package/dist/index.umd.js.map +1 -1
  9. package/dist/types/collection_editor_controller.d.ts +14 -0
  10. package/dist/types/collection_inference.d.ts +8 -2
  11. package/dist/types/config_controller.d.ts +23 -2
  12. package/dist/ui/AddKanbanColumnAction.d.ts +11 -0
  13. package/dist/ui/KanbanSetupAction.d.ts +10 -0
  14. package/dist/ui/collection_editor/AICollectionGeneratorPopover.d.ts +37 -0
  15. package/dist/ui/collection_editor/AIModifiedPathsContext.d.ts +20 -0
  16. package/dist/ui/collection_editor/CollectionDetailsForm.d.ts +2 -3
  17. package/dist/ui/collection_editor/CollectionEditorDialog.d.ts +24 -0
  18. package/dist/ui/collection_editor/CollectionEditorWelcomeView.d.ts +4 -1
  19. package/dist/ui/collection_editor/CollectionJsonImportDialog.d.ts +7 -0
  20. package/dist/ui/collection_editor/CollectionYupValidation.d.ts +9 -13
  21. package/dist/ui/collection_editor/DisplaySettingsForm.d.ts +3 -0
  22. package/dist/ui/collection_editor/EntityActionsEditTab.d.ts +2 -1
  23. package/dist/ui/collection_editor/ExtendSettingsForm.d.ts +14 -0
  24. package/dist/ui/collection_editor/GeneralSettingsForm.d.ts +7 -0
  25. package/dist/ui/collection_editor/KanbanConfigSection.d.ts +4 -0
  26. package/dist/ui/collection_editor/PropertyEditView.d.ts +6 -1
  27. package/dist/ui/collection_editor/PropertyTree.d.ts +2 -1
  28. package/dist/ui/collection_editor/SubcollectionsEditTab.d.ts +2 -1
  29. package/dist/ui/collection_editor/ViewModeSwitch.d.ts +6 -0
  30. package/dist/ui/collection_editor/properties/EnumPropertyField.d.ts +2 -1
  31. package/dist/ui/collection_editor/properties/conditions/ConditionsEditor.d.ts +10 -0
  32. package/dist/ui/collection_editor/properties/conditions/ConditionsPanel.d.ts +2 -0
  33. package/dist/ui/collection_editor/properties/conditions/EnumConditionsEditor.d.ts +6 -0
  34. package/dist/ui/collection_editor/properties/conditions/index.d.ts +6 -0
  35. package/dist/ui/collection_editor/properties/conditions/property_paths.d.ts +19 -0
  36. package/dist/useCollectionEditorPlugin.d.ts +7 -1
  37. package/dist/utils/validateCollectionJson.d.ts +22 -0
  38. package/package.json +15 -15
  39. package/src/ConfigControllerProvider.tsx +82 -47
  40. package/src/api/generateCollectionApi.ts +119 -0
  41. package/src/api/index.ts +1 -0
  42. package/src/index.ts +28 -1
  43. package/src/types/collection_editor_controller.tsx +16 -3
  44. package/src/types/collection_inference.ts +15 -2
  45. package/src/types/config_controller.tsx +27 -2
  46. package/src/ui/AddKanbanColumnAction.tsx +203 -0
  47. package/src/ui/EditorCollectionActionStart.tsx +1 -2
  48. package/src/ui/HomePageEditorCollectionAction.tsx +41 -13
  49. package/src/ui/KanbanSetupAction.tsx +38 -0
  50. package/src/ui/MissingReferenceWidget.tsx +1 -1
  51. package/src/ui/NewCollectionButton.tsx +1 -1
  52. package/src/ui/PropertyAddColumnComponent.tsx +1 -1
  53. package/src/ui/collection_editor/AICollectionGeneratorPopover.tsx +242 -0
  54. package/src/ui/collection_editor/AIModifiedPathsContext.tsx +88 -0
  55. package/src/ui/collection_editor/CollectionDetailsForm.tsx +212 -259
  56. package/src/ui/collection_editor/CollectionEditorDialog.tsx +237 -169
  57. package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +133 -67
  58. package/src/ui/collection_editor/CollectionJsonImportDialog.tsx +171 -0
  59. package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +190 -91
  60. package/src/ui/collection_editor/DisplaySettingsForm.tsx +333 -0
  61. package/src/ui/collection_editor/EntityActionsEditTab.tsx +106 -96
  62. package/src/ui/collection_editor/EntityActionsSelectDialog.tsx +6 -7
  63. package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +1 -3
  64. package/src/ui/collection_editor/EnumForm.tsx +147 -100
  65. package/src/ui/collection_editor/ExtendSettingsForm.tsx +93 -0
  66. package/src/ui/collection_editor/GeneralSettingsForm.tsx +337 -0
  67. package/src/ui/collection_editor/GetCodeDialog.tsx +57 -36
  68. package/src/ui/collection_editor/KanbanConfigSection.tsx +207 -0
  69. package/src/ui/collection_editor/LayoutModeSwitch.tsx +22 -41
  70. package/src/ui/collection_editor/PropertyEditView.tsx +206 -142
  71. package/src/ui/collection_editor/PropertyFieldPreview.tsx +1 -1
  72. package/src/ui/collection_editor/PropertyTree.tsx +130 -58
  73. package/src/ui/collection_editor/SubcollectionsEditTab.tsx +171 -162
  74. package/src/ui/collection_editor/UnsavedChangesDialog.tsx +0 -2
  75. package/src/ui/collection_editor/ViewModeSwitch.tsx +41 -0
  76. package/src/ui/collection_editor/properties/BlockPropertyField.tsx +0 -2
  77. package/src/ui/collection_editor/properties/BooleanPropertyField.tsx +1 -0
  78. package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +117 -35
  79. package/src/ui/collection_editor/properties/EnumPropertyField.tsx +28 -21
  80. package/src/ui/collection_editor/properties/MapPropertyField.tsx +0 -2
  81. package/src/ui/collection_editor/properties/MarkdownPropertyField.tsx +115 -39
  82. package/src/ui/collection_editor/properties/StoragePropertyField.tsx +1 -1
  83. package/src/ui/collection_editor/properties/conditions/ConditionsEditor.tsx +861 -0
  84. package/src/ui/collection_editor/properties/conditions/ConditionsPanel.tsx +28 -0
  85. package/src/ui/collection_editor/properties/conditions/EnumConditionsEditor.tsx +599 -0
  86. package/src/ui/collection_editor/properties/conditions/index.ts +6 -0
  87. package/src/ui/collection_editor/properties/conditions/property_paths.ts +92 -0
  88. package/src/ui/collection_editor/properties/validation/ValidationPanel.tsx +1 -1
  89. package/src/useCollectionEditorPlugin.tsx +32 -17
  90. package/src/utils/validateCollectionJson.ts +380 -0
@@ -0,0 +1,337 @@
1
+ import React, { useState } from "react";
2
+ import {
3
+ EntityCollection,
4
+ FieldCaption,
5
+ IconForView,
6
+ SearchIconsView,
7
+ singular,
8
+ toSnakeCase,
9
+ useAuthController,
10
+ useCustomizationController
11
+ } from "@firecms/core";
12
+ import {
13
+ BooleanSwitchWithLabel,
14
+ Chip,
15
+ cls,
16
+ Container,
17
+ DebouncedTextField,
18
+ Dialog,
19
+ ExpandablePanel,
20
+ HistoryIcon,
21
+ IconButton,
22
+ SearchIcon,
23
+ Select,
24
+ SelectItem,
25
+ TextField,
26
+ Tooltip,
27
+ Typography
28
+ } from "@firecms/ui";
29
+
30
+ import { Field, getIn, useFormex } from "@firecms/formex";
31
+
32
+ export function GeneralSettingsForm({
33
+ isNewCollection,
34
+ existingPaths,
35
+ existingIds,
36
+ parentCollection
37
+ }: {
38
+ isNewCollection: boolean;
39
+ existingPaths?: string[];
40
+ existingIds?: string[];
41
+ parentCollection?: EntityCollection;
42
+ }) {
43
+
44
+ const {
45
+ values,
46
+ setFieldValue,
47
+ handleChange,
48
+ touched,
49
+ errors,
50
+ setFieldTouched,
51
+ submitCount
52
+ } = useFormex<EntityCollection>();
53
+
54
+ const [iconDialogOpen, setIconDialogOpen] = useState(false);
55
+
56
+ const authController = useAuthController();
57
+ const customizationController = useCustomizationController();
58
+
59
+ const updateDatabaseId = (databaseId: string) => {
60
+ setFieldValue("databaseId", databaseId ?? undefined);
61
+ }
62
+
63
+ const updateName = (name: string) => {
64
+ setFieldValue("name", name);
65
+
66
+ const pathTouched = getIn(touched, "path");
67
+ if (!pathTouched && isNewCollection && name) {
68
+ setFieldValue("path", toSnakeCase(name));
69
+ }
70
+
71
+ const idTouched = getIn(touched, "id");
72
+ if (!idTouched && isNewCollection && name) {
73
+ setFieldValue("id", toSnakeCase(name));
74
+ }
75
+
76
+ const singularNameTouched = getIn(touched, "singularName");
77
+ if (!singularNameTouched && isNewCollection && name) {
78
+ setFieldValue("singularName", singular(name));
79
+ }
80
+ };
81
+
82
+ const collectionIcon = <IconForView collectionOrView={values} />;
83
+ const isSubcollection = !!parentCollection;
84
+ const showErrors = submitCount > 0;
85
+
86
+ return (
87
+ <div className={"overflow-auto my-auto"}>
88
+ <Container maxWidth={"4xl"} className={"flex flex-col gap-4 p-8 m-auto"}>
89
+
90
+ <div>
91
+ <div className="flex flex-row gap-2 py-2 pt-3 items-center">
92
+ <Typography variant={!isNewCollection ? "h5" : "h4"} className={"flex-grow"}>
93
+ {isNewCollection ? "New collection" : `${values?.name} collection`}
94
+ </Typography>
95
+ <DefaultDatabaseField databaseId={values.databaseId}
96
+ onDatabaseIdUpdate={updateDatabaseId} />
97
+
98
+ <Tooltip title={"Change icon"}
99
+ asChild={true}>
100
+ <IconButton
101
+ shape={"square"}
102
+ onClick={() => setIconDialogOpen(true)}>
103
+ {collectionIcon}
104
+ </IconButton>
105
+ </Tooltip>
106
+ </div>
107
+
108
+ {parentCollection && <Chip colorScheme={"tealDarker"}>
109
+ <Typography variant={"caption"}>
110
+ This is a subcollection of <b>{parentCollection.name}</b>
111
+ </Typography>
112
+ </Chip>}
113
+
114
+ </div>
115
+
116
+ <div className={"grid grid-cols-12 gap-4"}>
117
+
118
+ {/* Name */}
119
+ <div className={"col-span-12"}>
120
+ <TextField
121
+ value={values.name ?? ""}
122
+ onChange={(e: any) => updateName(e.target.value)}
123
+ label={"Name"}
124
+ autoFocus={true}
125
+ required
126
+ error={showErrors && Boolean(errors.name)} />
127
+ <FieldCaption error={touched.name && Boolean(errors.name)}>
128
+ {touched.name && Boolean(errors.name) ? errors.name : "Name of this collection, usually a plural name (e.g. Products)"}
129
+ </FieldCaption>
130
+ </div>
131
+
132
+ {/* Path */}
133
+ <div className={cls("col-span-12")}>
134
+ <Field name={"path"}
135
+ as={DebouncedTextField}
136
+ label={"Path"}
137
+ required
138
+ error={showErrors && Boolean(errors.path)} />
139
+
140
+ <FieldCaption error={touched.path && Boolean(errors.path)}>
141
+ {touched.path && Boolean(errors.path)
142
+ ? errors.path
143
+ : isSubcollection ? "Relative path to the parent (no need to include the parent path)" : "Path that this collection is stored in, in the database"}
144
+ </FieldCaption>
145
+ </div>
146
+
147
+ {/* Singular Name */}
148
+ <div className={"col-span-12"}>
149
+ <TextField
150
+ error={showErrors && Boolean(errors.singularName)}
151
+ name={"singularName"}
152
+ aria-describedby={"singularName-helper"}
153
+ onChange={(e) => {
154
+ setFieldTouched("singularName", true);
155
+ return handleChange(e);
156
+ }}
157
+ value={values.singularName ?? ""}
158
+ label={"Singular name"} />
159
+ <FieldCaption error={showErrors && Boolean(errors.singularName)}>
160
+ {showErrors && Boolean(errors.singularName) ? errors.singularName : "Optionally define a singular name for your entities"}
161
+ </FieldCaption>
162
+ </div>
163
+
164
+ {/* Description */}
165
+ <div className={"col-span-12"}>
166
+ <TextField
167
+ error={showErrors && Boolean(errors.description)}
168
+ name="description"
169
+ value={values.description ?? ""}
170
+ onChange={handleChange}
171
+ multiline
172
+ minRows={2}
173
+ aria-describedby="description-helper-text"
174
+ label="Description"
175
+ />
176
+ <FieldCaption error={showErrors && Boolean(errors.description)}>
177
+ {showErrors && Boolean(errors.description) ? errors.description : "Description of the collection, you can use markdown"}
178
+ </FieldCaption>
179
+ </div>
180
+
181
+ {/* Collection ID */}
182
+ <div className={"col-span-12"}>
183
+ <Field name={"id"}
184
+ as={DebouncedTextField}
185
+ disabled={!isNewCollection}
186
+ label={"Collection ID"}
187
+ error={showErrors && Boolean(errors.id)} />
188
+ <FieldCaption error={touched.id && Boolean(errors.id)}>
189
+ {touched.id && Boolean(errors.id) ? errors.id : "This ID identifies this collection. Typically the same as the path."}
190
+ </FieldCaption>
191
+ </div>
192
+
193
+ {/* Collection Group */}
194
+ <div className={"col-span-12"}>
195
+ <BooleanSwitchWithLabel
196
+ position={"start"}
197
+ size={"large"}
198
+ label="Collection group"
199
+ onValueChange={(v) => setFieldValue("collectionGroup", v)}
200
+ value={values.collectionGroup ?? false}
201
+ />
202
+ <FieldCaption>
203
+ A collection group consists of all collections with the same path. This allows
204
+ you to query over multiple collections at once.
205
+ </FieldCaption>
206
+ </div>
207
+
208
+ </div>
209
+
210
+ {/* Advanced Settings */}
211
+ <ExpandablePanel
212
+ title={<Typography variant="subtitle2">Advanced settings</Typography>}
213
+ initiallyExpanded={false}
214
+ className="mt-4"
215
+ innerClassName="p-4 flex flex-col gap-4"
216
+ >
217
+ {/* History revisions */}
218
+ <div>
219
+ <BooleanSwitchWithLabel
220
+ position={"start"}
221
+ size={"large"}
222
+ allowIndeterminate={true}
223
+ label={<span className="flex items-center gap-2"><HistoryIcon size={"smallest"} />{values.history === null || values.history === undefined ? "Document history revisions enabled if enabled globally" : (
224
+ values.history ? "Document history revisions ENABLED" : "Document history revisions NOT enabled"
225
+ )}</span>}
226
+ onValueChange={(v) => setFieldValue("history", v)}
227
+ value={values.history === undefined ? null : values.history}
228
+ />
229
+ <FieldCaption>
230
+ When enabled, each document in this collection will have a history of changes.
231
+ This is useful for auditing purposes. The data is stored in a subcollection of the document
232
+ in your database, called <b>__history</b>.
233
+ </FieldCaption>
234
+ </div>
235
+
236
+ {/* Document ID generation */}
237
+ <div>
238
+ <Select
239
+ name="customId"
240
+ label="Document IDs generation"
241
+ position={"item-aligned"}
242
+ size={"large"}
243
+ fullWidth={true}
244
+ disabled={typeof values.customId === "object"}
245
+ onValueChange={(v) => {
246
+ if (v === "code_defined")
247
+ throw new Error("This should not happen");
248
+ if (v === "false") setFieldValue("customId", false);
249
+ else if (v === "true") setFieldValue("customId", true);
250
+ else if (v === "optional") setFieldValue("customId", "optional");
251
+ }}
252
+ value={
253
+ typeof values.customId === "object" ? "code_defined" :
254
+ values.customId === true ? "true" :
255
+ values.customId === "optional" ? "optional" : "false"
256
+ }
257
+ renderValue={(value: any) => {
258
+ if (value === "code_defined")
259
+ return "Code defined";
260
+ else if (value === "true")
261
+ return "Users must define an ID";
262
+ else if (value === "optional")
263
+ return "Users can define an ID, but it is not required";
264
+ else
265
+ return "Document ID is generated automatically";
266
+ }}
267
+ >
268
+ <SelectItem value={"false"}>
269
+ Document ID is generated automatically
270
+ </SelectItem>
271
+ <SelectItem value={"true"}>
272
+ Users must define an ID
273
+ </SelectItem>
274
+ <SelectItem value={"optional"}>
275
+ Users can define an ID, but it is not required
276
+ </SelectItem>
277
+ </Select>
278
+ <FieldCaption>
279
+ Configure how document IDs are generated when creating new entities.
280
+ </FieldCaption>
281
+ </div>
282
+
283
+ {/* Text search */}
284
+ <div>
285
+ <BooleanSwitchWithLabel
286
+ position={"start"}
287
+ size={"large"}
288
+ label={<span className="flex items-center gap-2"><SearchIcon size={"smallest"} />Enable text search for this collection</span>}
289
+ onValueChange={(v) => setFieldValue("textSearchEnabled", v)}
290
+ value={values.textSearchEnabled ?? false}
291
+ />
292
+ <FieldCaption>
293
+ Allow text search for this collection. If you have not specified a text search
294
+ delegate, this will use the built-in local text search. This is not recommended
295
+ for large collections, as it may incur in performance and cost issues.
296
+ </FieldCaption>
297
+ </div>
298
+ </ExpandablePanel>
299
+
300
+ <div style={{ height: "52px" }} />
301
+
302
+ <Dialog
303
+ open={iconDialogOpen}
304
+ onOpenChange={setIconDialogOpen}
305
+ maxWidth={"xl"}
306
+ fullWidth
307
+ >
308
+ <div className={"p-4 overflow-auto min-h-[200px]"}>
309
+ <SearchIconsView selectedIcon={typeof values.icon === "string" ? values.icon : undefined}
310
+ onIconSelected={(icon: string) => {
311
+ setIconDialogOpen(false);
312
+ setFieldValue("icon", icon);
313
+ }} />
314
+ </div>
315
+ </Dialog>
316
+
317
+ </Container>
318
+ </div>
319
+ );
320
+ }
321
+
322
+ function DefaultDatabaseField({
323
+ databaseId,
324
+ onDatabaseIdUpdate
325
+ }: { databaseId?: string, onDatabaseIdUpdate: (databaseId: string) => void }) {
326
+
327
+ return <Tooltip title={"Database ID"}
328
+ side={"top"}
329
+ align={"start"}>
330
+ <TextField size={"small"}
331
+ invisible={true}
332
+ inputClassName={"text-end"}
333
+ value={databaseId ?? ""}
334
+ onChange={(e: any) => onDatabaseIdUpdate(e.target.value)}
335
+ placeholder={"(default)"}></TextField>
336
+ </Tooltip>
337
+ }
@@ -1,56 +1,76 @@
1
1
  import { EntityCollection, isEmptyObject, useSnackbarController } from "@firecms/core";
2
- import { Button, ContentCopyIcon, Dialog, DialogActions, DialogContent, DialogTitle, Typography } from "@firecms/ui";
3
- import React from "react";
2
+ import { Button, ContentCopyIcon, Dialog, DialogActions, DialogContent, DialogTitle, Tab, Tabs, Typography } from "@firecms/ui";
3
+ import React, { useState } from "react";
4
4
  import JSON5 from "json5";
5
5
  import { Highlight, themes } from "prism-react-renderer"
6
6
  import { camelCase } from "./utils/strings";
7
7
  import { clone } from "@firecms/formex";
8
8
 
9
9
  export function GetCodeDialog({
10
- collection,
11
- onOpenChange,
12
- open
13
- }: { onOpenChange: (open: boolean) => void, collection: any, open: any }) {
10
+ collection,
11
+ onOpenChange,
12
+ open
13
+ }: { onOpenChange: (open: boolean) => void, collection: any, open: any }) {
14
14
 
15
15
  const snackbarController = useSnackbarController();
16
+ const [format, setFormat] = useState<"ts" | "json">("json");
16
17
 
17
- const code = collection
18
- ? "import { EntityCollection } from \"@firecms/core\";\n\nconst " + (collection?.name ? camelCase(collection.name) : "my") + "Collection:EntityCollection = " + JSON5.stringify(collectionToCode({ ...collection }), null, "\t")
18
+ const collectionData = collectionToCode({ ...collection });
19
+
20
+ const tsCode = collection
21
+ ? "import { EntityCollection } from \"@firecms/core\";\n\nconst " + (collection?.name ? camelCase(collection.name) : "my") + "Collection:EntityCollection = " + JSON5.stringify(collectionData, null, "\t")
22
+ : "No collection selected";
23
+
24
+ const jsonCode = collection
25
+ ? JSON.stringify(collectionData, null, 2)
19
26
  : "No collection selected";
27
+
28
+ const code = format === "ts" ? tsCode : jsonCode;
29
+
20
30
  return <Dialog open={open}
21
- onOpenChange={onOpenChange}
22
- maxWidth={"4xl"}>
23
- <DialogTitle variant={"h6"}>Code for {collection.name}</DialogTitle>
31
+ onOpenChange={onOpenChange}
32
+ maxWidth={"4xl"}>
33
+ <div className="flex items-center justify-between pr-6">
34
+ <DialogTitle variant={"h6"}>Code for {collection.name}</DialogTitle>
35
+ <Tabs value={format} onValueChange={(v) => setFormat(v as "ts" | "json")}>
36
+ <Tab value="ts">TypeScript</Tab>
37
+ <Tab value="json">JSON</Tab>
38
+ </Tabs>
39
+ </div>
24
40
  <DialogContent>
25
41
 
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/cloud/quickstart"}>docs</a>.
42
+ <Typography variant={"body2"} className={"mb-4"}>
43
+ {format === "json"
44
+ ? "Use this config to define the collection in JSON format."
45
+ : <>
46
+ If you want to customise the collection in code, you can add this collection code to your CMS
47
+ app configuration.
48
+ More info in the <a
49
+ rel="noopener noreferrer"
50
+ href={"https://firecms.co/docs/cloud/quickstart"}>docs</a>.
51
+ </>}
32
52
  </Typography>
33
53
  <Highlight
34
54
  theme={themes.vsDark}
35
55
  code={code}
36
- language="typescript"
56
+ language={format === "ts" ? "typescript" : "json"}
37
57
  >
38
58
  {({
39
- className,
40
- style,
41
- tokens,
42
- getLineProps,
43
- getTokenProps
44
- }) => (
59
+ className,
60
+ style,
61
+ tokens,
62
+ getLineProps,
63
+ getTokenProps
64
+ }) => (
45
65
  <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>
66
+ {tokens.map((line, i) => (
67
+ <div key={i} {...getLineProps({ line })}>
68
+ {line.map((token, key) => (
69
+ <span key={key} {...getTokenProps({ token })} />
70
+ ))}
71
+ </div>
72
+ ))}
73
+ </pre>
54
74
  )}
55
75
  </Highlight>
56
76
 
@@ -59,7 +79,6 @@ export function GetCodeDialog({
59
79
  <Button
60
80
  variant={"text"}
61
81
  size={"small"}
62
- color={"primary"}
63
82
  onClick={(e) => {
64
83
  e.stopPropagation();
65
84
  e.preventDefault();
@@ -69,7 +88,7 @@ export function GetCodeDialog({
69
88
  })
70
89
  return navigator.clipboard.writeText(code);
71
90
  }}>
72
- <ContentCopyIcon size={"small"}/>
91
+ <ContentCopyIcon size={"small"} />
73
92
  Copy to clipboard
74
93
  </Button>
75
94
  <Button onClick={() => onOpenChange(false)}>Close</Button>
@@ -134,8 +153,10 @@ function collectionToCode(collection: EntityCollection): object {
134
153
  .map(([key, value]) => ({
135
154
  [key]: propertyCleanup(value)
136
155
  }))
137
- .reduce((a, b) => ({ ...a,
138
- ...b }), {}),
156
+ .reduce((a, b) => ({
157
+ ...a,
158
+ ...b
159
+ }), {}),
139
160
  subcollections: (collection.subcollections ?? []).map(collectionToCode)
140
161
  }
141
162