mirror of
https://github.com/strapi/strapi.git
synced 2025-09-25 08:19:07 +00:00
Merge pull request #16871 from strapi/enhancement/use-enterprise-hook
POC: Add useEnterprise() hook; refactor settings router
This commit is contained in:
commit
86eaf9f728
56
docs/docs/docs/01-core/admin/04-hooks/use-enterprise.mdx
Normal file
56
docs/docs/docs/01-core/admin/04-hooks/use-enterprise.mdx
Normal file
@ -0,0 +1,56 @@
|
||||
---
|
||||
title: useEnterprise
|
||||
description: API reference for the useEnterprise hook
|
||||
tags:
|
||||
- admin
|
||||
- hooks
|
||||
- users
|
||||
---
|
||||
|
||||
A hook that returns either community or enterprise-edition data-structures based on the global `window.strapi.isEE` flag.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
import { CE_DATA } from './data';
|
||||
|
||||
function Component() {
|
||||
const data = useEnterprise(CE_DATA, async () => (await import('./ee/data')).default);
|
||||
}
|
||||
```
|
||||
|
||||
It accepts an optional third argument to pass in options customizing the hook behavior:
|
||||
|
||||
### `combine()`
|
||||
|
||||
THe `combine` callback can be used as a custom "merge" function for the ce and ee arguments:
|
||||
|
||||
```
|
||||
const data = useEnterprise({ a: 1 }, () => { b: 1 }, { combine(ce, ee) { return { ...ce, ...ee } } });
|
||||
|
||||
console.log(data); // { a: 1, b: 1 }
|
||||
```
|
||||
|
||||
### `defaultValue`
|
||||
|
||||
By default the hook returns `null` if `window.strapi.isEE` is true and the enterprise data structure is not yet loaded. Customizing
|
||||
this value can help implementing various loading scenarios:
|
||||
|
||||
```
|
||||
// display a loading state while an EE component is loading
|
||||
const Component = useEnterprise(() => <p>CE</p>, () => <p>EE</p>, {
|
||||
defaultValue: () => <div>loading ...</div>
|
||||
})
|
||||
|
||||
// display nothing while an EE component is loading, but don't block the overall rendering
|
||||
const Component = useEnterprise(() => <p>CE</p>, () => <p>EE</p>, {
|
||||
defaultValue: () => null
|
||||
})
|
||||
|
||||
// display nothing while an EE component is loading
|
||||
const Component = useEnterprise(() => <p>CE</p>, () => <p>EE</p>)
|
||||
|
||||
if (!Component) {
|
||||
return;
|
||||
}
|
||||
```
|
@ -0,0 +1 @@
|
||||
export * from './useEnterprise';
|
@ -0,0 +1,66 @@
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
|
||||
import { useEnterprise } from '../useEnterprise';
|
||||
|
||||
const CE_DATA_FIXTURE = ['CE'];
|
||||
const EE_DATA_FIXTURE = ['EE'];
|
||||
|
||||
function setup(...args) {
|
||||
return renderHook(() => useEnterprise(...args));
|
||||
}
|
||||
|
||||
describe('useEnterprise (CE)', () => {
|
||||
test('Returns CE data', async () => {
|
||||
const { result } = setup(CE_DATA_FIXTURE, async () => EE_DATA_FIXTURE);
|
||||
|
||||
expect(result.current).toBe(CE_DATA_FIXTURE);
|
||||
});
|
||||
});
|
||||
|
||||
describe('useEnterprise (EE)', () => {
|
||||
beforeAll(() => {
|
||||
window.strapi.isEE = true;
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
window.strapi.isEE = false;
|
||||
});
|
||||
|
||||
test('Returns default data on first render and EE data on second', async () => {
|
||||
const { result } = setup(CE_DATA_FIXTURE, async () => EE_DATA_FIXTURE);
|
||||
|
||||
expect(result.current).toBe(null);
|
||||
|
||||
await waitFor(() => expect(result.current).toBe(EE_DATA_FIXTURE));
|
||||
});
|
||||
|
||||
test('Combines CE and EE data', async () => {
|
||||
const { result } = setup(CE_DATA_FIXTURE, async () => EE_DATA_FIXTURE, {
|
||||
combine(ceData, eeData) {
|
||||
return [...ceData, ...eeData];
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.current).toBe(null);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(result.current).toStrictEqual([...CE_DATA_FIXTURE, ...EE_DATA_FIXTURE])
|
||||
);
|
||||
});
|
||||
|
||||
test('Returns EE data without custom combine', async () => {
|
||||
const { result } = setup(CE_DATA_FIXTURE, async () => EE_DATA_FIXTURE);
|
||||
|
||||
await waitFor(() => expect(result.current).toStrictEqual(EE_DATA_FIXTURE));
|
||||
});
|
||||
|
||||
test('Returns a custom defaultValue on first render followed by the EE data', async () => {
|
||||
const { result } = setup(CE_DATA_FIXTURE, async () => EE_DATA_FIXTURE, {
|
||||
defaultValue: false,
|
||||
});
|
||||
|
||||
expect(result.current).toBe(false);
|
||||
|
||||
await waitFor(() => expect(result.current).toStrictEqual(EE_DATA_FIXTURE));
|
||||
});
|
||||
});
|
@ -0,0 +1,36 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { useCallbackRef } from '@strapi/helper-plugin';
|
||||
|
||||
function isEnterprise() {
|
||||
return window.strapi.isEE;
|
||||
}
|
||||
|
||||
export function useEnterprise(
|
||||
ceData,
|
||||
eeCallback,
|
||||
{ defaultValue = null, combine = (ceData, eeData) => eeData } = {}
|
||||
) {
|
||||
const eeCallbackRef = useCallbackRef(eeCallback);
|
||||
const combineCallbackRef = useCallbackRef(combine);
|
||||
|
||||
// We have to use a nested object here, because functions (e.g. Components)
|
||||
// can not be stored as value directly
|
||||
const [{ data }, setData] = React.useState({
|
||||
data: isEnterprise() ? defaultValue : ceData,
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
async function importEE() {
|
||||
const eeData = await eeCallbackRef();
|
||||
|
||||
setData({ data: combineCallbackRef(ceData, eeData) });
|
||||
}
|
||||
|
||||
if (isEnterprise()) {
|
||||
importEE();
|
||||
}
|
||||
}, [ceData, eeCallbackRef, combineCallbackRef]);
|
||||
|
||||
return data;
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
import adminPermissions from '../../permissions';
|
||||
|
||||
export const LINKS_CE = {
|
||||
global: [
|
||||
{
|
||||
intlLabel: { id: 'Settings.application.title', defaultMessage: 'Overview' },
|
||||
to: '/settings/application-infos',
|
||||
id: '000-application-infos',
|
||||
permissions: [],
|
||||
},
|
||||
{
|
||||
intlLabel: { id: 'Settings.webhooks.title', defaultMessage: 'Webhooks' },
|
||||
to: '/settings/webhooks',
|
||||
id: 'webhooks',
|
||||
permissions: adminPermissions.settings.webhooks.main,
|
||||
},
|
||||
{
|
||||
intlLabel: { id: 'Settings.apiTokens.title', defaultMessage: 'API Tokens' },
|
||||
to: '/settings/api-tokens?sort=name:ASC',
|
||||
id: 'api-tokens',
|
||||
permissions: adminPermissions.settings['api-tokens'].main,
|
||||
},
|
||||
{
|
||||
intlLabel: { id: 'Settings.transferTokens.title', defaultMessage: 'Transfer Tokens' },
|
||||
to: '/settings/transfer-tokens?sort=name:ASC',
|
||||
id: 'transfer-tokens',
|
||||
permissions: adminPermissions.settings['transfer-tokens'].main,
|
||||
},
|
||||
],
|
||||
|
||||
admin: [
|
||||
{
|
||||
intlLabel: { id: 'global.roles', defaultMessage: 'Roles' },
|
||||
to: '/settings/roles',
|
||||
id: 'roles',
|
||||
permissions: adminPermissions.settings.roles.main,
|
||||
},
|
||||
{
|
||||
intlLabel: { id: 'global.users' },
|
||||
// Init the search params directly
|
||||
to: '/settings/users?pageSize=10&page=1&sort=firstname',
|
||||
id: 'users',
|
||||
permissions: adminPermissions.settings.users.main,
|
||||
},
|
||||
],
|
||||
};
|
@ -1,56 +1,95 @@
|
||||
import { useEffect, useReducer } from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
import { hasPermissions, useAppInfo, useRBACProvider, useStrapiApp } from '@strapi/helper-plugin';
|
||||
import { hasPermissions, useRBACProvider, useStrapiApp, useAppInfo } from '@strapi/helper-plugin';
|
||||
|
||||
import init from './init';
|
||||
import reducer, { initialState } from './reducer';
|
||||
import { useEnterprise } from '../useEnterprise';
|
||||
|
||||
const useSettingsMenu = (noCheck = false) => {
|
||||
import { LINKS_CE } from './constants';
|
||||
import formatLinks from './utils/formatLinks';
|
||||
import sortLinks from './utils/sortLinks';
|
||||
|
||||
const useSettingsMenu = () => {
|
||||
const [{ isLoading, menu }, setData] = useState({
|
||||
isLoading: true,
|
||||
menu: [],
|
||||
});
|
||||
const { allPermissions: permissions } = useRBACProvider();
|
||||
const { shouldUpdateStrapi } = useAppInfo();
|
||||
const { settings } = useStrapiApp();
|
||||
|
||||
const [{ isLoading, menu }, dispatch] = useReducer(reducer, initialState, () =>
|
||||
init(initialState, { settings, shouldUpdateStrapi })
|
||||
const { global: globalLinks, admin: adminLinks } = useEnterprise(
|
||||
LINKS_CE,
|
||||
async () => (await import('../../../../ee/admin/hooks/useSettingsMenu/constants')).LINKS_EE,
|
||||
{
|
||||
combine(ceLinks, eeLinks) {
|
||||
return {
|
||||
admin: [...eeLinks.admin, ...ceLinks.admin],
|
||||
global: [...ceLinks.global, ...eeLinks.global],
|
||||
};
|
||||
},
|
||||
defaultValue: {
|
||||
admin: [],
|
||||
global: [],
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const getData = async () => {
|
||||
const checkPermissions = async (permissionsToCheck, path) => {
|
||||
const hasPermission = await hasPermissions(permissions, permissionsToCheck);
|
||||
const buildMenuPermissions = (sections) =>
|
||||
Promise.all(
|
||||
sections.reduce((acc, section, sectionIndex) => {
|
||||
const buildMenuPermissions = (links) =>
|
||||
links.map(async (link, linkIndex) => ({
|
||||
hasPermission: await hasPermissions(permissions, link.permissions),
|
||||
sectionIndex,
|
||||
linkIndex,
|
||||
}));
|
||||
|
||||
return { hasPermission, path };
|
||||
};
|
||||
return [...acc, ...buildMenuPermissions(section.links)];
|
||||
}, [])
|
||||
);
|
||||
|
||||
const generateArrayOfPromises = (array) => {
|
||||
return array.reduce((acc, current, sectionIndex) => {
|
||||
const generateArrayOfPromises = (array) =>
|
||||
array.map((link, index) =>
|
||||
checkPermissions(array[index].permissions, `${sectionIndex}.links.${index}`)
|
||||
const menuPermissions = await buildMenuPermissions(sections);
|
||||
|
||||
setData((prev) => ({
|
||||
...prev,
|
||||
isLoading: false,
|
||||
menu: sections.map((section, sectionIndex) => ({
|
||||
...section,
|
||||
links: section.links.map((link, linkIndex) => {
|
||||
const permission = menuPermissions.find(
|
||||
(permission) =>
|
||||
permission.sectionIndex === sectionIndex && permission.linkIndex === linkIndex
|
||||
);
|
||||
|
||||
return [...acc, ...generateArrayOfPromises(current.links)];
|
||||
}, []);
|
||||
};
|
||||
|
||||
const generalSectionLinksArrayOfPromises = generateArrayOfPromises(menu);
|
||||
|
||||
const data = await Promise.all(generalSectionLinksArrayOfPromises);
|
||||
|
||||
dispatch({
|
||||
type: 'CHECK_PERMISSIONS_SUCCEEDED',
|
||||
data,
|
||||
});
|
||||
return {
|
||||
...link,
|
||||
isDisplayed: Boolean(permission.hasPermission),
|
||||
};
|
||||
}),
|
||||
})),
|
||||
}));
|
||||
};
|
||||
|
||||
// This hook is also used by the main LeftMenu component in order to know which sections it needs to display/hide
|
||||
// Therefore, we don't need to make the checking all the times when the hook is used.
|
||||
if (!noCheck) {
|
||||
getData();
|
||||
}
|
||||
const { global, ...otherSections } = settings;
|
||||
const sections = formatLinks([
|
||||
{
|
||||
...settings.global,
|
||||
links: sortLinks([...settings.global.links, ...globalLinks]).map((link) => ({
|
||||
...link,
|
||||
hasNotification: link.id === '000-application-infos' && shouldUpdateStrapi,
|
||||
})),
|
||||
},
|
||||
{
|
||||
id: 'permissions',
|
||||
intlLabel: { id: 'Settings.permissions', defaultMessage: 'Administration Panel' },
|
||||
links: adminLinks,
|
||||
},
|
||||
...Object.values(otherSections),
|
||||
]);
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [permissions, noCheck]);
|
||||
getData();
|
||||
}, [adminLinks, globalLinks, permissions, settings, shouldUpdateStrapi]);
|
||||
|
||||
return { isLoading, menu };
|
||||
};
|
||||
|
@ -1,35 +0,0 @@
|
||||
import omit from 'lodash/omit';
|
||||
|
||||
import adminLinks from './utils/adminLinks';
|
||||
import formatLinks from './utils/formatLinks';
|
||||
import globalLinks from './utils/globalLinks';
|
||||
import sortLinks from './utils/sortLinks';
|
||||
|
||||
const init = (initialState, { settings, shouldUpdateStrapi }) => {
|
||||
// Retrieve the links that will be injected into the global section
|
||||
const pluginsGlobalLinks = settings.global.links;
|
||||
// Sort the links by name
|
||||
const sortedGlobalLinks = sortLinks([...pluginsGlobalLinks, ...globalLinks]).map((link) => ({
|
||||
...link,
|
||||
hasNotification: link.id === '000-application-infos' && shouldUpdateStrapi,
|
||||
}));
|
||||
|
||||
const otherSections = Object.values(omit(settings, 'global'));
|
||||
|
||||
const menu = [
|
||||
{
|
||||
...settings.global,
|
||||
links: sortedGlobalLinks,
|
||||
},
|
||||
{
|
||||
id: 'permissions',
|
||||
intlLabel: { id: 'Settings.permissions', defaultMessage: 'Administration Panel' },
|
||||
links: adminLinks,
|
||||
},
|
||||
...otherSections,
|
||||
];
|
||||
|
||||
return { ...initialState, menu: formatLinks(menu) };
|
||||
};
|
||||
|
||||
export default init;
|
@ -1,41 +0,0 @@
|
||||
import produce from 'immer';
|
||||
import set from 'lodash/set';
|
||||
|
||||
const initialState = {
|
||||
menu: [],
|
||||
isLoading: true,
|
||||
};
|
||||
|
||||
const reducer = (state, action) =>
|
||||
// eslint-disable-next-line consistent-return
|
||||
produce(state, (draftState) => {
|
||||
switch (action.type) {
|
||||
case 'CHECK_PERMISSIONS_SUCCEEDED': {
|
||||
action.data.forEach((checkedPermissions) => {
|
||||
if (checkedPermissions.hasPermission) {
|
||||
set(
|
||||
draftState,
|
||||
['menu', ...checkedPermissions.path.split('.'), 'isDisplayed'],
|
||||
checkedPermissions.hasPermission
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// Remove the not needed links in each section
|
||||
draftState.menu.forEach((section, sectionIndex) => {
|
||||
draftState.menu[sectionIndex].links = section.links.filter(
|
||||
(link) => link.isDisplayed === true
|
||||
);
|
||||
});
|
||||
|
||||
draftState.isLoading = false;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return draftState;
|
||||
}
|
||||
});
|
||||
|
||||
export default reducer;
|
||||
export { initialState };
|
@ -1,116 +0,0 @@
|
||||
import reducer from '../reducer';
|
||||
|
||||
describe('ADMIN | hooks | useSettingsMenu | reducer', () => {
|
||||
describe('DEFAULT_ACTION', () => {
|
||||
it('should return the state', () => {
|
||||
const initialState = {
|
||||
ok: true,
|
||||
};
|
||||
const expected = {
|
||||
ok: true,
|
||||
};
|
||||
|
||||
expect(reducer(initialState, {})).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('CHECK_PERMISSIONS_SUCCEEDED', () => {
|
||||
it('should set the permissions correctly', () => {
|
||||
const initialState = {
|
||||
isLoading: true,
|
||||
menu: [
|
||||
{
|
||||
id: 'global',
|
||||
links: [
|
||||
{
|
||||
to: 'global.test',
|
||||
isDisplayed: false,
|
||||
},
|
||||
{
|
||||
to: 'global.test2',
|
||||
isDisplayed: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'test',
|
||||
links: [
|
||||
{
|
||||
to: 'test.test',
|
||||
isDisplayed: false,
|
||||
},
|
||||
{
|
||||
to: 'test.test2',
|
||||
isDisplayed: false,
|
||||
},
|
||||
{
|
||||
to: 'test.test3',
|
||||
isDisplayed: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'test1',
|
||||
links: [
|
||||
{
|
||||
to: 'test1.test',
|
||||
isDisplayed: false,
|
||||
},
|
||||
{
|
||||
to: 'test1.test2',
|
||||
isDisplayed: false,
|
||||
},
|
||||
{
|
||||
to: 'test1.test3',
|
||||
isDisplayed: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
const action = {
|
||||
type: 'CHECK_PERMISSIONS_SUCCEEDED',
|
||||
data: [
|
||||
{ hasPermission: true, path: '1.links.0' },
|
||||
{ hasPermission: true, path: '1.links.1' },
|
||||
{ hasPermission: true, path: '0.links.1' },
|
||||
{ hasPermission: undefined, path: '2.links.0' },
|
||||
],
|
||||
};
|
||||
|
||||
const expected = {
|
||||
isLoading: false,
|
||||
menu: [
|
||||
{
|
||||
id: 'global',
|
||||
links: [
|
||||
{
|
||||
to: 'global.test2',
|
||||
isDisplayed: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'test',
|
||||
links: [
|
||||
{
|
||||
to: 'test.test',
|
||||
isDisplayed: true,
|
||||
},
|
||||
{
|
||||
to: 'test.test2',
|
||||
isDisplayed: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'test1',
|
||||
links: [],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
expect(reducer(initialState, action)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,5 +0,0 @@
|
||||
import customAdminLinks from 'ee_else_ce/hooks/useSettingsMenu/utils/customAdminLinks';
|
||||
|
||||
import defaultAdminLinks from './defaultAdminLinks';
|
||||
|
||||
export default [...customAdminLinks, ...defaultAdminLinks];
|
@ -1 +0,0 @@
|
||||
export default [];
|
@ -1 +0,0 @@
|
||||
export default [];
|
@ -1,21 +0,0 @@
|
||||
import adminPermissions from '../../../permissions';
|
||||
|
||||
const defaultAdminLinks = [
|
||||
{
|
||||
intlLabel: { id: 'global.roles', defaultMessage: 'Roles' },
|
||||
to: '/settings/roles',
|
||||
id: 'roles',
|
||||
isDisplayed: false,
|
||||
permissions: adminPermissions.settings.roles.main,
|
||||
},
|
||||
{
|
||||
intlLabel: { id: 'global.users' },
|
||||
// Init the search params directly
|
||||
to: '/settings/users?pageSize=10&page=1&sort=firstname',
|
||||
id: 'users',
|
||||
isDisplayed: false,
|
||||
permissions: adminPermissions.settings.users.main,
|
||||
},
|
||||
];
|
||||
|
||||
export default defaultAdminLinks;
|
@ -1,34 +0,0 @@
|
||||
import adminPermissions from '../../../permissions';
|
||||
|
||||
const defaultGlobalLinks = [
|
||||
{
|
||||
intlLabel: { id: 'Settings.application.title', defaultMessage: 'Overview' },
|
||||
to: '/settings/application-infos',
|
||||
id: '000-application-infos',
|
||||
isDisplayed: false,
|
||||
permissions: [],
|
||||
},
|
||||
{
|
||||
intlLabel: { id: 'Settings.webhooks.title', defaultMessage: 'Webhooks' },
|
||||
to: '/settings/webhooks',
|
||||
id: 'webhooks',
|
||||
isDisplayed: false,
|
||||
permissions: adminPermissions.settings.webhooks.main,
|
||||
},
|
||||
{
|
||||
intlLabel: { id: 'Settings.apiTokens.title', defaultMessage: 'API Tokens' },
|
||||
to: '/settings/api-tokens?sort=name:ASC',
|
||||
id: 'api-tokens',
|
||||
isDisplayed: false,
|
||||
permissions: adminPermissions.settings['api-tokens'].main,
|
||||
},
|
||||
{
|
||||
intlLabel: { id: 'Settings.transferTokens.title', defaultMessage: 'Transfer Tokens' },
|
||||
to: '/settings/transfer-tokens?sort=name:ASC',
|
||||
id: 'transfer-tokens',
|
||||
isDisplayed: false,
|
||||
permissions: adminPermissions.settings['transfer-tokens'].main,
|
||||
},
|
||||
];
|
||||
|
||||
export default defaultGlobalLinks;
|
@ -1,5 +0,0 @@
|
||||
import customGlobalLinks from 'ee_else_ce/hooks/useSettingsMenu/utils/customGlobalLinks';
|
||||
|
||||
import defaultGlobalLinks from './defaultGlobalLinks';
|
||||
|
||||
export default [...defaultGlobalLinks, ...customGlobalLinks];
|
@ -1 +1,3 @@
|
||||
export const SET_APP_RUNTIME_STATUS = 'StrapiAdmin/APP/SET_APP_RUNTIME_STATUS';
|
||||
|
||||
export const ROUTES_CE = [];
|
||||
|
@ -21,19 +21,27 @@ import { Route, Switch } from 'react-router-dom';
|
||||
|
||||
import PrivateRoute from '../../components/PrivateRoute';
|
||||
import { useConfigurations } from '../../hooks';
|
||||
import { useEnterprise } from '../../hooks/useEnterprise';
|
||||
import { createRoute, makeUniqueRoutes } from '../../utils';
|
||||
import AuthPage from '../AuthPage';
|
||||
import NotFoundPage from '../NotFoundPage';
|
||||
import UseCasePage from '../UseCasePage';
|
||||
|
||||
import { ROUTES_CE } from './constants';
|
||||
import { getUID } from './utils';
|
||||
import routes from './utils/routes';
|
||||
|
||||
const AuthenticatedApp = lazy(() =>
|
||||
import(/* webpackChunkName: "Admin-authenticatedApp" */ '../../components/AuthenticatedApp')
|
||||
);
|
||||
|
||||
function App() {
|
||||
const routes = useEnterprise(
|
||||
ROUTES_CE,
|
||||
async () => (await import('../../../../ee/admin/pages/App/constants')).ROUTES_EE,
|
||||
{
|
||||
defaultValue: [],
|
||||
}
|
||||
);
|
||||
const toggleNotification = useNotification();
|
||||
const { updateProjectSettings } = useConfigurations();
|
||||
const { formatMessage } = useIntl();
|
||||
@ -48,7 +56,7 @@ function App() {
|
||||
return makeUniqueRoutes(
|
||||
routes.map(({ to, Component, exact }) => createRoute(Component, to, exact))
|
||||
);
|
||||
}, []);
|
||||
}, [routes]);
|
||||
|
||||
const [telemetryProperties, setTelemetryProperties] = useState(null);
|
||||
|
||||
|
@ -1,3 +0,0 @@
|
||||
const customRoutes = [];
|
||||
|
||||
export default customRoutes;
|
@ -1,3 +0,0 @@
|
||||
const defaultRoutes = [];
|
||||
|
||||
export default defaultRoutes;
|
@ -1,3 +1,3 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
export { default as routes } from './routes';
|
||||
|
||||
export { default as getUID } from './unique-identifier';
|
||||
|
@ -1,5 +0,0 @@
|
||||
import customRoutes from 'ee_else_ce/pages/App/utils/customRoutes';
|
||||
|
||||
import defaultRoutes from './defaultRoutes';
|
||||
|
||||
export default [...customRoutes, ...defaultRoutes];
|
@ -1,8 +1,8 @@
|
||||
const defaultRoutes = [
|
||||
export const ROUTES_CE = [
|
||||
{
|
||||
async Component() {
|
||||
const component = await import(
|
||||
/* webpackChunkName: "admin-roles-list" */ '../pages/Roles/ProtectedListPage'
|
||||
/* webpackChunkName: "admin-roles-list" */ './pages/Roles/ProtectedListPage'
|
||||
);
|
||||
|
||||
return component;
|
||||
@ -13,7 +13,7 @@ const defaultRoutes = [
|
||||
{
|
||||
async Component() {
|
||||
const component = await import(
|
||||
/* webpackChunkName: "admin-edit-roles-page" */ '../pages/Roles/CreatePage'
|
||||
/* webpackChunkName: "admin-edit-roles-page" */ './pages/Roles/CreatePage'
|
||||
);
|
||||
|
||||
return component;
|
||||
@ -24,7 +24,7 @@ const defaultRoutes = [
|
||||
{
|
||||
async Component() {
|
||||
const component = await import(
|
||||
/* webpackChunkName: "admin-edit-roles-page" */ '../pages/Roles/CreatePage'
|
||||
/* webpackChunkName: "admin-edit-roles-page" */ './pages/Roles/CreatePage'
|
||||
);
|
||||
|
||||
return component;
|
||||
@ -35,7 +35,7 @@ const defaultRoutes = [
|
||||
{
|
||||
async Component() {
|
||||
const component = await import(
|
||||
/* webpackChunkName: "admin-edit-roles-page" */ '../pages/Roles/ProtectedEditPage'
|
||||
/* webpackChunkName: "admin-edit-roles-page" */ './pages/Roles/ProtectedEditPage'
|
||||
);
|
||||
|
||||
return component;
|
||||
@ -46,7 +46,7 @@ const defaultRoutes = [
|
||||
{
|
||||
async Component() {
|
||||
const component = await import(
|
||||
/* webpackChunkName: "admin-users" */ '../pages/Users/ProtectedListPage'
|
||||
/* webpackChunkName: "admin-users" */ './pages/Users/ProtectedListPage'
|
||||
);
|
||||
|
||||
return component;
|
||||
@ -57,7 +57,7 @@ const defaultRoutes = [
|
||||
{
|
||||
async Component() {
|
||||
const component = await import(
|
||||
/* webpackChunkName: "admin-edit-users" */ '../pages/Users/ProtectedEditPage'
|
||||
/* webpackChunkName: "admin-edit-users" */ './pages/Users/ProtectedEditPage'
|
||||
);
|
||||
|
||||
return component;
|
||||
@ -68,7 +68,7 @@ const defaultRoutes = [
|
||||
{
|
||||
async Component() {
|
||||
const component = await import(
|
||||
/* webpackChunkName: "webhook-edit-page" */ '../pages/Webhooks/ProtectedCreateView'
|
||||
/* webpackChunkName: "webhook-edit-page" */ './pages/Webhooks/ProtectedCreateView'
|
||||
);
|
||||
|
||||
return component;
|
||||
@ -79,7 +79,7 @@ const defaultRoutes = [
|
||||
{
|
||||
async Component() {
|
||||
const component = await import(
|
||||
/* webpackChunkName: "webhook-edit-page" */ '../pages/Webhooks/ProtectedEditView'
|
||||
/* webpackChunkName: "webhook-edit-page" */ './pages/Webhooks/ProtectedEditView'
|
||||
);
|
||||
|
||||
return component;
|
||||
@ -90,7 +90,7 @@ const defaultRoutes = [
|
||||
{
|
||||
async Component() {
|
||||
const component = await import(
|
||||
/* webpackChunkName: "webhook-list-page" */ '../pages/Webhooks/ProtectedListView'
|
||||
/* webpackChunkName: "webhook-list-page" */ './pages/Webhooks/ProtectedListView'
|
||||
);
|
||||
|
||||
return component;
|
||||
@ -101,7 +101,7 @@ const defaultRoutes = [
|
||||
{
|
||||
async Component() {
|
||||
const component = await import(
|
||||
/* webpackChunkName: "api-tokens-list-page" */ '../pages/ApiTokens/ProtectedListView'
|
||||
/* webpackChunkName: "api-tokens-list-page" */ './pages/ApiTokens/ProtectedListView'
|
||||
);
|
||||
|
||||
return component;
|
||||
@ -112,7 +112,7 @@ const defaultRoutes = [
|
||||
{
|
||||
async Component() {
|
||||
const component = await import(
|
||||
/* webpackChunkName: "api-tokens-create-page" */ '../pages/ApiTokens/ProtectedCreateView'
|
||||
/* webpackChunkName: "api-tokens-create-page" */ './pages/ApiTokens/ProtectedCreateView'
|
||||
);
|
||||
|
||||
return component;
|
||||
@ -123,7 +123,7 @@ const defaultRoutes = [
|
||||
{
|
||||
async Component() {
|
||||
const component = await import(
|
||||
/* webpackChunkName: "api-tokens-edit-page" */ '../pages/ApiTokens/ProtectedEditView'
|
||||
/* webpackChunkName: "api-tokens-edit-page" */ './pages/ApiTokens/ProtectedEditView'
|
||||
);
|
||||
|
||||
return component;
|
||||
@ -134,7 +134,7 @@ const defaultRoutes = [
|
||||
{
|
||||
async Component() {
|
||||
const component = await import(
|
||||
/* webpackChunkName: "transfer-tokens-create-page" */ '../pages/TransferTokens/ProtectedCreateView'
|
||||
/* webpackChunkName: "transfer-tokens-create-page" */ './pages/TransferTokens/ProtectedCreateView'
|
||||
);
|
||||
|
||||
return component;
|
||||
@ -145,7 +145,7 @@ const defaultRoutes = [
|
||||
{
|
||||
async Component() {
|
||||
const component = await import(
|
||||
/* webpackChunkName: "transfer-tokens-list-page" */ '../pages/TransferTokens/ProtectedListView'
|
||||
/* webpackChunkName: "transfer-tokens-list-page" */ './pages/TransferTokens/ProtectedListView'
|
||||
);
|
||||
|
||||
return component;
|
||||
@ -156,7 +156,7 @@ const defaultRoutes = [
|
||||
{
|
||||
async Component() {
|
||||
const component = await import(
|
||||
/* webpackChunkName: "transfer-tokens-edit-page" */ '../pages/TransferTokens/ProtectedEditView'
|
||||
/* webpackChunkName: "transfer-tokens-edit-page" */ './pages/TransferTokens/ProtectedEditView'
|
||||
);
|
||||
|
||||
return component;
|
||||
@ -165,5 +165,3 @@ const defaultRoutes = [
|
||||
exact: true,
|
||||
},
|
||||
];
|
||||
|
||||
export default defaultRoutes;
|
@ -18,24 +18,36 @@ import { useIntl } from 'react-intl';
|
||||
import { Redirect, Route, Switch, useParams } from 'react-router-dom';
|
||||
|
||||
import { useSettingsMenu } from '../../hooks';
|
||||
import { useEnterprise } from '../../hooks/useEnterprise';
|
||||
import { createRoute, makeUniqueRoutes } from '../../utils';
|
||||
|
||||
import SettingsNav from './components/SettingsNav';
|
||||
import { ROUTES_CE } from './constants';
|
||||
import ApplicationInfosPage from './pages/ApplicationInfosPage';
|
||||
import { createSectionsRoutes, routes } from './utils';
|
||||
import { createSectionsRoutes } from './utils';
|
||||
|
||||
function SettingsPage() {
|
||||
const { settingId } = useParams();
|
||||
const { settings } = useStrapiApp();
|
||||
const { formatMessage } = useIntl();
|
||||
const { isLoading, menu } = useSettingsMenu();
|
||||
const routes = useEnterprise(
|
||||
ROUTES_CE,
|
||||
async () => (await import('../../../../ee/admin/pages/SettingsPage/constants')).ROUTES_EE,
|
||||
{
|
||||
combine(ceRoutes, eeRoutes) {
|
||||
return [...ceRoutes, ...eeRoutes];
|
||||
},
|
||||
defaultValue: [],
|
||||
}
|
||||
);
|
||||
|
||||
// Creates the admin routes
|
||||
const adminRoutes = useMemo(() => {
|
||||
return makeUniqueRoutes(
|
||||
routes.map(({ to, Component, exact }) => createRoute(Component, to, exact))
|
||||
);
|
||||
}, []);
|
||||
}, [routes]);
|
||||
|
||||
const pluginsRoutes = createSectionsRoutes(settings);
|
||||
|
||||
|
@ -1,3 +0,0 @@
|
||||
const customRoutes = [];
|
||||
|
||||
export default customRoutes;
|
@ -1,3 +1,2 @@
|
||||
export { default as createSectionsRoutes } from './createSectionsRoutes';
|
||||
export { default as getSectionsToDisplay } from './getSectionsToDisplay';
|
||||
export { default as routes } from './routes';
|
||||
|
@ -1,6 +0,0 @@
|
||||
// This file makes it easier to make the difference between the ee and ce version
|
||||
import customRoutes from 'ee_else_ce/pages/SettingsPage/utils/customRoutes';
|
||||
|
||||
import defaultRoutes from './defaultRoutes';
|
||||
|
||||
export default [...customRoutes, ...defaultRoutes];
|
@ -0,0 +1,43 @@
|
||||
import adminPermissions from '../../../../admin/src/permissions';
|
||||
|
||||
export const LINKS_EE = {
|
||||
global: [
|
||||
...(window.strapi.features.isEnabled(window.strapi.features.SSO)
|
||||
? [
|
||||
{
|
||||
intlLabel: { id: 'Settings.sso.title', defaultMessage: 'Single Sign-On' },
|
||||
to: '/settings/single-sign-on',
|
||||
id: 'sso',
|
||||
permissions: adminPermissions.settings.sso.main,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
|
||||
...(window.strapi.features.isEnabled(window.strapi.features.REVIEW_WORKFLOWS)
|
||||
? [
|
||||
{
|
||||
intlLabel: {
|
||||
id: 'Settings.review-workflows.page.title',
|
||||
defaultMessage: 'Review Workflows',
|
||||
},
|
||||
to: '/settings/review-workflows',
|
||||
id: 'review-workflows',
|
||||
permissions: adminPermissions.settings['review-workflows'].main,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
],
|
||||
|
||||
admin: [
|
||||
...(window.strapi.features.isEnabled(window.strapi.features.AUDIT_LOGS)
|
||||
? [
|
||||
{
|
||||
intlLabel: { id: 'global.auditLogs', defaultMessage: 'Audit Logs' },
|
||||
to: '/settings/audit-logs?pageSize=50&page=1&sort=date:DESC',
|
||||
id: 'auditLogs',
|
||||
permissions: adminPermissions.settings.auditLogs.main,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
],
|
||||
};
|
@ -1,17 +0,0 @@
|
||||
import adminPermissions from '../../../../../admin/src/permissions';
|
||||
|
||||
const items = [];
|
||||
|
||||
if (window.strapi.features.isEnabled(window.strapi.features.AUDIT_LOGS)) {
|
||||
items.push({
|
||||
intlLabel: { id: 'global.auditLogs', defaultMessage: 'Audit Logs' },
|
||||
to: '/settings/audit-logs?pageSize=50&page=1&sort=date:DESC',
|
||||
id: 'auditLogs',
|
||||
isDisplayed: false,
|
||||
permissions: adminPermissions.settings.auditLogs.main,
|
||||
});
|
||||
}
|
||||
|
||||
const customAdminLinks = items;
|
||||
|
||||
export default customAdminLinks;
|
@ -1,25 +0,0 @@
|
||||
import adminPermissions from '../../../../../admin/src/permissions';
|
||||
|
||||
const items = [];
|
||||
|
||||
if (window.strapi.features.isEnabled(window.strapi.features.SSO)) {
|
||||
items.push({
|
||||
intlLabel: { id: 'Settings.sso.title', defaultMessage: 'Single Sign-On' },
|
||||
to: '/settings/single-sign-on',
|
||||
id: 'sso',
|
||||
isDisplayed: false,
|
||||
permissions: adminPermissions.settings.sso.main,
|
||||
});
|
||||
}
|
||||
|
||||
if (window.strapi.features.isEnabled(window.strapi.features.REVIEW_WORKFLOWS)) {
|
||||
items.push({
|
||||
intlLabel: { id: 'Settings.review-workflows.page.title', defaultMessage: 'Review Workflows' },
|
||||
to: '/settings/review-workflows',
|
||||
id: 'review-workflows',
|
||||
isDisplayed: false,
|
||||
permissions: adminPermissions.settings['review-workflows'].main,
|
||||
});
|
||||
}
|
||||
|
||||
export default items;
|
@ -1,11 +1,9 @@
|
||||
import AuthResponse from '../../AuthResponse';
|
||||
import { AuthResponse } from '../AuthResponse';
|
||||
|
||||
const customRoutes = [
|
||||
export const ROUTES_EE = [
|
||||
{
|
||||
Component: () => ({ default: AuthResponse }),
|
||||
to: '/auth/login/:authResponse',
|
||||
exact: true,
|
||||
},
|
||||
];
|
||||
|
||||
export default customRoutes;
|
@ -7,7 +7,7 @@ import { useHistory, useRouteMatch } from 'react-router-dom';
|
||||
|
||||
import { getRequestUrl } from '../../../../admin/src/utils';
|
||||
|
||||
const AuthResponse = () => {
|
||||
export const AuthResponse = () => {
|
||||
const {
|
||||
params: { authResponse },
|
||||
} = useRouteMatch('/auth/login/:authResponse');
|
||||
|
49
packages/core/admin/ee/admin/pages/SettingsPage/constants.js
Normal file
49
packages/core/admin/ee/admin/pages/SettingsPage/constants.js
Normal file
@ -0,0 +1,49 @@
|
||||
export const ROUTES_EE = [
|
||||
...(window.strapi.features.isEnabled(window.strapi.features.AUDIT_LOGS)
|
||||
? [
|
||||
{
|
||||
async Component() {
|
||||
const component = await import(
|
||||
/* webpackChunkName: "audit-logs-settings-page" */ './pages/AuditLogs/ProtectedListPage'
|
||||
);
|
||||
|
||||
return component;
|
||||
},
|
||||
to: '/settings/audit-logs',
|
||||
exact: true,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
|
||||
...(window.strapi.features.isEnabled(window.strapi.features.REVIEW_WORKFLOWS)
|
||||
? [
|
||||
{
|
||||
async Component() {
|
||||
const component = await import(
|
||||
/* webpackChunkName: "review-workflows-settings" */ './pages/ReviewWorkflows'
|
||||
);
|
||||
|
||||
return component;
|
||||
},
|
||||
to: '/settings/review-workflows',
|
||||
exact: true,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
|
||||
...(window.strapi.features.isEnabled(window.strapi.features.SSO)
|
||||
? [
|
||||
{
|
||||
async Component() {
|
||||
const component = await import(
|
||||
/* webpackChunkName: "sso-settings-page" */ './pages/SingleSignOn'
|
||||
);
|
||||
|
||||
return component;
|
||||
},
|
||||
to: '/settings/single-sign-on',
|
||||
exact: true,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
];
|
@ -1,45 +0,0 @@
|
||||
const routes = [];
|
||||
|
||||
if (window.strapi.features.isEnabled(window.strapi.features.SSO)) {
|
||||
routes.push({
|
||||
async Component() {
|
||||
const component = await import(
|
||||
/* webpackChunkName: "sso-settings-page" */ '../pages/SingleSignOn'
|
||||
);
|
||||
|
||||
return component;
|
||||
},
|
||||
to: '/settings/single-sign-on',
|
||||
exact: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (window.strapi.features.isEnabled(window.strapi.features.REVIEW_WORKFLOWS)) {
|
||||
routes.push({
|
||||
async Component() {
|
||||
const component = await import(
|
||||
/* webpackChunkName: "review-workflows-settings" */ '../pages/ReviewWorkflows'
|
||||
);
|
||||
|
||||
return component;
|
||||
},
|
||||
to: '/settings/review-workflows',
|
||||
exact: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (window.strapi.features.isEnabled(window.strapi.features.AUDIT_LOGS)) {
|
||||
routes.push({
|
||||
async Component() {
|
||||
const component = await import(
|
||||
/* webpackChunkName: "audit-logs-settings-page" */ '../pages/AuditLogs/ProtectedListPage'
|
||||
);
|
||||
|
||||
return component;
|
||||
},
|
||||
to: '/settings/audit-logs',
|
||||
exact: true,
|
||||
});
|
||||
}
|
||||
|
||||
export default routes;
|
@ -48,7 +48,10 @@ export type RouterConfig<TContentTypeUID extends Common.UID.ContentType> = {
|
||||
except?: string[];
|
||||
config: Utils.Expression.MatchFirst<
|
||||
[
|
||||
Utils.Expression.Test<Common.UID.IsCollectionType<TContentTypeUID>, CollectionTypeRouterConfig>,
|
||||
Utils.Expression.Test<
|
||||
Common.UID.IsCollectionType<TContentTypeUID>,
|
||||
CollectionTypeRouterConfig
|
||||
>,
|
||||
Utils.Expression.Test<Common.UID.IsSingleType<TContentTypeUID>, SingleTypeRouterConfig>
|
||||
],
|
||||
Generic
|
||||
|
Loading…
x
Reference in New Issue
Block a user