@firecms/core 3.0.0-beta.13 → 3.0.0-beta.15
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.
- package/dist/components/ArrayContainer.d.ts +7 -12
- package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +2 -1
- package/dist/components/EntityPreview.d.ts +4 -2
- package/dist/components/HomePage/DefaultHomePage.d.ts +2 -15
- package/dist/components/HomePage/HomePageDnD.d.ts +76 -0
- package/dist/components/HomePage/NavigationCard.d.ts +3 -1
- package/dist/components/HomePage/NavigationCardBinding.d.ts +3 -2
- package/dist/components/HomePage/NavigationGroup.d.ts +7 -1
- package/dist/components/HomePage/RenameGroupDialog.d.ts +9 -0
- package/dist/components/SelectableTable/SelectableTable.d.ts +1 -1
- package/dist/components/VirtualTable/VirtualTableProps.d.ts +0 -4
- package/dist/components/index.d.ts +1 -0
- package/dist/core/EntityEditView.d.ts +3 -0
- package/dist/core/EntityEditViewFormActions.d.ts +1 -1
- package/dist/core/field_configs.d.ts +1 -1
- package/dist/form/EntityForm.d.ts +2 -1
- package/dist/form/EntityFormActions.d.ts +6 -2
- package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/ReferenceAsStringFieldBinding.d.ts +9 -0
- package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +3 -9
- package/dist/form/index.d.ts +1 -0
- package/dist/hooks/useBuildNavigationController.d.ts +50 -8
- package/dist/index.es.js +3259 -1649
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +3265 -1658
- package/dist/index.umd.js.map +1 -1
- package/dist/types/analytics.d.ts +1 -1
- package/dist/types/collections.d.ts +28 -4
- package/dist/types/customization_controller.d.ts +8 -0
- package/dist/types/entity_actions.d.ts +46 -6
- package/dist/types/firecms.d.ts +10 -1
- package/dist/types/navigation.d.ts +26 -5
- package/dist/types/plugins.d.ts +32 -1
- package/dist/types/properties.d.ts +7 -0
- package/dist/types/property_config.d.ts +1 -1
- package/dist/types/side_entity_controller.d.ts +8 -0
- package/dist/util/callbacks.d.ts +2 -0
- package/dist/util/icons.d.ts +2 -2
- package/dist/util/index.d.ts +1 -0
- package/dist/util/navigation_from_path.d.ts +4 -0
- package/dist/util/resolutions.d.ts +2 -1
- package/package.json +8 -6
- package/src/components/ArrayContainer.tsx +409 -294
- package/src/components/ClearFilterSortButton.tsx +1 -1
- package/src/components/ConfirmationDialog.tsx +10 -9
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +6 -0
- package/src/components/EntityCollectionTable/PropertyTableCell.tsx +26 -4
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +3 -3
- package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +13 -2
- package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +53 -27
- package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +9 -9
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +11 -4
- package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +3 -2
- package/src/components/EntityPreview.tsx +18 -14
- package/src/components/ErrorView.tsx +1 -1
- package/src/components/FireCMSLogo.tsx +7 -51
- package/src/components/HomePage/DefaultHomePage.tsx +491 -156
- package/src/components/HomePage/FavouritesView.tsx +3 -3
- package/src/components/HomePage/HomePageDnD.tsx +599 -0
- package/src/components/HomePage/NavigationCard.tsx +47 -38
- package/src/components/HomePage/NavigationCardBinding.tsx +13 -7
- package/src/components/HomePage/NavigationGroup.tsx +63 -29
- package/src/components/HomePage/RenameGroupDialog.tsx +117 -0
- package/src/components/SelectableTable/SelectableTable.tsx +140 -143
- package/src/components/UnsavedChangesDialog.tsx +6 -2
- package/src/components/VirtualTable/VirtualTable.tsx +8 -30
- package/src/components/VirtualTable/VirtualTableProps.tsx +0 -5
- package/src/components/VirtualTable/fields/VirtualTableInput.tsx +0 -1
- package/src/components/common/default_entity_actions.tsx +25 -9
- package/src/components/common/useDataSourceTableController.tsx +2 -2
- package/src/components/index.tsx +2 -0
- package/src/core/DefaultDrawer.tsx +8 -8
- package/src/core/DrawerNavigationItem.tsx +1 -1
- package/src/core/EntityEditView.tsx +65 -18
- package/src/core/EntityEditViewFormActions.tsx +154 -29
- package/src/core/EntitySidePanel.tsx +19 -21
- package/src/core/FireCMS.tsx +9 -1
- package/src/core/field_configs.tsx +15 -1
- package/src/form/EntityForm.tsx +37 -5
- package/src/form/EntityFormActions.tsx +51 -9
- package/src/form/PropertyFieldBinding.tsx +0 -1
- package/src/form/components/CustomIdField.tsx +3 -1
- package/src/form/components/LabelWithIcon.tsx +1 -1
- package/src/form/components/StorageItemPreview.tsx +1 -1
- package/src/form/components/StorageUploadProgress.tsx +3 -3
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +3 -2
- package/src/form/field_bindings/MapFieldBinding.tsx +5 -4
- package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +4 -2
- package/src/form/field_bindings/MultiSelectFieldBinding.tsx +1 -1
- package/src/form/field_bindings/ReferenceAsStringFieldBinding.tsx +135 -0
- package/src/form/field_bindings/SelectFieldBinding.tsx +2 -1
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +216 -153
- package/src/form/index.tsx +1 -0
- package/src/hooks/data/save.ts +0 -6
- package/src/hooks/useBuildNavigationController.tsx +299 -96
- package/src/internal/useBuildSideEntityController.tsx +8 -5
- package/src/preview/PropertyPreview.tsx +14 -0
- package/src/preview/components/ImagePreview.tsx +2 -2
- package/src/preview/components/ReferencePreview.tsx +1 -1
- package/src/preview/property_previews/ArrayOfMapsPreview.tsx +1 -1
- package/src/preview/property_previews/MapPropertyPreview.tsx +1 -1
- package/src/preview/property_previews/SkeletonPropertyComponent.tsx +1 -1
- package/src/preview/property_previews/StringPropertyPreview.tsx +1 -1
- package/src/routes/FireCMSRoute.tsx +3 -3
- package/src/types/analytics.ts +3 -0
- package/src/types/collections.ts +32 -4
- package/src/types/customization_controller.tsx +9 -0
- package/src/types/entity_actions.tsx +57 -6
- package/src/types/firecms.tsx +11 -2
- package/src/types/navigation.ts +34 -6
- package/src/types/plugins.tsx +40 -1
- package/src/types/properties.ts +8 -0
- package/src/types/property_config.tsx +1 -0
- package/src/types/side_entity_controller.tsx +10 -5
- package/src/util/callbacks.ts +119 -0
- package/src/util/icons.tsx +22 -7
- package/src/util/index.ts +1 -0
- package/src/util/join_collections.ts +3 -1
- package/src/util/navigation_from_path.ts +15 -5
- package/src/util/navigation_utils.ts +72 -57
- package/src/util/objects.ts +53 -20
- package/src/util/resolutions.ts +13 -1
- package/dist/components/EntityCollectionTable/internal/popup_field/ElementResizeListener.d.ts +0 -5
- package/src/components/EntityCollectionTable/internal/popup_field/ElementResizeListener.tsx +0 -59
|
@@ -128,7 +128,7 @@ export function KeyValuePreview({ value }: { value: any }) {
|
|
|
128
128
|
</div>
|
|
129
129
|
<div
|
|
130
130
|
className="flex-grow max-w-[75%]">
|
|
131
|
-
{childValue && <Typography>
|
|
131
|
+
{childValue && typeof childValue !== "object" && <Typography>
|
|
132
132
|
<ErrorBoundary>
|
|
133
133
|
{childValue.toString()}
|
|
134
134
|
</ErrorBoundary>
|
|
@@ -46,7 +46,7 @@ export function SkeletonPropertyComponent({
|
|
|
46
46
|
content = <>{arrayProperty.of.map((p, i) => renderGenericArrayCell(p, i))} </>;
|
|
47
47
|
} else {
|
|
48
48
|
if (arrayProperty.of.dataType === "map" && arrayProperty.of.properties) {
|
|
49
|
-
content = renderArrayOfMaps(arrayProperty.of.properties, size, arrayProperty.of.
|
|
49
|
+
content = renderArrayOfMaps(arrayProperty.of.properties, size, arrayProperty.of.previewKeys);
|
|
50
50
|
} else if (arrayProperty.of.dataType === "string") {
|
|
51
51
|
if (arrayProperty.of.enumValues) {
|
|
52
52
|
content = renderArrayEnumTableCell();
|
|
@@ -45,7 +45,7 @@ export function StringPropertyPreview({
|
|
|
45
45
|
if (!value) return <></>;
|
|
46
46
|
const lines = value.split("\n");
|
|
47
47
|
return value && value.includes("\n")
|
|
48
|
-
? <div className={cls("overflow-x-scroll", size === "small" ? "text-sm" : "")}>
|
|
48
|
+
? <div className={cls("overflow-x-scroll overflow-hidden", size === "small" ? "text-sm" : "")}>
|
|
49
49
|
{lines.map((str, index) =>
|
|
50
50
|
<React.Fragment key={`string_preview_${index}`}>
|
|
51
51
|
<span>{str}</span>
|
|
@@ -79,7 +79,8 @@ export function FireCMSRoute() {
|
|
|
79
79
|
key={`collection_view_${collection.id ?? collection.path}`}
|
|
80
80
|
isSubCollection={false}
|
|
81
81
|
parentCollectionIds={[]}
|
|
82
|
-
fullPath={collection.
|
|
82
|
+
fullPath={collection.path}
|
|
83
|
+
fullIdPath={collection.id}
|
|
83
84
|
updateUrl={true}
|
|
84
85
|
{...collection}
|
|
85
86
|
Actions={toArray(collection.Actions)}/>
|
|
@@ -100,7 +101,7 @@ export function FireCMSRoute() {
|
|
|
100
101
|
fullIdPath={collection.id}
|
|
101
102
|
isSubCollection={false}
|
|
102
103
|
parentCollectionIds={[]}
|
|
103
|
-
fullPath={collection.
|
|
104
|
+
fullPath={collection.path}
|
|
104
105
|
updateUrl={true}
|
|
105
106
|
{...collection}
|
|
106
107
|
Actions={toArray(collection.Actions)}/>;
|
|
@@ -200,7 +201,6 @@ function EntityFullScreenRoute({
|
|
|
200
201
|
const collection = isNew ? lastCollectionEntry!.collection : lastEntityEntry!.parentCollection;
|
|
201
202
|
const fullIdPath = isNew ? lastCollectionEntry!.path : lastEntityEntry!.path;
|
|
202
203
|
const collectionPath = navigation.resolveIdsFrom(fullIdPath);
|
|
203
|
-
|
|
204
204
|
return <>
|
|
205
205
|
<EntityEditView
|
|
206
206
|
key={collection.id + "_" + (isNew ? "new" : (isCopy ? entityId + "_copy" : entityId))}
|
package/src/types/analytics.ts
CHANGED
package/src/types/collections.ts
CHANGED
|
@@ -70,12 +70,15 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
|
|
|
70
70
|
* e.g. 'account_tree' or 'person'.
|
|
71
71
|
* Find all the icons in https://firecms.co/docs/icons
|
|
72
72
|
*/
|
|
73
|
-
icon?: string;
|
|
73
|
+
icon?: string | React.ReactNode;
|
|
74
74
|
|
|
75
75
|
/**
|
|
76
76
|
* Optional field used to group top level navigation entries under a~
|
|
77
77
|
* navigation view. If you set this value in a subcollection it has no
|
|
78
78
|
* effect.
|
|
79
|
+
* @deprecated This prop is deprecated and will be removed in the future.
|
|
80
|
+
* You can apply grouping by using the `navigationGroupMappings` prop in the
|
|
81
|
+
* {@link useBuildNavigationController} hook instead.
|
|
79
82
|
*/
|
|
80
83
|
group?: string;
|
|
81
84
|
|
|
@@ -112,7 +115,7 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
|
|
|
112
115
|
* `hidden` in the property definition, will be ignored.
|
|
113
116
|
* `propertiesOrder` has precedence over `hidden`.
|
|
114
117
|
* - For properties use the property key.
|
|
115
|
-
* - For additional
|
|
118
|
+
* - For additional fields use the field key.
|
|
116
119
|
* - If you have subcollections, you get a column for each subcollection,
|
|
117
120
|
* with the path (or alias) as the subcollection, prefixed with
|
|
118
121
|
* `subcollection:`. e.g. `subcollection:orders`.
|
|
@@ -127,7 +130,8 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
|
|
|
127
130
|
|
|
128
131
|
/**
|
|
129
132
|
* If enabled, content is loaded in batches. If `false` all entities in the
|
|
130
|
-
* collection are loaded.
|
|
133
|
+
* collection are loaded. This means that when reaching the end of the
|
|
134
|
+
* collection, the CMS will load more entities.
|
|
131
135
|
* You can specify a number to specify the pagination size (50 by default)
|
|
132
136
|
* Defaults to `true`
|
|
133
137
|
*/
|
|
@@ -192,8 +196,11 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
|
|
|
192
196
|
* }
|
|
193
197
|
* }
|
|
194
198
|
* ```
|
|
199
|
+
*
|
|
200
|
+
* You can also pass the action as a string that represents the `key`, in which case it will
|
|
201
|
+
* use the action defined in the main configuration under `entityActions`.
|
|
195
202
|
*/
|
|
196
|
-
entityActions?: EntityAction<M, USER>[];
|
|
203
|
+
entityActions?: (EntityAction<M, USER> | string)[];
|
|
197
204
|
|
|
198
205
|
/**
|
|
199
206
|
* Pass your own selection controller if you want to control selected
|
|
@@ -337,6 +344,12 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
|
|
|
337
344
|
* If set to true, a tab including the JSON representation of the entity will be included.
|
|
338
345
|
*/
|
|
339
346
|
includeJsonView?: boolean;
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* If set to true, changes to the entity will be saved in a subcollection.
|
|
350
|
+
* This prop has no effect if the history plugin is not enabled
|
|
351
|
+
*/
|
|
352
|
+
history?: boolean;
|
|
340
353
|
}
|
|
341
354
|
|
|
342
355
|
/**
|
|
@@ -519,6 +532,11 @@ export type EntityCustomView<M extends Record<string, any> = any> =
|
|
|
519
532
|
*/
|
|
520
533
|
name: string;
|
|
521
534
|
|
|
535
|
+
/**
|
|
536
|
+
* Render this custom view in the tab of the entity view, instead of the name
|
|
537
|
+
*/
|
|
538
|
+
tabComponent?: React.ReactNode;
|
|
539
|
+
|
|
522
540
|
/**
|
|
523
541
|
* If set to true, the actions of the entity (save, discard,delete) will be
|
|
524
542
|
* included in the view. By default the actions are located in the right or bottom,
|
|
@@ -531,6 +549,11 @@ export type EntityCustomView<M extends Record<string, any> = any> =
|
|
|
531
549
|
* Builder for rendering the custom view
|
|
532
550
|
*/
|
|
533
551
|
Builder?: React.ComponentType<EntityCustomViewParams<M>>;
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* Position of this tab in the entity view. Defaults to `end`.
|
|
555
|
+
*/
|
|
556
|
+
position?: "start" | "end";
|
|
534
557
|
};
|
|
535
558
|
|
|
536
559
|
/**
|
|
@@ -561,6 +584,11 @@ export interface EntityCustomViewParams<M extends Record<string, any> = any> {
|
|
|
561
584
|
* Use the form context to access the form state and methods
|
|
562
585
|
*/
|
|
563
586
|
formContext: FormContext;
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* If this is a subcollection, this is the path of the parent collections
|
|
590
|
+
*/
|
|
591
|
+
parentCollectionIds?: string[];
|
|
564
592
|
}
|
|
565
593
|
|
|
566
594
|
export type InferCollectionType<S extends EntityCollection> = S extends EntityCollection<infer M> ? M : never;
|
|
@@ -4,6 +4,7 @@ import { FireCMSPlugin } from "./plugins";
|
|
|
4
4
|
import { EntityCustomView } from "./collections";
|
|
5
5
|
import { Locale } from "./locales";
|
|
6
6
|
import { PropertyConfig } from "./property_config";
|
|
7
|
+
import { EntityAction } from "./entity_actions";
|
|
7
8
|
|
|
8
9
|
export type CustomizationController = {
|
|
9
10
|
|
|
@@ -26,6 +27,14 @@ export type CustomizationController = {
|
|
|
26
27
|
*/
|
|
27
28
|
entityViews?: EntityCustomView[];
|
|
28
29
|
|
|
30
|
+
/**
|
|
31
|
+
* List of actions that can be performed on entities.
|
|
32
|
+
* These actions are displayed in the entity view and in the collection view.
|
|
33
|
+
* You can later reuse these actions in the `entityActions` prop of a collection,
|
|
34
|
+
* by specifying the `key` of the action.
|
|
35
|
+
*/
|
|
36
|
+
entityActions?: EntityAction<any, any>[];
|
|
37
|
+
|
|
29
38
|
/**
|
|
30
39
|
* Format of the dates in the CMS.
|
|
31
40
|
* Defaults to 'MMMM dd, yyyy, HH:mm:ss'
|
|
@@ -4,6 +4,7 @@ import { Entity } from "./entities";
|
|
|
4
4
|
import { EntityCollection, SelectionController } from "./collections";
|
|
5
5
|
import { User } from "./user";
|
|
6
6
|
import { SideEntityController } from "./side_entity_controller";
|
|
7
|
+
import { FormContext } from "./fields";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* An entity action is a custom action that can be performed on an entity.
|
|
@@ -17,7 +18,10 @@ export type EntityAction<M extends object = any, USER extends User = User> = {
|
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Key of the action. You only need to provide this if you want to
|
|
20
|
-
* override the default actions
|
|
21
|
+
* override the default actions, or if you are not passing the action
|
|
22
|
+
* directly to the `entityActions` prop of a collection.
|
|
23
|
+
* You can define your actions at the app level, in which case you
|
|
24
|
+
* must provide a key.
|
|
21
25
|
* The default actions are:
|
|
22
26
|
* - edit
|
|
23
27
|
* - delete
|
|
@@ -36,6 +40,12 @@ export type EntityAction<M extends object = any, USER extends User = User> = {
|
|
|
36
40
|
*/
|
|
37
41
|
onClick: (props: EntityActionClickProps<M, USER>) => Promise<void> | void;
|
|
38
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Optional callback in case you want to disable the action
|
|
45
|
+
* @param props
|
|
46
|
+
*/
|
|
47
|
+
isEnabled?: (props: EntityActionClickProps<M, USER>) => boolean;
|
|
48
|
+
|
|
39
49
|
/**
|
|
40
50
|
* Show this action collapsed in the menu of the collection view.
|
|
41
51
|
* Defaults to true
|
|
@@ -51,18 +61,59 @@ export type EntityAction<M extends object = any, USER extends User = User> = {
|
|
|
51
61
|
}
|
|
52
62
|
|
|
53
63
|
export type EntityActionClickProps<M extends object, USER extends User = User> = {
|
|
54
|
-
entity
|
|
64
|
+
entity?: Entity<M>;
|
|
55
65
|
context: FireCMSContext<USER>;
|
|
66
|
+
|
|
56
67
|
fullPath?: string;
|
|
68
|
+
fullIdPath?: string;
|
|
57
69
|
collection?: EntityCollection<M>;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Optional form context, present if the action is being called from a form.
|
|
73
|
+
* This allows you to access the form state and methods, including modifying the form values.
|
|
74
|
+
*/
|
|
75
|
+
formContext?: FormContext;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Present if this actions is being called from a side dialog only
|
|
79
|
+
*/
|
|
80
|
+
sideEntityController?: SideEntityController;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Is the action being called from the collection view or from the entity form view?
|
|
84
|
+
*/
|
|
85
|
+
view: "collection" | "form";
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* If the action is rendered in the form, is it open in a side panel or full screen?
|
|
89
|
+
*/
|
|
90
|
+
openEntityMode: "side_panel" | "full_screen";
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Optional selection controller, present if the action is being called from a collection view
|
|
94
|
+
*/
|
|
58
95
|
selectionController?: SelectionController;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Optional highlight function to highlight the entity in the collection view
|
|
99
|
+
* @param entity
|
|
100
|
+
*/
|
|
59
101
|
highlightEntity?: (entity: Entity<any>) => void;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Optional unhighlight function to remove the highlight from the entity in the collection view
|
|
105
|
+
* @param entity
|
|
106
|
+
*/
|
|
60
107
|
unhighlightEntity?: (entity: Entity<any>) => void;
|
|
61
|
-
|
|
108
|
+
|
|
62
109
|
/**
|
|
63
|
-
*
|
|
110
|
+
* Optional function to navigate back (e.g. when deleting an entity or navigating from a form)
|
|
64
111
|
*/
|
|
65
|
-
|
|
112
|
+
navigateBack?: () => void;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Callback to be called when the collection changes, e.g. after an entity is deleted or created.
|
|
116
|
+
*/
|
|
117
|
+
onCollectionChange?: () => void;
|
|
66
118
|
|
|
67
|
-
openEntityMode: "side_panel" | "full_screen";
|
|
68
119
|
};
|
package/src/types/firecms.tsx
CHANGED
|
@@ -12,6 +12,7 @@ import { EntityLinkBuilder } from "./entity_link_builder";
|
|
|
12
12
|
import { UserConfigurationPersistence } from "./local_config_persistence";
|
|
13
13
|
import { FireCMSPlugin } from "./plugins";
|
|
14
14
|
import { CMSAnalyticsEvent } from "./analytics";
|
|
15
|
+
import { EntityAction } from "./entity_actions";
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Use this callback to build entity collections dynamically.
|
|
@@ -92,9 +93,16 @@ export type FireCMSProps<USER extends User> = {
|
|
|
92
93
|
*
|
|
93
94
|
* You can also define an entity view from the UI.
|
|
94
95
|
*/
|
|
95
|
-
|
|
96
96
|
entityViews?: EntityCustomView[];
|
|
97
97
|
|
|
98
|
+
/**
|
|
99
|
+
* List of actions that can be performed on entities.
|
|
100
|
+
* These actions are displayed in the entity view and in the collection view.
|
|
101
|
+
* You can later reuse these actions in the `entityActions` prop of a collection,
|
|
102
|
+
* by specifying the `key` of the action.
|
|
103
|
+
*/
|
|
104
|
+
entityActions?: EntityAction[];
|
|
105
|
+
|
|
98
106
|
/**
|
|
99
107
|
* Format of the dates in the CMS.
|
|
100
108
|
* Defaults to 'MMMM dd, yyyy, HH:mm:ss'
|
|
@@ -129,7 +137,8 @@ export type FireCMSProps<USER extends User> = {
|
|
|
129
137
|
|
|
130
138
|
/**
|
|
131
139
|
* Use plugins to modify the behaviour of the CMS.
|
|
132
|
-
*
|
|
140
|
+
* DEPRECATED: use the `plugins` prop in the `useBuildNavigationController` instead.
|
|
141
|
+
* This prop will work as a fallback for the `plugins` prop in the `useBuildNavigationController`.
|
|
133
142
|
*/
|
|
134
143
|
plugins?: FireCMSPlugin<any, any, any>[];
|
|
135
144
|
|
package/src/types/navigation.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { EntityCollection } from "./collections";
|
|
3
3
|
import { EntityReference } from "./entities";
|
|
4
|
+
import { FireCMSPlugin } from "./plugins";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Controller that includes the resolved navigation and utility methods and
|
|
@@ -35,7 +36,7 @@ export type NavigationController<EC extends EntityCollection = EntityCollection<
|
|
|
35
36
|
* level of the navigation (e.g. in the home page or the navigation
|
|
36
37
|
* drawer)
|
|
37
38
|
*/
|
|
38
|
-
topLevelNavigation?:
|
|
39
|
+
topLevelNavigation?: NavigationResult;
|
|
39
40
|
|
|
40
41
|
/**
|
|
41
42
|
* Is the navigation loading (the configuration persistence has not
|
|
@@ -152,6 +153,11 @@ export type NavigationController<EC extends EntityCollection = EntityCollection<
|
|
|
152
153
|
*/
|
|
153
154
|
navigate: (to: string, options?: NavigateOptions) => void;
|
|
154
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Plugin system allowing to extend the CMS functionality.
|
|
158
|
+
*/
|
|
159
|
+
plugins?: FireCMSPlugin<any, any, any>[];
|
|
160
|
+
|
|
155
161
|
}
|
|
156
162
|
|
|
157
163
|
export interface NavigateOptions {
|
|
@@ -200,7 +206,7 @@ export interface CMSView {
|
|
|
200
206
|
* e.g. 'account_tree' or 'person'
|
|
201
207
|
* Find all the icons in https://firecms.co/docs/icons
|
|
202
208
|
*/
|
|
203
|
-
icon?: string;
|
|
209
|
+
icon?: string | React.ReactNode;
|
|
204
210
|
|
|
205
211
|
/**
|
|
206
212
|
* Should this view be hidden from the main navigation panel.
|
|
@@ -223,7 +229,22 @@ export interface CMSView {
|
|
|
223
229
|
|
|
224
230
|
}
|
|
225
231
|
|
|
226
|
-
|
|
232
|
+
/**
|
|
233
|
+
* Used to group navigation entries in the main navigation.
|
|
234
|
+
*/
|
|
235
|
+
export interface NavigationGroupMapping {
|
|
236
|
+
/**
|
|
237
|
+
* Name of the group, used to display the group header in the UI
|
|
238
|
+
*/
|
|
239
|
+
name: string;
|
|
240
|
+
/**
|
|
241
|
+
* List of collection ids or view paths that belong to this group.
|
|
242
|
+
*/
|
|
243
|
+
entries: string[];
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export interface NavigationEntry {
|
|
247
|
+
id: string;
|
|
227
248
|
url: string;
|
|
228
249
|
name: string;
|
|
229
250
|
path: string;
|
|
@@ -234,7 +255,14 @@ export interface TopNavigationEntry {
|
|
|
234
255
|
group: string;
|
|
235
256
|
}
|
|
236
257
|
|
|
237
|
-
export type
|
|
238
|
-
|
|
239
|
-
|
|
258
|
+
export type NavigationResult = {
|
|
259
|
+
|
|
260
|
+
allowDragAndDrop: boolean;
|
|
261
|
+
|
|
262
|
+
navigationEntries: NavigationEntry[],
|
|
263
|
+
|
|
264
|
+
groups: string[],
|
|
265
|
+
|
|
266
|
+
onNavigationEntriesUpdate: (entries: NavigationGroupMapping[]) => void;
|
|
240
267
|
};
|
|
268
|
+
|
package/src/types/plugins.tsx
CHANGED
|
@@ -7,6 +7,7 @@ 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 { NavigationGroupMapping } from "./navigation";
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Interface used to define plugins for FireCMS.
|
|
@@ -84,6 +85,20 @@ export type FireCMSPlugin<PROPS = any, FORM_PROPS = any, EC extends EntityCollec
|
|
|
84
85
|
children: React.ReactNode;
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Allow reordering with drag and drop of the collections in the home page.
|
|
90
|
+
*/
|
|
91
|
+
allowDragAndDrop?: boolean;
|
|
92
|
+
|
|
93
|
+
navigationEntries?: NavigationGroupMapping[];
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* This method will be called when the entries are updated in the home page.
|
|
97
|
+
* group => navigationEntriesOrder (path)
|
|
98
|
+
* @param entries
|
|
99
|
+
*/
|
|
100
|
+
onNavigationEntriesUpdate?: (entries: NavigationGroupMapping[]) => void;
|
|
101
|
+
|
|
87
102
|
}
|
|
88
103
|
|
|
89
104
|
collectionView?: {
|
|
@@ -151,13 +166,37 @@ export type FireCMSPlugin<PROPS = any, FORM_PROPS = any, EC extends EntityCollec
|
|
|
151
166
|
props?: FORM_PROPS;
|
|
152
167
|
}
|
|
153
168
|
|
|
169
|
+
/**
|
|
170
|
+
* Add custom actions to the default ones ("Save", "Discard"...)
|
|
171
|
+
*/
|
|
154
172
|
Actions?: React.ComponentType<PluginFormActionProps<any, EC>>;
|
|
155
173
|
|
|
174
|
+
/**
|
|
175
|
+
* Add custom actions to the top of the form
|
|
176
|
+
*/
|
|
177
|
+
ActionsTop?: React.ComponentType<PluginFormActionProps<any, EC>>;
|
|
178
|
+
|
|
156
179
|
fieldBuilder?: <T extends CMSType = CMSType>(props: PluginFieldBuilderParams<T, any, EC>) => React.ComponentType<FieldProps<T>> | null;
|
|
157
180
|
|
|
158
181
|
fieldBuilderEnabled?: <T extends CMSType = CMSType>(props: PluginFieldBuilderParams<T>) => boolean;
|
|
159
182
|
}
|
|
160
183
|
|
|
184
|
+
collection?: {
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Use this method to modify a single collection before it is rendered.
|
|
188
|
+
* @param collection
|
|
189
|
+
*/
|
|
190
|
+
modifyCollection?: (collection: EntityCollection) => EntityCollection;
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Use this method to modify, add or remove collections.
|
|
194
|
+
* @param collections
|
|
195
|
+
*/
|
|
196
|
+
injectCollections?: (collections: EntityCollection[]) => EntityCollection[];
|
|
197
|
+
|
|
198
|
+
}
|
|
199
|
+
|
|
161
200
|
}
|
|
162
201
|
|
|
163
202
|
/**
|
|
@@ -190,12 +229,12 @@ export interface PluginHomePageActionsProps<EP extends object = object, M extend
|
|
|
190
229
|
export interface PluginFormActionProps<USER extends User = User, EC extends EntityCollection = EntityCollection> {
|
|
191
230
|
entityId?: string;
|
|
192
231
|
path: string;
|
|
232
|
+
parentCollectionIds: string[];
|
|
193
233
|
status: EntityStatus;
|
|
194
234
|
collection: EC;
|
|
195
235
|
disabled: boolean;
|
|
196
236
|
formContext?: FormContext<any>;
|
|
197
237
|
context: FireCMSContext<USER>;
|
|
198
|
-
currentEntityId?: string;
|
|
199
238
|
openEntityMode: "side_panel" | "full_screen";
|
|
200
239
|
}
|
|
201
240
|
|
package/src/types/properties.ts
CHANGED
|
@@ -413,6 +413,14 @@ export interface StringProperty extends BaseProperty<string> {
|
|
|
413
413
|
* Add an icon to clear the value and set it to `null`. Defaults to `false`
|
|
414
414
|
*/
|
|
415
415
|
clearable?: boolean;
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* You can use this property (a string) to behave as a reference to another
|
|
419
|
+
* collection. The stored value is the ID of the entity in the
|
|
420
|
+
* collection, and the `path` prop is used to
|
|
421
|
+
* define the collection this reference points to.
|
|
422
|
+
*/
|
|
423
|
+
reference?: ReferenceProperty;
|
|
416
424
|
}
|
|
417
425
|
|
|
418
426
|
/**
|
|
@@ -15,16 +15,16 @@ export interface EntitySidePanelProps<M extends Record<string, any> = any> {
|
|
|
15
15
|
*/
|
|
16
16
|
path: string;
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Full CMS path of the entity, including the collection and sub-collections.
|
|
20
|
+
*/
|
|
21
|
+
fullIdPath?: string;
|
|
22
|
+
|
|
18
23
|
/**
|
|
19
24
|
* ID of the entity, if not set, it means we are creating a new entity
|
|
20
25
|
*/
|
|
21
26
|
entityId?: string;
|
|
22
27
|
|
|
23
|
-
// /**
|
|
24
|
-
// * Navigation path with ids of the entity
|
|
25
|
-
// */
|
|
26
|
-
// fullIdPath: string;
|
|
27
|
-
|
|
28
28
|
/**
|
|
29
29
|
* Set this flag to true if you want to make a copy of an existing entity
|
|
30
30
|
*/
|
|
@@ -76,6 +76,11 @@ export interface EntitySidePanelProps<M extends Record<string, any> = any> {
|
|
|
76
76
|
* Override some form properties
|
|
77
77
|
*/
|
|
78
78
|
formProps?: Partial<EntityFormProps<M>>;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Allow the user to open the entity fullscreen
|
|
82
|
+
*/
|
|
83
|
+
allowFullScreen?: boolean;
|
|
79
84
|
}
|
|
80
85
|
|
|
81
86
|
/**
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { EntityCallbacks } from "../types";
|
|
2
|
+
|
|
3
|
+
export const mergeCallbacks = (
|
|
4
|
+
baseCallbacks: EntityCallbacks = {},
|
|
5
|
+
pluginCallbacks: EntityCallbacks = {}
|
|
6
|
+
): EntityCallbacks | undefined => {
|
|
7
|
+
|
|
8
|
+
if (!baseCallbacks && !pluginCallbacks) {
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const mergedCallbacks: EntityCallbacks = {};
|
|
13
|
+
|
|
14
|
+
// Handle onFetch - returns Entity<M> or Promise<Entity<M>>
|
|
15
|
+
if (baseCallbacks.onFetch || pluginCallbacks.onFetch) {
|
|
16
|
+
mergedCallbacks.onFetch = async (props) => {
|
|
17
|
+
let entity = props.entity;
|
|
18
|
+
if (baseCallbacks.onFetch) {
|
|
19
|
+
entity = await Promise.resolve(baseCallbacks.onFetch(props));
|
|
20
|
+
}
|
|
21
|
+
if (pluginCallbacks.onFetch) {
|
|
22
|
+
entity = await Promise.resolve(pluginCallbacks.onFetch({
|
|
23
|
+
...props,
|
|
24
|
+
entity
|
|
25
|
+
}));
|
|
26
|
+
}
|
|
27
|
+
return entity;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Handle onSaveSuccess - returns void or Promise<void>
|
|
32
|
+
if (baseCallbacks.onSaveSuccess || pluginCallbacks.onSaveSuccess) {
|
|
33
|
+
mergedCallbacks.onSaveSuccess = async (props) => {
|
|
34
|
+
if (baseCallbacks.onSaveSuccess) {
|
|
35
|
+
await Promise.resolve(baseCallbacks.onSaveSuccess(props));
|
|
36
|
+
}
|
|
37
|
+
if (pluginCallbacks.onSaveSuccess) {
|
|
38
|
+
await Promise.resolve(pluginCallbacks.onSaveSuccess(props));
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Handle onSaveFailure - returns void or Promise<void>
|
|
44
|
+
if (baseCallbacks.onSaveFailure || pluginCallbacks.onSaveFailure) {
|
|
45
|
+
mergedCallbacks.onSaveFailure = async (props) => {
|
|
46
|
+
if (baseCallbacks.onSaveFailure) {
|
|
47
|
+
await Promise.resolve(baseCallbacks.onSaveFailure(props));
|
|
48
|
+
}
|
|
49
|
+
if (pluginCallbacks.onSaveFailure) {
|
|
50
|
+
await Promise.resolve(pluginCallbacks.onSaveFailure(props));
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Handle onPreSave - returns Partial<EntityValues<M>> or Promise<Partial<EntityValues<M>>>
|
|
56
|
+
if (baseCallbacks.onPreSave || pluginCallbacks.onPreSave) {
|
|
57
|
+
mergedCallbacks.onPreSave = async (props) => {
|
|
58
|
+
let values = { ...props.values };
|
|
59
|
+
if (baseCallbacks.onPreSave) {
|
|
60
|
+
const baseValues = await Promise.resolve(baseCallbacks.onPreSave(props));
|
|
61
|
+
values = { ...values, ...baseValues };
|
|
62
|
+
}
|
|
63
|
+
if (pluginCallbacks.onPreSave) {
|
|
64
|
+
const pluginValues = await Promise.resolve(pluginCallbacks.onPreSave({
|
|
65
|
+
...props,
|
|
66
|
+
values
|
|
67
|
+
}));
|
|
68
|
+
values = { ...values, ...pluginValues };
|
|
69
|
+
}
|
|
70
|
+
return values;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Handle onPreDelete - returns void
|
|
75
|
+
if (baseCallbacks.onPreDelete || pluginCallbacks.onPreDelete) {
|
|
76
|
+
mergedCallbacks.onPreDelete = (props) => {
|
|
77
|
+
if (baseCallbacks.onPreDelete) {
|
|
78
|
+
baseCallbacks.onPreDelete(props);
|
|
79
|
+
}
|
|
80
|
+
if (pluginCallbacks.onPreDelete) {
|
|
81
|
+
pluginCallbacks.onPreDelete(props);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Handle onDelete - returns void
|
|
87
|
+
if (baseCallbacks.onDelete || pluginCallbacks.onDelete) {
|
|
88
|
+
mergedCallbacks.onDelete = (props) => {
|
|
89
|
+
if (baseCallbacks.onDelete) {
|
|
90
|
+
baseCallbacks.onDelete(props);
|
|
91
|
+
}
|
|
92
|
+
if (pluginCallbacks.onDelete) {
|
|
93
|
+
pluginCallbacks.onDelete(props);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Handle onIdUpdate - returns string or Promise<string>
|
|
99
|
+
if (baseCallbacks.onIdUpdate || pluginCallbacks.onIdUpdate) {
|
|
100
|
+
mergedCallbacks.onIdUpdate = async (props) => {
|
|
101
|
+
let id = props.entityId || "";
|
|
102
|
+
|
|
103
|
+
if (baseCallbacks.onIdUpdate) {
|
|
104
|
+
id = await Promise.resolve(baseCallbacks.onIdUpdate(props));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (pluginCallbacks.onIdUpdate) {
|
|
108
|
+
id = await Promise.resolve(pluginCallbacks.onIdUpdate({
|
|
109
|
+
...props,
|
|
110
|
+
entityId: id
|
|
111
|
+
}));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return id;
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return Object.keys(mergedCallbacks).length > 0 ? mergedCallbacks : undefined;
|
|
119
|
+
};
|