@firecms/core 3.0.0-beta.7 → 3.0.0-beta.8
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/AppBar.d.ts +12 -0
- package/dist/app/Drawer.d.ts +17 -0
- package/dist/app/Scaffold.d.ts +30 -0
- package/dist/app/index.d.ts +4 -0
- package/dist/app/useApp.d.ts +16 -0
- package/dist/components/VirtualTable/VirtualTableProps.d.ts +4 -0
- package/dist/components/index.d.ts +1 -1
- package/dist/{components/FireCMSAppBar.d.ts → core/DefaultAppBar.d.ts} +2 -7
- package/dist/core/DefaultDrawer.d.ts +19 -0
- package/dist/core/EntityEditView.d.ts +17 -3
- package/dist/core/NavigationRoutes.d.ts +1 -1
- package/dist/core/index.d.ts +2 -2
- package/dist/form/PropertiesForm.d.ts +8 -0
- package/dist/form/components/FieldHelperText.d.ts +3 -3
- package/dist/form/components/StorageItemPreview.d.ts +4 -4
- package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +2 -4
- package/dist/form/index.d.ts +0 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +5595 -5574
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +5 -5
- package/dist/index.umd.js.map +1 -1
- package/dist/preview/PropertyPreviewProps.d.ts +5 -0
- package/dist/preview/components/StorageThumbnail.d.ts +2 -1
- package/dist/preview/components/UrlComponentPreview.d.ts +2 -1
- package/dist/types/auth.d.ts +1 -1
- package/dist/types/collections.d.ts +14 -0
- package/dist/types/datasource.d.ts +18 -8
- package/dist/types/fields.d.ts +31 -30
- package/dist/types/plugins.d.ts +11 -3
- package/dist/types/properties.d.ts +7 -2
- package/dist/util/icons.d.ts +2 -2
- package/dist/util/storage.d.ts +23 -2
- package/dist/util/useStorageUploadController.d.ts +1 -1
- package/package.json +13 -22
- package/src/app/AppBar.tsx +18 -0
- package/src/app/Drawer.tsx +25 -0
- package/src/{core → app}/Scaffold.tsx +61 -107
- package/src/app/index.ts +4 -0
- package/src/app/useApp.tsx +32 -0
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +7 -9
- package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +2 -1
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +7 -4
- package/src/components/VirtualTable/VirtualTable.tsx +3 -1
- package/src/components/VirtualTable/VirtualTableProps.tsx +5 -0
- package/src/components/common/useTableSearchHelper.ts +52 -12
- package/src/components/index.tsx +1 -1
- package/src/contexts/DialogsProvider.tsx +2 -2
- package/src/{components/FireCMSAppBar.tsx → core/DefaultAppBar.tsx} +26 -28
- package/src/core/DefaultDrawer.tsx +177 -0
- package/src/core/EntityEditView.tsx +669 -129
- package/src/core/EntitySidePanel.tsx +0 -1
- package/src/core/NavigationRoutes.tsx +3 -3
- package/src/core/index.tsx +2 -2
- package/src/form/PropertiesForm.tsx +81 -0
- package/src/form/PropertyFieldBinding.tsx +29 -5
- package/src/form/components/FieldHelperText.tsx +3 -3
- package/src/form/components/StorageItemPreview.tsx +19 -10
- package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +8 -5
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +5 -4
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +40 -35
- package/src/form/field_bindings/MapFieldBinding.tsx +11 -3
- package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +0 -7
- package/src/form/field_bindings/RepeatFieldBinding.tsx +10 -7
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +6 -35
- package/src/form/field_bindings/SwitchFieldBinding.tsx +1 -1
- package/src/form/index.tsx +4 -4
- package/src/form/validation.ts +1 -17
- package/src/index.ts +1 -0
- package/src/internal/useBuildDataSource.ts +12 -0
- package/src/preview/PropertyPreview.tsx +5 -2
- package/src/preview/PropertyPreviewProps.tsx +6 -0
- package/src/preview/components/ImagePreview.tsx +21 -33
- package/src/preview/components/ReferencePreview.tsx +2 -1
- package/src/preview/components/StorageThumbnail.tsx +5 -1
- package/src/preview/components/UrlComponentPreview.tsx +44 -11
- package/src/types/auth.tsx +1 -1
- package/src/types/collections.ts +14 -0
- package/src/types/customization_controller.tsx +0 -1
- package/src/types/datasource.ts +20 -16
- package/src/types/fields.tsx +33 -33
- package/src/types/plugins.tsx +12 -3
- package/src/types/properties.ts +7 -2
- package/src/util/entities.ts +4 -3
- package/src/util/objects.ts +17 -7
- package/src/util/permissions.ts +1 -0
- package/src/util/storage.ts +75 -21
- package/src/util/useStorageUploadController.tsx +21 -3
- package/dist/core/Drawer.d.ts +0 -16
- package/dist/core/Scaffold.d.ts +0 -51
- package/dist/form/EntityForm.d.ts +0 -77
- package/src/core/Drawer.tsx +0 -139
- package/src/form/EntityForm.tsx +0 -736
|
@@ -15,7 +15,7 @@ export type NavigationRoutesProps = {
|
|
|
15
15
|
*/
|
|
16
16
|
homePage?: React.ReactNode;
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
children?: React.ReactNode | React.ReactNode[]
|
|
19
19
|
|
|
20
20
|
};
|
|
21
21
|
|
|
@@ -31,7 +31,7 @@ export type NavigationRoutesProps = {
|
|
|
31
31
|
export const NavigationRoutes = React.memo<NavigationRoutesProps>(
|
|
32
32
|
function NavigationRoutes({
|
|
33
33
|
homePage = <DefaultHomePage/>,
|
|
34
|
-
|
|
34
|
+
children
|
|
35
35
|
}: NavigationRoutesProps) {
|
|
36
36
|
|
|
37
37
|
const location = useLocation();
|
|
@@ -111,7 +111,7 @@ export const NavigationRoutes = React.memo<NavigationRoutesProps>(
|
|
|
111
111
|
|
|
112
112
|
{notFoundRoute}
|
|
113
113
|
|
|
114
|
-
{
|
|
114
|
+
{children}
|
|
115
115
|
|
|
116
116
|
</Routes>
|
|
117
117
|
);
|
package/src/core/index.tsx
CHANGED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { FormContext, PropertiesOrBuilders, PropertyFieldBindingProps } from "../types";
|
|
2
|
+
import { Tooltip } from "@firecms/ui";
|
|
3
|
+
import { PropertyIdCopyTooltipContent } from "../components/PropertyIdCopyTooltipContent";
|
|
4
|
+
import { PropertyFieldBinding } from "./PropertyFieldBinding";
|
|
5
|
+
import { ErrorBoundary } from "../components";
|
|
6
|
+
import { isHidden, isReadOnly, resolveProperties } from "../util";
|
|
7
|
+
import { FormexController } from "@firecms/formex";
|
|
8
|
+
|
|
9
|
+
export type PropertiesFormProps<M extends Record<string, any> = Record<string, any>> = {
|
|
10
|
+
properties: PropertiesOrBuilders<M>;
|
|
11
|
+
propertiesOrder?: string[];
|
|
12
|
+
formex: FormexController<M>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function PropertiesForm<M extends Record<string, any> = Record<string, any>>({
|
|
16
|
+
properties,
|
|
17
|
+
propertiesOrder,
|
|
18
|
+
formex
|
|
19
|
+
}: PropertiesFormProps<M>) {
|
|
20
|
+
|
|
21
|
+
const resolvedProperties = resolveProperties({ properties });
|
|
22
|
+
|
|
23
|
+
const formContext: FormContext<M> = {
|
|
24
|
+
// @ts-ignore
|
|
25
|
+
setFieldValue: useCallback(formex.setFieldValue, []),
|
|
26
|
+
values: formex.values ?? {},
|
|
27
|
+
// @ts-ignore
|
|
28
|
+
save: useCallback(() => {
|
|
29
|
+
throw new Error("Not implemented. You currently can't call save from a custom field, within a PropertiesForm (it works in standard Entity forms)");
|
|
30
|
+
}, []),
|
|
31
|
+
formex
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const formFields = (
|
|
35
|
+
<div className={"flex flex-col gap-8"}>
|
|
36
|
+
{(propertiesOrder ?? Object.keys(resolvedProperties))
|
|
37
|
+
.map((key) => {
|
|
38
|
+
|
|
39
|
+
const property = resolvedProperties[key];
|
|
40
|
+
if (!property) {
|
|
41
|
+
console.warn(`Property ${key} not found in collection PropertiesForm`);
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const disabled = formex.isSubmitting || isReadOnly(property) || Boolean(property.disabled);
|
|
46
|
+
const hidden = isHidden(property);
|
|
47
|
+
if (hidden) return null;
|
|
48
|
+
const cmsFormFieldProps: PropertyFieldBindingProps<any, M> = {
|
|
49
|
+
propertyKey: key,
|
|
50
|
+
disabled,
|
|
51
|
+
property,
|
|
52
|
+
includeDescription: property.description || property.longDescription,
|
|
53
|
+
context: formContext,
|
|
54
|
+
tableMode: false,
|
|
55
|
+
partOfArray: false,
|
|
56
|
+
partOfBlock: false,
|
|
57
|
+
autoFocus: false
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<div id={`form_field_${key}`}
|
|
62
|
+
key={`field_${key}`}>
|
|
63
|
+
<ErrorBoundary>
|
|
64
|
+
<Tooltip title={<PropertyIdCopyTooltipContent propertyId={key}/>}
|
|
65
|
+
delayDuration={800}
|
|
66
|
+
side={"left"}
|
|
67
|
+
align={"start"}
|
|
68
|
+
sideOffset={16}>
|
|
69
|
+
<PropertyFieldBinding {...cmsFormFieldProps}/>
|
|
70
|
+
</Tooltip>
|
|
71
|
+
</ErrorBoundary>
|
|
72
|
+
</div>
|
|
73
|
+
);
|
|
74
|
+
})
|
|
75
|
+
.filter(Boolean)}
|
|
76
|
+
|
|
77
|
+
</div>
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
return <div></div>
|
|
81
|
+
}
|
|
@@ -85,6 +85,7 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Rec
|
|
|
85
85
|
|
|
86
86
|
return (
|
|
87
87
|
<Field
|
|
88
|
+
key={propertyKey}
|
|
88
89
|
name={propertyKey}
|
|
89
90
|
>
|
|
90
91
|
{(fieldProps) => {
|
|
@@ -110,7 +111,12 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Rec
|
|
|
110
111
|
} else {
|
|
111
112
|
const propertyConfig = getFieldConfig(resolvedProperty, customizationController.propertyConfigs);
|
|
112
113
|
if (!propertyConfig) {
|
|
113
|
-
console.log("INTERNAL: Could not find field config for property", {
|
|
114
|
+
console.log("INTERNAL: Could not find field config for property", {
|
|
115
|
+
propertyKey,
|
|
116
|
+
resolvedProperty,
|
|
117
|
+
fields: customizationController.propertyConfigs,
|
|
118
|
+
propertyConfig
|
|
119
|
+
});
|
|
114
120
|
throw new Error(`INTERNAL: Could not find field config for property ${propertyKey}`);
|
|
115
121
|
}
|
|
116
122
|
const configProperty = resolveProperty({
|
|
@@ -194,7 +200,14 @@ function FieldInternal<T extends CMSType, CustomProps, M extends Record<string,
|
|
|
194
200
|
(fieldProps.form.submitCount > 0 || property.validation?.unique) &&
|
|
195
201
|
(!Array.isArray(error) || !!error.filter((e: any) => !!e).length);
|
|
196
202
|
|
|
197
|
-
const WrappedComponent: ComponentType<FieldProps<T, any, M>> | null = useWrappedComponent(
|
|
203
|
+
const WrappedComponent: ComponentType<FieldProps<T, any, M>> | null = useWrappedComponent({
|
|
204
|
+
path: context.path,
|
|
205
|
+
collection: context.collection,
|
|
206
|
+
propertyKey: propertyKey,
|
|
207
|
+
property: property,
|
|
208
|
+
Component: Component,
|
|
209
|
+
plugins: plugins
|
|
210
|
+
});
|
|
198
211
|
const UsedComponent: ComponentType<FieldProps<T>> = WrappedComponent ?? Component;
|
|
199
212
|
|
|
200
213
|
const isSubmitting = fieldProps.form.isSubmitting;
|
|
@@ -264,13 +277,24 @@ const shouldPropertyReRender = (property: PropertyOrBuilder | ResolvedProperty,
|
|
|
264
277
|
}
|
|
265
278
|
}
|
|
266
279
|
|
|
267
|
-
|
|
268
|
-
path
|
|
269
|
-
collection
|
|
280
|
+
interface UseWrappedComponentParams<T extends CMSType = CMSType, M extends Record<string, any> = any> {
|
|
281
|
+
path?: string,
|
|
282
|
+
collection?: EntityCollection<M>,
|
|
270
283
|
propertyKey: string,
|
|
271
284
|
property: ResolvedProperty<T>,
|
|
272
285
|
Component: ComponentType<FieldProps<T, any, M>>,
|
|
273
286
|
plugins?: FireCMSPlugin[]
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function useWrappedComponent<T extends CMSType = CMSType, M extends Record<string, any> = any>(
|
|
290
|
+
{
|
|
291
|
+
path,
|
|
292
|
+
collection,
|
|
293
|
+
propertyKey,
|
|
294
|
+
property,
|
|
295
|
+
Component,
|
|
296
|
+
plugins
|
|
297
|
+
}: UseWrappedComponentParams<T, M>
|
|
274
298
|
): ComponentType<FieldProps<T, any, M>> | null {
|
|
275
299
|
|
|
276
300
|
const wrapperRef = useRef<ComponentType<FieldProps<T, any, M>> | null>((() => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ResolvedProperty } from "../../types";
|
|
1
|
+
import { Property, ResolvedProperty } from "../../types";
|
|
2
2
|
import { IconButton, InfoIcon, Tooltip, Typography } from "@firecms/ui";
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -13,8 +13,8 @@ export function FieldHelperText({
|
|
|
13
13
|
disabled
|
|
14
14
|
}: {
|
|
15
15
|
error?: string,
|
|
16
|
-
showError
|
|
17
|
-
property: ResolvedProperty,
|
|
16
|
+
showError?: boolean,
|
|
17
|
+
property: ResolvedProperty | Property,
|
|
18
18
|
includeDescription?: boolean,
|
|
19
19
|
disabled?: boolean,
|
|
20
20
|
}
|
|
@@ -1,39 +1,40 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { ResolvedStringProperty } from "../../types";
|
|
4
4
|
import { PreviewSize, PropertyPreview } from "../../preview";
|
|
5
5
|
|
|
6
|
-
import { cls, IconButton, paperMixin, RemoveIcon, Tooltip } from "@firecms/ui";
|
|
6
|
+
import { cls, DescriptionIcon, IconButton, paperMixin, RemoveIcon, Tooltip } from "@firecms/ui";
|
|
7
7
|
import { ErrorBoundary } from "../../components";
|
|
8
8
|
|
|
9
9
|
interface StorageItemPreviewProps {
|
|
10
10
|
name: string;
|
|
11
11
|
property: ResolvedStringProperty;
|
|
12
12
|
value: string,
|
|
13
|
-
entity: Entity<any>,
|
|
14
13
|
onRemove: (value: string) => void;
|
|
15
14
|
size: PreviewSize;
|
|
16
15
|
disabled: boolean;
|
|
17
|
-
|
|
16
|
+
placeholder?: boolean;
|
|
17
|
+
className?: string;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export function StorageItemPreview({
|
|
21
21
|
name,
|
|
22
22
|
property,
|
|
23
23
|
value,
|
|
24
|
-
entity,
|
|
25
24
|
onRemove,
|
|
26
25
|
disabled,
|
|
27
26
|
size,
|
|
28
|
-
|
|
27
|
+
placeholder,
|
|
28
|
+
className
|
|
29
29
|
}: StorageItemPreviewProps) {
|
|
30
30
|
|
|
31
31
|
return (
|
|
32
32
|
<div className={cls(paperMixin,
|
|
33
33
|
"relative m-4 border-box flex items-center justify-center",
|
|
34
|
-
size === "medium" ? "min-w-[220px] min-h-[220px] max-w-[220px]" : "min-w-[118px] min-h-[118px] max-w-[118px]"
|
|
34
|
+
size === "medium" ? "min-w-[220px] min-h-[220px] max-w-[220px]" : "min-w-[118px] min-h-[118px] max-w-[118px]",
|
|
35
|
+
className)}>
|
|
35
36
|
|
|
36
|
-
{!disabled &&
|
|
37
|
+
{!placeholder && !disabled &&
|
|
37
38
|
<div
|
|
38
39
|
className="absolute rounded-full -top-2 -right-2 z-10 bg-white dark:bg-gray-900">
|
|
39
40
|
|
|
@@ -51,16 +52,24 @@ export function StorageItemPreview({
|
|
|
51
52
|
</div>
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
{value &&
|
|
55
|
+
{!placeholder && value &&
|
|
55
56
|
<ErrorBoundary>
|
|
56
57
|
<PropertyPreview propertyKey={name}
|
|
57
58
|
value={value}
|
|
58
59
|
property={property}
|
|
59
|
-
|
|
60
|
+
interactive={false}
|
|
60
61
|
size={size}/>
|
|
61
62
|
</ErrorBoundary>
|
|
62
63
|
}
|
|
63
64
|
|
|
65
|
+
{placeholder &&
|
|
66
|
+
<div
|
|
67
|
+
onClick={(e) => e.stopPropagation()}
|
|
68
|
+
className="flex flex-col items-center justify-center w-full h-full">
|
|
69
|
+
<DescriptionIcon className="text-gray-700 dark:text-gray-300"/>
|
|
70
|
+
</div>
|
|
71
|
+
}
|
|
72
|
+
|
|
64
73
|
|
|
65
74
|
</div>
|
|
66
75
|
);
|
|
@@ -2,7 +2,7 @@ import React from "react";
|
|
|
2
2
|
import { FieldProps } from "../../types";
|
|
3
3
|
import { FieldHelperText, LabelWithIcon } from "../components";
|
|
4
4
|
import { PropertyFieldBinding } from "../PropertyFieldBinding";
|
|
5
|
-
import { ExpandablePanel } from "@firecms/ui";
|
|
5
|
+
import { ExpandablePanel, Typography } from "@firecms/ui";
|
|
6
6
|
import { getIconForProperty } from "../../util";
|
|
7
7
|
import { useClearRestoreValue } from "../useClearRestoreValue";
|
|
8
8
|
|
|
@@ -39,10 +39,13 @@ export function ArrayCustomShapedFieldBinding<T extends Array<any>>({
|
|
|
39
39
|
setValue
|
|
40
40
|
});
|
|
41
41
|
|
|
42
|
-
const title =
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
const title = (<>
|
|
43
|
+
<LabelWithIcon icon={getIconForProperty(property, "small")}
|
|
44
|
+
required={property.validation?.required}
|
|
45
|
+
title={property.name}
|
|
46
|
+
className={"flex-grow text-text-secondary dark:text-text-secondary-dark"}/>
|
|
47
|
+
{Array.isArray(value) && <Typography variant={"caption"} className={"px-4"}>({value.length})</Typography>}
|
|
48
|
+
</>);
|
|
46
49
|
|
|
47
50
|
const body = property.resolvedProperties.map((childProperty, index) => {
|
|
48
51
|
const fieldProps = {
|
|
@@ -6,7 +6,7 @@ import { ErrorView } from "../../components";
|
|
|
6
6
|
import { getIconForProperty, getReferenceFrom } from "../../util";
|
|
7
7
|
|
|
8
8
|
import { useNavigationController, useReferenceDialog } from "../../hooks";
|
|
9
|
-
import { Button, cls, ExpandablePanel, fieldBackgroundMixin } from "@firecms/ui";
|
|
9
|
+
import { Button, cls, ExpandablePanel, fieldBackgroundMixin, Typography } from "@firecms/ui";
|
|
10
10
|
import { useClearRestoreValue } from "../useClearRestoreValue";
|
|
11
11
|
|
|
12
12
|
type ArrayOfReferencesFieldProps = FieldProps<EntityReference[]>;
|
|
@@ -94,12 +94,13 @@ export function ArrayOfReferencesFieldBinding({
|
|
|
94
94
|
);
|
|
95
95
|
}, [ofProperty.path, ofProperty.previewProperties, value]);
|
|
96
96
|
|
|
97
|
-
const title = (
|
|
97
|
+
const title = (<>
|
|
98
98
|
<LabelWithIcon icon={getIconForProperty(property, "small")}
|
|
99
99
|
required={property.validation?.required}
|
|
100
100
|
title={property.name}
|
|
101
|
-
className={"text-text-secondary dark:text-text-secondary-dark"}/>
|
|
102
|
-
|
|
101
|
+
className={"flex-grow text-text-secondary dark:text-text-secondary-dark"}/>
|
|
102
|
+
{Array.isArray(value) && <Typography variant={"caption"} className={"px-4"}>({value.length})</Typography>}
|
|
103
|
+
</>);
|
|
103
104
|
|
|
104
105
|
const body = <>
|
|
105
106
|
{!collection && <ErrorView
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
} from "@firecms/ui";
|
|
22
22
|
import { getDefaultValueForDataType, getIconForProperty } from "../../util";
|
|
23
23
|
import { useCustomizationController } from "../../hooks";
|
|
24
|
+
import { getIn } from "@firecms/formex";
|
|
24
25
|
|
|
25
26
|
type MapEditViewRowState = [number, {
|
|
26
27
|
key: string,
|
|
@@ -52,9 +53,13 @@ export function KeyValueFieldBinding({
|
|
|
52
53
|
if (!property.keyValue) {
|
|
53
54
|
throw Error(`Your property ${propertyKey} needs to have the 'keyValue' prop in order to use this field binding`);
|
|
54
55
|
}
|
|
56
|
+
|
|
57
|
+
const initialValues = getIn(context.formex.initialValues, propertyKey);
|
|
58
|
+
|
|
55
59
|
const mapFormView = <MapEditView value={value}
|
|
56
60
|
setValue={setValue}
|
|
57
61
|
disabled={disabled}
|
|
62
|
+
initialValue={initialValues}
|
|
58
63
|
fieldName={property.name ?? propertyKey}/>;
|
|
59
64
|
|
|
60
65
|
const title = <LabelWithIcon
|
|
@@ -84,6 +89,7 @@ export function KeyValueFieldBinding({
|
|
|
84
89
|
|
|
85
90
|
interface MapEditViewParams<T extends Record<string, any>> {
|
|
86
91
|
value?: T;
|
|
92
|
+
initialValue?: T;
|
|
87
93
|
setValue: (value: (T | null)) => void;
|
|
88
94
|
fieldName?: string,
|
|
89
95
|
disabled?: boolean
|
|
@@ -91,14 +97,15 @@ interface MapEditViewParams<T extends Record<string, any>> {
|
|
|
91
97
|
|
|
92
98
|
function MapEditView<T extends Record<string, any>>({
|
|
93
99
|
value,
|
|
100
|
+
initialValue,
|
|
94
101
|
setValue,
|
|
95
102
|
fieldName,
|
|
96
103
|
disabled
|
|
97
104
|
}: MapEditViewParams<T>) {
|
|
98
105
|
const [internalState, setInternalState] = React.useState<MapEditViewRowState[]>(
|
|
99
|
-
Object.keys(
|
|
106
|
+
Object.keys(initialValue ?? {}).map((key) => [getRandomId(), {
|
|
100
107
|
key,
|
|
101
|
-
dataType: getDataType(
|
|
108
|
+
dataType: getDataType(initialValue?.[key]) ?? "string"
|
|
102
109
|
}])
|
|
103
110
|
);
|
|
104
111
|
|
|
@@ -121,8 +128,6 @@ function MapEditView<T extends Record<string, any>>({
|
|
|
121
128
|
setInternalState(newRowIds);
|
|
122
129
|
}, [value]);
|
|
123
130
|
|
|
124
|
-
const originalValue = React.useRef<T>(value ?? {} as T);
|
|
125
|
-
|
|
126
131
|
const updateDataType = (rowId: number, dataType: DataType) => {
|
|
127
132
|
if (!rowId) {
|
|
128
133
|
console.warn("No key selected for data type update");
|
|
@@ -168,7 +173,7 @@ function MapEditView<T extends Record<string, any>>({
|
|
|
168
173
|
}
|
|
169
174
|
|
|
170
175
|
const newValue = { ...(value ?? {}) } as T;
|
|
171
|
-
if (typeof
|
|
176
|
+
if (typeof initialValue === "object" && fieldKey in initialValue) {
|
|
172
177
|
// @ts-ignore
|
|
173
178
|
newValue[fieldKey] = undefined; // set to undefined to remove from the object, the datasource will remove it from the backend
|
|
174
179
|
} else {
|
|
@@ -186,7 +191,7 @@ function MapEditView<T extends Record<string, any>>({
|
|
|
186
191
|
value={value ?? {} as T}
|
|
187
192
|
onDeleteClick={() => {
|
|
188
193
|
const newValue = { ...(value ?? {}) as T };
|
|
189
|
-
if (
|
|
194
|
+
if (initialValue && fieldKey in initialValue) {
|
|
190
195
|
// @ts-ignore
|
|
191
196
|
newValue[fieldKey] = undefined;
|
|
192
197
|
} else {
|
|
@@ -305,7 +310,7 @@ function MapKeyValueRow<T extends Record<string, any>>({
|
|
|
305
310
|
}}/>;
|
|
306
311
|
} else if (dataType === "boolean") {
|
|
307
312
|
return <BooleanSwitchWithLabel value={entryValue}
|
|
308
|
-
size={"
|
|
313
|
+
size={"medium"}
|
|
309
314
|
position={"start"}
|
|
310
315
|
disabled={disabled || !fieldKey}
|
|
311
316
|
onValueChange={(newValue) => {
|
|
@@ -375,7 +380,7 @@ function MapKeyValueRow<T extends Record<string, any>>({
|
|
|
375
380
|
<Typography key={rowId.toString()}
|
|
376
381
|
component={"div"}
|
|
377
382
|
className="font-mono flex flex-row gap-1">
|
|
378
|
-
<div className="w-[
|
|
383
|
+
<div className="w-[300px] max-w-[30%]">
|
|
379
384
|
<TextField
|
|
380
385
|
value={fieldKey}
|
|
381
386
|
placeholder={"key"}
|
|
@@ -389,32 +394,32 @@ function MapKeyValueRow<T extends Record<string, any>>({
|
|
|
389
394
|
<div className="flex-grow">
|
|
390
395
|
{(dataType !== "map" && dataType !== "array") && buildInput(entryValue, fieldKey, dataType)}
|
|
391
396
|
</div>
|
|
392
|
-
<
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
</
|
|
397
|
+
<div className={"flex flex-col"}>
|
|
398
|
+
<Menu
|
|
399
|
+
trigger={<IconButton size={"smallest"}>
|
|
400
|
+
<ArrowDropDownIcon size={"small"}/>
|
|
401
|
+
</IconButton>}
|
|
402
|
+
>
|
|
403
|
+
<MenuItem dense
|
|
404
|
+
onClick={() => doUpdateDataType("string")}>string</MenuItem>
|
|
405
|
+
<MenuItem dense
|
|
406
|
+
onClick={() => doUpdateDataType("number")}>number</MenuItem>
|
|
407
|
+
<MenuItem dense
|
|
408
|
+
onClick={() => doUpdateDataType("boolean")}>boolean</MenuItem>
|
|
409
|
+
<MenuItem dense
|
|
410
|
+
onClick={() => doUpdateDataType("date")}>date</MenuItem>
|
|
411
|
+
<MenuItem dense
|
|
412
|
+
onClick={() => doUpdateDataType("map")}>map</MenuItem>
|
|
413
|
+
<MenuItem dense
|
|
414
|
+
onClick={() => doUpdateDataType("array")}>array</MenuItem>
|
|
415
|
+
</Menu>
|
|
416
|
+
|
|
417
|
+
<IconButton aria-label="delete"
|
|
418
|
+
size={"smallest"}
|
|
419
|
+
onClick={onDeleteClick}>
|
|
420
|
+
<RemoveIcon size={"smallest"}/>
|
|
421
|
+
</IconButton>
|
|
422
|
+
</div>
|
|
418
423
|
</Typography>
|
|
419
424
|
|
|
420
425
|
{(dataType === "map" || dataType === "array") && buildInput(entryValue, fieldKey, dataType)}
|
|
@@ -472,7 +477,7 @@ function ArrayKeyValueRow<T>({
|
|
|
472
477
|
}}/>;
|
|
473
478
|
} else if (dataType === "boolean") {
|
|
474
479
|
return <BooleanSwitchWithLabel value={entryValue}
|
|
475
|
-
size={"
|
|
480
|
+
size={"medium"}
|
|
476
481
|
position={"start"}
|
|
477
482
|
onValueChange={(v) => {
|
|
478
483
|
setValue(v as T);
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
CMSType,
|
|
4
|
+
FieldProps,
|
|
5
|
+
FormContext,
|
|
6
|
+
MapProperty,
|
|
7
|
+
Properties,
|
|
8
|
+
ResolvedProperties,
|
|
9
|
+
ResolvedProperty
|
|
10
|
+
} from "../../types";
|
|
3
11
|
|
|
4
12
|
import { ErrorBoundary } from "../../components";
|
|
5
13
|
import { getIconForProperty, isHidden, pick } from "../../util";
|
|
@@ -21,7 +29,6 @@ export function MapFieldBinding({
|
|
|
21
29
|
error,
|
|
22
30
|
disabled,
|
|
23
31
|
property,
|
|
24
|
-
setValue,
|
|
25
32
|
partOfBlock,
|
|
26
33
|
tableMode,
|
|
27
34
|
includeDescription,
|
|
@@ -68,6 +75,7 @@ export function MapFieldBinding({
|
|
|
68
75
|
partOfBlock: false,
|
|
69
76
|
autoFocus: autoFocus && index === 0
|
|
70
77
|
};
|
|
78
|
+
|
|
71
79
|
return (
|
|
72
80
|
<div key={`map-${propertyKey}-${index}`}>
|
|
73
81
|
<ErrorBoundary>
|
|
@@ -101,7 +109,7 @@ export function MapFieldBinding({
|
|
|
101
109
|
{(tableMode || partOfBlock) && mapFormView}
|
|
102
110
|
|
|
103
111
|
<FieldHelperText includeDescription={includeDescription}
|
|
104
|
-
showError={showError}
|
|
112
|
+
showError={showError ?? false}
|
|
105
113
|
error={error ? (typeof error === "string" ? error : "A property of this map has an error") : undefined}
|
|
106
114
|
disabled={disabled}
|
|
107
115
|
property={property}/>
|
|
@@ -30,12 +30,6 @@ export function ReadOnlyFieldBinding({
|
|
|
30
30
|
if (!context.entityId)
|
|
31
31
|
throw new Error("ReadOnlyFieldBinding: Entity id is null");
|
|
32
32
|
|
|
33
|
-
const entity: Entity<any> = {
|
|
34
|
-
id: context.entityId!,
|
|
35
|
-
values: context.values,
|
|
36
|
-
path: context.path
|
|
37
|
-
};
|
|
38
|
-
|
|
39
33
|
return (
|
|
40
34
|
|
|
41
35
|
<>
|
|
@@ -53,7 +47,6 @@ export function ReadOnlyFieldBinding({
|
|
|
53
47
|
<PropertyPreview propertyKey={propertyKey}
|
|
54
48
|
value={value}
|
|
55
49
|
property={property}
|
|
56
|
-
// entity={entity}
|
|
57
50
|
size={"medium"}/>
|
|
58
51
|
</ErrorBoundary>
|
|
59
52
|
|
|
@@ -2,9 +2,9 @@ import React, { useState } from "react";
|
|
|
2
2
|
import { CMSType, FieldProps, ResolvedProperty } from "../../types";
|
|
3
3
|
import { FieldHelperText, FormikArrayContainer, LabelWithIcon } from "../components";
|
|
4
4
|
import { ErrorBoundary } from "../../components";
|
|
5
|
-
import { getIconForProperty } from "../../util";
|
|
5
|
+
import { getDefaultValueFor, getIconForProperty } from "../../util";
|
|
6
6
|
import { PropertyFieldBinding } from "../PropertyFieldBinding";
|
|
7
|
-
import { ExpandablePanel } from "@firecms/ui";
|
|
7
|
+
import { ExpandablePanel, Typography } from "@firecms/ui";
|
|
8
8
|
import { useClearRestoreValue } from "../useClearRestoreValue";
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -75,12 +75,15 @@ export function RepeatFieldBinding<T extends Array<any>>({
|
|
|
75
75
|
onInternalIdAdded={setLastAddedId}
|
|
76
76
|
disabled={isSubmitting || Boolean(property.disabled)}
|
|
77
77
|
includeAddButton={!property.disabled}
|
|
78
|
-
newDefaultEntry={property.of
|
|
78
|
+
newDefaultEntry={getDefaultValueFor(property.of)}/>;
|
|
79
79
|
|
|
80
|
-
const title = (
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
const title = (<>
|
|
81
|
+
<LabelWithIcon icon={getIconForProperty(property, "small")}
|
|
82
|
+
required={property.validation?.required}
|
|
83
|
+
title={property.name}
|
|
84
|
+
className={"flex-grow text-text-secondary dark:text-text-secondary-dark"}/>
|
|
85
|
+
{Array.isArray(value) && <Typography variant={"caption"} className={"px-4"}>({value.length})</Typography>}
|
|
86
|
+
</>);
|
|
84
87
|
|
|
85
88
|
return (
|
|
86
89
|
|