@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
@@ -32,5 +32,5 @@ export interface CollectionEditorController {
32
32
  collection: PersistedCollection;
33
33
  }) => void;
34
34
  configPermissions: CollectionEditorPermissionsBuilder;
35
- rootPathSuggestions?: string[];
35
+ getPathSuggestions?: (path: string) => Promise<string[]>;
36
36
  }
@@ -0,0 +1,2 @@
1
+ import { CollectionActionsProps } from "@firecms/core";
2
+ export declare function EditorCollectionActionStart({ path: fullPath, parentCollectionIds, collection, tableController }: CollectionActionsProps): import("react/jsx-runtime").JSX.Element;
@@ -25,7 +25,7 @@ export interface CollectionEditorDialogProps {
25
25
  icon: React.ReactNode;
26
26
  };
27
27
  pathSuggestions?: (path?: string) => Promise<string[]>;
28
- getUser: (uid: string) => User | null;
28
+ getUser?: (uid: string) => User | null;
29
29
  getData?: (path: string, parentPaths: string[]) => Promise<object[]>;
30
30
  parentCollection?: PersistedCollection;
31
31
  }
@@ -4,7 +4,7 @@ export declare function CollectionEditorWelcomeView({ path, pathSuggestions, par
4
4
  path: string;
5
5
  pathSuggestions?: (path: string) => Promise<string[]>;
6
6
  parentCollection?: EntityCollection;
7
- onContinue: (importData?: object[]) => void;
7
+ onContinue: (importData?: object[], propertiesOrder?: string[]) => void;
8
8
  existingCollectionPaths?: string[];
9
9
  }): import("react/jsx-runtime").JSX.Element;
10
10
  export declare function TemplateButton({ title, subtitle, icon, onClick }: {
@@ -9,7 +9,7 @@ type CollectionEditorFormProps = {
9
9
  setDirty?: (dirty: boolean) => void;
10
10
  reservedGroups?: string[];
11
11
  extraIcon: React.ReactNode;
12
- getUser: (uid: string) => User | null;
12
+ getUser?: (uid: string) => User | null;
13
13
  getData?: () => Promise<object[]>;
14
14
  doCollectionInference: (collection: PersistedCollection) => Promise<Partial<EntityCollection> | null> | undefined;
15
15
  propertyConfigs: Record<string, PropertyConfig>;
@@ -4,17 +4,17 @@ import { DraggableProvided } from "@hello-pangea/dnd";
4
4
  export declare const PropertyTree: React.MemoExoticComponent<(<M extends {
5
5
  [Key: string]: CMSType;
6
6
  }>({ namespace, selectedPropertyKey, onPropertyClick, properties, propertiesOrder: propertiesOrderProp, additionalFields, errors, onPropertyMove, onPropertyRemove, className, inferredPropertyKeys, collectionEditable }: {
7
- namespace?: string | undefined;
8
- selectedPropertyKey?: string | undefined;
9
- onPropertyClick?: ((propertyKey: string, namespace?: string) => void) | undefined;
7
+ namespace?: string;
8
+ selectedPropertyKey?: string;
9
+ onPropertyClick?: (propertyKey: string, namespace?: string) => void;
10
10
  properties: PropertiesOrBuilders<M>;
11
- propertiesOrder?: string[] | undefined;
12
- additionalFields?: AdditionalFieldDelegate<M, import("@firecms/core").User>[] | undefined;
11
+ propertiesOrder?: string[];
12
+ additionalFields?: AdditionalFieldDelegate<M>[];
13
13
  errors: Record<string, any>;
14
- onPropertyMove?: ((propertiesOrder: string[], namespace?: string) => void) | undefined;
15
- onPropertyRemove?: ((propertyKey: string, namespace?: string) => void) | undefined;
16
- className?: string | undefined;
17
- inferredPropertyKeys?: string[] | undefined;
14
+ onPropertyMove?: (propertiesOrder: string[], namespace?: string) => void;
15
+ onPropertyRemove?: (propertyKey: string, namespace?: string) => void;
16
+ className?: string;
17
+ inferredPropertyKeys?: string[];
18
18
  collectionEditable: boolean;
19
19
  }) => import("react/jsx-runtime").JSX.Element)>;
20
20
  export declare function PropertyTreeEntry({ propertyKey, namespace, propertyOrBuilder, additionalField, provided, selectedPropertyKey, errors, onPropertyClick, onPropertyMove, onPropertyRemove, inferredPropertyKeys, collectionEditable }: {
@@ -7,6 +7,6 @@ export declare function SubcollectionsEditTab({ collection, parentCollection, co
7
7
  parentCollection?: EntityCollection;
8
8
  configController: CollectionsConfigController;
9
9
  collectionInference?: CollectionInference;
10
- getUser: (uid: string) => User | null;
10
+ getUser?: (uid: string) => User | null;
11
11
  parentCollectionIds?: string[];
12
12
  }): import("react/jsx-runtime").JSX.Element;
@@ -18,19 +18,18 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
18
18
  * names when creating collections.
19
19
  * e.g. ["admin"]
20
20
  */
21
- reservedGroups: string[];
21
+ reservedGroups?: string[];
22
22
  extraView?: {
23
23
  View: React.ComponentType<{
24
24
  path: string;
25
25
  }>;
26
26
  icon: React.ReactNode;
27
27
  };
28
- pathSuggestions?: (path: string) => Promise<string[]>;
28
+ getPathSuggestions?: (path?: string) => Promise<string[]>;
29
29
  collectionInference?: CollectionInference;
30
30
  getData?: (path: string, parentPaths: string[]) => Promise<object[]>;
31
- getUser: (uid: string) => UserType | null;
31
+ getUser?: (uid: string) => UserType | null;
32
32
  onAnalyticsEvent?: (event: string, params?: object) => void;
33
- introMode?: "new_project" | "existing_project";
34
33
  }
35
34
  /**
36
35
  * Use this hook to initialise the Collection Editor plugin.
@@ -39,11 +38,9 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
39
38
  * @param configPermissions
40
39
  * @param reservedGroups
41
40
  * @param extraView
42
- * @param pathSuggestions
41
+ * @param getPathsSuggestions
43
42
  * @param getUser
44
43
  * @param collectionInference
45
44
  */
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;
45
+ export declare function useCollectionEditorPlugin<EC extends PersistedCollection = PersistedCollection, UserType extends User = User>({ collectionConfigController, configPermissions, reservedGroups, extraView, getPathSuggestions, getUser, collectionInference, getData, onAnalyticsEvent }: CollectionConfigControllerProps<EC, UserType>): FireCMSPlugin<any, any, PersistedCollection>;
46
+ export declare function IntroWidget({}: {}): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,6 @@
1
+ import { EntityCollection, ModifyCollectionProps } from "@firecms/core";
2
+ import { PersistedCollection } from "../types/persisted_collection";
3
+ /**
4
+ * Function in charge of merging collections defined in code with those stored in the backend.
5
+ */
6
+ export declare const mergeCollections: (baseCollections: EntityCollection[], backendCollections: PersistedCollection[], modifyCollection?: (props: ModifyCollectionProps) => EntityCollection | void) => EntityCollection<any, any>[];
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.5",
4
+ "version": "3.0.0-beta.6",
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.5",
11
- "@firecms/formex": "^3.0.0-beta.5",
12
- "@firecms/schema_inference": "^3.0.0-beta.5",
13
- "@firecms/ui": "^3.0.0-beta.5",
10
+ "@firecms/data_import_export": "^3.0.0-beta.6",
11
+ "@firecms/formex": "^3.0.0-beta.6",
12
+ "@firecms/schema_inference": "^3.0.0-beta.6",
13
+ "@firecms/ui": "^3.0.0-beta.6",
14
14
  "json5": "^2.2.3",
15
15
  "prism-react-renderer": "^2.3.1"
16
16
  },
@@ -54,10 +54,10 @@
54
54
  },
55
55
  "devDependencies": {
56
56
  "@jest/globals": "^29.7.0",
57
- "@types/react": "^18.2.67",
58
- "@types/react-dom": "^18.2.22",
59
- "@typescript-eslint/eslint-plugin": "^7.3.1",
60
- "@typescript-eslint/parser": "^7.3.1",
57
+ "@types/react": "^18.2.79",
58
+ "@types/react-dom": "^18.2.25",
59
+ "@typescript-eslint/eslint-plugin": "^7.7.0",
60
+ "@typescript-eslint/parser": "^7.7.0",
61
61
  "@vitejs/plugin-react": "^4.2.1",
62
62
  "eslint": "^8.57.0",
63
63
  "eslint-config-standard": "^17.1.0",
@@ -67,11 +67,11 @@
67
67
  "eslint-plugin-react": "^7.34.1",
68
68
  "eslint-plugin-react-hooks": "^4.6.0",
69
69
  "jest": "^29.7.0",
70
- "react-router": "^6.22.0",
71
- "react-router-dom": "^6.22.0",
70
+ "react-router": "^6.22.3",
71
+ "react-router-dom": "^6.22.3",
72
72
  "ts-jest": "^29.1.2",
73
- "typescript": "^5.4.2",
74
- "vite": "^5.2.3",
73
+ "typescript": "^5.4.5",
74
+ "vite": "^5.2.9",
75
75
  "vite-plugin-fonts": "^0.7.0"
76
76
  },
77
77
  "files": [
@@ -81,5 +81,5 @@
81
81
  "publishConfig": {
82
82
  "access": "public"
83
83
  },
84
- "gitHead": "8bf864185c9617aa3f120e59c873c8b8bda8dac4"
84
+ "gitHead": "ffcbddbd73211bb644ff7503c2c62790bff6202a"
85
85
  }
@@ -1,4 +1,4 @@
1
- import React, { PropsWithChildren, useCallback, useEffect } from "react";
1
+ import React, { PropsWithChildren, useCallback } from "react";
2
2
  import equal from "react-fast-compare"
3
3
 
4
4
  import { CollectionsConfigController } from "./types/config_controller";
@@ -48,9 +48,9 @@ export interface ConfigControllerProviderProps {
48
48
  icon: React.ReactNode
49
49
  };
50
50
 
51
- pathSuggestions?: (path?: string) => Promise<string[]>;
51
+ getPathSuggestions?: (path?: string) => Promise<string[]>;
52
52
 
53
- getUser: (uid: string) => User | null
53
+ getUser?: (uid: string) => User | null
54
54
 
55
55
  getData?: (path: string, parentPaths: string[]) => Promise<object[]>;
56
56
 
@@ -66,7 +66,7 @@ export const ConfigControllerProvider = React.memo(
66
66
  reservedGroups,
67
67
  collectionInference,
68
68
  extraView,
69
- pathSuggestions,
69
+ getPathSuggestions,
70
70
  getUser,
71
71
  getData,
72
72
  onAnalyticsEvent
@@ -77,20 +77,6 @@ export const ConfigControllerProvider = React.memo(
77
77
  const snackbarController = useSnackbarController();
78
78
  const { propertyConfigs } = useCustomizationController();
79
79
 
80
- const {
81
- collections
82
- } = navigation;
83
- const existingPaths = (collections ?? []).map(col => col.path.trim().toLowerCase());
84
-
85
- const [rootPathSuggestions, setRootPathSuggestions] = React.useState<string[] | undefined>();
86
- useEffect(() => {
87
- if (pathSuggestions) {
88
- pathSuggestions().then((paths) => {
89
- setRootPathSuggestions(paths.filter(p => !existingPaths.includes(p.trim().toLowerCase())));
90
- });
91
- }
92
- }, [pathSuggestions]);
93
-
94
80
  const [currentDialog, setCurrentDialog] = React.useState<{
95
81
  isNewCollection: boolean,
96
82
  parentCollection?: PersistedCollection,
@@ -135,7 +121,10 @@ export const ConfigControllerProvider = React.memo(
135
121
  parentCollection?: PersistedCollection
136
122
  }) => {
137
123
  console.debug("Edit collection", id, fullPath, parentCollectionIds, parentCollection);
138
- onAnalyticsEvent?.("edit_collection", { id, fullPath });
124
+ onAnalyticsEvent?.("edit_collection", {
125
+ id,
126
+ fullPath
127
+ });
139
128
  setCurrentDialog({
140
129
  editedCollectionId: id,
141
130
  fullPath,
@@ -162,7 +151,10 @@ export const ConfigControllerProvider = React.memo(
162
151
  collection: PersistedCollection,
163
152
  }) => {
164
153
  console.debug("Edit property", propertyKey, property, editedCollectionId, currentPropertiesOrder, parentCollectionIds, collection);
165
- onAnalyticsEvent?.("edit_property", { propertyKey, editedCollectionId });
154
+ onAnalyticsEvent?.("edit_property", {
155
+ propertyKey,
156
+ editedCollectionId
157
+ });
166
158
  // namespace is all the path until the last dot
167
159
  const namespace = propertyKey && propertyKey.includes(".")
168
160
  ? propertyKey.substring(0, propertyKey.lastIndexOf("."))
@@ -175,7 +167,7 @@ export const ConfigControllerProvider = React.memo(
175
167
  property,
176
168
  namespace,
177
169
  currentPropertiesOrder,
178
- editedCollectionId: editedCollectionId,
170
+ editedCollectionId,
179
171
  parentCollectionIds,
180
172
  collectionEditable: collection?.editable ?? false
181
173
  });
@@ -198,8 +190,20 @@ export const ConfigControllerProvider = React.memo(
198
190
  redirect: boolean,
199
191
  sourceClick?: string
200
192
  }) => {
201
- console.debug("Create collection", { parentCollectionIds, parentCollection, initialValues, redirect, sourceClick });
202
- onAnalyticsEvent?.("create_collection", { parentCollectionIds, parentCollection, initialValues, redirect, sourceClick });
193
+ console.debug("Create collection", {
194
+ parentCollectionIds,
195
+ parentCollection,
196
+ initialValues,
197
+ redirect,
198
+ sourceClick
199
+ });
200
+ onAnalyticsEvent?.("create_collection", {
201
+ parentCollectionIds,
202
+ parentCollection,
203
+ initialValues,
204
+ redirect,
205
+ sourceClick
206
+ });
203
207
  setCurrentDialog({
204
208
  isNewCollection: true,
205
209
  parentCollectionIds,
@@ -209,16 +213,6 @@ export const ConfigControllerProvider = React.memo(
209
213
  });
210
214
  }, []);
211
215
 
212
- const getPathSuggestions = !pathSuggestions
213
- ? undefined
214
- : (path?: string) => {
215
- if (!path && rootPathSuggestions)
216
- return Promise.resolve(rootPathSuggestions);
217
- else {
218
- return pathSuggestions?.(path);
219
- }
220
- }
221
-
222
216
  return (
223
217
  <ConfigControllerContext.Provider value={collectionConfigController}>
224
218
  <CollectionEditorContext.Provider
@@ -227,7 +221,7 @@ export const ConfigControllerProvider = React.memo(
227
221
  createCollection,
228
222
  editProperty,
229
223
  configPermissions: configPermissions ?? defaultConfigPermissions,
230
- rootPathSuggestions
224
+ getPathSuggestions
231
225
  }}>
232
226
 
233
227
  {children}
package/src/index.ts CHANGED
@@ -12,6 +12,7 @@ export {
12
12
  export {
13
13
  editableProperty, removeNonEditableProperties
14
14
  } from "./utils/entities";
15
+ export * from "./utils/collections";
15
16
 
16
17
  export type {
17
18
  CollectionsConfigController, DeleteCollectionParams, SaveCollectionParams, UpdateCollectionParams
@@ -38,6 +38,6 @@ export interface CollectionEditorController {
38
38
 
39
39
  configPermissions: CollectionEditorPermissionsBuilder;
40
40
 
41
- rootPathSuggestions?: string[];
41
+ getPathSuggestions?: (path: string) => Promise<string[]>;
42
42
 
43
43
  }
@@ -23,8 +23,6 @@ export function EditorCollectionAction({
23
23
  const authController = useAuthController();
24
24
  const navigationController = useNavigationController();
25
25
  const collectionEditorController = useCollectionEditorController();
26
- const configController = useCollectionsConfigController();
27
- const snackbarController = useSnackbarController();
28
26
 
29
27
  const parentCollection = navigationController.getCollectionFromIds(parentCollectionIds);
30
28
 
@@ -35,54 +33,6 @@ export function EditorCollectionAction({
35
33
  }).editCollections
36
34
  : true;
37
35
 
38
- let saveDefaultFilterButton = null;
39
- if (!equal(getObjectOrNull(tableController.filterValues), getObjectOrNull(collection.initialFilter)) ||
40
- !equal(getObjectOrNull(tableController.sortBy), getObjectOrNull(collection.initialSort))) {
41
- saveDefaultFilterButton = <>
42
- {(collection.initialFilter || collection.initialSort) && <Tooltip
43
- title={"Reset to default filter and sort"}>
44
- <Button
45
- color={"primary"}
46
- size={"small"}
47
- variant={"text"}
48
- onClick={() => {
49
- tableController.clearFilter?.();
50
- if (collection?.initialFilter)
51
- tableController.setFilterValues?.(collection?.initialFilter);
52
- if (collection?.initialSort)
53
- tableController.setSortBy?.(collection?.initialSort);
54
- }}>
55
- <UndoIcon/>
56
- </Button>
57
- </Tooltip>}
58
-
59
- <Tooltip
60
- title={tableController.sortBy || tableController.filterValues ? "Save default filter and sort" : "Clear default filter and sort"}>
61
- <Button
62
- color={"primary"}
63
- size={"small"}
64
- variant={"outlined"}
65
- onClick={() => configController
66
- ?.saveCollection({
67
- id: collection.id,
68
- parentCollectionIds,
69
- collectionData: mergeDeep(collection as PersistedCollection,
70
- {
71
- initialFilter: tableController.filterValues ?? null,
72
- initialSort: tableController.sortBy ?? null
73
- })
74
- }).then(() => {
75
- snackbarController.open({
76
- type: "success",
77
- message: "Default config saved"
78
- });
79
- })}>
80
- <SaveIcon/>
81
- </Button>
82
- </Tooltip>
83
- </>;
84
- }
85
-
86
36
  const editorButton = <Tooltip
87
37
  title={canEditCollection ? "Edit collection" : "You don't have permissions to edit this collection"}>
88
38
  <IconButton
@@ -96,7 +46,6 @@ export function EditorCollectionAction({
96
46
  </Tooltip>;
97
47
 
98
48
  return <>
99
- {canEditCollection && saveDefaultFilterButton}
100
49
  {editorButton}
101
50
  </>
102
51
 
@@ -0,0 +1,87 @@
1
+ import equal from "react-fast-compare"
2
+
3
+ import { CollectionActionsProps, mergeDeep, useAuthController, useSnackbarController } from "@firecms/core";
4
+ import { Button, SaveIcon, Tooltip, UndoIcon, } from "@firecms/ui";
5
+
6
+ import { useCollectionEditorController } from "../useCollectionEditorController";
7
+ import { useCollectionsConfigController } from "../useCollectionsConfigController";
8
+ import { PersistedCollection } from "../types/persisted_collection";
9
+
10
+ export function EditorCollectionActionStart({
11
+ path: fullPath,
12
+ parentCollectionIds,
13
+ collection,
14
+ tableController
15
+ }: CollectionActionsProps) {
16
+
17
+ const authController = useAuthController();
18
+ const collectionEditorController = useCollectionEditorController();
19
+ const configController = useCollectionsConfigController();
20
+ const snackbarController = useSnackbarController();
21
+
22
+ const canEditCollection = collectionEditorController.configPermissions
23
+ ? collectionEditorController.configPermissions({
24
+ user: authController.user,
25
+ collection
26
+ }).editCollections
27
+ : true;
28
+
29
+ let saveDefaultFilterButton = null;
30
+ if (!equal(getObjectOrNull(tableController.filterValues), getObjectOrNull(collection.initialFilter)) ||
31
+ !equal(getObjectOrNull(tableController.sortBy), getObjectOrNull(collection.initialSort))) {
32
+ saveDefaultFilterButton = <>
33
+ <Tooltip
34
+ title={tableController.sortBy || tableController.filterValues ? "Save default filter and sort" : "Clear default filter and sort"}>
35
+ <Button
36
+ color={"primary"}
37
+ size={"small"}
38
+ variant={"outlined"}
39
+ onClick={() => configController
40
+ ?.saveCollection({
41
+ id: collection.id,
42
+ parentCollectionIds,
43
+ collectionData: mergeDeep(collection as PersistedCollection,
44
+ {
45
+ initialFilter: tableController.filterValues ?? null,
46
+ initialSort: tableController.sortBy ?? null
47
+ })
48
+ }).then(() => {
49
+ snackbarController.open({
50
+ type: "success",
51
+ message: "Default config saved"
52
+ });
53
+ })}>
54
+ <SaveIcon/>
55
+ </Button>
56
+ </Tooltip>
57
+
58
+ {(collection.initialFilter || collection.initialSort) && <Tooltip
59
+ title={"Reset to default filter and sort"}>
60
+ <Button
61
+ color={"primary"}
62
+ size={"small"}
63
+ variant={"text"}
64
+ onClick={() => {
65
+ tableController.clearFilter?.();
66
+ if (collection?.initialFilter)
67
+ tableController.setFilterValues?.(collection?.initialFilter);
68
+ if (collection?.initialSort)
69
+ tableController.setSortBy?.(collection?.initialSort);
70
+ }}>
71
+ <UndoIcon/>
72
+ </Button>
73
+ </Tooltip>}
74
+ </>;
75
+ }
76
+
77
+ return <>
78
+ {canEditCollection && saveDefaultFilterButton}
79
+ </>
80
+
81
+ }
82
+
83
+ function getObjectOrNull(o?: object): object | null {
84
+ if (o && Object.keys(o).length === 0)
85
+ return o
86
+ return o ?? null;
87
+ }
@@ -216,7 +216,7 @@ export function CollectionDetailsForm({
216
216
  label={"Collection id"}
217
217
  error={showErrors && Boolean(errors.id)}/>
218
218
  <FieldCaption error={touched.id && Boolean(errors.id)}>
219
- {touched.id && Boolean(errors.id) ? errors.id : "This id identifies this collection"}
219
+ {touched.id && Boolean(errors.id) ? errors.id : "This id identifies this collection. Typically the same as the path."}
220
220
  </FieldCaption>
221
221
  </div>
222
222
 
@@ -76,7 +76,7 @@ export interface CollectionEditorDialogProps {
76
76
  icon: React.ReactNode
77
77
  };
78
78
  pathSuggestions?: (path?: string) => Promise<string[]>;
79
- getUser: (uid: string) => User | null;
79
+ getUser?: (uid: string) => User | null;
80
80
  getData?: (path: string, parentPaths: string[]) => Promise<object[]>;
81
81
  parentCollection?: PersistedCollection;
82
82
  }
@@ -170,7 +170,8 @@ export function CollectionEditor(props: CollectionEditorDialogProps & {
170
170
  } catch (e) {
171
171
  console.error(e);
172
172
  }
173
- }, [navigation.getCollectionFromPaths, props.editedCollectionId, props.parentCollectionIds, navigation.initialised]);
173
+ }, [props.editedCollectionId, props.parentCollectionIds, navigation]);
174
+
174
175
  if (!topLevelNavigation) {
175
176
  throw Error("Internal: Navigation not ready in collection editor");
176
177
  }
@@ -486,19 +487,23 @@ function CollectionEditorInternal<M extends Record<string, any>>({
486
487
  setFormDirty(dirty);
487
488
  }, [dirty]);
488
489
 
489
- function onImportDataSet(data: object[]) {
490
+ function onImportDataSet(data: object[], propertiesOrder?: string[]) {
490
491
  importConfig.setInUse(true);
491
492
  buildEntityPropertiesFromData(data, getInferenceType)
492
493
  .then((properties) => {
493
494
  const res = cleanPropertiesFromImport(properties);
494
495
 
495
- setFieldValue("properties", res.properties);
496
- setFieldValue("propertiesOrder", Object.keys(res.properties));
497
-
498
496
  importConfig.setIdColumn(res.idColumn);
499
497
  importConfig.setImportData(data);
500
498
  importConfig.setHeadersMapping(res.headersMapping);
499
+ const filteredHeadingsOrder = ((propertiesOrder ?? [])
500
+ .filter((key) => res.headersMapping[key]) as string[]) ?? Object.keys(res.properties);
501
+ importConfig.setHeadingsOrder(filteredHeadingsOrder);
501
502
  importConfig.setOriginProperties(res.properties);
503
+
504
+ const mappedHeadings = (propertiesOrder ?? []).map((key) => res.headersMapping[key]).filter(Boolean) as string[] ?? Object.keys(res.properties);
505
+ setFieldValue("properties", res.properties);
506
+ setFieldValue("propertiesOrder", mappedHeadings);
502
507
  });
503
508
  }
504
509
 
@@ -551,9 +556,10 @@ function CollectionEditorInternal<M extends Record<string, any>>({
551
556
  {currentView === "welcome" &&
552
557
  <CollectionEditorWelcomeView
553
558
  path={path}
554
- onContinue={(importData) => {
559
+ onContinue={(importData, propertiesOrder) => {
560
+ // console.log("Import data", importData, propertiesOrder)
555
561
  if (importData) {
556
- onImportDataSet(importData);
562
+ onImportDataSet(importData, propertiesOrder);
557
563
  setCurrentView("import_data_mapping");
558
564
  } else {
559
565
  setCurrentView("details");
@@ -733,7 +739,10 @@ function CollectionEditorInternal<M extends Record<string, any>>({
733
739
  }
734
740
 
735
741
  function applyPropertyConfigs<M extends Record<string, any> = any>(collection: PersistedCollection<M>, propertyConfigs: Record<string, PropertyConfig<any>>): PersistedCollection<M> {
736
- const { properties, ...rest } = collection;
742
+ const {
743
+ properties,
744
+ ...rest
745
+ } = collection;
737
746
  const propertiesResult: PropertiesOrBuilders<any> = {};
738
747
  if (properties) {
739
748
  Object.keys(properties).forEach((key) => {
@@ -741,7 +750,10 @@ function applyPropertyConfigs<M extends Record<string, any> = any>(collection: P
741
750
  });
742
751
  }
743
752
 
744
- return { ...rest, properties: propertiesResult };
753
+ return {
754
+ ...rest,
755
+ properties: propertiesResult
756
+ };
745
757
  }
746
758
 
747
759
  function applyPropertiesConfig(property: PropertyOrBuilder, propertyConfigs: Record<string, PropertyConfig<any>>) {
@@ -761,7 +773,10 @@ function applyPropertiesConfig(property: PropertyOrBuilder, propertyConfigs: Rec
761
773
  Object.keys(internalProperty.properties).forEach((key) => {
762
774
  properties[key] = applyPropertiesConfig(((internalProperty as MapProperty).properties as Properties)[key] as Property, propertyConfigs);
763
775
  });
764
- internalProperty = { ...internalProperty, properties };
776
+ internalProperty = {
777
+ ...internalProperty,
778
+ properties
779
+ };
765
780
  }
766
781
 
767
782
  }
@@ -19,7 +19,7 @@ export function CollectionEditorWelcomeView({
19
19
  path: string;
20
20
  pathSuggestions?: (path: string) => Promise<string[]>;
21
21
  parentCollection?: EntityCollection;
22
- onContinue: (importData?: object[]) => void;
22
+ onContinue: (importData?: object[], propertiesOrder?: string[]) => void;
23
23
  existingCollectionPaths?: string[];
24
24
  }) {
25
25
 
@@ -154,7 +154,7 @@ export function CollectionEditorWelcomeView({
154
154
  ● Create a collection from a file (csv, json, xls, xslx...)
155
155
  </Typography>
156
156
 
157
- <ImportFileUpload onDataAdded={(data) => onContinue(data)}/>
157
+ <ImportFileUpload onDataAdded={(data, propertiesOrder) => onContinue(data, propertiesOrder)}/>
158
158
 
159
159
  </div>}
160
160
 
@@ -43,7 +43,7 @@ type CollectionEditorFormProps = {
43
43
  setDirty?: (dirty: boolean) => void;
44
44
  reservedGroups?: string[];
45
45
  extraIcon: React.ReactNode;
46
- getUser: (uid: string) => User | null;
46
+ getUser?: (uid: string) => User | null;
47
47
  getData?: () => Promise<object[]>;
48
48
  doCollectionInference: (collection: PersistedCollection) => Promise<Partial<EntityCollection> | null> | undefined;
49
49
  propertyConfigs: Record<string, PropertyConfig>;
@@ -301,7 +301,7 @@ export function CollectionPropertiesEditorForm({
301
301
  ? values.propertiesOrder
302
302
  : Object.keys(values.properties)) as string[];
303
303
 
304
- const owner = useMemo(() => values.ownerId ? getUser(values.ownerId) : null, [getUser, values.ownerId]);
304
+ const owner = useMemo(() => values.ownerId && getUser ? getUser(values.ownerId) : null, [getUser, values.ownerId]);
305
305
 
306
306
  const onPropertyClick = useCallback((propertyKey: string, namespace?: string) => {
307
307
  console.debug("CollectionEditor: onPropertyClick", {
@@ -41,7 +41,7 @@ export function SubcollectionsEditTab({
41
41
  parentCollection?: EntityCollection,
42
42
  configController: CollectionsConfigController;
43
43
  collectionInference?: CollectionInference;
44
- getUser: (uid: string) => User | null;
44
+ getUser?: (uid: string) => User | null;
45
45
  parentCollectionIds?: string[];
46
46
  }) {
47
47