@firecms/collection_editor 3.0.0-canary.258 → 3.0.0-canary.259
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 +633 -171
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +632 -170
- package/dist/index.umd.js.map +1 -1
- package/dist/types/collection_inference.d.ts +3 -0
- package/dist/ui/EditorEntityAction.d.ts +2 -0
- package/dist/ui/collection_editor/CollectionPropertiesEditorForm.d.ts +1 -1
- package/dist/ui/collection_editor/EntityActionsEditTab.d.ts +4 -0
- package/dist/ui/collection_editor/EntityActionsSelectDialog.d.ts +4 -0
- package/package.json +8 -8
- package/src/types/collection_inference.ts +3 -0
- package/src/ui/EditorCollectionAction.tsx +2 -7
- package/src/ui/EditorEntityAction.tsx +51 -0
- package/src/ui/collection_editor/CollectionEditorDialog.tsx +17 -4
- package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +5 -0
- package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +5 -2
- package/src/ui/collection_editor/EntityActionsEditTab.tsx +163 -0
- package/src/ui/collection_editor/EntityActionsSelectDialog.tsx +41 -0
- package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +5 -2
- package/src/ui/collection_editor/GetCodeDialog.tsx +5 -3
- package/src/ui/collection_editor/PropertyEditView.tsx +1 -0
- package/src/ui/collection_editor/UnsavedChangesDialog.tsx +6 -2
- package/src/useCollectionEditorPlugin.tsx +4 -0
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
import { EntityCollection } from "@firecms/core";
|
|
2
|
+
/**
|
|
3
|
+
* This function is used to infer the configuration of a collection given its path.
|
|
4
|
+
*/
|
|
2
5
|
export type CollectionInference = (path: string, collectionGroup: boolean, parentCollectionPaths: string[]) => Promise<Partial<EntityCollection> | null>;
|
|
@@ -11,7 +11,7 @@ type CollectionEditorFormProps = {
|
|
|
11
11
|
extraIcon: React.ReactNode;
|
|
12
12
|
getUser?: (uid: string) => User | null;
|
|
13
13
|
getData?: () => Promise<object[]>;
|
|
14
|
-
doCollectionInference
|
|
14
|
+
doCollectionInference?: (collection: PersistedCollection) => Promise<Partial<EntityCollection> | null> | undefined;
|
|
15
15
|
propertyConfigs: Record<string, PropertyConfig>;
|
|
16
16
|
collectionEditable: boolean;
|
|
17
17
|
};
|
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@firecms/collection_editor",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "3.0.0-canary.
|
|
4
|
+
"version": "3.0.0-canary.259",
|
|
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-canary.
|
|
11
|
-
"@firecms/data_import": "^3.0.0-canary.
|
|
12
|
-
"@firecms/data_import_export": "^3.0.0-canary.
|
|
13
|
-
"@firecms/formex": "^3.0.0-canary.
|
|
14
|
-
"@firecms/schema_inference": "^3.0.0-canary.
|
|
15
|
-
"@firecms/ui": "^3.0.0-canary.
|
|
10
|
+
"@firecms/data_export": "^3.0.0-canary.259",
|
|
11
|
+
"@firecms/data_import": "^3.0.0-canary.259",
|
|
12
|
+
"@firecms/data_import_export": "^3.0.0-canary.259",
|
|
13
|
+
"@firecms/formex": "^3.0.0-canary.259",
|
|
14
|
+
"@firecms/schema_inference": "^3.0.0-canary.259",
|
|
15
|
+
"@firecms/ui": "^3.0.0-canary.259",
|
|
16
16
|
"json5": "^2.2.3",
|
|
17
17
|
"prism-react-renderer": "^2.4.1"
|
|
18
18
|
},
|
|
@@ -69,5 +69,5 @@
|
|
|
69
69
|
"publishConfig": {
|
|
70
70
|
"access": "public"
|
|
71
71
|
},
|
|
72
|
-
"gitHead": "
|
|
72
|
+
"gitHead": "a4ab5e6aacfb9e10ee8c1c72354c939fb2275ab0"
|
|
73
73
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
import { EntityCollection } from "@firecms/core";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* This function is used to infer the configuration of a collection given its path.
|
|
5
|
+
*/
|
|
3
6
|
export type CollectionInference = (path: string, collectionGroup: boolean, parentCollectionPaths: string[]) => Promise<Partial<EntityCollection> | null>;
|
|
@@ -28,6 +28,7 @@ export function EditorCollectionAction({
|
|
|
28
28
|
asChild={true}
|
|
29
29
|
title={canEditCollection ? "Edit collection" : "You don't have permissions to edit this collection"}>
|
|
30
30
|
<IconButton
|
|
31
|
+
size={"small"}
|
|
31
32
|
color={"primary"}
|
|
32
33
|
disabled={!canEditCollection}
|
|
33
34
|
onClick={canEditCollection
|
|
@@ -39,7 +40,7 @@ export function EditorCollectionAction({
|
|
|
39
40
|
existingEntities: tableController?.data ?? []
|
|
40
41
|
})
|
|
41
42
|
: undefined}>
|
|
42
|
-
<SettingsIcon/>
|
|
43
|
+
<SettingsIcon size={"small"}/>
|
|
43
44
|
</IconButton>
|
|
44
45
|
</Tooltip>;
|
|
45
46
|
|
|
@@ -48,9 +49,3 @@ export function EditorCollectionAction({
|
|
|
48
49
|
</>
|
|
49
50
|
|
|
50
51
|
}
|
|
51
|
-
|
|
52
|
-
function getObjectOrNull(o?: object): object | null {
|
|
53
|
-
if (o && Object.keys(o).length === 0)
|
|
54
|
-
return o
|
|
55
|
-
return o ?? null;
|
|
56
|
-
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { PluginFormActionProps, useAuthController, useNavigationController } from "@firecms/core";
|
|
2
|
+
import { IconButton, SettingsIcon, Tooltip, } from "@firecms/ui";
|
|
3
|
+
|
|
4
|
+
import { useCollectionEditorController } from "../useCollectionEditorController";
|
|
5
|
+
import { PersistedCollection } from "../types/persisted_collection";
|
|
6
|
+
|
|
7
|
+
export function EditorEntityAction({
|
|
8
|
+
path: fullPath,
|
|
9
|
+
parentCollectionIds,
|
|
10
|
+
collection,
|
|
11
|
+
formContext
|
|
12
|
+
}: PluginFormActionProps) {
|
|
13
|
+
|
|
14
|
+
const authController = useAuthController();
|
|
15
|
+
const navigationController = useNavigationController();
|
|
16
|
+
const collectionEditorController = useCollectionEditorController();
|
|
17
|
+
|
|
18
|
+
const parentCollection = navigationController.getCollectionFromIds(parentCollectionIds);
|
|
19
|
+
|
|
20
|
+
const canEditCollection = collectionEditorController.configPermissions
|
|
21
|
+
? collectionEditorController.configPermissions({
|
|
22
|
+
user: authController.user,
|
|
23
|
+
collection
|
|
24
|
+
}).editCollections
|
|
25
|
+
: true;
|
|
26
|
+
|
|
27
|
+
const isDirty = formContext?.formex.dirty ?? false;
|
|
28
|
+
|
|
29
|
+
const editorButton = <Tooltip
|
|
30
|
+
asChild={true}
|
|
31
|
+
title={canEditCollection ? (isDirty ? "You need to save the document before changing the schema" : "Edit schema for this form") : "You don't have permissions to edit this collection"}>
|
|
32
|
+
<IconButton
|
|
33
|
+
color={"primary"}
|
|
34
|
+
disabled={!canEditCollection || isDirty}
|
|
35
|
+
onClick={canEditCollection
|
|
36
|
+
? () => collectionEditorController?.editCollection({
|
|
37
|
+
id: collection.id,
|
|
38
|
+
fullPath,
|
|
39
|
+
parentCollectionIds,
|
|
40
|
+
parentCollection: parentCollection as PersistedCollection,
|
|
41
|
+
})
|
|
42
|
+
: undefined}>
|
|
43
|
+
<SettingsIcon size={"small"}/>
|
|
44
|
+
</IconButton>
|
|
45
|
+
</Tooltip>;
|
|
46
|
+
|
|
47
|
+
return <>
|
|
48
|
+
{editorButton}
|
|
49
|
+
</>
|
|
50
|
+
|
|
51
|
+
}
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
isPropertyBuilder,
|
|
10
10
|
MapProperty,
|
|
11
11
|
mergeDeep,
|
|
12
|
+
NavigationResult,
|
|
12
13
|
Properties,
|
|
13
14
|
PropertiesOrBuilders,
|
|
14
15
|
Property,
|
|
@@ -17,7 +18,6 @@ import {
|
|
|
17
18
|
randomString,
|
|
18
19
|
removeInitialAndTrailingSlashes,
|
|
19
20
|
removeUndefined,
|
|
20
|
-
NavigationResult,
|
|
21
21
|
useAuthController,
|
|
22
22
|
useCustomizationController,
|
|
23
23
|
useNavigationController,
|
|
@@ -57,6 +57,7 @@ import { cleanPropertiesFromImport } from "./import/clean_import_data";
|
|
|
57
57
|
import { PersistedCollection } from "../../types/persisted_collection";
|
|
58
58
|
import { Formex, FormexController, useCreateFormex } from "@firecms/formex";
|
|
59
59
|
import { getFullIdPath } from "./util";
|
|
60
|
+
import { EntityActionsEditTab } from "./EntityActionsEditTab";
|
|
60
61
|
|
|
61
62
|
export interface CollectionEditorDialogProps {
|
|
62
63
|
open: boolean;
|
|
@@ -140,7 +141,8 @@ type EditorView = "welcome"
|
|
|
140
141
|
| "properties"
|
|
141
142
|
| "loading"
|
|
142
143
|
| "extra_view"
|
|
143
|
-
| "subcollections"
|
|
144
|
+
| "subcollections"
|
|
145
|
+
| "custom_actions";
|
|
144
146
|
|
|
145
147
|
export function CollectionEditor(props: CollectionEditorDialogProps & {
|
|
146
148
|
handleCancel: () => void,
|
|
@@ -325,10 +327,10 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
325
327
|
|
|
326
328
|
};
|
|
327
329
|
|
|
328
|
-
const doCollectionInference = (collection: PersistedCollection<any>) => {
|
|
330
|
+
const doCollectionInference = collectionInference ? (collection: PersistedCollection<any>) => {
|
|
329
331
|
if (!collectionInference) return undefined;
|
|
330
332
|
return collectionInference?.(collection.path, collection.collectionGroup ?? false, parentPaths ?? []);
|
|
331
|
-
};
|
|
333
|
+
} : undefined;
|
|
332
334
|
|
|
333
335
|
const inferCollectionFromData = async (newCollection: PersistedCollection<M>) => {
|
|
334
336
|
|
|
@@ -569,6 +571,9 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
569
571
|
<Tab value={"subcollections"}>
|
|
570
572
|
Additional views
|
|
571
573
|
</Tab>
|
|
574
|
+
<Tab value={"custom_actions"}>
|
|
575
|
+
Custom actions
|
|
576
|
+
</Tab>
|
|
572
577
|
</Tabs>}
|
|
573
578
|
|
|
574
579
|
<form noValidate
|
|
@@ -645,6 +650,9 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
645
650
|
</div>}
|
|
646
651
|
</CollectionDetailsForm>}
|
|
647
652
|
|
|
653
|
+
{currentView === "custom_actions" && collection &&
|
|
654
|
+
<EntityActionsEditTab collection={collection}/>}
|
|
655
|
+
|
|
648
656
|
{currentView === "subcollections" && collection &&
|
|
649
657
|
<SubcollectionsEditTab
|
|
650
658
|
parentCollection={parentCollection}
|
|
@@ -687,6 +695,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
687
695
|
{isNewCollection && includeTemplates && currentView === "import_data_mapping" &&
|
|
688
696
|
<Button variant={"text"}
|
|
689
697
|
type="button"
|
|
698
|
+
color={"primary"}
|
|
690
699
|
onClick={() => {
|
|
691
700
|
importConfig.setInUse(false);
|
|
692
701
|
return setCurrentView("welcome");
|
|
@@ -698,6 +707,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
698
707
|
{isNewCollection && includeTemplates && currentView === "import_data_preview" &&
|
|
699
708
|
<Button variant={"text"}
|
|
700
709
|
type="button"
|
|
710
|
+
color={"primary"}
|
|
701
711
|
onClick={() => {
|
|
702
712
|
setCurrentView("import_data_mapping");
|
|
703
713
|
}}>
|
|
@@ -707,6 +717,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
707
717
|
|
|
708
718
|
{isNewCollection && includeTemplates && currentView === "details" &&
|
|
709
719
|
<Button variant={"text"}
|
|
720
|
+
color={"primary"}
|
|
710
721
|
type="button"
|
|
711
722
|
onClick={() => setCurrentView("welcome")}>
|
|
712
723
|
<ArrowBackIcon/>
|
|
@@ -715,12 +726,14 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
715
726
|
|
|
716
727
|
{isNewCollection && currentView === "properties" && <Button variant={"text"}
|
|
717
728
|
type="button"
|
|
729
|
+
color={"primary"}
|
|
718
730
|
onClick={() => setCurrentView("details")}>
|
|
719
731
|
<ArrowBackIcon/>
|
|
720
732
|
Back
|
|
721
733
|
</Button>}
|
|
722
734
|
|
|
723
735
|
<Button variant={"text"}
|
|
736
|
+
color={"primary"}
|
|
724
737
|
onClick={() => {
|
|
725
738
|
handleCancel();
|
|
726
739
|
}}>
|
|
@@ -89,6 +89,11 @@ export function CollectionEditorWelcomeView({
|
|
|
89
89
|
{suggestion}
|
|
90
90
|
</Chip>
|
|
91
91
|
))}
|
|
92
|
+
{(filteredPathSuggestions ?? []).length === 0 && !loadingPathSuggestions && <Typography
|
|
93
|
+
variant={"caption"}
|
|
94
|
+
color={"secondary"}>
|
|
95
|
+
No existing paths found
|
|
96
|
+
</Typography>}
|
|
92
97
|
|
|
93
98
|
</div>
|
|
94
99
|
|
|
@@ -24,7 +24,6 @@ import {
|
|
|
24
24
|
DebouncedTextField,
|
|
25
25
|
defaultBorderMixin,
|
|
26
26
|
IconButton,
|
|
27
|
-
Paper,
|
|
28
27
|
Tooltip,
|
|
29
28
|
Typography,
|
|
30
29
|
} from "@firecms/ui";
|
|
@@ -45,7 +44,7 @@ type CollectionEditorFormProps = {
|
|
|
45
44
|
extraIcon: React.ReactNode;
|
|
46
45
|
getUser?: (uid: string) => User | null;
|
|
47
46
|
getData?: () => Promise<object[]>;
|
|
48
|
-
doCollectionInference
|
|
47
|
+
doCollectionInference?: (collection: PersistedCollection) => Promise<Partial<EntityCollection> | null> | undefined;
|
|
49
48
|
propertyConfigs: Record<string, PropertyConfig>;
|
|
50
49
|
collectionEditable: boolean;
|
|
51
50
|
};
|
|
@@ -108,6 +107,8 @@ export function CollectionPropertiesEditorForm({
|
|
|
108
107
|
return;
|
|
109
108
|
|
|
110
109
|
setInferringProperties(true);
|
|
110
|
+
|
|
111
|
+
console.debug("CollectionEditor: inferring properties from data", doCollectionInference, values);
|
|
111
112
|
// @ts-ignore
|
|
112
113
|
doCollectionInference(values)
|
|
113
114
|
.then((newCollection) => {
|
|
@@ -368,6 +369,7 @@ export function CollectionPropertiesEditorForm({
|
|
|
368
369
|
asChild={true}>
|
|
369
370
|
<Button
|
|
370
371
|
variant={"outlined"}
|
|
372
|
+
color={"primary"}
|
|
371
373
|
onClick={() => setNewPropertyDialogOpen(true)}>
|
|
372
374
|
<AddIcon/>
|
|
373
375
|
</Button>
|
|
@@ -436,6 +438,7 @@ export function CollectionPropertiesEditorForm({
|
|
|
436
438
|
: "Select a property to edit it"}
|
|
437
439
|
</Typography>
|
|
438
440
|
<Button variant={"outlined"}
|
|
441
|
+
color={"primary"}
|
|
439
442
|
onClick={() => setNewPropertyDialogOpen(true)}
|
|
440
443
|
>
|
|
441
444
|
<AddIcon/>
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {
|
|
3
|
+
ConfirmationDialog,
|
|
4
|
+
EntityAction,
|
|
5
|
+
EntityCollection,
|
|
6
|
+
resolveEntityAction,
|
|
7
|
+
useCustomizationController
|
|
8
|
+
} from "@firecms/core";
|
|
9
|
+
import {
|
|
10
|
+
AddIcon,
|
|
11
|
+
Alert,
|
|
12
|
+
Button,
|
|
13
|
+
Container,
|
|
14
|
+
DeleteIcon,
|
|
15
|
+
IconButton,
|
|
16
|
+
Paper,
|
|
17
|
+
Table,
|
|
18
|
+
TableBody,
|
|
19
|
+
TableCell,
|
|
20
|
+
TableRow,
|
|
21
|
+
Tooltip,
|
|
22
|
+
Typography,
|
|
23
|
+
} from "@firecms/ui";
|
|
24
|
+
import { PersistedCollection } from "../../types/persisted_collection";
|
|
25
|
+
import { useFormex } from "@firecms/formex";
|
|
26
|
+
import { EntityActionsSelectDialog } from "./EntityActionsSelectDialog";
|
|
27
|
+
|
|
28
|
+
export function EntityActionsEditTab({
|
|
29
|
+
collection,
|
|
30
|
+
}: {
|
|
31
|
+
collection: PersistedCollection,
|
|
32
|
+
}) {
|
|
33
|
+
|
|
34
|
+
const { entityActions: contextEntityActions } = useCustomizationController();
|
|
35
|
+
|
|
36
|
+
const [addEntityActionDialogOpen, setAddEntityActionDialogOpen] = React.useState<boolean>(false);
|
|
37
|
+
const [actionToDelete, setActionToDelete] = React.useState<string | undefined>();
|
|
38
|
+
|
|
39
|
+
const {
|
|
40
|
+
values,
|
|
41
|
+
setFieldValue
|
|
42
|
+
} = useFormex<EntityCollection>();
|
|
43
|
+
|
|
44
|
+
const resolvedEntityActions = values.entityActions?.filter((e): e is string => typeof e === "string")
|
|
45
|
+
.map(e => resolveEntityAction(e, contextEntityActions))
|
|
46
|
+
.filter(Boolean) as EntityAction<any>[] ?? [];
|
|
47
|
+
const hardCodedEntityActions = collection.entityActions?.filter((e): e is EntityAction<any> => typeof e !== "string") ?? [];
|
|
48
|
+
const totalEntityActions = resolvedEntityActions.length + hardCodedEntityActions.length;
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<div className={"overflow-auto my-auto"}>
|
|
52
|
+
<Container maxWidth={"2xl"} className={"flex flex-col gap-4 p-8 m-auto"}>
|
|
53
|
+
<div className={"flex flex-col gap-16"}>
|
|
54
|
+
<div className={"flex-grow flex flex-col gap-4 items-start"}>
|
|
55
|
+
<Typography variant={"h5"}>
|
|
56
|
+
Custom actions
|
|
57
|
+
</Typography>
|
|
58
|
+
|
|
59
|
+
{totalEntityActions === 0 &&
|
|
60
|
+
<Alert action={<Button variant="text"
|
|
61
|
+
size={"small"}
|
|
62
|
+
href={"https://firecms.co/docs/custom_actions"}
|
|
63
|
+
component={"a"}
|
|
64
|
+
rel="noopener noreferrer"
|
|
65
|
+
target="_blank">More info</Button>}>
|
|
66
|
+
Define your own custom actions by uploading them with the CLI.
|
|
67
|
+
</Alert>
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
{<>
|
|
71
|
+
<Paper className={"flex flex-col gap-4 p-2 w-full"}>
|
|
72
|
+
<Table>
|
|
73
|
+
<TableBody>
|
|
74
|
+
{resolvedEntityActions.map((action) => (
|
|
75
|
+
<TableRow key={action.key}>
|
|
76
|
+
<TableCell
|
|
77
|
+
align="left">
|
|
78
|
+
<Typography variant={"subtitle2"} className={"flex-grow"}>
|
|
79
|
+
{action.name}
|
|
80
|
+
</Typography>
|
|
81
|
+
</TableCell>
|
|
82
|
+
<TableCell
|
|
83
|
+
align="right">
|
|
84
|
+
<Tooltip title={"Remove"}
|
|
85
|
+
asChild={true}>
|
|
86
|
+
<IconButton size="small"
|
|
87
|
+
onClick={(e) => {
|
|
88
|
+
e.preventDefault();
|
|
89
|
+
e.stopPropagation();
|
|
90
|
+
setActionToDelete(action.key);
|
|
91
|
+
}}
|
|
92
|
+
color="inherit">
|
|
93
|
+
<DeleteIcon size={"small"}/>
|
|
94
|
+
</IconButton>
|
|
95
|
+
</Tooltip>
|
|
96
|
+
</TableCell>
|
|
97
|
+
</TableRow>
|
|
98
|
+
))}
|
|
99
|
+
{hardCodedEntityActions.map((action) => (
|
|
100
|
+
<TableRow key={action.key}>
|
|
101
|
+
<TableCell
|
|
102
|
+
align="left">
|
|
103
|
+
<Typography variant={"subtitle2"} className={"flex-grow"}>
|
|
104
|
+
{action.name}
|
|
105
|
+
</Typography>
|
|
106
|
+
<Typography variant={"caption"} className={"flex-grow"}>
|
|
107
|
+
This action is defined in code with
|
|
108
|
+
key <code>{action.key}</code>
|
|
109
|
+
</Typography>
|
|
110
|
+
</TableCell>
|
|
111
|
+
</TableRow>
|
|
112
|
+
))}
|
|
113
|
+
</TableBody>
|
|
114
|
+
</Table>
|
|
115
|
+
|
|
116
|
+
<Button
|
|
117
|
+
onClick={() => {
|
|
118
|
+
setAddEntityActionDialogOpen(true);
|
|
119
|
+
}}
|
|
120
|
+
variant={"text"}
|
|
121
|
+
startIcon={<AddIcon/>}>
|
|
122
|
+
Add custom entity action
|
|
123
|
+
</Button>
|
|
124
|
+
</Paper>
|
|
125
|
+
|
|
126
|
+
</>}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
</div>
|
|
132
|
+
</Container>
|
|
133
|
+
|
|
134
|
+
<div style={{ height: "52px" }}/>
|
|
135
|
+
|
|
136
|
+
{actionToDelete &&
|
|
137
|
+
<ConfirmationDialog open={Boolean(actionToDelete)}
|
|
138
|
+
onAccept={() => {
|
|
139
|
+
setFieldValue("entityActions", values.entityActions?.filter(e => e !== actionToDelete));
|
|
140
|
+
setActionToDelete(undefined);
|
|
141
|
+
}}
|
|
142
|
+
onCancel={() => setActionToDelete(undefined)}
|
|
143
|
+
title={<>Remove this action?</>}
|
|
144
|
+
body={<>This will <b>not
|
|
145
|
+
delete any data</b>, only
|
|
146
|
+
the action in the CMS</>}/>}
|
|
147
|
+
|
|
148
|
+
<EntityActionsSelectDialog
|
|
149
|
+
open={addEntityActionDialogOpen}
|
|
150
|
+
onClose={(selectedActionKey) => {
|
|
151
|
+
if (selectedActionKey) {
|
|
152
|
+
console.log("Selected action key:", selectedActionKey);
|
|
153
|
+
const value = [...(values.entityActions ?? []), selectedActionKey]
|
|
154
|
+
// only actions that are defined in the registry
|
|
155
|
+
.filter((e): e is string => typeof e === "string" && (contextEntityActions ?? []).some(action => action.key === e));
|
|
156
|
+
;
|
|
157
|
+
setFieldValue("entityActions", value);
|
|
158
|
+
}
|
|
159
|
+
setAddEntityActionDialogOpen(false);
|
|
160
|
+
}}/>
|
|
161
|
+
</div>
|
|
162
|
+
);
|
|
163
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { useCustomizationController } from "@firecms/core";
|
|
2
|
+
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Typography } from "@firecms/ui";
|
|
3
|
+
import React from "react";
|
|
4
|
+
|
|
5
|
+
export function EntityActionsSelectDialog({
|
|
6
|
+
open,
|
|
7
|
+
onClose
|
|
8
|
+
}: { open: boolean, onClose: (selectedActionKey?: string) => void }) {
|
|
9
|
+
const {
|
|
10
|
+
entityActions
|
|
11
|
+
} = useCustomizationController();
|
|
12
|
+
|
|
13
|
+
return <Dialog
|
|
14
|
+
maxWidth={"md"}
|
|
15
|
+
open={open}>
|
|
16
|
+
<DialogTitle>Select custom action</DialogTitle>
|
|
17
|
+
<DialogContent className={"flex flex-col gap-4"}>
|
|
18
|
+
{entityActions?.map((action) => {
|
|
19
|
+
return <Button
|
|
20
|
+
key={action.key}
|
|
21
|
+
onClick={() => onClose(action.key)}
|
|
22
|
+
fullWidth
|
|
23
|
+
variant={"text"}
|
|
24
|
+
>
|
|
25
|
+
{action.name} ({action.key})
|
|
26
|
+
</Button>;
|
|
27
|
+
})}
|
|
28
|
+
{(entityActions ?? []).length === 0 &&
|
|
29
|
+
<Typography variant={"body2"}>
|
|
30
|
+
No custom actions defined. Define your custom actions in the customization settings, before using this
|
|
31
|
+
dialog.
|
|
32
|
+
</Typography>
|
|
33
|
+
}
|
|
34
|
+
</DialogContent>
|
|
35
|
+
<DialogActions>
|
|
36
|
+
<Button variant={"outlined"}
|
|
37
|
+
color={"primary"}
|
|
38
|
+
onClick={() => onClose()}>Cancel</Button>
|
|
39
|
+
</DialogActions>
|
|
40
|
+
</Dialog>
|
|
41
|
+
}
|
|
@@ -27,12 +27,15 @@ export function EntityCustomViewsSelectDialog({
|
|
|
27
27
|
})}
|
|
28
28
|
{(entityViews ?? []).length === 0 &&
|
|
29
29
|
<Typography variant={"body2"}>
|
|
30
|
-
No custom views defined
|
|
30
|
+
No custom views defined. Define your custom views in the customization settings, before using this
|
|
31
|
+
dialog.
|
|
31
32
|
</Typography>
|
|
32
33
|
}
|
|
33
34
|
</DialogContent>
|
|
34
35
|
<DialogActions>
|
|
35
|
-
<Button variant={"outlined"}
|
|
36
|
+
<Button variant={"outlined"}
|
|
37
|
+
color={"primary"}
|
|
38
|
+
onClick={() => onClose()}>Cancel</Button>
|
|
36
39
|
</DialogActions>
|
|
37
40
|
</Dialog>
|
|
38
41
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EntityCollection, isEmptyObject, useSnackbarController } from "@firecms/core";
|
|
2
|
-
import { Button, ContentCopyIcon, Dialog, DialogActions, DialogContent, DialogTitle, Typography
|
|
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"
|
|
@@ -59,12 +59,13 @@ export function GetCodeDialog({
|
|
|
59
59
|
<Button
|
|
60
60
|
variant={"text"}
|
|
61
61
|
size={"small"}
|
|
62
|
+
color={"primary"}
|
|
62
63
|
onClick={(e) => {
|
|
63
64
|
e.stopPropagation();
|
|
64
65
|
e.preventDefault();
|
|
65
66
|
snackbarController.open({
|
|
66
67
|
type: "success",
|
|
67
|
-
message:
|
|
68
|
+
message: "Copied"
|
|
68
69
|
})
|
|
69
70
|
return navigator.clipboard.writeText(code);
|
|
70
71
|
}}>
|
|
@@ -133,7 +134,8 @@ function collectionToCode(collection: EntityCollection): object {
|
|
|
133
134
|
.map(([key, value]) => ({
|
|
134
135
|
[key]: propertyCleanup(value)
|
|
135
136
|
}))
|
|
136
|
-
.reduce((a, b) => ({ ...a,
|
|
137
|
+
.reduce((a, b) => ({ ...a,
|
|
138
|
+
...b }), {}),
|
|
137
139
|
subcollections: (collection.subcollections ?? []).map(collectionToCode)
|
|
138
140
|
}
|
|
139
141
|
|
|
@@ -37,8 +37,12 @@ export function UnsavedChangesDialog({
|
|
|
37
37
|
</DialogContent>
|
|
38
38
|
|
|
39
39
|
<DialogActions>
|
|
40
|
-
<Button variant="text"
|
|
41
|
-
|
|
40
|
+
<Button variant="text"
|
|
41
|
+
color={"primary"}
|
|
42
|
+
onClick={handleCancel} autoFocus> Cancel </Button>
|
|
43
|
+
<Button
|
|
44
|
+
color={"primary"}
|
|
45
|
+
onClick={handleOk}> Ok </Button>
|
|
42
46
|
</DialogActions>
|
|
43
47
|
</Dialog>
|
|
44
48
|
);
|
|
@@ -14,6 +14,7 @@ import { AddIcon, Button, Paper, Typography } from "@firecms/ui";
|
|
|
14
14
|
import { useCollectionEditorController } from "./useCollectionEditorController";
|
|
15
15
|
import { EditorCollectionActionStart } from "./ui/EditorCollectionActionStart";
|
|
16
16
|
import { NewCollectionCard } from "./ui/NewCollectionCard";
|
|
17
|
+
import { EditorEntityAction } from "./ui/EditorEntityAction";
|
|
17
18
|
|
|
18
19
|
export interface CollectionConfigControllerProps<EC extends PersistedCollection = PersistedCollection, USER extends User = User> {
|
|
19
20
|
|
|
@@ -107,6 +108,9 @@ export function useCollectionEditorPlugin<EC extends PersistedCollection = Persi
|
|
|
107
108
|
CollectionActions: EditorCollectionAction,
|
|
108
109
|
HeaderAction: CollectionViewHeaderAction,
|
|
109
110
|
AddColumnComponent: PropertyAddColumnComponent
|
|
111
|
+
},
|
|
112
|
+
form: {
|
|
113
|
+
ActionsTop: EditorEntityAction,
|
|
110
114
|
}
|
|
111
115
|
};
|
|
112
116
|
}
|