strapi-plugin-navigation 2.2.3 → 2.2.5
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 +35 -6
- package/admin/src/components/AdditionalFieldInput/index.js +2 -2
- package/admin/src/components/AdditionalFieldInput/types.d.ts +1 -0
- package/admin/src/components/Item/ItemCardHeader/icons.d.ts +1 -1
- package/admin/src/components/Item/ItemCardHeader/icons.js +2 -1
- package/admin/src/components/Item/ItemCardHeader/index.d.ts +1 -0
- package/admin/src/components/Item/ItemCardHeader/index.js +10 -8
- package/admin/src/components/Item/index.js +7 -6
- package/admin/src/components/NavigationItemList/index.d.ts +2 -1
- package/admin/src/components/NavigationItemList/index.js +2 -2
- package/admin/src/hooks/useNavigationManager.d.ts +0 -1
- package/admin/src/index.js +1 -1
- package/admin/src/pages/DataManagerProvider/index.js +2 -0
- package/admin/src/pages/DataManagerProvider/reducer.d.ts +1 -1
- package/admin/src/pages/NoAccessPage/index.d.ts +3 -0
- package/admin/src/pages/NoAccessPage/index.js +31 -0
- package/admin/src/pages/SettingsPage/index.d.ts +0 -1
- package/admin/src/pages/SettingsPage/index.js +9 -0
- package/admin/src/pages/SettingsPage/types.d.ts +1 -1
- package/admin/src/pages/View/components/NavigationHeader/index.d.ts +2 -1
- package/admin/src/pages/View/components/NavigationHeader/index.js +9 -8
- package/admin/src/pages/View/components/NavigationItemForm/index.js +36 -24
- package/admin/src/pages/View/components/NavigationItemForm/types.d.ts +8 -1
- package/admin/src/pages/View/components/NavigationItemPopup/NavigationItemPopupFooter.d.ts +4 -2
- package/admin/src/pages/View/components/NavigationItemPopup/NavigationItemPopupFooter.js +5 -1
- package/admin/src/pages/View/components/NavigationItemPopup/NavigationItemPopupHeader.d.ts +2 -1
- package/admin/src/pages/View/components/NavigationItemPopup/NavigationItemPopupHeader.js +6 -2
- package/admin/src/pages/View/components/NavigationItemPopup/index.d.ts +4 -1
- package/admin/src/pages/View/components/NavigationItemPopup/index.js +5 -3
- package/admin/src/pages/View/components/NavigationManager/AllNavigations/icons.d.ts +0 -1
- package/admin/src/pages/View/components/NavigationManager/AllNavigations/index.d.ts +0 -1
- package/admin/src/pages/View/components/NavigationManager/DeletionConfirm/index.d.ts +0 -1
- package/admin/src/pages/View/components/NavigationManager/ErrorDetails/index.d.ts +0 -1
- package/admin/src/pages/View/components/NavigationManager/Form/index.d.ts +0 -1
- package/admin/src/pages/View/components/NavigationManager/NavigationUpdate/index.d.ts +0 -1
- package/admin/src/pages/View/components/NavigationManager/NewNavigation/index.d.ts +0 -1
- package/admin/src/pages/View/components/NavigationManager/index.d.ts +0 -1
- package/admin/src/pages/View/index.js +40 -20
- package/admin/src/permissions.d.ts +4 -0
- package/admin/src/permissions.js +1 -0
- package/admin/src/translations/en.json +8 -0
- package/package.json +2 -2
- package/permissions.d.ts +1 -0
- package/permissions.js +1 -0
- package/server/bootstrap/index.js +6 -0
- package/server/config/index.js +0 -1
- package/server/config/setupStrategy.js +0 -9
- package/server/content-types/index.d.ts +2 -0
- package/server/content-types/navigation/index.d.ts +1 -0
- package/server/content-types/navigation/schema.d.ts +1 -0
- package/server/content-types/navigation/schema.js +2 -1
- package/server/content-types/navigation-item/index.d.ts +1 -0
- package/server/content-types/navigation-item/schema.d.ts +1 -0
- package/server/content-types/navigation-item/schema.js +2 -1
- package/server/controllers/admin.js +13 -0
- package/server/index.d.ts +2 -0
- package/server/routes/admin.js +10 -0
- package/server/services/admin.js +2 -10
- package/server/services/client.js +10 -14
- package/server/services/common.js +27 -1
- package/strapi-server.d.ts +2 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/types/config.d.ts +0 -1
- package/types/controllers.d.ts +5 -0
- package/types/services.d.ts +1 -0
- package/types/utils.d.ts +5 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Audience, Effect, ContentTypeEntity, NavigationItemAdditionalField, NavigationItemAdditionalFieldValues, NavigationItemType, NavigationPluginConfig, PluginConfigNameFields, ToBeFixed, VoidEffect } from '../../../../../../types';
|
|
1
|
+
import { Audience, Effect, ContentTypeEntity, NavigationItemAdditionalField, NavigationItemAdditionalFieldValues, NavigationItemType, NavigationPluginConfig, PluginConfigNameFields, PluginPermissions, ToBeFixed, VoidEffect } from '../../../../../../types';
|
|
2
2
|
import { Id } from 'strapi-typed';
|
|
3
3
|
import { StrapiContentTypeSchema } from '../../../SettingsPage/types';
|
|
4
4
|
export declare type FormEventTarget<TValue = unknown> = {
|
|
@@ -60,6 +60,10 @@ export declare type NavigationItemFormProps = {
|
|
|
60
60
|
availableLocale: string[];
|
|
61
61
|
readNavigationItemFromLocale: ToBeFixed;
|
|
62
62
|
inputsPrefix: string;
|
|
63
|
+
slugify: (q: string) => Promise<{
|
|
64
|
+
slug: string;
|
|
65
|
+
}>;
|
|
66
|
+
permissions: PluginPermissions;
|
|
63
67
|
};
|
|
64
68
|
export declare type ContentTypeSearchQuery = ToBeFixed;
|
|
65
69
|
export declare type RawFormPayload = {
|
|
@@ -86,5 +90,8 @@ export declare type SanitizedFormPayload = {
|
|
|
86
90
|
singleRelatedItem: ContentTypeEntity | undefined;
|
|
87
91
|
uiRouterKey: string | undefined;
|
|
88
92
|
};
|
|
93
|
+
export declare type Slugify = (q: string) => Promise<{
|
|
94
|
+
slug: string;
|
|
95
|
+
}>;
|
|
89
96
|
export {};
|
|
90
97
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
export function NavigationItemPopupFooter({ handleCancel, handleSubmit, submitDisabled, formViewId }: {
|
|
1
|
+
export function NavigationItemPopupFooter({ handleCancel, handleSubmit, submitDisabled, formViewId, canUpdate }: {
|
|
2
2
|
handleCancel: any;
|
|
3
3
|
handleSubmit: any;
|
|
4
4
|
submitDisabled: any;
|
|
5
5
|
formViewId: any;
|
|
6
|
-
|
|
6
|
+
canUpdate: any;
|
|
7
|
+
}): JSX.Element | null;
|
|
7
8
|
export namespace NavigationItemPopupFooter {
|
|
8
9
|
namespace defaultProps {
|
|
9
10
|
const onValidate: undefined;
|
|
@@ -17,6 +18,7 @@ export namespace NavigationItemPopupFooter {
|
|
|
17
18
|
export { submitDisabled_1 as submitDisabled };
|
|
18
19
|
const formViewId_1: PropTypes.Requireable<object>;
|
|
19
20
|
export { formViewId_1 as formViewId };
|
|
21
|
+
export const canUpdate: PropTypes.Requireable<boolean>;
|
|
20
22
|
}
|
|
21
23
|
}
|
|
22
24
|
import PropTypes from "prop-types";
|
|
@@ -9,7 +9,10 @@ const prop_types_1 = __importDefault(require("prop-types"));
|
|
|
9
9
|
const Button_1 = require("@strapi/design-system/Button");
|
|
10
10
|
const ModalLayout_1 = require("@strapi/design-system/ModalLayout");
|
|
11
11
|
const utils_1 = require("../../../../utils");
|
|
12
|
-
const NavigationItemPopupFooter = ({ handleCancel, handleSubmit, submitDisabled, formViewId }) => {
|
|
12
|
+
const NavigationItemPopupFooter = ({ handleCancel, handleSubmit, submitDisabled, formViewId, canUpdate }) => {
|
|
13
|
+
if (!canUpdate) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
13
16
|
return (react_1.default.createElement(ModalLayout_1.ModalFooter, { startActions: react_1.default.createElement(Button_1.Button, { onClick: handleCancel, variant: "tertiary" }, (0, utils_1.getMessage)('popup.item.form.button.cancel')), endActions: react_1.default.createElement(Button_1.Button, { onClick: handleSubmit, disabled: submitDisabled }, (0, utils_1.getMessage)(`popup.item.form.button.save`)) }));
|
|
14
17
|
};
|
|
15
18
|
exports.NavigationItemPopupFooter = NavigationItemPopupFooter;
|
|
@@ -23,5 +26,6 @@ exports.NavigationItemPopupFooter.propTypes = {
|
|
|
23
26
|
handleSubmit: prop_types_1.default.func,
|
|
24
27
|
submitDisabled: prop_types_1.default.bool,
|
|
25
28
|
formViewId: prop_types_1.default.object,
|
|
29
|
+
canUpdate: prop_types_1.default.bool,
|
|
26
30
|
};
|
|
27
31
|
//# sourceMappingURL=NavigationItemPopupFooter.js.map
|
|
@@ -8,9 +8,13 @@ const react_1 = __importDefault(require("react"));
|
|
|
8
8
|
const Typography_1 = require("@strapi/design-system/Typography");
|
|
9
9
|
const ModalLayout_1 = require("@strapi/design-system/ModalLayout");
|
|
10
10
|
const utils_1 = require("../../../../utils");
|
|
11
|
-
const NavigationItemPopupHeader = ({ isNewItem }) => {
|
|
11
|
+
const NavigationItemPopupHeader = ({ isNewItem, canUpdate }) => {
|
|
12
|
+
let modalType = 'view';
|
|
13
|
+
if (canUpdate) {
|
|
14
|
+
modalType = isNewItem ? 'new' : 'edit';
|
|
15
|
+
}
|
|
12
16
|
return (react_1.default.createElement(ModalLayout_1.ModalHeader, null,
|
|
13
|
-
react_1.default.createElement(Typography_1.Typography, { variant: "omega", fontWeight: "bold", textColor: "neutral800", as: "h2", id: "asset-dialog-title" }, (0, utils_1.getMessage)(`popup.item.header.${
|
|
17
|
+
react_1.default.createElement(Typography_1.Typography, { variant: "omega", fontWeight: "bold", textColor: "neutral800", as: "h2", id: "asset-dialog-title" }, (0, utils_1.getMessage)(`popup.item.header.${modalType}`))));
|
|
14
18
|
};
|
|
15
19
|
exports.NavigationItemPopupHeader = NavigationItemPopupHeader;
|
|
16
20
|
//# sourceMappingURL=NavigationItemPopupHeader.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export default NavigationItemPopUp;
|
|
2
|
-
declare function NavigationItemPopUp({ availableLocale, isOpen, isLoading, data, config, onSubmit, onClose, usedContentTypeItems, getContentTypeItems, usedContentTypesData, locale, readNavigationItemFromLocale, }: {
|
|
2
|
+
declare function NavigationItemPopUp({ availableLocale, isOpen, isLoading, data, config, onSubmit, onClose, usedContentTypeItems, getContentTypeItems, usedContentTypesData, locale, readNavigationItemFromLocale, slugify, permissions, }: {
|
|
3
3
|
availableLocale: any;
|
|
4
4
|
isOpen: any;
|
|
5
5
|
isLoading: any;
|
|
@@ -12,6 +12,8 @@ declare function NavigationItemPopUp({ availableLocale, isOpen, isLoading, data,
|
|
|
12
12
|
usedContentTypesData: any;
|
|
13
13
|
locale: any;
|
|
14
14
|
readNavigationItemFromLocale: any;
|
|
15
|
+
slugify: any;
|
|
16
|
+
permissions?: {} | undefined;
|
|
15
17
|
}): JSX.Element;
|
|
16
18
|
declare namespace NavigationItemPopUp {
|
|
17
19
|
namespace propTypes {
|
|
@@ -24,6 +26,7 @@ declare namespace NavigationItemPopUp {
|
|
|
24
26
|
const getContentTypeItems: PropTypes.Validator<(...args: any[]) => any>;
|
|
25
27
|
const locale: PropTypes.Requireable<string>;
|
|
26
28
|
const readNavigationItemFromLocale: PropTypes.Validator<(...args: any[]) => any>;
|
|
29
|
+
const slugify: PropTypes.Validator<(...args: any[]) => any>;
|
|
27
30
|
}
|
|
28
31
|
}
|
|
29
32
|
import PropTypes from "prop-types";
|
|
@@ -34,12 +34,13 @@ const NavigationItemForm_1 = __importDefault(require("../NavigationItemForm"));
|
|
|
34
34
|
const parsers_1 = require("../../utils/parsers");
|
|
35
35
|
const NavigationItemPopupHeader_1 = require("./NavigationItemPopupHeader");
|
|
36
36
|
const utils_1 = require("../../../../utils");
|
|
37
|
-
const NavigationItemPopUp = ({ availableLocale, isOpen, isLoading, data, config = {}, onSubmit, onClose, usedContentTypeItems, getContentTypeItems, usedContentTypesData, locale, readNavigationItemFromLocale, }) => {
|
|
37
|
+
const NavigationItemPopUp = ({ availableLocale, isOpen, isLoading, data, config = {}, onSubmit, onClose, usedContentTypeItems, getContentTypeItems, usedContentTypesData, locale, readNavigationItemFromLocale, slugify, permissions = {}, }) => {
|
|
38
38
|
const handleOnSubmit = (payload) => {
|
|
39
39
|
onSubmit(payload);
|
|
40
40
|
};
|
|
41
41
|
const { related, relatedType } = data;
|
|
42
42
|
const { availableAudience = [], additionalFields, contentTypes, contentTypeItems, contentTypesNameFields = {}, } = config;
|
|
43
|
+
const { canUpdate } = permissions;
|
|
43
44
|
const appendLabelPublicationStatus = (label = '', item = {}, isCollection = false) => {
|
|
44
45
|
const appendix = (0, parsers_1.isRelationPublished)({
|
|
45
46
|
relatedRef: item,
|
|
@@ -70,8 +71,8 @@ const NavigationItemPopUp = ({ availableLocale, isOpen, isLoading, data, config
|
|
|
70
71
|
const preparedData = (0, react_1.useMemo)(prepareFormData.bind(null, data), [data]);
|
|
71
72
|
const hasViewId = !!data.viewId;
|
|
72
73
|
return (react_1.default.createElement(ModalLayout_1.ModalLayout, { labelledBy: "condition-modal-breadcrumbs", onClose: onClose, isOpen: isOpen },
|
|
73
|
-
react_1.default.createElement(NavigationItemPopupHeader_1.NavigationItemPopupHeader, { isNewItem: !hasViewId }),
|
|
74
|
-
react_1.default.createElement(NavigationItemForm_1.default, { availableLocale: availableLocale, config: config, data: preparedData, isLoading: isLoading, additionalFields: additionalFields, contentTypesNameFields: contentTypesNameFields, availableAudience: availableAudience, contentTypes: contentTypes, contentTypeEntities: contentTypeItems, usedContentTypeEntities: usedContentTypeItems, getContentTypeEntities: getContentTypeItems, usedContentTypesData: usedContentTypesData, onSubmit: handleOnSubmit, onCancel: onClose, appendLabelPublicationStatus: appendLabelPublicationStatus, locale: locale, readNavigationItemFromLocale: readNavigationItemFromLocale })));
|
|
74
|
+
react_1.default.createElement(NavigationItemPopupHeader_1.NavigationItemPopupHeader, { isNewItem: !hasViewId, canUpdate: canUpdate }),
|
|
75
|
+
react_1.default.createElement(NavigationItemForm_1.default, { availableLocale: availableLocale, config: config, data: preparedData, isLoading: isLoading, additionalFields: additionalFields, contentTypesNameFields: contentTypesNameFields, availableAudience: availableAudience, contentTypes: contentTypes, contentTypeEntities: contentTypeItems, usedContentTypeEntities: usedContentTypeItems, getContentTypeEntities: getContentTypeItems, usedContentTypesData: usedContentTypesData, onSubmit: handleOnSubmit, onCancel: onClose, appendLabelPublicationStatus: appendLabelPublicationStatus, locale: locale, readNavigationItemFromLocale: readNavigationItemFromLocale, slugify: slugify, permissions: permissions })));
|
|
75
76
|
};
|
|
76
77
|
NavigationItemPopUp.propTypes = {
|
|
77
78
|
data: prop_types_1.default.object.isRequired,
|
|
@@ -83,6 +84,7 @@ NavigationItemPopUp.propTypes = {
|
|
|
83
84
|
getContentTypeItems: prop_types_1.default.func.isRequired,
|
|
84
85
|
locale: prop_types_1.default.string,
|
|
85
86
|
readNavigationItemFromLocale: prop_types_1.default.func.isRequired,
|
|
87
|
+
slugify: prop_types_1.default.func.isRequired,
|
|
86
88
|
};
|
|
87
89
|
exports.default = NavigationItemPopUp;
|
|
88
90
|
//# sourceMappingURL=index.js.map
|
|
@@ -40,6 +40,7 @@ const Select_1 = require("@strapi/design-system/Select");
|
|
|
40
40
|
const helper_plugin_1 = require("@strapi/helper-plugin");
|
|
41
41
|
const EmptyDocuments_1 = __importDefault(require("@strapi/icons/EmptyDocuments"));
|
|
42
42
|
const Plus_1 = __importDefault(require("@strapi/icons/Plus"));
|
|
43
|
+
const permissions_1 = __importDefault(require("../../permissions"));
|
|
43
44
|
const NavigationItemList_1 = __importDefault(require("../../components/NavigationItemList"));
|
|
44
45
|
const NavigationContentHeader_1 = __importDefault(require("./components/NavigationContentHeader"));
|
|
45
46
|
const NavigationHeader_1 = __importDefault(require("./components/NavigationHeader"));
|
|
@@ -49,9 +50,15 @@ const Search_1 = __importDefault(require("../../components/Search"));
|
|
|
49
50
|
const useDataManager_1 = __importDefault(require("../../hooks/useDataManager"));
|
|
50
51
|
const translations_1 = require("../../translations");
|
|
51
52
|
const parsers_1 = require("./utils/parsers");
|
|
53
|
+
const NoAccessPage_1 = __importDefault(require("../NoAccessPage"));
|
|
52
54
|
const View = () => {
|
|
53
55
|
const toggleNotification = (0, helper_plugin_1.useNotification)();
|
|
54
|
-
const { items: availableNavigations, activeItem: activeNavigation, changedActiveItem: changedActiveNavigation, config, navigationItemPopupOpened, isLoading, isLoadingForAdditionalDataToBeSet, isLoadingForSubmit, handleChangeNavigationItemPopupVisibility, handleChangeSelection, handleChangeNavigationData, handleResetNavigationData, handleSubmitNavigation, handleLocalizationSelection, handleI18nCopy, getContentTypeItems, error, availableLocale: allAvailableLocale, readNavigationItemFromLocale, } = (0, useDataManager_1.default)();
|
|
56
|
+
const { items: availableNavigations, activeItem: activeNavigation, changedActiveItem: changedActiveNavigation, config, navigationItemPopupOpened, isLoading, isLoadingForAdditionalDataToBeSet, isLoadingForSubmit, handleChangeNavigationItemPopupVisibility, handleChangeSelection, handleChangeNavigationData, handleResetNavigationData, handleSubmitNavigation, handleLocalizationSelection, handleI18nCopy, getContentTypeItems, error, availableLocale: allAvailableLocale, readNavigationItemFromLocale, slugify, } = (0, useDataManager_1.default)();
|
|
57
|
+
const viewPermissions = (0, react_1.useMemo)(() => ({
|
|
58
|
+
access: permissions_1.default.access || permissions_1.default.update,
|
|
59
|
+
update: permissions_1.default.update,
|
|
60
|
+
}), []);
|
|
61
|
+
const { isLoading: isLoadingForPermissions, allowedActions: { canAccess, canUpdate, }, } = (0, helper_plugin_1.useRBAC)(viewPermissions);
|
|
55
62
|
const availableLocale = (0, react_1.useMemo)(() => allAvailableLocale.filter(locale => locale !== changedActiveNavigation?.localeCode), [changedActiveNavigation, allAvailableLocale]);
|
|
56
63
|
const { i18nCopyItemsModal, i18nCopySourceLocale, setI18nCopyModalOpened, setI18nCopySourceLocale } = (0, useI18nCopyNavigationItemsModal_1.useI18nCopyNavigationItemsModal)((0, react_1.useCallback)((sourceLocale) => {
|
|
57
64
|
const source = activeNavigation?.localizations?.find(({ localeCode }) => localeCode === sourceLocale);
|
|
@@ -80,15 +87,17 @@ const View = () => {
|
|
|
80
87
|
handleChangeNavigationItemPopupVisibility(visible);
|
|
81
88
|
};
|
|
82
89
|
const addNewNavigationItem = (0, react_1.useCallback)((event, viewParentId = null, isMenuAllowedLevel = true, levelPath = '', parentAttachedToMenu = true, structureId = "0") => {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
if (canUpdate) {
|
|
91
|
+
event.preventDefault();
|
|
92
|
+
event.stopPropagation();
|
|
93
|
+
changeNavigationItemPopupState(true, {
|
|
94
|
+
viewParentId,
|
|
95
|
+
isMenuAllowedLevel,
|
|
96
|
+
levelPath,
|
|
97
|
+
parentAttachedToMenu,
|
|
98
|
+
structureId,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
92
101
|
}, [changeNavigationItemPopupState]);
|
|
93
102
|
const usedContentTypesData = (0, react_1.useMemo)(() => changedActiveNavigation ? (0, parsers_1.usedContentTypes)(changedActiveNavigation.items) : [], [changedActiveNavigation]);
|
|
94
103
|
const pullUsedContentTypeItem = (items = []) => items.reduce((prev, curr) => [...prev, curr.relatedRef ? {
|
|
@@ -198,7 +207,9 @@ const View = () => {
|
|
|
198
207
|
tradId: 'header.action.collapseAll',
|
|
199
208
|
margin: '8px',
|
|
200
209
|
},
|
|
201
|
-
|
|
210
|
+
];
|
|
211
|
+
if (canUpdate) {
|
|
212
|
+
endActions.push({
|
|
202
213
|
onClick: addNewNavigationItem,
|
|
203
214
|
startIcon: react_1.default.createElement(Plus_1.default, null),
|
|
204
215
|
disabled: isLoadingForSubmit,
|
|
@@ -206,12 +217,17 @@ const View = () => {
|
|
|
206
217
|
variant: "default",
|
|
207
218
|
tradId: 'header.action.newItem',
|
|
208
219
|
margin: '16px',
|
|
209
|
-
}
|
|
210
|
-
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
if (!canAccess && !isLoadingForPermissions) {
|
|
223
|
+
return (react_1.default.createElement(NoAccessPage_1.default, null));
|
|
224
|
+
}
|
|
211
225
|
return (react_1.default.createElement(Main_1.Main, { labelledBy: "title", "aria-busy": isLoadingForSubmit },
|
|
212
|
-
react_1.default.createElement(NavigationHeader_1.default, { structureHasErrors: structureHasErrors, structureHasChanged: structureChanged, availableNavigations: availableNavigations, activeNavigation: activeNavigation, handleChangeSelection: handleChangeNavigationSelection, handleSave: handleSave, handleLocalizationSelection: handleLocalizationSelection, config: config
|
|
226
|
+
react_1.default.createElement(NavigationHeader_1.default, { structureHasErrors: structureHasErrors, structureHasChanged: structureChanged, availableNavigations: availableNavigations, activeNavigation: activeNavigation, handleChangeSelection: handleChangeNavigationSelection, handleSave: handleSave, handleLocalizationSelection: handleLocalizationSelection, config: config, permissions: {
|
|
227
|
+
canAccess, canUpdate
|
|
228
|
+
} }),
|
|
213
229
|
react_1.default.createElement(Layout_1.ContentLayout, null,
|
|
214
|
-
isLoading && react_1.default.createElement(helper_plugin_1.LoadingIndicatorPage, null),
|
|
230
|
+
(isLoading || isLoadingForPermissions) && react_1.default.createElement(helper_plugin_1.LoadingIndicatorPage, null),
|
|
215
231
|
changedActiveNavigation && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
216
232
|
react_1.default.createElement(NavigationContentHeader_1.default, { startActions: react_1.default.createElement(Search_1.default, { value: searchValue, setValue: setSearchValue }), endActions: endActions.map(({ tradId, margin, ...item }, i) => react_1.default.createElement(Box_1.Box, { marginLeft: margin, key: i },
|
|
217
233
|
react_1.default.createElement(Button_1.Button, { ...item },
|
|
@@ -222,8 +238,8 @@ const View = () => {
|
|
|
222
238
|
react_1.default.createElement(Icon_1.Icon, { as: EmptyDocuments_1.default, width: "160px", height: "88px", color: "" }),
|
|
223
239
|
react_1.default.createElement(Box_1.Box, { padding: 4 },
|
|
224
240
|
react_1.default.createElement(Typography_1.Typography, { variant: "beta", textColor: "neutral600" }, formatMessage((0, translations_1.getTrad)('empty')))),
|
|
225
|
-
react_1.default.createElement(Button_1.Button, { variant: 'secondary', startIcon: react_1.default.createElement(Plus_1.default, null), label: formatMessage((0, translations_1.getTrad)('empty.cta')), onClick: addNewNavigationItem }, formatMessage((0, translations_1.getTrad)('empty.cta'))),
|
|
226
|
-
config.i18nEnabled && availableLocale.length ? (react_1.default.createElement(Flex_1.Flex, { direction: "column", justifyContent: "center" },
|
|
241
|
+
canUpdate && (react_1.default.createElement(Button_1.Button, { variant: 'secondary', startIcon: react_1.default.createElement(Plus_1.default, null), label: formatMessage((0, translations_1.getTrad)('empty.cta')), onClick: addNewNavigationItem }, formatMessage((0, translations_1.getTrad)('empty.cta')))),
|
|
242
|
+
canUpdate && config.i18nEnabled && availableLocale.length ? (react_1.default.createElement(Flex_1.Flex, { direction: "column", justifyContent: "center" },
|
|
227
243
|
react_1.default.createElement(Box_1.Box, { paddingTop: 3, paddingBottom: 3 },
|
|
228
244
|
react_1.default.createElement(Typography_1.Typography, { variant: "beta", textColor: "neutral600" }, formatMessage((0, translations_1.getTrad)('view.i18n.fill.cta')))),
|
|
229
245
|
react_1.default.createElement(Flex_1.Flex, { direction: "row", justifyContent: "center", alignItems: "center" },
|
|
@@ -232,9 +248,13 @@ const View = () => {
|
|
|
232
248
|
react_1.default.createElement(Box_1.Box, { paddingLeft: 1, paddingRight: 1 },
|
|
233
249
|
react_1.default.createElement(Button_1.Button, { variant: "tertiary", onClick: openI18nCopyModalOpened, disabled: !i18nCopySourceLocale, size: "S" }, formatMessage((0, translations_1.getTrad)('view.i18n.fill.cta.button'))))))) : null)),
|
|
234
250
|
!(0, lodash_1.isEmpty)(changedActiveNavigation.items || [])
|
|
235
|
-
&& react_1.default.createElement(NavigationItemList_1.default, { items: isSearchEmpty ? changedActiveNavigation.items || [] : filteredList, onItemLevelAdd: addNewNavigationItem, onItemRemove: handleItemRemove, onItemEdit: handleItemEdit, onItemRestore: handleItemRestore, onItemReOrder: handleItemReOrder, onItemToggleCollapse: handleItemToggleCollapse, displayFlat: !isSearchEmpty, root: true, error: error, allowedLevels: config.allowedLevels, contentTypes: config.contentTypes, isParentAttachedToMenu: true, contentTypesNameFields: config.contentTypesNameFields
|
|
236
|
-
|
|
237
|
-
|
|
251
|
+
&& react_1.default.createElement(NavigationItemList_1.default, { items: isSearchEmpty ? changedActiveNavigation.items || [] : filteredList, onItemLevelAdd: addNewNavigationItem, onItemRemove: handleItemRemove, onItemEdit: handleItemEdit, onItemRestore: handleItemRestore, onItemReOrder: handleItemReOrder, onItemToggleCollapse: handleItemToggleCollapse, displayFlat: !isSearchEmpty, root: true, error: error, allowedLevels: config.allowedLevels, contentTypes: config.contentTypes, isParentAttachedToMenu: true, contentTypesNameFields: config.contentTypesNameFields, permissions: {
|
|
252
|
+
canAccess, canUpdate
|
|
253
|
+
} })))),
|
|
254
|
+
navigationItemPopupOpened && react_1.default.createElement(NavigationItemPopup_1.default, { availableLocale: availableLocale, isLoading: isLoadingForAdditionalDataToBeSet, data: activeNavigationItem, config: config, usedContentTypesData: usedContentTypesData, usedContentTypeItems: usedContentTypeItems, getContentTypeItems: getContentTypeItems, onSubmit: handleSubmitNavigationItem, onClose: onPopUpClose, locale: activeNavigation.localeCode, readNavigationItemFromLocale: readNavigationItemFromLocale, slugify: slugify, permissions: {
|
|
255
|
+
canAccess, canUpdate
|
|
256
|
+
} }),
|
|
257
|
+
canUpdate && i18nCopyItemsModal));
|
|
238
258
|
};
|
|
239
259
|
exports.default = (0, react_1.memo)(View);
|
|
240
260
|
//# sourceMappingURL=index.js.map
|
package/admin/src/permissions.js
CHANGED
|
@@ -7,6 +7,7 @@ const permissions_1 = __importDefault(require("../../permissions"));
|
|
|
7
7
|
const pluginPermissions = {
|
|
8
8
|
access: [{ action: permissions_1.default.render(permissions_1.default.navigation.read), subject: null }],
|
|
9
9
|
update: [{ action: permissions_1.default.render(permissions_1.default.navigation.update), subject: null }],
|
|
10
|
+
settings: [{ action: permissions_1.default.render(permissions_1.default.navigation.settings), subject: null }],
|
|
10
11
|
};
|
|
11
12
|
exports.default = pluginPermissions;
|
|
12
13
|
//# sourceMappingURL=permissions.js.map
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"submit.cta.save": "Save",
|
|
11
11
|
"empty": "Your navigation is empty",
|
|
12
12
|
"empty.cta": "Create first item",
|
|
13
|
+
"popup.item.header.view": "View navigation item",
|
|
13
14
|
"popup.item.header.edit": "Edit navigation item",
|
|
14
15
|
"popup.item.header.new": "New navigation item",
|
|
15
16
|
"popup.item.form.title.label": "Title",
|
|
@@ -83,6 +84,8 @@
|
|
|
83
84
|
"notification.error": "Error while processing request.",
|
|
84
85
|
"notification.error.customField.type": "Unsupported type of custom field",
|
|
85
86
|
"notification.error.item.relation": "Relations provided in some items are incorrect",
|
|
87
|
+
"page.auth.noAccess": "No access",
|
|
88
|
+
"page.auth.not.allowed": "Oops! It seems like You do not have access to this page...",
|
|
86
89
|
"pages.main.search.placeholder": "Type to start searching...",
|
|
87
90
|
"pages.main.header.localization.select.placeholder": "Select locale",
|
|
88
91
|
"pages.settings.general.title": "General settings",
|
|
@@ -185,6 +188,10 @@
|
|
|
185
188
|
"pages.settings.form.customFields.popup.options.description": "Enabling this field will not change already exiting navigation items",
|
|
186
189
|
"pages.settings.form.customFields.popup.multi.label": "Enable multiple options input",
|
|
187
190
|
"components.navigationItem.action.newItem": "Add nested item",
|
|
191
|
+
"components.navigationItem.action.edit": "Edit",
|
|
192
|
+
"components.navigationItem.action.view": "View",
|
|
193
|
+
"components.navigationItem.action.restore": "Restore",
|
|
194
|
+
"components.navigationItem.action.remove": "Remove",
|
|
188
195
|
"components.navigationItem.badge.removed": "Removed",
|
|
189
196
|
"components.navigationItem.badge.draft": "Draft",
|
|
190
197
|
"components.navigationItem.badge.published": "Published",
|
|
@@ -192,6 +199,7 @@
|
|
|
192
199
|
"components.confirmation.dialog.button.confirm": "Confirm",
|
|
193
200
|
"components.confirmation.dialog.description": "Do you want to continue?",
|
|
194
201
|
"components.confirmation.dialog.header": "Confirmation",
|
|
202
|
+
"components.notAccessPage.back": "Back to homepage",
|
|
195
203
|
"view.i18n.fill.cta": "or bootstrap",
|
|
196
204
|
"view.i18n.fill.option": "{locale} locale",
|
|
197
205
|
"view.i18n.fill.cta.button": "copy"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "strapi-plugin-navigation",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.5",
|
|
4
4
|
"description": "Strapi - Navigation plugin",
|
|
5
5
|
"strapi": {
|
|
6
6
|
"name": "navigation",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"scripts": {},
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@sindresorhus/slugify": "1.1.0",
|
|
18
|
-
"@strapi/utils": "^4.
|
|
18
|
+
"@strapi/utils": "^4.9.0",
|
|
19
19
|
"lodash": "^4.17.11",
|
|
20
20
|
"pluralize": "^8.0.0",
|
|
21
21
|
"react": "^16.9.0",
|
package/permissions.d.ts
CHANGED
package/permissions.js
CHANGED
|
@@ -28,6 +28,12 @@ const setupPermissions = async ({ strapi }) => {
|
|
|
28
28
|
uid: permissions_1.default.navigation.update,
|
|
29
29
|
pluginName: "navigation",
|
|
30
30
|
},
|
|
31
|
+
{
|
|
32
|
+
section: "plugins",
|
|
33
|
+
displayName: "Settings",
|
|
34
|
+
uid: permissions_1.default.navigation.settings,
|
|
35
|
+
pluginName: "navigation",
|
|
36
|
+
},
|
|
31
37
|
];
|
|
32
38
|
await strapi.admin.services.permission.actionProvider.registerMany(actions);
|
|
33
39
|
};
|
package/server/config/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.configSetupStrategy = void 0;
|
|
4
|
-
const lodash_1 = require("lodash");
|
|
5
4
|
const types_1 = require("../../types");
|
|
6
5
|
const utils_1 = require("../utils");
|
|
7
6
|
const configSetupStrategy = async ({ strapi }) => {
|
|
@@ -23,7 +22,6 @@ const configSetupStrategy = async ({ strapi }) => {
|
|
|
23
22
|
allowedLevels: getWithFallback("allowedLevels"),
|
|
24
23
|
gql: getWithFallback("gql"),
|
|
25
24
|
i18nEnabled: hasI18nPlugin && getWithFallback("i18nEnabled"),
|
|
26
|
-
slugify: (0, lodash_1.pick)(getWithFallback("slugify"), validSlugifyFields),
|
|
27
25
|
pruneObsoleteI18nNavigations: false,
|
|
28
26
|
pathDefaultFields: getWithFallback("pathDefaultFields"),
|
|
29
27
|
cascadeMenuAttached: getWithFallback("cascadeMenuAttached"),
|
|
@@ -41,11 +39,4 @@ const getWithFallbackFactory = (config, fallback) => (key) => {
|
|
|
41
39
|
(0, types_1.assertNotEmpty)(value, new Error(`[Navigation] Config "${key}" is undefined`));
|
|
42
40
|
return value;
|
|
43
41
|
};
|
|
44
|
-
const validSlugifyFields = [
|
|
45
|
-
"separator",
|
|
46
|
-
"lowercase",
|
|
47
|
-
"decamelize",
|
|
48
|
-
"customReplacements",
|
|
49
|
-
"preserveLeadingUnderscore",
|
|
50
|
-
];
|
|
51
42
|
//# sourceMappingURL=setupStrategy.js.map
|
|
@@ -67,6 +67,7 @@ declare const _default: {
|
|
|
67
67
|
relation: string;
|
|
68
68
|
target: string;
|
|
69
69
|
configurable: boolean;
|
|
70
|
+
mappedBy: string;
|
|
70
71
|
};
|
|
71
72
|
localizations: {
|
|
72
73
|
type: string;
|
|
@@ -167,6 +168,7 @@ declare const _default: {
|
|
|
167
168
|
relation: string;
|
|
168
169
|
target: string;
|
|
169
170
|
configurable: boolean;
|
|
171
|
+
inversedBy: string;
|
|
170
172
|
};
|
|
171
173
|
audience: {
|
|
172
174
|
type: string;
|
|
@@ -121,6 +121,19 @@ const adminControllers = {
|
|
|
121
121
|
throw error;
|
|
122
122
|
}
|
|
123
123
|
},
|
|
124
|
+
getSlug(ctx) {
|
|
125
|
+
const { query: { q } } = ctx;
|
|
126
|
+
try {
|
|
127
|
+
(0, types_1.assertNotEmpty)(q);
|
|
128
|
+
return this.getService("common").getSlug(q).then((slug) => ({ slug }));
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
if (error instanceof Error) {
|
|
132
|
+
return ctx.badRequest(error.message);
|
|
133
|
+
}
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
},
|
|
124
137
|
};
|
|
125
138
|
const assertCopyParams = (source, target) => {
|
|
126
139
|
(0, types_1.assertIsNumber)(source, new InvalidParamNavigationError_1.InvalidParamNavigationError("Source's id is not a number"));
|
package/server/index.d.ts
CHANGED
|
@@ -70,6 +70,7 @@ declare const _default: {
|
|
|
70
70
|
relation: string;
|
|
71
71
|
target: string;
|
|
72
72
|
configurable: boolean;
|
|
73
|
+
mappedBy: string;
|
|
73
74
|
};
|
|
74
75
|
localizations: {
|
|
75
76
|
type: string;
|
|
@@ -170,6 +171,7 @@ declare const _default: {
|
|
|
170
171
|
relation: string;
|
|
171
172
|
target: string;
|
|
172
173
|
configurable: boolean;
|
|
174
|
+
inversedBy: string;
|
|
173
175
|
};
|
|
174
176
|
audience: {
|
|
175
177
|
type: string;
|
package/server/routes/admin.js
CHANGED
|
@@ -28,6 +28,16 @@ const routes = {
|
|
|
28
28
|
path: '/config',
|
|
29
29
|
handler: 'admin.restoreConfig',
|
|
30
30
|
},
|
|
31
|
+
{
|
|
32
|
+
method: 'GET',
|
|
33
|
+
path: '/slug',
|
|
34
|
+
handler: 'admin.getSlug',
|
|
35
|
+
config: {
|
|
36
|
+
policies: [
|
|
37
|
+
'admin::isAuthenticatedAdmin'
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
},
|
|
31
41
|
{
|
|
32
42
|
method: 'GET',
|
|
33
43
|
path: '/:id',
|