diff --git a/docs/3.0.0-beta.x/plugin-development/frontend-settings-api.md b/docs/3.0.0-beta.x/plugin-development/frontend-settings-api.md index 66764c01e6..66b65e9898 100644 --- a/docs/3.0.0-beta.x/plugin-development/frontend-settings-api.md +++ b/docs/3.0.0-beta.x/plugin-development/frontend-settings-api.md @@ -191,3 +191,85 @@ export default strapi => { return strapi.registerPlugin(plugin); }; ``` + +## Adding a setting into the global section + +In order to add a link into the global section of the settings view you need to create a global array containing the links you want to add; + +**Path —** `plugins/my-plugin/admin/src/index.js`. + +``` +import pluginPkg from '../../package.json'; +// Import the component +import Settings from './containers/Settings'; +import SettingLink from './components/SettingLink'; +import pluginId from './pluginId'; + +export default strapi => { + const pluginDescription = + pluginPkg.strapi.description || pluginPkg.description; + + // Declare the links that will be injected into the settings menu + const menuSection = { + id: pluginId, + title: { + id: `${pluginId}.foo`, + defaultMessage: 'Super cool setting', + }, + links: [ + { + title: 'Setting page 1', + to: `${strapi.settingsBaseURL}/${pluginId}/setting1`, + name: 'setting1', + }, + { + title: { + id: `${pluginId}.bar`, + defaultMessage: 'Setting page 2', + }, + to: `${strapi.settingsBaseURL}/${pluginId}/setting2`, + name: 'setting2', + }, + ], + }; + + const plugin = { + blockerComponent: null, + blockerComponentProps: {}, + description: pluginDescription, + icon: pluginPkg.strapi.icon, + id: pluginId, + initializer: () => null, + injectedComponents: [], + isReady: true, + leftMenuLinks: [], + leftMenuSections: [], + mainComponent: null, + name: pluginPkg.strapi.name, + preventComponentRendering: false, + settings: { + // Add a link into the global section of the settings view + global: [ + { + title: 'Setting link 1', + to: `${strapi.settingsBaseURL}/setting-link-1`, + name: 'settingLink1', + Component: SettingLink, + // Bool : https://reacttraining.com/react-router/web/api/Route/exact-bool + exact: false, + }, + ], + mainComponent: Settings, + menuSection, + }, + trads: {}, + }; + + return strapi.registerPlugin(plugin); +}; + +``` + +::: danger +It is currently not possible to add a link into another plugin's setting section +::: diff --git a/packages/strapi-admin/admin/src/containers/SettingsPage/index.js b/packages/strapi-admin/admin/src/containers/SettingsPage/index.js index c69aa05b33..7721a34f3c 100644 --- a/packages/strapi-admin/admin/src/containers/SettingsPage/index.js +++ b/packages/strapi-admin/admin/src/containers/SettingsPage/index.js @@ -6,29 +6,30 @@ import React, { memo } from 'react'; import { useGlobalContext, LeftMenu, LeftMenuList } from 'strapi-helper-plugin'; -import { get } from 'lodash'; import { Switch, Redirect, Route, useParams } from 'react-router-dom'; - import EditView from '../Webhooks/EditView'; import ListView from '../Webhooks/ListView'; import SettingDispatcher from './SettingDispatcher'; import Wrapper from './Wrapper'; +import retrieveGlobalLinks from './utils/retrieveGlobalLinks'; +import retrievePluginsMenu from './utils/retrievePluginsMenu'; function SettingsPage() { const { settingId } = useParams(); const { formatMessage, plugins, settingsBaseURL } = useGlobalContext(); + // Retrieve the links that will be injected into the global section + const globalLinks = retrieveGlobalLinks(plugins); + // Create the plugins settings section + // Note it is currently not possible to add a link into a plugin section + const pluginsMenu = retrievePluginsMenu(plugins); - const pluginsMenu = Object.keys(plugins).reduce((acc, current) => { - const pluginMenu = get(plugins, [current, 'settings', 'menuSection'], null); - - if (!pluginMenu) { - return acc; - } - - acc.push(pluginMenu); - - return acc; - }, []); + const createdRoutes = globalLinks + .map(({ to, Component, exact }) => ( + + )) + .filter((route, index, refArray) => { + return refArray.findIndex(obj => obj.key === route.key) === index; + }); const menuItems = [ { @@ -40,6 +41,7 @@ function SettingsPage() { to: `${settingsBaseURL}/webhooks`, name: 'webhooks', }, + ...globalLinks, ], }, ...pluginsMenu, @@ -74,6 +76,7 @@ function SettingsPage() { path={`${settingsBaseURL}/webhooks/:id`} component={EditView} /> + {createdRoutes} { + return Object.values(pluginsObj).reduce((acc, current) => { + const links = get(current, ['settings', 'global'], null); + + if (links) { + for (let i = 0; i < links.length; i++) { + acc.push(links[i]); + } + } + + return acc; + }, []); +}; + +export default retrieveGlobalLinks; diff --git a/packages/strapi-admin/admin/src/containers/SettingsPage/utils/retrievePluginsMenu.js b/packages/strapi-admin/admin/src/containers/SettingsPage/utils/retrievePluginsMenu.js new file mode 100644 index 0000000000..ca703113bc --- /dev/null +++ b/packages/strapi-admin/admin/src/containers/SettingsPage/utils/retrievePluginsMenu.js @@ -0,0 +1,17 @@ +import { get } from 'lodash'; + +const retrievePluginsMenu = pluginsObj => { + return Object.values(pluginsObj).reduce((acc, current) => { + const pluginMenu = get(current, ['settings', 'menuSection'], null); + + if (!pluginMenu) { + return acc; + } + + acc.push(pluginMenu); + + return acc; + }, []); +}; + +export default retrievePluginsMenu; diff --git a/packages/strapi-admin/admin/src/containers/SettingsPage/utils/tests/retrieveGlobalLinks.test.js b/packages/strapi-admin/admin/src/containers/SettingsPage/utils/tests/retrieveGlobalLinks.test.js new file mode 100644 index 0000000000..85509eb280 --- /dev/null +++ b/packages/strapi-admin/admin/src/containers/SettingsPage/utils/tests/retrieveGlobalLinks.test.js @@ -0,0 +1,33 @@ +import retrieveGlobalLinks from '../retrieveGlobalLinks'; + +describe('ADMIN | containers | SettingsPage | utils', () => { + describe('retrieveGlobalLinks', () => { + it('should return an empty array if there is no plugins', () => { + expect(retrieveGlobalLinks({})).toHaveLength(0); + }); + + it('should return an array of links', () => { + const plugins = { + test: { + settings: { + global: [], + }, + }, + noSettings: {}, + foo: { + settings: { + global: ['test'], + }, + }, + bar: { + settings: { + global: ['test2'], + }, + }, + }; + const expected = ['test', 'test2']; + + expect(retrieveGlobalLinks(plugins)).toEqual(expected); + }); + }); +}); diff --git a/packages/strapi-admin/admin/src/containers/SettingsPage/utils/tests/retrievePluginsMenu.test.js b/packages/strapi-admin/admin/src/containers/SettingsPage/utils/tests/retrievePluginsMenu.test.js new file mode 100644 index 0000000000..ca0c3d68e7 --- /dev/null +++ b/packages/strapi-admin/admin/src/containers/SettingsPage/utils/tests/retrievePluginsMenu.test.js @@ -0,0 +1,33 @@ +import retrievePluginsMenu from '../retrievePluginsMenu'; + +describe('ADMIN | containers | SettingsPage | utils', () => { + describe('retrievePluginsMenu', () => { + it('should return an empty array if there is no plugins', () => { + expect(retrievePluginsMenu({})).toHaveLength(0); + }); + + it('should return an array of menu sections', () => { + const plugins = { + test: { + settings: { + menuSection: null, + }, + }, + noSettings: {}, + foo: { + settings: { + menuSection: { label: 'test' }, + }, + }, + bar: { + settings: { + menuSection: { label: 'test2' }, + }, + }, + }; + const expected = [{ label: 'test' }, { label: 'test2' }]; + + expect(retrievePluginsMenu(plugins)).toEqual(expected); + }); + }); +}); diff --git a/packages/strapi-plugin-upload/admin/src/index.js b/packages/strapi-plugin-upload/admin/src/index.js index 117fa0c5e7..6e85c88288 100644 --- a/packages/strapi-plugin-upload/admin/src/index.js +++ b/packages/strapi-plugin-upload/admin/src/index.js @@ -4,6 +4,7 @@ import App from './containers/App'; import trads from './translations'; import pluginId from './pluginId'; +import getTrad from './utils/getTrad'; export default strapi => { const pluginDescription = @@ -25,6 +26,20 @@ export default strapi => { name: pluginPkg.strapi.name, pluginLogo, preventComponentRendering: false, + settings: { + global: [ + { + title: { + id: getTrad('settings.link.label'), + defaultMessage: 'Media Library', + }, + name: 'media-library', + to: `${strapi.settingsBaseURL}/media-library`, + // TODO + Component: () => 'COMING SOON', + }, + ], + }, trads, };