@firecms/collection_editor 3.0.0-beta.5 → 3.0.0-beta.6

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 (34) hide show
  1. package/LICENSE +113 -21
  2. package/dist/ConfigControllerProvider.d.ts +2 -2
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.es.js +1721 -1712
  5. package/dist/index.es.js.map +1 -1
  6. package/dist/index.umd.js +2 -2
  7. package/dist/index.umd.js.map +1 -1
  8. package/dist/types/collection_editor_controller.d.ts +1 -1
  9. package/dist/ui/EditorCollectionActionStart.d.ts +2 -0
  10. package/dist/ui/collection_editor/CollectionEditorDialog.d.ts +1 -1
  11. package/dist/ui/collection_editor/CollectionEditorWelcomeView.d.ts +1 -1
  12. package/dist/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +1 -1
  13. package/dist/ui/collection_editor/PropertyTree.d.ts +9 -9
  14. package/dist/ui/collection_editor/SubcollectionsEditTab.d.ts +1 -1
  15. package/dist/useCollectionEditorPlugin.d.ts +6 -9
  16. package/dist/utils/collections.d.ts +6 -0
  17. package/package.json +14 -14
  18. package/src/ConfigControllerProvider.tsx +28 -34
  19. package/src/index.ts +1 -0
  20. package/src/types/collection_editor_controller.tsx +1 -1
  21. package/src/ui/EditorCollectionAction.tsx +0 -51
  22. package/src/ui/EditorCollectionActionStart.tsx +87 -0
  23. package/src/ui/collection_editor/CollectionDetailsForm.tsx +1 -1
  24. package/src/ui/collection_editor/CollectionEditorDialog.tsx +26 -11
  25. package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +2 -2
  26. package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +2 -2
  27. package/src/ui/collection_editor/SubcollectionsEditTab.tsx +1 -1
  28. package/src/ui/collection_editor/import/CollectionEditorImportDataPreview.tsx +23 -8
  29. package/src/ui/collection_editor/import/CollectionEditorImportMapping.tsx +9 -7
  30. package/src/ui/collection_editor/properties/BlockPropertyField.tsx +9 -3
  31. package/src/useCollectionEditorPlugin.tsx +27 -26
  32. package/src/utils/collections.ts +30 -0
  33. package/dist/ui/RootCollectionSuggestions.d.ts +0 -3
  34. package/src/ui/RootCollectionSuggestions.tsx +0 -63
@@ -1,21 +1,33 @@
1
- import { convertDataToEntity, getPropertiesMapping, ImportConfig } from "@firecms/data_import_export";
2
- import { EntityCollectionTable, Properties, useSelectionController } from "@firecms/core";
3
- import { useEffect } from "react";
1
+ import { convertDataToEntity, ImportConfig } from "@firecms/data_import_export";
2
+ import { CircularProgressCenter, EntityCollectionTable, Properties, useSelectionController } from "@firecms/core";
3
+ import { useEffect, useState } from "react";
4
4
  import { Typography } from "@firecms/ui";
5
5
 
6
- export function CollectionEditorImportDataPreview({ importConfig, properties, propertiesOrder }: {
6
+ export function CollectionEditorImportDataPreview({
7
+ importConfig,
8
+ properties,
9
+ propertiesOrder
10
+ }: {
7
11
  importConfig: ImportConfig,
8
12
  properties: Properties,
9
13
  propertiesOrder: string[]
10
14
  }) {
11
15
 
12
- useEffect(() => {
13
- const propertiesMapping = getPropertiesMapping(importConfig.originProperties, properties);
14
- const mappedData = importConfig.importData.map(d => convertDataToEntity(d, importConfig.idColumn, importConfig.headersMapping, properties, propertiesMapping, "TEMP_PATH"));
16
+ const [loading, setLoading] = useState<boolean>(false);
17
+
18
+ async function loadEntities() {
19
+ // const propertiesMapping = getPropertiesMapping(importConfig.originProperties, properties, importConfig.headersMapping);
20
+ const mappedData = importConfig.importData.map(d => convertDataToEntity(d, importConfig.idColumn, importConfig.headersMapping, properties, "TEMP_PATH", importConfig.defaultValues));
15
21
  importConfig.setEntities(mappedData);
22
+ }
23
+
24
+ useEffect(() => {
25
+ loadEntities().finally(() => setLoading(false));
16
26
  }, []);
17
27
 
18
28
  const selectionController = useSelectionController();
29
+ if (loading)
30
+ return <CircularProgressCenter/>
19
31
 
20
32
  return <EntityCollectionTable
21
33
  title={<div>
@@ -31,7 +43,10 @@ export function CollectionEditorImportDataPreview({ importConfig, properties, pr
31
43
  filterable={false}
32
44
  sortable={false}
33
45
  selectionController={selectionController}
34
- displayedColumnIds={propertiesOrder.map(p => ({ key: p, disabled: false }))}
46
+ displayedColumnIds={propertiesOrder.map(p => ({
47
+ key: p,
48
+ disabled: false
49
+ }))}
35
50
  properties={properties}/>
36
51
 
37
52
  }
@@ -6,7 +6,7 @@ import {
6
6
  } from "@firecms/data_import_export";
7
7
  import { getIn, useFormex } from "@firecms/formex";
8
8
 
9
- import { PropertyConfigBadge, getFieldConfig, getFieldId, Properties, Property, PropertyConfig, } from "@firecms/core";
9
+ import { getFieldConfig, getFieldId, Properties, Property, PropertyConfig, PropertyConfigBadge, } from "@firecms/core";
10
10
  import { Container, Select, Tooltip, Typography } from "@firecms/ui";
11
11
  import React, { useState } from "react";
12
12
  import { OnPropertyChangedParams, PropertyFormDialog, PropertyWithId } from "../PropertyEditView";
@@ -143,18 +143,20 @@ export function CollectionEditorImportMapping({
143
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
- <Typography variant="h6" className={"mt-4"}>Data property mapping</Typography>
146
+ <Typography variant="h6" className={"my-4 ml-3.5"}>Data property mapping</Typography>
147
147
 
148
- <DataNewPropertiesMapping headersMapping={importConfig.headersMapping}
149
- idColumn={importConfig.idColumn}
150
- originProperties={importConfig.originProperties}
148
+ <DataNewPropertiesMapping importConfig={importConfig}
151
149
  destinationProperties={values.properties as Properties}
152
- onIdPropertyChanged={(value) => importConfig.setIdColumn(value ?? undefined)}
153
150
  buildPropertyView={({
154
151
  property,
155
152
  propertyKey,
156
- importKey
153
+ importKey,
154
+ isIdColumn
157
155
  }) => {
156
+ if (isIdColumn) {
157
+ return <Typography> This column will be used as ID</Typography>
158
+ }
159
+
158
160
  return <ImportNewPropertyFieldPreview
159
161
  property={property}
160
162
  propertyKey={propertyKey}
@@ -2,11 +2,17 @@ import React, { useCallback, useState } from "react";
2
2
  import { AddIcon, Button, Paper, Typography } from "@firecms/ui";
3
3
  import { getIn, useFormex } from "@firecms/formex";
4
4
  import { PropertyFormDialog } from "../PropertyEditView";
5
- import { getFullId, idToPropertiesPath, namespaceToPropertiesOrderPath } from "../util";
5
+ import { getFullId, idToPropertiesPath, namespaceToPropertiesOrderPath, namespaceToPropertiesPath } from "../util";
6
6
  import { PropertyTree } from "../PropertyTree";
7
7
  import { ArrayProperty, Property, PropertyConfig } from "@firecms/core";
8
8
 
9
- export function BlockPropertyField({ disabled, getData, allowDataInference, propertyConfigs, collectionEditable }: {
9
+ export function BlockPropertyField({
10
+ disabled,
11
+ getData,
12
+ allowDataInference,
13
+ propertyConfigs,
14
+ collectionEditable
15
+ }: {
10
16
  disabled: boolean;
11
17
  getData?: () => Promise<object[]>;
12
18
  allowDataInference: boolean;
@@ -50,7 +56,7 @@ export function BlockPropertyField({ disabled, getData, allowDataInference, prop
50
56
 
51
57
  setFieldValue(`oneOf.${idToPropertiesPath(fullId)}`, undefined, false);
52
58
  const propertiesOrderPath = `oneOf.${namespaceToPropertiesOrderPath(namespace)}`;
53
- const currentPropertiesOrder: string[] = getIn(values, propertiesOrderPath);
59
+ const currentPropertiesOrder: string[] = getIn(values, propertiesOrderPath) ?? Object.keys(getIn(values, namespaceToPropertiesPath(namespace)));
54
60
  setFieldValue(propertiesOrderPath, currentPropertiesOrder.filter((p) => p !== propertyKey), false);
55
61
 
56
62
  setPropertyDialogOpen(false);
@@ -4,16 +4,16 @@ import { ConfigControllerProvider } from "./ConfigControllerProvider";
4
4
  import { CollectionEditorPermissionsBuilder } from "./types/config_permissions";
5
5
  import { EditorCollectionAction } from "./ui/EditorCollectionAction";
6
6
  import { HomePageEditorCollectionAction } from "./ui/HomePageEditorCollectionAction";
7
- import { NewCollectionCard } from "./ui/NewCollectionCard";
8
7
  import { PersistedCollection } from "./types/persisted_collection";
9
8
  import { CollectionInference } from "./types/collection_inference";
10
9
  import { CollectionsConfigController } from "./types/config_controller";
11
- import { RootCollectionSuggestions } from "./ui/RootCollectionSuggestions";
12
10
  import { CollectionViewHeaderAction } from "./ui/CollectionViewHeaderAction";
13
11
  import { PropertyAddColumnComponent } from "./ui/PropertyAddColumnComponent";
14
12
  import { NewCollectionButton } from "./ui/NewCollectionButton";
15
- import { AddIcon, Button, Typography } from "@firecms/ui";
13
+ import { AddIcon, Button, Paper, Typography } from "@firecms/ui";
16
14
  import { useCollectionEditorController } from "./useCollectionEditorController";
15
+ import { EditorCollectionActionStart } from "./ui/EditorCollectionActionStart";
16
+ import { NewCollectionCard } from "./ui/NewCollectionCard";
17
17
 
18
18
  export interface CollectionConfigControllerProps<EC extends PersistedCollection = PersistedCollection, UserType extends User = User> {
19
19
 
@@ -32,7 +32,7 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
32
32
  * names when creating collections.
33
33
  * e.g. ["admin"]
34
34
  */
35
- reservedGroups: string[];
35
+ reservedGroups?: string[];
36
36
 
37
37
  extraView?: {
38
38
  View: React.ComponentType<{
@@ -41,18 +41,16 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
41
41
  icon: React.ReactNode
42
42
  };
43
43
 
44
- pathSuggestions?: (path: string) => Promise<string[]>;
44
+ getPathSuggestions?: (path?: string) => Promise<string[]>;
45
45
 
46
46
  collectionInference?: CollectionInference;
47
47
 
48
48
  getData?: (path: string, parentPaths: string[]) => Promise<object[]>;
49
49
 
50
- getUser: (uid: string) => UserType | null;
50
+ getUser?: (uid: string) => UserType | null;
51
51
 
52
52
  onAnalyticsEvent?: (event: string, params?: object) => void;
53
53
 
54
- introMode?: "new_project" | "existing_project";
55
-
56
54
  }
57
55
 
58
56
  /**
@@ -62,18 +60,17 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
62
60
  * @param configPermissions
63
61
  * @param reservedGroups
64
62
  * @param extraView
65
- * @param pathSuggestions
63
+ * @param getPathsSuggestions
66
64
  * @param getUser
67
65
  * @param collectionInference
68
66
  */
69
67
  export function useCollectionEditorPlugin<EC extends PersistedCollection = PersistedCollection, UserType extends User = User>
70
68
  ({
71
69
  collectionConfigController,
72
- introMode,
73
70
  configPermissions,
74
71
  reservedGroups,
75
72
  extraView,
76
- pathSuggestions,
73
+ getPathSuggestions,
77
74
  getUser,
78
75
  collectionInference,
79
76
  getData,
@@ -91,7 +88,7 @@ export function useCollectionEditorPlugin<EC extends PersistedCollection = Persi
91
88
  collectionInference,
92
89
  reservedGroups,
93
90
  extraView,
94
- pathSuggestions,
91
+ getPathSuggestions,
95
92
  getUser,
96
93
  getData,
97
94
  onAnalyticsEvent
@@ -99,12 +96,13 @@ export function useCollectionEditorPlugin<EC extends PersistedCollection = Persi
99
96
  },
100
97
  homePage: {
101
98
  additionalActions: <NewCollectionButton/>,
102
- additionalChildrenStart: introMode ? <IntroWidget introMode={introMode}/> : undefined,
103
- additionalChildrenEnd: <RootCollectionSuggestions introMode={introMode}/>,
99
+ additionalChildrenStart: <IntroWidget/>,
100
+ // additionalChildrenEnd: <RootCollectionSuggestions introMode={introMode}/>,
104
101
  CollectionActions: HomePageEditorCollectionAction,
105
- AdditionalCards: introMode ? undefined : NewCollectionCard,
102
+ AdditionalCards: NewCollectionCard,
106
103
  },
107
104
  collectionView: {
105
+ CollectionActionsStart: EditorCollectionActionStart,
108
106
  CollectionActions: EditorCollectionAction,
109
107
  HeaderAction: CollectionViewHeaderAction,
110
108
  AddColumnComponent: PropertyAddColumnComponent
@@ -112,9 +110,7 @@ export function useCollectionEditorPlugin<EC extends PersistedCollection = Persi
112
110
  };
113
111
  }
114
112
 
115
- export function IntroWidget({ introMode }: {
116
- introMode?: "new_project" | "existing_project";
117
- }) {
113
+ export function IntroWidget({}: {}) {
118
114
 
119
115
  const navigation = useNavigationController();
120
116
  if (!navigation.topLevelNavigation)
@@ -129,17 +125,19 @@ export function IntroWidget({ introMode }: {
129
125
  }).createCollections
130
126
  : true;
131
127
 
128
+ if (!navigation.initialised || navigation.collections === undefined || (navigation.collections ?? []).length > 0) {
129
+ return null;
130
+ }
131
+
132
132
  return (
133
- <div className={"mt-8 flex flex-col mt-8 p-2"}>
134
- <Typography variant={"h4"} className="mb-4">Welcome</Typography>
135
- <Typography paragraph={true}>Your admin panel is ready ✌️</Typography>
136
- <Typography paragraph={true}>
133
+ <Paper
134
+ className={"my-4 px-4 py-6 flex flex-col bg-white dark:bg-slate-800 gap-2"}>
135
+ <Typography variant={"subtitle2"} className={"uppercase"}>No collections found</Typography>
136
+ <Typography>
137
137
  Start building collections in FireCMS easily. Map them to your existing
138
- database data, import from files, or use our templates. Simplify your data management process
139
- now.
138
+ database data, import from files, or use our templates.
140
139
  </Typography>
141
140
  {canCreateCollections && <Button
142
- className={"mt-4"}
143
141
  onClick={collectionEditorController && canCreateCollections
144
142
  ? () => collectionEditorController.createCollection({
145
143
  parentCollectionIds: [],
@@ -149,6 +147,9 @@ export function IntroWidget({ introMode }: {
149
147
  : undefined}>
150
148
  <AddIcon/>Create your first collection
151
149
  </Button>}
152
- </div>
150
+ <Typography variant={"caption"} color={"secondary"}>
151
+ You can also define collections programmatically.
152
+ </Typography>
153
+ </Paper>
153
154
  );
154
155
  }
@@ -0,0 +1,30 @@
1
+ import {
2
+ EntityCollection,
3
+ joinCollectionLists,
4
+ makePropertiesEditable,
5
+ ModifyCollectionProps,
6
+ Properties
7
+ } from "@firecms/core";
8
+ import { PersistedCollection } from "../types/persisted_collection";
9
+
10
+ /**
11
+ * Function in charge of merging collections defined in code with those stored in the backend.
12
+ */
13
+ export const mergeCollections = (baseCollections: EntityCollection[],
14
+ backendCollections: PersistedCollection[],
15
+ modifyCollection?: (props: ModifyCollectionProps) => EntityCollection | void
16
+ ) => {
17
+
18
+ const markAsEditable = (c: PersistedCollection) => {
19
+ makePropertiesEditable(c.properties as Properties);
20
+ c.subcollections?.forEach(markAsEditable);
21
+ };
22
+ const storedCollections = backendCollections ?? [];
23
+ storedCollections.forEach(markAsEditable);
24
+
25
+ console.debug("Collections specified in code:", baseCollections);
26
+ console.debug("Collections stored in the backend", storedCollections);
27
+ const result = joinCollectionLists(baseCollections, storedCollections, [], modifyCollection);
28
+ console.debug("Collections after joining:", result);
29
+ return result;
30
+ }
@@ -1,3 +0,0 @@
1
- export declare function RootCollectionSuggestions({ introMode }: {
2
- introMode?: "new_project" | "existing_project";
3
- }): import("react/jsx-runtime").JSX.Element;
@@ -1,63 +0,0 @@
1
- import { unslugify, useAuthController, useNavigationController } from "@firecms/core";
2
- import { AddIcon, Chip, CircularProgress, Collapse, Typography, } from "@firecms/ui";
3
- import { useCollectionEditorController } from "../useCollectionEditorController";
4
- import React from "react";
5
-
6
- export function RootCollectionSuggestions({ introMode }: { introMode?: "new_project" | "existing_project" }) {
7
-
8
- const authController = useAuthController();
9
- const navigationController = useNavigationController();
10
-
11
- const collectionEditorController = useCollectionEditorController();
12
- const canCreateCollections = collectionEditorController.configPermissions
13
- ? collectionEditorController.configPermissions({
14
- user: authController.user
15
- }).createCollections
16
- : true;
17
-
18
- const rootPathSuggestions = collectionEditorController.rootPathSuggestions;
19
-
20
- const showSuggestions = (rootPathSuggestions ?? []).length > 3 || ((navigationController.collections ?? []).length === 0 && (rootPathSuggestions ?? []).length > 0);
21
- const forceShowSuggestions = introMode === "existing_project";
22
- return <Collapse
23
- in={forceShowSuggestions || showSuggestions}>
24
-
25
- <div
26
- className={"flex flex-col gap-1 p-2 my-4"}>
27
-
28
- {!introMode && <Typography variant={"body2"} color={"secondary"}>
29
- Create a collection <b>automatically</b> from your data:
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>}
35
-
36
- <div
37
- className={"flex flex-row gap-1 overflow-scroll no-scrollbar "}>
38
- {(rootPathSuggestions ?? []).map((path) => {
39
- return (
40
- <div key={path}>
41
- <Chip
42
- icon={<AddIcon size={"small"}/>}
43
- colorScheme={"cyanLighter"}
44
- onClick={collectionEditorController && canCreateCollections
45
- ? () => collectionEditorController.createCollection({
46
- initialValues: { path, name: unslugify(path) },
47
- parentCollectionIds: [],
48
- redirect: true,
49
- sourceClick: "root_collection_suggestion"
50
- })
51
- : undefined}
52
- size="small">
53
- {path}
54
- </Chip>
55
- </div>
56
- );
57
- })}
58
- {rootPathSuggestions === undefined && <CircularProgress size={"small"}/>}
59
- {rootPathSuggestions?.length === 0 && <Typography variant={"caption"}>No suggestions</Typography>}
60
- </div>
61
- </div>
62
- </Collapse>
63
- }