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,
};