@firecms/core 3.0.0-beta.4.pre.2 → 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 (109) hide show
  1. package/README.md +1 -1
  2. package/dist/components/ClearFilterSortButton.d.ts +5 -0
  3. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +11 -11
  4. package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +1 -1
  5. package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +1 -4
  6. package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +11 -1
  7. package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +11 -0
  8. package/dist/components/EntityPreview.d.ts +2 -2
  9. package/dist/components/SelectableTable/SelectableTable.d.ts +1 -1
  10. package/dist/components/common/types.d.ts +1 -1
  11. package/dist/contexts/AuthControllerContext.d.ts +1 -1
  12. package/dist/form/components/ErrorFocus.d.ts +1 -1
  13. package/dist/hooks/data/delete.d.ts +2 -2
  14. package/dist/hooks/data/save.d.ts +1 -1
  15. package/dist/hooks/data/useDataSource.d.ts +1 -1
  16. package/dist/hooks/data/useEntityFetch.d.ts +3 -3
  17. package/dist/hooks/index.d.ts +1 -0
  18. package/dist/hooks/useBuildNavigationController.d.ts +1 -2
  19. package/dist/hooks/useProjectLog.d.ts +2 -2
  20. package/dist/hooks/useValidateAuthenticator.d.ts +21 -0
  21. package/dist/index.es.js +3948 -3737
  22. package/dist/index.es.js.map +1 -1
  23. package/dist/index.umd.js +5 -5
  24. package/dist/index.umd.js.map +1 -1
  25. package/dist/internal/useBuildDataSource.d.ts +1 -16
  26. package/dist/internal/useRestoreScroll.d.ts +1 -1
  27. package/dist/preview/PropertyPreviewProps.d.ts +1 -4
  28. package/dist/types/auth.d.ts +30 -1
  29. package/dist/types/collections.d.ts +8 -4
  30. package/dist/types/datasource.d.ts +3 -6
  31. package/dist/types/entities.d.ts +5 -1
  32. package/dist/types/entity_callbacks.d.ts +2 -2
  33. package/dist/types/index.d.ts +1 -1
  34. package/dist/types/navigation.d.ts +4 -4
  35. package/dist/types/plugins.d.ts +5 -3
  36. package/dist/types/properties.d.ts +2 -2
  37. package/dist/types/roles.d.ts +31 -0
  38. package/dist/types/storage.d.ts +11 -3
  39. package/dist/types/user.d.ts +5 -0
  40. package/dist/util/collections.d.ts +1 -1
  41. package/dist/util/entities.d.ts +1 -1
  42. package/dist/util/navigation_utils.d.ts +2 -2
  43. package/dist/util/resolutions.d.ts +5 -5
  44. package/dist/util/useTraceUpdate.d.ts +1 -0
  45. package/package.json +23 -20
  46. package/src/components/ClearFilterSortButton.tsx +41 -0
  47. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +10 -11
  48. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +1 -1
  49. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +16 -19
  50. package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +1 -1
  51. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +27 -32
  52. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +11 -6
  53. package/src/components/EntityCollectionView/EntityCollectionView.tsx +28 -5
  54. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +68 -0
  55. package/src/components/EntityPreview.tsx +5 -2
  56. package/src/components/EntityView.tsx +1 -1
  57. package/src/components/HomePage/DefaultHomePage.tsx +2 -2
  58. package/src/components/HomePage/NavigationCard.tsx +1 -1
  59. package/src/components/ReferenceWidget.tsx +1 -1
  60. package/src/components/SelectableTable/SelectableTable.tsx +1 -1
  61. package/src/components/SelectableTable/filters/BooleanFilterField.tsx +2 -3
  62. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +23 -8
  63. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +24 -5
  64. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +35 -15
  65. package/src/components/VirtualTable/VirtualTable.tsx +28 -20
  66. package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +1 -1
  67. package/src/components/common/types.tsx +1 -1
  68. package/src/contexts/AuthControllerContext.tsx +1 -1
  69. package/src/core/FireCMS.tsx +2 -3
  70. package/src/core/field_configs.tsx +1 -2
  71. package/src/form/EntityForm.tsx +1 -1
  72. package/src/form/field_bindings/DateTimeFieldBinding.tsx +1 -1
  73. package/src/hooks/data/delete.ts +3 -3
  74. package/src/hooks/data/save.ts +2 -1
  75. package/src/hooks/data/useDataSource.tsx +1 -1
  76. package/src/hooks/data/useEntityFetch.tsx +3 -3
  77. package/src/hooks/index.tsx +2 -0
  78. package/src/hooks/useBuildLocalConfigurationPersistence.tsx +9 -10
  79. package/src/hooks/useBuildModeController.tsx +11 -5
  80. package/src/hooks/useBuildNavigationController.tsx +136 -59
  81. package/src/hooks/useProjectLog.tsx +8 -6
  82. package/src/hooks/useValidateAuthenticator.tsx +115 -0
  83. package/src/internal/useBuildDataSource.ts +42 -47
  84. package/src/internal/useBuildSideEntityController.tsx +18 -12
  85. package/src/preview/PropertyPreview.tsx +2 -12
  86. package/src/preview/PropertyPreviewProps.tsx +1 -11
  87. package/src/preview/components/BooleanPreview.tsx +4 -2
  88. package/src/preview/components/ReferencePreview.tsx +1 -1
  89. package/src/types/auth.tsx +40 -1
  90. package/src/types/collections.ts +8 -4
  91. package/src/types/datasource.ts +8 -5
  92. package/src/types/entities.ts +9 -1
  93. package/src/types/entity_callbacks.ts +2 -2
  94. package/src/types/index.ts +1 -1
  95. package/src/types/navigation.ts +6 -6
  96. package/src/types/plugins.tsx +6 -5
  97. package/src/types/properties.ts +5 -4
  98. package/src/types/roles.ts +41 -0
  99. package/src/types/storage.ts +12 -3
  100. package/src/types/user.ts +7 -0
  101. package/src/util/collections.ts +1 -1
  102. package/src/util/entities.ts +1 -1
  103. package/src/util/navigation_utils.ts +6 -6
  104. package/src/util/strings.ts +2 -2
  105. package/src/util/useTraceUpdate.tsx +2 -1
  106. package/dist/internal/useLocaleConfig.d.ts +0 -1
  107. package/dist/types/appcheck.d.ts +0 -26
  108. package/src/internal/useLocaleConfig.tsx +0 -18
  109. package/src/types/appcheck.ts +0 -29
@@ -34,6 +34,7 @@ export const useBuildSideEntityController = (navigation: NavigationController,
34
34
  // only on initialisation, create panels from URL
35
35
  useEffect(() => {
36
36
  if (!navigation.loading && !initialised.current) {
37
+ console.debug("Initialising side entity controller");
37
38
  if (navigation.isUrlCollectionPath(location.pathname)) {
38
39
  const newFlag = location.hash === `#${NEW_URL_HASH}`;
39
40
  const entityOrCollectionPath = navigation.urlPathToDataPath(location.pathname);
@@ -42,15 +43,17 @@ export const useBuildSideEntityController = (navigation: NavigationController,
42
43
  const panel = panelsFromUrl[i];
43
44
  setTimeout(() => {
44
45
  if (i === 0)
45
- sideDialogsController.replace(propsToSidePanel(panel, navigation, smallLayout));
46
+ sideDialogsController.replace(propsToSidePanel(panel, navigation.buildUrlCollectionPath, navigation.resolveAliasesFrom, smallLayout));
46
47
  else
47
- sideDialogsController.open(propsToSidePanel(panel, navigation, smallLayout))
48
+ sideDialogsController.open(propsToSidePanel(panel, navigation.buildUrlCollectionPath, navigation.resolveAliasesFrom, smallLayout))
48
49
  }, 1);
49
50
  }
51
+ } else {
52
+ // console.warn("Location path is not a collection path");
50
53
  }
51
54
  initialised.current = true;
52
55
  }
53
- }, [location, navigation, sideDialogsController, smallLayout]);
56
+ }, [location, navigation.loading, navigation.isUrlCollectionPath, navigation.buildUrlCollectionPath, navigation.resolveAliasesFrom, sideDialogsController, smallLayout, navigation]);
54
57
 
55
58
  const close = useCallback(() => {
56
59
  sideDialogsController.close();
@@ -73,9 +76,9 @@ export const useBuildSideEntityController = (navigation: NavigationController,
73
76
  sideDialogsController.open(propsToSidePanel({
74
77
  selectedSubPath: defaultSelectedView,
75
78
  ...props,
76
- }, navigation, smallLayout));
79
+ }, navigation.buildUrlCollectionPath, navigation.resolveAliasesFrom, smallLayout));
77
80
 
78
- }, [sideDialogsController, navigation, smallLayout]);
81
+ }, [sideDialogsController, navigation.buildUrlCollectionPath, navigation.resolveAliasesFrom, smallLayout]);
79
82
 
80
83
  const replace = useCallback((props: EntitySidePanelProps<any>) => {
81
84
 
@@ -83,9 +86,9 @@ export const useBuildSideEntityController = (navigation: NavigationController,
83
86
  throw Error("If you want to copy an entity you need to provide an entityId");
84
87
  }
85
88
 
86
- sideDialogsController.replace(propsToSidePanel(props, navigation, smallLayout));
89
+ sideDialogsController.replace(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveAliasesFrom, smallLayout));
87
90
 
88
- }, [navigation, sideDialogsController, smallLayout]);
91
+ }, [navigation.buildUrlCollectionPath, navigation.resolveAliasesFrom, sideDialogsController, smallLayout]);
89
92
 
90
93
  return {
91
94
  close,
@@ -146,14 +149,17 @@ export function buildSidePanelsFromUrl(path: string, collections: EntityCollecti
146
149
  return sidePanels;
147
150
  }
148
151
 
149
- const propsToSidePanel = (props: EntitySidePanelProps<any>, navigation: NavigationController, smallLayout: boolean): SideDialogPanelProps => {
152
+ const propsToSidePanel = (props: EntitySidePanelProps<any>,
153
+ buildUrlCollectionPath: (path: string) => string,
154
+ resolveAliasesFrom: (pathWithAliases: string) => string,
155
+ smallLayout: boolean): SideDialogPanelProps => {
150
156
 
151
157
  const collectionPath = removeInitialAndTrailingSlashes(props.path);
152
158
 
153
159
  const newPath = props.entityId
154
- ? navigation.buildUrlCollectionPath(`${collectionPath}/${props.entityId}/${props.selectedSubPath || ""}`)
155
- : navigation.buildUrlCollectionPath(`${collectionPath}#${NEW_URL_HASH}`);
156
- const resolvedPath = navigation.resolveAliasesFrom(props.path);
160
+ ? buildUrlCollectionPath(`${collectionPath}/${props.entityId}/${props.selectedSubPath || ""}`)
161
+ : buildUrlCollectionPath(`${collectionPath}#${NEW_URL_HASH}`);
162
+ const resolvedPath = resolveAliasesFrom(props.path);
157
163
 
158
164
  const resolvedPanelProps: EntitySidePanelProps<any> = {
159
165
  ...props,
@@ -164,7 +170,7 @@ const propsToSidePanel = (props: EntitySidePanelProps<any>, navigation: Navigati
164
170
  key: `${props.path}/${props.entityId}`,
165
171
  component: <EntitySidePanel {...resolvedPanelProps}/>,
166
172
  urlPath: newPath,
167
- parentUrlPath: navigation.buildUrlCollectionPath(collectionPath),
173
+ parentUrlPath: buildUrlCollectionPath(collectionPath),
168
174
  width: getEntityViewWidth(props, smallLayout),
169
175
  onClose: props.onClose
170
176
  });
@@ -92,7 +92,7 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
92
92
  size={props.size}
93
93
  storagePathOrDownloadUrl={value}/>;
94
94
  } else if (stringProperty.markdown) {
95
- content = <Markdown source={value}/>;
95
+ content = <Markdown source={value} size={"small"}/>;
96
96
  } else {
97
97
  content = <StringPropertyPreview {...props}
98
98
  property={stringProperty}
@@ -113,17 +113,7 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
113
113
  content = <ArrayPropertyPreview {...props}
114
114
  value={value}
115
115
  property={property as ResolvedArrayProperty}/>;
116
- }
117
- // else if (arrayProperty.of.dataType === "map") {
118
- // content =
119
- // <ArrayOfMapsPreview propertyKey={propertyKey}
120
- // property={property as ResolvedArrayProperty}
121
- // value={value as Record<string, any>[]} // This might be wrong
122
- // entity={entity}
123
- // size={size}
124
- // />;
125
- // }
126
- else if (arrayProperty.of.dataType === "reference") {
116
+ } else if (arrayProperty.of.dataType === "reference") {
127
117
  content = <ArrayOfReferencesPreview {...props}
128
118
  value={value}
129
119
  property={property as ResolvedArrayProperty}/>;
@@ -8,7 +8,7 @@ export type PreviewSize = "medium" | "small" | "tiny";
8
8
  /**
9
9
  * @group Preview components
10
10
  */
11
- export interface PropertyPreviewProps<T extends CMSType = any, CustomProps = any, M extends Record<string, any> = Record<string, any>> {
11
+ export interface PropertyPreviewProps<T extends CMSType = any, CustomProps = any> {
12
12
  /**
13
13
  * Name of the property
14
14
  */
@@ -24,11 +24,6 @@ export interface PropertyPreviewProps<T extends CMSType = any, CustomProps = any
24
24
  */
25
25
  property: Property<T> | ResolvedProperty<T>;
26
26
 
27
- /**
28
- * Click handler
29
- */
30
- // onClick?: () => void;
31
-
32
27
  /**
33
28
  * Desired size of the preview, depending on the context.
34
29
  */
@@ -51,9 +46,4 @@ export interface PropertyPreviewProps<T extends CMSType = any, CustomProps = any
51
46
  */
52
47
  customProps?: CustomProps;
53
48
 
54
- /**
55
- * Entity this property refers to
56
- */
57
- // entity?: Entity<M>;
58
-
59
49
  }
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { Checkbox } from "@firecms/ui";
2
+ import { Checkbox, cn } from "@firecms/ui";
3
3
  import { PreviewSize } from "../PropertyPreviewProps";
4
4
  import { Property } from "../../types";
5
5
 
@@ -17,8 +17,10 @@ export function BooleanPreview({
17
17
  }): React.ReactElement {
18
18
  return <div className={"flex flex-row gap-2 items-center"}>
19
19
  <Checkbox checked={value}
20
+ padding={false}
20
21
  size={size}
21
22
  color={"secondary"}/>
22
- {property.name && <span className={size === "tiny" ? "text-sm" : ""}>{property.name}</span>}
23
+ {property.name && <span
24
+ className={cn("text-text-secondary dark:text-text-secondary-dark", size === "tiny" ? "text-sm" : "")}>{property.name}</span>}
23
25
  </div>;
24
26
  }
@@ -64,7 +64,7 @@ function ReferencePreviewInternal<M extends Record<string, any>>({
64
64
 
65
65
  const navigationController = useNavigationController();
66
66
 
67
- const collection = navigationController.getCollection<EntityCollection<M>>(reference.path);
67
+ const collection = navigationController.getCollection(reference.path);
68
68
  if (!collection) {
69
69
  if (customizationController.components?.missingReference) {
70
70
  return <customizationController.components.missingReference path={reference.path}/>;
@@ -1,4 +1,7 @@
1
1
  import { User } from "./user";
2
+ import { Role } from "./roles";
3
+ import { DataSourceDelegate } from "./datasource";
4
+ import { StorageSource } from "./storage";
2
5
 
3
6
  /**
4
7
  * Controller for retrieving the logged user or performing auth related operations.
@@ -6,7 +9,7 @@ import { User } from "./user";
6
9
  * to do it as the result of a hook.
7
10
  * @group Hooks and utilities
8
11
  */
9
- export type AuthController<UserType extends User = User, ExtraData extends any = any> = {
12
+ export type AuthController<UserType extends User = any, ExtraData extends any = any> = {
10
13
 
11
14
  /**
12
15
  * The user currently logged in
@@ -14,6 +17,11 @@ export type AuthController<UserType extends User = User, ExtraData extends any =
14
17
  */
15
18
  user: UserType | null;
16
19
 
20
+ /**
21
+ * Roles related to the logged user
22
+ */
23
+ roles?: Role[];
24
+
17
25
  /**
18
26
  * Initial loading flag. It is used not to display the login screen
19
27
  * when the app first loads, and it has not been checked whether the user
@@ -56,4 +64,35 @@ export type AuthController<UserType extends User = User, ExtraData extends any =
56
64
 
57
65
  setExtra: (extra: ExtraData) => void;
58
66
 
67
+ // setUser?: (user: UserType | null) => void;
68
+
69
+ // setRoles?: (roles: Role[]) => void;
59
70
  };
71
+
72
+ /**
73
+ * Implement this function to allow access to specific users.
74
+ * @group Hooks and utilities
75
+ */
76
+ export type Authenticator<UserType extends User = User, Controller extends AuthController<UserType> = AuthController<UserType>> = (props: {
77
+
78
+ /**
79
+ * Logged-in user or null
80
+ */
81
+ user: UserType | null;
82
+
83
+ /**
84
+ * AuthController
85
+ */
86
+ authController: Controller;
87
+
88
+ /**
89
+ * Connector to your database, e.g. your Firestore database
90
+ */
91
+ dataSourceDelegate: DataSourceDelegate;
92
+
93
+ /**
94
+ * Used storage implementation
95
+ */
96
+ storageSource: StorageSource;
97
+
98
+ }) => boolean | Promise<boolean>;
@@ -17,7 +17,7 @@ import { EntityOverrides } from "./entity_overrides";
17
17
  *
18
18
  * @group Models
19
19
  */
20
- export interface EntityCollection<M extends Record<string, any> = any, UserType extends User = User> {
20
+ export interface EntityCollection<M extends Record<string, any> = any, UserType extends User = any> {
21
21
 
22
22
  /**
23
23
  * You can set an alias that will be used internally instead of the `path`.
@@ -107,6 +107,10 @@ export interface EntityCollection<M extends Record<string, any> = any, UserType
107
107
  * `subcollection:`. e.g. `subcollection:orders`.
108
108
  * - If you are using a collection group, you will also have an
109
109
  * additional `collectionGroupParent` column.
110
+ * You can use this prop to hide some properties from the table view.
111
+ * Note that if you set this prop, other ways to hide fields, like
112
+ * `hidden` in the property definition,will be ignored.
113
+ * `propertiesOrder` has precedence over `hidden`.
110
114
  */
111
115
  propertiesOrder?: Extract<keyof M, string>[];
112
116
 
@@ -147,7 +151,7 @@ export interface EntityCollection<M extends Record<string, any> = any, UserType
147
151
  * is being created, updated or deleted.
148
152
  * Useful for adding your own logic or blocking the execution of the operation.
149
153
  */
150
- callbacks?: EntityCallbacks<M>;
154
+ callbacks?: EntityCallbacks<M, UserType>;
151
155
 
152
156
  /**
153
157
  * Builder for rendering additional components such as buttons in the
@@ -451,7 +455,7 @@ export interface AdditionalFieldDelegate<M extends Record<string, any> = any,
451
455
  * view.
452
456
  * @param entity
453
457
  */
454
- value?: (props: { entity: Entity<M>, context: FireCMSContext }) => string | number | Promise<string | number> | undefined;
458
+ value?: (props: { entity: Entity<M>, context: FireCMSContext<any> }) => string | number | Promise<string | number> | undefined;
455
459
  }
456
460
 
457
461
  /**
@@ -523,7 +527,7 @@ export type EntityTableController<M extends Record<string, any> = any> = {
523
527
  filterValues?: FilterValues<Extract<keyof M, string>>;
524
528
  setFilterValues?: (filterValues: FilterValues<Extract<keyof M, string>>) => void;
525
529
  sortBy?: [Extract<keyof M, string>, "asc" | "desc"];
526
- setSortBy?: (sortBy: [Extract<keyof M, string>, "asc" | "desc"]) => void;
530
+ setSortBy?: (sortBy?: [Extract<keyof M, string>, "asc" | "desc"]) => void;
527
531
  searchString?: string;
528
532
  setSearchString?: (searchString?: string) => void;
529
533
  clearFilter?: () => void;
@@ -8,7 +8,7 @@ import { ResolvedEntityCollection } from "./resolved_entities";
8
8
  export interface FetchEntityProps<M extends Record<string, any> = any> {
9
9
  path: string;
10
10
  entityId: string;
11
- collection?: EntityCollection<M>
11
+ collection?: EntityCollection<M, any>
12
12
  }
13
13
 
14
14
  /**
@@ -216,6 +216,7 @@ export interface DataSource {
216
216
  * @param props
217
217
  */
218
218
  isFilterCombinationValid?(props: FilterCombinationValidProps): boolean;
219
+
219
220
  }
220
221
 
221
222
  export type FilterCombinationValidProps = {
@@ -366,24 +367,26 @@ export interface DataSourceDelegate {
366
367
  * Convert a FireCMS reference to a reference that can be used by the datasource
367
368
  * @param reference
368
369
  */
369
- buildReference: (reference: EntityReference) => any,
370
+ // buildReference: (reference: EntityReference) => any,
370
371
 
371
372
  /**
372
373
  * Convert a FireCMS GeoPoint to a GeoPoint that can be used by the datasource
373
374
  * @param geoPoint
374
375
  */
375
- buildGeoPoint: (geoPoint: GeoPoint) => any,
376
+ // buildGeoPoint: (geoPoint: GeoPoint) => any,
376
377
 
377
378
  /**
378
379
  * Get the object to generate the current time in the datasource
379
380
  */
380
381
  currentTime(): any;
381
382
 
382
- buildDate: (date: Date) => any;
383
+ // buildDate: (date: Date) => any;
383
384
 
384
- buildDeleteFieldValue: () => any;
385
+ // buildDeleteFieldValue: () => any;
385
386
 
386
387
  delegateToCMSModel: (data: any) => any;
387
388
 
389
+ cmsToDelegateModel: (data: any) => any;
390
+
388
391
  setDateToMidnight: (input?: any) => any;
389
392
  }
@@ -37,7 +37,7 @@ export type EntityValues<M extends object> = M;
37
37
  /**
38
38
  * Class used to create a reference to an entity in a different path
39
39
  */
40
- export class EntityReference<M extends Record<string, any> = any> {
40
+ export class EntityReference {
41
41
  /**
42
42
  * ID of the entity
43
43
  */
@@ -78,3 +78,11 @@ export class GeoPoint {
78
78
  this.longitude = longitude;
79
79
  }
80
80
  }
81
+
82
+ export class Vector {
83
+ readonly value: number[];
84
+
85
+ constructor(value: number[]) {
86
+ this.value = value;
87
+ }
88
+ }
@@ -78,7 +78,7 @@ export interface EntityOnFetchProps<M extends Record<string, any> = any, UserTyp
78
78
  /**
79
79
  * Collection of the entity
80
80
  */
81
- collection: EntityCollection<M>;
81
+ collection: EntityCollection<M, UserType>;
82
82
 
83
83
  /**
84
84
  * Full path of the CMS where this collection is being fetched.
@@ -193,7 +193,7 @@ export interface EntityOnDeleteProps<M extends Record<string, any> = any, UserTy
193
193
  /**
194
194
  * Context of the app status
195
195
  */
196
- context: FireCMSContext;
196
+ context: FireCMSContext<UserType>;
197
197
  }
198
198
 
199
199
  /**
@@ -22,7 +22,7 @@ export * from "./local_config_persistence";
22
22
  export * from "./plugins";
23
23
  export * from "./analytics";
24
24
  export * from "./firecms";
25
- export * from "./appcheck";
25
+ export * from "./roles";
26
26
  export * from "./export_import";
27
27
  export * from "./modify_collections";
28
28
  export * from "./analytics_controller";
@@ -7,7 +7,7 @@ import { EntityReference } from "./entities";
7
7
  * attributes.
8
8
  * @group Models
9
9
  */
10
- export type NavigationController = {
10
+ export type NavigationController<EC extends EntityCollection = EntityCollection<any>> = {
11
11
 
12
12
  /**
13
13
  * List of the mapped collections in the CMS.
@@ -56,18 +56,18 @@ export type NavigationController = {
56
56
  * Get the collection configuration for a given path.
57
57
  * The collection is resolved from the given path or alias.
58
58
  */
59
- getCollection: <EC extends EntityCollection = EntityCollection<any>>(pathOrAlias: string,
60
- entityId?: string,
61
- includeUserOverride?: boolean) => EC | undefined;
59
+ getCollection: (pathOrId: string,
60
+ entityId?: string,
61
+ includeUserOverride?: boolean) => EC | undefined;
62
62
  /**
63
63
  * Get the collection configuration from its parent path segments.
64
64
  */
65
- getCollectionFromIds: <EC extends EntityCollection = EntityCollection<any>>(ids: string[]) => EC | undefined;
65
+ getCollectionFromIds: (ids: string[]) => EC | undefined;
66
66
 
67
67
  /**
68
68
  * Get the collection configuration from its parent path segments.
69
69
  */
70
- getCollectionFromPaths: <EC extends EntityCollection = EntityCollection<any>>(pathSegments: string[]) => EC | undefined;
70
+ getCollectionFromPaths: (pathSegments: string[]) => EC | undefined;
71
71
 
72
72
  /**
73
73
  * Default path under the navigation routes of the CMS will be created
@@ -7,19 +7,18 @@ import { FieldProps, FormContext } from "./fields";
7
7
  import { CMSType, Property } from "./properties";
8
8
  import { EntityStatus } from "./entities";
9
9
  import { ResolvedProperty } from "./resolved_entities";
10
- import { CMSView } from "./navigation";
11
10
 
12
11
  /**
13
12
  * Interface used to define plugins for FireCMS.
14
13
  * NOTE: This is a work in progress and the API is not stable yet.
15
14
  * @group Core
16
15
  */
17
- export type FireCMSPlugin<PROPS = any, FORM_PROPS = any, EC extends EntityCollection = EntityCollection, COL_ACTIONS_PROPS = any> = {
16
+ export type FireCMSPlugin<PROPS = any, FORM_PROPS = any, EC extends EntityCollection = EntityCollection, COL_ACTIONS_PROPS = any, COL_ACTIONS_START__PROPS = any> = {
18
17
 
19
18
  /**
20
- * Name of the plugin
19
+ * Key of the plugin. This is used to identify the plugin in the CMS.
21
20
  */
22
- name: string;
21
+ key: string;
23
22
 
24
23
  /**
25
24
  * If this flag is set to true, no content will be shown in the CMS
@@ -94,9 +93,11 @@ export type FireCMSPlugin<PROPS = any, FORM_PROPS = any, EC extends EntityCollec
94
93
  * toolbar.
95
94
  */
96
95
  CollectionActions?: React.ComponentType<CollectionActionsProps<any, any, EC> & COL_ACTIONS_PROPS> | React.ComponentType<CollectionActionsProps<any, any, EC> & COL_ACTIONS_PROPS>[];
97
-
98
96
  collectionActionsProps?: COL_ACTIONS_PROPS;
99
97
 
98
+ CollectionActionsStart?: React.ComponentType<CollectionActionsProps<any, any, EC> & COL_ACTIONS_START__PROPS> | React.ComponentType<CollectionActionsProps<any, any, EC> & COL_ACTIONS_START__PROPS>[];
99
+ collectionActionsStartProps?: COL_ACTIONS_START__PROPS;
100
+
100
101
  showTextSearchBar?: (props: {
101
102
  context: FireCMSContext,
102
103
  path: string,
@@ -1,7 +1,7 @@
1
1
  import React from "react";
2
2
  import { FieldProps } from "./fields";
3
3
  import { PropertyPreviewProps } from "../preview";
4
- import { EntityReference, EntityValues, GeoPoint } from "./entities";
4
+ import { EntityReference, EntityValues, GeoPoint, Vector } from "./entities";
5
5
  import { ResolvedArrayProperty, ResolvedStringProperty } from "./resolved_entities";
6
6
  import { FilterValues } from "./collections";
7
7
  import { ChipColorKey, ChipColorScheme } from "@firecms/ui";
@@ -15,9 +15,10 @@ export type DataType<T extends CMSType = CMSType> =
15
15
  T extends boolean ? "boolean" :
16
16
  T extends Date ? "date" :
17
17
  T extends GeoPoint ? "geopoint" :
18
- T extends EntityReference ? "reference" :
19
- T extends Array<CMSType> ? "array" :
20
- T extends Record<string, any> ? "map" : never;
18
+ T extends Vector ? "vector" :
19
+ T extends EntityReference ? "reference" :
20
+ T extends Array<CMSType> ? "array" :
21
+ T extends Record<string, any> ? "map" : never;
21
22
 
22
23
  /**
23
24
  * @group Entity properties
@@ -0,0 +1,41 @@
1
+ import { Permissions } from "../index";
2
+
3
+ export type Role = {
4
+
5
+ /**
6
+ * ID of the role
7
+ */
8
+ id: string;
9
+
10
+ /**
11
+ * Name of the role
12
+ */
13
+ name: string;
14
+
15
+ /**
16
+ * If this flag is true, the user can perform any action
17
+ */
18
+ isAdmin?: boolean;
19
+
20
+ /**
21
+ * Default permissions for all collections for this role.
22
+ * You can override this values at the collection level using
23
+ * {@link collectionPermissions}
24
+ */
25
+ defaultPermissions?: Permissions;
26
+
27
+ /**
28
+ * Record of stripped collection ids to their permissions.
29
+ * @see stripCollectionPath
30
+ */
31
+ collectionPermissions?: Record<string, Permissions>;
32
+
33
+ config?: {
34
+
35
+ createCollections?: boolean;
36
+
37
+ editCollections?: boolean | "own";
38
+
39
+ deleteCollections?: boolean | "own";
40
+ }
41
+ }
@@ -6,6 +6,7 @@ export interface UploadFileProps {
6
6
  fileName?: string,
7
7
  path?: string,
8
8
  metadata?: any,
9
+ bucket?: string
9
10
  }
10
11
 
11
12
  /**
@@ -16,6 +17,10 @@ export interface UploadFileResult {
16
17
  * Storage path including the file name where the file was uploaded.
17
18
  */
18
19
  path: string;
20
+ /**
21
+ * Bucket where the file was uploaded
22
+ */
23
+ bucket: string;
19
24
  }
20
25
 
21
26
  /**
@@ -73,24 +78,28 @@ export interface StorageSource {
73
78
  * @param fileName
74
79
  * @param path
75
80
  * @param metadata
81
+ * @param bucket
76
82
  */
77
83
  uploadFile: ({
78
84
  file,
79
85
  fileName,
80
86
  path,
81
- metadata
87
+ metadata,
88
+ bucket
82
89
  }: UploadFileProps) => Promise<UploadFileResult>;
83
90
 
84
91
  /**
85
92
  * Convert a storage path or URL into a download configuration
86
93
  * @param path
94
+ * @param bucket
87
95
  */
88
- getDownloadURL: (pathOrUrl: string) => Promise<DownloadConfig>;
96
+ getDownloadURL: (pathOrUrl: string, bucket?: string) => Promise<DownloadConfig>;
89
97
 
90
98
  /**
91
99
  * Get a file from a storage path.
92
100
  * It returns null if the file does not exist.
93
101
  * @param props
102
+ * @param bucket
94
103
  */
95
- getFile: (path:string) => Promise<File | null>;
104
+ getFile: (path:string, bucket?: string) => Promise<File | null>;
96
105
  }
package/src/types/user.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { Role } from "./roles";
2
+
1
3
  /**
2
4
  * This interface represents a user.
3
5
  * It has some of the same fields as a Firebase User.
@@ -34,4 +36,9 @@ export type User = {
34
36
  */
35
37
  readonly isAnonymous: boolean;
36
38
 
39
+ /**
40
+ *
41
+ */
42
+ roles?: Role[];
43
+
37
44
  };
@@ -58,7 +58,7 @@ export function resolveDefaultSelectedView(
58
58
  * @param collections
59
59
  * @param permissionsBuilder
60
60
  */
61
- export const applyPermissionsFunctionIfEmpty = (collections: EntityCollection[], permissionsBuilder?: PermissionsBuilder): EntityCollection[] => {
61
+ export const applyPermissionsFunctionIfEmpty = (collections: EntityCollection[], permissionsBuilder?: PermissionsBuilder<any, any>): EntityCollection[] => {
62
62
 
63
63
  return collections.map(collection => {
64
64
  if (collection.permissions) {
@@ -139,7 +139,7 @@ export function sanitizeData<M extends Record<string, any>>
139
139
  return result;
140
140
  }
141
141
 
142
- export function getReferenceFrom<M extends Record<string, any>>(entity: Entity<M>): EntityReference<M> {
142
+ export function getReferenceFrom<M extends Record<string, any>>(entity: Entity<M>): EntityReference {
143
143
  return new EntityReference(entity.id, entity.path);
144
144
  }
145
145
 
@@ -60,14 +60,14 @@ export function resolveCollectionPathIds(path: string, allCollections: EntityCol
60
60
  /**
61
61
  * Find the corresponding view at any depth for a given path.
62
62
  * Note that path or segments of the paths can be collection aliases.
63
- * @param pathOrAlias
63
+ * @param pathOrId
64
64
  * @param collections
65
65
  */
66
- export function getCollectionByPathOrId(pathOrAlias: string, collections: EntityCollection[]): EntityCollection | undefined {
66
+ export function getCollectionByPathOrId(pathOrId: string, collections: EntityCollection[]): EntityCollection | undefined {
67
67
 
68
- const subpaths = removeInitialAndTrailingSlashes(pathOrAlias).split("/");
68
+ const subpaths = removeInitialAndTrailingSlashes(pathOrId).split("/");
69
69
  if (subpaths.length % 2 === 0) {
70
- throw Error(`getCollectionByPathOrAlias: Collection paths must have an odd number of segments: ${pathOrAlias}`);
70
+ throw Error(`getCollectionByPathOrId: Collection paths must have an odd number of segments: ${pathOrId}`);
71
71
  }
72
72
 
73
73
  const subpathCombinations = getCollectionPathsCombinations(subpaths);
@@ -80,10 +80,10 @@ export function getCollectionByPathOrId(pathOrAlias: string, collections: Entity
80
80
 
81
81
  if (navigationEntry) {
82
82
 
83
- if (subpathCombination === pathOrAlias) {
83
+ if (subpathCombination === pathOrId) {
84
84
  result = navigationEntry;
85
85
  } else if (navigationEntry.subcollections) {
86
- const newPath = pathOrAlias.replace(subpathCombination, "").split("/").slice(2).join("/");
86
+ const newPath = pathOrId.replace(subpathCombination, "").split("/").slice(2).join("/");
87
87
  if (newPath.length > 0)
88
88
  result = getCollectionByPathOrId(newPath, navigationEntry.subcollections);
89
89
  }
@@ -56,8 +56,8 @@ export function unslugify(slug?: string): string {
56
56
  const result = slug.replace(/[-_]/g, " ");
57
57
  return result.replace(/\w\S*/g, function (txt) {
58
58
  return txt.charAt(0).toUpperCase() + txt.substr(1);
59
- });
59
+ }).trim();
60
60
  } else {
61
- return slug;
61
+ return slug.trim();
62
62
  }
63
63
  }