mirror of
https://github.com/strapi/strapi.git
synced 2025-11-02 02:44:55 +00:00
chore(admin): convert useSettingsMenu to TS (#18616)
* chore(admin): move constants into global constants * chore(admin): convert useSettingsMenu to TS
This commit is contained in:
parent
f5b09a8e61
commit
477ea8ee80
@ -52,7 +52,7 @@ export const App = () => {
|
||||
defaultValue: ADMIN_PERMISSIONS_CE,
|
||||
}
|
||||
);
|
||||
const routes = useEnterprise<StrapiRoute[] | null, StrapiRoute[], StrapiRoute[]>(
|
||||
const routes = useEnterprise(
|
||||
ROUTES_CE,
|
||||
async () => (await import('../../ee/admin/src/constants')).ROUTES_EE,
|
||||
{
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { StrapiAppSettingLink } from '@strapi/helper-plugin';
|
||||
|
||||
export const ADMIN_PERMISSIONS_CE = {
|
||||
contentManager: {
|
||||
main: [],
|
||||
@ -122,13 +124,22 @@ export const HOOKS = {
|
||||
export const ACTION_SET_APP_RUNTIME_STATUS = 'StrapiAdmin/APP/SET_APP_RUNTIME_STATUS';
|
||||
export const ACTION_SET_ADMIN_PERMISSIONS = 'StrapiAdmin/App/SET_ADMIN_PERMISSIONS';
|
||||
|
||||
export const SETTINGS_LINKS_CE = () => ({
|
||||
export interface SettingsMenuLink extends Omit<StrapiAppSettingLink, 'Component' | 'permissions'> {
|
||||
Component?: never;
|
||||
lockIcon?: boolean;
|
||||
}
|
||||
|
||||
export type SettingsMenu = {
|
||||
admin: SettingsMenuLink[];
|
||||
global: SettingsMenuLink[];
|
||||
};
|
||||
|
||||
export const SETTINGS_LINKS_CE = (): SettingsMenu => ({
|
||||
global: [
|
||||
{
|
||||
intlLabel: { id: 'Settings.application.title', defaultMessage: 'Overview' },
|
||||
to: '/settings/application-infos',
|
||||
id: '000-application-infos',
|
||||
permissions: [],
|
||||
},
|
||||
{
|
||||
intlLabel: { id: 'Settings.webhooks.title', defaultMessage: 'Webhooks' },
|
||||
@ -182,7 +193,7 @@ export const SETTINGS_LINKS_CE = () => ({
|
||||
id: 'roles',
|
||||
},
|
||||
{
|
||||
intlLabel: { id: 'global.users' },
|
||||
intlLabel: { id: 'global.users', defaultMessage: 'Users' },
|
||||
// Init the search params directly
|
||||
to: '/settings/users?pageSize=10&page=1&sort=firstname',
|
||||
id: 'users',
|
||||
|
||||
@ -0,0 +1,4 @@
|
||||
export const useSettingsMenu = jest.fn().mockReturnValue({
|
||||
isLoading: false,
|
||||
menu: [],
|
||||
});
|
||||
@ -1 +0,0 @@
|
||||
export { default as useSettingsMenu } from './useSettingsMenu';
|
||||
@ -1,21 +1,15 @@
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
|
||||
import { useEnterprise, UseEnterpriseOptions } from '../useEnterprise';
|
||||
import { useEnterprise } from '../useEnterprise';
|
||||
|
||||
const CE_DATA_FIXTURE = ['CE'];
|
||||
const EE_DATA_FIXTURE = ['EE'];
|
||||
|
||||
function setup(
|
||||
ceData: any,
|
||||
eeCallback: () => Promise<any>,
|
||||
options?: UseEnterpriseOptions<any, any, any>
|
||||
) {
|
||||
return renderHook(() => useEnterprise(ceData, eeCallback, options));
|
||||
}
|
||||
|
||||
describe('useEnterprise (CE)', () => {
|
||||
test('Returns CE data', async () => {
|
||||
const { result } = setup(CE_DATA_FIXTURE, async () => EE_DATA_FIXTURE);
|
||||
const { result } = renderHook(() =>
|
||||
useEnterprise(CE_DATA_FIXTURE, async () => EE_DATA_FIXTURE)
|
||||
);
|
||||
|
||||
expect(result.current).toBe(CE_DATA_FIXTURE);
|
||||
});
|
||||
@ -31,7 +25,9 @@ describe('useEnterprise (EE)', () => {
|
||||
});
|
||||
|
||||
test('Returns default data on first render and EE data on second', async () => {
|
||||
const { result } = setup(CE_DATA_FIXTURE, async () => EE_DATA_FIXTURE);
|
||||
const { result } = renderHook(() =>
|
||||
useEnterprise(CE_DATA_FIXTURE, async () => EE_DATA_FIXTURE)
|
||||
);
|
||||
|
||||
expect(result.current).toBe(null);
|
||||
|
||||
@ -39,11 +35,13 @@ describe('useEnterprise (EE)', () => {
|
||||
});
|
||||
|
||||
test('Combines CE and EE data', async () => {
|
||||
const { result } = setup(CE_DATA_FIXTURE, async () => EE_DATA_FIXTURE, {
|
||||
combine(ceData: string[], eeData: string[]) {
|
||||
return [...ceData, ...eeData];
|
||||
},
|
||||
});
|
||||
const { result } = renderHook(() =>
|
||||
useEnterprise(CE_DATA_FIXTURE, async () => EE_DATA_FIXTURE, {
|
||||
combine(ceData, eeData) {
|
||||
return [...ceData, ...eeData];
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
expect(result.current).toBe(null);
|
||||
|
||||
@ -53,23 +51,29 @@ describe('useEnterprise (EE)', () => {
|
||||
});
|
||||
|
||||
test('Returns EE data without custom combine', async () => {
|
||||
const { result } = setup(CE_DATA_FIXTURE, async () => EE_DATA_FIXTURE);
|
||||
const { result } = renderHook(() =>
|
||||
useEnterprise(CE_DATA_FIXTURE, async () => EE_DATA_FIXTURE)
|
||||
);
|
||||
|
||||
await waitFor(() => expect(result.current).toStrictEqual(EE_DATA_FIXTURE));
|
||||
});
|
||||
|
||||
test('Returns CE data, when enabled is set to false', async () => {
|
||||
const { result } = setup(CE_DATA_FIXTURE, async () => EE_DATA_FIXTURE, {
|
||||
enabled: false,
|
||||
});
|
||||
const { result } = renderHook(() =>
|
||||
useEnterprise(CE_DATA_FIXTURE, async () => EE_DATA_FIXTURE, {
|
||||
enabled: false,
|
||||
})
|
||||
);
|
||||
|
||||
await waitFor(() => expect(result.current).toStrictEqual(CE_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,
|
||||
});
|
||||
const { result } = renderHook(() =>
|
||||
useEnterprise(CE_DATA_FIXTURE, async () => EE_DATA_FIXTURE, {
|
||||
defaultValue: false,
|
||||
})
|
||||
);
|
||||
|
||||
expect(result.current).toBe(false);
|
||||
|
||||
|
||||
@ -2,50 +2,49 @@ import * as React from 'react';
|
||||
|
||||
import { useCallbackRef } from '@strapi/helper-plugin';
|
||||
|
||||
/**
|
||||
* TODO: this hook needs typing better, it's a bit similar to react-query's useQuery tbf
|
||||
* We have an async function that returns something, and we can set initialData as well as
|
||||
* a select function, the return type of the function should infer it all...
|
||||
*/
|
||||
|
||||
function isEnterprise() {
|
||||
return window.strapi.isEE;
|
||||
}
|
||||
|
||||
export interface UseEnterpriseOptions<
|
||||
TCEData = unknown,
|
||||
TEEData = unknown,
|
||||
TCombinedData = TEEData
|
||||
> {
|
||||
defaultValue?: TCEData | TEEData | null;
|
||||
combine?: (ceData: TCEData, eeData: TEEData) => TCombinedData;
|
||||
export interface UseEnterpriseOptions<TCEData, TEEData, TDefaultValue, TCombinedValue> {
|
||||
defaultValue?: TDefaultValue;
|
||||
combine?: (ceData: TCEData, eeData: TEEData) => TCombinedValue;
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export function useEnterprise<TCEData = unknown, TEEData = unknown, TCombinedData = TEEData>(
|
||||
type UseEnterpriseReturn<TCEData, TEEData, TDefaultValue, TCombinedValue> =
|
||||
TDefaultValue extends null
|
||||
? TCEData | TEEData | TCombinedValue | null
|
||||
: TCEData | TEEData | TCombinedValue | TDefaultValue;
|
||||
|
||||
export const useEnterprise = <
|
||||
TCEData,
|
||||
TEEData = TCEData,
|
||||
TCombinedValue = TEEData,
|
||||
TDefaultValue = TCEData | null
|
||||
>(
|
||||
ceData: TCEData,
|
||||
eeCallback: () => Promise<TEEData>,
|
||||
{
|
||||
defaultValue = null,
|
||||
// @ts-expect-error – TODO: fix this type
|
||||
combine = (ceData, eeData) => eeData,
|
||||
enabled = true,
|
||||
}: UseEnterpriseOptions<TCEData, TEEData, TCombinedData> = {}
|
||||
): null | TCEData | TEEData | TCombinedData {
|
||||
opts: UseEnterpriseOptions<TCEData, TEEData, TDefaultValue, TCombinedValue> = {}
|
||||
): UseEnterpriseReturn<TCEData, TEEData, TDefaultValue, TCombinedValue> => {
|
||||
const { defaultValue = null, combine = (_ceData, eeData) => eeData, enabled = true } = opts;
|
||||
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: TCEData | TEEData | TCombinedData | null }>({
|
||||
const [{ data }, setData] = React.useState<{
|
||||
data: TCEData | TEEData | TDefaultValue | TCombinedValue | null;
|
||||
}>({
|
||||
data: isEnterprise() && enabled ? defaultValue : ceData,
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
async function importEE() {
|
||||
const eeData = await eeCallbackRef();
|
||||
const combinedValue = combineCallbackRef(ceData, eeData);
|
||||
|
||||
setData({ data: combineCallbackRef(ceData, eeData) });
|
||||
setData({ data: combinedValue ? combinedValue : eeData });
|
||||
}
|
||||
|
||||
if (isEnterprise() && enabled) {
|
||||
@ -53,5 +52,6 @@ export function useEnterprise<TCEData = unknown, TEEData = unknown, TCombinedDat
|
||||
}
|
||||
}, [ceData, eeCallbackRef, combineCallbackRef, enabled]);
|
||||
|
||||
// @ts-expect-error – the hook type assertion works in practice. But seems to have issues here...
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
||||
181
packages/core/admin/admin/src/hooks/useSettingsMenu.ts
Normal file
181
packages/core/admin/admin/src/hooks/useSettingsMenu.ts
Normal file
@ -0,0 +1,181 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import {
|
||||
hasPermissions,
|
||||
StrapiAppSetting,
|
||||
StrapiAppSettingLink,
|
||||
useRBACProvider,
|
||||
useStrapiApp,
|
||||
useAppInfo,
|
||||
} from '@strapi/helper-plugin';
|
||||
import sortBy from 'lodash/sortBy';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { SETTINGS_LINKS_CE, SettingsMenuLink } from '../constants';
|
||||
import { selectAdminPermissions } from '../selectors';
|
||||
|
||||
import { useEnterprise } from './useEnterprise';
|
||||
|
||||
const formatLinks = (menu: SettingsMenuSection[]): SettingsMenuSectionWithDisplayedLinks[] =>
|
||||
menu.map((menuSection) => {
|
||||
const formattedLinks = menuSection.links.map((link) => ({
|
||||
...link,
|
||||
isDisplayed: false,
|
||||
}));
|
||||
|
||||
return { ...menuSection, links: formattedLinks };
|
||||
});
|
||||
|
||||
interface SettingsMenuLinkWithPermissions extends SettingsMenuLink {
|
||||
permissions: StrapiAppSettingLink['permissions'];
|
||||
}
|
||||
|
||||
interface SettingsMenuSection extends Omit<StrapiAppSetting, 'links'> {
|
||||
links: Array<SettingsMenuLinkWithPermissions | StrapiAppSettingLink>;
|
||||
}
|
||||
|
||||
interface SettingsMenuLinkWithPermissionsAndDisplayed extends SettingsMenuLinkWithPermissions {
|
||||
isDisplayed: boolean;
|
||||
}
|
||||
|
||||
interface StrapiAppSettingLinkWithDisplayed extends StrapiAppSettingLink {
|
||||
isDisplayed: boolean;
|
||||
}
|
||||
|
||||
interface SettingsMenuSectionWithDisplayedLinks extends Omit<SettingsMenuSection, 'links'> {
|
||||
links: Array<SettingsMenuLinkWithPermissionsAndDisplayed | StrapiAppSettingLinkWithDisplayed>;
|
||||
}
|
||||
|
||||
type SettingsMenu = SettingsMenuSectionWithDisplayedLinks[];
|
||||
|
||||
const useSettingsMenu = (): {
|
||||
isLoading: boolean;
|
||||
menu: SettingsMenu;
|
||||
} => {
|
||||
const [{ isLoading, menu }, setData] = React.useState<{
|
||||
isLoading: boolean;
|
||||
menu: SettingsMenu;
|
||||
}>({
|
||||
isLoading: true,
|
||||
menu: [],
|
||||
});
|
||||
const { allPermissions: userPermissions } = useRBACProvider();
|
||||
const { shouldUpdateStrapi } = useAppInfo();
|
||||
const { settings } = useStrapiApp();
|
||||
const permissions = useSelector(selectAdminPermissions);
|
||||
|
||||
/**
|
||||
* memoize the return value of this function to avoid re-computing it on every render
|
||||
* because it's used in an effect it ends up re-running recursively.
|
||||
*/
|
||||
const ceLinks = React.useMemo(() => SETTINGS_LINKS_CE(), []);
|
||||
|
||||
const { admin: adminLinks, global: globalLinks } = useEnterprise(
|
||||
ceLinks,
|
||||
async () => (await import('../../../ee/admin/src/constants')).SETTINGS_LINKS_EE(),
|
||||
{
|
||||
combine(ceLinks, eeLinks) {
|
||||
return {
|
||||
admin: [...eeLinks.admin, ...ceLinks.admin],
|
||||
global: [...ceLinks.global, ...eeLinks.global],
|
||||
};
|
||||
},
|
||||
defaultValue: {
|
||||
admin: [],
|
||||
global: [],
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const addPermissions = React.useCallback(
|
||||
(link: SettingsMenuLink) => {
|
||||
if (!link.id) {
|
||||
throw new Error('The settings menu item must have an id attribute.');
|
||||
}
|
||||
|
||||
return {
|
||||
...link,
|
||||
permissions: permissions.settings?.[link.id]?.main ?? [],
|
||||
} satisfies SettingsMenuLinkWithPermissions;
|
||||
},
|
||||
[permissions.settings]
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
const getData = async () => {
|
||||
interface MenuLinkPermission {
|
||||
hasPermission: boolean;
|
||||
sectionIndex: number;
|
||||
linkIndex: number;
|
||||
}
|
||||
|
||||
const buildMenuPermissions = (sections: SettingsMenuSectionWithDisplayedLinks[]) =>
|
||||
Promise.all(
|
||||
sections.reduce<Promise<MenuLinkPermission>[]>((acc, section, sectionIndex) => {
|
||||
const linksWithPermissions = section.links.map(async (link, linkIndex) => ({
|
||||
hasPermission: await hasPermissions(userPermissions, link.permissions),
|
||||
sectionIndex,
|
||||
linkIndex,
|
||||
}));
|
||||
|
||||
return [...acc, ...linksWithPermissions];
|
||||
}, [])
|
||||
);
|
||||
|
||||
const menuPermissions = await buildMenuPermissions(sections);
|
||||
|
||||
setData((prev) => {
|
||||
return {
|
||||
...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 {
|
||||
...link,
|
||||
isDisplayed: Boolean(permission?.hasPermission),
|
||||
};
|
||||
}),
|
||||
})),
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const { global, ...otherSections } = settings;
|
||||
const sections = formatLinks([
|
||||
{
|
||||
...global,
|
||||
links: sortBy([...global.links, ...globalLinks.map(addPermissions)], (link) => link.id).map(
|
||||
(link) => ({
|
||||
...link,
|
||||
hasNotification: link.id === '000-application-infos' && shouldUpdateStrapi,
|
||||
})
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'permissions',
|
||||
intlLabel: { id: 'Settings.permissions', defaultMessage: 'Administration Panel' },
|
||||
links: adminLinks.map(addPermissions),
|
||||
},
|
||||
...Object.values(otherSections),
|
||||
]);
|
||||
|
||||
getData();
|
||||
}, [adminLinks, globalLinks, userPermissions, settings, shouldUpdateStrapi, addPermissions]);
|
||||
|
||||
return {
|
||||
isLoading,
|
||||
menu: menu.map((menuItem) => ({
|
||||
...menuItem,
|
||||
links: menuItem.links.filter((link) => link.isDisplayed),
|
||||
})),
|
||||
};
|
||||
};
|
||||
|
||||
export { useSettingsMenu };
|
||||
export type { SettingsMenu };
|
||||
@ -1,133 +0,0 @@
|
||||
import { useState, useEffect, useCallback, useMemo } from 'react';
|
||||
|
||||
import { hasPermissions, useRBACProvider, useStrapiApp, useAppInfo } from '@strapi/helper-plugin';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { SETTINGS_LINKS_CE } from '../../constants';
|
||||
import { selectAdminPermissions } from '../../selectors';
|
||||
import { useEnterprise } from '../useEnterprise';
|
||||
|
||||
import formatLinks from './utils/formatLinks';
|
||||
import sortLinks from './utils/sortLinks';
|
||||
|
||||
const useSettingsMenu = () => {
|
||||
const [{ isLoading, menu }, setData] = useState({
|
||||
isLoading: true,
|
||||
menu: [],
|
||||
});
|
||||
const { allPermissions: userPermissions } = useRBACProvider();
|
||||
const { shouldUpdateStrapi } = useAppInfo();
|
||||
const { settings } = useStrapiApp();
|
||||
const permissions = useSelector(selectAdminPermissions);
|
||||
|
||||
/**
|
||||
* memoize the return value of this function to avoid re-computing it on every render
|
||||
* because it's used in an effect it ends up re-running recursively.
|
||||
*/
|
||||
const ceLinks = useMemo(() => SETTINGS_LINKS_CE(), []);
|
||||
|
||||
const { global: globalLinks, admin: adminLinks } = useEnterprise(
|
||||
ceLinks,
|
||||
async () => (await import('../../../../ee/admin/src/constants')).SETTINGS_LINKS_EE(),
|
||||
{
|
||||
combine(ceLinks, eeLinks) {
|
||||
return {
|
||||
admin: [...eeLinks.admin, ...ceLinks.admin],
|
||||
global: [...ceLinks.global, ...eeLinks.global],
|
||||
};
|
||||
},
|
||||
defaultValue: {
|
||||
admin: [],
|
||||
global: [],
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const addPermissions = useCallback(
|
||||
(link) => {
|
||||
if (!link.id) {
|
||||
throw new Error('The settings menu item must have an id attribute.');
|
||||
}
|
||||
|
||||
return {
|
||||
...link,
|
||||
permissions: permissions.settings?.[link.id]?.main,
|
||||
};
|
||||
},
|
||||
[permissions.settings]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const getData = async () => {
|
||||
const buildMenuPermissions = (sections) =>
|
||||
Promise.all(
|
||||
sections.reduce((acc, section, sectionIndex) => {
|
||||
const buildMenuPermissions = (links) =>
|
||||
links.map(async (link, linkIndex) => ({
|
||||
hasPermission: await hasPermissions(userPermissions, link.permissions),
|
||||
sectionIndex,
|
||||
linkIndex,
|
||||
}));
|
||||
|
||||
return [...acc, ...buildMenuPermissions(section.links)];
|
||||
}, [])
|
||||
);
|
||||
|
||||
const menuPermissions = await buildMenuPermissions(sections);
|
||||
|
||||
setData((prev) => {
|
||||
return {
|
||||
...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 {
|
||||
...link,
|
||||
isDisplayed: Boolean(permission.hasPermission),
|
||||
};
|
||||
}),
|
||||
})),
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const { global, ...otherSections } = settings;
|
||||
|
||||
const sections = formatLinks([
|
||||
{
|
||||
...settings.global,
|
||||
links: sortLinks([...settings.global.links, ...globalLinks.map(addPermissions)]).map(
|
||||
(link) => ({
|
||||
...link,
|
||||
hasNotification: link.id === '000-application-infos' && shouldUpdateStrapi,
|
||||
})
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'permissions',
|
||||
intlLabel: { id: 'Settings.permissions', defaultMessage: 'Administration Panel' },
|
||||
links: adminLinks.map(addPermissions),
|
||||
},
|
||||
...Object.values(otherSections),
|
||||
]);
|
||||
|
||||
getData();
|
||||
}, [adminLinks, globalLinks, userPermissions, settings, shouldUpdateStrapi, addPermissions]);
|
||||
|
||||
const filterMenu = (menuItem) => {
|
||||
return {
|
||||
...menuItem,
|
||||
links: menuItem.links.filter((link) => link.isDisplayed),
|
||||
};
|
||||
};
|
||||
|
||||
return { isLoading, menu: menu.map(filterMenu) };
|
||||
};
|
||||
|
||||
export default useSettingsMenu;
|
||||
@ -1,12 +0,0 @@
|
||||
const formatLinks = (menu) => {
|
||||
return menu.map((menuSection) => {
|
||||
const formattedLinks = menuSection.links.map((link) => ({
|
||||
...link,
|
||||
isDisplayed: false,
|
||||
}));
|
||||
|
||||
return { ...menuSection, links: formattedLinks };
|
||||
});
|
||||
};
|
||||
|
||||
export default formatLinks;
|
||||
@ -1,5 +0,0 @@
|
||||
import sortBy from 'lodash/sortBy';
|
||||
|
||||
const sortLinks = (links) => sortBy(links, (link) => link.id);
|
||||
|
||||
export default sortLinks;
|
||||
@ -1,30 +0,0 @@
|
||||
import formatLinks from '../formatLinks';
|
||||
|
||||
describe('ADMIN | hooks | useSettingsMenu | utils | formatLinks', () => {
|
||||
it('should add the isDisplayed key to all sections links', () => {
|
||||
const menu = [
|
||||
{
|
||||
links: [{ name: 'link 1' }, { name: 'link 2' }],
|
||||
},
|
||||
{
|
||||
links: [{ name: 'link 3' }, { name: 'link 4' }],
|
||||
},
|
||||
];
|
||||
const expected = [
|
||||
{
|
||||
links: [
|
||||
{ name: 'link 1', isDisplayed: false },
|
||||
{ name: 'link 2', isDisplayed: false },
|
||||
],
|
||||
},
|
||||
{
|
||||
links: [
|
||||
{ name: 'link 3', isDisplayed: false },
|
||||
{ name: 'link 4', isDisplayed: false },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
expect(formatLinks(menu)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
@ -24,7 +24,7 @@ const AuthPage = ({ hasAdmin }: AuthPageProps) => {
|
||||
LoginCE,
|
||||
async () => (await import('../../../../ee/admin/src/pages/AuthPage/components/Login')).LoginEE
|
||||
);
|
||||
const forms = useEnterprise<FormDictionary, Partial<FormDictionary>, FormDictionary>(
|
||||
const forms = useEnterprise<FormDictionary, Partial<FormDictionary>>(
|
||||
FORMS,
|
||||
async () => (await import('../../../../ee/admin/src/pages/AuthPage/constants')).FORMS,
|
||||
{
|
||||
|
||||
@ -516,8 +516,7 @@ const SOCIAL_LINKS = [
|
||||
* -----------------------------------------------------------------------------------------------*/
|
||||
|
||||
const HomePage = () => {
|
||||
type CompFn = () => React.JSX.Element;
|
||||
const Page = useEnterprise<CompFn, CompFn, CompFn>(
|
||||
const Page = useEnterprise(
|
||||
HomePageCE,
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
async () => (await import('../../../ee/admin/src/pages/HomePage')).HomePageEE
|
||||
|
||||
@ -6,8 +6,8 @@ import { Helmet } from 'react-helmet';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { Redirect, Route, Switch, useParams } from 'react-router-dom';
|
||||
|
||||
import { useSettingsMenu } from '../../hooks';
|
||||
import { useEnterprise } from '../../hooks/useEnterprise';
|
||||
import { useSettingsMenu } from '../../hooks/useSettingsMenu';
|
||||
import { createRoute } from '../../utils/createRoute';
|
||||
|
||||
import SettingsNav from './components/SettingsNav';
|
||||
|
||||
@ -10,13 +10,9 @@ import { Route, Router } from 'react-router-dom';
|
||||
import { SettingsPage } from '..';
|
||||
import { Theme } from '../../../components/Theme';
|
||||
import { ThemeToggleProvider } from '../../../components/ThemeToggleProvider';
|
||||
import { useSettingsMenu } from '../../../hooks';
|
||||
import { useSettingsMenu } from '../../../hooks/useSettingsMenu';
|
||||
|
||||
jest.mock('../../../hooks', () => ({
|
||||
useSettingsMenu: jest.fn(() => ({ isLoading: false, menu: [] })),
|
||||
useAppInfo: jest.fn(() => ({ shouldUpdateStrapi: false })),
|
||||
useThemeToggle: jest.fn(() => ({ currentTheme: 'light', themes: { light: lightTheme } })),
|
||||
}));
|
||||
jest.mock('../../../hooks/useSettingsMenu');
|
||||
|
||||
jest.mock('react-intl', () => ({
|
||||
FormattedMessage: ({ id }) => id,
|
||||
|
||||
@ -4,6 +4,19 @@ interface PermissionMap {
|
||||
marketplace: {
|
||||
main: Permission[];
|
||||
};
|
||||
/**
|
||||
* TODO: remove the use of record to make it "concrete".
|
||||
*/
|
||||
settings: Record<
|
||||
string,
|
||||
{
|
||||
main: Permission[];
|
||||
create: Permission[];
|
||||
read: Permission[];
|
||||
update: Permission[];
|
||||
delete: Permission[];
|
||||
}
|
||||
>;
|
||||
}
|
||||
|
||||
export { PermissionMap };
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import { AuthResponse } from './pages/AuthResponse';
|
||||
|
||||
import type { SettingsMenu } from '../../../admin/src/constants';
|
||||
|
||||
export const ADMIN_PERMISSIONS_EE = {
|
||||
settings: {
|
||||
auditLogs: {
|
||||
@ -31,7 +33,7 @@ export const ROUTES_EE = [
|
||||
// TODO: the constants.js file is imported before the React application is setup and
|
||||
// therefore `window.strapi` might not exist at import-time. We should probably define
|
||||
// which constant is available at which stage of the application lifecycle.
|
||||
export const SETTINGS_LINKS_EE = () => ({
|
||||
export const SETTINGS_LINKS_EE = (): SettingsMenu => ({
|
||||
global: [
|
||||
...(window.strapi.features.isEnabled(window.strapi.features.SSO)
|
||||
? [
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user