@firecms/collection_editor 3.0.0-alpha.30 → 3.0.0-alpha.32

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@firecms/collection_editor",
3
- "version": "3.0.0-alpha.30",
3
+ "version": "3.0.0-alpha.32",
4
4
  "main": "./dist/index.umd.js",
5
5
  "module": "./dist/index.es.js",
6
6
  "types": "dist/index.d.ts",
@@ -14,8 +14,10 @@
14
14
  "./package.json": "./package.json"
15
15
  },
16
16
  "dependencies": {
17
- "@firecms/data_import": "^3.0.0-alpha.30",
18
- "@firecms/schema_inference": "^3.0.0-alpha.30"
17
+ "@firecms/data_import": "^3.0.0-alpha.32",
18
+ "@firecms/schema_inference": "^3.0.0-alpha.32",
19
+ "json5": "^2.2.3",
20
+ "prism-react-renderer": "^2.3.0"
19
21
  },
20
22
  "peerDependencies": {
21
23
  "react": "^18.2.0",
@@ -76,5 +78,5 @@
76
78
  "publishConfig": {
77
79
  "access": "public"
78
80
  },
79
- "gitHead": "89854d00f9088e09134623a84be752990c6cbc32"
81
+ "gitHead": "f545e3572aa7f025222713984025288bf62b0d4c"
80
82
  }
@@ -391,7 +391,7 @@ export function CollectionEditorDialogInternal<M extends {
391
391
  }) => {
392
392
 
393
393
  const path = values.path ?? editedCollectionPath;
394
- const updatedFullPath = fullPath?.includes("/") ? fullPath?.split("/").slice(0, -1).join("/") + "/" + path : path;
394
+ const updatedFullPath = fullPath?.includes("/") ? fullPath?.split("/").slice(0, -1).join("/") + "/" + path : path; // TODO: this path is wrong
395
395
  const resolvedPath = navigation.resolveAliasesFrom(updatedFullPath);
396
396
  const getDataWithPath = resolvedPath && getData ? () => getData(resolvedPath) : undefined;
397
397
 
@@ -1,4 +1,5 @@
1
1
  import React, { useEffect, useMemo, useState } from "react";
2
+ import JSON5 from "json5";
2
3
 
3
4
  import { Field, FormikErrors, getIn, useFormikContext } from "formik";
4
5
  import {
@@ -7,28 +8,36 @@ import {
7
8
  Button,
8
9
  CircularProgress,
9
10
  cn,
11
+ CodeIcon,
10
12
  DebouncedTextField,
11
13
  defaultBorderMixin,
14
+ Dialog,
15
+ DialogActions,
16
+ DialogContent,
12
17
  EntityCollection,
13
18
  ErrorBoundary,
14
- PropertyConfig,
19
+ IconButton,
15
20
  isPropertyBuilder,
16
21
  makePropertiesEditable,
17
22
  Paper,
18
23
  Properties,
19
24
  Property,
25
+ PropertyConfig,
20
26
  PropertyOrBuilder,
21
27
  Tooltip,
22
28
  Typography,
23
29
  useLargeLayout,
24
30
  User,
25
- useSnackbarController,
31
+ useSnackbarController
26
32
  } from "@firecms/core";
27
33
 
34
+ import { Highlight, themes } from "prism-react-renderer"
35
+
28
36
  import { getFullId, idToPropertiesPath, namespaceToPropertiesOrderPath } from "./util";
29
37
  import { OnPropertyChangedParams, PropertyForm, PropertyFormDialog } from "./PropertyEditView";
30
38
  import { PropertyTree } from "./PropertyTree";
31
39
  import { PersistedCollection } from "../../types/persisted_collection";
40
+ import { camelCase } from "./utils/strings";
32
41
 
33
42
  type CollectionEditorFormProps = {
34
43
  showErrors: boolean;
@@ -45,6 +54,47 @@ type CollectionEditorFormProps = {
45
54
  collectionEditable: boolean;
46
55
  };
47
56
 
57
+ function GetCodeDialog({ collection, onOpenChange, open }: { onOpenChange: (open: boolean) => void, collection: any, open: any }) {
58
+ const code = "const " + camelCase(collection.name) + "Collection = " + JSON5.stringify(collection, null, "\t");
59
+ return <Dialog open={open}
60
+ onOpenChange={onOpenChange}
61
+ maxWidth={"4xl"}>
62
+ <DialogContent>
63
+ <Typography variant={"h6"} className={"my-4"}>
64
+ Code for {collection.name}
65
+ </Typography>
66
+ <Typography variant={"body2"} className={"my-4 mb-8"}>
67
+ If you want to customise the collection in code, you can add this collection code to your CMS
68
+ app configuration.
69
+ More info in the <a
70
+ rel="noopener noreferrer"
71
+ href={"https://firecms.co/docs/customization_quickstart"}>docs</a>.
72
+ </Typography>
73
+ <Highlight
74
+ theme={themes.vsDark}
75
+ code={code}
76
+ language="typescript"
77
+ >
78
+ {({ className, style, tokens, getLineProps, getTokenProps }) => (
79
+ <pre style={style} className={"p-4 rounded"}>
80
+ {tokens.map((line, i) => (
81
+ <div key={i} {...getLineProps({ line })}>
82
+ {line.map((token, key) => (
83
+ <span key={key} {...getTokenProps({ token })} />
84
+ ))}
85
+ </div>
86
+ ))}
87
+ </pre>
88
+ )}
89
+ </Highlight>
90
+
91
+ </DialogContent>
92
+ <DialogActions>
93
+ <Button onClick={() => onOpenChange(false)}>Close</Button>
94
+ </DialogActions>
95
+ </Dialog>;
96
+ }
97
+
48
98
  export function CollectionPropertiesEditorForm({
49
99
  showErrors,
50
100
  isNewCollection,
@@ -81,6 +131,7 @@ export function CollectionPropertiesEditorForm({
81
131
 
82
132
  const selectedPropertyFullId = selectedPropertyKey ? getFullId(selectedPropertyKey, selectedPropertyNamespace) : undefined;
83
133
  const selectedProperty = selectedPropertyFullId ? getIn(values.properties, selectedPropertyFullId.replaceAll(".", ".properties.")) : undefined;
134
+ const [codeDialogOpen, setCodeDialogOpen] = useState<boolean>(false);
84
135
 
85
136
  const [inferringProperties, setInferringProperties] = useState<boolean>(false);
86
137
 
@@ -112,7 +163,7 @@ export function CollectionPropertiesEditorForm({
112
163
  if (!newCollection) {
113
164
  snackbarController.open({
114
165
  type: "error",
115
- message: "Could not infer properties from data",
166
+ message: "Could not infer properties from data"
116
167
  });
117
168
  return;
118
169
  }
@@ -122,7 +173,7 @@ export function CollectionPropertiesEditorForm({
122
173
  if (newPropertyKeys.length === 0) {
123
174
  snackbarController.open({
124
175
  type: "info",
125
- message: "No new properties found",
176
+ message: "No new properties found"
126
177
  });
127
178
  return;
128
179
  }
@@ -132,7 +183,7 @@ export function CollectionPropertiesEditorForm({
132
183
  acc[propertyKey] = newCollection.properties[propertyKey];
133
184
  return acc;
134
185
  }, {} as { [key: string]: PropertyOrBuilder }),
135
- ...values.properties,
186
+ ...values.properties
136
187
  };
137
188
  const updatedPropertiesOrder = [
138
189
  ...newPropertyKeys,
@@ -323,13 +374,21 @@ export function CollectionPropertiesEditorForm({
323
374
  </div>}
324
375
 
325
376
  <div className="ml-1 mt-2 flex flex-row gap-2">
377
+ <Tooltip title={"Get the code of this collection"}>
378
+ <IconButton
379
+ variant={"filled"}
380
+ disabled={inferringProperties}
381
+ onClick={() => setCodeDialogOpen(true)}>
382
+ <CodeIcon/>
383
+ </IconButton>
384
+ </Tooltip>
326
385
  {inferPropertiesFromData && <Tooltip title={"Add new properties based on data"}>
327
- <Button
328
- variant={"text"}
386
+ <IconButton
387
+ variant={"filled"}
329
388
  disabled={inferringProperties}
330
389
  onClick={inferPropertiesFromData}>
331
390
  {inferringProperties ? <CircularProgress size={"small"}/> : <AutoAwesomeIcon/>}
332
- </Button>
391
+ </IconButton>
333
392
  </Tooltip>}
334
393
  <Tooltip title={"Add new property"}>
335
394
  <Button
@@ -458,6 +517,11 @@ export function CollectionPropertiesEditorForm({
458
517
  collectionEditable={collectionEditable}
459
518
  existingPropertyKeys={values.propertiesOrder as string[]}/>
460
519
 
520
+ <GetCodeDialog
521
+ collection={values}
522
+ open={codeDialogOpen}
523
+ onOpenChange={setCodeDialogOpen}/>
524
+
461
525
  </>
462
526
  );
463
527
  }
@@ -1,6 +1,6 @@
1
- import { buildCollection, buildProperty } from "@firecms/core";
1
+ import { EntityCollection } from "@firecms/firebase";
2
2
 
3
- export const blogCollectionTemplate = buildCollection({
3
+ export const blogCollectionTemplate:EntityCollection = {
4
4
  path: "blog",
5
5
  name: "Blog",
6
6
  singularName: "Blog entry",
@@ -9,12 +9,12 @@ export const blogCollectionTemplate = buildCollection({
9
9
  description: "A collection of blog entries",
10
10
  defaultSize: "l",
11
11
  properties: {
12
- name: buildProperty({
12
+ name: {
13
13
  name: "Name",
14
14
  validation: { required: true },
15
15
  dataType: "string"
16
- }),
17
- header_image: buildProperty({
16
+ },
17
+ header_image: {
18
18
  name: "Header image",
19
19
  dataType: "string",
20
20
  storage: {
@@ -24,8 +24,8 @@ export const blogCollectionTemplate = buildCollection({
24
24
  cacheControl: "max-age=1000000"
25
25
  }
26
26
  }
27
- }),
28
- content: buildProperty({
27
+ },
28
+ content: {
29
29
  name: "Content",
30
30
  description: "Content blocks for the blog entry",
31
31
  validation: { required: true },
@@ -71,7 +71,7 @@ export const blogCollectionTemplate = buildCollection({
71
71
  },
72
72
  propertiesOrder: ["text", "quote", "images", "products"]
73
73
  }
74
- }),
74
+ },
75
75
  created_on: {
76
76
  name: "Created on",
77
77
  dataType: "date",
@@ -112,4 +112,4 @@ export const blogCollectionTemplate = buildCollection({
112
112
  initialFilter: {
113
113
  status: ["==", "published"]
114
114
  }
115
- });
115
+ };
@@ -1,6 +1,6 @@
1
- import { buildCollection } from "@firecms/core";
1
+ import { EntityCollection } from "@firecms/core";
2
2
 
3
- export const productsCollectionTemplate = buildCollection({
3
+ export const productsCollectionTemplate: EntityCollection = {
4
4
  path: "products",
5
5
  name: "Products",
6
6
  singularName: "Product",
@@ -86,4 +86,4 @@ export const productsCollectionTemplate = buildCollection({
86
86
  }
87
87
  }
88
88
 
89
- });
89
+ };
@@ -1,6 +1,6 @@
1
- import { buildCollection } from "@firecms/core";
1
+ import { EntityCollection } from "@firecms/core";
2
2
 
3
- export const usersCollectionTemplate = buildCollection({
3
+ export const usersCollectionTemplate: EntityCollection = {
4
4
  path: "users",
5
5
  name: "Users",
6
6
  singularName: "User",
@@ -31,4 +31,4 @@ export const usersCollectionTemplate = buildCollection({
31
31
  url: "image"
32
32
  }
33
33
  },
34
- });
34
+ };
@@ -0,0 +1,8 @@
1
+ export function camelCase(str: string): string {
2
+ return (str.slice(0, 1).toLowerCase() + str.slice(1))
3
+ .replace(/([-_ ]){1,}/g, ' ')
4
+ .split(/[-_ ]/)
5
+ .reduce((cur, acc) => {
6
+ return cur + acc[0].toUpperCase() + acc.substring(1);
7
+ });
8
+ }
@@ -1,4 +1,14 @@
1
- import { buildProperty, PropertyConfig, mergeDeep, Property } from "@firecms/core";
1
+ import {
2
+ ArrayProperty,
3
+ BooleanProperty,
4
+ DateProperty,
5
+ MapProperty,
6
+ mergeDeep,
7
+ NumberProperty,
8
+ Property,
9
+ PropertyConfig,
10
+ StringProperty
11
+ } from "@firecms/core";
2
12
 
3
13
  export function updatePropertyFromWidget(propertyData: any,
4
14
  selectedWidgetId: string | undefined,
@@ -8,7 +18,7 @@ export function updatePropertyFromWidget(propertyData: any,
8
18
  if (selectedWidgetId === "text_field") {
9
19
  updatedProperty = mergeDeep(
10
20
  propertyData,
11
- buildProperty({
21
+ {
12
22
  dataType: "string",
13
23
  propertyConfig: "text_field",
14
24
  editable: propertyData.editable !== undefined ? propertyData.editable : true,
@@ -18,12 +28,12 @@ export function updatePropertyFromWidget(propertyData: any,
18
28
  email: undefined,
19
29
  url: undefined,
20
30
  enumValues: undefined
21
- })
31
+ } satisfies StringProperty
22
32
  );
23
33
  } else if (selectedWidgetId === "multiline") {
24
34
  updatedProperty = mergeDeep(
25
35
  propertyData,
26
- buildProperty({
36
+ {
27
37
  dataType: "string",
28
38
  propertyConfig: "multiline",
29
39
  editable: propertyData.editable !== undefined ? propertyData.editable : true,
@@ -33,12 +43,12 @@ export function updatePropertyFromWidget(propertyData: any,
33
43
  email: undefined,
34
44
  url: undefined,
35
45
  enumValues: undefined
36
- })
46
+ } satisfies StringProperty
37
47
  );
38
48
  } else if (selectedWidgetId === "markdown") {
39
49
  updatedProperty = mergeDeep(
40
50
  propertyData,
41
- buildProperty({
51
+ {
42
52
  dataType: "string",
43
53
  propertyConfig: "markdown",
44
54
  editable: propertyData.editable !== undefined ? propertyData.editable : true,
@@ -47,12 +57,12 @@ export function updatePropertyFromWidget(propertyData: any,
47
57
  markdown: true,
48
58
  email: undefined,
49
59
  url: undefined
50
- })
60
+ } satisfies StringProperty
51
61
  );
52
62
  } else if (selectedWidgetId === "url") {
53
63
  updatedProperty = mergeDeep(
54
64
  propertyData,
55
- buildProperty({
65
+ {
56
66
  dataType: "string",
57
67
  propertyConfig: "url",
58
68
  editable: propertyData.editable !== undefined ? propertyData.editable : true,
@@ -62,12 +72,12 @@ export function updatePropertyFromWidget(propertyData: any,
62
72
  email: undefined,
63
73
  url: true,
64
74
  enumValues: undefined
65
- })
75
+ } satisfies StringProperty
66
76
  );
67
77
  } else if (selectedWidgetId === "email") {
68
78
  updatedProperty = mergeDeep(
69
79
  propertyData,
70
- buildProperty({
80
+ {
71
81
  dataType: "string",
72
82
  propertyConfig: "email",
73
83
  editable: propertyData.editable !== undefined ? propertyData.editable : true,
@@ -77,12 +87,12 @@ export function updatePropertyFromWidget(propertyData: any,
77
87
  email: true,
78
88
  url: undefined,
79
89
  enumValues: undefined
80
- })
90
+ } satisfies StringProperty
81
91
  );
82
92
  } else if (selectedWidgetId === "select") {
83
93
  updatedProperty = mergeDeep(
84
94
  propertyData,
85
- buildProperty({
95
+ {
86
96
  dataType: "string",
87
97
  propertyConfig: "select",
88
98
  editable: propertyData.editable !== undefined ? propertyData.editable : true,
@@ -92,12 +102,12 @@ export function updatePropertyFromWidget(propertyData: any,
92
102
  email: undefined,
93
103
  url: undefined,
94
104
  enumValues: propertyData.enumValues ?? []
95
- })
105
+ } satisfies StringProperty
96
106
  );
97
107
  } else if (selectedWidgetId === "multi_select") {
98
108
  updatedProperty = mergeDeep(
99
109
  propertyData,
100
- buildProperty({
110
+ {
101
111
  dataType: "array",
102
112
  propertyConfig: "multi_select",
103
113
  editable: propertyData.editable !== undefined ? propertyData.editable : true,
@@ -105,32 +115,32 @@ export function updatePropertyFromWidget(propertyData: any,
105
115
  dataType: "string",
106
116
  enumValues: propertyData.of?.enumValues ?? []
107
117
  }
108
- })
118
+ } satisfies ArrayProperty
109
119
  );
110
120
  } else if (selectedWidgetId === "number_input") {
111
121
  updatedProperty = mergeDeep(
112
122
  propertyData,
113
- buildProperty({
123
+ {
114
124
  dataType: "number",
115
125
  propertyConfig: "number_input",
116
126
  editable: propertyData.editable !== undefined ? propertyData.editable : true,
117
127
  enumValues: undefined
118
- })
128
+ } satisfies NumberProperty
119
129
  );
120
130
  } else if (selectedWidgetId === "number_select") {
121
131
  updatedProperty = mergeDeep(
122
132
  propertyData,
123
- buildProperty({
133
+ {
124
134
  dataType: "number",
125
135
  propertyConfig: "number_select",
126
136
  editable: propertyData.editable !== undefined ? propertyData.editable : true,
127
137
  enumValues: propertyData.enumValues ?? []
128
- })
138
+ } satisfies NumberProperty
129
139
  );
130
140
  } else if (selectedWidgetId === "multi_number_select") {
131
141
  updatedProperty = mergeDeep(
132
142
  propertyData,
133
- buildProperty({
143
+ {
134
144
  dataType: "array",
135
145
  propertyConfig: "multi_number_select",
136
146
  editable: propertyData.editable !== undefined ? propertyData.editable : true,
@@ -138,24 +148,24 @@ export function updatePropertyFromWidget(propertyData: any,
138
148
  dataType: "number",
139
149
  enumValues: propertyData.of?.enumValues ?? []
140
150
  }
141
- })
151
+ } satisfies ArrayProperty
142
152
  );
143
153
  } else if (selectedWidgetId === "file_upload") {
144
154
  updatedProperty = mergeDeep(
145
155
  propertyData,
146
- buildProperty({
156
+ {
147
157
  dataType: "string",
148
158
  propertyConfig: "file_upload",
149
159
  editable: propertyData.editable !== undefined ? propertyData.editable : true,
150
160
  storage: {
151
161
  storagePath: "/"
152
162
  }
153
- })
163
+ } satisfies StringProperty
154
164
  );
155
165
  } else if (selectedWidgetId === "multi_file_upload") {
156
166
  updatedProperty = mergeDeep(
157
167
  propertyData,
158
- buildProperty({
168
+ {
159
169
  dataType: "array",
160
170
  propertyConfig: "multi_file_upload",
161
171
  editable: propertyData.editable !== undefined ? propertyData.editable : true,
@@ -165,90 +175,90 @@ export function updatePropertyFromWidget(propertyData: any,
165
175
  storagePath: "/"
166
176
  }
167
177
  }
168
- })
178
+ } satisfies ArrayProperty
169
179
  );
170
180
  } else if (selectedWidgetId === "group") {
171
181
  updatedProperty = mergeDeep(
172
182
  propertyData,
173
- buildProperty({
183
+ {
174
184
  dataType: "map",
175
185
  propertyConfig: "group",
176
186
  editable: propertyData.editable !== undefined ? propertyData.editable : true,
177
187
  keyValue: false,
178
188
  properties: propertyData.properties ?? {}
179
- })
189
+ } satisfies MapProperty
180
190
  );
181
191
  } else if (selectedWidgetId === "key_value") {
182
192
  updatedProperty = mergeDeep(
183
193
  propertyData,
184
- buildProperty({
194
+ {
185
195
  dataType: "map",
186
196
  propertyConfig: "key_value",
187
197
  editable: propertyData.editable !== undefined ? propertyData.editable : true,
188
198
  keyValue: true,
189
199
  properties: undefined
190
- })
200
+ } satisfies MapProperty
191
201
  );
192
202
  } else if (selectedWidgetId === "reference") {
193
203
  updatedProperty = mergeDeep(
194
204
  propertyData,
195
- buildProperty({
205
+ {
196
206
  dataType: "reference",
197
207
  propertyConfig: "reference",
198
208
  editable: propertyData.editable !== undefined ? propertyData.editable : true
199
- })
209
+ } satisfies Property
200
210
  );
201
211
  } else if (selectedWidgetId === "multi_references") {
202
212
  updatedProperty = mergeDeep(
203
213
  propertyData,
204
- buildProperty({
214
+ {
205
215
  dataType: "array",
206
216
  propertyConfig: "multi_references",
207
217
  editable: propertyData.editable !== undefined ? propertyData.editable : true,
208
218
  of: {
209
219
  dataType: "reference"
210
220
  }
211
- })
221
+ } satisfies ArrayProperty
212
222
  );
213
223
  } else if (selectedWidgetId === "switch") {
214
224
  updatedProperty = mergeDeep(
215
225
  propertyData,
216
- buildProperty({
226
+ {
217
227
  dataType: "boolean",
218
228
  propertyConfig: "switch",
219
229
  editable: propertyData.editable !== undefined ? propertyData.editable : true
220
- })
230
+ } satisfies BooleanProperty
221
231
  );
222
232
  } else if (selectedWidgetId === "date_time") {
223
233
  updatedProperty = mergeDeep(
224
234
  propertyData,
225
- buildProperty({
235
+ {
226
236
  dataType: "date",
227
237
  propertyConfig: "date_time",
228
238
  editable: propertyData.editable !== undefined ? propertyData.editable : true,
229
239
  mode: "date_time"
230
- })
240
+ } satisfies DateProperty
231
241
  );
232
242
  } else if (selectedWidgetId === "repeat") {
233
243
  updatedProperty = mergeDeep(
234
244
  propertyData,
235
- buildProperty({
245
+ {
236
246
  dataType: "array",
237
247
  propertyConfig: "repeat",
238
248
  editable: propertyData.editable !== undefined ? propertyData.editable : true
239
- })
249
+ } satisfies ArrayProperty
240
250
  );
241
251
  } else if (selectedWidgetId === "block") {
242
252
  updatedProperty = mergeDeep(
243
253
  propertyData,
244
- buildProperty({
254
+ {
245
255
  dataType: "array",
246
256
  propertyConfig: "block",
247
257
  editable: propertyData.editable !== undefined ? propertyData.editable : true,
248
258
  oneOf: {
249
259
  properties: {}
250
260
  }
251
- })
261
+ } satisfies ArrayProperty
252
262
  );
253
263
  } else if (selectedWidgetId && customFields[selectedWidgetId]) {
254
264
  updatedProperty = { ...customFields[selectedWidgetId].property, propertyConfig: selectedWidgetId };