@firecms/collection_editor 3.0.0-beta.10 → 3.0.0-beta.11
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/index.es.js +8975 -5244
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +8967 -5237
- package/dist/index.umd.js.map +1 -1
- package/dist/types/config_permissions.d.ts +2 -2
- package/dist/types/persisted_collection.d.ts +1 -1
- package/dist/useCollectionEditorPlugin.d.ts +4 -4
- package/package.json +18 -16
- 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/NewCollectionButton.tsx +1 -1
- package/src/ui/PropertyAddColumnComponent.tsx +2 -2
- package/src/ui/collection_editor/CollectionDetailsForm.tsx +8 -4
- package/src/ui/collection_editor/CollectionEditorDialog.tsx +9 -5
- package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +2 -2
- package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +5 -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 +41 -23
- package/src/ui/collection_editor/PropertyEditView.tsx +7 -4
- 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/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 -6
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EntityCollection } from "@firecms/core";
|
|
2
|
-
export type CollectionEditorPermissionsBuilder<
|
|
3
|
-
user:
|
|
2
|
+
export type CollectionEditorPermissionsBuilder<USER = any, EC extends EntityCollection = EntityCollection> = (params: {
|
|
3
|
+
user: USER | null;
|
|
4
4
|
collection?: EC;
|
|
5
5
|
}) => CollectionEditorPermissions;
|
|
6
6
|
export type CollectionEditorPermissions = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EntityCollection, User } from "@firecms/core";
|
|
2
|
-
export type PersistedCollection<M extends Record<string, any> = any,
|
|
2
|
+
export type PersistedCollection<M extends Record<string, any> = any, USER extends User = User> = Omit<EntityCollection<M, USER>, "subcollections"> & {
|
|
3
3
|
ownerId?: string;
|
|
4
4
|
subcollections?: PersistedCollection<any, any>[];
|
|
5
5
|
editable?: boolean;
|
|
@@ -4,7 +4,7 @@ import { CollectionEditorPermissionsBuilder } from "./types/config_permissions";
|
|
|
4
4
|
import { PersistedCollection } from "./types/persisted_collection";
|
|
5
5
|
import { CollectionInference } from "./types/collection_inference";
|
|
6
6
|
import { CollectionsConfigController } from "./types/config_controller";
|
|
7
|
-
export interface CollectionConfigControllerProps<EC extends PersistedCollection = PersistedCollection,
|
|
7
|
+
export interface CollectionConfigControllerProps<EC extends PersistedCollection = PersistedCollection, USER extends User = User> {
|
|
8
8
|
/**
|
|
9
9
|
* Firebase app where the configuration is saved.
|
|
10
10
|
*/
|
|
@@ -12,7 +12,7 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
|
|
|
12
12
|
/**
|
|
13
13
|
* Define what actions can be performed on the configuration.
|
|
14
14
|
*/
|
|
15
|
-
configPermissions?: CollectionEditorPermissionsBuilder<
|
|
15
|
+
configPermissions?: CollectionEditorPermissionsBuilder<USER, EC>;
|
|
16
16
|
/**
|
|
17
17
|
* The words you define here will not be allowed to be used as group
|
|
18
18
|
* names when creating collections.
|
|
@@ -28,7 +28,7 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
|
|
|
28
28
|
getPathSuggestions?: (path?: string) => Promise<string[]>;
|
|
29
29
|
collectionInference?: CollectionInference;
|
|
30
30
|
getData?: (path: string, parentPaths: string[]) => Promise<object[]>;
|
|
31
|
-
getUser?: (uid: string) =>
|
|
31
|
+
getUser?: (uid: string) => USER | null;
|
|
32
32
|
onAnalyticsEvent?: (event: string, params?: object) => void;
|
|
33
33
|
components?: {
|
|
34
34
|
/**
|
|
@@ -51,5 +51,5 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
|
|
|
51
51
|
* @param getUser
|
|
52
52
|
* @param collectionInference
|
|
53
53
|
*/
|
|
54
|
-
export declare function useCollectionEditorPlugin<EC extends PersistedCollection = PersistedCollection,
|
|
54
|
+
export declare function useCollectionEditorPlugin<EC extends PersistedCollection = PersistedCollection, USER extends User = User>({ collectionConfigController, configPermissions, reservedGroups, extraView, getPathSuggestions, getUser, collectionInference, getData, onAnalyticsEvent, components }: CollectionConfigControllerProps<EC, USER>): FireCMSPlugin<any, any, PersistedCollection>;
|
|
55
55
|
export declare function IntroWidget({}: {}): import("react/jsx-runtime").JSX.Element | null;
|
package/package.json
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@firecms/collection_editor",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "3.0.0-beta.
|
|
4
|
+
"version": "3.0.0-beta.11",
|
|
5
5
|
"main": "./dist/index.umd.js",
|
|
6
6
|
"module": "./dist/index.es.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"source": "src/index.ts",
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@firecms/data_export": "^3.0.0-beta.
|
|
11
|
-
"@firecms/data_import": "^3.0.0-beta.
|
|
12
|
-
"@firecms/data_import_export": "^3.0.0-beta.
|
|
13
|
-
"@firecms/formex": "^3.0.0-beta.
|
|
14
|
-
"@firecms/schema_inference": "^3.0.0-beta.
|
|
15
|
-
"@firecms/ui": "^3.0.0-beta.
|
|
10
|
+
"@firecms/data_export": "^3.0.0-beta.11",
|
|
11
|
+
"@firecms/data_import": "^3.0.0-beta.11",
|
|
12
|
+
"@firecms/data_import_export": "^3.0.0-beta.11",
|
|
13
|
+
"@firecms/formex": "^3.0.0-beta.11",
|
|
14
|
+
"@firecms/schema_inference": "^3.0.0-beta.11",
|
|
15
|
+
"@firecms/ui": "^3.0.0-beta.11",
|
|
16
16
|
"json5": "^2.2.3",
|
|
17
17
|
"prism-react-renderer": "^2.4.0"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
20
|
"react": "^18.3.1",
|
|
21
21
|
"react-dom": "^18.3.1",
|
|
22
|
-
"react-router": "^6.
|
|
23
|
-
"react-router-dom": "^6.
|
|
22
|
+
"react-router": "^6.28.0",
|
|
23
|
+
"react-router-dom": "^6.28.0"
|
|
24
24
|
},
|
|
25
25
|
"exports": {
|
|
26
26
|
".": {
|
|
@@ -51,14 +51,16 @@
|
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@jest/globals": "^29.7.0",
|
|
53
53
|
"@types/react": "^18.3.11",
|
|
54
|
-
"@types/react-dom": "^18.3.
|
|
55
|
-
"@vitejs/plugin-react": "^4.3.
|
|
54
|
+
"@types/react-dom": "^18.3.1",
|
|
55
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
56
|
+
"babel-plugin-react-compiler": "beta",
|
|
57
|
+
"eslint-plugin-react-compiler": "beta",
|
|
56
58
|
"jest": "^29.7.0",
|
|
57
|
-
"react-router": "^6.
|
|
58
|
-
"react-router-dom": "^6.
|
|
59
|
+
"react-router": "^6.28.0",
|
|
60
|
+
"react-router-dom": "^6.28.0",
|
|
59
61
|
"ts-jest": "^29.2.5",
|
|
60
|
-
"typescript": "^5.
|
|
61
|
-
"vite": "^5.4.
|
|
62
|
+
"typescript": "^5.7.2",
|
|
63
|
+
"vite": "^5.4.11"
|
|
62
64
|
},
|
|
63
65
|
"files": [
|
|
64
66
|
"dist",
|
|
@@ -67,5 +69,5 @@
|
|
|
67
69
|
"publishConfig": {
|
|
68
70
|
"access": "public"
|
|
69
71
|
},
|
|
70
|
-
"gitHead": "
|
|
72
|
+
"gitHead": "cb6d419faf2664cfd6cb2603a834e4bf499a92bb"
|
|
71
73
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EntityCollection } from "@firecms/core";
|
|
2
2
|
|
|
3
|
-
export type CollectionEditorPermissionsBuilder<
|
|
3
|
+
export type CollectionEditorPermissionsBuilder<USER = any, EC extends EntityCollection = EntityCollection> = (params: { user: USER | null, collection?: EC }) => CollectionEditorPermissions;
|
|
4
4
|
|
|
5
5
|
export type CollectionEditorPermissions = {
|
|
6
6
|
/**
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { EntityCollection, User } from "@firecms/core";
|
|
2
2
|
|
|
3
|
-
export type PersistedCollection<M extends Record<string, any> = any,
|
|
4
|
-
= Omit<EntityCollection<M,
|
|
5
|
-
// properties: Properties<M>;
|
|
3
|
+
export type PersistedCollection<M extends Record<string, any> = any, USER extends User = User>
|
|
4
|
+
= Omit<EntityCollection<M, USER>, "subcollections"> & {
|
|
6
5
|
ownerId?: string;
|
|
7
6
|
subcollections?: PersistedCollection<any, any>[];
|
|
8
7
|
editable?: boolean;
|
|
@@ -29,7 +29,7 @@ export function CollectionViewHeaderAction({
|
|
|
29
29
|
asChild={true}
|
|
30
30
|
title={"Edit"}>
|
|
31
31
|
<IconButton
|
|
32
|
-
className={onHover ? "bg-white dark:bg-
|
|
32
|
+
className={onHover ? "bg-white dark:bg-surface-950" : "hidden"}
|
|
33
33
|
onClick={() => {
|
|
34
34
|
collectionEditorController.editProperty({
|
|
35
35
|
propertyKey,
|
|
@@ -3,7 +3,7 @@ import { useCollectionEditorController } from "../useCollectionEditorController"
|
|
|
3
3
|
|
|
4
4
|
export function NewCollectionButton() {
|
|
5
5
|
const collectionEditorController = useCollectionEditorController();
|
|
6
|
-
return <div className={"bg-
|
|
6
|
+
return <div className={"bg-surface-50 dark:bg-surface-900 min-w-fit rounded"}>
|
|
7
7
|
<Button className={"min-w-fit"}
|
|
8
8
|
variant={"outlined"}
|
|
9
9
|
onClick={() => collectionEditorController.createCollection({
|
|
@@ -29,8 +29,8 @@ export function PropertyAddColumnComponent({
|
|
|
29
29
|
asChild={true}
|
|
30
30
|
title={canEditCollection ? "Add new property" : "You don't have permission to add new properties"}>
|
|
31
31
|
<div
|
|
32
|
-
className={"p-0.5 w-20 h-full flex items-center justify-center cursor-pointer bg-
|
|
33
|
-
// className={onHover ? "bg-white dark:bg-
|
|
32
|
+
className={"p-0.5 w-20 h-full flex items-center justify-center cursor-pointer bg-surface-100 bg-opacity-40 hover:bg-surface-100 dark:bg-surface-950 dark:bg-opacity-40 dark:hover:bg-surface-950"}
|
|
33
|
+
// className={onHover ? "bg-white dark:bg-surface-950" : undefined}
|
|
34
34
|
onClick={() => {
|
|
35
35
|
collectionEditorController.editProperty({
|
|
36
36
|
editedCollectionId: collection.id,
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
AutocompleteItem,
|
|
6
6
|
BooleanSwitchWithLabel,
|
|
7
7
|
Chip,
|
|
8
|
-
|
|
8
|
+
CloseIcon,
|
|
9
9
|
cls,
|
|
10
10
|
Container,
|
|
11
11
|
DebouncedTextField,
|
|
@@ -214,7 +214,7 @@ export function CollectionDetailsForm({
|
|
|
214
214
|
expanded={advancedPanelExpanded}
|
|
215
215
|
onExpandedChange={setAdvancedPanelExpanded}
|
|
216
216
|
title={
|
|
217
|
-
<div className="flex flex-row text-
|
|
217
|
+
<div className="flex flex-row text-surface-500">
|
|
218
218
|
<SettingsIcon/>
|
|
219
219
|
<Typography variant={"subtitle2"}
|
|
220
220
|
className="ml-2">
|
|
@@ -271,7 +271,7 @@ export function CollectionDetailsForm({
|
|
|
271
271
|
setFieldValue("sideDialogWidth", null);
|
|
272
272
|
}}
|
|
273
273
|
disabled={!values.sideDialogWidth}>
|
|
274
|
-
<
|
|
274
|
+
<CloseIcon size={"small"}/>
|
|
275
275
|
</IconButton>}
|
|
276
276
|
value={values.sideDialogWidth ?? ""}
|
|
277
277
|
label={"Side dialog width"}/>
|
|
@@ -298,6 +298,8 @@ export function CollectionDetailsForm({
|
|
|
298
298
|
<div className={"col-span-12"}>
|
|
299
299
|
<Select
|
|
300
300
|
name="defaultSize"
|
|
301
|
+
size={"large"}
|
|
302
|
+
fullWidth={true}
|
|
301
303
|
label="Default row size"
|
|
302
304
|
position={"item-aligned"}
|
|
303
305
|
onChange={handleChange}
|
|
@@ -318,6 +320,8 @@ export function CollectionDetailsForm({
|
|
|
318
320
|
name="customId"
|
|
319
321
|
label="Document IDs generation"
|
|
320
322
|
position={"item-aligned"}
|
|
323
|
+
size={"large"}
|
|
324
|
+
fullWidth={true}
|
|
321
325
|
disabled={customIdValue === "code_defined"}
|
|
322
326
|
onValueChange={(v) => {
|
|
323
327
|
if (v === "code_defined")
|
|
@@ -416,7 +420,7 @@ function DefaultDatabaseField({
|
|
|
416
420
|
return <Tooltip title={"Database ID"}
|
|
417
421
|
side={"top"}
|
|
418
422
|
align={"start"}>
|
|
419
|
-
<TextField size={"
|
|
423
|
+
<TextField size={"small"}
|
|
420
424
|
invisible={true}
|
|
421
425
|
inputClassName={"text-end"}
|
|
422
426
|
value={databaseId ?? ""}
|
|
@@ -26,13 +26,14 @@ import {
|
|
|
26
26
|
import {
|
|
27
27
|
ArrowBackIcon,
|
|
28
28
|
Button,
|
|
29
|
+
CheckIcon,
|
|
29
30
|
cls,
|
|
30
31
|
coolIconKeys,
|
|
31
32
|
defaultBorderMixin,
|
|
32
33
|
Dialog,
|
|
33
34
|
DialogActions,
|
|
34
35
|
DialogContent,
|
|
35
|
-
|
|
36
|
+
DialogTitle,
|
|
36
37
|
IconButton,
|
|
37
38
|
LoadingButton,
|
|
38
39
|
Tab,
|
|
@@ -114,6 +115,7 @@ export function CollectionEditorDialog(props: CollectionEditorDialogProps) {
|
|
|
114
115
|
maxWidth={"7xl"}
|
|
115
116
|
onOpenChange={(open) => !open ? handleCancel() : undefined}
|
|
116
117
|
>
|
|
118
|
+
<DialogTitle hidden>Collection editor</DialogTitle>
|
|
117
119
|
{open && <CollectionEditor {...props}
|
|
118
120
|
handleCancel={handleCancel}
|
|
119
121
|
setFormDirty={setFormDirty}/>}
|
|
@@ -276,6 +278,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
276
278
|
|
|
277
279
|
const saveCollection = (updatedCollection: PersistedCollection<M>): Promise<boolean> => {
|
|
278
280
|
const id = updatedCollection.id || updatedCollection.path;
|
|
281
|
+
|
|
279
282
|
return configController.saveCollection({
|
|
280
283
|
id,
|
|
281
284
|
collectionData: updatedCollection,
|
|
@@ -377,7 +380,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
377
380
|
|
|
378
381
|
if (!isNewCollection) {
|
|
379
382
|
saveCollection(newCollectionState).then(() => {
|
|
380
|
-
formexController.resetForm(
|
|
383
|
+
formexController.resetForm();
|
|
381
384
|
handleClose(newCollectionState);
|
|
382
385
|
});
|
|
383
386
|
return;
|
|
@@ -466,7 +469,8 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
466
469
|
const formController = useCreateFormex<PersistedCollection<M>>({
|
|
467
470
|
initialValues,
|
|
468
471
|
onSubmit,
|
|
469
|
-
validation
|
|
472
|
+
validation,
|
|
473
|
+
debugId: "COLLECTION_EDITOR"
|
|
470
474
|
});
|
|
471
475
|
|
|
472
476
|
const {
|
|
@@ -536,7 +540,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
536
540
|
|
|
537
541
|
<>
|
|
538
542
|
{!isNewCollection && <Tabs value={currentView}
|
|
539
|
-
|
|
543
|
+
innerClassName={cls(defaultBorderMixin, "justify-end bg-surface-50 dark:bg-surface-950 border-b")}
|
|
540
544
|
onValueChange={(v) => setCurrentView(v as EditorView)}>
|
|
541
545
|
<Tab value={"details"}>
|
|
542
546
|
Details
|
|
@@ -722,7 +726,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
722
726
|
loading={isSubmitting}
|
|
723
727
|
disabled={isSubmitting || (currentView === "details" && !validValues)}
|
|
724
728
|
startIcon={currentView === "properties"
|
|
725
|
-
? <
|
|
729
|
+
? <CheckIcon/>
|
|
726
730
|
: undefined}
|
|
727
731
|
>
|
|
728
732
|
{currentView === "details" && "Next"}
|
|
@@ -191,9 +191,9 @@ export function TemplateButton({
|
|
|
191
191
|
onClick={onClick}
|
|
192
192
|
className={cls(
|
|
193
193
|
"my-2 rounded-md border mx-0 p-6 px-4 focus:outline-none transition ease-in-out duration-150 flex flex-row gap-4 items-center",
|
|
194
|
-
"text-
|
|
194
|
+
"text-surface-700 dark:text-surface-accent-300",
|
|
195
195
|
"hover:border-primary-dark hover:text-primary-dark dark:hover:text-primary focus:ring-primary hover:ring-1 hover:ring-primary",
|
|
196
|
-
"border-
|
|
196
|
+
"border-surface-400 dark:border-surface-600 "
|
|
197
197
|
)}
|
|
198
198
|
>
|
|
199
199
|
{icon}
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
} from "@firecms/core";
|
|
17
17
|
import {
|
|
18
18
|
AddIcon,
|
|
19
|
-
|
|
19
|
+
AutorenewIcon,
|
|
20
20
|
Button,
|
|
21
21
|
CircularProgress,
|
|
22
22
|
cls,
|
|
@@ -228,17 +228,13 @@ export function CollectionPropertiesEditorForm({
|
|
|
228
228
|
namespace
|
|
229
229
|
}: OnPropertyChangedParams) => {
|
|
230
230
|
|
|
231
|
+
console.log("!!!!!! onPropertyChanged", property)
|
|
232
|
+
|
|
231
233
|
const fullId = id ? getFullId(id, namespace) : undefined;
|
|
232
234
|
const propertyPath = fullId ? idToPropertiesPath(fullId) : undefined;
|
|
233
235
|
|
|
234
236
|
// If the id has changed we need to a little cleanup
|
|
235
237
|
if (previousId && previousId !== id) {
|
|
236
|
-
console.debug("onPropertyChanged, id change", {
|
|
237
|
-
id,
|
|
238
|
-
property,
|
|
239
|
-
previousId,
|
|
240
|
-
namespace
|
|
241
|
-
})
|
|
242
238
|
|
|
243
239
|
const previousFullId = getFullId(previousId, namespace);
|
|
244
240
|
const previousPropertyPath = idToPropertiesPath(previousFullId);
|
|
@@ -316,7 +312,7 @@ export function CollectionPropertiesEditorForm({
|
|
|
316
312
|
};
|
|
317
313
|
|
|
318
314
|
const body = (
|
|
319
|
-
<div className={"grid grid-cols-12 gap-2 h-full bg-
|
|
315
|
+
<div className={"grid grid-cols-12 gap-2 h-full bg-surface-50 dark:bg-surface-900"}>
|
|
320
316
|
<div className={cls(
|
|
321
317
|
"p-4 md:p-8 pb-20 md:pb-20",
|
|
322
318
|
"col-span-12 lg:col-span-5 h-full overflow-auto",
|
|
@@ -366,7 +362,7 @@ export function CollectionPropertiesEditorForm({
|
|
|
366
362
|
variant={"filled"}
|
|
367
363
|
disabled={inferringProperties}
|
|
368
364
|
onClick={inferPropertiesFromData}>
|
|
369
|
-
{inferringProperties ? <CircularProgress size={"small"}/> : <
|
|
365
|
+
{inferringProperties ? <CircularProgress size={"small"}/> : <AutorenewIcon/>}
|
|
370
366
|
</IconButton>
|
|
371
367
|
</Tooltip>}
|
|
372
368
|
<Tooltip title={"Add new property"}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { useCustomizationController } from "@firecms/core";
|
|
2
|
-
import { Button, Dialog, DialogActions, DialogContent, Typography } from "@firecms/ui";
|
|
2
|
+
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Typography } from "@firecms/ui";
|
|
3
3
|
import React from "react";
|
|
4
4
|
|
|
5
|
-
export function EntityCustomViewsSelectDialog({
|
|
5
|
+
export function EntityCustomViewsSelectDialog({
|
|
6
|
+
open,
|
|
7
|
+
onClose
|
|
8
|
+
}: { open: boolean, onClose: (selectedViewKey?: string) => void }) {
|
|
6
9
|
const {
|
|
7
10
|
entityViews,
|
|
8
11
|
} = useCustomizationController();
|
|
@@ -10,10 +13,8 @@ export function EntityCustomViewsSelectDialog({ open, onClose }: { open: boolean
|
|
|
10
13
|
return <Dialog
|
|
11
14
|
maxWidth={"md"}
|
|
12
15
|
open={open}>
|
|
16
|
+
<DialogTitle>Select custom view</DialogTitle>
|
|
13
17
|
<DialogContent className={"flex flex-col gap-4"}>
|
|
14
|
-
<Typography variant={"h6"}>
|
|
15
|
-
Select view
|
|
16
|
-
</Typography>
|
|
17
18
|
{entityViews?.map((view) => {
|
|
18
19
|
return <Button
|
|
19
20
|
key={view.key}
|
|
@@ -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={"small"}/> : <
|
|
186
|
+
{inferring ? <CircularProgress size={"small"}/> : <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,15 +15,14 @@ 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.
|
|
@@ -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
|
}))
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
ConfirmationDialog,
|
|
7
7
|
DEFAULT_FIELD_CONFIGS,
|
|
8
8
|
getFieldConfig,
|
|
9
|
-
getFieldId,
|
|
9
|
+
getFieldId, isEmptyObject,
|
|
10
10
|
isPropertyBuilder,
|
|
11
11
|
isValidRegExp,
|
|
12
12
|
mergeDeep,
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
InfoLabel,
|
|
32
32
|
Tooltip,
|
|
33
33
|
Typography,
|
|
34
|
-
|
|
34
|
+
WarningIcon
|
|
35
35
|
} from "@firecms/ui";
|
|
36
36
|
import { EnumPropertyField } from "./properties/EnumPropertyField";
|
|
37
37
|
import { StoragePropertyField } from "./properties/StoragePropertyField";
|
|
@@ -142,6 +142,7 @@ export const PropertyForm = React.memo(
|
|
|
142
142
|
};
|
|
143
143
|
|
|
144
144
|
const formexController = useCreateFormex<PropertyWithId>({
|
|
145
|
+
debugId: "PROPERTY_FORM",
|
|
145
146
|
initialValues: property
|
|
146
147
|
? { id: propertyKey, ...property } as PropertyWithId
|
|
147
148
|
: initialValue,
|
|
@@ -274,7 +275,9 @@ export function PropertyFormDialog({
|
|
|
274
275
|
e.stopPropagation();
|
|
275
276
|
formexRef.current?.handleSubmit(e)
|
|
276
277
|
}}>
|
|
278
|
+
<DialogTitle hidden>Property edit view</DialogTitle>
|
|
277
279
|
<DialogContent>
|
|
280
|
+
|
|
278
281
|
<PropertyForm {...formProps}
|
|
279
282
|
onDismiss={onCancel}
|
|
280
283
|
onPropertyChanged={(params) => {
|
|
@@ -380,7 +383,7 @@ function PropertyEditFormFields({
|
|
|
380
383
|
}, [deferredValues, includeIdAndTitle, propertyNamespace]);
|
|
381
384
|
|
|
382
385
|
useEffect(() => {
|
|
383
|
-
if (values?.id && onError) {
|
|
386
|
+
if (values?.id && onError && !isEmptyObject(errors)) {
|
|
384
387
|
onError(values?.id, propertyNamespace, errors);
|
|
385
388
|
}
|
|
386
389
|
}, [errors, propertyNamespace, values?.id]);
|
|
@@ -771,7 +774,7 @@ export function WidgetSelectViewItem({
|
|
|
771
774
|
<div className={"flex flex-row gap-2 items-center"}>
|
|
772
775
|
{shouldWarnChangingDataType && <Tooltip
|
|
773
776
|
title={"This widget uses a different data type than the initially selected widget. This can cause errors with existing data."}>
|
|
774
|
-
<
|
|
777
|
+
<WarningIcon size="smallest" className={"w-4"}/>
|
|
775
778
|
</Tooltip>}
|
|
776
779
|
<Typography
|
|
777
780
|
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"}
|