@firecms/collection_editor 3.0.0-beta.2-pre.5 → 3.0.0-beta.3

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,16 +1,16 @@
1
1
  {
2
2
  "name": "@firecms/collection_editor",
3
3
  "type": "module",
4
- "version": "3.0.0-beta.2-pre.5",
4
+ "version": "3.0.0-beta.3",
5
5
  "main": "./dist/index.umd.js",
6
6
  "module": "./dist/index.es.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "source": "src/index.ts",
9
9
  "dependencies": {
10
- "@firecms/data_import_export": "^3.0.0-beta.2-pre.5",
11
- "@firecms/formex": "^3.0.0-beta.2-pre.5",
12
- "@firecms/schema_inference": "^3.0.0-beta.2-pre.5",
13
- "@firecms/ui": "^3.0.0-beta.2-pre.5",
10
+ "@firecms/data_import_export": "^3.0.0-beta.3",
11
+ "@firecms/formex": "^3.0.0-beta.3",
12
+ "@firecms/schema_inference": "^3.0.0-beta.3",
13
+ "@firecms/ui": "^3.0.0-beta.3",
14
14
  "json5": "^2.2.3",
15
15
  "prism-react-renderer": "^2.3.1"
16
16
  },
@@ -20,6 +20,14 @@
20
20
  "react-router": "^6.12.0",
21
21
  "react-router-dom": "^6.12.0"
22
22
  },
23
+ "exports": {
24
+ ".": {
25
+ "import": "./dist/index.es.js",
26
+ "require": "./dist/index.umd.js",
27
+ "types": "./dist/src/index.d.ts"
28
+ },
29
+ "./package.json": "./package.json"
30
+ },
23
31
  "scripts": {
24
32
  "dev": "vite",
25
33
  "test": "jest",
@@ -73,5 +81,5 @@
73
81
  "publishConfig": {
74
82
  "access": "public"
75
83
  },
76
- "gitHead": "5159646cfdb35e11cc510080bd3cff17104d0cb4"
84
+ "gitHead": "33cceff5d5bc2a7002cc5a3904b787e70bfb9c6e"
77
85
  }
@@ -26,7 +26,7 @@ export function RootCollectionSuggestions({ introMode }: { introMode?: "new_proj
26
26
  className={"flex flex-col gap-1 p-2 my-4"}>
27
27
 
28
28
  {!introMode && <Typography variant={"body2"} color={"secondary"}>
29
- Create a collection from your data:
29
+ Create a collection <b>automatically</b> from your data:
30
30
  </Typography>}
31
31
 
32
32
  {introMode === "existing_project" && <Typography>
@@ -96,16 +96,14 @@ export function CollectionDetailsForm({
96
96
  const isSubcollection = !!parentCollection;
97
97
 
98
98
  let customIdValue: "true" | "false" | "optional" | "code_defined" | undefined;
99
- if (customIdValue) {
100
- if (typeof values.customId === "object") {
101
- customIdValue = "code_defined";
102
- } else if (values.customId === true) {
103
- customIdValue = "true";
104
- } else if (values.customId === false) {
105
- customIdValue = "false";
106
- } else if (values.customId === "optional") {
107
- customIdValue = "optional";
108
- }
99
+ if (typeof values.customId === "object") {
100
+ customIdValue = "code_defined";
101
+ } else if (values.customId === true) {
102
+ customIdValue = "true";
103
+ } else if (values.customId === false) {
104
+ customIdValue = "false";
105
+ } else if (values.customId === "optional") {
106
+ customIdValue = "optional";
109
107
  }
110
108
 
111
109
  const showErrors = submitCount > 0;
@@ -226,7 +224,7 @@ export function CollectionDetailsForm({
226
224
  <div className={"col-span-12"}>
227
225
  <TextField
228
226
  error={showErrors && Boolean(errors.singularName)}
229
- id={"singularName"}
227
+ name={"singularName"}
230
228
  aria-describedby={"singularName-helper"}
231
229
  onChange={(e) => {
232
230
  setFieldTouched("singularName", true);
@@ -241,7 +239,7 @@ export function CollectionDetailsForm({
241
239
  <div className={"col-span-12"}>
242
240
  <TextField
243
241
  error={showErrors && Boolean(errors.description)}
244
- id="description"
242
+ name="description"
245
243
  value={values.description ?? ""}
246
244
  onChange={handleChange}
247
245
  multiline
@@ -261,7 +261,6 @@ function CollectionEditorInternal<M extends Record<string, any>>({
261
261
  const importConfig = useImportConfig();
262
262
  const navigation = useNavigationController();
263
263
  const snackbarController = useSnackbarController();
264
- console.log({ importConfig })
265
264
 
266
265
  // Use this ref to store which properties have errors
267
266
  const propertyErrorsRef = useRef({});
@@ -474,7 +473,8 @@ function CollectionEditorInternal<M extends Record<string, any>>({
474
473
  submitCount
475
474
  } = formController;
476
475
 
477
- const path = values.path ?? editedCollectionId;
476
+ // TODO: getting data is only working in root collections with this code
477
+ const path = values.path;
478
478
  const updatedFullPath = fullPath?.includes("/") ? fullPath?.split("/").slice(0, -1).join("/") + "/" + path : path; // TODO: this path is wrong
479
479
  const pathError = validatePath(path, isNewCollection, existingPaths, values.id);
480
480
 
@@ -576,6 +576,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
576
576
  {currentView === "import_data_saving" && importConfig &&
577
577
  <ImportSaveInProgress importConfig={importConfig}
578
578
  collection={values}
579
+ path={path}
579
580
  onImportSuccess={async (importedCollection) => {
580
581
  snackbarController.open({
581
582
  type: "info",
@@ -1,6 +1,6 @@
1
1
  import React, { useCallback, useEffect, useMemo, useState } from "react";
2
2
 
3
- import { Field, getIn } from "@firecms/formex";
3
+ import { Field, getIn, useFormex } from "@firecms/formex";
4
4
  import {
5
5
  EntityCollection,
6
6
  ErrorBoundary,
@@ -34,7 +34,6 @@ import { OnPropertyChangedParams, PropertyForm, PropertyFormDialog } from "./Pro
34
34
  import { PropertyTree } from "./PropertyTree";
35
35
  import { PersistedCollection } from "../../types/persisted_collection";
36
36
  import { GetCodeDialog } from "./GetCodeDialog";
37
- import { useFormex } from "@firecms/formex";
38
37
 
39
38
  type CollectionEditorFormProps = {
40
39
  showErrors: boolean;
@@ -138,7 +137,9 @@ export function CollectionPropertiesEditorForm({
138
137
  ...newPropertyKeys.reduce((acc, propertyKey) => {
139
138
  acc[propertyKey] = (newCollection.properties ?? {})[propertyKey];
140
139
  return acc;
141
- }, {} as { [key: string]: PropertyOrBuilder }),
140
+ }, {} as {
141
+ [key: string]: PropertyOrBuilder
142
+ }),
142
143
  ...values.properties
143
144
  };
144
145
  const updatedPropertiesOrder = [
@@ -224,11 +225,19 @@ export function CollectionPropertiesEditorForm({
224
225
  previousId,
225
226
  namespace
226
227
  }: OnPropertyChangedParams) => {
228
+
227
229
  const fullId = id ? getFullId(id, namespace) : undefined;
228
230
  const propertyPath = fullId ? idToPropertiesPath(fullId) : undefined;
229
231
 
230
232
  // If the id has changed we need to a little cleanup
231
233
  if (previousId && previousId !== id) {
234
+ console.debug("onPropertyChanged, id change", {
235
+ id,
236
+ property,
237
+ previousId,
238
+ namespace
239
+ })
240
+
232
241
  const previousFullId = getFullId(previousId, namespace);
233
242
  const previousPropertyPath = idToPropertiesPath(previousFullId);
234
243
 
@@ -420,11 +429,19 @@ export function CollectionPropertiesEditorForm({
420
429
  />}
421
430
 
422
431
  {!selectedProperty &&
423
- <Typography variant={"label"} className="flex items-center justify-center h-full">
424
- {emptyCollection
425
- ? "Now you can add your first property"
426
- : "Select a property to edit it"}
427
- </Typography>}
432
+ <div className={"w-full flex flex-col items-center justify-center h-full gap-4"}>
433
+ <Typography variant={"label"} className="">
434
+ {emptyCollection
435
+ ? "Now you can add your first property"
436
+ : "Select a property to edit it"}
437
+ </Typography>
438
+ <Button variant={"outlined"}
439
+ onClick={() => setNewPropertyDialogOpen(true)}
440
+ >
441
+ <AddIcon/>
442
+ Add new property
443
+ </Button>
444
+ </div>}
428
445
 
429
446
  {selectedProperty && isPropertyBuilder(selectedProperty) &&
430
447
  <Typography variant={"label"} className="flex items-center justify-center">
@@ -53,7 +53,7 @@ export function SubcollectionsEditTab({
53
53
 
54
54
  const [currentDialog, setCurrentDialog] = React.useState<{
55
55
  isNewCollection: boolean,
56
- editedCollectionPath?: string,
56
+ editedCollectionId?: string,
57
57
  }>();
58
58
 
59
59
  const {
@@ -78,52 +78,53 @@ export function SubcollectionsEditTab({
78
78
  Subcollections of {values.name}
79
79
  </Typography>
80
80
 
81
- {subcollections && subcollections.length > 0 &&
82
- <Paper className={"flex flex-col gap-4 p-2 w-full"}>
83
- <Table>
84
- <TableBody>
85
- {subcollections.map((subcollection) => (
86
- <TableRow key={subcollection.path}
87
- onClick={() => setCurrentDialog({
88
- isNewCollection: false,
89
- editedCollectionPath: subcollection.path,
90
- })}>
91
- <TableCell
92
- align="left">
93
- <Typography variant={"subtitle2"} className={"flex-grow"}>
94
- {subcollection.name}
95
- </Typography>
96
- </TableCell>
97
- <TableCell
98
- align="right">
99
- <Tooltip title={"Remove"}>
100
- <IconButton size="small"
101
- onClick={(e) => {
102
- e.preventDefault();
103
- e.stopPropagation();
104
- setSubcollectionToDelete(subcollection.id);
105
- }}
106
- color="inherit">
107
- <DeleteIcon size={"small"}/>
108
- </IconButton>
109
- </Tooltip>
110
- </TableCell>
111
- </TableRow>
112
- ))}
113
- </TableBody>
114
- </Table>
115
- </Paper>}
81
+ <Paper className={"flex flex-col gap-4 p-2 w-full"}>
82
+ {subcollections && subcollections.length > 0 && <Table>
83
+ <TableBody>
84
+ {subcollections.map((subcollection) => (
85
+ <TableRow key={subcollection.path}
86
+ onClick={() => setCurrentDialog({
87
+ isNewCollection: false,
88
+ editedCollectionId: subcollection.id
89
+ })}>
90
+ <TableCell
91
+ align="left">
92
+ <Typography variant={"subtitle2"} className={"flex-grow"}>
93
+ {subcollection.name}
94
+ </Typography>
95
+ </TableCell>
96
+ <TableCell
97
+ align="right">
98
+ <Tooltip title={"Remove"}>
99
+ <IconButton size="small"
100
+ onClick={(e) => {
101
+ e.preventDefault();
102
+ e.stopPropagation();
103
+ setSubcollectionToDelete(subcollection.id);
104
+ }}
105
+ color="inherit">
106
+ <DeleteIcon size={"small"}/>
107
+ </IconButton>
108
+ </Tooltip>
109
+ </TableCell>
110
+ </TableRow>
111
+ ))}
112
+ </TableBody>
113
+ </Table>}
114
+
115
+ <Button
116
+ onClick={() => {
117
+ setCurrentDialog({
118
+ isNewCollection: true
119
+ });
120
+ }}
121
+ variant={"text"}
122
+ startIcon={<AddIcon/>}>
123
+ Add subcollection
124
+ </Button>
125
+
126
+ </Paper>
116
127
 
117
- <Button
118
- onClick={() => {
119
- setCurrentDialog({
120
- isNewCollection: true
121
- });
122
- }}
123
- variant={"outlined"}
124
- startIcon={<AddIcon/>}>
125
- Add subcollection
126
- </Button>
127
128
  </div>
128
129
 
129
130
  <div className={"flex-grow flex flex-col gap-4 items-start"}>
@@ -131,7 +132,18 @@ export function SubcollectionsEditTab({
131
132
  Custom views
132
133
  </Typography>
133
134
 
134
- {totalEntityViews > 0 && <>
135
+ {totalEntityViews === 0 &&
136
+ <Alert action={<Button variant="text"
137
+ size={"small"}
138
+ href={"https://firecms.co/docs/customization_quickstart"}
139
+ component={"a"}
140
+ rel="noopener noreferrer"
141
+ target="_blank">More info</Button>}>
142
+ Define your own custom views by uploading them with the CLI.
143
+ </Alert>
144
+ }
145
+
146
+ {<>
135
147
  <Paper className={"flex flex-col gap-4 p-2 w-full"}>
136
148
  <Table>
137
149
  <TableBody>
@@ -175,29 +187,19 @@ export function SubcollectionsEditTab({
175
187
  ))}
176
188
  </TableBody>
177
189
  </Table>
190
+
191
+ <Button
192
+ onClick={() => {
193
+ setAddEntityViewDialogOpen(true);
194
+ }}
195
+ variant={"text"}
196
+ startIcon={<AddIcon/>}>
197
+ Add custom entity view
198
+ </Button>
178
199
  </Paper>
179
200
 
180
201
  </>}
181
202
 
182
- {totalEntityViews === 0 &&
183
- <Alert action={<Button variant="text"
184
- size={"small"}
185
- href={"https://firecms.co/docs/customization_quickstart"}
186
- component={"a"}
187
- rel="noopener noreferrer"
188
- target="_blank">More info</Button>}>
189
- Define your own custom views by uploading it with the CLI.
190
- </Alert>
191
- }
192
-
193
- <Button
194
- onClick={() => {
195
- setAddEntityViewDialogOpen(true);
196
- }}
197
- variant={"outlined"}
198
- startIcon={<AddIcon/>}>
199
- Add custom entity view
200
- </Button>
201
203
 
202
204
  </div>
203
205
 
@@ -23,19 +23,22 @@ export function BlockPropertyField({ disabled, getData, allowDataInference, prop
23
23
  const [selectedPropertyKey, setSelectedPropertyKey] = useState<string | undefined>();
24
24
  const [selectedPropertyNamespace, setSelectedPropertyNamespace] = useState<string | undefined>();
25
25
 
26
- const onPropertyCreated = useCallback(({
27
- id,
28
- property
29
- }: { id?: string, property: Property }) => {
26
+ const onPropertyChanged = ({
27
+ id,
28
+ property
29
+ }: { id?: string, property: Property }) => {
30
30
  if (!id)
31
31
  throw Error();
32
+
32
33
  setFieldValue("oneOf.properties", {
33
34
  ...(values.oneOf?.properties ?? {}),
34
35
  [id]: property
35
36
  }, false);
36
- setFieldValue("oneOf.propertiesOrder", [...(values.oneOf?.propertiesOrder ?? Object.keys(values.oneOf?.properties ?? {})), id], false);
37
+ const currentPropertiesOrder = values.oneOf?.propertiesOrder ?? Object.keys(values.oneOf?.properties ?? {});
38
+ const newPropertiesOrder = currentPropertiesOrder.includes(id) ? currentPropertiesOrder : [...currentPropertiesOrder, id];
39
+ setFieldValue("oneOf.propertiesOrder", newPropertiesOrder, false);
37
40
  setPropertyDialogOpen(false);
38
- }, [values.oneOf?.properties, values.oneOf?.propertiesOrder]);
41
+ };
39
42
 
40
43
  const selectedPropertyFullId = selectedPropertyKey ? getFullId(selectedPropertyKey, selectedPropertyNamespace) : undefined;
41
44
  const selectedProperty = selectedPropertyFullId ? getIn(values.oneOf?.properties, selectedPropertyFullId.replaceAll(".", ".properties.")) : undefined;
@@ -127,7 +130,7 @@ export function BlockPropertyField({ disabled, getData, allowDataInference, prop
127
130
  existingProperty={Boolean(selectedPropertyKey)}
128
131
  autoUpdateId={!selectedPropertyKey}
129
132
  autoOpenTypeSelect={!selectedPropertyKey}
130
- onPropertyChanged={onPropertyCreated}
133
+ onPropertyChanged={onPropertyChanged}
131
134
  existingPropertyKeys={selectedPropertyKey ? undefined : values.oneOf?.propertiesOrder}
132
135
  propertyConfigs={propertyConfigs}/>}
133
136
 
@@ -25,19 +25,23 @@ export function MapPropertyField({ disabled, getData, allowDataInference, proper
25
25
  const [selectedPropertyNamespace, setSelectedPropertyNamespace] = useState<string | undefined>();
26
26
 
27
27
  const propertiesOrder = values.propertiesOrder ?? Object.keys(values.properties ?? {});
28
- const onPropertyCreated = useCallback(({
29
- id,
30
- property
31
- }: { id?: string, property: Property }) => {
28
+ const onPropertyCreated = ({
29
+ id,
30
+ property
31
+ }: { id?: string, property: Property }) => {
32
32
  if (!id)
33
33
  throw Error();
34
34
  setFieldValue("properties", {
35
35
  ...(values.properties ?? {}),
36
36
  [id]: property
37
37
  }, false);
38
- setFieldValue("propertiesOrder", [...propertiesOrder, id], false);
38
+
39
+ const currentPropertiesOrder = values.propertiesOrder ?? Object.keys(values.properties ?? {});
40
+ const newPropertiesOrder = currentPropertiesOrder.includes(id) ? currentPropertiesOrder : [...currentPropertiesOrder, id];
41
+ setFieldValue("propertiesOrder", newPropertiesOrder, false);
42
+
39
43
  setPropertyDialogOpen(false);
40
- }, [values.properties, propertiesOrder]);
44
+ };
41
45
 
42
46
  const deleteProperty = useCallback((propertyKey?: string, namespace?: string) => {
43
47
  const fullId = propertyKey ? getFullId(propertyKey, namespace) : undefined;
@@ -60,15 +64,6 @@ export function MapPropertyField({ disabled, getData, allowDataInference, proper
60
64
  const selectedPropertyFullId = selectedPropertyKey ? getFullId(selectedPropertyKey, selectedPropertyNamespace) : undefined;
61
65
  const selectedProperty = selectedPropertyFullId ? getIn(values.properties, selectedPropertyFullId.replaceAll(".", ".properties.")) : undefined;
62
66
 
63
- const addChildButton = <Button
64
- color="primary"
65
- variant={"outlined"}
66
- onClick={() => setPropertyDialogOpen(true)}
67
- startIcon={<AddIcon/>}
68
- >
69
- Add property to {values.name ?? "this group"}
70
- </Button>;
71
-
72
67
  const empty = !propertiesOrder || propertiesOrder.length < 1;
73
68
 
74
69
  const onPropertyMove = useCallback((propertiesOrder: string[], namespace?: string) => {
@@ -80,7 +75,14 @@ export function MapPropertyField({ disabled, getData, allowDataInference, proper
80
75
  <div className={"col-span-12"}>
81
76
  <div className="flex justify-between items-end my-4">
82
77
  <Typography variant={"subtitle2"}>Properties in this group</Typography>
83
- {addChildButton}
78
+ <Button
79
+ color="primary"
80
+ variant={"outlined"}
81
+ onClick={() => setPropertyDialogOpen(true)}
82
+ startIcon={<AddIcon/>}
83
+ >
84
+ Add property to {values.name ?? "this group"}
85
+ </Button>
84
86
  </div>
85
87
  <Paper className="p-2 pl-8">
86
88
  <PropertyTree
@@ -40,7 +40,7 @@ export function ReferencePropertyField({
40
40
  <Field name={pathPath}
41
41
  pathPath={pathPath}
42
42
  type="select"
43
- disabled={existing || disabled}
43
+ disabled={(existing && Boolean(pathValue)) || disabled}
44
44
  value={pathValue}
45
45
  error={pathError}
46
46
  handleChange={handleChange}
@@ -52,7 +52,6 @@ export function ReferencePropertyField({
52
52
  );
53
53
  }
54
54
 
55
-
56
55
  export function CollectionsSelect({
57
56
  disabled,
58
57
  pathPath,
@@ -1,4 +1,4 @@
1
- import React, { useCallback, useState } from "react";
1
+ import React, { useState } from "react";
2
2
  import { ArrayProperty, getFieldConfig, Property, PropertyConfig } from "@firecms/core";
3
3
  import { Button, Paper, Typography } from "@firecms/ui";
4
4
  import { Field, getIn, useFormex } from "@firecms/formex";