@firecms/collection_editor 3.0.0-canary.7 → 3.0.0-canary.70

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 (56) 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 +1944 -1890
  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/types/persisted_collection.d.ts +1 -1
  10. package/dist/ui/EditorCollectionActionStart.d.ts +2 -0
  11. package/dist/ui/collection_editor/CollectionEditorDialog.d.ts +2 -2
  12. package/dist/ui/collection_editor/CollectionEditorWelcomeView.d.ts +1 -1
  13. package/dist/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +1 -1
  14. package/dist/ui/collection_editor/PropertyTree.d.ts +9 -9
  15. package/dist/ui/collection_editor/SubcollectionsEditTab.d.ts +1 -1
  16. package/dist/ui/collection_editor/utils/supported_fields.d.ts +2 -2
  17. package/dist/useCollectionEditorPlugin.d.ts +6 -9
  18. package/dist/utils/collections.d.ts +6 -0
  19. package/package.json +26 -26
  20. package/src/ConfigControllerProvider.tsx +53 -59
  21. package/src/index.ts +1 -0
  22. package/src/types/collection_editor_controller.tsx +1 -1
  23. package/src/types/persisted_collection.ts +1 -1
  24. package/src/ui/EditorCollectionAction.tsx +0 -51
  25. package/src/ui/EditorCollectionActionStart.tsx +87 -0
  26. package/src/ui/HomePageEditorCollectionAction.tsx +16 -11
  27. package/src/ui/MissingReferenceWidget.tsx +2 -1
  28. package/src/ui/NewCollectionButton.tsx +12 -10
  29. package/src/ui/NewCollectionCard.tsx +3 -3
  30. package/src/ui/collection_editor/CollectionDetailsForm.tsx +51 -22
  31. package/src/ui/collection_editor/CollectionEditorDialog.tsx +49 -32
  32. package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +5 -5
  33. package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +27 -24
  34. package/src/ui/collection_editor/EnumForm.tsx +3 -4
  35. package/src/ui/collection_editor/GetCodeDialog.tsx +15 -3
  36. package/src/ui/collection_editor/PropertyEditView.tsx +9 -8
  37. package/src/ui/collection_editor/PropertyFieldPreview.tsx +3 -6
  38. package/src/ui/collection_editor/PropertySelectItem.tsx +2 -2
  39. package/src/ui/collection_editor/PropertyTree.tsx +3 -3
  40. package/src/ui/collection_editor/SubcollectionsEditTab.tsx +1 -1
  41. package/src/ui/collection_editor/import/CollectionEditorImportDataPreview.tsx +25 -9
  42. package/src/ui/collection_editor/import/CollectionEditorImportMapping.tsx +9 -7
  43. package/src/ui/collection_editor/properties/BlockPropertyField.tsx +14 -8
  44. package/src/ui/collection_editor/properties/CommonPropertyFields.tsx +7 -8
  45. package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +7 -8
  46. package/src/ui/collection_editor/properties/MapPropertyField.tsx +8 -9
  47. package/src/ui/collection_editor/properties/ReferencePropertyField.tsx +3 -4
  48. package/src/ui/collection_editor/properties/RepeatPropertyField.tsx +0 -1
  49. package/src/ui/collection_editor/properties/validation/StringPropertyValidation.tsx +3 -4
  50. package/src/ui/collection_editor/utils/supported_fields.tsx +3 -3
  51. package/src/useCollectionEditorPlugin.tsx +29 -30
  52. package/src/utils/collections.ts +30 -0
  53. package/dist/ui/RootCollectionSuggestions.d.ts +0 -3
  54. package/dist/ui/collection_editor/properties/FieldHelperView.d.ts +0 -4
  55. package/src/ui/RootCollectionSuggestions.tsx +0 -63
  56. package/src/ui/collection_editor/properties/FieldHelperView.tsx +0 -13
@@ -1,11 +1,10 @@
1
- import React, { useCallback, useState } from "react";
2
- import { MapProperty, Property, PropertyConfig, } from "@firecms/core";
1
+ import React, { useState } from "react";
2
+ import { FieldCaption, MapProperty, Property, PropertyConfig, } from "@firecms/core";
3
3
  import { AddIcon, BooleanSwitchWithLabel, Button, Paper, Typography } from "@firecms/ui";
4
4
  import { PropertyFormDialog } from "../PropertyEditView";
5
5
  import { getIn, useFormex } from "@firecms/formex";
6
6
  import { PropertyTree } from "../PropertyTree";
7
7
  import { getFullId, idToPropertiesPath, namespaceToPropertiesOrderPath, namespaceToPropertiesPath } from "../util";
8
- import { FieldHelperView } from "./FieldHelperView";
9
8
 
10
9
  export function MapPropertyField({ disabled, getData, allowDataInference, propertyConfigs, collectionEditable }: {
11
10
  disabled: boolean;
@@ -43,7 +42,7 @@ export function MapPropertyField({ disabled, getData, allowDataInference, proper
43
42
  setPropertyDialogOpen(false);
44
43
  };
45
44
 
46
- const deleteProperty = useCallback((propertyKey?: string, namespace?: string) => {
45
+ const deleteProperty = (propertyKey?: string, namespace?: string) => {
47
46
  const fullId = propertyKey ? getFullId(propertyKey, namespace) : undefined;
48
47
  if (!fullId)
49
48
  throw Error("collection editor miss config");
@@ -59,16 +58,16 @@ export function MapPropertyField({ disabled, getData, allowDataInference, proper
59
58
  setPropertyDialogOpen(false);
60
59
  setSelectedPropertyKey(undefined);
61
60
  setSelectedPropertyNamespace(undefined);
62
- }, [setFieldValue, values]);
61
+ };
63
62
 
64
63
  const selectedPropertyFullId = selectedPropertyKey ? getFullId(selectedPropertyKey, selectedPropertyNamespace) : undefined;
65
64
  const selectedProperty = selectedPropertyFullId ? getIn(values.properties, selectedPropertyFullId.replaceAll(".", ".properties.")) : undefined;
66
65
 
67
66
  const empty = !propertiesOrder || propertiesOrder.length < 1;
68
67
 
69
- const onPropertyMove = useCallback((propertiesOrder: string[], namespace?: string) => {
68
+ const onPropertyMove = (propertiesOrder: string[], namespace?: string) => {
70
69
  setFieldValue(namespaceToPropertiesOrderPath(namespace), propertiesOrder, false);
71
- }, []);
70
+ };
72
71
 
73
72
  return (
74
73
  <>
@@ -113,9 +112,9 @@ export function MapPropertyField({ disabled, getData, allowDataInference, proper
113
112
  onValueChange={(v) => setFieldValue("spreadChildren", v)}
114
113
  value={values.spreadChildren ?? false}
115
114
  />
116
- <FieldHelperView>
115
+ <FieldCaption>
117
116
  Set this flag to true if you want to display the children of this group as individual columns.
118
- </FieldHelperView>
117
+ </FieldCaption>
119
118
  </div>
120
119
 
121
120
  <PropertyFormDialog
@@ -1,8 +1,7 @@
1
1
  import React from "react";
2
2
  import { Field, getIn, useFormex } from "@firecms/formex";
3
- import { IconForView, NumberProperty, StringProperty, useNavigationController } from "@firecms/core";
3
+ import { FieldCaption, IconForView, NumberProperty, StringProperty, useNavigationController } from "@firecms/core";
4
4
  import { CircularProgress, Select, SelectGroup, SelectItem, Typography, } from "@firecms/ui";
5
- import { FieldHelperView } from "./FieldHelperView";
6
5
 
7
6
  export function ReferencePropertyField({
8
7
  existing,
@@ -152,10 +151,10 @@ export function CollectionsSelect({
152
151
 
153
152
  </Select>
154
153
 
155
- <FieldHelperView>
154
+ <FieldCaption>
156
155
  You can only edit the reference collection upon field
157
156
  creation.
158
- </FieldHelperView>
157
+ </FieldCaption>
159
158
  </>
160
159
  );
161
160
  }
@@ -39,7 +39,6 @@ export function RepeatPropertyField({
39
39
 
40
40
  const onPropertyChanged = ({ id, property, namespace }:
41
41
  { id?: string, property: Property, namespace?: string }) => {
42
- console.log("onPropertyChanged", id, property, namespace);
43
42
  setFieldValue("of", property);
44
43
  };
45
44
 
@@ -1,10 +1,9 @@
1
1
  import React from "react";
2
2
 
3
3
  import { Field, FormexFieldProps, getIn, useFormex } from "@firecms/formex";
4
- import { serializeRegExp } from "@firecms/core";
4
+ import { FieldCaption, serializeRegExp } from "@firecms/core";
5
5
  import { DebouncedTextField, } from "@firecms/ui";
6
6
  import { GeneralPropertyValidation } from "./GeneralPropertyValidation";
7
- import { FieldHelperView } from "../FieldHelperView";
8
7
  import { SwitchControl } from "../../SwitchControl";
9
8
 
10
9
  export function StringPropertyValidation({
@@ -140,9 +139,9 @@ export function StringPropertyValidation({
140
139
  disabled={disabled}
141
140
  value={matchesStringValue}
142
141
  error={Boolean(matchesError)}/>
143
- <FieldHelperView error={Boolean(matchesError)}>
142
+ <FieldCaption error={Boolean(matchesError)}>
144
143
  {matchesError ? "Not a valid regexp" : "e.g. /^\\d+$/ for digits only"}
145
- </FieldHelperView>
144
+ </FieldCaption>
146
145
  </div>}
147
146
 
148
147
  </div>
@@ -1,6 +1,6 @@
1
- import { DEFAULT_FIELD_CONFIGS, FieldConfigId, PropertyConfig } from "@firecms/core";
1
+ import { DEFAULT_FIELD_CONFIGS, PropertyConfigId, PropertyConfig } from "@firecms/core";
2
2
 
3
- export const supportedFieldsIds: FieldConfigId[] = [
3
+ export const supportedFieldsIds: PropertyConfigId[] = [
4
4
  "text_field",
5
5
  "multiline",
6
6
  "markdown",
@@ -24,6 +24,6 @@ export const supportedFieldsIds: FieldConfigId[] = [
24
24
  ];
25
25
 
26
26
  export const supportedFields: Record<string, PropertyConfig> = Object.entries(DEFAULT_FIELD_CONFIGS)
27
- .filter(([id]) => supportedFieldsIds.includes(id as FieldConfigId))
27
+ .filter(([id]) => supportedFieldsIds.includes(id as PropertyConfigId))
28
28
  .map(([id, config]) => ({ [id]: config }))
29
29
  .reduce((a, b) => ({ ...a, ...b }), {});
@@ -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,
@@ -81,11 +78,8 @@ export function useCollectionEditorPlugin<EC extends PersistedCollection = Persi
81
78
  }: CollectionConfigControllerProps<EC, UserType>): FireCMSPlugin<any, any, PersistedCollection> {
82
79
 
83
80
  return {
84
- name: "Collection Editor",
81
+ key: "collection_editor",
85
82
  loading: collectionConfigController.loading,
86
- collections: {
87
- CollectionActions: EditorCollectionAction
88
- },
89
83
  provider: {
90
84
  Component: ConfigControllerProvider,
91
85
  props: {
@@ -94,7 +88,7 @@ export function useCollectionEditorPlugin<EC extends PersistedCollection = Persi
94
88
  collectionInference,
95
89
  reservedGroups,
96
90
  extraView,
97
- pathSuggestions,
91
+ getPathSuggestions,
98
92
  getUser,
99
93
  getData,
100
94
  onAnalyticsEvent
@@ -102,21 +96,21 @@ export function useCollectionEditorPlugin<EC extends PersistedCollection = Persi
102
96
  },
103
97
  homePage: {
104
98
  additionalActions: <NewCollectionButton/>,
105
- additionalChildrenStart: introMode ? <IntroWidget introMode={introMode}/> : undefined,
106
- additionalChildrenEnd: <RootCollectionSuggestions introMode={introMode}/>,
99
+ additionalChildrenStart: <IntroWidget/>,
100
+ // additionalChildrenEnd: <RootCollectionSuggestions introMode={introMode}/>,
107
101
  CollectionActions: HomePageEditorCollectionAction,
108
- AdditionalCards: introMode ? undefined : NewCollectionCard,
102
+ AdditionalCards: NewCollectionCard,
109
103
  },
110
104
  collectionView: {
105
+ CollectionActionsStart: EditorCollectionActionStart,
106
+ CollectionActions: EditorCollectionAction,
111
107
  HeaderAction: CollectionViewHeaderAction,
112
108
  AddColumnComponent: PropertyAddColumnComponent
113
109
  }
114
110
  };
115
111
  }
116
112
 
117
- export function IntroWidget({ introMode }: {
118
- introMode?: "new_project" | "existing_project";
119
- }) {
113
+ export function IntroWidget({}: {}) {
120
114
 
121
115
  const navigation = useNavigationController();
122
116
  if (!navigation.topLevelNavigation)
@@ -131,17 +125,19 @@ export function IntroWidget({ introMode }: {
131
125
  }).createCollections
132
126
  : true;
133
127
 
128
+ if (!navigation.initialised || (navigation.collections ?? []).length > 0) {
129
+ return null;
130
+ }
131
+
134
132
  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}>
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>
139
137
  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.
138
+ database data, import from files, or use our templates.
142
139
  </Typography>
143
140
  {canCreateCollections && <Button
144
- className={"mt-4"}
145
141
  onClick={collectionEditorController && canCreateCollections
146
142
  ? () => collectionEditorController.createCollection({
147
143
  parentCollectionIds: [],
@@ -151,6 +147,9 @@ export function IntroWidget({ introMode }: {
151
147
  : undefined}>
152
148
  <AddIcon/>Create your first collection
153
149
  </Button>}
154
- </div>
150
+ <Typography variant={"caption"} color={"secondary"}>
151
+ You can also define collections programmatically.
152
+ </Typography>
153
+ </Paper>
155
154
  );
156
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,4 +0,0 @@
1
- export declare function FieldHelperView({ error, children }: {
2
- error?: boolean;
3
- children?: React.ReactNode;
4
- }): import("react/jsx-runtime").JSX.Element | null;
@@ -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
- }
@@ -1,13 +0,0 @@
1
- import { Typography } from "@firecms/ui";
2
-
3
- export function FieldHelperView({
4
- error,
5
- children
6
- }: { error?: boolean, children?: React.ReactNode }) {
7
- if (!children) return null;
8
- return (
9
- <Typography variant={"caption"} color={error ? "error" : "secondary"} className={"ml-3.5 mt-0.5"}>
10
- {children}
11
- </Typography>
12
- );
13
- }