From b68245b8b1c8f845e59686dd5ae32623f92ae807 Mon Sep 17 00:00:00 2001 From: soupette Date: Tue, 9 Jun 2020 12:05:59 +0200 Subject: [PATCH] Add permissions to plugins links in the menu only Signed-off-by: soupette --- .../LeftMenuLink/LeftMenuLinkContent.js | 51 +++---- .../LeftMenu/LeftMenuLink/Plugin.js | 33 ----- .../components/LeftMenu/LeftMenuLink/index.js | 29 +--- .../LeftMenu/LeftMenuLinkContainer/index.js | 23 --- .../admin/src/containers/Admin/index.js | 2 +- .../admin/src/containers/LeftMenu/index.js | 48 ++++-- .../admin/src/containers/LeftMenu/init.js | 23 +++ .../admin/src/containers/LeftMenu/reducer.js | 15 +- .../containers/LeftMenu/tests/init.test.js | 139 ++++++++++++++++++ .../containers/LeftMenu/tests/reducer.test.js | 92 ++++++++++-- .../src/containers/PluginDispatcher/index.js | 7 +- packages/strapi-admin/admin/src/plugins.js | 5 +- .../admin/src/utils/fakePermissionsData.js | 12 +- .../files/admin/src/index.js | 26 +++- .../admin/src/index.js | 2 - .../admin/src/index.js | 20 ++- .../admin/src/translations/en.json | 3 +- .../admin/src/index.js | 24 ++- .../admin/src/translations/en.json | 3 +- .../strapi-plugin-upload/admin/src/index.js | 20 ++- .../admin/src/containers/App/index.js | 15 +- .../admin/src/index.js | 31 +++- .../admin/src/translations/en.json | 3 +- 23 files changed, 445 insertions(+), 181 deletions(-) delete mode 100644 packages/strapi-admin/admin/src/components/LeftMenu/LeftMenuLink/Plugin.js create mode 100644 packages/strapi-admin/admin/src/containers/LeftMenu/init.js create mode 100644 packages/strapi-admin/admin/src/containers/LeftMenu/tests/init.test.js diff --git a/packages/strapi-admin/admin/src/components/LeftMenu/LeftMenuLink/LeftMenuLinkContent.js b/packages/strapi-admin/admin/src/components/LeftMenu/LeftMenuLink/LeftMenuLinkContent.js index 8f8eed6a5e..645de067cd 100644 --- a/packages/strapi-admin/admin/src/components/LeftMenu/LeftMenuLink/LeftMenuLinkContent.js +++ b/packages/strapi-admin/admin/src/components/LeftMenu/LeftMenuLink/LeftMenuLinkContent.js @@ -22,34 +22,29 @@ const LinkLabel = styled.span` padding-left: 2.5rem; `; -const LeftMenuLinkContent = ({ - destination, - iconName, - label, - location, - source, - suffixUrlToReplaceForLeftMenuHighlight, -}) => { +// TODO: refacto this file +const LeftMenuLinkContent = ({ destination, iconName, label, location }) => { const isLinkActive = startsWith( location.pathname.replace('/admin', '').concat('/'), - - destination.replace(suffixUrlToReplaceForLeftMenuHighlight, '').concat('/') + destination.concat('/') ); // Check if messageId exists in en locale to prevent warning messages - const content = en[label] ? ( - - {message => {message}} - - ) : ( - {label} - ); + const labelId = label.id || label; + const content = + en[labelId] || label.defaultMessage ? ( + + {message => {message}} + + ) : ( + {labelId} + ); // Create external or internal link. return destination.includes('http') ? ( @@ -68,7 +63,6 @@ const LeftMenuLinkContent = ({ className={isLinkActive ? 'linkActive' : ''} to={{ pathname: destination, - search: source ? `?source=${source}` : '', }} > @@ -80,17 +74,10 @@ const LeftMenuLinkContent = ({ LeftMenuLinkContent.propTypes = { destination: PropTypes.string.isRequired, iconName: PropTypes.string.isRequired, - label: PropTypes.string.isRequired, + label: PropTypes.oneOfType([PropTypes.object, PropTypes.string]).isRequired, location: PropTypes.shape({ pathname: PropTypes.string, }).isRequired, - source: PropTypes.string, - suffixUrlToReplaceForLeftMenuHighlight: PropTypes.string, -}; - -LeftMenuLinkContent.defaultProps = { - source: '', - suffixUrlToReplaceForLeftMenuHighlight: '', }; export default withRouter(LeftMenuLinkContent); diff --git a/packages/strapi-admin/admin/src/components/LeftMenu/LeftMenuLink/Plugin.js b/packages/strapi-admin/admin/src/components/LeftMenu/LeftMenuLink/Plugin.js deleted file mode 100644 index bad4677129..0000000000 --- a/packages/strapi-admin/admin/src/components/LeftMenu/LeftMenuLink/Plugin.js +++ /dev/null @@ -1,33 +0,0 @@ -import styled from 'styled-components'; - -const Plugin = styled.div` - cursor: pointer; - position: absolute; - top: 10px; - left: calc(100% - 4px); - display: inline-block; - width: auto; - height: 20px; - transition: right 1s ease-in-out; - - span { - display: inline-block; - overflow: hidden; - width: auto; - height: 20px; - padding: 0 14px 0 10px; - color: #ffffff; - font-size: 12px; - line-height: 20px; - background: #0097f7; - border-radius: 3px; - transition: transform 0.3s ease-in-out; - white-space: pre; - - &:hover { - transform: translateX(calc(-100% + 9px)); - } - } -`; - -export default Plugin; diff --git a/packages/strapi-admin/admin/src/components/LeftMenu/LeftMenuLink/index.js b/packages/strapi-admin/admin/src/components/LeftMenu/LeftMenuLink/index.js index 29e8decd55..1665a2ee3f 100644 --- a/packages/strapi-admin/admin/src/components/LeftMenu/LeftMenuLink/index.js +++ b/packages/strapi-admin/admin/src/components/LeftMenu/LeftMenuLink/index.js @@ -5,29 +5,11 @@ */ import React from 'react'; -import { upperFirst } from 'lodash'; import PropTypes from 'prop-types'; import LeftMenuLinkContent from './LeftMenuLinkContent'; -import Plugin from './Plugin'; - -const LeftMenuLink = ({ - destination, - iconName, - label, - location, - source, - suffixUrlToReplaceForLeftMenuHighlight, -}) => { - const plugin = - source !== 'content-manager' && source !== '' ? ( - - {upperFirst(source.split('-').join(' '))} - - ) : ( - '' - ); +const LeftMenuLink = ({ destination, iconName, label, location }) => { return ( <> - {plugin} ); }; @@ -46,18 +25,14 @@ const LeftMenuLink = ({ LeftMenuLink.propTypes = { destination: PropTypes.string.isRequired, iconName: PropTypes.string, - label: PropTypes.string.isRequired, + label: PropTypes.oneOfType([PropTypes.object, PropTypes.string]).isRequired, location: PropTypes.shape({ pathname: PropTypes.string, }).isRequired, - source: PropTypes.string, - suffixUrlToReplaceForLeftMenuHighlight: PropTypes.string, }; LeftMenuLink.defaultProps = { iconName: 'circle', - source: '', - suffixUrlToReplaceForLeftMenuHighlight: '', }; export default LeftMenuLink; diff --git a/packages/strapi-admin/admin/src/components/LeftMenu/LeftMenuLinkContainer/index.js b/packages/strapi-admin/admin/src/components/LeftMenu/LeftMenuLinkContainer/index.js index f46e20c129..526e3ea17f 100644 --- a/packages/strapi-admin/admin/src/components/LeftMenu/LeftMenuLinkContainer/index.js +++ b/packages/strapi-admin/admin/src/components/LeftMenu/LeftMenuLinkContainer/index.js @@ -4,8 +4,6 @@ import { useLocation } from 'react-router-dom'; import PropTypes from 'prop-types'; import { get, snakeCase, isEmpty } from 'lodash'; -import messages from './messages.json'; - import LeftMenuLinkSection from '../LeftMenuLinkSection'; const LeftMenuLinkContainer = ({ plugins }) => { @@ -34,29 +32,8 @@ const LeftMenuLinkContainer = ({ plugins }) => { return acc; }, {}); - // Generate the list of plugin links (plugins without a mainComponent should not appear in the left menu) - const pluginsLinks = Object.values(plugins) - .filter( - plugin => plugin.id !== 'email' && plugin.id !== 'content-manager' && !!plugin.mainComponent - ) - .map(plugin => { - const pluginSuffixUrl = plugin.suffixUrl ? plugin.suffixUrl(plugins) : ''; - - return { - icon: get(plugin, 'icon') || 'plug', - label: get(plugin, 'name'), - destination: `/plugins/${get(plugin, 'id')}${pluginSuffixUrl}`, - }; - }); - const menu = { ...contentTypesSections, - plugins: { - searchable: false, - name: 'plugins', - emptyLinksListMessage: messages.noPluginsInstalled.id, - links: pluginsLinks, - }, }; return Object.keys(menu).map(current => ( diff --git a/packages/strapi-admin/admin/src/containers/Admin/index.js b/packages/strapi-admin/admin/src/containers/Admin/index.js index fd7b6696df..3f8537225d 100644 --- a/packages/strapi-admin/admin/src/containers/Admin/index.js +++ b/packages/strapi-admin/admin/src/containers/Admin/index.js @@ -214,7 +214,7 @@ export class Admin extends React.Component { exact /> - + diff --git a/packages/strapi-admin/admin/src/containers/LeftMenu/index.js b/packages/strapi-admin/admin/src/containers/LeftMenu/index.js index 0ba1f4b51a..efacfe55ae 100644 --- a/packages/strapi-admin/admin/src/containers/LeftMenu/index.js +++ b/packages/strapi-admin/admin/src/containers/LeftMenu/index.js @@ -4,7 +4,7 @@ * */ -import React, { useContext, useEffect, useReducer } from 'react'; +import React, { useContext, useEffect, useMemo, useReducer } from 'react'; import PropTypes from 'prop-types'; import { useLocation } from 'react-router-dom'; import { UserContext, hasPermissions } from 'strapi-helper-plugin'; @@ -15,6 +15,7 @@ import { LeftMenuLinkContainer, LinksContainer, } from '../../components/LeftMenu'; +import init from './init'; import reducer, { initialState } from './reducer'; import Loader from './Loader'; import Wrapper from './Wrapper'; @@ -22,8 +23,21 @@ import Wrapper from './Wrapper'; const LeftMenu = ({ version, plugins }) => { const location = useLocation(); const permissions = useContext(UserContext); - const [{ generalSectionLinks, isLoading }, dispatch] = useReducer(reducer, initialState); - const filteredLinks = generalSectionLinks.filter(link => link.isDisplayed); + const [{ generalSectionLinks, isLoading, pluginsSectionLinks }, dispatch] = useReducer( + reducer, + initialState, + () => init(initialState, plugins) + ); + const generalSectionLinksFiltered = useMemo( + () => generalSectionLinks.filter(link => link.isDisplayed), + [generalSectionLinks] + ); + const pluginsSectionLinksFiltered = useMemo( + () => pluginsSectionLinks.filter(link => link.isDisplayed), + [pluginsSectionLinks] + ); + + console.log(pluginsSectionLinks); useEffect(() => { const getLinksPermissions = async () => { @@ -33,15 +47,21 @@ const LeftMenu = ({ version, plugins }) => { return { index, hasPermission }; }; - const generalSectionLinksArrayOfPromises = generalSectionLinks.map((_, index) => - checkPermissions(index, generalSectionLinks[index].permissions) - ); + const generateArrayOfPromises = array => + array.map((_, index) => checkPermissions(index, array[index].permissions)); - const results = await Promise.all(generalSectionLinksArrayOfPromises); + const generalSectionLinksArrayOfPromises = generateArrayOfPromises(generalSectionLinks); + const pluginsSectionLinksArrayOfPromises = generateArrayOfPromises(pluginsSectionLinks); + + const generalSectionResults = await Promise.all(generalSectionLinksArrayOfPromises); + const pluginsSectionResults = await Promise.all(pluginsSectionLinksArrayOfPromises); dispatch({ type: 'SET_LINK_PERMISSIONS', - results, + data: { + generalSectionLinks: generalSectionResults, + pluginsSectionLinks: pluginsSectionResults, + }, }); dispatch({ @@ -59,11 +79,19 @@ const LeftMenu = ({ version, plugins }) => { - {filteredLinks.length && ( + + {generalSectionLinksFiltered.length && ( diff --git a/packages/strapi-admin/admin/src/containers/LeftMenu/init.js b/packages/strapi-admin/admin/src/containers/LeftMenu/init.js new file mode 100644 index 0000000000..a68f2f24ca --- /dev/null +++ b/packages/strapi-admin/admin/src/containers/LeftMenu/init.js @@ -0,0 +1,23 @@ +import { get, omit, set, sortBy } from 'lodash'; + +const sortLinks = links => sortBy(links, object => object.name); + +const init = (initialState, plugins = {}) => { + const pluginsLinks = Object.values(plugins).reduce((acc, current) => { + const pluginsSectionLinks = get(current, 'menu.pluginsSectionLinks', []); + + return [...acc, ...pluginsSectionLinks]; + }, []); + const sortedLinks = sortLinks(pluginsLinks).map(link => { + return { ...omit(link, 'name'), isDisplayed: false }; + }); + + if (sortedLinks.length) { + set(initialState, 'pluginsSectionLinks', sortedLinks); + } + + return initialState; +}; + +export default init; +export { sortLinks }; diff --git a/packages/strapi-admin/admin/src/containers/LeftMenu/reducer.js b/packages/strapi-admin/admin/src/containers/LeftMenu/reducer.js index 414eb29a65..cd46b111a2 100644 --- a/packages/strapi-admin/admin/src/containers/LeftMenu/reducer.js +++ b/packages/strapi-admin/admin/src/containers/LeftMenu/reducer.js @@ -46,11 +46,14 @@ const initialState = { { action: 'admin::roles.update', subject: null }, { action: 'admin::roles.read', subject: null }, { action: 'admin::roles.delete', subject: null }, + + // TODO this should be set by the plugin directly // media library { action: 'plugins::upload.settings.read', subject: null }, ], }, ], + pluginsSectionLinks: [], isLoading: true, }; @@ -58,12 +61,12 @@ const reducer = (state, action) => produce(state, draftState => { switch (action.type) { case 'SET_LINK_PERMISSIONS': { - action.results.forEach(result => { - set( - draftState, - ['generalSectionLinks', result.index, 'isDisplayed'], - result.hasPermission - ); + Object.keys(action.data).forEach(sectionName => { + const sectionData = action.data[sectionName]; + + sectionData.forEach(result => { + set(draftState, [sectionName, result.index, 'isDisplayed'], result.hasPermission); + }); }); break; } diff --git a/packages/strapi-admin/admin/src/containers/LeftMenu/tests/init.test.js b/packages/strapi-admin/admin/src/containers/LeftMenu/tests/init.test.js new file mode 100644 index 0000000000..10a2225d24 --- /dev/null +++ b/packages/strapi-admin/admin/src/containers/LeftMenu/tests/init.test.js @@ -0,0 +1,139 @@ +import init, { sortLinks } from '../init'; + +describe('ADMIN | LeftMenu | init', () => { + describe('init', () => { + it('should return the initialState if the plugins are empty', () => { + const initialState = { + ok: true, + }; + + expect(init(initialState)).toEqual({ ok: true }); + }); + + it('should create the pluginsSectionLinks correctly', () => { + const plugins = { + documentation: { + menu: { + pluginsSectionLinks: [ + { + destination: '/plugins/documentation', + icon: 'doc', + label: { + id: 'documentation.plugin.name', + defaultMessage: 'Documentation', + }, + name: 'documentation', + permissions: [{ action: 'plugins::documentation.read', subject: null }], + }, + { + destination: '/plugins/documentation/test', + icon: 'doc', + label: { + id: 'documentation.plugin.name.test', + defaultMessage: 'Documentation Test', + }, + name: 'documentation test', + permissions: [], + }, + ], + }, + }, + test: {}, + 'content-type-builder': { + menu: { + pluginsSectionLinks: [ + { + destination: '/plugins/content-type-builder', + icon: 'plug', + label: { + id: 'content-type-builder.plugin.name', + defaultMessage: 'content-type-builder', + }, + name: 'content-type-builder', + permissions: [{ action: 'plugins::content-type-builder.read', subject: null }], + }, + ], + }, + }, + }; + const initialState = { + generalSectionLinks: [], + pluginsSectionLinks: [], + isLoading: true, + }; + const expected = { + generalSectionLinks: [], + pluginsSectionLinks: [ + { + destination: '/plugins/content-type-builder', + icon: 'plug', + label: { + id: 'content-type-builder.plugin.name', + defaultMessage: 'content-type-builder', + }, + isDisplayed: false, + permissions: [{ action: 'plugins::content-type-builder.read', subject: null }], + }, + { + destination: '/plugins/documentation', + icon: 'doc', + label: { + id: 'documentation.plugin.name', + defaultMessage: 'Documentation', + }, + isDisplayed: false, + permissions: [{ action: 'plugins::documentation.read', subject: null }], + }, + { + destination: '/plugins/documentation/test', + icon: 'doc', + label: { + id: 'documentation.plugin.name.test', + defaultMessage: 'Documentation Test', + }, + isDisplayed: false, + permissions: [], + }, + ], + isLoading: true, + }; + + expect(init(initialState, plugins)).toEqual(expected); + }); + }); + + describe('sortLinks', () => { + it('should return an empty array', () => { + expect(sortLinks([])).toEqual([]); + }); + + it('should return a sorted array', () => { + const data = [ + { + name: 'un', + }, + { name: 'deux' }, + { name: 'un-un' }, + { name: 'un-deux' }, + { name: 'un un' }, + ]; + const expected = [ + { + name: 'deux', + }, + { + name: 'un', + }, + { name: 'un un' }, + { + name: 'un-deux', + }, + { + name: 'un-un', + }, + ]; + + expect(sortLinks(data)).toEqual(expected); + }); + }); +}); diff --git a/packages/strapi-admin/admin/src/containers/LeftMenu/tests/reducer.test.js b/packages/strapi-admin/admin/src/containers/LeftMenu/tests/reducer.test.js index 277ea9b4d9..66eba8750c 100644 --- a/packages/strapi-admin/admin/src/containers/LeftMenu/tests/reducer.test.js +++ b/packages/strapi-admin/admin/src/containers/LeftMenu/tests/reducer.test.js @@ -62,23 +62,59 @@ describe('ADMIN | LeftMenu | reducer', () => { permissions: [], }, ], + pluginsSectionLinks: [ + { + destination: '/plugins/content-type-builder', + icon: 'paint-brush', + isDisplayed: false, + label: { + id: 'content-type-builder.plugin.name', + defaultMessage: 'Content-Types Builder', + }, + permissions: [ + { + action: 'plugins::content-type-builder.read', + subject: null, + }, + ], + }, + { + destination: '/plugins/documentation', + icon: 'book', + isDisplayed: false, + label: { id: 'documentation.plugin.name', defaultMessage: 'Documentation' }, + permissions: [ + { action: 'plugins::documentation.read', subject: null }, + { action: 'plugins::documentation.regenerate', subject: null }, + { action: 'plugins::documentation.update', subject: null }, + ], + }, + ], }; const action = { type: 'SET_LINK_PERMISSIONS', - results: [ - { - index: 1, - hasPermission: true, - }, - { - index: 0, - hasPermission: false, - }, - { - index: 2, - hasPermission: true, - }, - ], + data: { + generalSectionLinks: [ + { + index: 1, + hasPermission: true, + }, + { + index: 0, + hasPermission: false, + }, + { + index: 2, + hasPermission: true, + }, + ], + pluginsSectionLinks: [ + { + index: 0, + hasPermission: true, + }, + ], + }, }; const expected = { @@ -112,6 +148,34 @@ describe('ADMIN | LeftMenu | reducer', () => { permissions: [], }, ], + pluginsSectionLinks: [ + { + destination: '/plugins/content-type-builder', + icon: 'paint-brush', + isDisplayed: true, + label: { + id: 'content-type-builder.plugin.name', + defaultMessage: 'Content-Types Builder', + }, + permissions: [ + { + action: 'plugins::content-type-builder.read', + subject: null, + }, + ], + }, + { + destination: '/plugins/documentation', + icon: 'book', + isDisplayed: false, + label: { id: 'documentation.plugin.name', defaultMessage: 'Documentation' }, + permissions: [ + { action: 'plugins::documentation.read', subject: null }, + { action: 'plugins::documentation.regenerate', subject: null }, + { action: 'plugins::documentation.update', subject: null }, + ], + }, + ], }; expect(reducer(state, action)).toEqual(expected); diff --git a/packages/strapi-admin/admin/src/containers/PluginDispatcher/index.js b/packages/strapi-admin/admin/src/containers/PluginDispatcher/index.js index dc9ba6e52b..49c382fd31 100644 --- a/packages/strapi-admin/admin/src/containers/PluginDispatcher/index.js +++ b/packages/strapi-admin/admin/src/containers/PluginDispatcher/index.js @@ -6,6 +6,7 @@ import React, { memo } from 'react'; import PropTypes from 'prop-types'; +import { Redirect } from 'react-router-dom'; import { get } from 'lodash'; import { BlockerComponent } from 'strapi-helper-plugin'; @@ -25,7 +26,7 @@ export function PluginDispatcher(props) { const pluginToRender = get(plugins, pluginId, null); if (!pluginToRender) { - return null; + return ; } const { @@ -35,9 +36,7 @@ export function PluginDispatcher(props) { name, preventComponentRendering, } = pluginToRender; - let PluginEntryComponent = preventComponentRendering - ? BlockerComponent - : mainComponent; + let PluginEntryComponent = preventComponentRendering ? BlockerComponent : mainComponent; // Change the plugin's blockerComponent if the plugin uses a custom one. if (preventComponentRendering && blockerComponent) { diff --git a/packages/strapi-admin/admin/src/plugins.js b/packages/strapi-admin/admin/src/plugins.js index 9f9a185b10..fe49218c64 100644 --- a/packages/strapi-admin/admin/src/plugins.js +++ b/packages/strapi-admin/admin/src/plugins.js @@ -23,14 +23,15 @@ window.strapi = Object.assign(window.strapi || {}, { }); module.exports = { + 'strapi-plugin-documentation': require('../../../strapi-plugin-documentation/admin/src').default, 'strapi-plugin-users-permissions': require('../../../strapi-plugin-users-permissions/admin/src') .default, 'strapi-plugin-content-manager': require('../../../strapi-plugin-content-manager/admin/src') .default, 'strapi-plugin-content-type-builder': require('../../../strapi-plugin-content-type-builder/admin/src') .default, - 'strapi-plugin-documentation': require('../../../strapi-plugin-documentation/admin/src').default, + 'strapi-plugin-email': require('../../../strapi-plugin-email/admin/src').default, - 'strapi-plugin-upload': require('../../../strapi-plugin-upload/admin/src').default, + // 'strapi-plugin-upload': require('../../../strapi-plugin-upload/admin/src').default, 'strapi-plugin-graphql': require('../../../strapi-plugin-graphql/admin/src').default, }; diff --git a/packages/strapi-admin/admin/src/utils/fakePermissionsData.js b/packages/strapi-admin/admin/src/utils/fakePermissionsData.js index f98b0533c8..6999cea5ff 100644 --- a/packages/strapi-admin/admin/src/utils/fakePermissionsData.js +++ b/packages/strapi-admin/admin/src/utils/fakePermissionsData.js @@ -354,12 +354,12 @@ const data = { // }, // Upload plugin - { - action: 'plugins::upload.read', - subject: null, - fields: null, - conditions: [], - }, + // { + // action: 'plugins::upload.read', + // subject: null, + // fields: null, + // conditions: [], + // }, { action: 'plugins::upload.assets.create', subject: null, diff --git a/packages/strapi-generate-plugin/files/admin/src/index.js b/packages/strapi-generate-plugin/files/admin/src/index.js index cd8763d11d..ee02d9e24e 100644 --- a/packages/strapi-generate-plugin/files/admin/src/index.js +++ b/packages/strapi-generate-plugin/files/admin/src/index.js @@ -7,12 +7,14 @@ import trads from './translations'; export default strapi => { const pluginDescription = pluginPkg.strapi.description || pluginPkg.description; + const icon = pluginPkg.strapi.icon; + const name = pluginPkg.strapi.name; const plugin = { blockerComponent: null, blockerComponentProps: {}, description: pluginDescription, - icon: pluginPkg.strapi.icon, + icon, id: pluginId, initializer: Initializer, injectedComponents: [], @@ -23,9 +25,29 @@ export default strapi => { leftMenuLinks: [], leftMenuSections: [], mainComponent: App, - name: pluginPkg.strapi.name, + name, preventComponentRendering: false, trads, + menu: { + pluginsSection: [ + { + destination: `/plugins/${pluginId}`, + icon, + label: { + id: `${pluginId}.plugin.name`, + defaultMessage: name, + }, + name, + permissions: [ + // Uncomment to set the permissions of the plugin here + // { + // action: '', // the action name should be plugins::plugin-name.actionType + // subject: null, + // }, + ], + }, + ], + }, }; return strapi.registerPlugin(plugin); diff --git a/packages/strapi-plugin-content-manager/admin/src/index.js b/packages/strapi-plugin-content-manager/admin/src/index.js index fcb99a67d8..dbe71a6dde 100644 --- a/packages/strapi-plugin-content-manager/admin/src/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/index.js @@ -43,8 +43,6 @@ export default strapi => { pluginLogo, preventComponentRendering: false, reducers, - suffixUrl: () => '/ctm-configurations/models', - suffixUrlToReplaceForLeftMenuHighlight: '/models', trads, }; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/index.js b/packages/strapi-plugin-content-type-builder/admin/src/index.js index 5c1efcdccc..466b413d98 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/index.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/index.js @@ -17,11 +17,13 @@ import pluginId from './pluginId'; export default strapi => { const pluginDescription = pluginPkg.strapi.description || pluginPkg.description; + const icon = pluginPkg.strapi.icon; + const name = pluginPkg.strapi.name; const plugin = { blockerComponent: null, blockerComponentProps: {}, description: pluginDescription, - icon: pluginPkg.strapi.icon, + icon, id: pluginId, initializer: Initializer, injectedComponents: [ @@ -50,10 +52,24 @@ export default strapi => { leftMenuLinks: [], leftMenuSections: [], mainComponent: App, - name: pluginPkg.strapi.name, + name, pluginLogo, preventComponentRendering: false, trads, + menu: { + pluginsSectionLinks: [ + { + destination: `/plugins/${pluginId}`, + icon, + label: { + id: `${pluginId}.plugin.name`, + defaultMessage: 'Content-Types Builder', + }, + name, + permissions: [{ action: 'plugins::content-type-builder.read', subject: null }], + }, + ], + }, }; return strapi.registerPlugin(plugin); diff --git a/packages/strapi-plugin-content-type-builder/admin/src/translations/en.json b/packages/strapi-plugin-content-type-builder/admin/src/translations/en.json index 6841f67b59..8a77395710 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/translations/en.json +++ b/packages/strapi-plugin-content-type-builder/admin/src/translations/en.json @@ -176,5 +176,6 @@ "relation.oneToOne": "has and belongs to one", "relation.oneWay": "has one", "table.attributes.title.plural": "{number} fields", - "table.attributes.title.singular": "{number} field" + "table.attributes.title.singular": "{number} field", + "plugin.name": "Content-Types Builder" } diff --git a/packages/strapi-plugin-documentation/admin/src/index.js b/packages/strapi-plugin-documentation/admin/src/index.js index 66748b9708..d9a3d835e1 100644 --- a/packages/strapi-plugin-documentation/admin/src/index.js +++ b/packages/strapi-plugin-documentation/admin/src/index.js @@ -16,11 +16,13 @@ import trads from './translations'; export default strapi => { const pluginDescription = pluginPkg.strapi.description || pluginPkg.description; + const icon = pluginPkg.strapi.icon; + const name = pluginPkg.strapi.name; const plugin = { blockerComponent: null, blockerComponentProps: {}, description: pluginDescription, - icon: pluginPkg.strapi.icon, + icon, id: pluginId, initializer: Initializer, injectedComponents: [], @@ -31,11 +33,29 @@ export default strapi => { leftMenuLinks: [], leftMenuSections: [], mainComponent: App, - name: pluginPkg.strapi.name, + name, pluginLogo, preventComponentRendering: false, reducers, trads, + menu: { + pluginsSectionLinks: [ + { + destination: `/plugins/${pluginId}`, + icon, + label: { + id: `${pluginId}.plugin.name`, + defaultMessage: 'Documentation', + }, + name, + permissions: [ + { action: 'plugins::documentation.read', subject: null }, + { action: 'plugins::documentation.regenerate', subject: null }, + { action: 'plugins::documentation.update', subject: null }, + ], + }, + ], + }, }; return strapi.registerPlugin(plugin); diff --git a/packages/strapi-plugin-documentation/admin/src/translations/en.json b/packages/strapi-plugin-documentation/admin/src/translations/en.json index 987ebbf02f..4200c18bbd 100755 --- a/packages/strapi-plugin-documentation/admin/src/translations/en.json +++ b/packages/strapi-plugin-documentation/admin/src/translations/en.json @@ -25,5 +25,6 @@ "error.noVersion": "A version is required", "error.regenerateDoc.versionMissing": "The version you are trying to generate doesn't exist", "error.deleteDoc.versionMissing": "The version you are trying to delete does not exist.", - "notification.update.success": "Settings updated successfully" + "notification.update.success": "Settings updated successfully", + "plugin.name": "Documentation" } diff --git a/packages/strapi-plugin-upload/admin/src/index.js b/packages/strapi-plugin-upload/admin/src/index.js index a00fda1e11..359172ee7f 100644 --- a/packages/strapi-plugin-upload/admin/src/index.js +++ b/packages/strapi-plugin-upload/admin/src/index.js @@ -19,12 +19,14 @@ import { getTrad } from './utils'; export default strapi => { const pluginDescription = pluginPkg.strapi.description || pluginPkg.description; + const icon = pluginPkg.strapi.icon; + const name = pluginPkg.strapi.name; const plugin = { blockerComponent: null, blockerComponentProps: {}, description: pluginDescription, fileModel: null, - icon: pluginPkg.strapi.icon, + icon, id: pluginId, initializer: Initializer, injectedComponents: [], @@ -35,7 +37,7 @@ export default strapi => { leftMenuLinks: [], leftMenuSections: [], mainComponent: App, - name: pluginPkg.strapi.name, + name, pluginLogo, preventComponentRendering: false, settings: { @@ -52,6 +54,20 @@ export default strapi => { ], }, trads, + menu: { + pluginsSectionLinks: [ + { + destination: `/plugins/${pluginId}`, + icon, + label: { + id: `${pluginId}.plugin.name`, + defaultMessage: 'Media Library', + }, + name, + permissions: [{ action: 'plugins::upload.read', subject: null }], + }, + ], + }, }; strapi.registerComponent({ name: 'media-library', Component: InputModalStepper }); diff --git a/packages/strapi-plugin-users-permissions/admin/src/containers/App/index.js b/packages/strapi-plugin-users-permissions/admin/src/containers/App/index.js index 39e752a598..776d5cef10 100644 --- a/packages/strapi-plugin-users-permissions/admin/src/containers/App/index.js +++ b/packages/strapi-plugin-users-permissions/admin/src/containers/App/index.js @@ -6,7 +6,7 @@ */ import React from 'react'; -import { Switch, Route } from 'react-router-dom'; +import { Switch, Redirect, Route, useRouteMatch } from 'react-router-dom'; import { NotFound } from 'strapi-helper-plugin'; import pluginId from '../../pluginId'; @@ -14,6 +14,13 @@ import EditPage from '../EditPage'; import HomePage from '../HomePage'; const App = () => { + const settingType = useRouteMatch(`/plugins/${pluginId}/:settingType`); + + // Todo check if the settingType is allowed + if (!settingType) { + return ; + } + return (
@@ -22,11 +29,7 @@ const App = () => { component={EditPage} exact /> - +
diff --git a/packages/strapi-plugin-users-permissions/admin/src/index.js b/packages/strapi-plugin-users-permissions/admin/src/index.js index 0f214c938b..e07743c3e6 100644 --- a/packages/strapi-plugin-users-permissions/admin/src/index.js +++ b/packages/strapi-plugin-users-permissions/admin/src/index.js @@ -17,12 +17,14 @@ import trads from './translations'; export default strapi => { const pluginDescription = pluginPkg.strapi.description || pluginPkg.description; + const icon = pluginPkg.strapi.icon; + const name = pluginPkg.strapi.name; const plugin = { blockerComponent: null, blockerComponentProps: {}, description: pluginDescription, - icon: pluginPkg.strapi.icon, + icon, id: pluginId, initializer: Initializer, injectedComponents: [], @@ -32,14 +34,35 @@ export default strapi => { leftMenuLinks: [], leftMenuSections: [], mainComponent: App, - name: pluginPkg.strapi.name, + name, pluginLogo, preventComponentRendering: false, reducers, settings: {}, - suffixUrl: () => '/roles', - suffixUrlToReplaceForLeftMenuHighlight: '/roles', trads, + menu: { + pluginsSectionLinks: [ + { + destination: `/plugins/${pluginId}`, + icon, + label: { + id: `${pluginId}.plugin.name`, + defaultMessage: 'Roles & Permissions', + }, + name, + permissions: [ + { action: 'plugins::users-permissions.advanced-settings.read', subject: null }, + { action: 'plugins::users-permissions.advanced-settings.update', subject: null }, + { action: 'plugins::users-permissions.email-templates.read', subject: null }, + { action: 'plugins::users-permissions.email-templates.update', subject: null }, + { action: 'plugins::users-permissions.providers.read', subject: null }, + { action: 'plugins::users-permissions.providers.update', subject: null }, + { action: 'plugins::users-permissions.roles.create', subject: null }, + { action: 'plugins::users-permissions.roles.read', subject: null }, + ], + }, + ], + }, }; return strapi.registerPlugin(plugin); diff --git a/packages/strapi-plugin-users-permissions/admin/src/translations/en.json b/packages/strapi-plugin-users-permissions/admin/src/translations/en.json index 4641850a35..9eecf61872 100644 --- a/packages/strapi-plugin-users-permissions/admin/src/translations/en.json +++ b/packages/strapi-plugin-users-permissions/admin/src/translations/en.json @@ -112,5 +112,6 @@ "notification.success.delete": "The item has been deleted", "notification.success.submit": "Settings have been updated", "plugin.description.long": "Protect your API with a full authentication process based on JWT. This plugin comes also with an ACL strategy that allows you to manage the permissions between the groups of users.", - "plugin.description.short": "Protect your API with a full authentication process based on JWT" + "plugin.description.short": "Protect your API with a full authentication process based on JWT", + "plugin.name": "Roles & Permission" }