@firecms/core 3.0.0-alpha.46 → 3.0.0-alpha.47

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 (39) hide show
  1. package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +1 -1
  2. package/dist/components/EntityCollectionView/EntityCollectionViewActions.d.ts +2 -2
  3. package/dist/index.es.js +2087 -2059
  4. package/dist/index.es.js.map +1 -1
  5. package/dist/index.umd.js +12 -12
  6. package/dist/index.umd.js.map +1 -1
  7. package/dist/internal/EntityView.d.ts +2 -1
  8. package/dist/types/collections.d.ts +8 -8
  9. package/dist/types/index.d.ts +1 -0
  10. package/dist/types/modify_collections.d.ts +5 -0
  11. package/dist/types/navigation.d.ts +9 -0
  12. package/dist/types/plugins.d.ts +2 -2
  13. package/dist/ui/ExpandablePanel.d.ts +2 -1
  14. package/dist/util/join_collections.d.ts +3 -7
  15. package/package.json +2 -2
  16. package/src/components/EntityCollectionTable/internal/EntityCollectionRowActions.tsx +1 -1
  17. package/src/components/EntityCollectionTable/internal/common.tsx +1 -1
  18. package/src/components/EntityCollectionView/EntityCollectionView.tsx +7 -7
  19. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +3 -3
  20. package/src/core/EntitySidePanel.tsx +5 -0
  21. package/src/core/NavigationRoutes.tsx +5 -5
  22. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +1 -0
  23. package/src/internal/EntityView.tsx +6 -12
  24. package/src/internal/useBuildNavigationController.tsx +33 -9
  25. package/src/internal/useBuildSideEntityController.tsx +1 -1
  26. package/src/preview/PropertyPreview.tsx +0 -1
  27. package/src/types/collections.ts +9 -9
  28. package/src/types/firecms.tsx +1 -1
  29. package/src/types/index.ts +1 -0
  30. package/src/types/modify_collections.tsx +6 -0
  31. package/src/types/navigation.ts +11 -0
  32. package/src/types/plugins.tsx +2 -2
  33. package/src/ui/ExpandablePanel.tsx +9 -2
  34. package/src/util/builders.ts +2 -1
  35. package/src/util/join_collections.ts +49 -19
  36. package/src/util/navigation_from_path.ts +2 -2
  37. package/src/util/navigation_utils.ts +3 -3
  38. package/src/util/parent_references_from_path.ts +2 -2
  39. package/src/util/property_utils.tsx +1 -7
@@ -5,6 +5,7 @@ export interface EntityViewProps<M extends Record<string, any>> {
5
5
  entityId?: string;
6
6
  copy?: boolean;
7
7
  selectedSubPath?: string;
8
+ parentCollectionIds: string[];
8
9
  formWidth?: number | string;
9
10
  onValuesAreModified: (modified: boolean) => void;
10
11
  onUpdate?: (params: {
@@ -18,4 +19,4 @@ export interface EntityViewProps<M extends Record<string, any>> {
18
19
  * You probably don't want to use this view directly since it is bound to the
19
20
  * side panel. Instead, you might want to use {@link EntityForm} or {@link EntityCollectionView}
20
21
  */
21
- export declare function EntityView<M extends Record<string, any>, UserType extends User>({ path, entityId, selectedSubPath, copy, collection, onValuesAreModified, formWidth, onUpdate, onClose }: EntityViewProps<M>): import("react/jsx-runtime").JSX.Element;
22
+ export declare function EntityView<M extends Record<string, any>, UserType extends User>({ path, entityId, selectedSubPath, copy, collection, parentCollectionIds, onValuesAreModified, formWidth, onUpdate, onClose }: EntityViewProps<M>): import("react/jsx-runtime").JSX.Element;
@@ -16,6 +16,13 @@ import { ExportConfig } from "./export_import";
16
16
  * @group Models
17
17
  */
18
18
  export interface EntityCollection<M extends Record<string, any> = any, UserType extends User = User> {
19
+ /**
20
+ * You can set an alias that will be used internally instead of the `path`.
21
+ * The `alias` value will be used to determine the URL of the collection,
22
+ * while `path` will still be used in the datasource.
23
+ * Note that you can use this value in reference properties too.
24
+ */
25
+ id: string;
19
26
  /**
20
27
  * Name of the collection, typically plural.
21
28
  * E.g. `Products`, `Blog`
@@ -41,13 +48,6 @@ export interface EntityCollection<M extends Record<string, any> = any, UserType
41
48
  * property to `true` to indicate that this collection is a collection group.
42
49
  */
43
50
  collectionGroup?: boolean;
44
- /**
45
- * You can set an alias that will be used internally instead of the `path`.
46
- * The `alias` value will be used to determine the URL of the collection,
47
- * while `path` will still be used in the datasource.
48
- * Note that you can use this value in reference properties too.
49
- */
50
- alias?: string;
51
51
  /**
52
52
  * Icon key to use in this collection.
53
53
  * You can use any of the icons in the Material specs:
@@ -262,7 +262,7 @@ export interface CollectionActionsProps<M extends Record<string, any> = any, Use
262
262
  /**
263
263
  * Array of the parent path segments like `['users']`
264
264
  */
265
- parentPathSegments: string[];
265
+ parentCollectionIds: string[];
266
266
  /**
267
267
  * The collection configuration
268
268
  */
@@ -24,3 +24,4 @@ export * from "./analytics";
24
24
  export * from "./firecms";
25
25
  export * from "./appcheck";
26
26
  export * from "./export_import";
27
+ export * from "./modify_collections";
@@ -0,0 +1,5 @@
1
+ import { EntityCollection } from "./collections";
2
+ export type ModifyCollectionProps = {
3
+ collection: EntityCollection;
4
+ parentPaths: string[];
5
+ };
@@ -42,6 +42,10 @@ export type NavigationController = {
42
42
  * The collection is resolved from the given path or alias.
43
43
  */
44
44
  getCollection: <EC extends EntityCollection = EntityCollection<any>>(pathOrAlias: string, entityId?: string, includeUserOverride?: boolean) => EC | undefined;
45
+ /**
46
+ * Get the collection configuration from its parent path segments.
47
+ */
48
+ getCollectionFromIds: <EC extends EntityCollection = EntityCollection<any>>(ids: string[]) => EC | undefined;
45
49
  /**
46
50
  * Get the collection configuration from its parent path segments.
47
51
  */
@@ -106,6 +110,11 @@ export type NavigationController = {
106
110
  * @param path
107
111
  */
108
112
  getParentReferencesFromPath: (path: string) => EntityReference[];
113
+ /**
114
+ * Retrieve all the related parent collection ids for a given path
115
+ * @param path
116
+ */
117
+ getParentCollectionIds: (path: string) => string[];
109
118
  };
110
119
  /**
111
120
  * Custom additional views created by the developer, added to the main
@@ -95,7 +95,7 @@ export type FireCMSPlugin<PROPS = any, FORM_PROPS = any, EC extends EntityCollec
95
95
  property: ResolvedProperty;
96
96
  propertyKey: string;
97
97
  fullPath: string;
98
- parentPathSegments: string[];
98
+ parentCollectionIds: string[];
99
99
  onHover: boolean;
100
100
  collection: EC;
101
101
  }>;
@@ -105,7 +105,7 @@ export type FireCMSPlugin<PROPS = any, FORM_PROPS = any, EC extends EntityCollec
105
105
  */
106
106
  AddColumnComponent?: React.ComponentType<{
107
107
  fullPath: string;
108
- parentPathSegments: string[];
108
+ parentCollectionIds: string[];
109
109
  collection: EC;
110
110
  }>;
111
111
  };
@@ -1,8 +1,9 @@
1
1
  import React, { PropsWithChildren } from "react";
2
- export declare function ExpandablePanel({ title, children, invisible, initiallyExpanded: initiallyOpen, onExpandedChange, titleClassName, asField, className }: PropsWithChildren<{
2
+ export declare function ExpandablePanel({ title, children, invisible, expanded, onExpandedChange, initiallyExpanded, titleClassName, asField, className }: PropsWithChildren<{
3
3
  title: React.ReactNode;
4
4
  invisible?: boolean;
5
5
  initiallyExpanded?: boolean;
6
+ expanded?: boolean;
6
7
  onExpandedChange?: (expanded: boolean) => void;
7
8
  titleClassName?: string;
8
9
  asField?: boolean;
@@ -1,13 +1,9 @@
1
- import { EntityCollection } from "../types";
1
+ import { EntityCollection, ModifyCollectionProps } from "../types";
2
2
  /**
3
3
  *
4
- * @param storedCollections
5
- * @param codedCollections
6
4
  */
7
- export declare function joinCollectionLists(storedCollections: EntityCollection[], codedCollections: EntityCollection[] | undefined): EntityCollection[];
5
+ export declare function joinCollectionLists(targetCollections: EntityCollection[], sourceCollections: EntityCollection[] | undefined, parentPaths?: string[], modifyCollection?: (props: ModifyCollectionProps) => EntityCollection | undefined): EntityCollection[];
8
6
  /**
9
7
  *
10
- * @param target
11
- * @param source
12
8
  */
13
- export declare function mergeCollection(target: EntityCollection, source: EntityCollection): EntityCollection;
9
+ export declare function mergeCollection(target: EntityCollection, source: EntityCollection, parentPaths?: string[], modifyCollection?: (props: ModifyCollectionProps) => EntityCollection | undefined): EntityCollection;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@firecms/core",
3
- "version": "3.0.0-alpha.46",
3
+ "version": "3.0.0-alpha.47",
4
4
  "description": "Awesome Firebase/Firestore-based headless open-source CMS",
5
5
  "funding": {
6
6
  "url": "https://github.com/sponsors/firecmsco"
@@ -133,7 +133,7 @@
133
133
  "dist",
134
134
  "src"
135
135
  ],
136
- "gitHead": "53ef13adab3db13baeea2ad7953e37cf3552fd62",
136
+ "gitHead": "1c2310776f2da9bba46ba352e9a5244118dcdc3f",
137
137
  "publishConfig": {
138
138
  "access": "public"
139
139
  }
@@ -2,7 +2,7 @@ import React, { MouseEvent, useCallback } from "react";
2
2
  import equal from "react-fast-compare"
3
3
 
4
4
  import { CollectionSize, Entity, EntityAction, EntityCollection, SelectionController } from "../../../types";
5
- import { Checkbox, cn, IconButton, Menu, MenuItem, Tooltip, Typography, Skeleton } from "../../../ui";
5
+ import { Checkbox, cn, IconButton, Menu, MenuItem, Skeleton, Tooltip, Typography } from "../../../ui";
6
6
  import { useFireCMSContext, useLargeLayout } from "../../../hooks";
7
7
  import { MoreVertIcon } from "../../../icons";
8
8
 
@@ -66,5 +66,5 @@ export function getTablePropertyColumnWidth(property: ResolvedProperty): number
66
66
  }
67
67
 
68
68
  export function getSubcollectionColumnId(collection: EntityCollection) {
69
- return `subcollection:${collection.alias ?? collection.path}`;
69
+ return `subcollection:${collection.id ?? collection.path}`;
70
70
  }
@@ -69,7 +69,7 @@ const COLLECTION_GROUP_PARENT_ID = "collectionGroupParent";
69
69
  */
70
70
  export type EntityCollectionViewProps<M extends Record<string, any>> = {
71
71
  fullPath: string;
72
- parentPathSegments?: string[];
72
+ parentCollectionIds?: string[];
73
73
  isSubCollection?: boolean;
74
74
  className?: string;
75
75
  } & EntityCollection<M>;
@@ -101,7 +101,7 @@ export type EntityCollectionViewProps<M extends Record<string, any>> = {
101
101
  export const EntityCollectionView = React.memo(
102
102
  function EntityCollectionView<M extends Record<string, any>>({
103
103
  fullPath,
104
- parentPathSegments,
104
+ parentCollectionIds,
105
105
  isSubCollection,
106
106
  className,
107
107
  ...collectionProp
@@ -238,7 +238,7 @@ export const EntityCollectionView = React.memo(
238
238
 
239
239
  let AddColumnComponent: React.ComponentType<{
240
240
  fullPath: string,
241
- parentPathSegments: string[],
241
+ parentCollectionIds: string[],
242
242
  collection: EntityCollection;
243
243
  }> | undefined
244
244
 
@@ -367,7 +367,7 @@ export const EntityCollectionView = React.memo(
367
367
  sideEntityController.open({
368
368
  path: fullPath,
369
369
  entityId: entity.id,
370
- selectedSubPath: subcollection.alias ?? subcollection.path,
370
+ selectedSubPath: subcollection.id ?? subcollection.path,
371
371
  collection,
372
372
  updateUrl: true
373
373
  });
@@ -529,7 +529,7 @@ export const EntityCollectionView = React.memo(
529
529
  property={property}
530
530
  fullPath={fullPath}
531
531
  collection={collection}
532
- parentPathSegments={parentPathSegments ?? []}/>;
532
+ parentCollectionIds={parentCollectionIds ?? []}/>;
533
533
  })}
534
534
  </>;
535
535
  }
@@ -538,7 +538,7 @@ export const EntityCollectionView = React.memo(
538
538
  ? function () {
539
539
  if (typeof AddColumnComponent === "function")
540
540
  return <AddColumnComponent fullPath={fullPath}
541
- parentPathSegments={parentPathSegments ?? []}
541
+ parentCollectionIds={parentCollectionIds ?? []}
542
542
  collection={collection}/>;
543
543
  return null;
544
544
  }
@@ -565,7 +565,7 @@ export const EntityCollectionView = React.memo(
565
565
  properties={resolvedCollection.properties}
566
566
  getPropertyFor={getPropertyFor}
567
567
  actions={<EntityCollectionViewActions
568
- parentPathSegments={parentPathSegments ?? []}
568
+ parentCollectionIds={parentCollectionIds ?? []}
569
569
  collection={collection}
570
570
  tableController={tableController}
571
571
  onMultipleDeleteClick={onMultipleDeleteClick}
@@ -12,7 +12,7 @@ export type EntityCollectionViewActionsProps<M extends Record<string, any>> = {
12
12
  collection: EntityCollection<M>;
13
13
  path: string;
14
14
  relativePath: string;
15
- parentPathSegments: string[];
15
+ parentCollectionIds: string[];
16
16
  selectionEnabled: boolean;
17
17
  onNewClick: () => void;
18
18
  onMultipleDeleteClick: () => void;
@@ -24,7 +24,7 @@ export type EntityCollectionViewActionsProps<M extends Record<string, any>> = {
24
24
  export function EntityCollectionViewActions<M extends Record<string, any>>({
25
25
  collection,
26
26
  relativePath,
27
- parentPathSegments,
27
+ parentCollectionIds,
28
28
  onNewClick,
29
29
  onMultipleDeleteClick,
30
30
  selectionEnabled,
@@ -95,7 +95,7 @@ export function EntityCollectionViewActions<M extends Record<string, any>>({
95
95
  const actionProps: CollectionActionsProps = {
96
96
  path,
97
97
  relativePath,
98
- parentPathSegments,
98
+ parentCollectionIds,
99
99
  collection,
100
100
  selectionController,
101
101
  context,
@@ -25,6 +25,10 @@ export function EntitySidePanel(props: EntitySidePanelProps) {
25
25
 
26
26
  const navigationController = useNavigationController();
27
27
 
28
+ const parentCollectionIds = useMemo(() => {
29
+ return navigationController.getParentCollectionIds(props.path);
30
+ }, [navigationController, props.path]);
31
+
28
32
  const collection = useMemo(() => {
29
33
  if (!props) return undefined;
30
34
  let usedCollection = props.collection;
@@ -76,6 +80,7 @@ export function EntitySidePanel(props: EntitySidePanelProps) {
76
80
  {...props}
77
81
  formWidth={props.width}
78
82
  collection={collection}
83
+ parentCollectionIds={parentCollectionIds}
79
84
  onValuesAreModified={onValuesAreModified}
80
85
  />
81
86
  </ErrorBoundary>
@@ -67,19 +67,19 @@ export const NavigationRoutes = React.memo<NavigationRoutesProps>(
67
67
 
68
68
  const collectionRoutes = sortedCollections
69
69
  .map((collection) => {
70
- const urlPath = navigation.buildUrlCollectionPath(collection.alias ?? collection.path);
70
+ const urlPath = navigation.buildUrlCollectionPath(collection.id ?? collection.path);
71
71
  return <Route path={urlPath + "/*"}
72
- key={`navigation_${collection.alias ?? collection.path}`}
72
+ key={`navigation_${collection.id ?? collection.path}`}
73
73
  element={
74
74
  <RouteWrapper
75
75
  path={urlPath}
76
76
  title={collection.name}
77
77
  type={"collection"}>
78
78
  <EntityCollectionView
79
- key={`collection_view_${collection.alias ?? collection.path}`}
79
+ key={`collection_view_${collection.id ?? collection.path}`}
80
80
  isSubCollection={false}
81
- parentPathSegments={[]}
82
- fullPath={collection.alias ?? collection.path}
81
+ parentCollectionIds={[]}
82
+ fullPath={collection.id ?? collection.path}
83
83
  {...collection}
84
84
  Actions={toArray(collection.Actions)}/>
85
85
  </RouteWrapper>
@@ -56,6 +56,7 @@ export function ArrayOfReferencesFieldBinding({
56
56
  }
57
57
 
58
58
  const onMultipleEntitiesSelected = useCallback((entities: Entity<any>[]) => {
59
+ console.debug("onMultipleEntitiesSelected", entities);
59
60
  setValue(entities.map(e => getReferenceFrom(e)));
60
61
  }, [setValue]);
61
62
 
@@ -45,18 +45,13 @@ export interface EntityViewProps<M extends Record<string, any>> {
45
45
  entityId?: string;
46
46
  copy?: boolean;
47
47
  selectedSubPath?: string;
48
+ parentCollectionIds: string[];
48
49
  formWidth?: number | string;
49
50
  onValuesAreModified: (modified: boolean) => void;
50
51
  onUpdate?: (params: { entity: Entity<any> }) => void;
51
52
  onClose?: () => void;
52
53
  }
53
54
 
54
- type EntityViewView = {
55
- label: string;
56
- component: React.ReactNode;
57
- size: "full" | "half";
58
- }
59
-
60
55
  /**
61
56
  * This is the default view that is used as the content of a side panel when
62
57
  * an entity is opened.
@@ -69,12 +64,14 @@ export function EntityView<M extends Record<string, any>, UserType extends User>
69
64
  selectedSubPath,
70
65
  copy,
71
66
  collection,
67
+ parentCollectionIds,
72
68
  onValuesAreModified,
73
69
  formWidth,
74
70
  onUpdate,
75
71
  onClose
76
72
  }: EntityViewProps<M>) {
77
73
 
74
+
78
75
  if (collection.customId && collection.formAutoSave) {
79
76
  console.warn(`The collection ${collection.path} has customId and formAutoSave enabled. This is not supported and formAutoSave will be ignored`);
80
77
  }
@@ -343,7 +340,7 @@ export function EntityView<M extends Record<string, any>, UserType extends User>
343
340
 
344
341
  const subCollectionsViews = subcollections && subcollections.map(
345
342
  (subcollection, colIndex) => {
346
- const subcollectionId = subcollection.alias ?? subcollection.path;
343
+ const subcollectionId = subcollection.id ?? subcollection.path;
347
344
  const fullPath = usedEntity ? `${path}/${usedEntity?.id}/${removeInitialAndTrailingSlashes(subcollectionId)}` : undefined;
348
345
  if (selectedTabRef.current !== subcollectionId)
349
346
  return null;
@@ -359,7 +356,7 @@ export function EntityView<M extends Record<string, any>, UserType extends User>
359
356
  (usedEntity && fullPath
360
357
  ? <EntityCollectionView
361
358
  fullPath={fullPath}
362
- parentPathSegments={fullPathToCollectionSegments(path)}
359
+ parentCollectionIds={[...parentCollectionIds, collection.id]}
363
360
  isSubCollection={true}
364
361
  {...subcollection}/>
365
362
  : <div
@@ -480,7 +477,7 @@ export function EntityView<M extends Record<string, any>, UserType extends User>
480
477
  (subcollection) =>
481
478
  <Tab
482
479
  className="text-sm min-w-[140px]"
483
- value={subcollection.path}
480
+ value={subcollection.id}
484
481
  key={`entity_detail_collection_tab_${subcollection.name}`}>
485
482
  {subcollection.name}
486
483
  </Tab>
@@ -533,9 +530,6 @@ export function EntityView<M extends Record<string, any>, UserType extends User>
533
530
 
534
531
  <Tab
535
532
  disabled={!hasAdditionalViews}
536
- // onClick={() => {
537
- // onSideTabClick(-1);
538
- // }}
539
533
  value={MAIN_TAB_VALUE}
540
534
  className={`${
541
535
  !hasAdditionalViews ? "hidden" : ""
@@ -5,7 +5,7 @@ import {
5
5
  AuthController,
6
6
  CMSView,
7
7
  CMSViewsBuilder,
8
- DataSource, DataSourceDelegate,
8
+ DataSourceDelegate,
9
9
  EntityCollection,
10
10
  EntityCollectionsBuilder,
11
11
  EntityReference,
@@ -24,7 +24,6 @@ import {
24
24
  resolvePermissions
25
25
  } from "../util";
26
26
  import { getParentReferencesFromPath } from "../util/parent_references_from_path";
27
- import { useTraceUpdate } from "../util/useTraceUpdate";
28
27
 
29
28
  const DEFAULT_BASE_PATH = "/";
30
29
  const DEFAULT_COLLECTION_PATH = "/c";
@@ -79,10 +78,10 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
79
78
  const navigationEntries: TopNavigationEntry[] = [
80
79
  ...(collections ?? []).map(collection => (!collection.hideFromNavigation
81
80
  ? {
82
- url: buildUrlCollectionPath(collection.alias ?? collection.path),
81
+ url: buildUrlCollectionPath(collection.id ?? collection.path),
83
82
  type: "collection",
84
83
  name: collection.name.trim(),
85
- path: collection.alias ?? collection.path,
84
+ path: collection.id ?? collection.path,
86
85
  collection,
87
86
  description: collection.description?.trim(),
88
87
  group: collection.group?.trim()
@@ -142,7 +141,7 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
142
141
  }, [refreshNavigation]);
143
142
 
144
143
  const getCollection = useCallback(<EC extends EntityCollection>(
145
- pathOrAlias: string,
144
+ idOrPath: string,
146
145
  entityId?: string,
147
146
  includeUserOverride = false
148
147
  ): EC | undefined => {
@@ -150,9 +149,9 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
150
149
  if (!collections)
151
150
  return undefined;
152
151
 
153
- const baseCollection = getCollectionByPathOrAlias(removeInitialAndTrailingSlashes(pathOrAlias), collections);
152
+ const baseCollection = getCollectionByPathOrAlias(removeInitialAndTrailingSlashes(idOrPath), collections);
154
153
 
155
- const userOverride = includeUserOverride ? userConfigPersistence?.getCollectionConfig(pathOrAlias) : undefined;
154
+ const userOverride = includeUserOverride ? userConfigPersistence?.getCollectionConfig(idOrPath) : undefined;
156
155
 
157
156
  const overriddenCollection = baseCollection ? mergeDeep(baseCollection, userOverride) : undefined;
158
157
 
@@ -187,7 +186,7 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
187
186
 
188
187
  for (let i = 0; i < pathSegments.length; i++) {
189
188
  const pathSegment = pathSegments[i];
190
- const collection: EntityCollection | undefined = currentCollections!.find(c => c.alias === pathSegment || c.path === pathSegment);
189
+ const collection: EntityCollection | undefined = currentCollections!.find(c => c.id === pathSegment || c.path === pathSegment);
191
190
  if (!collection)
192
191
  return undefined;
193
192
  currentCollections = collection.subcollections;
@@ -199,6 +198,25 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
199
198
 
200
199
  }, [collections]);
201
200
 
201
+ const getCollectionFromIds = useCallback(<EC extends EntityCollection>(ids: string[]): EC | undefined => {
202
+ let currentCollections = collections;
203
+ if (!currentCollections)
204
+ throw Error("Collections have not been initialised yet");
205
+
206
+ for (let i = 0; i < ids.length; i++) {
207
+ const id = ids[i];
208
+ const collection: EntityCollection | undefined = currentCollections!.find(c => c.id === id);
209
+ if (!collection)
210
+ return undefined;
211
+ currentCollections = collection.subcollections;
212
+ if (i === ids.length - 1)
213
+ return collection as EC;
214
+ }
215
+
216
+ return undefined;
217
+
218
+ }, [collections]);
219
+
202
220
  const isUrlCollectionPath = useCallback(
203
221
  (path: string): boolean => removeInitialAndTrailingSlashes(path + "/").startsWith(removeInitialAndTrailingSlashes(fullCollectionPath) + "/"),
204
222
  [fullCollectionPath]);
@@ -239,6 +257,10 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
239
257
  });
240
258
  }, [collections]);
241
259
 
260
+ const getParentCollectionIds = useCallback((path: string): string[] => {
261
+ return getAllParentCollectionsForPath(path).map(r => r.id);
262
+ }, [getAllParentCollectionsForPath])
263
+
242
264
  return useMemo(() => ({
243
265
  collections: collections ?? [],
244
266
  views: views ?? [],
@@ -250,6 +272,7 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
250
272
  initialised,
251
273
  getCollection,
252
274
  getCollectionFromPaths,
275
+ getCollectionFromIds,
253
276
  isUrlCollectionPath,
254
277
  urlPathToDataPath,
255
278
  buildUrlCollectionPath,
@@ -259,7 +282,8 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
259
282
  topLevelNavigation,
260
283
  baseLocation,
261
284
  refreshNavigation,
262
- getParentReferencesFromPath: getAllParentCollectionsForPath
285
+ getParentReferencesFromPath: getAllParentCollectionsForPath,
286
+ getParentCollectionIds
263
287
  }), [baseCollectionPath, baseLocation, basePath, buildCMSUrlPath, buildUrlCollectionPath, buildUrlEditCollectionPath, collections, getAllParentCollectionsForPath, getCollection, getCollectionFromPaths, homeUrl, initialised, isUrlCollectionPath, navigationLoading, navigationLoadingError, refreshNavigation, resolveAliasesFrom, topLevelNavigation, urlPathToDataPath, views]);
264
288
  }
265
289
 
@@ -125,7 +125,7 @@ export function buildSidePanelsFromUrl(path: string, collections: EntityCollecti
125
125
  if (previousEntry.type === "entity") {
126
126
  const lastSidePanel: EntitySidePanelProps<any> = sidePanels[sidePanels.length - 1];
127
127
  if (lastSidePanel)
128
- lastSidePanel.selectedSubPath = navigationEntry.collection.alias ?? navigationEntry.collection.path;
128
+ lastSidePanel.selectedSubPath = navigationEntry.collection.id ?? navigationEntry.collection.path;
129
129
  }
130
130
  }
131
131
  }
@@ -17,7 +17,6 @@ import { UrlComponentPreview } from "./components/UrlComponentPreview";
17
17
  import { StorageThumbnail } from "./components/StorageThumbnail";
18
18
  import { Markdown } from "../ui";
19
19
  import { StringPropertyPreview } from "./property_previews/StringPropertyPreview";
20
- import { ArrayOfMapsPreview } from "./property_previews/ArrayOfMapsPreview";
21
20
  import { ArrayPropertyPreview } from "./property_previews/ArrayPropertyPreview";
22
21
  import { ArrayOfReferencesPreview } from "./property_previews/ArrayOfReferencesPreview";
23
22
  import { ArrayOfStorageComponentsPreview } from "./property_previews/ArrayOfStorageComponentsPreview";
@@ -18,6 +18,14 @@ import { ExportConfig } from "./export_import";
18
18
  */
19
19
  export interface EntityCollection<M extends Record<string, any> = any, UserType extends User = User> {
20
20
 
21
+ /**
22
+ * You can set an alias that will be used internally instead of the `path`.
23
+ * The `alias` value will be used to determine the URL of the collection,
24
+ * while `path` will still be used in the datasource.
25
+ * Note that you can use this value in reference properties too.
26
+ */
27
+ id: string;
28
+
21
29
  /**
22
30
  * Name of the collection, typically plural.
23
31
  * E.g. `Products`, `Blog`
@@ -48,14 +56,6 @@ export interface EntityCollection<M extends Record<string, any> = any, UserType
48
56
  */
49
57
  collectionGroup?: boolean;
50
58
 
51
- /**
52
- * You can set an alias that will be used internally instead of the `path`.
53
- * The `alias` value will be used to determine the URL of the collection,
54
- * while `path` will still be used in the datasource.
55
- * Note that you can use this value in reference properties too.
56
- */
57
- alias?: string;
58
-
59
59
  /**
60
60
  * Icon key to use in this collection.
61
61
  * You can use any of the icons in the Material specs:
@@ -300,7 +300,7 @@ export interface CollectionActionsProps<M extends Record<string, any> = any, Use
300
300
  /**
301
301
  * Array of the parent path segments like `['users']`
302
302
  */
303
- parentPathSegments: string[];
303
+ parentCollectionIds: string[];
304
304
 
305
305
  /**
306
306
  * The collection configuration
@@ -1,7 +1,7 @@
1
1
  import React from "react";
2
2
  import { User } from "./user";
3
3
  import { AuthController } from "./auth";
4
- import { DataSource, DataSourceDelegate } from "./datasource";
4
+ import { DataSourceDelegate } from "./datasource";
5
5
  import { EntityCollection, EntityCustomView } from "./collections";
6
6
  import { CMSView } from "./navigation";
7
7
  import { FireCMSContext } from "./firecms_context";
@@ -24,3 +24,4 @@ export * from "./analytics";
24
24
  export * from "./firecms";
25
25
  export * from "./appcheck";
26
26
  export * from "./export_import";
27
+ export * from "./modify_collections";
@@ -0,0 +1,6 @@
1
+ import { EntityCollection } from "./collections";
2
+
3
+ export type ModifyCollectionProps = {
4
+ collection: EntityCollection,
5
+ parentPaths: string[],
6
+ };
@@ -52,6 +52,11 @@ export type NavigationController = {
52
52
  getCollection: <EC extends EntityCollection = EntityCollection<any>>(pathOrAlias: string,
53
53
  entityId?: string,
54
54
  includeUserOverride?: boolean) => EC | undefined;
55
+ /**
56
+ * Get the collection configuration from its parent path segments.
57
+ */
58
+ getCollectionFromIds: <EC extends EntityCollection = EntityCollection<any>>(ids: string[]) => EC | undefined;
59
+
55
60
  /**
56
61
  * Get the collection configuration from its parent path segments.
57
62
  */
@@ -128,6 +133,12 @@ export type NavigationController = {
128
133
  * @param path
129
134
  */
130
135
  getParentReferencesFromPath: (path: string) => EntityReference[];
136
+
137
+ /**
138
+ * Retrieve all the related parent collection ids for a given path
139
+ * @param path
140
+ */
141
+ getParentCollectionIds: (path: string) => string[];
131
142
  }
132
143
 
133
144
  /**
@@ -116,7 +116,7 @@ export type FireCMSPlugin<PROPS = any, FORM_PROPS = any, EC extends EntityCollec
116
116
  property: ResolvedProperty,
117
117
  propertyKey: string,
118
118
  fullPath: string,
119
- parentPathSegments: string[],
119
+ parentCollectionIds: string[],
120
120
  onHover: boolean,
121
121
  collection: EC;
122
122
  }>;
@@ -127,7 +127,7 @@ export type FireCMSPlugin<PROPS = any, FORM_PROPS = any, EC extends EntityCollec
127
127
  */
128
128
  AddColumnComponent?: React.ComponentType<{
129
129
  fullPath: string,
130
- parentPathSegments: string[],
130
+ parentCollectionIds: string[],
131
131
  collection: EC;
132
132
  }>;
133
133
  }