@firecms/core 3.0.0-canary.204 → 3.0.0-canary.206
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/form/EntityForm.d.ts +0 -10
- package/dist/index.es.js +185 -402
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +185 -402
- package/dist/index.umd.js.map +1 -1
- package/dist/internal/useBuildSideEntityController.d.ts +2 -2
- package/dist/util/resolutions.d.ts +6 -1
- package/package.json +5 -5
- package/src/core/EntityEditView.tsx +14 -50
- package/src/core/EntitySidePanel.tsx +2 -2
- package/src/form/EntityForm.tsx +81 -100
- package/src/internal/useBuildSideEntityController.tsx +28 -14
- package/src/util/resolutions.ts +26 -5
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EntityCollection, EntitySidePanelProps, NavigationController, SideDialogsController, SideEntityController } from "../types";
|
|
2
|
-
export declare function getEntityViewWidth(props: EntitySidePanelProps<any>, small: boolean): string;
|
|
1
|
+
import { CustomizationController, EntityCollection, EntitySidePanelProps, NavigationController, SideDialogsController, SideEntityController } from "../types";
|
|
2
|
+
export declare function getEntityViewWidth(props: EntitySidePanelProps<any>, small: boolean, customizationController: CustomizationController): string;
|
|
3
3
|
export declare const useBuildSideEntityController: (navigation: NavigationController, sideDialogsController: SideDialogsController) => SideEntityController;
|
|
4
4
|
export declare function buildSidePanelsFromUrl(path: string, collections: EntityCollection[], newFlag: boolean): EntitySidePanelProps<any>[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ArrayProperty, CMSType, EntityCollection, EntityCustomView, EntityValues, EnumValueConfig, EnumValues, NumberProperty, PropertiesOrBuilders, PropertyConfig, PropertyOrBuilder, ResolvedArrayProperty, ResolvedEntityCollection, ResolvedNumberProperty, ResolvedProperties, ResolvedProperty, ResolvedStringProperty, StringProperty, UserConfigurationPersistence } from "../types";
|
|
1
|
+
import { ArrayProperty, CMSType, CustomizationController, EntityCollection, EntityCustomView, EntityValues, EnumValueConfig, EnumValues, NumberProperty, PropertiesOrBuilders, PropertyConfig, PropertyOrBuilder, ResolvedArrayProperty, ResolvedEntityCollection, ResolvedNumberProperty, ResolvedProperties, ResolvedProperty, ResolvedStringProperty, StringProperty, UserConfigurationPersistence } from "../types";
|
|
2
2
|
export declare const resolveCollection: <M extends Record<string, any>>({ collection, path, entityId, values, previousValues, userConfigPersistence, propertyConfigs, ignoreMissingFields }: {
|
|
3
3
|
collection: EntityCollection<M> | ResolvedEntityCollection<M>;
|
|
4
4
|
path: string;
|
|
@@ -76,3 +76,8 @@ export declare function resolveProperties<M extends Record<string, any>>({ prope
|
|
|
76
76
|
export declare function resolvePropertyEnum(property: StringProperty | NumberProperty, fromBuilder?: boolean): ResolvedStringProperty | ResolvedNumberProperty;
|
|
77
77
|
export declare function resolveEnumValues(input: EnumValues): EnumValueConfig[] | undefined;
|
|
78
78
|
export declare function resolveEntityView(entityView: string | EntityCustomView<any>, contextEntityViews?: EntityCustomView<any>[]): EntityCustomView<any> | undefined;
|
|
79
|
+
export declare function resolvedSelectedEntityView<M extends Record<string, any>>(customViews: (string | EntityCustomView<M>)[] | undefined, customizationController: CustomizationController, selectedTab?: string): {
|
|
80
|
+
resolvedEntityViews: EntityCustomView[];
|
|
81
|
+
selectedEntityView: EntityCustomView | undefined;
|
|
82
|
+
selectedSecondaryForm: EntityCustomView | undefined;
|
|
83
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@firecms/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "3.0.0-canary.
|
|
4
|
+
"version": "3.0.0-canary.206",
|
|
5
5
|
"description": "Awesome Firebase/Firestore-based headless open-source CMS",
|
|
6
6
|
"funding": {
|
|
7
7
|
"url": "https://github.com/sponsors/firecmsco"
|
|
@@ -50,9 +50,9 @@
|
|
|
50
50
|
"./package.json": "./package.json"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@firecms/editor": "^3.0.0-canary.
|
|
54
|
-
"@firecms/formex": "^3.0.0-canary.
|
|
55
|
-
"@firecms/ui": "^3.0.0-canary.
|
|
53
|
+
"@firecms/editor": "^3.0.0-canary.206",
|
|
54
|
+
"@firecms/formex": "^3.0.0-canary.206",
|
|
55
|
+
"@firecms/ui": "^3.0.0-canary.206",
|
|
56
56
|
"@hello-pangea/dnd": "^17.0.0",
|
|
57
57
|
"@radix-ui/react-portal": "^1.1.3",
|
|
58
58
|
"clsx": "^2.1.1",
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
"dist",
|
|
105
105
|
"src"
|
|
106
106
|
],
|
|
107
|
-
"gitHead": "
|
|
107
|
+
"gitHead": "1e2b2703b9a4c0b7282a2a489193f57f1754730e",
|
|
108
108
|
"publishConfig": {
|
|
109
109
|
"access": "public"
|
|
110
110
|
},
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import React, { useEffect, useMemo, useState } from "react";
|
|
2
|
-
import { Entity, EntityCollection,
|
|
2
|
+
import { Entity, EntityCollection, EntityStatus, FireCMSPlugin, FormContext, User } from "../types";
|
|
3
3
|
|
|
4
4
|
import { CircularProgressCenter, EntityCollectionView, EntityView, ErrorBoundary } from "../components";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
canEditEntity,
|
|
7
|
+
removeInitialAndTrailingSlashes,
|
|
8
|
+
resolveDefaultSelectedView,
|
|
9
|
+
resolvedSelectedEntityView
|
|
10
|
+
} from "../util";
|
|
6
11
|
|
|
7
12
|
import {
|
|
8
13
|
useAuthController,
|
|
@@ -13,7 +18,7 @@ import {
|
|
|
13
18
|
} from "../hooks";
|
|
14
19
|
import { CircularProgress, cls, defaultBorderMixin, Tab, Tabs, Typography } from "@firecms/ui";
|
|
15
20
|
import { getEntityFromCache } from "../util/entity_cache";
|
|
16
|
-
import { EntityForm, EntityFormProps
|
|
21
|
+
import { EntityForm, EntityFormProps } from "../form";
|
|
17
22
|
import { EntityEditViewFormActions } from "./EntityEditViewFormActions";
|
|
18
23
|
|
|
19
24
|
const MAIN_TAB_VALUE = "main_##Q$SC^#S6";
|
|
@@ -120,43 +125,6 @@ export function EntityEditView<M extends Record<string, any>, USER extends User>
|
|
|
120
125
|
/>;
|
|
121
126
|
}
|
|
122
127
|
|
|
123
|
-
function SecondaryForm<M extends object>({
|
|
124
|
-
collection,
|
|
125
|
-
className,
|
|
126
|
-
customView,
|
|
127
|
-
entity,
|
|
128
|
-
formContext,
|
|
129
|
-
forceActionsAtTheBottom,
|
|
130
|
-
}: {
|
|
131
|
-
className?: string,
|
|
132
|
-
customView: EntityCustomView,
|
|
133
|
-
formContext: FormContext<M>,
|
|
134
|
-
collection: EntityCollection<M>,
|
|
135
|
-
forceActionsAtTheBottom?: boolean,
|
|
136
|
-
entity: Entity<M> | undefined,
|
|
137
|
-
}) {
|
|
138
|
-
|
|
139
|
-
if (!customView.Builder) {
|
|
140
|
-
console.error("customView.Builder is not defined");
|
|
141
|
-
return null;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return <FormLayoutInner
|
|
145
|
-
className={className}
|
|
146
|
-
forceActionsAtTheBottom={forceActionsAtTheBottom}
|
|
147
|
-
formContext={formContext}
|
|
148
|
-
EntityFormActionsComponent={EntityEditViewFormActions}>
|
|
149
|
-
<ErrorBoundary>
|
|
150
|
-
{formContext && <customView.Builder
|
|
151
|
-
collection={collection}
|
|
152
|
-
entity={entity}
|
|
153
|
-
modifiedValues={formContext.formex.values ?? entity?.values}
|
|
154
|
-
formContext={formContext}
|
|
155
|
-
/>}
|
|
156
|
-
</ErrorBoundary>
|
|
157
|
-
</FormLayoutInner>;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
128
|
export function EntityEditViewInner<M extends Record<string, any>>({
|
|
161
129
|
path,
|
|
162
130
|
entityId,
|
|
@@ -220,15 +188,11 @@ export function EntityEditViewInner<M extends Record<string, any>>({
|
|
|
220
188
|
const customViewsCount = customViews?.length ?? 0;
|
|
221
189
|
const hasAdditionalViews = customViewsCount > 0 || subcollectionsCount > 0;
|
|
222
190
|
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
const selectedEntityView = resolvedEntityViews.find(e => e.key === selectedTab);
|
|
229
|
-
const selectedSecondaryForm = formContext
|
|
230
|
-
&& customViews
|
|
231
|
-
&& resolvedEntityViews.filter(e => e.includeActions).find(e => e.key === selectedTab);
|
|
191
|
+
const {
|
|
192
|
+
resolvedEntityViews,
|
|
193
|
+
selectedEntityView,
|
|
194
|
+
selectedSecondaryForm
|
|
195
|
+
} = resolvedSelectedEntityView(customViews, customizationController, selectedTab);
|
|
232
196
|
|
|
233
197
|
const actionsAtTheBottom = !largeLayout || layout === "side_panel" || selectedEntityView?.includeActions === "bottom";
|
|
234
198
|
|
|
@@ -305,7 +269,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
|
|
|
305
269
|
path,
|
|
306
270
|
entityId,
|
|
307
271
|
selectedTab: value === MAIN_TAB_VALUE ? undefined : value,
|
|
308
|
-
collection
|
|
272
|
+
collection,
|
|
309
273
|
});
|
|
310
274
|
}
|
|
311
275
|
};
|
|
@@ -141,14 +141,14 @@ export function EntitySidePanel(props: EntitySidePanelProps) {
|
|
|
141
141
|
path,
|
|
142
142
|
entityId,
|
|
143
143
|
selectedTab,
|
|
144
|
-
collection
|
|
144
|
+
collection,
|
|
145
145
|
}) => {
|
|
146
146
|
sideEntityController.replace({
|
|
147
147
|
path,
|
|
148
148
|
entityId,
|
|
149
149
|
selectedTab,
|
|
150
150
|
updateUrl: true,
|
|
151
|
-
collection
|
|
151
|
+
collection,
|
|
152
152
|
});
|
|
153
153
|
}}
|
|
154
154
|
formProps={props.formProps}
|
package/src/form/EntityForm.tsx
CHANGED
|
@@ -131,7 +131,7 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
131
131
|
entityId: entityIdProp,
|
|
132
132
|
collection,
|
|
133
133
|
path,
|
|
134
|
-
values: valuesToBeSaved
|
|
134
|
+
values: valuesToBeSaved
|
|
135
135
|
});
|
|
136
136
|
}, false, 2000);
|
|
137
137
|
|
|
@@ -222,6 +222,29 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
222
222
|
}
|
|
223
223
|
});
|
|
224
224
|
|
|
225
|
+
|
|
226
|
+
useEffect(() => {
|
|
227
|
+
|
|
228
|
+
const handleKeyDown = (e: KeyboardEvent) => {
|
|
229
|
+
const isUndo = (e.metaKey || e.ctrlKey) && !e.shiftKey && e.key.toLowerCase() === "z";
|
|
230
|
+
const isRedo =
|
|
231
|
+
((e.metaKey || e.ctrlKey) && e.shiftKey && e.key.toLowerCase() === "z") ||
|
|
232
|
+
((e.metaKey || e.ctrlKey) && !e.shiftKey && e.key.toLowerCase() === "y");
|
|
233
|
+
|
|
234
|
+
if (isUndo && formex.canUndo) {
|
|
235
|
+
e.preventDefault();
|
|
236
|
+
formex.undo();
|
|
237
|
+
} else if (isRedo && formex.canRedo) {
|
|
238
|
+
e.preventDefault();
|
|
239
|
+
formex.redo();
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
244
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
245
|
+
|
|
246
|
+
}, [formex]);
|
|
247
|
+
|
|
225
248
|
const resolvedCollection = useMemo(() => resolveCollection<M>({
|
|
226
249
|
collection,
|
|
227
250
|
path,
|
|
@@ -349,7 +372,7 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
349
372
|
path,
|
|
350
373
|
entityId,
|
|
351
374
|
values,
|
|
352
|
-
previousValues
|
|
375
|
+
previousValues
|
|
353
376
|
});
|
|
354
377
|
}
|
|
355
378
|
};
|
|
@@ -589,7 +612,7 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
589
612
|
|
|
590
613
|
const formView = <ErrorBoundary>
|
|
591
614
|
<>
|
|
592
|
-
<div className={"w-full py-2 flex flex-col items-start my-4 lg:my-6"}>
|
|
615
|
+
{!Builder && <div className={"w-full py-2 flex flex-col items-start my-4 lg:my-6"}>
|
|
593
616
|
<Typography
|
|
594
617
|
className={"py-4 flex-grow line-clamp-1 " + (collection.hideIdFromForm ? "mb-2" : "mb-0")}
|
|
595
618
|
variant={"h4"}>
|
|
@@ -601,11 +624,11 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
601
624
|
{entity?.path ?? path}/{entityId}
|
|
602
625
|
</code>
|
|
603
626
|
</Alert>}
|
|
604
|
-
</div>
|
|
627
|
+
</div>}
|
|
605
628
|
|
|
606
629
|
{children}
|
|
607
630
|
|
|
608
|
-
{!collection.hideIdFromForm &&
|
|
631
|
+
{!Builder && !collection.hideIdFromForm &&
|
|
609
632
|
<CustomIdField customId={collection.customId}
|
|
610
633
|
entityId={entityId}
|
|
611
634
|
status={status}
|
|
@@ -631,104 +654,14 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
631
654
|
onIdChange(entityId);
|
|
632
655
|
}, [entityId, onIdChange]);
|
|
633
656
|
|
|
634
|
-
return (
|
|
635
|
-
<FormLayoutInner
|
|
636
|
-
className={className}
|
|
637
|
-
id={`form_${path}`}
|
|
638
|
-
pluginActions={pluginActions}
|
|
639
|
-
forceActionsAtTheBottom={forceActionsAtTheBottom}
|
|
640
|
-
EntityFormActionsComponent={EntityFormActionsComponent}
|
|
641
|
-
formContext={formContext}
|
|
642
|
-
showDefaultActions={showDefaultActions}>
|
|
643
|
-
{formView}
|
|
644
|
-
</FormLayoutInner>
|
|
645
|
-
);
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
function getInitialEntityValues<M extends object>(
|
|
649
|
-
collection: EntityCollection,
|
|
650
|
-
path: string,
|
|
651
|
-
status: "new" | "existing" | "copy",
|
|
652
|
-
entity: Entity<M> | undefined,
|
|
653
|
-
propertyConfigs?: Record<string, PropertyConfig>
|
|
654
|
-
): Partial<EntityValues<M>> {
|
|
655
|
-
const resolvedCollection = resolveCollection({
|
|
656
|
-
collection,
|
|
657
|
-
path,
|
|
658
|
-
values: entity?.values,
|
|
659
|
-
propertyConfigs
|
|
660
|
-
});
|
|
661
|
-
const properties = resolvedCollection.properties;
|
|
662
|
-
if ((status === "existing" || status === "copy") && entity) {
|
|
663
|
-
if (!collection.alwaysApplyDefaultValues) {
|
|
664
|
-
return entity.values ?? getDefaultValuesFor(properties);
|
|
665
|
-
} else {
|
|
666
|
-
const defaultValues = getDefaultValuesFor(properties);
|
|
667
|
-
return mergeDeep(defaultValues, entity.values ?? {});
|
|
668
|
-
}
|
|
669
|
-
} else if (status === "new") {
|
|
670
|
-
return getDefaultValuesFor(properties);
|
|
671
|
-
} else {
|
|
672
|
-
console.error({
|
|
673
|
-
status,
|
|
674
|
-
entity
|
|
675
|
-
});
|
|
676
|
-
throw new Error("Form has not been initialised with the correct parameters");
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
export function yupToFormErrors(yupError: ValidationError): Record<string, any> {
|
|
681
|
-
let errors: Record<string, any> = {};
|
|
682
|
-
if (yupError.inner) {
|
|
683
|
-
if (yupError.inner.length === 0) {
|
|
684
|
-
return setIn(errors, yupError.path!, yupError.message);
|
|
685
|
-
}
|
|
686
|
-
for (const err of yupError.inner) {
|
|
687
|
-
if (!getIn(errors, err.path!)) {
|
|
688
|
-
errors = setIn(errors, err.path!, err.message);
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
return errors;
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
export function FormLayoutInner({
|
|
696
|
-
id,
|
|
697
|
-
formContext,
|
|
698
|
-
children,
|
|
699
|
-
className,
|
|
700
|
-
forceActionsAtTheBottom,
|
|
701
|
-
pluginActions,
|
|
702
|
-
EntityFormActionsComponent,
|
|
703
|
-
showDefaultActions,
|
|
704
|
-
}: {
|
|
705
|
-
id?: string,
|
|
706
|
-
formContext: FormContext,
|
|
707
|
-
children: React.ReactNode,
|
|
708
|
-
className?: string,
|
|
709
|
-
forceActionsAtTheBottom?: boolean,
|
|
710
|
-
pluginActions?: React.ReactNode[],
|
|
711
|
-
EntityFormActionsComponent: React.FC<EntityFormActionsProps>;
|
|
712
|
-
showDefaultActions?: boolean;
|
|
713
|
-
}) {
|
|
714
|
-
|
|
715
|
-
const formex = formContext.formex;
|
|
716
|
-
const collection = formContext.collection;
|
|
717
|
-
const path = formContext.path;
|
|
718
|
-
const entity = formContext.entity;
|
|
719
|
-
const savingError = formContext.savingError;
|
|
720
|
-
const status = formContext.status;
|
|
721
|
-
const openEntityMode = formContext.openEntityMode;
|
|
722
657
|
const disabled = formex.isSubmitting || (!formex.dirty && status === "existing");
|
|
723
658
|
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
if (!collection || !path) {
|
|
659
|
+
if (!resolvedCollection || !path) {
|
|
727
660
|
throw Error("INTERNAL: Collection and path must be defined in form context");
|
|
728
661
|
}
|
|
729
662
|
|
|
730
663
|
const dialogActions = <EntityFormActionsComponent
|
|
731
|
-
collection={
|
|
664
|
+
collection={resolvedCollection}
|
|
732
665
|
path={path}
|
|
733
666
|
entity={entity}
|
|
734
667
|
layout={forceActionsAtTheBottom ? "bottom" : "side"}
|
|
@@ -746,12 +679,12 @@ export function FormLayoutInner({
|
|
|
746
679
|
<form
|
|
747
680
|
onSubmit={formContext.formex.handleSubmit}
|
|
748
681
|
onReset={() => formex.resetForm({
|
|
749
|
-
values: getInitialEntityValues(collection, path, status, entity, customizationController.propertyConfigs)
|
|
682
|
+
values: getInitialEntityValues(collection, path, status, entity, customizationController.propertyConfigs) as M
|
|
750
683
|
})}
|
|
751
684
|
noValidate
|
|
752
685
|
className={cls("flex-1 flex flex-row w-full overflow-y-auto justify-center", className)}>
|
|
753
686
|
<div
|
|
754
|
-
id={
|
|
687
|
+
id={`form_${path}`}
|
|
755
688
|
className={cls("relative flex flex-row max-w-4xl lg:max-w-3xl xl:max-w-4xl 2xl:max-w-6xl w-full h-fit")}>
|
|
756
689
|
|
|
757
690
|
<div className={cls("flex flex-col w-full pt-12 pb-16 px-4 sm:px-8 md:px-10")}>
|
|
@@ -769,7 +702,8 @@ export function FormLayoutInner({
|
|
|
769
702
|
<CheckIcon size={"smallest"}/>
|
|
770
703
|
</Chip>
|
|
771
704
|
</Tooltip>}
|
|
772
|
-
|
|
705
|
+
|
|
706
|
+
{formView}
|
|
773
707
|
|
|
774
708
|
</div>
|
|
775
709
|
|
|
@@ -781,6 +715,53 @@ export function FormLayoutInner({
|
|
|
781
715
|
);
|
|
782
716
|
}
|
|
783
717
|
|
|
718
|
+
function getInitialEntityValues<M extends object>(
|
|
719
|
+
collection: EntityCollection,
|
|
720
|
+
path: string,
|
|
721
|
+
status: "new" | "existing" | "copy",
|
|
722
|
+
entity: Entity<M> | undefined,
|
|
723
|
+
propertyConfigs?: Record<string, PropertyConfig>
|
|
724
|
+
): Partial<EntityValues<M>> {
|
|
725
|
+
const resolvedCollection = resolveCollection({
|
|
726
|
+
collection,
|
|
727
|
+
path,
|
|
728
|
+
values: entity?.values,
|
|
729
|
+
propertyConfigs
|
|
730
|
+
});
|
|
731
|
+
const properties = resolvedCollection.properties;
|
|
732
|
+
if ((status === "existing" || status === "copy") && entity) {
|
|
733
|
+
if (!collection.alwaysApplyDefaultValues) {
|
|
734
|
+
return entity.values ?? getDefaultValuesFor(properties);
|
|
735
|
+
} else {
|
|
736
|
+
const defaultValues = getDefaultValuesFor(properties);
|
|
737
|
+
return mergeDeep(defaultValues, entity.values ?? {});
|
|
738
|
+
}
|
|
739
|
+
} else if (status === "new") {
|
|
740
|
+
return getDefaultValuesFor(properties);
|
|
741
|
+
} else {
|
|
742
|
+
console.error({
|
|
743
|
+
status,
|
|
744
|
+
entity
|
|
745
|
+
});
|
|
746
|
+
throw new Error("Form has not been initialised with the correct parameters");
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
export function yupToFormErrors(yupError: ValidationError): Record<string, any> {
|
|
751
|
+
let errors: Record<string, any> = {};
|
|
752
|
+
if (yupError.inner) {
|
|
753
|
+
if (yupError.inner.length === 0) {
|
|
754
|
+
return setIn(errors, yupError.path!, yupError.message);
|
|
755
|
+
}
|
|
756
|
+
for (const err of yupError.inner) {
|
|
757
|
+
if (!getIn(errors, err.path!)) {
|
|
758
|
+
errors = setIn(errors, err.path!, err.message);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
return errors;
|
|
763
|
+
}
|
|
764
|
+
|
|
784
765
|
function useOnAutoSave(autoSave: undefined | boolean, formex: FormexController<any>, lastSavedValues: any, save: (values: EntityValues<any>) => Promise<void>) {
|
|
785
766
|
if (!autoSave) return;
|
|
786
767
|
useEffect(() => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef } from "react";
|
|
2
2
|
import {
|
|
3
|
+
CustomizationController,
|
|
3
4
|
EntityCollection,
|
|
4
5
|
EntitySidePanelProps,
|
|
5
6
|
NavigationController,
|
|
@@ -10,17 +11,28 @@ import {
|
|
|
10
11
|
} from "../types";
|
|
11
12
|
import { getNavigationEntriesFromPath, NavigationViewInternal } from "../util/navigation_from_path";
|
|
12
13
|
import { useLocation } from "react-router-dom";
|
|
13
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
removeInitialAndTrailingSlashes,
|
|
16
|
+
resolveCollection,
|
|
17
|
+
resolveDefaultSelectedView,
|
|
18
|
+
resolvedSelectedEntityView
|
|
19
|
+
} from "../util";
|
|
14
20
|
import { ADDITIONAL_TAB_WIDTH, CONTAINER_FULL_WIDTH, FORM_CONTAINER_WIDTH } from "./common";
|
|
15
|
-
import { useLargeLayout } from "../hooks";
|
|
21
|
+
import { useCustomizationController, useLargeLayout } from "../hooks";
|
|
16
22
|
import { EntitySidePanel } from "../core/EntitySidePanel";
|
|
17
23
|
|
|
18
24
|
const NEW_URL_HASH = "new_side";
|
|
19
25
|
const SIDE_URL_HASH = "side";
|
|
20
26
|
|
|
21
|
-
export function getEntityViewWidth(props: EntitySidePanelProps<any>, small: boolean): string {
|
|
27
|
+
export function getEntityViewWidth(props: EntitySidePanelProps<any>, small: boolean, customizationController: CustomizationController): string {
|
|
22
28
|
if (small) return CONTAINER_FULL_WIDTH;
|
|
23
|
-
|
|
29
|
+
|
|
30
|
+
const {
|
|
31
|
+
selectedSecondaryForm
|
|
32
|
+
} = resolvedSelectedEntityView(props.collection?.entityViews, customizationController, props.selectedTab);
|
|
33
|
+
|
|
34
|
+
const shouldUseSmallLayout = !props.selectedTab || Boolean(selectedSecondaryForm);
|
|
35
|
+
|
|
24
36
|
let resolvedWidth: string | undefined;
|
|
25
37
|
if (props.width) {
|
|
26
38
|
resolvedWidth = typeof props.width === "number" ? `${props.width}px` : props.width;
|
|
@@ -28,7 +40,7 @@ export function getEntityViewWidth(props: EntitySidePanelProps<any>, small: bool
|
|
|
28
40
|
resolvedWidth = typeof props.collection.sideDialogWidth === "number" ? `${props.collection.sideDialogWidth}px` : props.collection.sideDialogWidth;
|
|
29
41
|
}
|
|
30
42
|
|
|
31
|
-
if (!
|
|
43
|
+
if (!shouldUseSmallLayout) {
|
|
32
44
|
return `calc(${ADDITIONAL_TAB_WIDTH} + ${resolvedWidth ?? FORM_CONTAINER_WIDTH})`
|
|
33
45
|
} else {
|
|
34
46
|
if (resolvedWidth) {
|
|
@@ -89,6 +101,7 @@ export const useBuildSideEntityController = (navigation: NavigationController,
|
|
|
89
101
|
|
|
90
102
|
const location = useLocation();
|
|
91
103
|
const initialised = useRef<boolean>(false);
|
|
104
|
+
const customizationController = useCustomizationController();
|
|
92
105
|
|
|
93
106
|
const smallLayout = !useLargeLayout();
|
|
94
107
|
|
|
@@ -105,9 +118,9 @@ export const useBuildSideEntityController = (navigation: NavigationController,
|
|
|
105
118
|
for (let i = 0; i < panelsFromUrl.length; i++) {
|
|
106
119
|
const props = panelsFromUrl[i];
|
|
107
120
|
if (i === 0)
|
|
108
|
-
sideDialogsController.replace(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout));
|
|
121
|
+
sideDialogsController.replace(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController));
|
|
109
122
|
else
|
|
110
|
-
sideDialogsController.open(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout))
|
|
123
|
+
sideDialogsController.open(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController))
|
|
111
124
|
}
|
|
112
125
|
}
|
|
113
126
|
initialised.current = true;
|
|
@@ -127,7 +140,7 @@ export const useBuildSideEntityController = (navigation: NavigationController,
|
|
|
127
140
|
return;
|
|
128
141
|
}
|
|
129
142
|
const lastPanel = panelsFromUrl[panelsFromUrl.length - 1];
|
|
130
|
-
const panelProps = propsToSidePanel(lastPanel, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout);
|
|
143
|
+
const panelProps = propsToSidePanel(lastPanel, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController);
|
|
131
144
|
const lastCurrentPanel = currentPanelKeys.length > 0 ? currentPanelKeys[currentPanelKeys.length - 1] : undefined;
|
|
132
145
|
if (!lastCurrentPanel || lastCurrentPanel !== panelProps.key) {
|
|
133
146
|
sideDialogsController.replace(panelProps);
|
|
@@ -140,7 +153,7 @@ export const useBuildSideEntityController = (navigation: NavigationController,
|
|
|
140
153
|
useEffect(() => {
|
|
141
154
|
const updatedSidePanels = sideDialogsController.sidePanels.map(sidePanelProps => {
|
|
142
155
|
if (sidePanelProps.additional) {
|
|
143
|
-
return propsToSidePanel(sidePanelProps.additional, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout);
|
|
156
|
+
return propsToSidePanel(sidePanelProps.additional, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController);
|
|
144
157
|
}
|
|
145
158
|
return sidePanelProps;
|
|
146
159
|
});
|
|
@@ -172,7 +185,8 @@ export const useBuildSideEntityController = (navigation: NavigationController,
|
|
|
172
185
|
},
|
|
173
186
|
navigation.buildUrlCollectionPath,
|
|
174
187
|
navigation.resolveIdsFrom,
|
|
175
|
-
smallLayout
|
|
188
|
+
smallLayout,
|
|
189
|
+
customizationController
|
|
176
190
|
));
|
|
177
191
|
|
|
178
192
|
}, [sideDialogsController, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout]);
|
|
@@ -183,7 +197,7 @@ export const useBuildSideEntityController = (navigation: NavigationController,
|
|
|
183
197
|
throw Error("If you want to copy an entity you need to provide an entityId");
|
|
184
198
|
}
|
|
185
199
|
|
|
186
|
-
sideDialogsController.replace(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout));
|
|
200
|
+
sideDialogsController.replace(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout, customizationController));
|
|
187
201
|
|
|
188
202
|
}, [navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, sideDialogsController, smallLayout]);
|
|
189
203
|
|
|
@@ -242,11 +256,11 @@ export function buildSidePanelsFromUrl(path: string, collections: EntityCollecti
|
|
|
242
256
|
return sidePanel ? [sidePanel] : [];
|
|
243
257
|
}
|
|
244
258
|
|
|
245
|
-
|
|
246
259
|
const propsToSidePanel = (props: EntitySidePanelProps,
|
|
247
260
|
buildUrlCollectionPath: (path: string) => string,
|
|
248
261
|
resolveIdsFrom: (pathWithAliases: string) => string,
|
|
249
|
-
smallLayout: boolean
|
|
262
|
+
smallLayout: boolean,
|
|
263
|
+
customizationController: CustomizationController): SideDialogPanelProps => {
|
|
250
264
|
|
|
251
265
|
const collectionPath = removeInitialAndTrailingSlashes(props.path);
|
|
252
266
|
|
|
@@ -261,7 +275,7 @@ const propsToSidePanel = (props: EntitySidePanelProps,
|
|
|
261
275
|
formProps: props.formProps
|
|
262
276
|
};
|
|
263
277
|
|
|
264
|
-
const entityViewWidth = getEntityViewWidth(props, smallLayout);
|
|
278
|
+
const entityViewWidth = getEntityViewWidth(props, smallLayout, customizationController);
|
|
265
279
|
|
|
266
280
|
return {
|
|
267
281
|
key: `${props.path}/${props.entityId}`,
|
package/src/util/resolutions.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ArrayProperty,
|
|
3
3
|
CMSType,
|
|
4
|
+
CustomizationController,
|
|
4
5
|
EntityCollection,
|
|
5
6
|
EntityCustomView,
|
|
6
7
|
EntityValues,
|
|
@@ -218,11 +219,11 @@ export function resolveProperty<T extends CMSType = CMSType, M extends Record<st
|
|
|
218
219
|
}
|
|
219
220
|
|
|
220
221
|
export function getArrayResolvedProperties<M>({
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
222
|
+
propertyKey,
|
|
223
|
+
propertyValue,
|
|
224
|
+
property,
|
|
225
|
+
...props
|
|
226
|
+
}: {
|
|
226
227
|
propertyValue: any,
|
|
227
228
|
propertyKey?: string,
|
|
228
229
|
property: ArrayProperty<any> | ResolvedArrayProperty<any>,
|
|
@@ -430,3 +431,23 @@ export function resolveEntityView(entityView: string | EntityCustomView<any>, co
|
|
|
430
431
|
return entityView;
|
|
431
432
|
}
|
|
432
433
|
}
|
|
434
|
+
|
|
435
|
+
export function resolvedSelectedEntityView<M extends Record<string, any>>(
|
|
436
|
+
customViews: (string | EntityCustomView<M>)[] | undefined,
|
|
437
|
+
customizationController: CustomizationController,
|
|
438
|
+
selectedTab?: string
|
|
439
|
+
) {
|
|
440
|
+
const resolvedEntityViews = customViews ? customViews
|
|
441
|
+
.map(e => resolveEntityView(e, customizationController.entityViews))
|
|
442
|
+
.filter(Boolean) as EntityCustomView[]
|
|
443
|
+
: [];
|
|
444
|
+
|
|
445
|
+
const selectedEntityView = resolvedEntityViews.find(e => e.key === selectedTab);
|
|
446
|
+
const selectedSecondaryForm = customViews
|
|
447
|
+
&& resolvedEntityViews.filter(e => e.includeActions).find(e => e.key === selectedTab);
|
|
448
|
+
return {
|
|
449
|
+
resolvedEntityViews,
|
|
450
|
+
selectedEntityView,
|
|
451
|
+
selectedSecondaryForm
|
|
452
|
+
};
|
|
453
|
+
}
|