@firecms/collection_editor 3.0.0-canary.102 → 3.0.0-canary.104
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 +9 -0
- package/dist/index.es.js +177 -24
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +176 -23
- package/dist/index.umd.js.map +1 -1
- package/dist/types/collection_editor_controller.d.ts +10 -0
- package/dist/ui/collection_editor/properties/MarkdownPropertyField.d.ts +4 -0
- package/dist/ui/collection_editor/properties/StringPropertyField.d.ts +1 -1
- package/dist/useCollectionEditorPlugin.d.ts +10 -1
- package/package.json +8 -8
- package/src/ConfigControllerProvider.tsx +11 -2
- package/src/types/collection_editor_controller.tsx +8 -0
- package/src/ui/collection_editor/CollectionDetailsForm.tsx +31 -2
- package/src/ui/collection_editor/PropertyEditView.tsx +10 -3
- package/src/ui/collection_editor/PropertySelectItem.tsx +1 -1
- package/src/ui/collection_editor/properties/MarkdownPropertyField.tsx +139 -0
- package/src/ui/collection_editor/properties/StringPropertyField.tsx +1 -10
- package/src/useCollectionEditorPlugin.tsx +11 -2
|
@@ -33,5 +33,14 @@ export interface ConfigControllerProviderProps {
|
|
|
33
33
|
getUser?: (uid: string) => User | null;
|
|
34
34
|
getData?: (path: string, parentPaths: string[]) => Promise<object[]>;
|
|
35
35
|
onAnalyticsEvent?: (event: string, params?: object) => void;
|
|
36
|
+
components?: {
|
|
37
|
+
/**
|
|
38
|
+
* Custom component to render the database field
|
|
39
|
+
*/
|
|
40
|
+
DatabaseField?: React.ComponentType<{
|
|
41
|
+
databaseId?: string;
|
|
42
|
+
onDatabaseIdUpdate: (databaseId: string) => void;
|
|
43
|
+
}>;
|
|
44
|
+
};
|
|
36
45
|
}
|
|
37
46
|
export declare const ConfigControllerProvider: React.NamedExoticComponent<React.PropsWithChildren<ConfigControllerProviderProps>>;
|
package/dist/index.es.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { FieldCaption, SearchIconsView, toSnakeCase, singular, IconForView, ArrayContainer, serializeRegExp, useSnackbarController, resolveEnumValues, isPropertyBuilder, useCustomizationController, getFieldConfig, ErrorBoundary, PropertyConfigBadge, unslugify, useNavigationController, mergeDeep, DEFAULT_FIELD_CONFIGS, isValidRegExp, getFieldId, DeleteConfirmationDialog, useLargeLayout, makePropertiesEditable, resolveEntityView, useSelectionController, CircularProgressCenter, EntityCollectionTable, slugify, useAuthController, randomString, removeUndefined, ErrorView, removeInitialAndTrailingSlashes, getDefaultPropertiesOrder, joinCollectionLists } from "@firecms/core";
|
|
3
3
|
import * as React from "react";
|
|
4
|
-
import React__default, { useState, useEffect, useMemo, useRef, useDeferredValue, useCallback
|
|
4
|
+
import React__default, { useContext, useState, useEffect, useMemo, useRef, useDeferredValue, useCallback } from "react";
|
|
5
5
|
import equal from "react-fast-compare";
|
|
6
6
|
import { useAutoComplete, Container, Typography, Tooltip, IconButton, Chip, TextField, cls, DebouncedTextField, Autocomplete, AutocompleteItem, ExpandablePanel, SettingsIcon, ClearIcon, Select, SelectItem, BooleanSwitchWithLabel, Dialog, AutoAwesomeIcon, Badge, ListIcon, Button, CircularProgress, Paper, DialogContent, DialogActions, RuleIcon, FileUploadIcon, MultiSelect, MultiSelectItem, Checkbox, cardMixin, cardClickableMixin, cardSelectedMixin, FunctionsIcon, RemoveCircleIcon, defaultBorderMixin, RemoveIcon, DragHandleIcon, AddIcon, SelectGroup, InfoLabel, DeleteIcon, ContentCopyIcon, CodeIcon, Table, TableBody, TableRow, TableCell, Alert, Icon, Card, coolIconKeys, Tabs, Tab, ArrowBackIcon, LoadingButton, DoneIcon, Menu, MoreVertIcon, MenuItem, SaveIcon, UndoIcon } from "@firecms/ui";
|
|
7
7
|
import * as Yup from "yup";
|
|
@@ -17,6 +17,7 @@ const YupSchema = Yup.object().shape({
|
|
|
17
17
|
name: Yup.string().required("Required"),
|
|
18
18
|
path: Yup.string().required("Required")
|
|
19
19
|
});
|
|
20
|
+
const useCollectionEditorController = () => useContext(CollectionEditorContext);
|
|
20
21
|
function CollectionDetailsForm({
|
|
21
22
|
isNewCollection,
|
|
22
23
|
reservedGroups,
|
|
@@ -36,8 +37,12 @@ function CollectionDetailsForm({
|
|
|
36
37
|
isSubmitting,
|
|
37
38
|
submitCount
|
|
38
39
|
} = useFormex();
|
|
40
|
+
const collectionEditor = useCollectionEditorController();
|
|
39
41
|
const [iconDialogOpen, setIconDialogOpen] = useState(false);
|
|
40
42
|
const [advancedPanelExpanded, setAdvancedPanelExpanded] = useState(false);
|
|
43
|
+
const updateDatabaseId = (databaseId) => {
|
|
44
|
+
setFieldValue("databaseId", databaseId ?? void 0);
|
|
45
|
+
};
|
|
41
46
|
const updateName = (name) => {
|
|
42
47
|
setFieldValue("name", name);
|
|
43
48
|
const pathTouched = getIn(touched, "path");
|
|
@@ -58,6 +63,7 @@ function CollectionDetailsForm({
|
|
|
58
63
|
setAdvancedPanelExpanded(true);
|
|
59
64
|
}
|
|
60
65
|
}, [errors.id]);
|
|
66
|
+
const DatabaseField = collectionEditor.components?.DatabaseField ?? DefaultDatabaseField;
|
|
61
67
|
const collectionIcon = /* @__PURE__ */ jsx(IconForView, { collectionOrView: values });
|
|
62
68
|
const groupOptions = groups?.filter((group) => !reservedGroups?.includes(group));
|
|
63
69
|
const {
|
|
@@ -84,9 +90,16 @@ function CollectionDetailsForm({
|
|
|
84
90
|
/* @__PURE__ */ jsxs(
|
|
85
91
|
"div",
|
|
86
92
|
{
|
|
87
|
-
className: "flex flex-row py-2 pt-3 items-center",
|
|
93
|
+
className: "flex flex-row gap-2 py-2 pt-3 items-center",
|
|
88
94
|
children: [
|
|
89
95
|
/* @__PURE__ */ jsx(Typography, { variant: !isNewCollection ? "h5" : "h4", className: "flex-grow", children: isNewCollection ? "New collection" : `${values?.name} collection` }),
|
|
96
|
+
/* @__PURE__ */ jsx(
|
|
97
|
+
DatabaseField,
|
|
98
|
+
{
|
|
99
|
+
databaseId: values.databaseId,
|
|
100
|
+
onDatabaseIdUpdate: updateDatabaseId
|
|
101
|
+
}
|
|
102
|
+
),
|
|
90
103
|
/* @__PURE__ */ jsx(Tooltip, { title: "Change icon", children: /* @__PURE__ */ jsx(
|
|
91
104
|
IconButton,
|
|
92
105
|
{
|
|
@@ -165,7 +178,7 @@ function CollectionDetailsForm({
|
|
|
165
178
|
})
|
|
166
179
|
}
|
|
167
180
|
),
|
|
168
|
-
/* @__PURE__ */ jsx(FieldCaption, { children: showErrors && Boolean(errors.group) ? errors.group : "Group
|
|
181
|
+
/* @__PURE__ */ jsx(FieldCaption, { children: showErrors && Boolean(errors.group) ? errors.group : "Group in the home page" })
|
|
169
182
|
] }),
|
|
170
183
|
/* @__PURE__ */ jsx("div", { className: "col-span-12", children: /* @__PURE__ */ jsx(
|
|
171
184
|
ExpandablePanel,
|
|
@@ -369,6 +382,30 @@ function CollectionDetailsForm({
|
|
|
369
382
|
)
|
|
370
383
|
] }) });
|
|
371
384
|
}
|
|
385
|
+
function DefaultDatabaseField({
|
|
386
|
+
databaseId,
|
|
387
|
+
onDatabaseIdUpdate
|
|
388
|
+
}) {
|
|
389
|
+
return /* @__PURE__ */ jsx(
|
|
390
|
+
Tooltip,
|
|
391
|
+
{
|
|
392
|
+
title: "Database ID",
|
|
393
|
+
side: "top",
|
|
394
|
+
align: "start",
|
|
395
|
+
children: /* @__PURE__ */ jsx(
|
|
396
|
+
TextField,
|
|
397
|
+
{
|
|
398
|
+
size: "smallest",
|
|
399
|
+
invisible: true,
|
|
400
|
+
inputClassName: "text-end",
|
|
401
|
+
value: databaseId ?? "",
|
|
402
|
+
onChange: (e) => onDatabaseIdUpdate(e.target.value),
|
|
403
|
+
placeholder: "(default)"
|
|
404
|
+
}
|
|
405
|
+
)
|
|
406
|
+
}
|
|
407
|
+
);
|
|
408
|
+
}
|
|
372
409
|
function idToPropertiesPath(id) {
|
|
373
410
|
return "properties." + id.replaceAll(".", ".properties.");
|
|
374
411
|
}
|
|
@@ -1953,19 +1990,6 @@ function StringPropertyField({
|
|
|
1953
1990
|
showErrors
|
|
1954
1991
|
}
|
|
1955
1992
|
),
|
|
1956
|
-
widgetId === "markdown" && /* @__PURE__ */ jsx(
|
|
1957
|
-
StringPropertyValidation,
|
|
1958
|
-
{
|
|
1959
|
-
disabled,
|
|
1960
|
-
length: true,
|
|
1961
|
-
lowercase: true,
|
|
1962
|
-
max: true,
|
|
1963
|
-
min: true,
|
|
1964
|
-
trim: true,
|
|
1965
|
-
uppercase: true,
|
|
1966
|
-
showErrors
|
|
1967
|
-
}
|
|
1968
|
-
),
|
|
1969
1993
|
widgetId === "email" && /* @__PURE__ */ jsx(
|
|
1970
1994
|
StringPropertyValidation,
|
|
1971
1995
|
{
|
|
@@ -2776,7 +2800,7 @@ function PropertySelectItem({ value, optionDisabled, propertyConfig, existing })
|
|
|
2776
2800
|
"div",
|
|
2777
2801
|
{
|
|
2778
2802
|
className: cls(
|
|
2779
|
-
"flex flex-row items-center text-base min-h-[
|
|
2803
|
+
"flex flex-row items-center text-base min-h-[48px]",
|
|
2780
2804
|
optionDisabled ? "w-full" : ""
|
|
2781
2805
|
),
|
|
2782
2806
|
children: [
|
|
@@ -2886,6 +2910,121 @@ const supportedFieldsIds = [
|
|
|
2886
2910
|
"block"
|
|
2887
2911
|
];
|
|
2888
2912
|
const supportedFields = Object.entries(DEFAULT_FIELD_CONFIGS).filter(([id]) => supportedFieldsIds.includes(id)).map(([id, config]) => ({ [id]: config })).reduce((a, b) => ({ ...a, ...b }), {});
|
|
2913
|
+
function MarkdownPropertyField({
|
|
2914
|
+
disabled,
|
|
2915
|
+
showErrors
|
|
2916
|
+
}) {
|
|
2917
|
+
const {
|
|
2918
|
+
values,
|
|
2919
|
+
setFieldValue
|
|
2920
|
+
} = useFormex();
|
|
2921
|
+
const baseStoragePath = "storage";
|
|
2922
|
+
const fileName = `${baseStoragePath}.fileName`;
|
|
2923
|
+
const maxSize = `${baseStoragePath}.maxSize`;
|
|
2924
|
+
const storagePath = `${baseStoragePath}.storagePath`;
|
|
2925
|
+
const fileNameValue = getIn(values, fileName) ?? "{rand}_{file}";
|
|
2926
|
+
const storagePathValue = getIn(values, storagePath) ?? "/";
|
|
2927
|
+
const maxSizeValue = getIn(values, maxSize);
|
|
2928
|
+
const hasFilenameCallback = typeof fileNameValue === "function";
|
|
2929
|
+
const hasStoragePathCallback = typeof storagePathValue === "function";
|
|
2930
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2931
|
+
/* @__PURE__ */ jsx("div", { className: "col-span-12", children: /* @__PURE__ */ jsx(ValidationPanel, { children: /* @__PURE__ */ jsx(
|
|
2932
|
+
StringPropertyValidation,
|
|
2933
|
+
{
|
|
2934
|
+
disabled,
|
|
2935
|
+
length: true,
|
|
2936
|
+
lowercase: true,
|
|
2937
|
+
max: true,
|
|
2938
|
+
min: true,
|
|
2939
|
+
trim: true,
|
|
2940
|
+
uppercase: true,
|
|
2941
|
+
showErrors
|
|
2942
|
+
}
|
|
2943
|
+
) }) }),
|
|
2944
|
+
/* @__PURE__ */ jsx("div", { className: "col-span-12", children: /* @__PURE__ */ jsx(
|
|
2945
|
+
ExpandablePanel,
|
|
2946
|
+
{
|
|
2947
|
+
title: /* @__PURE__ */ jsxs("div", { className: "flex flex-row text-gray-500", children: [
|
|
2948
|
+
/* @__PURE__ */ jsx(FileUploadIcon, {}),
|
|
2949
|
+
/* @__PURE__ */ jsx(
|
|
2950
|
+
Typography,
|
|
2951
|
+
{
|
|
2952
|
+
variant: "subtitle2",
|
|
2953
|
+
className: "ml-2",
|
|
2954
|
+
children: "File upload config"
|
|
2955
|
+
}
|
|
2956
|
+
)
|
|
2957
|
+
] }),
|
|
2958
|
+
children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-12 gap-2 p-4", children: [
|
|
2959
|
+
/* @__PURE__ */ jsx("div", { className: "col-span-12", children: /* @__PURE__ */ jsx(
|
|
2960
|
+
Field,
|
|
2961
|
+
{
|
|
2962
|
+
name: fileName,
|
|
2963
|
+
as: DebouncedTextField,
|
|
2964
|
+
label: "File name",
|
|
2965
|
+
size: "small",
|
|
2966
|
+
disabled: hasFilenameCallback || disabled,
|
|
2967
|
+
value: hasFilenameCallback ? "-" : fileNameValue
|
|
2968
|
+
}
|
|
2969
|
+
) }),
|
|
2970
|
+
/* @__PURE__ */ jsxs("div", { className: "col-span-12", children: [
|
|
2971
|
+
/* @__PURE__ */ jsx(
|
|
2972
|
+
Field,
|
|
2973
|
+
{
|
|
2974
|
+
name: storagePath,
|
|
2975
|
+
as: DebouncedTextField,
|
|
2976
|
+
label: "Storage path",
|
|
2977
|
+
disabled: hasStoragePathCallback || disabled,
|
|
2978
|
+
size: "small",
|
|
2979
|
+
value: hasStoragePathCallback ? "-" : storagePathValue
|
|
2980
|
+
}
|
|
2981
|
+
),
|
|
2982
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "ml-3.5 mt-1 mb-2", children: [
|
|
2983
|
+
/* @__PURE__ */ jsx("p", { children: "You can use the following placeholders in the file name and storage path values:" }),
|
|
2984
|
+
/* @__PURE__ */ jsxs("ul", { children: [
|
|
2985
|
+
/* @__PURE__ */ jsx("li", { children: "{file} - Full name of the uploaded file" }),
|
|
2986
|
+
/* @__PURE__ */ jsx("li", { children: "{file.name} - Name of the uploaded file without extension" }),
|
|
2987
|
+
/* @__PURE__ */ jsx("li", { children: "{file.ext} - Extension of the uploaded file" }),
|
|
2988
|
+
/* @__PURE__ */ jsx("li", { children: "{entityId} - ID of the entity" }),
|
|
2989
|
+
/* @__PURE__ */ jsx("li", { children: "{propertyKey} - ID of this field" }),
|
|
2990
|
+
/* @__PURE__ */ jsx("li", { children: "{path} - Path of this entity" }),
|
|
2991
|
+
/* @__PURE__ */ jsx("li", { children: "{rand} - Random value used to avoid name collisions" })
|
|
2992
|
+
] })
|
|
2993
|
+
] }),
|
|
2994
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", className: "ml-3.5 mt-1 mb-2", children: "When using Markdown, the URL of the uploaded files are always saved in the text value (not the path)." })
|
|
2995
|
+
] }),
|
|
2996
|
+
/* @__PURE__ */ jsx("div", { className: "col-span-12", children: /* @__PURE__ */ jsx(
|
|
2997
|
+
DebouncedTextField,
|
|
2998
|
+
{
|
|
2999
|
+
name: maxSize,
|
|
3000
|
+
type: "number",
|
|
3001
|
+
label: "Max size (in bytes)",
|
|
3002
|
+
size: "small",
|
|
3003
|
+
value: maxSizeValue !== void 0 && maxSizeValue !== null ? maxSizeValue.toString() : "",
|
|
3004
|
+
onChange: (e) => {
|
|
3005
|
+
const value = e.target.value;
|
|
3006
|
+
if (value === "") setFieldValue(maxSize, void 0);
|
|
3007
|
+
else setFieldValue(maxSize, parseInt(value));
|
|
3008
|
+
}
|
|
3009
|
+
}
|
|
3010
|
+
) })
|
|
3011
|
+
] })
|
|
3012
|
+
}
|
|
3013
|
+
) }),
|
|
3014
|
+
/* @__PURE__ */ jsx("div", { className: "col-span-12", children: /* @__PURE__ */ jsx(
|
|
3015
|
+
TextField,
|
|
3016
|
+
{
|
|
3017
|
+
name: "defaultValue",
|
|
3018
|
+
disabled,
|
|
3019
|
+
onChange: (e) => {
|
|
3020
|
+
setFieldValue("defaultValue", e.target.value === "" ? void 0 : e.target.value);
|
|
3021
|
+
},
|
|
3022
|
+
label: "Default value",
|
|
3023
|
+
value: getIn(values, "defaultValue") ?? ""
|
|
3024
|
+
}
|
|
3025
|
+
) })
|
|
3026
|
+
] });
|
|
3027
|
+
}
|
|
2889
3028
|
const PropertyForm = React__default.memo(
|
|
2890
3029
|
function PropertyForm2(props) {
|
|
2891
3030
|
const {
|
|
@@ -2946,7 +3085,10 @@ const PropertyForm = React__default.memo(
|
|
|
2946
3085
|
} = newPropertyWithId;
|
|
2947
3086
|
doOnPropertyChanged({
|
|
2948
3087
|
id,
|
|
2949
|
-
property: {
|
|
3088
|
+
property: {
|
|
3089
|
+
...property2,
|
|
3090
|
+
editable: property2.editable ?? true
|
|
3091
|
+
}
|
|
2950
3092
|
});
|
|
2951
3093
|
if (!existingProperty)
|
|
2952
3094
|
controller.resetForm({ values: initialValue });
|
|
@@ -3151,7 +3293,7 @@ function PropertyEditFormFields({
|
|
|
3151
3293
|
}, 0);
|
|
3152
3294
|
};
|
|
3153
3295
|
let childComponent;
|
|
3154
|
-
if (selectedFieldConfigId === "text_field" || selectedFieldConfigId === "multiline" || selectedFieldConfigId === "
|
|
3296
|
+
if (selectedFieldConfigId === "text_field" || selectedFieldConfigId === "multiline" || selectedFieldConfigId === "email") {
|
|
3155
3297
|
childComponent = /* @__PURE__ */ jsx(
|
|
3156
3298
|
StringPropertyField,
|
|
3157
3299
|
{
|
|
@@ -3168,6 +3310,14 @@ function PropertyEditFormFields({
|
|
|
3168
3310
|
showErrors
|
|
3169
3311
|
}
|
|
3170
3312
|
);
|
|
3313
|
+
} else if (selectedFieldConfigId === "markdown") {
|
|
3314
|
+
childComponent = /* @__PURE__ */ jsx(
|
|
3315
|
+
MarkdownPropertyField,
|
|
3316
|
+
{
|
|
3317
|
+
disabled,
|
|
3318
|
+
showErrors
|
|
3319
|
+
}
|
|
3320
|
+
);
|
|
3171
3321
|
} else if (selectedFieldConfigId === "select" || selectedFieldConfigId === "number_select") {
|
|
3172
3322
|
childComponent = /* @__PURE__ */ jsx(
|
|
3173
3323
|
EnumPropertyField,
|
|
@@ -5795,7 +5945,8 @@ const ConfigControllerProvider = React__default.memo(
|
|
|
5795
5945
|
getPathSuggestions,
|
|
5796
5946
|
getUser,
|
|
5797
5947
|
getData,
|
|
5798
|
-
onAnalyticsEvent
|
|
5948
|
+
onAnalyticsEvent,
|
|
5949
|
+
components
|
|
5799
5950
|
}) {
|
|
5800
5951
|
const navigation = useNavigationController();
|
|
5801
5952
|
const navigate = useNavigate();
|
|
@@ -5894,7 +6045,8 @@ const ConfigControllerProvider = React__default.memo(
|
|
|
5894
6045
|
createCollection,
|
|
5895
6046
|
editProperty,
|
|
5896
6047
|
configPermissions: configPermissions ?? defaultConfigPermissions,
|
|
5897
|
-
getPathSuggestions
|
|
6048
|
+
getPathSuggestions,
|
|
6049
|
+
components
|
|
5898
6050
|
},
|
|
5899
6051
|
children: [
|
|
5900
6052
|
children,
|
|
@@ -6004,7 +6156,6 @@ const ConfigControllerProvider = React__default.memo(
|
|
|
6004
6156
|
},
|
|
6005
6157
|
equal
|
|
6006
6158
|
);
|
|
6007
|
-
const useCollectionEditorController = () => useContext(CollectionEditorContext);
|
|
6008
6159
|
function EditorCollectionAction({
|
|
6009
6160
|
path: fullPath,
|
|
6010
6161
|
parentCollectionIds,
|
|
@@ -6328,7 +6479,8 @@ function useCollectionEditorPlugin({
|
|
|
6328
6479
|
getUser,
|
|
6329
6480
|
collectionInference,
|
|
6330
6481
|
getData,
|
|
6331
|
-
onAnalyticsEvent
|
|
6482
|
+
onAnalyticsEvent,
|
|
6483
|
+
components
|
|
6332
6484
|
}) {
|
|
6333
6485
|
return {
|
|
6334
6486
|
key: "collection_editor",
|
|
@@ -6344,7 +6496,8 @@ function useCollectionEditorPlugin({
|
|
|
6344
6496
|
getPathSuggestions,
|
|
6345
6497
|
getUser,
|
|
6346
6498
|
getData,
|
|
6347
|
-
onAnalyticsEvent
|
|
6499
|
+
onAnalyticsEvent,
|
|
6500
|
+
components
|
|
6348
6501
|
}
|
|
6349
6502
|
},
|
|
6350
6503
|
homePage: {
|