@firecms/core 3.0.0-canary.4 → 3.0.0-canary.41
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/README.md +2 -2
- package/dist/components/ClearFilterSortButton.d.ts +5 -0
- package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +11 -11
- package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +2 -2
- package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +2 -2
- package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +1 -4
- package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +12 -3
- package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +11 -0
- package/dist/components/EntityCollectionView/useSelectionController.d.ts +2 -0
- package/dist/components/EntityPreview.d.ts +25 -7
- package/dist/components/EntityView.d.ts +11 -0
- package/dist/components/FieldCaption.d.ts +5 -0
- package/dist/components/HomePage/NavigationCard.d.ts +8 -0
- package/dist/components/HomePage/{NavigationCollectionCard.d.ts → NavigationCardBinding.d.ts} +2 -2
- package/dist/components/HomePage/SmallNavigationCard.d.ts +6 -0
- package/dist/components/HomePage/index.d.ts +3 -1
- package/dist/components/VirtualTable/VirtualTableProps.d.ts +1 -1
- package/dist/components/index.d.ts +4 -3
- package/dist/contexts/AuthControllerContext.d.ts +1 -1
- package/dist/{internal/EntityView.d.ts → core/EntityEditView.d.ts} +2 -2
- package/dist/core/SideEntityView.d.ts +7 -0
- package/dist/core/index.d.ts +0 -2
- package/dist/form/EntityForm.d.ts +1 -1
- package/dist/form/components/ErrorFocus.d.ts +1 -1
- package/dist/form/components/StorageItemPreview.d.ts +3 -2
- package/dist/form/components/StorageUploadProgress.d.ts +1 -1
- package/dist/form/components/index.d.ts +1 -0
- package/dist/form/field_bindings/KeyValueFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +4 -3
- package/dist/form/field_bindings/TextFieldBinding.d.ts +2 -2
- package/dist/form/index.d.ts +1 -0
- package/dist/form/validation.d.ts +1 -1
- package/dist/hooks/data/delete.d.ts +2 -2
- package/dist/hooks/data/save.d.ts +1 -1
- package/dist/hooks/data/useDataSource.d.ts +2 -2
- package/dist/hooks/data/useEntityFetch.d.ts +3 -3
- package/dist/hooks/index.d.ts +3 -1
- package/dist/{core → hooks}/useBuildModeController.d.ts +1 -1
- package/dist/hooks/useBuildNavigationController.d.ts +6 -4
- package/dist/hooks/useProjectLog.d.ts +6 -2
- package/dist/hooks/useStorageSource.d.ts +2 -2
- package/dist/hooks/useValidateAuthenticator.d.ts +25 -0
- package/dist/index.es.js +8258 -7767
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +5 -5
- package/dist/index.umd.js.map +1 -1
- package/dist/internal/useBuildDataSource.d.ts +4 -0
- package/dist/preview/PropertyPreview.d.ts +1 -1
- package/dist/preview/PropertyPreviewProps.d.ts +1 -4
- package/dist/preview/components/BooleanPreview.d.ts +5 -1
- package/dist/preview/components/EnumValuesChip.d.ts +1 -1
- package/dist/preview/components/ReferencePreview.d.ts +1 -7
- package/dist/types/analytics.d.ts +1 -1
- package/dist/types/auth.d.ts +37 -1
- package/dist/types/collections.d.ts +22 -5
- package/dist/types/datasource.d.ts +1 -1
- package/dist/types/entities.d.ts +1 -1
- package/dist/types/entity_callbacks.d.ts +2 -2
- package/dist/types/entity_overrides.d.ts +6 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/navigation.d.ts +14 -13
- package/dist/types/permissions.d.ts +5 -1
- package/dist/types/plugins.d.ts +20 -20
- package/dist/types/properties.d.ts +2 -2
- package/dist/types/property_config.d.ts +2 -2
- package/dist/types/roles.d.ts +31 -0
- package/dist/types/storage.d.ts +11 -3
- package/dist/types/user.d.ts +5 -0
- package/dist/util/collections.d.ts +9 -1
- package/dist/util/entities.d.ts +1 -1
- package/dist/util/icons.d.ts +8 -2
- package/dist/util/navigation_utils.d.ts +2 -2
- package/dist/util/permissions.d.ts +4 -4
- package/dist/util/references.d.ts +4 -2
- package/dist/util/resolutions.d.ts +6 -6
- package/dist/util/useTraceUpdate.d.ts +1 -0
- package/package.json +27 -24
- package/src/components/ClearFilterSortButton.tsx +41 -0
- package/src/components/DeleteEntityDialog.tsx +4 -4
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +2 -2
- package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +268 -277
- package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +1 -1
- package/src/components/EntityCollectionTable/PropertyTableCell.tsx +13 -13
- package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +9 -16
- package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +3 -3
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +27 -32
- package/src/components/EntityCollectionTable/internal/default_entity_actions.tsx +9 -5
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +51 -52
- package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +5 -6
- package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +68 -0
- package/src/components/EntityCollectionView/useSelectionController.tsx +30 -0
- package/src/components/EntityPreview.tsx +207 -70
- package/src/components/EntityView.tsx +84 -0
- package/src/components/FieldCaption.tsx +14 -0
- package/src/components/FireCMSAppBar.tsx +8 -0
- package/src/components/HomePage/DefaultHomePage.tsx +14 -10
- package/src/components/HomePage/NavigationCard.tsx +69 -0
- package/src/components/HomePage/NavigationCardBinding.tsx +116 -0
- package/src/components/HomePage/SmallNavigationCard.tsx +45 -0
- package/src/components/HomePage/index.tsx +3 -1
- package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +3 -4
- package/src/components/ReferenceWidget.tsx +4 -4
- package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +23 -8
- package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +35 -24
- package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +35 -15
- package/src/components/VirtualTable/VirtualTable.tsx +17 -7
- package/src/components/VirtualTable/VirtualTableProps.tsx +1 -1
- package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +1 -1
- package/src/components/common/useDataSourceEntityCollectionTableController.tsx +1 -1
- package/src/components/index.tsx +4 -3
- package/src/contexts/AuthControllerContext.tsx +1 -1
- package/src/core/Drawer.tsx +66 -39
- package/src/{internal/EntityView.tsx → core/EntityEditView.tsx} +22 -39
- package/src/core/EntitySidePanel.tsx +2 -2
- package/src/core/FireCMS.tsx +18 -3
- package/src/core/NavigationRoutes.tsx +8 -0
- package/src/core/SideEntityView.tsx +38 -0
- package/src/core/field_configs.tsx +1 -2
- package/src/core/index.tsx +0 -2
- package/src/form/EntityForm.tsx +20 -12
- package/src/form/components/StorageItemPreview.tsx +5 -3
- package/src/form/components/StorageUploadProgress.tsx +6 -5
- package/src/form/components/index.tsx +1 -0
- package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +2 -3
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +12 -15
- package/src/form/field_bindings/BlockFieldBinding.tsx +2 -3
- package/src/form/field_bindings/DateTimeFieldBinding.tsx +4 -4
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +18 -18
- package/src/form/field_bindings/MapFieldBinding.tsx +17 -17
- package/src/form/field_bindings/MarkdownFieldBinding.tsx +1 -2
- package/src/form/field_bindings/MultiSelectBinding.tsx +2 -3
- package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +3 -3
- package/src/form/field_bindings/ReferenceFieldBinding.tsx +5 -3
- package/src/form/field_bindings/RepeatFieldBinding.tsx +3 -3
- package/src/form/field_bindings/SelectFieldBinding.tsx +2 -3
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +15 -6
- package/src/form/field_bindings/SwitchFieldBinding.tsx +2 -3
- package/src/form/field_bindings/TextFieldBinding.tsx +10 -9
- package/src/form/index.tsx +1 -0
- package/src/form/validation.ts +3 -4
- package/src/hooks/data/delete.ts +3 -3
- package/src/hooks/data/save.ts +1 -1
- package/src/hooks/data/useCollectionFetch.tsx +1 -1
- package/src/hooks/data/useDataSource.tsx +8 -3
- package/src/hooks/data/useEntityFetch.tsx +4 -4
- package/src/hooks/index.tsx +5 -1
- package/src/{core → hooks}/useBuildLocalConfigurationPersistence.tsx +9 -10
- package/src/{core → hooks}/useBuildModeController.tsx +12 -6
- package/src/hooks/useBuildNavigationController.tsx +197 -79
- package/src/hooks/useProjectLog.tsx +17 -7
- package/src/hooks/useReferenceDialog.tsx +2 -2
- package/src/hooks/useStorageSource.tsx +7 -2
- package/src/hooks/useValidateAuthenticator.tsx +135 -0
- package/src/internal/useBuildDataSource.ts +6 -1
- package/src/internal/useBuildSideEntityController.tsx +18 -12
- package/src/preview/PropertyPreview.tsx +1 -1
- package/src/preview/PropertyPreviewProps.tsx +1 -11
- package/src/preview/components/BooleanPreview.tsx +19 -4
- package/src/preview/components/EnumValuesChip.tsx +1 -1
- package/src/preview/components/ReferencePreview.tsx +55 -147
- package/src/preview/property_previews/StringPropertyPreview.tsx +8 -7
- package/src/types/analytics.ts +1 -0
- package/src/types/auth.tsx +50 -1
- package/src/types/collections.ts +24 -5
- package/src/types/datasource.ts +1 -1
- package/src/types/entities.ts +1 -1
- package/src/types/entity_actions.tsx +4 -0
- package/src/types/entity_callbacks.ts +2 -2
- package/src/types/entity_overrides.tsx +7 -0
- package/src/types/firecms.tsx +0 -1
- package/src/types/index.ts +2 -0
- package/src/types/navigation.ts +17 -16
- package/src/types/permissions.ts +6 -1
- package/src/types/plugins.tsx +26 -28
- package/src/types/properties.ts +3 -2
- package/src/types/property_config.tsx +2 -2
- package/src/types/roles.ts +41 -0
- package/src/types/side_entity_controller.tsx +1 -0
- package/src/types/storage.ts +12 -3
- package/src/types/user.ts +7 -0
- package/src/util/collections.ts +22 -0
- package/src/util/entities.ts +1 -1
- package/src/util/icons.tsx +11 -3
- package/src/util/navigation_utils.ts +6 -6
- package/src/util/permissions.ts +11 -8
- package/src/util/references.ts +36 -5
- package/src/util/strings.ts +2 -2
- package/src/util/useTraceUpdate.tsx +2 -1
- package/dist/internal/useLocaleConfig.d.ts +0 -1
- package/src/components/HomePage/NavigationCollectionCard.tsx +0 -146
- package/src/internal/useLocaleConfig.tsx +0 -18
- /package/dist/{components → form/components}/LabelWithIcon.d.ts +0 -0
- /package/dist/{core → hooks}/useBuildLocalConfigurationPersistence.d.ts +0 -0
- /package/src/{components → form/components}/LabelWithIcon.tsx +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useCallback, useState } from "react";
|
|
2
2
|
import equal from "react-fast-compare"
|
|
3
3
|
|
|
4
|
-
import { ReferencePreview
|
|
4
|
+
import { ReferencePreview } from "../../../preview";
|
|
5
5
|
import { CollectionSize, Entity, EntityCollection, EntityReference, FilterValues } from "../../../types";
|
|
6
6
|
|
|
7
7
|
import { getPreviewSizeFrom } from "../../../preview/util";
|
|
@@ -9,6 +9,7 @@ import { getReferenceFrom } from "../../../util";
|
|
|
9
9
|
import { useCustomizationController, useNavigationController, useReferenceDialog } from "../../../hooks";
|
|
10
10
|
import { ErrorView } from "../../ErrorView";
|
|
11
11
|
import { Button } from "@firecms/ui";
|
|
12
|
+
import { EntityPreviewContainer } from "../../EntityPreview";
|
|
12
13
|
|
|
13
14
|
type TableReferenceFieldProps = {
|
|
14
15
|
name: string;
|
|
@@ -28,7 +29,7 @@ export function TableReferenceField(props: TableReferenceFieldProps) {
|
|
|
28
29
|
|
|
29
30
|
const navigationController = useNavigationController();
|
|
30
31
|
const { path } = props;
|
|
31
|
-
const collection = navigationController.getCollection
|
|
32
|
+
const collection = navigationController.getCollection(path);
|
|
32
33
|
if (!collection) {
|
|
33
34
|
if (customizationController.components?.missingReference) {
|
|
34
35
|
return <customizationController.components.missingReference path={path}/>;
|
|
@@ -57,11 +58,6 @@ export const TableReferenceFieldSuccess = React.memo(
|
|
|
57
58
|
collection
|
|
58
59
|
} = props;
|
|
59
60
|
|
|
60
|
-
const [onHover, setOnHover] = useState(false);
|
|
61
|
-
|
|
62
|
-
const hoverTrue = useCallback(() => setOnHover(true), []);
|
|
63
|
-
const hoverFalse = useCallback(() => setOnHover(false), []);
|
|
64
|
-
|
|
65
61
|
const onSingleEntitySelected = useCallback((entity: Entity<any>) => {
|
|
66
62
|
updateValue(entity ? getReferenceFrom(entity) : null);
|
|
67
63
|
}, [updateValue]);
|
|
@@ -101,29 +97,29 @@ export const TableReferenceFieldSuccess = React.memo(
|
|
|
101
97
|
onClick={disabled ? undefined : handleOpen}
|
|
102
98
|
size={getPreviewSizeFrom(size)}
|
|
103
99
|
reference={internalValue as EntityReference}
|
|
104
|
-
|
|
100
|
+
hover={!disabled}
|
|
105
101
|
disabled={!path}
|
|
106
102
|
previewProperties={previewProperties}
|
|
107
103
|
/>;
|
|
108
104
|
else
|
|
109
|
-
return <
|
|
105
|
+
return <EntityPreviewContainer
|
|
110
106
|
onClick={disabled ? undefined : handleOpen}
|
|
111
107
|
size={getPreviewSizeFrom(size)}>
|
|
112
108
|
<ErrorView title="Value is not a reference." error={"Click to edit"}/>
|
|
113
|
-
</
|
|
109
|
+
</EntityPreviewContainer>;
|
|
114
110
|
};
|
|
115
111
|
|
|
116
112
|
const buildMultipleReferenceField = () => {
|
|
117
113
|
if (Array.isArray(internalValue))
|
|
118
114
|
return <>
|
|
119
115
|
{internalValue.map((reference, index) =>
|
|
120
|
-
<div className="
|
|
116
|
+
<div className="w-full my-0.5"
|
|
121
117
|
key={`preview_array_ref_${name}_${index}`}>
|
|
122
118
|
<ReferencePreview
|
|
123
119
|
onClick={disabled ? undefined : handleOpen}
|
|
124
120
|
size={"tiny"}
|
|
125
121
|
reference={reference}
|
|
126
|
-
|
|
122
|
+
hover={!disabled}
|
|
127
123
|
disabled={!path}
|
|
128
124
|
previewProperties={previewProperties}
|
|
129
125
|
/>
|
|
@@ -139,10 +135,7 @@ export const TableReferenceFieldSuccess = React.memo(
|
|
|
139
135
|
return <ErrorView error={"The specified collection does not exist"}/>;
|
|
140
136
|
|
|
141
137
|
return (
|
|
142
|
-
<div className="w-full"
|
|
143
|
-
onMouseEnter={hoverTrue}
|
|
144
|
-
onMouseMove={hoverTrue}
|
|
145
|
-
onMouseLeave={hoverFalse}>
|
|
138
|
+
<div className="w-full group">
|
|
146
139
|
|
|
147
140
|
{internalValue && !multiselect && buildSingleReferenceField()}
|
|
148
141
|
|
|
@@ -51,7 +51,7 @@ export function TableStorageUpload(props: {
|
|
|
51
51
|
entity,
|
|
52
52
|
path,
|
|
53
53
|
previewSize,
|
|
54
|
-
updateValue
|
|
54
|
+
updateValue,
|
|
55
55
|
} = props;
|
|
56
56
|
|
|
57
57
|
const storageSource = useStorageSource();
|
|
@@ -137,7 +137,7 @@ function StorageUpload({
|
|
|
137
137
|
storage,
|
|
138
138
|
onFilesAdded,
|
|
139
139
|
onFileUploadComplete,
|
|
140
|
-
storagePathBuilder
|
|
140
|
+
storagePathBuilder,
|
|
141
141
|
}: StorageUploadProps) {
|
|
142
142
|
|
|
143
143
|
const [onHover, setOnHover] = useState(false);
|
|
@@ -293,7 +293,7 @@ export function TableStorageItemPreview({
|
|
|
293
293
|
|
|
294
294
|
return (
|
|
295
295
|
<div
|
|
296
|
-
className={"relative
|
|
296
|
+
className={"relative p-2 max-w-full"}
|
|
297
297
|
>
|
|
298
298
|
|
|
299
299
|
{value &&
|
|
@@ -16,20 +16,27 @@ import { useLargeLayout } from "../../../hooks";
|
|
|
16
16
|
|
|
17
17
|
interface CollectionTableToolbarProps {
|
|
18
18
|
size: CollectionSize;
|
|
19
|
-
filterIsSet: boolean;
|
|
20
19
|
loading: boolean;
|
|
21
|
-
forceFilter?: boolean;
|
|
22
20
|
actionsStart?: React.ReactNode;
|
|
23
21
|
actions?: React.ReactNode;
|
|
24
22
|
title?: React.ReactNode,
|
|
25
23
|
onTextSearchClick?: () => void;
|
|
26
24
|
onTextSearch?: (searchString?: string) => void;
|
|
27
25
|
onSizeChanged: (size: CollectionSize) => void;
|
|
28
|
-
clearFilter?: () => void;
|
|
29
26
|
textSearchLoading?: boolean;
|
|
30
27
|
}
|
|
31
28
|
|
|
32
|
-
export function CollectionTableToolbar(
|
|
29
|
+
export function CollectionTableToolbar({
|
|
30
|
+
actions,
|
|
31
|
+
actionsStart,
|
|
32
|
+
loading,
|
|
33
|
+
onSizeChanged,
|
|
34
|
+
onTextSearch,
|
|
35
|
+
onTextSearchClick,
|
|
36
|
+
size,
|
|
37
|
+
textSearchLoading,
|
|
38
|
+
title
|
|
39
|
+
}: CollectionTableToolbarProps) {
|
|
33
40
|
|
|
34
41
|
const searchInputRef = React.useRef<HTMLInputElement>(null);
|
|
35
42
|
const largeLayout = useLargeLayout();
|
|
@@ -37,30 +44,20 @@ export function CollectionTableToolbar(props: CollectionTableToolbarProps) {
|
|
|
37
44
|
const searchLoading = React.useRef<boolean>(false);
|
|
38
45
|
|
|
39
46
|
useEffect(() => {
|
|
40
|
-
if (searchInputRef.current && searchLoading.current && !
|
|
47
|
+
if (searchInputRef.current && searchLoading.current && !textSearchLoading) {
|
|
41
48
|
searchInputRef.current.focus();
|
|
42
49
|
}
|
|
43
|
-
searchLoading.current =
|
|
44
|
-
}, [
|
|
45
|
-
|
|
46
|
-
const clearFilterButton = !props.forceFilter && props.filterIsSet && props.clearFilter &&
|
|
47
|
-
<Button
|
|
48
|
-
variant={"outlined"}
|
|
49
|
-
className="h-fit-content"
|
|
50
|
-
aria-label="filter clear"
|
|
51
|
-
onClick={props.clearFilter}
|
|
52
|
-
size="small">
|
|
53
|
-
<FilterListOffIcon/>
|
|
54
|
-
Clear filter
|
|
55
|
-
</Button>;
|
|
50
|
+
searchLoading.current = textSearchLoading ?? false;
|
|
51
|
+
}, [textSearchLoading]);
|
|
52
|
+
|
|
56
53
|
|
|
57
54
|
const sizeSelect = (
|
|
58
55
|
<Tooltip title={"Table row size"} side={"right"} sideOffset={4}>
|
|
59
56
|
<Select
|
|
60
|
-
value={
|
|
57
|
+
value={size as string}
|
|
61
58
|
className="w-16 h-10"
|
|
62
59
|
size={"small"}
|
|
63
|
-
onValueChange={(v) =>
|
|
60
|
+
onValueChange={(v) => onSizeChanged(v as CollectionSize)}
|
|
64
61
|
renderValue={(v) => <div className={"font-medium"}>{v.toUpperCase()}</div>}
|
|
65
62
|
>
|
|
66
63
|
{["xs", "s", "m", "l", "xl"].map((size) => (
|
|
@@ -78,36 +75,34 @@ export function CollectionTableToolbar(props: CollectionTableToolbarProps) {
|
|
|
78
75
|
|
|
79
76
|
<div className="flex items-center gap-2 md:mr-4 mr-2">
|
|
80
77
|
|
|
81
|
-
{
|
|
82
|
-
{
|
|
78
|
+
{title && <div className={"hidden lg:block"}>
|
|
79
|
+
{title}
|
|
83
80
|
</div>}
|
|
84
81
|
|
|
85
82
|
{sizeSelect}
|
|
86
83
|
|
|
87
|
-
{
|
|
88
|
-
|
|
89
|
-
{clearFilterButton}
|
|
84
|
+
{actionsStart}
|
|
90
85
|
|
|
91
86
|
</div>
|
|
92
87
|
|
|
93
88
|
<div className="flex items-center gap-2">
|
|
94
89
|
|
|
95
90
|
{largeLayout && <div className="w-[22px]">
|
|
96
|
-
{
|
|
91
|
+
{loading &&
|
|
97
92
|
<CircularProgress size={"small"}/>}
|
|
98
93
|
</div>}
|
|
99
94
|
|
|
100
|
-
{(
|
|
95
|
+
{(onTextSearch || onTextSearchClick) &&
|
|
101
96
|
<SearchBar
|
|
102
97
|
key={"search-bar"}
|
|
103
98
|
inputRef={searchInputRef}
|
|
104
|
-
loading={
|
|
105
|
-
disabled={Boolean(
|
|
106
|
-
onClick={
|
|
107
|
-
onTextSearch={
|
|
99
|
+
loading={textSearchLoading}
|
|
100
|
+
disabled={Boolean(onTextSearchClick)}
|
|
101
|
+
onClick={onTextSearchClick}
|
|
102
|
+
onTextSearch={onTextSearchClick ? undefined : onTextSearch}
|
|
108
103
|
expandable={true}/>}
|
|
109
104
|
|
|
110
|
-
{
|
|
105
|
+
{actions}
|
|
111
106
|
|
|
112
107
|
</div>
|
|
113
108
|
|
|
@@ -9,21 +9,23 @@ export const editEntityAction: EntityAction = {
|
|
|
9
9
|
onClick({
|
|
10
10
|
entity,
|
|
11
11
|
collection,
|
|
12
|
+
fullPath,
|
|
12
13
|
context,
|
|
13
14
|
highlightEntity,
|
|
14
|
-
unhighlightEntity
|
|
15
|
+
unhighlightEntity,
|
|
15
16
|
}): Promise<void> {
|
|
16
17
|
highlightEntity?.(entity);
|
|
17
18
|
context.analyticsController?.onAnalyticsEvent?.("entity_click", {
|
|
18
19
|
path: entity.path,
|
|
19
20
|
entityId: entity.id
|
|
20
21
|
});
|
|
22
|
+
const path = collection?.collectionGroup ? entity.path : (fullPath ?? entity.path);
|
|
21
23
|
context.sideEntityController.open({
|
|
22
24
|
entityId: entity.id,
|
|
23
|
-
path
|
|
25
|
+
path,
|
|
24
26
|
collection,
|
|
25
27
|
updateUrl: true,
|
|
26
|
-
onClose: () => unhighlightEntity?.(entity)
|
|
28
|
+
onClose: () => unhighlightEntity?.(entity),
|
|
27
29
|
});
|
|
28
30
|
return Promise.resolve(undefined);
|
|
29
31
|
}
|
|
@@ -37,7 +39,7 @@ export const copyEntityAction: EntityAction = {
|
|
|
37
39
|
collection,
|
|
38
40
|
context,
|
|
39
41
|
highlightEntity,
|
|
40
|
-
unhighlightEntity
|
|
42
|
+
unhighlightEntity,
|
|
41
43
|
}): Promise<void> {
|
|
42
44
|
highlightEntity?.(entity);
|
|
43
45
|
context.analyticsController?.onAnalyticsEvent?.("copy_entity_click", {
|
|
@@ -50,11 +52,12 @@ export const copyEntityAction: EntityAction = {
|
|
|
50
52
|
copy: true,
|
|
51
53
|
collection,
|
|
52
54
|
updateUrl: true,
|
|
53
|
-
onClose: () => unhighlightEntity?.(entity)
|
|
55
|
+
onClose: () => unhighlightEntity?.(entity),
|
|
54
56
|
});
|
|
55
57
|
return Promise.resolve(undefined);
|
|
56
58
|
}
|
|
57
59
|
}
|
|
60
|
+
|
|
58
61
|
export const archiveEntityAction: EntityAction = {
|
|
59
62
|
icon: <ArchiveIcon/>,
|
|
60
63
|
name: "Archive",
|
|
@@ -69,6 +72,7 @@ export const archiveEntityAction: EntityAction = {
|
|
|
69
72
|
return Promise.resolve(undefined);
|
|
70
73
|
}
|
|
71
74
|
}
|
|
75
|
+
|
|
72
76
|
export const openWebsiteAction: EntityAction = {
|
|
73
77
|
icon: <OpenInNewIcon/>,
|
|
74
78
|
name: "See in website",
|
|
@@ -12,8 +12,7 @@ import {
|
|
|
12
12
|
PartialEntityCollection,
|
|
13
13
|
PropertyOrBuilder,
|
|
14
14
|
ResolvedProperty,
|
|
15
|
-
SaveEntityProps
|
|
16
|
-
SelectionController
|
|
15
|
+
SaveEntityProps
|
|
17
16
|
} from "../../types";
|
|
18
17
|
import {
|
|
19
18
|
EntityCollectionRowActions,
|
|
@@ -25,7 +24,6 @@ import {
|
|
|
25
24
|
canCreateEntity,
|
|
26
25
|
canDeleteEntity,
|
|
27
26
|
canEditEntity,
|
|
28
|
-
fullPathToCollectionSegments,
|
|
29
27
|
getPropertyInPath,
|
|
30
28
|
mergeDeep,
|
|
31
29
|
resolveCollection,
|
|
@@ -74,6 +72,8 @@ import {
|
|
|
74
72
|
} from "../EntityCollectionTable/internal/default_entity_actions";
|
|
75
73
|
import { DeleteEntityDialog } from "../DeleteEntityDialog";
|
|
76
74
|
import { useAnalyticsController } from "../../hooks/useAnalyticsController";
|
|
75
|
+
import { useSelectionController } from "./useSelectionController";
|
|
76
|
+
import { EntityCollectionViewStartActions } from "./EntityCollectionViewStartActions";
|
|
77
77
|
|
|
78
78
|
const COLLECTION_GROUP_PARENT_ID = "collectionGroupParent";
|
|
79
79
|
|
|
@@ -81,8 +81,18 @@ const COLLECTION_GROUP_PARENT_ID = "collectionGroupParent";
|
|
|
81
81
|
* @group Components
|
|
82
82
|
*/
|
|
83
83
|
export type EntityCollectionViewProps<M extends Record<string, any>> = {
|
|
84
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Complete path where this collection is located.
|
|
86
|
+
* It defaults to the collection path if not provided.
|
|
87
|
+
*/
|
|
88
|
+
fullPath?: string;
|
|
89
|
+
/**
|
|
90
|
+
* If this is a subcollection, specify the parent collection ids.
|
|
91
|
+
*/
|
|
85
92
|
parentCollectionIds?: string[];
|
|
93
|
+
/**
|
|
94
|
+
* Whether this is a subcollection or not.
|
|
95
|
+
*/
|
|
86
96
|
isSubCollection?: boolean;
|
|
87
97
|
className?: string;
|
|
88
98
|
} & EntityCollection<M>;
|
|
@@ -113,7 +123,7 @@ export type EntityCollectionViewProps<M extends Record<string, any>> = {
|
|
|
113
123
|
*/
|
|
114
124
|
export const EntityCollectionView = React.memo(
|
|
115
125
|
function EntityCollectionView<M extends Record<string, any>>({
|
|
116
|
-
fullPath,
|
|
126
|
+
fullPath: fullPathProp,
|
|
117
127
|
parentCollectionIds,
|
|
118
128
|
isSubCollection,
|
|
119
129
|
className,
|
|
@@ -121,7 +131,8 @@ export const EntityCollectionView = React.memo(
|
|
|
121
131
|
}: EntityCollectionViewProps<M>
|
|
122
132
|
) {
|
|
123
133
|
|
|
124
|
-
const
|
|
134
|
+
const fullPath = fullPathProp ?? collectionProp.path;
|
|
135
|
+
const dataSource = useDataSource(collectionProp);
|
|
125
136
|
const navigation = useNavigationController();
|
|
126
137
|
const sideEntityController = useSideEntityController();
|
|
127
138
|
const authController = useAuthController();
|
|
@@ -141,7 +152,7 @@ export const EntityCollectionView = React.memo(
|
|
|
141
152
|
collectionRef.current = collection;
|
|
142
153
|
}, [collection]);
|
|
143
154
|
|
|
144
|
-
const canCreateEntities = canCreateEntity(collection, authController,
|
|
155
|
+
const canCreateEntities = canCreateEntity(collection, authController, fullPath, null);
|
|
145
156
|
const [selectedNavigationEntity, setSelectedNavigationEntity] = useState<Entity<M> | undefined>(undefined);
|
|
146
157
|
const [deleteEntityClicked, setDeleteEntityClicked] = React.useState<Entity<M> | Entity<M>[] | undefined>(undefined);
|
|
147
158
|
|
|
@@ -160,7 +171,7 @@ export const EntityCollectionView = React.memo(
|
|
|
160
171
|
|
|
161
172
|
const checkInlineEditing = useCallback((entity?: Entity<any>): boolean => {
|
|
162
173
|
const collection = collectionRef.current;
|
|
163
|
-
if (!canEditEntity(collection, authController,
|
|
174
|
+
if (!canEditEntity(collection, authController, fullPath, entity ?? null)) {
|
|
164
175
|
return false;
|
|
165
176
|
}
|
|
166
177
|
return collection.inlineEditing === undefined || collection.inlineEditing;
|
|
@@ -175,7 +186,6 @@ export const EntityCollectionView = React.memo(
|
|
|
175
186
|
const usedSelectionController = collection.selectionController ?? selectionController;
|
|
176
187
|
const {
|
|
177
188
|
selectedEntities,
|
|
178
|
-
toggleEntitySelection,
|
|
179
189
|
isEntitySelected,
|
|
180
190
|
setSelectedEntities
|
|
181
191
|
} = usedSelectionController;
|
|
@@ -199,6 +209,7 @@ export const EntityCollectionView = React.memo(
|
|
|
199
209
|
}, [tableController.setPopupCell]);
|
|
200
210
|
|
|
201
211
|
const onEntityClick = useCallback((clickedEntity: Entity<M>) => {
|
|
212
|
+
console.log("Entity clicked", clickedEntity)
|
|
202
213
|
const collection = collectionRef.current;
|
|
203
214
|
setSelectedNavigationEntity(clickedEntity);
|
|
204
215
|
analyticsController.onAnalyticsEvent?.("edit_entity_clicked", {
|
|
@@ -210,9 +221,9 @@ export const EntityCollectionView = React.memo(
|
|
|
210
221
|
path: clickedEntity.path,
|
|
211
222
|
collection,
|
|
212
223
|
updateUrl: true,
|
|
213
|
-
onClose: unselectNavigatedEntity
|
|
224
|
+
onClose: unselectNavigatedEntity,
|
|
214
225
|
});
|
|
215
|
-
}, [unselectNavigatedEntity]);
|
|
226
|
+
}, [unselectNavigatedEntity, sideEntityController]);
|
|
216
227
|
|
|
217
228
|
const onNewClick = useCallback(() => {
|
|
218
229
|
|
|
@@ -224,9 +235,9 @@ export const EntityCollectionView = React.memo(
|
|
|
224
235
|
path: fullPath,
|
|
225
236
|
collection,
|
|
226
237
|
updateUrl: true,
|
|
227
|
-
onClose: unselectNavigatedEntity
|
|
238
|
+
onClose: unselectNavigatedEntity,
|
|
228
239
|
});
|
|
229
|
-
}, [fullPath]);
|
|
240
|
+
}, [fullPath, sideEntityController]);
|
|
230
241
|
|
|
231
242
|
const onMultipleDeleteClick = () => {
|
|
232
243
|
analyticsController.onAnalyticsEvent?.("multiple_delete_dialog_open", {
|
|
@@ -288,7 +299,7 @@ export const EntityCollectionView = React.memo(
|
|
|
288
299
|
onCollectionModifiedForUser(fullPath, { defaultSize: size })
|
|
289
300
|
}, [onCollectionModifiedForUser, fullPath, userConfigPersistence]);
|
|
290
301
|
|
|
291
|
-
const createEnabled = canCreateEntity(collection, authController,
|
|
302
|
+
const createEnabled = canCreateEntity(collection, authController, fullPath, null);
|
|
292
303
|
|
|
293
304
|
const uniqueFieldValidator: UniqueFieldValidator = useCallback(
|
|
294
305
|
({
|
|
@@ -387,7 +398,7 @@ export const EntityCollectionView = React.memo(
|
|
|
387
398
|
entityId: entity.id,
|
|
388
399
|
selectedSubPath: subcollection.id ?? subcollection.path,
|
|
389
400
|
collection,
|
|
390
|
-
updateUrl: true
|
|
401
|
+
updateUrl: true,
|
|
391
402
|
});
|
|
392
403
|
}}>
|
|
393
404
|
{subcollection.name}
|
|
@@ -425,7 +436,7 @@ export const EntityCollectionView = React.memo(
|
|
|
425
436
|
...subcollectionColumns,
|
|
426
437
|
...collectionGroupParentCollections
|
|
427
438
|
];
|
|
428
|
-
}, [collection, fullPath]);
|
|
439
|
+
}, [collection, fullPath, sideEntityController]);
|
|
429
440
|
|
|
430
441
|
const updateLastDeleteTimestamp = useCallback(() => {
|
|
431
442
|
setLastDeleteTimestamp(Date.now());
|
|
@@ -433,11 +444,14 @@ export const EntityCollectionView = React.memo(
|
|
|
433
444
|
|
|
434
445
|
const largeLayout = useLargeLayout();
|
|
435
446
|
|
|
436
|
-
const getActionsForEntity = ({
|
|
447
|
+
const getActionsForEntity = ({
|
|
448
|
+
entity,
|
|
449
|
+
customEntityActions
|
|
450
|
+
}: {
|
|
437
451
|
entity?: Entity<M>,
|
|
438
452
|
customEntityActions?: EntityAction[]
|
|
439
453
|
}): EntityAction[] => {
|
|
440
|
-
const deleteEnabled = entity ? canDeleteEntity(collection, authController,
|
|
454
|
+
const deleteEnabled = entity ? canDeleteEntity(collection, authController, fullPath, entity) : true;
|
|
441
455
|
const actions: EntityAction[] = [editEntityAction];
|
|
442
456
|
if (createEnabled)
|
|
443
457
|
actions.push(copyEntityAction);
|
|
@@ -448,13 +462,13 @@ export const EntityCollectionView = React.memo(
|
|
|
448
462
|
return actions;
|
|
449
463
|
};
|
|
450
464
|
|
|
451
|
-
const getIdColumnWidth =
|
|
465
|
+
const getIdColumnWidth = () => {
|
|
452
466
|
const entityActions = getActionsForEntity({});
|
|
453
467
|
const collapsedActions = entityActions.filter(a => a.collapsed !== false);
|
|
454
468
|
const uncollapsedActions = entityActions.filter(a => a.collapsed === false);
|
|
455
469
|
const actionsWidth = uncollapsedActions.length * (largeLayout ? 40 : 30);
|
|
456
470
|
return (largeLayout ? (80 + actionsWidth) : (70 + actionsWidth)) + (collapsedActions.length > 0 ? (largeLayout ? 40 : 30) : 0);
|
|
457
|
-
}
|
|
471
|
+
};
|
|
458
472
|
|
|
459
473
|
const tableRowActionsBuilder = ({
|
|
460
474
|
entity,
|
|
@@ -470,7 +484,10 @@ export const EntityCollectionView = React.memo(
|
|
|
470
484
|
|
|
471
485
|
const isSelected = isEntitySelected(entity);
|
|
472
486
|
|
|
473
|
-
const actions = getActionsForEntity({
|
|
487
|
+
const actions = getActionsForEntity({
|
|
488
|
+
entity,
|
|
489
|
+
customEntityActions: collection.entityActions
|
|
490
|
+
});
|
|
474
491
|
|
|
475
492
|
return (
|
|
476
493
|
<EntityCollectionRowActions
|
|
@@ -577,7 +594,7 @@ export const EntityCollectionView = React.memo(
|
|
|
577
594
|
});
|
|
578
595
|
|
|
579
596
|
return (
|
|
580
|
-
<div className={cn("overflow-hidden h-full w-full", className)}
|
|
597
|
+
<div className={cn("overflow-hidden h-full w-full rounded-md", className)}
|
|
581
598
|
ref={containerRef}>
|
|
582
599
|
<EntityCollectionTable
|
|
583
600
|
key={`collection_table_${fullPath}`}
|
|
@@ -599,6 +616,14 @@ export const EntityCollectionView = React.memo(
|
|
|
599
616
|
onTextSearchClick={textSearchInitialised ? undefined : onTextSearchClick}
|
|
600
617
|
textSearchLoading={textSearchLoading}
|
|
601
618
|
textSearchEnabled={textSearchEnabled}
|
|
619
|
+
actionsStart={<EntityCollectionViewStartActions
|
|
620
|
+
parentCollectionIds={parentCollectionIds ?? []}
|
|
621
|
+
collection={collection}
|
|
622
|
+
tableController={tableController}
|
|
623
|
+
path={fullPath}
|
|
624
|
+
relativePath={collection.path}
|
|
625
|
+
selectionController={usedSelectionController}
|
|
626
|
+
collectionEntitiesCount={docsCount}/>}
|
|
602
627
|
actions={<EntityCollectionViewActions
|
|
603
628
|
parentCollectionIds={parentCollectionIds ?? []}
|
|
604
629
|
collection={collection}
|
|
@@ -676,39 +701,13 @@ export const EntityCollectionView = React.memo(
|
|
|
676
701
|
equal(a.selectionController, b.selectionController) &&
|
|
677
702
|
equal(a.Actions, b.Actions) &&
|
|
678
703
|
equal(a.defaultSize, b.defaultSize) &&
|
|
704
|
+
equal(a.initialFilter, b.initialFilter) &&
|
|
705
|
+
equal(a.initialSort, b.initialSort) &&
|
|
679
706
|
equal(a.textSearchEnabled, b.textSearchEnabled) &&
|
|
680
707
|
equal(a.additionalFields, b.additionalFields) &&
|
|
681
708
|
equal(a.forceFilter, b.forceFilter);
|
|
682
709
|
}) as React.FunctionComponent<EntityCollectionViewProps<any>>
|
|
683
710
|
|
|
684
|
-
export function useSelectionController<M extends Record<string, any> = any>(
|
|
685
|
-
onSelectionChange?: (entity: Entity<M>, selected: boolean) => void
|
|
686
|
-
): SelectionController<M> {
|
|
687
|
-
|
|
688
|
-
const [selectedEntities, setSelectedEntities] = useState<Entity<M>[]>([]);
|
|
689
|
-
|
|
690
|
-
const toggleEntitySelection = useCallback((entity: Entity<M>) => {
|
|
691
|
-
let newValue;
|
|
692
|
-
if (selectedEntities.map(e => e.id).includes(entity.id)) {
|
|
693
|
-
onSelectionChange?.(entity, false);
|
|
694
|
-
newValue = selectedEntities.filter((item: Entity<M>) => item.id !== entity.id);
|
|
695
|
-
} else {
|
|
696
|
-
onSelectionChange?.(entity, true);
|
|
697
|
-
newValue = [...selectedEntities, entity];
|
|
698
|
-
}
|
|
699
|
-
setSelectedEntities(newValue);
|
|
700
|
-
}, [selectedEntities]);
|
|
701
|
-
|
|
702
|
-
const isEntitySelected = useCallback((entity: Entity<M>) => selectedEntities.map(e => e.id).includes(entity.id), [selectedEntities]);
|
|
703
|
-
|
|
704
|
-
return {
|
|
705
|
-
selectedEntities,
|
|
706
|
-
setSelectedEntities,
|
|
707
|
-
isEntitySelected,
|
|
708
|
-
toggleEntitySelection
|
|
709
|
-
};
|
|
710
|
-
}
|
|
711
|
-
|
|
712
711
|
function EntitiesCount({
|
|
713
712
|
fullPath,
|
|
714
713
|
collection,
|
|
@@ -723,7 +722,7 @@ function EntitiesCount({
|
|
|
723
722
|
onCountChange?: (count: number) => void,
|
|
724
723
|
}) {
|
|
725
724
|
|
|
726
|
-
const dataSource = useDataSource();
|
|
725
|
+
const dataSource = useDataSource(collection);
|
|
727
726
|
const navigation = useNavigationController();
|
|
728
727
|
const [count, setCount] = useState<number | undefined>(undefined);
|
|
729
728
|
const [error, setError] = useState<Error | undefined>(undefined);
|
|
@@ -799,7 +798,7 @@ function EntityIdHeaderWidget({
|
|
|
799
798
|
entityId: searchString,
|
|
800
799
|
path,
|
|
801
800
|
collection,
|
|
802
|
-
updateUrl: true
|
|
801
|
+
updateUrl: true,
|
|
803
802
|
});
|
|
804
803
|
}}
|
|
805
804
|
className={"text-gray-900 dark:text-white w-96 max-w-full"}>
|
|
@@ -44,7 +44,7 @@ export function EntityCollectionViewActions<M extends Record<string, any>>({
|
|
|
44
44
|
|
|
45
45
|
const selectedEntities = selectionController.selectedEntities;
|
|
46
46
|
|
|
47
|
-
const addButton = canCreateEntity(collection, authController,
|
|
47
|
+
const addButton = canCreateEntity(collection, authController, path, null) &&
|
|
48
48
|
onNewClick && (largeLayout
|
|
49
49
|
? <Button
|
|
50
50
|
id={`add_entity_${path}`}
|
|
@@ -57,14 +57,13 @@ export function EntityCollectionViewActions<M extends Record<string, any>>({
|
|
|
57
57
|
: <Button
|
|
58
58
|
id={`add_entity_${path}`}
|
|
59
59
|
onClick={onNewClick}
|
|
60
|
-
size="medium"
|
|
61
60
|
variant="filled"
|
|
62
61
|
color="primary"
|
|
63
62
|
>
|
|
64
63
|
<AddIcon/>
|
|
65
64
|
</Button>);
|
|
66
65
|
|
|
67
|
-
const multipleDeleteEnabled = canDeleteEntity(collection, authController,
|
|
66
|
+
const multipleDeleteEnabled = canDeleteEntity(collection, authController, path, null);
|
|
68
67
|
|
|
69
68
|
let multipleDeleteButton: React.ReactNode | undefined;
|
|
70
69
|
if (selectionEnabled) {
|
|
@@ -112,11 +111,11 @@ export function EntityCollectionViewActions<M extends Record<string, any>>({
|
|
|
112
111
|
|
|
113
112
|
if (plugins) {
|
|
114
113
|
plugins.forEach((plugin, i) => {
|
|
115
|
-
if (plugin.
|
|
116
|
-
actions.push(...toArray(plugin.
|
|
114
|
+
if (plugin.collectionView?.CollectionActions) {
|
|
115
|
+
actions.push(...toArray(plugin.collectionView?.CollectionActions)
|
|
117
116
|
.map((Action, j) => (
|
|
118
117
|
<ErrorBoundary key={`plugin_actions_${i}_${j}`}>
|
|
119
|
-
<Action {...actionProps} {...plugin.
|
|
118
|
+
<Action {...actionProps} {...plugin.collectionView?.collectionActionsProps}/>
|
|
120
119
|
</ErrorBoundary>
|
|
121
120
|
)));
|
|
122
121
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { useCustomizationController, useFireCMSContext } from "../../hooks";
|
|
3
|
+
import { CollectionActionsProps, EntityCollection, EntityTableController, SelectionController } from "../../types";
|
|
4
|
+
import { toArray } from "../../util/arrays";
|
|
5
|
+
import { ErrorBoundary } from "../ErrorBoundary";
|
|
6
|
+
import { ClearFilterSortButton } from "../ClearFilterSortButton";
|
|
7
|
+
|
|
8
|
+
export type EntityCollectionViewStartActionsProps<M extends Record<string, any>> = {
|
|
9
|
+
collection: EntityCollection<M>;
|
|
10
|
+
path: string;
|
|
11
|
+
relativePath: string;
|
|
12
|
+
parentCollectionIds: string[];
|
|
13
|
+
selectionController: SelectionController<M>;
|
|
14
|
+
tableController: EntityTableController<M>;
|
|
15
|
+
collectionEntitiesCount: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function EntityCollectionViewStartActions<M extends Record<string, any>>({
|
|
19
|
+
collection,
|
|
20
|
+
relativePath,
|
|
21
|
+
parentCollectionIds,
|
|
22
|
+
path,
|
|
23
|
+
selectionController,
|
|
24
|
+
tableController,
|
|
25
|
+
collectionEntitiesCount
|
|
26
|
+
}: EntityCollectionViewStartActionsProps<M>) {
|
|
27
|
+
|
|
28
|
+
const context = useFireCMSContext();
|
|
29
|
+
|
|
30
|
+
const customizationController = useCustomizationController();
|
|
31
|
+
const plugins = customizationController.plugins ?? [];
|
|
32
|
+
|
|
33
|
+
const actionProps: CollectionActionsProps = {
|
|
34
|
+
path,
|
|
35
|
+
relativePath,
|
|
36
|
+
parentCollectionIds,
|
|
37
|
+
collection,
|
|
38
|
+
selectionController,
|
|
39
|
+
context,
|
|
40
|
+
tableController,
|
|
41
|
+
collectionEntitiesCount
|
|
42
|
+
};
|
|
43
|
+
const actions: React.ReactNode[] = [
|
|
44
|
+
<ClearFilterSortButton
|
|
45
|
+
key={"clear_filter"}
|
|
46
|
+
tableController={tableController}
|
|
47
|
+
enabled={!collection.forceFilter}/>
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
if (plugins) {
|
|
51
|
+
plugins.forEach((plugin, i) => {
|
|
52
|
+
if (plugin.collectionView?.CollectionActionsStart) {
|
|
53
|
+
actions.push(...toArray(plugin.collectionView?.CollectionActionsStart)
|
|
54
|
+
.map((Action, j) => (
|
|
55
|
+
<ErrorBoundary key={`plugin_actions_${i}_${j}`}>
|
|
56
|
+
<Action {...actionProps} {...plugin.collectionView?.collectionActionsStartProps}/>
|
|
57
|
+
</ErrorBoundary>
|
|
58
|
+
)));
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<>
|
|
65
|
+
{actions}
|
|
66
|
+
</>
|
|
67
|
+
);
|
|
68
|
+
}
|