diff --git a/packages/core/admin/admin/src/StrapiApp.js b/packages/core/admin/admin/src/StrapiApp.js
index 117accf157..36867db510 100644
--- a/packages/core/admin/admin/src/StrapiApp.js
+++ b/packages/core/admin/admin/src/StrapiApp.js
@@ -1,4 +1,4 @@
-import * as React from 'react';
+import React from 'react';
import { darkTheme, lightTheme } from '@strapi/design-system';
import invariant from 'invariant';
@@ -114,30 +114,14 @@ class StrapiApp {
);
invariant(
link.Component && typeof link.Component === 'function',
- `link.Component must be a function returning a Promise. Please use: \`Component: () => import(path)\` instead.`
+ `link.Component should be a valid React Component`
);
invariant(
link.icon && typeof link.icon === 'function',
`link.Icon should be a valid React Component`
);
- if (
- link.Component &&
- typeof link.Component === 'function' &&
- link.Component[Symbol.toStringTag] === 'AsyncFunction'
- ) {
- console.warn(`
- [deprecated] addMenuLink() was called with an async Component from the plugin "${link.intlLabel.Internationalization}". This will be removed
- in the future. Please use: \`Component: () => import(path)\` instead.
- `);
- }
-
- this.menu.push({
- ...link,
-
- // React.lazy can be removed once we migrate to react-router@6, because the component can handle it natively
- Component: React.lazy(link.Component),
- });
+ this.menu.push(link);
};
addMiddlewares = (middlewares) => {
@@ -165,26 +149,10 @@ class StrapiApp {
invariant(link.to, `link.to should be defined for ${stringifiedLink}`);
invariant(
link.Component && typeof link.Component === 'function',
- `link.Component must be a function returning a Promise. Please use: \`Component: () => import(path)\` instead.`
+ `link.Component should be a valid React Component`
);
- if (
- link.Component &&
- typeof link.Component === 'function' &&
- link.Component[Symbol.toStringTag] === 'AsyncFunction'
- ) {
- console.warn(`
- [deprecated] addSettingsLink() was called with an async Component from the plugin: "${link.intlLabel.Internationalization}". This will be removed
- in the future. Please use: \`Component: () => import(path)\` instead.
- `);
- }
-
- this.settings[sectionId].links.push({
- ...link,
-
- // React.lazy can be removed once we migrate to react-router@6, because the component can handle it natively
- Component: React.lazy(link.Component),
- });
+ this.settings[sectionId].links.push(link);
};
addSettingsLinks = (sectionId, links) => {
diff --git a/packages/core/admin/admin/src/components/Providers/index.js b/packages/core/admin/admin/src/components/Providers/index.js
index e7c10d5738..412891cbc7 100644
--- a/packages/core/admin/admin/src/components/Providers/index.js
+++ b/packages/core/admin/admin/src/components/Providers/index.js
@@ -111,8 +111,7 @@ Providers.propTypes = {
defaultMessage: PropTypes.string.isRequired,
}).isRequired,
permissions: PropTypes.array,
- // React.lazy loadable
- Component: PropTypes.object,
+ Component: PropTypes.func,
})
).isRequired,
menuLogo: PropTypes.oneOfType([PropTypes.string, PropTypes.any]).isRequired,
diff --git a/packages/core/admin/admin/src/pages/Admin/index.js b/packages/core/admin/admin/src/pages/Admin/index.js
index 2463a7f54d..dd0129a3d1 100644
--- a/packages/core/admin/admin/src/pages/Admin/index.js
+++ b/packages/core/admin/admin/src/pages/Admin/index.js
@@ -16,6 +16,7 @@ import { Route, Switch } from 'react-router-dom';
import LeftMenu from '../../components/LeftMenu';
import useConfigurations from '../../hooks/useConfigurations';
import useMenu from '../../hooks/useMenu';
+import { createRoute } from '../../utils/createRoute';
import { SET_APP_RUNTIME_STATUS } from '../App/constants';
const CM = React.lazy(() =>
@@ -75,6 +76,25 @@ export const Admin = () => {
}
}, [appStatus, dispatch, trackUsage]);
+ const routes = menu
+ .filter((link) => link.Component)
+
+ /**
+ * `Component` is an async function, which is passed as property of the
+ * addMenuLink() API during the plugin registration step.
+ *
+ * Because of that we can't just render ,
+ * but have to await the function.
+ *
+ * This isn't a good React pattern and should be reconsidered.
+ */
+
+ .map(({ to, Component, exact }) => createRoute(Component, to, exact));
+
+ if (isLoading) {
+ return ;
+ }
+
return (
@@ -84,31 +104,18 @@ export const Admin = () => {
/>
- {isLoading ? (
-
- ) : (
+ }>
- {menu.map(({ to, Component, exact }) => (
- (
- }>
-
-
- )}
- key={to}
- path={to}
- exact={exact || false}
- />
- ))}
+ {routes}
- )}
+
{/* TODO: we should move the logic to determine whether the guided tour is displayed
diff --git a/packages/core/admin/admin/src/pages/SettingsPage/constants.js b/packages/core/admin/admin/src/pages/SettingsPage/constants.js
index 3aaf3315c8..2ade0f5bbf 100644
--- a/packages/core/admin/admin/src/pages/SettingsPage/constants.js
+++ b/packages/core/admin/admin/src/pages/SettingsPage/constants.js
@@ -2,67 +2,67 @@ import * as React from 'react';
export const SETTINGS_ROUTES_CE = [
{
- Component: React.lazy(() =>
+ component: React.lazy(() =>
import(/* webpackChunkName: "admin-roles-list" */ './pages/Roles/ProtectedListPage')
),
path: '/settings/roles',
},
{
- Component: React.lazy(() =>
+ component: React.lazy(() =>
import(/* webpackChunkName: "admin-edit-roles-page" */ './pages/Roles/CreatePage')
),
path: '/settings/roles/duplicate/:id',
},
{
- Component: React.lazy(() =>
+ component: React.lazy(() =>
import(/* webpackChunkName: "admin-edit-roles-page" */ './pages/Roles/CreatePage')
),
path: '/settings/roles/new',
},
{
- Component: React.lazy(() =>
+ component: React.lazy(() =>
import(/* webpackChunkName: "admin-edit-roles-page" */ './pages/Roles/ProtectedEditPage')
),
path: '/settings/roles/:id',
},
{
- Component: React.lazy(() =>
+ component: React.lazy(() =>
import(/* webpackChunkName: "admin-users" */ './pages/Users/ProtectedListPage')
),
path: '/settings/users',
},
{
- Component: React.lazy(() =>
+ component: React.lazy(() =>
import(/* webpackChunkName: "admin-edit-users" */ './pages/Users/ProtectedEditPage')
),
path: '/settings/users/:id',
},
{
- Component: React.lazy(() =>
+ component: React.lazy(() =>
import(/* webpackChunkName: "webhook-edit-page" */ './pages/Webhooks/ProtectedCreateView')
),
path: '/settings/webhooks/create',
},
{
- Component: React.lazy(() =>
+ component: React.lazy(() =>
import(/* webpackChunkName: "webhook-edit-page" */ './pages/Webhooks/ProtectedEditView')
),
path: '/settings/webhooks/:id',
},
{
- Component: React.lazy(() =>
+ component: React.lazy(() =>
import(/* webpackChunkName: "webhook-list-page" */ './pages/Webhooks/ProtectedListView')
),
path: '/settings/webhooks',
},
{
- Component: React.lazy(() =>
+ component: React.lazy(() =>
import(/* webpackChunkName: "api-tokens-list-page" */ './pages/ApiTokens/ProtectedListView')
),
path: '/settings/api-tokens',
},
{
- Component: React.lazy(() =>
+ component: React.lazy(() =>
import(
/* webpackChunkName: "api-tokens-create-page" */ './pages/ApiTokens/ProtectedCreateView'
)
@@ -70,13 +70,13 @@ export const SETTINGS_ROUTES_CE = [
path: '/settings/api-tokens/create',
},
{
- Component: React.lazy(() =>
+ component: React.lazy(() =>
import(/* webpackChunkName: "api-tokens-edit-page" */ './pages/ApiTokens/ProtectedEditView')
),
path: '/settings/api-tokens/:id',
},
{
- Component: React.lazy(() =>
+ component: React.lazy(() =>
import(
/* webpackChunkName: "transfer-tokens-create-page" */ './pages/TransferTokens/ProtectedCreateView'
)
@@ -84,7 +84,7 @@ export const SETTINGS_ROUTES_CE = [
path: '/settings/transfer-tokens/create',
},
{
- Component: React.lazy(() =>
+ component: React.lazy(() =>
import(
/* webpackChunkName: "transfer-tokens-list-page" */ './pages/TransferTokens/ProtectedListView'
)
@@ -92,7 +92,7 @@ export const SETTINGS_ROUTES_CE = [
path: '/settings/transfer-tokens',
},
{
- Component: React.lazy(() =>
+ component: React.lazy(() =>
import(
/* webpackChunkName: "transfer-tokens-edit-page" */ './pages/TransferTokens/ProtectedEditView'
)
diff --git a/packages/core/admin/admin/src/pages/SettingsPage/index.js b/packages/core/admin/admin/src/pages/SettingsPage/index.js
index 428260f2b2..d502b7152e 100644
--- a/packages/core/admin/admin/src/pages/SettingsPage/index.js
+++ b/packages/core/admin/admin/src/pages/SettingsPage/index.js
@@ -8,6 +8,7 @@ import { Redirect, Route, Switch, useParams } from 'react-router-dom';
import { useSettingsMenu } from '../../hooks';
import { useEnterprise } from '../../hooks/useEnterprise';
+import { createRoute } from '../../utils/createRoute';
import SettingsNav from './components/SettingsNav';
import { SETTINGS_ROUTES_CE } from './constants';
@@ -30,6 +31,26 @@ export function SettingsPage() {
}
);
+ /**
+ * `Component` is an async function, which is passed as property of the
+ * addSettingsLink() API during the plugin bootstrap step.
+ *
+ * Because of that we can't just render ,
+ * but have to await the function.
+ *
+ * This isn't a good React pattern and should be reconsidered.
+ */
+
+ const pluginSettingsRoutes = Object.values(settings).flatMap((section) =>
+ section.links.map((link) => createRoute(link.Component, link.to, link.exact || false))
+ );
+
+ // Since the useSettingsMenu hook can make API calls in order to check the links permissions
+ // We need to add a loading state to prevent redirecting the user while permissions are being checked
+ if (isLoading) {
+ return ;
+ }
+
if (!settingId) {
return ;
}
@@ -43,49 +64,15 @@ export function SettingsPage() {
})}
/>
- {isLoading ? (
-
- ) : (
-
- (
- }>
-
-
- )}
- exact
- />
+
+
- {routes.map(({ path, Component }) => (
- (
- }>
-
-
- )}
- exact
- />
- ))}
+ {routes.map(({ path, component }) => (
+
+ ))}
- {Object.values(settings).flatMap((section) =>
- section.links.map(({ Component, to, exact }) => (
- (
- }>
-
-
- )}
- key={to}
- path={to}
- exact={exact || false}
- />
- ))
- )}
-
- )}
+ {pluginSettingsRoutes}
+
);
}
diff --git a/packages/core/admin/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/index.js b/packages/core/admin/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/index.js
index b8ac35a952..d863c007df 100644
--- a/packages/core/admin/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/index.js
+++ b/packages/core/admin/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/index.js
@@ -9,11 +9,11 @@ import {
HeaderLayout,
Layout,
Link,
+ Loader,
Main,
Typography,
} from '@strapi/design-system';
import {
- LoadingIndicatorPage,
prefixFileUrlWithBackendUrl,
SettingsPageTitle,
useAPIErrorHandler,
@@ -161,7 +161,12 @@ const ApplicationInfosPage = () => {
{isLoading ? (
-
+
+ {formatMessage({
+ id: 'Settings.application.isLoading',
+ defaultMessage: 'Loading',
+ })}
+
) : (