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

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.
@@ -1 +1,3 @@
1
- export declare function RootCollectionSuggestions(): import("react/jsx-runtime").JSX.Element;
1
+ export declare function RootCollectionSuggestions({ introMode }: {
2
+ introMode?: "new_project" | "existing_project";
3
+ }): import("react/jsx-runtime").JSX.Element;
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { EntityCollection, FireCMSPlugin, ModifyCollectionProps, User } from "@firecms/core";
2
+ import { FireCMSPlugin, User } from "@firecms/core";
3
3
  import { CollectionEditorPermissionsBuilder } from "./types/config_permissions";
4
4
  import { PersistedCollection } from "./types/persisted_collection";
5
5
  import { CollectionInference } from "./types/collection_inference";
@@ -9,7 +9,6 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
9
9
  * Firebase app where the configuration is saved.
10
10
  */
11
11
  collectionConfigController: CollectionsConfigController;
12
- modifyCollection?: (props: ModifyCollectionProps) => EntityCollection | void;
13
12
  /**
14
13
  * Define what actions can be performed on the configuration.
15
14
  */
@@ -31,6 +30,7 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
31
30
  getData?: (path: string, parentPaths: string[]) => Promise<object[]>;
32
31
  getUser: (uid: string) => UserType | null;
33
32
  onAnalyticsEvent?: (event: string, params?: object) => void;
33
+ introMode?: "new_project" | "existing_project";
34
34
  }
35
35
  /**
36
36
  * Use this hook to initialise the Collection Editor plugin.
@@ -43,4 +43,7 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
43
43
  * @param getUser
44
44
  * @param collectionInference
45
45
  */
46
- export declare function useCollectionEditorPlugin<EC extends PersistedCollection = PersistedCollection, UserType extends User = User>({ collectionConfigController, modifyCollection, configPermissions, reservedGroups, extraView, pathSuggestions, getUser, collectionInference, getData, onAnalyticsEvent }: CollectionConfigControllerProps<EC, UserType>): FireCMSPlugin<any, any, PersistedCollection>;
46
+ export declare function useCollectionEditorPlugin<EC extends PersistedCollection = PersistedCollection, UserType extends User = User>({ collectionConfigController, introMode, configPermissions, reservedGroups, extraView, pathSuggestions, getUser, collectionInference, getData, onAnalyticsEvent }: CollectionConfigControllerProps<EC, UserType>): FireCMSPlugin<any, any, PersistedCollection>;
47
+ export declare function IntroWidget({ introMode }: {
48
+ introMode?: "new_project" | "existing_project";
49
+ }): import("react/jsx-runtime").JSX.Element;
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.4",
4
+ "version": "3.0.0-beta.2-pre.5",
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.4",
11
- "@firecms/formex": "^3.0.0-beta.2-pre.4",
12
- "@firecms/schema_inference": "^3.0.0-beta.2-pre.4",
13
- "@firecms/ui": "^3.0.0-beta.2-pre.4",
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",
14
14
  "json5": "^2.2.3",
15
15
  "prism-react-renderer": "^2.3.1"
16
16
  },
@@ -63,7 +63,7 @@
63
63
  "react-router-dom": "^6.22.0",
64
64
  "ts-jest": "^29.1.2",
65
65
  "typescript": "^5.3.3",
66
- "vite": "^4.5.2",
66
+ "vite": "^5.1.1",
67
67
  "vite-plugin-fonts": "^0.7.0"
68
68
  },
69
69
  "files": [
@@ -73,5 +73,5 @@
73
73
  "publishConfig": {
74
74
  "access": "public"
75
75
  },
76
- "gitHead": "a947c08aada0e374aec7dff2b0dc9e540e170834"
76
+ "gitHead": "5159646cfdb35e11cc510080bd3cff17104d0cb4"
77
77
  }
@@ -1,9 +1,9 @@
1
1
  import { unslugify, useAuthController, useNavigationController } from "@firecms/core";
2
- import { AddIcon, Chip, Collapse, Typography, } from "@firecms/ui";
2
+ import { AddIcon, Chip, CircularProgress, Collapse, Typography, } from "@firecms/ui";
3
3
  import { useCollectionEditorController } from "../useCollectionEditorController";
4
4
  import React from "react";
5
5
 
6
- export function RootCollectionSuggestions() {
6
+ export function RootCollectionSuggestions({ introMode }: { introMode?: "new_project" | "existing_project" }) {
7
7
 
8
8
  const authController = useAuthController();
9
9
  const navigationController = useNavigationController();
@@ -15,22 +15,27 @@ export function RootCollectionSuggestions() {
15
15
  }).createCollections
16
16
  : true;
17
17
 
18
- const rootPathSuggestions = collectionEditorController.rootPathSuggestions ?? [];
18
+ const rootPathSuggestions = collectionEditorController.rootPathSuggestions;
19
19
 
20
- const showSuggestions = rootPathSuggestions.length > 3 || ((navigationController.collections ?? []).length === 0 && rootPathSuggestions.length > 0);
20
+ const showSuggestions = (rootPathSuggestions ?? []).length > 3 || ((navigationController.collections ?? []).length === 0 && (rootPathSuggestions ?? []).length > 0);
21
+ const forceShowSuggestions = introMode === "existing_project";
21
22
  return <Collapse
22
- in={showSuggestions}>
23
+ in={forceShowSuggestions || showSuggestions}>
23
24
 
24
25
  <div
25
26
  className={"flex flex-col gap-1 p-2 my-4"}>
26
27
 
27
- <Typography variant={"body2"} color={"secondary"}>
28
+ {!introMode && <Typography variant={"body2"} color={"secondary"}>
28
29
  Create a collection from your data:
29
- </Typography>
30
+ </Typography>}
31
+
32
+ {introMode === "existing_project" && <Typography>
33
+ You will see your <b>database collections</b> here, a few seconds after project creation
34
+ </Typography>}
30
35
 
31
36
  <div
32
37
  className={"flex flex-row gap-1 overflow-scroll no-scrollbar "}>
33
- {rootPathSuggestions.map((path) => {
38
+ {(rootPathSuggestions ?? []).map((path) => {
34
39
  return (
35
40
  <div key={path}>
36
41
  <Chip
@@ -50,6 +55,8 @@ export function RootCollectionSuggestions() {
50
55
  </div>
51
56
  );
52
57
  })}
58
+ {rootPathSuggestions === undefined && <CircularProgress size={"small"}/>}
59
+ {rootPathSuggestions?.length === 0 && <Typography variant={"caption"}>No suggestions</Typography>}
53
60
  </div>
54
61
  </div>
55
62
  </Collapse>
@@ -21,7 +21,7 @@ import {
21
21
  } from "@firecms/ui";
22
22
 
23
23
  import { FieldHelperView } from "./properties/FieldHelperView";
24
- import { useFormex, Field, getIn } from "@firecms/formex";
24
+ import { Field, getIn, useFormex } from "@firecms/formex";
25
25
 
26
26
  export function CollectionDetailsForm({
27
27
  isNewCollection,
@@ -70,7 +70,7 @@ export function CollectionDetailsForm({
70
70
 
71
71
  const singularNameTouched = getIn(touched, "singularName");
72
72
  if (!singularNameTouched && isNewCollection && name) {
73
- setFieldValue("singularName", singular(name))
73
+ setFieldValue("singularName", singular(name));
74
74
  }
75
75
 
76
76
  };
@@ -107,6 +107,8 @@ export function CollectionDetailsForm({
107
107
  customIdValue = "optional";
108
108
  }
109
109
  }
110
+
111
+ const showErrors = submitCount > 0;
110
112
  return (
111
113
  <div className={"overflow-auto my-auto"}>
112
114
  <Container maxWidth={"4xl"} className={"flex flex-col gap-4 p-8 m-auto"}>
@@ -141,7 +143,7 @@ export function CollectionDetailsForm({
141
143
  onChange={(e: any) => updateName(e.target.value)}
142
144
  label={"Name"}
143
145
  required
144
- error={touched.name && Boolean(errors.name)}/>
146
+ error={showErrors && Boolean(errors.name)}/>
145
147
  <FieldHelperView error={touched.name && Boolean(errors.name)}>
146
148
  {touched.name && Boolean(errors.name) ? errors.name : "Name of in this collection, usually a plural name (e.g. Products)"}
147
149
  </FieldHelperView>
@@ -153,7 +155,7 @@ export function CollectionDetailsForm({
153
155
  label={"Path"}
154
156
  disabled={!isNewCollection}
155
157
  required
156
- error={touched.path && Boolean(errors.path)}/>
158
+ error={showErrors && Boolean(errors.path)}/>
157
159
 
158
160
  <FieldHelperView error={touched.path && Boolean(errors.path)}>
159
161
  {touched.path && Boolean(errors.path)
@@ -165,7 +167,7 @@ export function CollectionDetailsForm({
165
167
 
166
168
  {!isSubcollection && <div className={"col-span-12 sm:col-span-4 relative"}>
167
169
 
168
- <TextField error={touched.group && Boolean(errors.group)}
170
+ <TextField error={showErrors && Boolean(errors.group)}
169
171
  disabled={isSubmitting}
170
172
  value={values.group ?? ""}
171
173
  autoComplete="off"
@@ -191,7 +193,7 @@ export function CollectionDetailsForm({
191
193
  })}
192
194
  </Autocomplete>
193
195
  <FieldHelperView>
194
- {touched.group && Boolean(errors.group) ? errors.group : "Group of the collection"}
196
+ {showErrors && Boolean(errors.group) ? errors.group : "Group of the collection"}
195
197
  </FieldHelperView>
196
198
  </div>}
197
199
 
@@ -215,7 +217,7 @@ export function CollectionDetailsForm({
215
217
  as={DebouncedTextField}
216
218
  disabled={!isNewCollection}
217
219
  label={"Collection id"}
218
- error={touched.id && Boolean(errors.id)}/>
220
+ error={showErrors && Boolean(errors.id)}/>
219
221
  <FieldHelperView error={touched.id && Boolean(errors.id)}>
220
222
  {touched.id && Boolean(errors.id) ? errors.id : "This id identifies this collection"}
221
223
  </FieldHelperView>
@@ -223,7 +225,7 @@ export function CollectionDetailsForm({
223
225
 
224
226
  <div className={"col-span-12"}>
225
227
  <TextField
226
- error={touched.singularName && Boolean(errors.singularName)}
228
+ error={showErrors && Boolean(errors.singularName)}
227
229
  id={"singularName"}
228
230
  aria-describedby={"singularName-helper"}
229
231
  onChange={(e) => {
@@ -232,13 +234,13 @@ export function CollectionDetailsForm({
232
234
  }}
233
235
  value={values.singularName ?? ""}
234
236
  label={"Singular name"}/>
235
- <FieldHelperView error={touched.singularName && Boolean(errors.singularName)}>
236
- {touched.singularName && Boolean(errors.singularName) ? errors.singularName : "Optionally define a singular name for your entities"}
237
+ <FieldHelperView error={showErrors && Boolean(errors.singularName)}>
238
+ {showErrors && Boolean(errors.singularName) ? errors.singularName : "Optionally define a singular name for your entities"}
237
239
  </FieldHelperView>
238
240
  </div>
239
241
  <div className={"col-span-12"}>
240
242
  <TextField
241
- error={touched.description && Boolean(errors.description)}
243
+ error={showErrors && Boolean(errors.description)}
242
244
  id="description"
243
245
  value={values.description ?? ""}
244
246
  onChange={handleChange}
@@ -247,8 +249,8 @@ export function CollectionDetailsForm({
247
249
  aria-describedby="description-helper-text"
248
250
  label="Description"
249
251
  />
250
- <FieldHelperView error={touched.description && Boolean(errors.description)}>
251
- {touched.description && Boolean(errors.description) ? errors.description : "Description of the collection, you can use markdown"}
252
+ <FieldHelperView error={showErrors && Boolean(errors.description)}>
253
+ {showErrors && Boolean(errors.description) ? errors.description : "Description of the collection, you can use markdown"}
252
254
  </FieldHelperView>
253
255
  </div>
254
256
 
@@ -261,6 +261,7 @@ 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 })
264
265
 
265
266
  // Use this ref to store which properties have errors
266
267
  const propertyErrorsRef = useRef({});
@@ -374,7 +375,6 @@ function CollectionEditorInternal<M extends Record<string, any>>({
374
375
  if (!isNewCollection) {
375
376
  saveCollection(newCollectionState).then(() => {
376
377
  formexController.resetForm({ values: initialValues });
377
- // setNextMode();
378
378
  handleClose(newCollectionState);
379
379
  });
380
380
  return;
@@ -482,7 +482,6 @@ function CollectionEditorInternal<M extends Record<string, any>>({
482
482
  const resolvedPath = !pathError ? navigation.resolveAliasesFrom(updatedFullPath) : undefined;
483
483
  const getDataWithPath = resolvedPath && getData ? () => getData(resolvedPath, parentPaths ?? []) : undefined;
484
484
 
485
- // eslint-disable-next-line react-hooks/rules-of-hooks
486
485
  useEffect(() => {
487
486
  setFormDirty(dirty);
488
487
  }, [dirty]);
@@ -552,9 +551,9 @@ function CollectionEditorInternal<M extends Record<string, any>>({
552
551
  {currentView === "welcome" &&
553
552
  <CollectionEditorWelcomeView
554
553
  path={path}
555
- onContinue={(data) => {
556
- if (data) {
557
- onImportDataSet(data);
554
+ onContinue={(importData) => {
555
+ if (importData) {
556
+ onImportDataSet(importData);
558
557
  setCurrentView("import_data_mapping");
559
558
  } else {
560
559
  setCurrentView("details");
@@ -577,12 +576,13 @@ function CollectionEditorInternal<M extends Record<string, any>>({
577
576
  {currentView === "import_data_saving" && importConfig &&
578
577
  <ImportSaveInProgress importConfig={importConfig}
579
578
  collection={values}
580
- onImportSuccess={(importedCollection) => {
581
- handleClose(importedCollection);
579
+ onImportSuccess={async (importedCollection) => {
582
580
  snackbarController.open({
583
581
  type: "info",
584
582
  message: "Data imported successfully"
585
583
  });
584
+ await saveCollection(values);
585
+ handleClose(importedCollection);
586
586
  }}
587
587
  />}
588
588
 
@@ -649,7 +649,6 @@ function CollectionEditorInternal<M extends Record<string, any>>({
649
649
  <Button variant={"text"}
650
650
  type="button"
651
651
  onClick={() => {
652
- saveCollection(values);
653
652
  setCurrentView("import_data_mapping");
654
653
  }}>
655
654
  <ArrowBackIcon/>
@@ -718,7 +717,6 @@ function CollectionEditorInternal<M extends Record<string, any>>({
718
717
  color="primary"
719
718
  type="submit"
720
719
  loading={isSubmitting}
721
- // disabled={isSubmitting || !dirty}
722
720
  >
723
721
  Update collection
724
722
  </LoadingButton>}
@@ -99,7 +99,7 @@ function collectionToCode(collection: EntityCollection): object {
99
99
  customId: collection.customId,
100
100
  initialFilter: collection.initialFilter,
101
101
  initialSort: collection.initialSort,
102
- properties: Object.entries(collection.properties)
102
+ properties: Object.entries(collection.properties ?? {})
103
103
  .map(([key, value]) => ({
104
104
  [key]: propertyCleanup(value)
105
105
  }))
@@ -140,7 +140,7 @@ export function CollectionEditorImportMapping({
140
140
 
141
141
  return (
142
142
 
143
- <div className={"overflow-auto my-auto bg-gray-50 dark:bg-gray-900"}>
143
+ <div className={"overflow-auto my-auto"}>
144
144
  <Container maxWidth={"6xl"} className={"flex flex-col gap-4 p-8 m-auto"}>
145
145
 
146
146
  <Typography variant="h6" className={"mt-4"}>Data property mapping</Typography>
@@ -1,13 +1,5 @@
1
1
  import React from "react";
2
- import {
3
- EntityCollection,
4
- FireCMSPlugin,
5
- joinCollectionLists,
6
- makePropertiesEditable,
7
- ModifyCollectionProps,
8
- Properties,
9
- User
10
- } from "@firecms/core";
2
+ import { FireCMSPlugin, useAuthController, useNavigationController, User } from "@firecms/core";
11
3
  import { ConfigControllerProvider } from "./ConfigControllerProvider";
12
4
  import { CollectionEditorPermissionsBuilder } from "./types/config_permissions";
13
5
  import { EditorCollectionAction } from "./ui/EditorCollectionAction";
@@ -20,6 +12,8 @@ import { RootCollectionSuggestions } from "./ui/RootCollectionSuggestions";
20
12
  import { CollectionViewHeaderAction } from "./ui/CollectionViewHeaderAction";
21
13
  import { PropertyAddColumnComponent } from "./ui/PropertyAddColumnComponent";
22
14
  import { NewCollectionButton } from "./ui/NewCollectionButton";
15
+ import { AddIcon, Button, Typography } from "@firecms/ui";
16
+ import { useCollectionEditorController } from "./useCollectionEditorController";
23
17
 
24
18
  export interface CollectionConfigControllerProps<EC extends PersistedCollection = PersistedCollection, UserType extends User = User> {
25
19
 
@@ -28,8 +22,6 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
28
22
  */
29
23
  collectionConfigController: CollectionsConfigController;
30
24
 
31
- modifyCollection?: (props: ModifyCollectionProps) => EntityCollection | void;
32
-
33
25
  /**
34
26
  * Define what actions can be performed on the configuration.
35
27
  */
@@ -59,6 +51,8 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
59
51
 
60
52
  onAnalyticsEvent?: (event: string, params?: object) => void;
61
53
 
54
+ introMode?: "new_project" | "existing_project";
55
+
62
56
  }
63
57
 
64
58
  /**
@@ -75,7 +69,7 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
75
69
  export function useCollectionEditorPlugin<EC extends PersistedCollection = PersistedCollection, UserType extends User = User>
76
70
  ({
77
71
  collectionConfigController,
78
- modifyCollection,
72
+ introMode,
79
73
  configPermissions,
80
74
  reservedGroups,
81
75
  extraView,
@@ -86,8 +80,6 @@ export function useCollectionEditorPlugin<EC extends PersistedCollection = Persi
86
80
  onAnalyticsEvent
87
81
  }: CollectionConfigControllerProps<EC, UserType>): FireCMSPlugin<any, any, PersistedCollection> {
88
82
 
89
-
90
-
91
83
  return {
92
84
  name: "Collection Editor",
93
85
  loading: collectionConfigController.loading,
@@ -110,9 +102,10 @@ export function useCollectionEditorPlugin<EC extends PersistedCollection = Persi
110
102
  },
111
103
  homePage: {
112
104
  additionalActions: <NewCollectionButton/>,
113
- additionalChildrenEnd: <RootCollectionSuggestions/>,
105
+ additionalChildrenStart: introMode ? <IntroWidget introMode={introMode}/> : undefined,
106
+ additionalChildrenEnd: <RootCollectionSuggestions introMode={introMode}/>,
114
107
  CollectionActions: HomePageEditorCollectionAction,
115
- AdditionalCards: NewCollectionCard,
108
+ AdditionalCards: introMode ? undefined : NewCollectionCard,
116
109
  },
117
110
  collectionView: {
118
111
  HeaderAction: CollectionViewHeaderAction,
@@ -120,3 +113,44 @@ export function useCollectionEditorPlugin<EC extends PersistedCollection = Persi
120
113
  }
121
114
  };
122
115
  }
116
+
117
+ export function IntroWidget({ introMode }: {
118
+ introMode?: "new_project" | "existing_project";
119
+ }) {
120
+
121
+ const navigation = useNavigationController();
122
+ if (!navigation.topLevelNavigation)
123
+ throw Error("Navigation not ready in FireCMSHomePage");
124
+
125
+ const authController = useAuthController();
126
+
127
+ const collectionEditorController = useCollectionEditorController();
128
+ const canCreateCollections = collectionEditorController.configPermissions
129
+ ? collectionEditorController.configPermissions({
130
+ user: authController.user,
131
+ }).createCollections
132
+ : true;
133
+
134
+ return (
135
+ <div className={"mt-8 flex flex-col mt-8 p-2"}>
136
+ <Typography variant={"h4"} className="mb-4">Welcome</Typography>
137
+ <Typography paragraph={true}>Your admin panel is ready ✌️</Typography>
138
+ <Typography paragraph={true}>
139
+ Start building collections in FireCMS easily. Map them to your existing
140
+ database data, import from files, or use our templates. Simplify your data management process
141
+ now.
142
+ </Typography>
143
+ {canCreateCollections && <Button
144
+ className={"mt-4"}
145
+ onClick={collectionEditorController && canCreateCollections
146
+ ? () => collectionEditorController.createCollection({
147
+ parentCollectionIds: [],
148
+ redirect: true,
149
+ sourceClick: "new_collection_card"
150
+ })
151
+ : undefined}>
152
+ <AddIcon/>Create your first collection
153
+ </Button>}
154
+ </div>
155
+ );
156
+ }