@firecms/core 3.0.0-alpha.28 → 3.0.0-alpha.29

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 (57) hide show
  1. package/dist/core/FireCMS.d.ts +2 -2
  2. package/dist/core/builders.d.ts +2 -2
  3. package/dist/core/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +4 -2
  4. package/dist/core/components/EntityCollectionTable/internal/EntityCollectionRowActions.d.ts +15 -11
  5. package/dist/core/components/EntityCollectionTable/internal/default_entity_actions.d.ts +5 -0
  6. package/dist/core/components/EntityCollectionTable/types.d.ts +1 -37
  7. package/dist/core/components/VirtualTable/VirtualTableProps.d.ts +1 -1
  8. package/dist/core/contexts/DialogsProvider.d.ts +4 -0
  9. package/dist/core/index.d.ts +1 -1
  10. package/dist/core/internal/useBuildNavigationContext.d.ts +3 -3
  11. package/dist/core/util/resolutions.d.ts +1 -1
  12. package/dist/hooks/useDialogsController.d.ts +11 -0
  13. package/dist/index.es.js +8400 -8230
  14. package/dist/index.es.js.map +1 -1
  15. package/dist/index.umd.js +67 -67
  16. package/dist/index.umd.js.map +1 -1
  17. package/dist/styles.d.ts +1 -1
  18. package/dist/types/collections.d.ts +36 -13
  19. package/dist/types/dialogs_controller.d.ts +30 -0
  20. package/dist/types/entity_actions.d.ts +33 -0
  21. package/dist/types/firecms.d.ts +5 -5
  22. package/dist/types/firecms_context.d.ts +7 -0
  23. package/dist/types/index.d.ts +1 -0
  24. package/dist/types/navigation.d.ts +3 -3
  25. package/dist/types/plugins.d.ts +11 -10
  26. package/package.json +3 -3
  27. package/src/components/Sheet.tsx +1 -0
  28. package/src/core/FireCMS.tsx +9 -6
  29. package/src/core/builders.ts +6 -6
  30. package/src/core/components/ArrayContainer.tsx +1 -1
  31. package/src/core/components/EntityCollectionTable/EntityCollectionTable.tsx +16 -9
  32. package/src/core/components/EntityCollectionTable/EntityCollectionTableProps.tsx +5 -2
  33. package/src/core/components/EntityCollectionTable/internal/EntityCollectionRowActions.tsx +96 -79
  34. package/src/core/components/EntityCollectionTable/internal/default_entity_actions.tsx +107 -0
  35. package/src/core/components/EntityCollectionTable/types.tsx +1 -56
  36. package/src/core/components/EntityCollectionView/EntityCollectionView.tsx +66 -42
  37. package/src/core/components/ReferenceSelectionInner.tsx +2 -2
  38. package/src/core/components/VirtualTable/VirtualTable.tsx +4 -6
  39. package/src/core/components/VirtualTable/VirtualTableProps.tsx +1 -1
  40. package/src/core/contexts/DialogsProvider.tsx +50 -0
  41. package/src/core/index.tsx +1 -1
  42. package/src/core/internal/useBuildNavigationContext.tsx +13 -13
  43. package/src/core/internal/useBuildSideEntityController.tsx +9 -1
  44. package/src/form/EntityForm.tsx +63 -6
  45. package/src/hooks/useDialogsController.tsx +14 -0
  46. package/src/hooks/useFireCMSContext.tsx +5 -11
  47. package/src/styles.ts +1 -1
  48. package/src/types/collections.ts +36 -17
  49. package/src/types/dialogs_controller.tsx +31 -0
  50. package/src/types/entity_actions.tsx +36 -0
  51. package/src/types/firecms.tsx +5 -5
  52. package/src/types/firecms_context.tsx +8 -0
  53. package/src/types/index.ts +1 -0
  54. package/src/types/navigation.ts +3 -3
  55. package/src/types/plugins.tsx +11 -10
  56. /package/dist/core/contexts/{SnackbarContext.d.ts → SnackbarProvider.d.ts} +0 -0
  57. /package/src/core/contexts/{SnackbarContext.tsx → SnackbarProvider.tsx} +0 -0
@@ -0,0 +1,50 @@
1
+ import React, { PropsWithChildren, useCallback, useRef, useState } from "react";
2
+ import { DialogControllerEntryProps, DialogsController } from "../../types/dialogs_controller";
3
+
4
+ export const DialogsControllerContext = React.createContext<DialogsController>({} as DialogsController);
5
+
6
+ export const DialogsProvider: React.FC<PropsWithChildren<{}>> = ({ children }) => {
7
+
8
+ const [dialogEntries, setDialogEntries] = useState<DialogControllerEntryProps[]>([]);
9
+ const dialogEntriesRef = useRef<DialogControllerEntryProps[]>(dialogEntries);
10
+
11
+ const updateDialogEntries = (newPanels: DialogControllerEntryProps[]) => {
12
+ dialogEntriesRef.current = newPanels;
13
+ setDialogEntries(newPanels);
14
+ };
15
+
16
+ const close = useCallback(() => {
17
+
18
+ if (dialogEntries.length === 0)
19
+ return;
20
+
21
+ const updatedPanels = [...dialogEntries.slice(0, -1)];
22
+ updateDialogEntries(updatedPanels);
23
+
24
+ }, [dialogEntries]);
25
+
26
+ const open = useCallback((dialogEntry: DialogControllerEntryProps) => {
27
+
28
+ const updatedPanels = [...dialogEntries, dialogEntry];
29
+ updateDialogEntries(updatedPanels);
30
+
31
+ return {
32
+ closeDialog: () => {
33
+ const updatedPanels = dialogEntriesRef.current.filter(e => e.key !== dialogEntry.key);
34
+ updateDialogEntries(updatedPanels);
35
+ }
36
+ }
37
+ }, [dialogEntries]);
38
+
39
+ return (
40
+ <DialogsControllerContext.Provider value={{
41
+ open,
42
+ close
43
+ }}>
44
+ {children}
45
+ {dialogEntries.map((entry, i) => <entry.Component
46
+ key={`dialog_${i}`}
47
+ open={true}/>)}
48
+ </DialogsControllerContext.Provider>
49
+ );
50
+ };
@@ -20,7 +20,7 @@ export * from "./useBuildModeController";
20
20
  export * from "../components/util/useOutsideAlerter";
21
21
  export * from "./useBuildLocalConfigurationPersistence";
22
22
 
23
- export { SnackbarProvider } from "./contexts/SnackbarContext";
23
+ export { SnackbarProvider } from "./contexts/SnackbarProvider";
24
24
  export { ModeControllerProvider } from "./contexts/ModeController";
25
25
 
26
26
  export * from "./contexts/AuthControllerContext";
@@ -25,27 +25,27 @@ import {
25
25
  } from "../util";
26
26
  import { getParentReferencesFromPath } from "../util/parent_references_from_path";
27
27
 
28
- type BuildNavigationContextProps<UserType extends User> = {
28
+ type BuildNavigationContextProps<EC extends EntityCollection, UserType extends User> = {
29
29
  basePath: string,
30
30
  baseCollectionPath: string,
31
31
  authController: AuthController<UserType>;
32
- collections?: EntityCollection[] | EntityCollectionsBuilder;
32
+ collections?: EC[] | EntityCollectionsBuilder<EC>;
33
33
  views?: CMSView[] | CMSViewsBuilder;
34
34
  userConfigPersistence?: UserConfigurationPersistence;
35
35
  plugins?: FireCMSPlugin[];
36
36
  dataSource: DataSource;
37
37
  };
38
38
 
39
- export function useBuildNavigationContext<UserType extends User>({
40
- basePath,
41
- baseCollectionPath,
42
- authController,
43
- collections: baseCollections,
44
- views: baseViews,
45
- userConfigPersistence,
46
- plugins,
47
- dataSource
48
- }: BuildNavigationContextProps<UserType>): NavigationContext {
39
+ export function useBuildNavigationContext<EC extends EntityCollection, UserType extends User>({
40
+ basePath,
41
+ baseCollectionPath,
42
+ authController,
43
+ collections: baseCollections,
44
+ views: baseViews,
45
+ userConfigPersistence,
46
+ plugins,
47
+ dataSource
48
+ }: BuildNavigationContextProps<EC, UserType>): NavigationContext {
49
49
 
50
50
  const location = useLocation();
51
51
 
@@ -288,7 +288,7 @@ function filterOutNotAllowedCollections(resolvedCollections: EntityCollection[],
288
288
  });
289
289
  }
290
290
 
291
- async function resolveCollections(collections: undefined | EntityCollection[] | EntityCollectionsBuilder, authController: AuthController, dataSource: DataSource, plugins?: FireCMSPlugin[]) {
291
+ async function resolveCollections(collections: undefined | EntityCollection[] | EntityCollectionsBuilder<any>, authController: AuthController, dataSource: DataSource, plugins?: FireCMSPlugin[]) {
292
292
  let resolvedCollections: EntityCollection[] = [];
293
293
  if (typeof collections === "function") {
294
294
  resolvedCollections = await collections({
@@ -38,7 +38,15 @@ export const useBuildSideEntityController = (navigation: NavigationContext,
38
38
  const newFlag = location.hash === `#${NEW_URL_HASH}`;
39
39
  const entityOrCollectionPath = navigation.urlPathToDataPath(location.pathname);
40
40
  const panelsFromUrl = buildSidePanelsFromUrl(entityOrCollectionPath, navigation.collections, newFlag);
41
- sideDialogsController.replace(panelsFromUrl.map((props) => propsToSidePanel(props, navigation, smallLayout)));
41
+ for (let i = 0; i < panelsFromUrl.length; i++) {
42
+ const panel = panelsFromUrl[i];
43
+ setTimeout(() => {
44
+ if (i === 0)
45
+ sideDialogsController.replace(propsToSidePanel(panel, navigation, smallLayout));
46
+ else
47
+ sideDialogsController.open(propsToSidePanel(panel, navigation, smallLayout))
48
+ }, 1);
49
+ }
42
50
  }
43
51
  initialised.current = true;
44
52
  }
@@ -3,6 +3,7 @@ import React, { MutableRefObject, useCallback, useEffect, useMemo, useRef, useSt
3
3
  import {
4
4
  CMSAnalyticsEvent,
5
5
  Entity,
6
+ EntityAction,
6
7
  EntityCollection,
7
8
  EntityStatus,
8
9
  EntityValues,
@@ -15,13 +16,26 @@ import { Form, Formik, FormikHelpers, FormikProps } from "formik";
15
16
  import { PropertyFieldBinding } from "./PropertyFieldBinding";
16
17
  import { CustomFieldValidator, getYupEntitySchema } from "./validation";
17
18
  import equal from "react-fast-compare"
18
- import { ErrorBoundary, getDefaultValuesFor, isHidden, isReadOnly, resolveCollection } from "../core";
19
- import { useDataSource, useFireCMSContext } from "../hooks";
19
+ import {
20
+ canCreateEntity,
21
+ canDeleteEntity,
22
+ ErrorBoundary,
23
+ fullPathToCollectionSegments,
24
+ getDefaultValuesFor,
25
+ isHidden,
26
+ isReadOnly,
27
+ resolveCollection
28
+ } from "../core";
29
+ import { useAuthController, useDataSource, useFireCMSContext, useSideEntityController } from "../hooks";
20
30
  import { ErrorFocus } from "./components/ErrorFocus";
21
31
  import { CustomIdField } from "./components/CustomIdField";
22
- import { DialogActions, Typography } from "../components";
32
+ import { DialogActions, IconButton, Typography } from "../components";
23
33
  import { Button } from "../components/Button";
24
34
  import { cn } from "../components/util/cn";
35
+ import {
36
+ copyEntityAction,
37
+ deleteEntityAction
38
+ } from "../core/components/EntityCollectionTable/internal/default_entity_actions";
25
39
 
26
40
  /**
27
41
  * @category Components
@@ -326,6 +340,21 @@ function EntityFormInternal<M extends Record<string, any>>({
326
340
  : undefined,
327
341
  [entityId, collection.properties, uniqueFieldValidator]);
328
342
 
343
+ const authController = useAuthController();
344
+
345
+ const getActionsForEntity = useCallback(({ entity, customEntityActions }: { entity?: Entity<M>, customEntityActions?: EntityAction[] }): EntityAction[] => {
346
+ const createEnabled = canCreateEntity(collection, authController, fullPathToCollectionSegments(path), null);
347
+ const deleteEnabled = entity ? canDeleteEntity(collection, authController, fullPathToCollectionSegments(path), entity) : true;
348
+ const actions: EntityAction[] = [];
349
+ if (createEnabled)
350
+ actions.push(copyEntityAction);
351
+ if (deleteEnabled)
352
+ actions.push(deleteEntityAction);
353
+ if (customEntityActions)
354
+ actions.push(...customEntityActions);
355
+ return actions;
356
+ }, [authController, collection, path]);
357
+
329
358
  return (
330
359
  <Formik
331
360
  initialValues={baseDataSourceValues as M}
@@ -417,7 +446,8 @@ function EntityFormInternal<M extends Record<string, any>>({
417
446
  status={status}
418
447
  savingError={savingError}
419
448
  closeAfterSaveRef={closeAfterSaveRef}
420
- autoSave={autoSave}/>}
449
+ autoSave={autoSave}
450
+ entityActions={getActionsForEntity({ entity, customEntityActions: collection.entityActions })}/>}
421
451
 
422
452
  </div>
423
453
  </div>
@@ -436,7 +466,8 @@ function InnerForm<M extends Record<string, any>>(props: FormikProps<M> & {
436
466
  status: "new" | "existing" | "copy",
437
467
  savingError?: Error,
438
468
  closeAfterSaveRef: MutableRefObject<boolean>,
439
- autoSave?: boolean
469
+ autoSave?: boolean,
470
+ entityActions: EntityAction[]
440
471
  }) {
441
472
 
442
473
  const {
@@ -455,9 +486,14 @@ function InnerForm<M extends Record<string, any>>(props: FormikProps<M> & {
455
486
  savingError,
456
487
  dirty,
457
488
  closeAfterSaveRef,
458
- autoSave
489
+ autoSave,
490
+ entityActions
459
491
  } = props;
460
492
 
493
+ const context = useFireCMSContext();
494
+ const formActions = entityActions.filter(a => a.includeInForm === undefined || a.includeInForm);
495
+ const sideEntityController = useSideEntityController();
496
+
461
497
  const modified = dirty;
462
498
  useEffect(() => {
463
499
  if (onModified)
@@ -553,6 +589,27 @@ function InnerForm<M extends Record<string, any>>(props: FormikProps<M> & {
553
589
  </Typography>
554
590
  </div>}
555
591
 
592
+ {entity && formActions.length > 0 && <div className="flex-grow flex overflow-auto no-scrollbar">
593
+ {formActions.map(action => (
594
+ <IconButton
595
+ key={action.name}
596
+ color="primary"
597
+ onClick={(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
598
+ event.stopPropagation();
599
+ if (entity)
600
+ action.onClick({
601
+ entity,
602
+ fullPath: resolvedCollection.path,
603
+ collection: resolvedCollection,
604
+ context,
605
+ sideEntityController
606
+ });
607
+ }}>
608
+ {action.icon}
609
+ </IconButton>
610
+ ))}
611
+ </div>}
612
+
556
613
  <Button
557
614
  variant="text"
558
615
  disabled={disabled}
@@ -0,0 +1,14 @@
1
+ import { useContext } from "react";
2
+ import { DialogsController } from "../types/dialogs_controller";
3
+ import { DialogsControllerContext } from "../core/contexts/DialogsProvider";
4
+
5
+ /**
6
+ * Use this hook to open a dialog imperatively.
7
+ * Alternatively, you can use dialogs declaratively using the `Dialog` component.
8
+ *
9
+ * Consider that in order to use this hook you need to have a parent
10
+ * `FireCMS`
11
+ *
12
+ * @category Hooks and utilities
13
+ */
14
+ export const useDialogsController = (): DialogsController => useContext(DialogsControllerContext);
@@ -8,17 +8,9 @@ import { useDataSource } from "./data/useDataSource";
8
8
  import { useStorageSource } from "./useStorageSource";
9
9
  import { useSnackbarController } from "./useSnackbarController";
10
10
  import { useUserConfigurationPersistence } from "./useUserConfigurationPersistence";
11
+ import { useDialogsController } from "./useDialogsController";
11
12
 
12
- export const FireCMSContextInstance = createContext<Partial<FireCMSContext>>({
13
- sideDialogsController: {} as any,
14
- sideEntityController: {} as any,
15
- navigation: {} as any,
16
- dataSource: {} as any,
17
- storageSource: {} as any,
18
- authController: {} as any,
19
- snackbarController: {} as any,
20
- fields: {}
21
- });
13
+ export const FireCMSContextInstance = createContext<Partial<FireCMSContext>>({});
22
14
 
23
15
  /**
24
16
  * Hook to retrieve the {@link FireCMSContext}.
@@ -40,6 +32,7 @@ export const useFireCMSContext = <UserType extends User = User, AuthControllerTy
40
32
  const storageSource = useStorageSource();
41
33
  const snackbarController = useSnackbarController();
42
34
  const userConfigPersistence = useUserConfigurationPersistence();
35
+ const dialogsController = useDialogsController();
43
36
 
44
37
  return {
45
38
  ...partialContext,
@@ -50,7 +43,8 @@ export const useFireCMSContext = <UserType extends User = User, AuthControllerTy
50
43
  dataSource,
51
44
  storageSource,
52
45
  snackbarController,
53
- userConfigPersistence
46
+ userConfigPersistence,
47
+ dialogsController
54
48
  }
55
49
 
56
50
  };
package/src/styles.ts CHANGED
@@ -1,4 +1,4 @@
1
- export const focusedMixin = "focus:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-transparent";
1
+ export const focusedMixin = "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-transparent";
2
2
  export const focusedInvisibleMixin = "focus:bg-opacity-70 focus:bg-gray-100 focus:dark:bg-gray-800 focus:dark:bg-opacity-60";
3
3
  export const focusedClasses = "z-30 outline-none ring-2 ring-primary ring-opacity-75 ring-offset-2 ring-offset-transparent ";
4
4
  export const fieldBackgroundMixin = "bg-opacity-70 bg-gray-100 dark:bg-gray-800 dark:bg-opacity-60 transition duration-150 ease-in-out";
@@ -6,6 +6,7 @@ import { EntityCallbacks } from "./entity_callbacks";
6
6
  import { Permissions, PermissionsBuilder } from "./permissions";
7
7
  import { EnumValues, PropertiesOrBuilders } from "./properties";
8
8
  import { FormContext } from "./fields";
9
+ import { EntityAction } from "./entity_actions";
9
10
 
10
11
  /**
11
12
  * This interface represents a view that includes a collection of entities.
@@ -14,9 +15,7 @@ import { FormContext } from "./fields";
14
15
  *
15
16
  * @category Models
16
17
  */
17
- export interface EntityCollection<M extends Record<string, any> = any,
18
- AdditionalKey extends string = string,
19
- UserType extends User = User> {
18
+ export interface EntityCollection<M extends Record<string, any> = any, UserType extends User = User> {
20
19
 
21
20
  /**
22
21
  * Name of the collection, typically plural.
@@ -58,9 +57,9 @@ export interface EntityCollection<M extends Record<string, any> = any,
58
57
 
59
58
  /**
60
59
  * Icon key to use in this collection.
61
- * You can use any of the icons in the MUI specs:
62
- * https://mui.com/material-ui/material-icons/
63
- * e.g. 'AccountTree' or 'Person'
60
+ * You can use any of the icons in the Material specs:
61
+ * https://fonts.google.com/icons
62
+ * e.g. 'account_tree' or 'person'
64
63
  */
65
64
  icon?: string;
66
65
 
@@ -93,7 +92,7 @@ export interface EntityCollection<M extends Record<string, any> = any,
93
92
  * - If you are using a collection group, you will also have an
94
93
  * additional `collectionGroupParent` column.
95
94
  */
96
- propertiesOrder?: Extract<keyof M | AdditionalKey, string>[];
95
+ propertiesOrder?: Extract<keyof M, string>[];
97
96
 
98
97
  /**
99
98
  * If enabled, content is loaded in batches. If `false` all entities in the
@@ -113,7 +112,7 @@ export interface EntityCollection<M extends Record<string, any> = any,
113
112
  * Permissions the logged-in user can perform on this collection.
114
113
  * If not specified everything defaults to `true`.
115
114
  */
116
- permissions?: Permissions | PermissionsBuilder<EntityCollection<M>, UserType, M>;
115
+ permissions?: Permissions | PermissionsBuilder<any, UserType, M>;
117
116
 
118
117
  /**
119
118
  * Are the entities in this collection selectable. Defaults to `true`
@@ -140,6 +139,31 @@ export interface EntityCollection<M extends Record<string, any> = any,
140
139
  */
141
140
  Actions?: React.ComponentType<CollectionActionsProps> | React.ComponentType<CollectionActionsProps>[];
142
141
 
142
+ /**
143
+ * You can define additional actions that can be performed on the entities
144
+ * in this collection. These actions can be displayed in the collection
145
+ * view or in the entity view.
146
+ *
147
+ * You can use the `onClick` method to implement your own logic.
148
+ * In the `context` prop you can access all the controllers of FireCMS.
149
+ *
150
+ * ```
151
+ * const archiveEntityAction: EntityAction = {
152
+ * icon: <ArchiveIcon/>,
153
+ * name: "Archive",
154
+ * onClick({
155
+ * entity,
156
+ * collection,
157
+ * context,
158
+ * }): Promise<void> {
159
+ * // Add your code here
160
+ * return Promise.resolve(undefined);
161
+ * }
162
+ * }
163
+ * ```
164
+ */
165
+ entityActions?: EntityAction<M, UserType>[];
166
+
143
167
  /**
144
168
  * Pass your own selection controller if you want to control selected
145
169
  * entities externally.
@@ -190,8 +214,7 @@ export interface EntityCollection<M extends Record<string, any> = any,
190
214
  * You can add additional fields to the collection view by implementing
191
215
  * an additional field delegate.
192
216
  */
193
- additionalFields?: AdditionalFieldDelegate<M, AdditionalKey, UserType>[];
194
-
217
+ additionalFields?: AdditionalFieldDelegate<M, UserType>[];
195
218
 
196
219
  /**
197
220
  * Default size of the rendered collection
@@ -245,10 +268,8 @@ export interface EntityCollection<M extends Record<string, any> = any,
245
268
 
246
269
  /**
247
270
  * Parameter passed to the `Actions` prop in the collection configuration.
248
- * Note that actions are rendered in the collection toolbar, as well
249
- * as in the home page card.
250
- * If you don't want to render the actions in the home page card, you can
251
- * return `null` if mode is `home`.
271
+ * The component will receive this prop when it is rendered in the collection
272
+ * toolbar.
252
273
  *
253
274
  * @category Models
254
275
  */
@@ -349,7 +370,6 @@ export type FilterCombination<Key extends string> = Partial<Record<Key, "asc" |
349
370
  */
350
371
  export type CollectionSize = "xs" | "s" | "m" | "l" | "xl";
351
372
 
352
-
353
373
  export type AdditionalFieldDelegateProps<M extends Record<string, any> = any, UserType extends User = User> = {
354
374
  entity: Entity<M>,
355
375
  context: FireCMSContext<UserType>
@@ -361,14 +381,13 @@ export type AdditionalFieldDelegateProps<M extends Record<string, any> = any, Us
361
381
  * @category Models
362
382
  */
363
383
  export interface AdditionalFieldDelegate<M extends Record<string, any> = any,
364
- AdditionalKey extends string = string,
365
384
  UserType extends User = User> {
366
385
 
367
386
  /**
368
387
  * ID of this column. You can use this id in the `properties` field of the
369
388
  * collection in any order you want
370
389
  */
371
- id: AdditionalKey;
390
+ id: string;
372
391
 
373
392
  /**
374
393
  * Header of this column
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Controller to open the side dialog
3
+ * @category Hooks and utilities
4
+ */
5
+ export interface DialogsController {
6
+
7
+ /**
8
+ * Close the last dialog
9
+ */
10
+ close: () => void;
11
+
12
+ /**
13
+ * Open a dialog
14
+ * @param props
15
+ */
16
+ open: (props: DialogControllerEntryProps) => { closeDialog: () => void };
17
+ }
18
+
19
+ /**
20
+ * Props used to open a side dialog
21
+ * @category Hooks and utilities
22
+ */
23
+ export interface DialogControllerEntryProps {
24
+
25
+ key: string;
26
+ /**
27
+ * The component type that will be rendered
28
+ */
29
+ Component: React.ComponentType<{ open: boolean }>;
30
+
31
+ }
@@ -0,0 +1,36 @@
1
+ import React from "react";
2
+ import { FireCMSContext } from "./firecms_context";
3
+ import { Entity } from "./entities";
4
+ import { EntityCollection, SelectionController } from "./collections";
5
+ import { User } from "./user";
6
+ import { SideEntityController } from "./side_entity_controller";
7
+
8
+ export type EntityAction<M extends object = any, UserType extends User = User> = {
9
+ name: string;
10
+ icon?: React.ReactElement;
11
+ onClick: (props: EntityActionClickProps<M, UserType>) => Promise<void>;
12
+ /**
13
+ * Show this action in the menu, defaults to true
14
+ */
15
+ collapsed?: boolean;
16
+
17
+ /**
18
+ * Show this action in the form, defaults to true
19
+ */
20
+ includeInForm?: boolean;
21
+ }
22
+
23
+ export type EntityActionClickProps<M extends object, UserType extends User = User> = {
24
+ entity: Entity<M>;
25
+ context: FireCMSContext<UserType>;
26
+ fullPath?: string;
27
+ collection?: EntityCollection<M>;
28
+ selectionController?: SelectionController;
29
+ highlightEntity?: (entity: Entity<any>) => void;
30
+ unhighlightEntity?: (entity: Entity<any>) => void;
31
+ onCollectionChange?: () => void;
32
+ /**
33
+ * If this actions is being called from a side dialog
34
+ */
35
+ sideEntityController?: SideEntityController;
36
+ };
@@ -23,11 +23,11 @@ import { CMSAnalyticsEvent } from "./analytics";
23
23
  * APIs directly, or a REST API.
24
24
  * @category Models
25
25
  */
26
- export type EntityCollectionsBuilder = (params: {
26
+ export type EntityCollectionsBuilder<EC extends EntityCollection> = (params: {
27
27
  user: User | null,
28
28
  authController: AuthController,
29
29
  dataSource: DataSource
30
- }) => EntityCollection[] | Promise<EntityCollection[]>;
30
+ }) => EC[] | Promise<EC[]>;
31
31
 
32
32
  /**
33
33
  * Use this callback to build custom views dynamically.
@@ -47,7 +47,7 @@ export type CMSViewsBuilder = (params: {
47
47
  /**
48
48
  * @category Models
49
49
  */
50
- export type FireCMSProps<UserType extends User> = {
50
+ export type FireCMSProps<UserType extends User, EC extends EntityCollection> = {
51
51
 
52
52
  /**
53
53
  * Use this function to return the components you want to render under
@@ -73,7 +73,7 @@ export type FireCMSProps<UserType extends User> = {
73
73
  * Each of the navigation entries in this field
74
74
  * generates an entry in the main menu.
75
75
  */
76
- collections?: EntityCollection[] | EntityCollectionsBuilder;
76
+ collections?: EC[] | EntityCollectionsBuilder<EC>;
77
77
 
78
78
  /**
79
79
  * Custom additional views created by the developer, added to the main
@@ -148,7 +148,7 @@ export type FireCMSProps<UserType extends User> = {
148
148
  * Use plugins to modify the behaviour of the CMS.
149
149
  * Currently, in ALPHA, and likely subject to change.
150
150
  */
151
- plugins?: FireCMSPlugin[];
151
+ plugins?: FireCMSPlugin<any, any, any>[];
152
152
 
153
153
  /**
154
154
  * Callback used to get analytics events from the CMS
@@ -13,6 +13,7 @@ import { FireCMSPlugin } from "./plugins";
13
13
  import { CMSAnalyticsEvent } from "./analytics";
14
14
  import { PropertyConfig } from "./property_config";
15
15
  import { EntityCustomView } from "./collections";
16
+ import { DialogsController } from "./dialogs_controller";
16
17
 
17
18
  /**
18
19
  * Context that includes the internal controllers and contexts used by the app.
@@ -59,9 +60,16 @@ export type FireCMSContext<UserType extends User = User, AuthControllerType exte
59
60
 
60
61
  /**
61
62
  * Controller used to open side dialogs
63
+ * This is the controller used internally by side entity dialogs
64
+ * or reference dialogs.
62
65
  */
63
66
  sideDialogsController: SideDialogsController;
64
67
 
68
+ /**
69
+ * Controller used to open regular dialogs
70
+ */
71
+ dialogsController: DialogsController;
72
+
65
73
  /**
66
74
  * Used auth controller
67
75
  */
@@ -1,5 +1,6 @@
1
1
  export * from "./auth";
2
2
  export * from "./entities";
3
+ export * from "./entity_actions";
3
4
  export * from "./resolved_entities";
4
5
  export * from "./properties";
5
6
  export * from "./collections";
@@ -154,9 +154,9 @@ export interface CMSView {
154
154
 
155
155
  /**
156
156
  * Icon key to use in this view.
157
- * You can use any of the icons in the MUI specs:
158
- * https://mui.com/material-ui/material-icons/
159
- * e.g. 'AccountTree' or 'Person'
157
+ * You can use any of the icons in the Material specs:
158
+ * https://fonts.google.com/icons
159
+ * e.g. 'account_tree' or 'person'
160
160
  */
161
161
  icon?: string;
162
162