@firecms/collection_editor 3.0.0-beta.10 → 3.0.0-beta.12
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/ConfigControllerProvider.d.ts +0 -9
- package/dist/index.es.js +9188 -5266
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +9180 -5259
- package/dist/index.umd.js.map +1 -1
- package/dist/types/collection_editor_controller.d.ts +0 -10
- package/dist/types/config_permissions.d.ts +2 -2
- package/dist/types/persisted_collection.d.ts +1 -1
- package/dist/ui/collection_editor/CollectionDetailsForm.d.ts +3 -1
- package/dist/ui/collection_editor/LayoutModeSwitch.d.ts +5 -0
- package/dist/useCollectionEditorPlugin.d.ts +4 -13
- package/dist/utils/collections.d.ts +1 -1
- package/package.json +22 -19
- package/src/ConfigControllerProvider.tsx +1 -10
- package/src/types/collection_editor_controller.tsx +0 -7
- package/src/types/config_permissions.ts +1 -1
- package/src/types/persisted_collection.ts +2 -3
- package/src/ui/CollectionViewHeaderAction.tsx +1 -1
- package/src/ui/HomePageEditorCollectionAction.tsx +1 -0
- package/src/ui/NewCollectionButton.tsx +1 -1
- package/src/ui/PropertyAddColumnComponent.tsx +2 -2
- package/src/ui/collection_editor/CollectionDetailsForm.tsx +26 -10
- package/src/ui/collection_editor/CollectionEditorDialog.tsx +50 -8
- package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +2 -2
- package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +3 -9
- package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +6 -5
- package/src/ui/collection_editor/EnumForm.tsx +10 -6
- package/src/ui/collection_editor/GetCodeDialog.tsx +42 -24
- package/src/ui/collection_editor/LayoutModeSwitch.tsx +54 -0
- package/src/ui/collection_editor/PropertyEditView.tsx +7 -3
- package/src/ui/collection_editor/PropertyFieldPreview.tsx +4 -4
- package/src/ui/collection_editor/PropertyTree.tsx +2 -2
- package/src/ui/collection_editor/UnsavedChangesDialog.tsx +3 -5
- package/src/ui/collection_editor/import/CollectionEditorImportDataPreview.tsx +1 -0
- package/src/ui/collection_editor/import/CollectionEditorImportMapping.tsx +2 -0
- package/src/ui/collection_editor/properties/BlockPropertyField.tsx +18 -12
- package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +4 -0
- package/src/ui/collection_editor/properties/EnumPropertyField.tsx +2 -0
- package/src/ui/collection_editor/properties/MapPropertyField.tsx +2 -1
- package/src/ui/collection_editor/properties/MarkdownPropertyField.tsx +3 -3
- package/src/ui/collection_editor/properties/ReferencePropertyField.tsx +2 -0
- package/src/ui/collection_editor/properties/StoragePropertyField.tsx +3 -3
- package/src/ui/collection_editor/properties/UrlPropertyField.tsx +1 -0
- package/src/ui/collection_editor/properties/validation/ValidationPanel.tsx +1 -1
- package/src/useCollectionEditorPlugin.tsx +6 -15
- package/src/utils/collections.ts +13 -7
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React, { useEffect } from "react";
|
|
2
2
|
import equal from "react-fast-compare"
|
|
3
3
|
|
|
4
|
-
import { ArrayContainer, EnumValueConfig, EnumValues, FieldCaption, } from "@firecms/core";
|
|
4
|
+
import { ArrayContainer, ArrayEntryParams, EnumValueConfig, EnumValues, FieldCaption, } from "@firecms/core";
|
|
5
5
|
import {
|
|
6
|
-
|
|
6
|
+
AutorenewIcon,
|
|
7
7
|
Badge,
|
|
8
8
|
Button,
|
|
9
9
|
CircularProgress,
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
Dialog,
|
|
12
12
|
DialogActions,
|
|
13
13
|
DialogContent,
|
|
14
|
+
DialogTitle,
|
|
14
15
|
IconButton,
|
|
15
16
|
ListIcon,
|
|
16
17
|
Paper,
|
|
@@ -121,7 +122,10 @@ function EnumFormFields({
|
|
|
121
122
|
const inferredValuesRef = React.useRef(new Set());
|
|
122
123
|
const inferredValues = inferredValuesRef.current;
|
|
123
124
|
|
|
124
|
-
const buildEntry = (
|
|
125
|
+
const buildEntry = ({
|
|
126
|
+
index,
|
|
127
|
+
internalId
|
|
128
|
+
}:ArrayEntryParams) => {
|
|
125
129
|
const justAdded = lastInternalIdAdded === internalId;
|
|
126
130
|
const entryError = errors?.enumValues && errors?.enumValues[index];
|
|
127
131
|
return <EnumEntry index={index}
|
|
@@ -179,7 +183,7 @@ function EnumFormFields({
|
|
|
179
183
|
variant={"text"}
|
|
180
184
|
size={"small"}
|
|
181
185
|
onClick={inferValues}>
|
|
182
|
-
{inferring ? <CircularProgress size={"
|
|
186
|
+
{inferring ? <CircularProgress size={"smallest"}/> : <AutorenewIcon/>}
|
|
183
187
|
Infer values from data
|
|
184
188
|
</Button>}
|
|
185
189
|
</div>
|
|
@@ -263,7 +267,7 @@ const EnumEntry = React.memo(
|
|
|
263
267
|
size="small"
|
|
264
268
|
autoFocus={autoFocus}
|
|
265
269
|
autoComplete="off"
|
|
266
|
-
endAdornment={inferredEntry && <
|
|
270
|
+
endAdornment={inferredEntry && <AutorenewIcon size={"small"}/>}
|
|
267
271
|
error={Boolean(entryError?.label)}/>
|
|
268
272
|
|
|
269
273
|
{!disabled &&
|
|
@@ -324,7 +328,7 @@ function EnumEntryDialog({
|
|
|
324
328
|
open={open}
|
|
325
329
|
onOpenChange={(open) => !open ? onClose() : undefined}
|
|
326
330
|
>
|
|
327
|
-
|
|
331
|
+
<DialogTitle hidden>Enum form dialog</DialogTitle>
|
|
328
332
|
<DialogContent>
|
|
329
333
|
{index !== undefined &&
|
|
330
334
|
<div>
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { EntityCollection, useSnackbarController } from "@firecms/core";
|
|
2
|
-
import { Button, ContentCopyIcon, Dialog, DialogActions, DialogContent, Typography, } from "@firecms/ui";
|
|
1
|
+
import { EntityCollection, isEmptyObject, useSnackbarController } from "@firecms/core";
|
|
2
|
+
import { Button, ContentCopyIcon, Dialog, DialogActions, DialogContent, DialogTitle, Typography, } from "@firecms/ui";
|
|
3
3
|
import React from "react";
|
|
4
4
|
import JSON5 from "json5";
|
|
5
5
|
import { Highlight, themes } from "prism-react-renderer"
|
|
6
6
|
import { camelCase } from "./utils/strings";
|
|
7
|
+
import { clone } from "@firecms/formex";
|
|
7
8
|
|
|
8
9
|
export function GetCodeDialog({
|
|
9
10
|
collection,
|
|
@@ -14,21 +15,20 @@ export function GetCodeDialog({
|
|
|
14
15
|
const snackbarController = useSnackbarController();
|
|
15
16
|
|
|
16
17
|
const code = collection
|
|
17
|
-
? "import { EntityCollection } from \"@firecms/core\";\n\nconst " + (collection?.name ? camelCase(collection.name) : "my") + "Collection:EntityCollection = " + JSON5.stringify(collectionToCode(collection), null, "\t")
|
|
18
|
+
? "import { EntityCollection } from \"@firecms/core\";\n\nconst " + (collection?.name ? camelCase(collection.name) : "my") + "Collection:EntityCollection = " + JSON5.stringify(collectionToCode({ ...collection }), null, "\t")
|
|
18
19
|
: "No collection selected";
|
|
19
20
|
return <Dialog open={open}
|
|
20
21
|
onOpenChange={onOpenChange}
|
|
21
22
|
maxWidth={"4xl"}>
|
|
23
|
+
<DialogTitle variant={"h6"}>Code for {collection.name}</DialogTitle>
|
|
22
24
|
<DialogContent>
|
|
23
|
-
|
|
24
|
-
Code for {collection.name}
|
|
25
|
-
</Typography>
|
|
25
|
+
|
|
26
26
|
<Typography variant={"body2"} className={"my-4 mb-8"}>
|
|
27
27
|
If you want to customise the collection in code, you can add this collection code to your CMS
|
|
28
28
|
app configuration.
|
|
29
29
|
More info in the <a
|
|
30
30
|
rel="noopener noreferrer"
|
|
31
|
-
href={"https://firecms.co/docs/
|
|
31
|
+
href={"https://firecms.co/docs/cloud/quickstart"}>docs</a>.
|
|
32
32
|
</Typography>
|
|
33
33
|
<Highlight
|
|
34
34
|
theme={themes.vsDark}
|
|
@@ -78,24 +78,40 @@ export function GetCodeDialog({
|
|
|
78
78
|
|
|
79
79
|
function collectionToCode(collection: EntityCollection): object {
|
|
80
80
|
|
|
81
|
-
const propertyCleanup = (
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
81
|
+
const propertyCleanup = (value: any): any => {
|
|
82
|
+
if (value === undefined || value === null) {
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
const valueCopy = clone(value);
|
|
86
|
+
if (typeof valueCopy === "function") {
|
|
87
|
+
return valueCopy;
|
|
88
|
+
}
|
|
89
|
+
if (Array.isArray(valueCopy)) {
|
|
90
|
+
return valueCopy.map((v: any) => propertyCleanup(v));
|
|
91
|
+
}
|
|
92
|
+
if (typeof valueCopy === "object") {
|
|
93
|
+
if (valueCopy === null)
|
|
94
|
+
return valueCopy;
|
|
95
|
+
Object.keys(valueCopy).forEach((key) => {
|
|
96
|
+
if (!isEmptyObject(valueCopy)) {
|
|
97
|
+
const childRes = propertyCleanup(valueCopy[key]);
|
|
98
|
+
if (childRes !== null && childRes !== undefined && childRes !== false && !isEmptyObject(childRes)) {
|
|
99
|
+
valueCopy[key] = childRes;
|
|
100
|
+
} else {
|
|
101
|
+
delete valueCopy[key];
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
delete valueCopy.fromBuilder;
|
|
106
|
+
delete valueCopy.resolved;
|
|
107
|
+
delete valueCopy.propertiesOrder;
|
|
108
|
+
delete valueCopy.propertyConfig;
|
|
109
|
+
delete valueCopy.resolvedProperties;
|
|
110
|
+
delete valueCopy.editable;
|
|
91
111
|
|
|
92
|
-
if (updatedProperty.type === "map") {
|
|
93
|
-
return {
|
|
94
|
-
...updatedProperty,
|
|
95
|
-
properties: updatedProperty.properties.map(propertyCleanup)
|
|
96
|
-
}
|
|
97
112
|
}
|
|
98
|
-
|
|
113
|
+
|
|
114
|
+
return valueCopy;
|
|
99
115
|
}
|
|
100
116
|
|
|
101
117
|
return {
|
|
@@ -111,7 +127,9 @@ function collectionToCode(collection: EntityCollection): object {
|
|
|
111
127
|
customId: collection.customId,
|
|
112
128
|
initialFilter: collection.initialFilter,
|
|
113
129
|
initialSort: collection.initialSort,
|
|
114
|
-
properties: Object.entries(
|
|
130
|
+
properties: Object.entries({
|
|
131
|
+
...(collection.properties ?? {})
|
|
132
|
+
})
|
|
115
133
|
.map(([key, value]) => ({
|
|
116
134
|
[key]: propertyCleanup(value)
|
|
117
135
|
}))
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Card, cls, SquareIcon, Tooltip, Typography, VerticalSplitIcon } from "@firecms/ui";
|
|
2
|
+
|
|
3
|
+
export function LayoutModeSwitch({
|
|
4
|
+
value,
|
|
5
|
+
onChange,
|
|
6
|
+
className
|
|
7
|
+
}: {
|
|
8
|
+
value: "side_panel" | "full_screen";
|
|
9
|
+
onChange: (value: "side_panel" | "full_screen") => void;
|
|
10
|
+
className?: string;
|
|
11
|
+
}) {
|
|
12
|
+
|
|
13
|
+
return <div className={cls(className)}>
|
|
14
|
+
<Typography variant={"label"} color={"secondary"} className={"ml-3.5"}>Document view</Typography>
|
|
15
|
+
<div className={cls("flex flex-row gap-4")}>
|
|
16
|
+
|
|
17
|
+
<Tooltip title={"Documents are open in a side panel"}>
|
|
18
|
+
<Card
|
|
19
|
+
onClick={() => onChange("side_panel")}
|
|
20
|
+
className={cls(
|
|
21
|
+
"my-2 rounded-md mx-0 p-4 focus:outline-none transition ease-in-out duration-150 flex flex-row gap-4 items-center",
|
|
22
|
+
"text-surface-700 dark:text-surface-accent-300",
|
|
23
|
+
"hover:text-primary-dark dark:hover:text-primary focus:ring-primary hover:ring-1 hover:ring-primary",
|
|
24
|
+
value === "side_panel" ? "border-primary dark:border-primary" : "border-surface-400 dark:border-surface-600",
|
|
25
|
+
)}
|
|
26
|
+
>
|
|
27
|
+
<VerticalSplitIcon/>
|
|
28
|
+
<Typography variant={"label"}>
|
|
29
|
+
Side panel
|
|
30
|
+
</Typography>
|
|
31
|
+
</Card>
|
|
32
|
+
</Tooltip>
|
|
33
|
+
|
|
34
|
+
<Tooltip title={"Documents are open full-screen"}>
|
|
35
|
+
<Card
|
|
36
|
+
onClick={() => onChange("full_screen")}
|
|
37
|
+
className={cls(
|
|
38
|
+
"my-2 rounded-md mx-0 p-4 focus:outline-none transition ease-in-out duration-150 flex flex-row gap-4 items-center",
|
|
39
|
+
"text-surface-700 dark:text-surface-accent-300",
|
|
40
|
+
"hover:text-primary-dark dark:hover:text-primary focus:ring-primary hover:ring-1 hover:ring-primary",
|
|
41
|
+
value === "full_screen" ? "border-primary dark:border-primary" : "border-surface-400 dark:border-surface-600",
|
|
42
|
+
)}
|
|
43
|
+
>
|
|
44
|
+
<SquareIcon/>
|
|
45
|
+
<Typography variant={"label"}>
|
|
46
|
+
Full screen
|
|
47
|
+
</Typography>
|
|
48
|
+
</Card>
|
|
49
|
+
</Tooltip>
|
|
50
|
+
|
|
51
|
+
</div>
|
|
52
|
+
<Typography variant={"caption"} color={"secondary"} className={"ml-3.5"}>Should documents be opened full screen or in an inline side dialog</Typography>
|
|
53
|
+
</div>
|
|
54
|
+
}
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
DEFAULT_FIELD_CONFIGS,
|
|
8
8
|
getFieldConfig,
|
|
9
9
|
getFieldId,
|
|
10
|
+
isEmptyObject,
|
|
10
11
|
isPropertyBuilder,
|
|
11
12
|
isValidRegExp,
|
|
12
13
|
mergeDeep,
|
|
@@ -31,7 +32,7 @@ import {
|
|
|
31
32
|
InfoLabel,
|
|
32
33
|
Tooltip,
|
|
33
34
|
Typography,
|
|
34
|
-
|
|
35
|
+
WarningIcon
|
|
35
36
|
} from "@firecms/ui";
|
|
36
37
|
import { EnumPropertyField } from "./properties/EnumPropertyField";
|
|
37
38
|
import { StoragePropertyField } from "./properties/StoragePropertyField";
|
|
@@ -142,6 +143,7 @@ export const PropertyForm = React.memo(
|
|
|
142
143
|
};
|
|
143
144
|
|
|
144
145
|
const formexController = useCreateFormex<PropertyWithId>({
|
|
146
|
+
debugId: "PROPERTY_FORM",
|
|
145
147
|
initialValues: property
|
|
146
148
|
? { id: propertyKey, ...property } as PropertyWithId
|
|
147
149
|
: initialValue,
|
|
@@ -274,7 +276,9 @@ export function PropertyFormDialog({
|
|
|
274
276
|
e.stopPropagation();
|
|
275
277
|
formexRef.current?.handleSubmit(e)
|
|
276
278
|
}}>
|
|
279
|
+
<DialogTitle hidden>Property edit view</DialogTitle>
|
|
277
280
|
<DialogContent>
|
|
281
|
+
|
|
278
282
|
<PropertyForm {...formProps}
|
|
279
283
|
onDismiss={onCancel}
|
|
280
284
|
onPropertyChanged={(params) => {
|
|
@@ -380,7 +384,7 @@ function PropertyEditFormFields({
|
|
|
380
384
|
}, [deferredValues, includeIdAndTitle, propertyNamespace]);
|
|
381
385
|
|
|
382
386
|
useEffect(() => {
|
|
383
|
-
if (values?.id && onError) {
|
|
387
|
+
if (values?.id && onError && !isEmptyObject(errors)) {
|
|
384
388
|
onError(values?.id, propertyNamespace, errors);
|
|
385
389
|
}
|
|
386
390
|
}, [errors, propertyNamespace, values?.id]);
|
|
@@ -771,7 +775,7 @@ export function WidgetSelectViewItem({
|
|
|
771
775
|
<div className={"flex flex-row gap-2 items-center"}>
|
|
772
776
|
{shouldWarnChangingDataType && <Tooltip
|
|
773
777
|
title={"This widget uses a different data type than the initially selected widget. This can cause errors with existing data."}>
|
|
774
|
-
<
|
|
778
|
+
<WarningIcon size="smallest" className={"w-4"}/>
|
|
775
779
|
</Tooltip>}
|
|
776
780
|
<Typography
|
|
777
781
|
color={shouldWarnChangingDataType ? "secondary" : undefined}>{propertyConfig.name}</Typography>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ErrorBoundary,
|
|
3
|
-
PropertyConfigBadge,
|
|
4
3
|
getFieldConfig,
|
|
5
4
|
isPropertyBuilder,
|
|
6
5
|
Property,
|
|
6
|
+
PropertyConfigBadge,
|
|
7
7
|
PropertyOrBuilder,
|
|
8
8
|
useCustomizationController,
|
|
9
9
|
} from "@firecms/core";
|
|
@@ -12,9 +12,9 @@ import {
|
|
|
12
12
|
cardMixin,
|
|
13
13
|
cardSelectedMixin,
|
|
14
14
|
cls,
|
|
15
|
+
DoNotDisturbOnIcon,
|
|
15
16
|
FunctionsIcon,
|
|
16
17
|
Paper,
|
|
17
|
-
RemoveCircleIcon,
|
|
18
18
|
Typography,
|
|
19
19
|
} from "@firecms/ui";
|
|
20
20
|
|
|
@@ -130,10 +130,10 @@ export function NonEditablePropertyPreview({
|
|
|
130
130
|
<div className={"relative m-4"}>
|
|
131
131
|
{propertyConfig && <PropertyConfigBadge propertyConfig={propertyConfig}/>}
|
|
132
132
|
{!propertyConfig && <div
|
|
133
|
-
className={"h-8 w-8 p-1 rounded-full shadow text-white bg-
|
|
133
|
+
className={"h-8 w-8 p-1 rounded-full shadow text-white bg-surface-500"}>
|
|
134
134
|
<FunctionsIcon color={"inherit"} size={"medium"}/>
|
|
135
135
|
</div>}
|
|
136
|
-
<
|
|
136
|
+
<DoNotDisturbOnIcon color={"disabled"} size={"small"} className={"absolute -right-2 -top-2"}/>
|
|
137
137
|
</div>
|
|
138
138
|
<Paper
|
|
139
139
|
className={cls(
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
PropertiesOrBuilders,
|
|
10
10
|
PropertyOrBuilder
|
|
11
11
|
} from "@firecms/core";
|
|
12
|
-
import {
|
|
12
|
+
import { AutorenewIcon, defaultBorderMixin, DragHandleIcon, IconButton, RemoveIcon, Tooltip } from "@firecms/ui";
|
|
13
13
|
import { NonEditablePropertyPreview, PropertyFieldPreview } from "./PropertyFieldPreview";
|
|
14
14
|
import { DragDropContext, Draggable, DraggableProvided, Droppable } from "@hello-pangea/dnd";
|
|
15
15
|
import { getFullId, getFullIdPath } from "./util";
|
|
@@ -224,7 +224,7 @@ export function PropertyTreeEntry({
|
|
|
224
224
|
<div className="absolute top-2 right-2 flex flex-row ">
|
|
225
225
|
|
|
226
226
|
{isPropertyInferred && <Tooltip title={"Inferred property"}>
|
|
227
|
-
<
|
|
227
|
+
<AutorenewIcon size="small" className={"p-2"}/>
|
|
228
228
|
</Tooltip>}
|
|
229
229
|
|
|
230
230
|
{onPropertyRemove && <Tooltip title={"Remove"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { Button, Dialog, DialogActions, DialogContent, Typography } from "@firecms/ui";
|
|
2
|
+
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Typography } from "@firecms/ui";
|
|
3
3
|
|
|
4
4
|
export interface UnsavedChangesDialogProps {
|
|
5
5
|
open: boolean;
|
|
@@ -24,11 +24,9 @@ export function UnsavedChangesDialog({
|
|
|
24
24
|
aria-labelledby="alert-dialog-title"
|
|
25
25
|
aria-describedby="alert-dialog-description"
|
|
26
26
|
>
|
|
27
|
-
<DialogContent>
|
|
28
|
-
<Typography variant={"h6"}>
|
|
29
|
-
{title ?? "Unsaved changes"}
|
|
30
|
-
</Typography>
|
|
31
27
|
|
|
28
|
+
<DialogTitle>{title ?? "Unsaved changes"}</DialogTitle>
|
|
29
|
+
<DialogContent>
|
|
32
30
|
{body && <Typography>
|
|
33
31
|
{body}
|
|
34
32
|
</Typography>}
|
|
@@ -235,9 +235,11 @@ function PropertySelect({
|
|
|
235
235
|
open={selectOpen}
|
|
236
236
|
onOpenChange={setSelectOpen}
|
|
237
237
|
invisible={true}
|
|
238
|
+
size={"large"}
|
|
238
239
|
className={"w-full"}
|
|
239
240
|
disabled={disabled}
|
|
240
241
|
error={!widget}
|
|
242
|
+
fullWidth={true}
|
|
241
243
|
value={fieldId ?? ""}
|
|
242
244
|
placeholder={"Select a property widget"}
|
|
243
245
|
position={"item-aligned"}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import React, { useState } from "react";
|
|
2
2
|
import { AddIcon, Button, Paper, Typography } from "@firecms/ui";
|
|
3
3
|
import { getIn, useFormex } from "@firecms/formex";
|
|
4
|
-
import { PropertyFormDialog } from "../PropertyEditView";
|
|
5
|
-
import {
|
|
4
|
+
import { OnPropertyChangedParams, PropertyFormDialog } from "../PropertyEditView";
|
|
5
|
+
import {
|
|
6
|
+
getFullId,
|
|
7
|
+
getFullIdPath,
|
|
8
|
+
idToPropertiesPath,
|
|
9
|
+
namespaceToPropertiesOrderPath,
|
|
10
|
+
namespaceToPropertiesPath
|
|
11
|
+
} from "../util";
|
|
6
12
|
import { PropertyTree } from "../PropertyTree";
|
|
7
|
-
import { ArrayProperty,
|
|
13
|
+
import { ArrayProperty, PropertyConfig } from "@firecms/core";
|
|
8
14
|
|
|
9
15
|
export function BlockPropertyField({
|
|
10
16
|
disabled,
|
|
@@ -31,18 +37,17 @@ export function BlockPropertyField({
|
|
|
31
37
|
|
|
32
38
|
const onPropertyChanged = ({
|
|
33
39
|
id,
|
|
40
|
+
namespace,
|
|
34
41
|
property
|
|
35
|
-
}:
|
|
42
|
+
}: OnPropertyChangedParams) => {
|
|
36
43
|
if (!id)
|
|
37
44
|
throw Error();
|
|
38
45
|
|
|
39
|
-
setFieldValue("oneOf.
|
|
40
|
-
|
|
41
|
-
[id]: property
|
|
42
|
-
}, false);
|
|
46
|
+
setFieldValue("oneOf." + getFullIdPath(id, namespace), property, false);
|
|
47
|
+
|
|
43
48
|
const currentPropertiesOrder = values.oneOf?.propertiesOrder ?? Object.keys(values.oneOf?.properties ?? {});
|
|
44
49
|
const newPropertiesOrder = currentPropertiesOrder.includes(id) ? currentPropertiesOrder : [...currentPropertiesOrder, id];
|
|
45
|
-
setFieldValue("oneOf.
|
|
50
|
+
setFieldValue("oneOf." + namespaceToPropertiesOrderPath(namespace), newPropertiesOrder, false);
|
|
46
51
|
setPropertyDialogOpen(false);
|
|
47
52
|
};
|
|
48
53
|
|
|
@@ -82,8 +87,9 @@ export function BlockPropertyField({
|
|
|
82
87
|
<>
|
|
83
88
|
<div className={"col-span-12"}>
|
|
84
89
|
<div className={"flex justify-between items-end mt-8 mb-4"}>
|
|
85
|
-
<Typography variant={"subtitle2"}>
|
|
86
|
-
block
|
|
90
|
+
<Typography variant={"subtitle2"}>
|
|
91
|
+
Properties in this block
|
|
92
|
+
</Typography>
|
|
87
93
|
{addChildButton}
|
|
88
94
|
</div>
|
|
89
95
|
<Paper className="p-2 pl-8">
|
|
@@ -104,7 +110,7 @@ export function BlockPropertyField({
|
|
|
104
110
|
? undefined
|
|
105
111
|
: onPropertyMove}/>
|
|
106
112
|
|
|
107
|
-
{!disabled &&
|
|
113
|
+
{!disabled && (values.oneOf?.propertiesOrder?.length === 0)&&
|
|
108
114
|
<div className="h-full flex items-center justify-center p-4">
|
|
109
115
|
Add the first property to this block
|
|
110
116
|
</div>}
|
|
@@ -31,8 +31,10 @@ export function DateTimePropertyField({ disabled }: {
|
|
|
31
31
|
<Select name={modePath}
|
|
32
32
|
value={modeValue ?? "date"}
|
|
33
33
|
error={Boolean(modeError)}
|
|
34
|
+
size={"large"}
|
|
34
35
|
onValueChange={(v) => setFieldValue(modePath, v)}
|
|
35
36
|
label={"Mode"}
|
|
37
|
+
fullWidth={true}
|
|
36
38
|
renderValue={(v) => {
|
|
37
39
|
switch (v) {
|
|
38
40
|
case "date_time":
|
|
@@ -54,6 +56,8 @@ export function DateTimePropertyField({ disabled }: {
|
|
|
54
56
|
<div>
|
|
55
57
|
<Select name={autoValuePath}
|
|
56
58
|
disabled={disabled}
|
|
59
|
+
size={"large"}
|
|
60
|
+
fullWidth={true}
|
|
57
61
|
value={autoValueValue ?? ""}
|
|
58
62
|
onValueChange={(v) => setFieldValue(autoValuePath, v === "none" ? null : v)}
|
|
59
63
|
renderValue={(v) => {
|
|
@@ -93,9 +93,11 @@ export function EnumPropertyField({
|
|
|
93
93
|
<Select
|
|
94
94
|
disabled={disabled}
|
|
95
95
|
position={"item-aligned"}
|
|
96
|
+
fullWidth={true}
|
|
96
97
|
onValueChange={(value: string) => {
|
|
97
98
|
setFieldValue("defaultValue", value);
|
|
98
99
|
}}
|
|
100
|
+
size={"large"}
|
|
99
101
|
label={"Default value"}
|
|
100
102
|
value={defaultValue ?? ""}>
|
|
101
103
|
{enumValues
|
|
@@ -113,7 +113,8 @@ export function MapPropertyField({ disabled, getData, allowDataInference, proper
|
|
|
113
113
|
value={values.spreadChildren ?? false}
|
|
114
114
|
/>
|
|
115
115
|
<FieldCaption>
|
|
116
|
-
Set this flag to true if you want to display the children of this group as individual columns.
|
|
116
|
+
Set this flag to true if you want to display the children of this group as individual columns. This
|
|
117
|
+
will only work for top level groups.
|
|
117
118
|
</FieldCaption>
|
|
118
119
|
</div>
|
|
119
120
|
|
|
@@ -3,7 +3,7 @@ import { StringPropertyValidation } from "./validation/StringPropertyValidation"
|
|
|
3
3
|
import { ValidationPanel } from "./validation/ValidationPanel";
|
|
4
4
|
import { Field, getIn, useFormex } from "@firecms/formex";
|
|
5
5
|
|
|
6
|
-
import { DebouncedTextField, ExpandablePanel,
|
|
6
|
+
import { CloudUploadIcon, DebouncedTextField, ExpandablePanel, TextField, Typography } from "@firecms/ui";
|
|
7
7
|
|
|
8
8
|
export function MarkdownPropertyField({
|
|
9
9
|
disabled,
|
|
@@ -54,8 +54,8 @@ export function MarkdownPropertyField({
|
|
|
54
54
|
<div className={"col-span-12"}>
|
|
55
55
|
<ExpandablePanel
|
|
56
56
|
title={
|
|
57
|
-
<div className="flex flex-row text-
|
|
58
|
-
<
|
|
57
|
+
<div className="flex flex-row text-surface-500">
|
|
58
|
+
<CloudUploadIcon/>
|
|
59
59
|
<Typography variant={"subtitle2"}
|
|
60
60
|
className="ml-2">
|
|
61
61
|
File upload config
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import {
|
|
3
3
|
Button,
|
|
4
|
+
CloudUploadIcon,
|
|
4
5
|
DebouncedTextField,
|
|
5
6
|
ExpandablePanel,
|
|
6
|
-
FileUploadIcon,
|
|
7
7
|
MultiSelect,
|
|
8
8
|
MultiSelectItem,
|
|
9
9
|
Typography
|
|
@@ -74,8 +74,8 @@ export function StoragePropertyField({
|
|
|
74
74
|
|
|
75
75
|
<ExpandablePanel
|
|
76
76
|
title={
|
|
77
|
-
<div className="flex flex-row text-
|
|
78
|
-
<
|
|
77
|
+
<div className="flex flex-row text-surface-500">
|
|
78
|
+
<CloudUploadIcon/>
|
|
79
79
|
<Typography variant={"subtitle2"}
|
|
80
80
|
className="ml-2">
|
|
81
81
|
File upload config
|
|
@@ -12,7 +12,7 @@ export function ValidationPanel({
|
|
|
12
12
|
asField={true}
|
|
13
13
|
innerClassName="p-4"
|
|
14
14
|
title={
|
|
15
|
-
<div className="flex flex-row text-
|
|
15
|
+
<div className="flex flex-row text-surface-500">
|
|
16
16
|
<RuleIcon/>
|
|
17
17
|
<Typography variant={"subtitle2"}
|
|
18
18
|
className="ml-2">
|
|
@@ -15,7 +15,7 @@ import { useCollectionEditorController } from "./useCollectionEditorController";
|
|
|
15
15
|
import { EditorCollectionActionStart } from "./ui/EditorCollectionActionStart";
|
|
16
16
|
import { NewCollectionCard } from "./ui/NewCollectionCard";
|
|
17
17
|
|
|
18
|
-
export interface CollectionConfigControllerProps<EC extends PersistedCollection = PersistedCollection,
|
|
18
|
+
export interface CollectionConfigControllerProps<EC extends PersistedCollection = PersistedCollection, USER extends User = User> {
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Firebase app where the configuration is saved.
|
|
@@ -25,7 +25,7 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
|
|
|
25
25
|
/**
|
|
26
26
|
* Define what actions can be performed on the configuration.
|
|
27
27
|
*/
|
|
28
|
-
configPermissions?: CollectionEditorPermissionsBuilder<
|
|
28
|
+
configPermissions?: CollectionEditorPermissionsBuilder<USER, EC>;
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* The words you define here will not be allowed to be used as group
|
|
@@ -47,17 +47,10 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
|
|
|
47
47
|
|
|
48
48
|
getData?: (path: string, parentPaths: string[]) => Promise<object[]>;
|
|
49
49
|
|
|
50
|
-
getUser?: (uid: string) =>
|
|
50
|
+
getUser?: (uid: string) => USER | null;
|
|
51
51
|
|
|
52
52
|
onAnalyticsEvent?: (event: string, params?: object) => void;
|
|
53
53
|
|
|
54
|
-
components?: {
|
|
55
|
-
/**
|
|
56
|
-
* Custom component to render the database field
|
|
57
|
-
*/
|
|
58
|
-
DatabaseField?: React.ComponentType<{ databaseId?: string, onDatabaseIdUpdate: (databaseId:string) => void }>;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
54
|
}
|
|
62
55
|
|
|
63
56
|
/**
|
|
@@ -71,7 +64,7 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
|
|
|
71
64
|
* @param getUser
|
|
72
65
|
* @param collectionInference
|
|
73
66
|
*/
|
|
74
|
-
export function useCollectionEditorPlugin<EC extends PersistedCollection = PersistedCollection,
|
|
67
|
+
export function useCollectionEditorPlugin<EC extends PersistedCollection = PersistedCollection, USER extends User = User>
|
|
75
68
|
({
|
|
76
69
|
collectionConfigController,
|
|
77
70
|
configPermissions,
|
|
@@ -82,8 +75,7 @@ export function useCollectionEditorPlugin<EC extends PersistedCollection = Persi
|
|
|
82
75
|
collectionInference,
|
|
83
76
|
getData,
|
|
84
77
|
onAnalyticsEvent,
|
|
85
|
-
|
|
86
|
-
}: CollectionConfigControllerProps<EC, UserType>): FireCMSPlugin<any, any, PersistedCollection> {
|
|
78
|
+
}: CollectionConfigControllerProps<EC, USER>): FireCMSPlugin<any, any, PersistedCollection> {
|
|
87
79
|
|
|
88
80
|
return {
|
|
89
81
|
key: "collection_editor",
|
|
@@ -100,7 +92,6 @@ export function useCollectionEditorPlugin<EC extends PersistedCollection = Persi
|
|
|
100
92
|
getUser,
|
|
101
93
|
getData,
|
|
102
94
|
onAnalyticsEvent,
|
|
103
|
-
components
|
|
104
95
|
}
|
|
105
96
|
},
|
|
106
97
|
homePage: {
|
|
@@ -140,7 +131,7 @@ export function IntroWidget({}: {}) {
|
|
|
140
131
|
|
|
141
132
|
return (
|
|
142
133
|
<Paper
|
|
143
|
-
className={"my-4 px-4 py-6 flex flex-col bg-white dark:bg-
|
|
134
|
+
className={"my-4 px-4 py-6 flex flex-col bg-white dark:bg-surface-accent-800 gap-2"}>
|
|
144
135
|
<Typography variant={"subtitle2"} className={"uppercase"}>No collections found</Typography>
|
|
145
136
|
<Typography>
|
|
146
137
|
Start building collections in FireCMS easily. Map them to your existing
|