@firecms/core 3.0.0-beta.12 → 3.0.0-beta.14
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/app/Scaffold.d.ts +4 -0
- package/dist/components/ArrayContainer.d.ts +13 -11
- package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +4 -0
- package/dist/components/EntityJsonPreview.d.ts +3 -0
- package/dist/components/EntityPreview.d.ts +4 -2
- 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/DefaultAppBar.d.ts +8 -2
- package/dist/core/EntityEditView.d.ts +8 -1
- package/dist/core/FireCMS.d.ts +2 -2
- package/dist/form/EntityForm.d.ts +5 -1
- package/dist/form/PropertyFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +3 -9
- package/dist/hooks/data/save.d.ts +1 -1
- package/dist/hooks/useBuildNavigationController.d.ts +2 -9
- package/dist/index.es.js +9251 -8721
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +16686 -16160
- package/dist/index.umd.js.map +1 -1
- package/dist/internal/useBuildDataSource.d.ts +3 -2
- package/dist/internal/useBuildSideEntityController.d.ts +3 -3
- package/dist/types/collections.d.ts +26 -2
- package/dist/types/fields.d.ts +4 -1
- package/dist/types/firecms.d.ts +3 -2
- package/dist/types/navigation.d.ts +9 -0
- package/dist/types/plugins.d.ts +13 -0
- package/dist/types/properties.d.ts +22 -1
- package/dist/types/side_entity_controller.d.ts +4 -0
- package/dist/util/callbacks.d.ts +2 -0
- package/dist/util/createFormexStub.d.ts +2 -0
- package/dist/util/index.d.ts +1 -0
- package/dist/util/navigation_utils.d.ts +2 -1
- package/dist/util/objects.d.ts +1 -1
- package/dist/util/property_utils.d.ts +2 -2
- package/dist/util/references.d.ts +2 -2
- package/dist/util/resolutions.d.ts +11 -6
- package/package.json +9 -6
- package/src/app/Scaffold.tsx +13 -3
- package/src/components/ArrayContainer.tsx +414 -282
- package/src/components/ClearFilterSortButton.tsx +1 -1
- package/src/components/ConfirmationDialog.tsx +9 -9
- package/src/components/DeleteEntityDialog.tsx +4 -2
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +8 -6
- package/src/components/EntityCollectionTable/PropertyTableCell.tsx +1 -1
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +1 -1
- package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +13 -2
- package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +58 -29
- package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +9 -9
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +26 -6
- package/src/components/EntityJsonPreview.tsx +66 -0
- package/src/components/EntityPreview.tsx +27 -16
- package/src/components/EntityView.tsx +4 -1
- package/src/components/ErrorView.tsx +1 -1
- package/src/components/HomePage/DefaultHomePage.tsx +2 -1
- package/src/components/HomePage/NavigationCardBinding.tsx +3 -1
- package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +3 -1
- package/src/components/SelectableTable/SelectableTable.tsx +140 -143
- package/src/components/VirtualTable/VirtualTable.tsx +37 -31
- 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 +15 -4
- package/src/components/index.tsx +2 -0
- package/src/core/DefaultAppBar.tsx +17 -5
- package/src/core/EntityEditView.tsx +135 -47
- package/src/core/EntitySidePanel.tsx +15 -20
- package/src/core/FireCMS.tsx +19 -12
- package/src/form/EntityForm.tsx +32 -24
- package/src/form/PropertyFieldBinding.tsx +8 -6
- package/src/form/components/CustomIdField.tsx +3 -1
- package/src/form/components/LabelWithIcon.tsx +1 -1
- package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +4 -1
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +4 -2
- package/src/form/field_bindings/BlockFieldBinding.tsx +1 -1
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +1 -1
- package/src/form/field_bindings/MapFieldBinding.tsx +5 -4
- package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +6 -2
- package/src/form/field_bindings/MultiSelectFieldBinding.tsx +3 -3
- package/src/form/field_bindings/RepeatFieldBinding.tsx +9 -2
- package/src/form/field_bindings/SelectFieldBinding.tsx +3 -2
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +227 -156
- package/src/hooks/data/save.ts +24 -35
- package/src/hooks/useBuildNavigationController.tsx +42 -17
- package/src/hooks/useFireCMSContext.tsx +0 -30
- package/src/internal/useBuildDataSource.ts +9 -5
- package/src/internal/useBuildSideEntityController.tsx +26 -20
- package/src/preview/PropertyPreview.tsx +4 -2
- package/src/preview/components/ImagePreview.tsx +2 -2
- package/src/preview/components/ReferencePreview.tsx +1 -1
- package/src/preview/property_previews/ArrayOfMapsPreview.tsx +5 -4
- package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +4 -3
- package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +4 -2
- package/src/preview/property_previews/ArrayOfStringsPreview.tsx +4 -3
- package/src/preview/property_previews/ArrayOneOfPreview.tsx +4 -2
- package/src/preview/property_previews/ArrayPropertyPreview.tsx +4 -2
- 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 +15 -4
- package/src/types/collections.ts +31 -2
- package/src/types/fields.tsx +5 -1
- package/src/types/firecms.tsx +3 -3
- package/src/types/navigation.ts +11 -0
- package/src/types/plugins.tsx +17 -0
- package/src/types/properties.ts +27 -1
- package/src/types/side_entity_controller.tsx +5 -0
- package/src/util/callbacks.ts +119 -0
- package/src/util/createFormexStub.tsx +62 -0
- package/src/util/index.ts +1 -0
- package/src/util/join_collections.ts +3 -1
- package/src/util/navigation_from_path.ts +5 -1
- package/src/util/navigation_utils.ts +84 -20
- package/src/util/objects.ts +54 -17
- package/src/util/property_utils.tsx +7 -3
- package/src/util/references.ts +8 -6
- package/src/util/resolutions.ts +17 -9
- package/src/util/useStorageUploadController.tsx +21 -2
- package/dist/components/EntityCollectionTable/internal/popup_field/ElementResizeListener.d.ts +0 -5
- package/src/components/EntityCollectionTable/internal/popup_field/ElementResizeListener.tsx +0 -59
|
@@ -13,6 +13,7 @@ import { useBreadcrumbsController } from "../hooks/useBreadcrumbsController";
|
|
|
13
13
|
import { toArray } from "../util/arrays";
|
|
14
14
|
import { EntityCollectionView, NotFoundPage } from "../components";
|
|
15
15
|
import { UnsavedChangesDialog } from "../components/UnsavedChangesDialog";
|
|
16
|
+
import { EntityCollection } from "../types";
|
|
16
17
|
|
|
17
18
|
export function FireCMSRoute() {
|
|
18
19
|
|
|
@@ -68,7 +69,10 @@ export function FireCMSRoute() {
|
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
if (navigationEntries.length === 1 && navigationEntries[0].type === "collection") {
|
|
71
|
-
|
|
72
|
+
let collection: EntityCollection<any> | undefined;
|
|
73
|
+
collection = navigation.getCollectionById(navigationEntries[0].id);
|
|
74
|
+
if (!collection)
|
|
75
|
+
collection = navigation.getCollection(navigationEntries[0].path);
|
|
72
76
|
if (!collection)
|
|
73
77
|
return null;
|
|
74
78
|
return <EntityCollectionView
|
|
@@ -84,11 +88,16 @@ export function FireCMSRoute() {
|
|
|
84
88
|
if (isSidePanel) {
|
|
85
89
|
const lastCollectionEntry = navigationEntries.findLast((entry) => entry.type === "collection");
|
|
86
90
|
if (lastCollectionEntry) {
|
|
87
|
-
|
|
91
|
+
let collection: EntityCollection<any> | undefined;
|
|
92
|
+
const firstEntry = navigationEntries[0] as NavigationViewCollectionInternal<any>;
|
|
93
|
+
collection = navigation.getCollectionById(firstEntry.id);
|
|
94
|
+
if (!collection)
|
|
95
|
+
collection = navigation.getCollection(firstEntry.path);
|
|
88
96
|
if (!collection)
|
|
89
97
|
return null;
|
|
90
98
|
return <EntityCollectionView
|
|
91
99
|
key={`collection_view_${collection.id ?? collection.path}`}
|
|
100
|
+
fullIdPath={collection.id}
|
|
92
101
|
isSubCollection={false}
|
|
93
102
|
parentCollectionIds={[]}
|
|
94
103
|
fullPath={collection.id}
|
|
@@ -175,7 +184,7 @@ function EntityFullScreenRoute({
|
|
|
175
184
|
return blocked.current;
|
|
176
185
|
});
|
|
177
186
|
} catch (e) {
|
|
178
|
-
console.warn("Blocker not available, navigation will not be blocked");
|
|
187
|
+
// console.warn("Blocker not available, navigation will not be blocked");
|
|
179
188
|
}
|
|
180
189
|
|
|
181
190
|
const lastCollectionEntry = navigationEntries.findLast((entry) => entry.type === "collection");
|
|
@@ -189,12 +198,14 @@ function EntityFullScreenRoute({
|
|
|
189
198
|
}
|
|
190
199
|
|
|
191
200
|
const collection = isNew ? lastCollectionEntry!.collection : lastEntityEntry!.parentCollection;
|
|
192
|
-
const
|
|
201
|
+
const fullIdPath = isNew ? lastCollectionEntry!.path : lastEntityEntry!.path;
|
|
202
|
+
const collectionPath = navigation.resolveIdsFrom(fullIdPath);
|
|
193
203
|
|
|
194
204
|
return <>
|
|
195
205
|
<EntityEditView
|
|
196
206
|
key={collection.id + "_" + (isNew ? "new" : (isCopy ? entityId + "_copy" : entityId))}
|
|
197
207
|
entityId={isNew ? undefined : entityId}
|
|
208
|
+
fullIdPath={fullIdPath}
|
|
198
209
|
collection={collection}
|
|
199
210
|
layout={"full_screen"}
|
|
200
211
|
path={collectionPath}
|
package/src/types/collections.ts
CHANGED
|
@@ -112,7 +112,7 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
|
|
|
112
112
|
* `hidden` in the property definition, will be ignored.
|
|
113
113
|
* `propertiesOrder` has precedence over `hidden`.
|
|
114
114
|
* - For properties use the property key.
|
|
115
|
-
* - For additional
|
|
115
|
+
* - For additional fields use the field key.
|
|
116
116
|
* - If you have subcollections, you get a column for each subcollection,
|
|
117
117
|
* with the path (or alias) as the subcollection, prefixed with
|
|
118
118
|
* `subcollection:`. e.g. `subcollection:orders`.
|
|
@@ -127,7 +127,8 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
|
|
|
127
127
|
|
|
128
128
|
/**
|
|
129
129
|
* If enabled, content is loaded in batches. If `false` all entities in the
|
|
130
|
-
* collection are loaded.
|
|
130
|
+
* collection are loaded. This means that when reaching the end of the
|
|
131
|
+
* collection, the CMS will load more entities.
|
|
131
132
|
* You can specify a number to specify the pagination size (50 by default)
|
|
132
133
|
* Defaults to `true`
|
|
133
134
|
*/
|
|
@@ -215,6 +216,7 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
|
|
|
215
216
|
* Force a filter in this view. If applied, the rest of the filters will
|
|
216
217
|
* be disabled. Filters applied with this prop cannot be changed.
|
|
217
218
|
* e.g. `forceFilter: { age: [">=", 18] }`
|
|
219
|
+
* e.g. `forceFilter: { related_user: ["==", new EntityReference("sdc43dsw2", "users")] }`
|
|
218
220
|
*/
|
|
219
221
|
forceFilter?: FilterValues<Extract<keyof M, string>>;
|
|
220
222
|
|
|
@@ -222,6 +224,7 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
|
|
|
222
224
|
* Initial filters applied to the collection this collection is related to.
|
|
223
225
|
* Defaults to none. Filters applied with this prop can be changed.
|
|
224
226
|
* e.g. `initialFilter: { age: [">=", 18] }`
|
|
227
|
+
* e.g. `initialFilter: { related_user: ["==", new EntityReference("sdc43dsw2", "users")] }`
|
|
225
228
|
*/
|
|
226
229
|
initialFilter?: FilterValues<Extract<keyof M, string>>; // setting FilterValues<M> can break defining collections by code
|
|
227
230
|
|
|
@@ -330,6 +333,17 @@ export interface EntityCollection<M extends Record<string, any> = any, USER exte
|
|
|
330
333
|
* Defaults to false.
|
|
331
334
|
*/
|
|
332
335
|
alwaysApplyDefaultValues?: boolean;
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* If set to true, a tab including the JSON representation of the entity will be included.
|
|
339
|
+
*/
|
|
340
|
+
includeJsonView?: boolean;
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* If set to true, changes to the entity will be saved in a subcollection.
|
|
344
|
+
* This prop has no effect if the history plugin is not enabled
|
|
345
|
+
*/
|
|
346
|
+
history?: boolean;
|
|
333
347
|
}
|
|
334
348
|
|
|
335
349
|
/**
|
|
@@ -512,6 +526,11 @@ export type EntityCustomView<M extends Record<string, any> = any> =
|
|
|
512
526
|
*/
|
|
513
527
|
name: string;
|
|
514
528
|
|
|
529
|
+
/**
|
|
530
|
+
* Render this custom view in the tab of the entity view, instead of the name
|
|
531
|
+
*/
|
|
532
|
+
tabComponent?: React.ReactNode;
|
|
533
|
+
|
|
515
534
|
/**
|
|
516
535
|
* If set to true, the actions of the entity (save, discard,delete) will be
|
|
517
536
|
* included in the view. By default the actions are located in the right or bottom,
|
|
@@ -524,6 +543,11 @@ export type EntityCustomView<M extends Record<string, any> = any> =
|
|
|
524
543
|
* Builder for rendering the custom view
|
|
525
544
|
*/
|
|
526
545
|
Builder?: React.ComponentType<EntityCustomViewParams<M>>;
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Position of this tab in the entity view. Defaults to `end`.
|
|
549
|
+
*/
|
|
550
|
+
position?: "start" | "end";
|
|
527
551
|
};
|
|
528
552
|
|
|
529
553
|
/**
|
|
@@ -554,6 +578,11 @@ export interface EntityCustomViewParams<M extends Record<string, any> = any> {
|
|
|
554
578
|
* Use the form context to access the form state and methods
|
|
555
579
|
*/
|
|
556
580
|
formContext: FormContext;
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* If this is a subcollection, this is the path of the parent collections
|
|
584
|
+
*/
|
|
585
|
+
parentCollectionIds?: string[];
|
|
557
586
|
}
|
|
558
587
|
|
|
559
588
|
export type InferCollectionType<S extends EntityCollection> = S extends EntityCollection<infer M> ? M : never;
|
package/src/types/fields.tsx
CHANGED
|
@@ -171,9 +171,13 @@ export interface FormContext<M extends Record<string, any> = any> {
|
|
|
171
171
|
openEntityMode: "side_panel" | "full_screen";
|
|
172
172
|
|
|
173
173
|
/**
|
|
174
|
-
* This is the underlying formex controller that powers the form
|
|
174
|
+
* This is the underlying formex controller that powers the form.
|
|
175
|
+
* If you are in a red only mode, the formex controller is there, but you can't
|
|
176
|
+
* operate with it
|
|
175
177
|
*/
|
|
176
178
|
formex: FormexController<M>;
|
|
179
|
+
|
|
180
|
+
disabled: boolean;
|
|
177
181
|
}
|
|
178
182
|
|
|
179
183
|
/**
|
package/src/types/firecms.tsx
CHANGED
|
@@ -47,7 +47,7 @@ export type CMSViewsBuilder = (params: {
|
|
|
47
47
|
/**
|
|
48
48
|
* @group Models
|
|
49
49
|
*/
|
|
50
|
-
export type FireCMSProps<USER extends User
|
|
50
|
+
export type FireCMSProps<USER extends User> = {
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
53
|
* Use this function to return the components you want to render under
|
|
@@ -92,7 +92,6 @@ export type FireCMSProps<USER extends User, EC extends EntityCollection> = {
|
|
|
92
92
|
*
|
|
93
93
|
* You can also define an entity view from the UI.
|
|
94
94
|
*/
|
|
95
|
-
|
|
96
95
|
entityViews?: EntityCustomView[];
|
|
97
96
|
|
|
98
97
|
/**
|
|
@@ -129,7 +128,8 @@ export type FireCMSProps<USER extends User, EC extends EntityCollection> = {
|
|
|
129
128
|
|
|
130
129
|
/**
|
|
131
130
|
* Use plugins to modify the behaviour of the CMS.
|
|
132
|
-
*
|
|
131
|
+
* DEPRECATED: use the `plugins` prop in the `useBuildNavigationController` instead.
|
|
132
|
+
* This prop will work as a fallback for the `plugins` prop in the `useBuildNavigationController`.
|
|
133
133
|
*/
|
|
134
134
|
plugins?: FireCMSPlugin<any, any, any>[];
|
|
135
135
|
|
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
|
|
@@ -59,6 +60,11 @@ export type NavigationController<EC extends EntityCollection = EntityCollection<
|
|
|
59
60
|
*/
|
|
60
61
|
getCollection: (pathOrId: string, includeUserOverride?: boolean) => EC | undefined;
|
|
61
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Get the top level collection configuration for a given id
|
|
65
|
+
*/
|
|
66
|
+
getCollectionById: (id: string) => EC | undefined;
|
|
67
|
+
|
|
62
68
|
/**
|
|
63
69
|
* Get the collection configuration from its parent ids.
|
|
64
70
|
*/
|
|
@@ -147,6 +153,11 @@ export type NavigationController<EC extends EntityCollection = EntityCollection<
|
|
|
147
153
|
*/
|
|
148
154
|
navigate: (to: string, options?: NavigateOptions) => void;
|
|
149
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Plugin system allowing to extend the CMS functionality.
|
|
158
|
+
*/
|
|
159
|
+
plugins?: FireCMSPlugin<any, any, any>[];
|
|
160
|
+
|
|
150
161
|
}
|
|
151
162
|
|
|
152
163
|
export interface NavigateOptions {
|
package/src/types/plugins.tsx
CHANGED
|
@@ -158,6 +158,22 @@ export type FireCMSPlugin<PROPS = any, FORM_PROPS = any, EC extends EntityCollec
|
|
|
158
158
|
fieldBuilderEnabled?: <T extends CMSType = CMSType>(props: PluginFieldBuilderParams<T>) => boolean;
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
+
collection?: {
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Use this method to modify a single collection before it is rendered.
|
|
165
|
+
* @param collection
|
|
166
|
+
*/
|
|
167
|
+
modifyCollection?: (collection: EntityCollection) => EntityCollection;
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Use this method to modify, add or remove collections.
|
|
171
|
+
* @param collections
|
|
172
|
+
*/
|
|
173
|
+
injectCollections?: (collections: EntityCollection[]) => EntityCollection[];
|
|
174
|
+
|
|
175
|
+
}
|
|
176
|
+
|
|
161
177
|
}
|
|
162
178
|
|
|
163
179
|
/**
|
|
@@ -192,6 +208,7 @@ export interface PluginFormActionProps<USER extends User = User, EC extends Enti
|
|
|
192
208
|
path: string;
|
|
193
209
|
status: EntityStatus;
|
|
194
210
|
collection: EC;
|
|
211
|
+
disabled: boolean;
|
|
195
212
|
formContext?: FormContext<any>;
|
|
196
213
|
context: FireCMSContext<USER>;
|
|
197
214
|
currentEntityId?: string;
|
package/src/types/properties.ts
CHANGED
|
@@ -5,6 +5,7 @@ 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";
|
|
8
|
+
import { AuthController } from "./auth";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* @group Entity properties
|
|
@@ -270,6 +271,11 @@ export type PropertyBuilderProps<M extends Record<string, any> = any> =
|
|
|
270
271
|
* Entity ID
|
|
271
272
|
*/
|
|
272
273
|
entityId?: string;
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Controller to manage authentication
|
|
277
|
+
*/
|
|
278
|
+
authController: AuthController;
|
|
273
279
|
};
|
|
274
280
|
|
|
275
281
|
/**
|
|
@@ -285,7 +291,8 @@ export type PropertyBuilder<T extends CMSType = any, M extends Record<string, an
|
|
|
285
291
|
propertyValue,
|
|
286
292
|
index,
|
|
287
293
|
path,
|
|
288
|
-
entityId
|
|
294
|
+
entityId,
|
|
295
|
+
authController
|
|
289
296
|
}: PropertyBuilderProps<M>) => Property<T> | null;
|
|
290
297
|
|
|
291
298
|
/**
|
|
@@ -481,6 +488,18 @@ export interface ArrayProperty<T extends ArrayT[] = any[], ArrayT extends CMSTyp
|
|
|
481
488
|
*/
|
|
482
489
|
minimalistView?: boolean;
|
|
483
490
|
|
|
491
|
+
/**
|
|
492
|
+
* Can the elements in this array be reordered. Defaults to `true`.
|
|
493
|
+
* This prop has no effect if `disabled` is set to true.
|
|
494
|
+
*/
|
|
495
|
+
sortable?: boolean;
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Can the elements in this array be added. Defaults to `true`
|
|
499
|
+
* This prop has no effect if `disabled` is set to true.
|
|
500
|
+
*/
|
|
501
|
+
canAddElements?: boolean;
|
|
502
|
+
|
|
484
503
|
}
|
|
485
504
|
|
|
486
505
|
/**
|
|
@@ -796,6 +815,13 @@ export type StorageConfig = {
|
|
|
796
815
|
*/
|
|
797
816
|
maxSize?: number,
|
|
798
817
|
|
|
818
|
+
/**
|
|
819
|
+
* Use this callback to process the file before uploading it to the storage.
|
|
820
|
+
* If nothing is returned, the file is uploaded as it is.
|
|
821
|
+
* @param file
|
|
822
|
+
*/
|
|
823
|
+
processFile?: (file: File) => Promise<File> | undefined;
|
|
824
|
+
|
|
799
825
|
/**
|
|
800
826
|
* Postprocess the saved value (storage path or URL)
|
|
801
827
|
* after it has been resolved.
|
|
@@ -71,6 +71,11 @@ export interface EntitySidePanelProps<M extends Record<string, any> = any> {
|
|
|
71
71
|
* Override some form properties
|
|
72
72
|
*/
|
|
73
73
|
formProps?: Partial<EntityFormProps<M>>;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Allow the user to open the entity fullscreen
|
|
77
|
+
*/
|
|
78
|
+
allowFullScreen?: boolean;
|
|
74
79
|
}
|
|
75
80
|
|
|
76
81
|
/**
|
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { FormexController } from "@firecms/formex";
|
|
2
|
+
|
|
3
|
+
export function createFormexStub<T extends object>(values: T): FormexController<T> {
|
|
4
|
+
const errorMessage = "You are in a read-only context. You cannot modify the formex controller.";
|
|
5
|
+
|
|
6
|
+
return {
|
|
7
|
+
values,
|
|
8
|
+
initialValues: values,
|
|
9
|
+
touched: {} as Record<string, boolean>,
|
|
10
|
+
dirty: false,
|
|
11
|
+
errors: {} as Record<string, string>,
|
|
12
|
+
submitCount: 0,
|
|
13
|
+
isSubmitting: false,
|
|
14
|
+
isValidating: false,
|
|
15
|
+
version: 0,
|
|
16
|
+
canUndo: false,
|
|
17
|
+
canRedo: false,
|
|
18
|
+
|
|
19
|
+
setValues: () => {
|
|
20
|
+
throw new Error(errorMessage);
|
|
21
|
+
},
|
|
22
|
+
setFieldValue: () => {
|
|
23
|
+
throw new Error(errorMessage);
|
|
24
|
+
},
|
|
25
|
+
setFieldTouched: () => {
|
|
26
|
+
throw new Error(errorMessage);
|
|
27
|
+
},
|
|
28
|
+
setDirty: () => {
|
|
29
|
+
throw new Error(errorMessage);
|
|
30
|
+
},
|
|
31
|
+
setSubmitCount: () => {
|
|
32
|
+
throw new Error(errorMessage);
|
|
33
|
+
},
|
|
34
|
+
setFieldError: () => {
|
|
35
|
+
throw new Error(errorMessage);
|
|
36
|
+
},
|
|
37
|
+
handleChange: () => {
|
|
38
|
+
throw new Error(errorMessage);
|
|
39
|
+
},
|
|
40
|
+
handleBlur: () => {
|
|
41
|
+
throw new Error(errorMessage);
|
|
42
|
+
},
|
|
43
|
+
handleSubmit: () => {
|
|
44
|
+
throw new Error(errorMessage);
|
|
45
|
+
},
|
|
46
|
+
validate: () => {
|
|
47
|
+
throw new Error(errorMessage);
|
|
48
|
+
},
|
|
49
|
+
resetForm: () => {
|
|
50
|
+
throw new Error(errorMessage);
|
|
51
|
+
},
|
|
52
|
+
setSubmitting: () => {
|
|
53
|
+
throw new Error(errorMessage);
|
|
54
|
+
},
|
|
55
|
+
undo: () => {
|
|
56
|
+
throw new Error(errorMessage);
|
|
57
|
+
},
|
|
58
|
+
redo: () => {
|
|
59
|
+
throw new Error(errorMessage);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
package/src/util/index.ts
CHANGED
|
@@ -78,6 +78,7 @@ export function mergeCollection(target: EntityCollection,
|
|
|
78
78
|
modifyCollection?: (props: ModifyCollectionProps) => EntityCollection | void
|
|
79
79
|
): EntityCollection {
|
|
80
80
|
|
|
81
|
+
|
|
81
82
|
const subcollectionsMerged = joinCollectionLists(
|
|
82
83
|
target?.subcollections ?? [],
|
|
83
84
|
source?.subcollections ?? [],
|
|
@@ -94,7 +95,7 @@ export function mergeCollection(target: EntityCollection,
|
|
|
94
95
|
propertiesMerged[key] = source.properties[key] as PropertyOrBuilder;
|
|
95
96
|
});
|
|
96
97
|
|
|
97
|
-
const mergedCollection = mergeDeep(target, source);
|
|
98
|
+
const mergedCollection = mergeDeep(target, source, true);
|
|
98
99
|
const targetPropertiesOrder = getCollectionKeys(target);
|
|
99
100
|
const sourcePropertiesOrder = getCollectionKeys(source);
|
|
100
101
|
const mergedPropertiesOrder = [...new Set([...sourcePropertiesOrder, ...targetPropertiesOrder])];
|
|
@@ -118,6 +119,7 @@ export function mergeCollection(target: EntityCollection,
|
|
|
118
119
|
|
|
119
120
|
// @ts-ignore
|
|
120
121
|
resultCollection["merged"] = true;
|
|
122
|
+
|
|
121
123
|
return resultCollection
|
|
122
124
|
}
|
|
123
125
|
|
|
@@ -51,7 +51,11 @@ export function getNavigationEntriesFromPath(props: {
|
|
|
51
51
|
for (let i = 0; i < subpathCombinations.length; i++) {
|
|
52
52
|
const subpathCombination = subpathCombinations[i];
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
let collection: EntityCollection<any> | undefined;
|
|
55
|
+
collection = collections && collections.find((entry) => entry.id === subpathCombination);
|
|
56
|
+
if (!collection) {
|
|
57
|
+
collection = collections && collections.find((entry) => entry.path === subpathCombination);
|
|
58
|
+
}
|
|
55
59
|
|
|
56
60
|
if (collection) {
|
|
57
61
|
const pathOrAlias = collection.id ?? collection.path;
|