mirror of
https://github.com/strapi/strapi.git
synced 2025-10-17 02:53:22 +00:00
Move CM menu
Signed-off-by: HichamELBSI <elabbassih@gmail.com>
This commit is contained in:
parent
923cb57fbe
commit
a68384567f
@ -6,7 +6,6 @@ const { combineReducers, createStore } = require('redux');
|
||||
const reducers = {
|
||||
language: jest.fn(() => ({ locale: 'en' })),
|
||||
menu: jest.fn(() => ({
|
||||
collectionTypesSectionLinks: [],
|
||||
generalSectionLinks: [
|
||||
{
|
||||
icon: 'list',
|
||||
@ -43,7 +42,6 @@ const reducers = {
|
||||
notificationsCount: 0,
|
||||
},
|
||||
],
|
||||
singleTypesSectionLinks: [],
|
||||
pluginsSectionLinks: [],
|
||||
isLoading: true,
|
||||
})),
|
||||
|
@ -1,14 +1,4 @@
|
||||
import {
|
||||
TOGGLE_IS_LOADING,
|
||||
SET_CT_OR_ST_LINKS,
|
||||
SET_SECTION_LINKS,
|
||||
UNSET_IS_LOADING,
|
||||
} from './constants';
|
||||
|
||||
export const setCtOrStLinks = (authorizedCtLinks, authorizedStLinks, contentTypeSchemas) => ({
|
||||
type: SET_CT_OR_ST_LINKS,
|
||||
data: { authorizedCtLinks, authorizedStLinks, contentTypeSchemas },
|
||||
});
|
||||
import { TOGGLE_IS_LOADING, SET_SECTION_LINKS, UNSET_IS_LOADING } from './constants';
|
||||
|
||||
export const setSectionLinks = (authorizedGeneralLinks, authorizedPluginLinks) => ({
|
||||
type: SET_SECTION_LINKS,
|
||||
|
@ -1,4 +1,3 @@
|
||||
export const SET_CT_OR_ST_LINKS = 'StrapiAdmin/LeftMenu/SET_CT_OR_ST_LINKS';
|
||||
export const SET_SECTION_LINKS = 'StrapiAdmin/LeftMenu/SET_SECTION_LINKS';
|
||||
export const TOGGLE_IS_LOADING = 'StrapiAdmin/LeftMenu/TOGGLE_IS_LOADING';
|
||||
export const UNSET_IS_LOADING = 'StrapiAdmin/LeftMenu/UNSET_IS_LOADING';
|
||||
|
@ -11,22 +11,11 @@ const LeftMenu = ({ setUpdateMenu }) => {
|
||||
const { shouldUpdateStrapi } = useAppInfos();
|
||||
const { plugins } = useStrapiApp();
|
||||
const {
|
||||
state: {
|
||||
isLoading,
|
||||
collectionTypesSectionLinks,
|
||||
singleTypesSectionLinks,
|
||||
generalSectionLinks,
|
||||
pluginsSectionLinks,
|
||||
},
|
||||
state: { isLoading, generalSectionLinks, pluginsSectionLinks },
|
||||
toggleLoading,
|
||||
generateMenu,
|
||||
} = useMenuSections(plugins, shouldUpdateStrapi);
|
||||
|
||||
const filteredCollectionTypeLinks = collectionTypesSectionLinks.filter(
|
||||
({ isDisplayed }) => isDisplayed
|
||||
);
|
||||
const filteredSingleTypeLinks = singleTypesSectionLinks.filter(({ isDisplayed }) => isDisplayed);
|
||||
|
||||
// This effect is really temporary until we create the menu api
|
||||
// We need this because we need to regenerate the links when the settings are being changed
|
||||
// in the content manager configurations list
|
||||
@ -43,25 +32,6 @@ const LeftMenu = ({ setUpdateMenu }) => {
|
||||
<Loader show={isLoading} />
|
||||
<Header />
|
||||
<LinksContainer>
|
||||
{filteredCollectionTypeLinks.length > 0 && (
|
||||
<LinksSection
|
||||
section="collectionType"
|
||||
name="collectionType"
|
||||
links={filteredCollectionTypeLinks}
|
||||
location={location}
|
||||
searchable
|
||||
/>
|
||||
)}
|
||||
{filteredSingleTypeLinks.length > 0 && (
|
||||
<LinksSection
|
||||
section="singleType"
|
||||
name="singleType"
|
||||
links={filteredSingleTypeLinks}
|
||||
location={location}
|
||||
searchable
|
||||
/>
|
||||
)}
|
||||
|
||||
{pluginsSectionLinks.length > 0 && (
|
||||
<LinksSection
|
||||
section="plugins"
|
||||
|
@ -1,15 +1,9 @@
|
||||
/* eslint-disable consistent-return */
|
||||
import produce from 'immer';
|
||||
import adminPermissions from '../../permissions';
|
||||
import {
|
||||
SET_CT_OR_ST_LINKS,
|
||||
SET_SECTION_LINKS,
|
||||
TOGGLE_IS_LOADING,
|
||||
UNSET_IS_LOADING,
|
||||
} from './constants';
|
||||
import { SET_SECTION_LINKS, TOGGLE_IS_LOADING, UNSET_IS_LOADING } from './constants';
|
||||
|
||||
const initialState = {
|
||||
collectionTypesSectionLinks: [],
|
||||
generalSectionLinks: [
|
||||
{
|
||||
icon: 'list',
|
||||
@ -38,7 +32,6 @@ const initialState = {
|
||||
notificationsCount: 0,
|
||||
},
|
||||
],
|
||||
singleTypesSectionLinks: [],
|
||||
pluginsSectionLinks: [],
|
||||
isLoading: true,
|
||||
};
|
||||
@ -46,13 +39,6 @@ const initialState = {
|
||||
const reducer = (state = initialState, action) =>
|
||||
produce(state, draftState => {
|
||||
switch (action.type) {
|
||||
case SET_CT_OR_ST_LINKS: {
|
||||
const { authorizedCtLinks, authorizedStLinks } = action.data;
|
||||
draftState.collectionTypesSectionLinks = authorizedCtLinks;
|
||||
draftState.singleTypesSectionLinks = authorizedStLinks;
|
||||
break;
|
||||
}
|
||||
|
||||
case SET_SECTION_LINKS: {
|
||||
const { authorizedGeneralLinks, authorizedPluginLinks } = action.data;
|
||||
draftState.generalSectionLinks = authorizedGeneralLinks;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import reducer, { initialState } from '../reducer';
|
||||
import { SET_CT_OR_ST_LINKS, SET_SECTION_LINKS, TOGGLE_IS_LOADING } from '../constants';
|
||||
import { SET_SECTION_LINKS, TOGGLE_IS_LOADING } from '../constants';
|
||||
|
||||
describe('ADMIN | LeftMenu | reducer', () => {
|
||||
describe('DEFAULT_ACTION', () => {
|
||||
@ -51,27 +51,4 @@ describe('ADMIN | LeftMenu | reducer', () => {
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('SET_CT_OR_ST_LINKS', () => {
|
||||
it('sets the generalSectionLinks and the pluginsSectionLinks with the action', () => {
|
||||
const state = { ...initialState };
|
||||
const action = {
|
||||
type: SET_CT_OR_ST_LINKS,
|
||||
data: {
|
||||
authorizedCtLinks: ['authorizd', 'ct-links'],
|
||||
authorizedStLinks: ['authorizd', 'st-links'],
|
||||
},
|
||||
};
|
||||
|
||||
const expected = {
|
||||
...initialState,
|
||||
collectionTypesSectionLinks: ['authorizd', 'ct-links'],
|
||||
singleTypesSectionLinks: ['authorizd', 'st-links'],
|
||||
};
|
||||
|
||||
const actual = reducer(state, action);
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,15 +1,13 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { useNotification, useRBACProvider } from '@strapi/helper-plugin';
|
||||
import { useRBACProvider } from '@strapi/helper-plugin';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import getCtOrStLinks from './utils/getCtOrStLinks';
|
||||
import getPluginSectionLinks from './utils/getPluginSectionLinks';
|
||||
import getGeneralLinks from './utils/getGeneralLinks';
|
||||
import { setCtOrStLinks, setSectionLinks, toggleIsLoading, unsetIsLoading } from './actions';
|
||||
import { setSectionLinks, toggleIsLoading, unsetIsLoading } from './actions';
|
||||
import toPluginLinks from './utils/toPluginLinks';
|
||||
import selectMenuLinks from './selectors';
|
||||
|
||||
const useMenuSections = (plugins, shouldUpdateStrapi) => {
|
||||
const toggleNotification = useNotification();
|
||||
const state = useSelector(selectMenuLinks);
|
||||
const dispatch = useDispatch();
|
||||
const { allPermissions } = useRBACProvider();
|
||||
@ -26,10 +24,6 @@ const useMenuSections = (plugins, shouldUpdateStrapi) => {
|
||||
|
||||
const resolvePermissions = async (permissions = allPermissions) => {
|
||||
const pluginsSectionLinks = toPluginLinks(pluginsRef.current);
|
||||
const { authorizedCtLinks, authorizedStLinks, contentTypes } = await getCtOrStLinks(
|
||||
permissions,
|
||||
toggleNotification
|
||||
);
|
||||
|
||||
const authorizedPluginSectionLinks = await getPluginSectionLinks(
|
||||
permissions,
|
||||
@ -42,7 +36,6 @@ const useMenuSections = (plugins, shouldUpdateStrapi) => {
|
||||
shouldUpdateStrapiRef.current
|
||||
);
|
||||
|
||||
dispatch(setCtOrStLinks(authorizedCtLinks, authorizedStLinks, contentTypes));
|
||||
dispatch(setSectionLinks(authorizedGeneralSectionLinks, authorizedPluginSectionLinks));
|
||||
dispatch(unsetIsLoading());
|
||||
};
|
||||
|
@ -1,2 +0,0 @@
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export { default as generateModelsLinks } from './generateModelsLinks';
|
@ -1,7 +1,9 @@
|
||||
const selectMenuLinks = state => {
|
||||
const menuState = state.menu;
|
||||
import pluginId from '../../pluginId';
|
||||
|
||||
return menuState.collectionTypesSectionLinks;
|
||||
const selectMenuLinks = state => {
|
||||
const cmState = state[`${pluginId}_app`];
|
||||
|
||||
return cmState.collectionTypeLinks;
|
||||
};
|
||||
|
||||
export default selectMenuLinks;
|
||||
|
@ -23,23 +23,23 @@ const mergeParams = (initialParams, params) => {
|
||||
}, {});
|
||||
};
|
||||
|
||||
const getDeleteRedirectionLink = (links, slug, rawQuery) => {
|
||||
const matchingLink = links.find(({ destination }) => destination.includes(slug));
|
||||
const getRedirectionLink = (links, slug, rawQuery) => {
|
||||
const matchingLink = links.find(({ to }) => to.includes(slug));
|
||||
|
||||
if (!matchingLink) {
|
||||
return '/';
|
||||
}
|
||||
|
||||
const { destination, search } = matchingLink;
|
||||
const { to, search } = matchingLink;
|
||||
const searchQueryParams = parse(search);
|
||||
const currentQueryParams = parse(rawQuery.substring(1));
|
||||
|
||||
const mergedParams = mergeParams(searchQueryParams, currentQueryParams);
|
||||
|
||||
const link = `${destination}?${stringify(mergedParams, { encode: false })}`;
|
||||
const link = `${to}?${stringify(mergedParams, { encode: false })}`;
|
||||
|
||||
return link;
|
||||
};
|
||||
|
||||
export default getDeleteRedirectionLink;
|
||||
export default getRedirectionLink;
|
||||
export { mergeParams };
|
||||
|
@ -5,11 +5,11 @@ describe('CONTENT MANAGER | Containers | CollectionTypeFormWrapper | utils ', ()
|
||||
it('should return an when no links is matching the slug', () => {
|
||||
const links = [
|
||||
{
|
||||
destination: '/cm/foo',
|
||||
to: '/cm/foo',
|
||||
search: 'page=1&pageSize=10',
|
||||
},
|
||||
{
|
||||
destination: '/cm/bar',
|
||||
to: '/cm/bar',
|
||||
search: 'page=1&pageSize=10',
|
||||
},
|
||||
];
|
||||
@ -21,11 +21,11 @@ describe('CONTENT MANAGER | Containers | CollectionTypeFormWrapper | utils ', ()
|
||||
it('should not mutate the link when the rawQuery is empty', () => {
|
||||
const links = [
|
||||
{
|
||||
destination: '/cm/foo',
|
||||
to: '/cm/foo',
|
||||
search: 'page=1&pageSize=10',
|
||||
},
|
||||
{
|
||||
destination: '/cm/bar',
|
||||
to: '/cm/bar',
|
||||
search: 'page=1&pageSize=10',
|
||||
},
|
||||
];
|
||||
@ -38,11 +38,11 @@ describe('CONTENT MANAGER | Containers | CollectionTypeFormWrapper | utils ', ()
|
||||
it('should merge the current search with the link original one', () => {
|
||||
const links = [
|
||||
{
|
||||
destination: '/cm/foo',
|
||||
to: '/cm/foo',
|
||||
search: 'page=1&pageSize=10&plugins[i18n][locale]=en',
|
||||
},
|
||||
{
|
||||
destination: '/cm/bar',
|
||||
to: '/cm/bar',
|
||||
search: 'page=1&pageSize=10&plugins[i18n][locale]=en',
|
||||
},
|
||||
];
|
||||
|
@ -10,6 +10,7 @@ import pluginId from './pluginId';
|
||||
import pluginLogo from './assets/images/logo.svg';
|
||||
import reducers from './reducers';
|
||||
import trads from './translations';
|
||||
import pluginPermissions from './permissions';
|
||||
|
||||
const pluginDescription = pluginPkg.strapi.description || pluginPkg.description;
|
||||
const icon = pluginPkg.strapi.icon;
|
||||
@ -32,6 +33,20 @@ export default {
|
||||
name,
|
||||
pluginLogo,
|
||||
trads,
|
||||
menu: {
|
||||
pluginsSectionLinks: [
|
||||
{
|
||||
destination: `/plugins/${pluginId}`,
|
||||
icon,
|
||||
label: {
|
||||
id: `${pluginId}.plugin.name`,
|
||||
defaultMessage: 'Content manager',
|
||||
},
|
||||
name,
|
||||
permissions: pluginPermissions.main,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
},
|
||||
boot() {},
|
||||
|
@ -0,0 +1,58 @@
|
||||
/**
|
||||
*
|
||||
* LeftMenu
|
||||
*
|
||||
*/
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
import { LeftMenuList, colors, sizes } from '@strapi/helper-plugin';
|
||||
import styled from 'styled-components';
|
||||
import { useSelector, shallowEqual } from 'react-redux';
|
||||
import getTrad from '../../../utils/getTrad';
|
||||
import { makeSelectModelLinks } from '../selectors';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
width: 100%;
|
||||
min-height: calc(100vh - ${sizes.header.height});
|
||||
background-color: ${colors.leftMenu.mediumGrey};
|
||||
padding-top: 3.1rem;
|
||||
padding-left: 2rem;
|
||||
padding-right: 2rem;
|
||||
`;
|
||||
|
||||
const LeftMenu = () => {
|
||||
const modelLinksSelector = useMemo(makeSelectModelLinks, []);
|
||||
const { collectionTypeLinks, singleTypeLinks } = useSelector(
|
||||
state => modelLinksSelector(state),
|
||||
shallowEqual
|
||||
);
|
||||
|
||||
const data = [
|
||||
{
|
||||
name: 'models',
|
||||
title: {
|
||||
id: getTrad('components.LeftMenu.collection-types.'),
|
||||
},
|
||||
searchable: true,
|
||||
links: collectionTypeLinks,
|
||||
},
|
||||
{
|
||||
name: 'singleTypes',
|
||||
title: {
|
||||
id: getTrad('components.LeftMenu.single-types.'),
|
||||
},
|
||||
searchable: true,
|
||||
links: singleTypeLinks,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Wrapper className="col-md-3">
|
||||
{data.map(list => {
|
||||
return <LeftMenuList {...list} key={list.name} />;
|
||||
})}
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default LeftMenu;
|
@ -1,13 +1,12 @@
|
||||
import { GET_DATA, GET_DATA_SUCCEEDED, RESET_PROPS } from './constants';
|
||||
import { GET_DATA, RESET_PROPS, SET_CONTENT_TYPE_LINKS } from './constants';
|
||||
|
||||
export const getData = () => ({
|
||||
type: GET_DATA,
|
||||
});
|
||||
|
||||
export const getDataSucceeded = (models, components) => ({
|
||||
type: GET_DATA_SUCCEEDED,
|
||||
components,
|
||||
models,
|
||||
});
|
||||
|
||||
export const resetProps = () => ({ type: RESET_PROPS });
|
||||
|
||||
export const setContentTypeLinks = (authorizedCtLinks, authorizedStLinks, models, components) => ({
|
||||
type: SET_CONTENT_TYPE_LINKS,
|
||||
data: { authorizedCtLinks, authorizedStLinks, components, contentTypeSchemas: models },
|
||||
});
|
||||
|
@ -1,3 +1,3 @@
|
||||
export const GET_DATA = 'ContentManager/App/GET_DATA';
|
||||
export const GET_DATA_SUCCEEDED = 'ContentManager/App/GET_DATA_SUCCEEDED';
|
||||
export const RESET_PROPS = 'ContentManager/App/RESET_PROPS';
|
||||
export const SET_CONTENT_TYPE_LINKS = 'ContentManager/App/SET_CONTENT_TYPE_LINKS';
|
||||
|
@ -1,103 +1,59 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators, compose } from 'redux';
|
||||
import { Switch, Route } from 'react-router-dom';
|
||||
import {
|
||||
CheckPagePermissions,
|
||||
LoadingIndicatorPage,
|
||||
NotFound,
|
||||
request,
|
||||
useNotification,
|
||||
} from '@strapi/helper-plugin';
|
||||
import React from 'react';
|
||||
import { Switch, Route, useRouteMatch, Redirect } from 'react-router-dom';
|
||||
import { CheckPagePermissions, LoadingIndicatorPage, NotFound } from '@strapi/helper-plugin';
|
||||
import { DndProvider } from 'react-dnd';
|
||||
import HTML5Backend from 'react-dnd-html5-backend';
|
||||
import pluginId from '../../pluginId';
|
||||
import pluginPermissions from '../../permissions';
|
||||
import { getRequestUrl } from '../../utils';
|
||||
import DragLayer from '../../components/DragLayer';
|
||||
import CollectionTypeRecursivePath from '../CollectionTypeRecursivePath';
|
||||
import ComponentSettingsView from '../ComponentSetttingsView';
|
||||
import SingleTypeRecursivePath from '../SingleTypeRecursivePath';
|
||||
import { getData, getDataSucceeded, resetProps } from './actions';
|
||||
import makeSelectApp from './selectors';
|
||||
import LeftMenu from './LeftMenu';
|
||||
import useModels from './useModels';
|
||||
|
||||
function Main({ getData, getDataSucceeded, isLoading, resetProps }) {
|
||||
const toggleNotification = useNotification();
|
||||
const App = () => {
|
||||
const contentTypeMatch = useRouteMatch(`/plugins/${pluginId}/:kind/:uid`);
|
||||
const { status, collectionTypeLinks, singleTypeLinks } = useModels();
|
||||
const models = [...collectionTypeLinks, ...singleTypeLinks];
|
||||
|
||||
useEffect(() => {
|
||||
const abortController = new AbortController();
|
||||
const { signal } = abortController;
|
||||
|
||||
const fetchData = async signal => {
|
||||
getData();
|
||||
|
||||
try {
|
||||
const [{ data: components }, { data: models }] = await Promise.all(
|
||||
['components', 'content-types'].map(endPoint =>
|
||||
request(getRequestUrl(endPoint), { method: 'GET', signal })
|
||||
)
|
||||
);
|
||||
|
||||
getDataSucceeded(models, components);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
toggleNotification({ type: 'warning', message: { id: 'notification.error' } });
|
||||
}
|
||||
};
|
||||
|
||||
fetchData(signal);
|
||||
|
||||
return () => {
|
||||
abortController.abort();
|
||||
resetProps();
|
||||
};
|
||||
}, [getData, getDataSucceeded, resetProps, toggleNotification]);
|
||||
|
||||
if (isLoading) {
|
||||
if (status === 'loading') {
|
||||
return <LoadingIndicatorPage />;
|
||||
}
|
||||
|
||||
if (!contentTypeMatch && models.length > 0) {
|
||||
return <Redirect to={`${models[0].to}${models[0].search ? `?${models[0].search}` : ''}`} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<DragLayer />
|
||||
|
||||
<Switch>
|
||||
<Route path={`/plugins/${pluginId}/components/:uid/configurations/edit`}>
|
||||
<CheckPagePermissions permissions={pluginPermissions.componentsConfigurations}>
|
||||
<ComponentSettingsView />
|
||||
</CheckPagePermissions>
|
||||
</Route>
|
||||
<Route
|
||||
path={`/plugins/${pluginId}/collectionType/:slug`}
|
||||
component={CollectionTypeRecursivePath}
|
||||
/>
|
||||
<Route path={`/plugins/${pluginId}/singleType/:slug`} component={SingleTypeRecursivePath} />
|
||||
<Route path="" component={NotFound} />
|
||||
</Switch>
|
||||
<div className="container-fluid">
|
||||
<div className="row">
|
||||
<LeftMenu />
|
||||
<div className="col-md-9 content" style={{ padding: '0 30px' }}>
|
||||
<Switch>
|
||||
<Route path={`/plugins/${pluginId}/components/:uid/configurations/edit`}>
|
||||
<CheckPagePermissions permissions={pluginPermissions.componentsConfigurations}>
|
||||
<ComponentSettingsView />
|
||||
</CheckPagePermissions>
|
||||
</Route>
|
||||
<Route
|
||||
path={`/plugins/${pluginId}/collectionType/:slug`}
|
||||
component={CollectionTypeRecursivePath}
|
||||
/>
|
||||
<Route
|
||||
path={`/plugins/${pluginId}/singleType/:slug`}
|
||||
component={SingleTypeRecursivePath}
|
||||
/>
|
||||
<Route path="" component={NotFound} />
|
||||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DndProvider>
|
||||
);
|
||||
}
|
||||
|
||||
Main.propTypes = {
|
||||
getData: PropTypes.func.isRequired,
|
||||
getDataSucceeded: PropTypes.func.isRequired,
|
||||
isLoading: PropTypes.bool.isRequired,
|
||||
resetProps: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
const mapStateToProps = makeSelectApp();
|
||||
|
||||
export function mapDispatchToProps(dispatch) {
|
||||
return bindActionCreators(
|
||||
{
|
||||
getData,
|
||||
getDataSucceeded,
|
||||
resetProps,
|
||||
},
|
||||
dispatch
|
||||
);
|
||||
}
|
||||
const withConnect = connect(mapStateToProps, mapDispatchToProps);
|
||||
|
||||
export default compose(withConnect)(Main);
|
||||
export default App;
|
||||
|
@ -4,30 +4,34 @@
|
||||
*/
|
||||
/* eslint-disable consistent-return */
|
||||
import produce from 'immer';
|
||||
import { GET_DATA, GET_DATA_SUCCEEDED, RESET_PROPS } from './constants';
|
||||
import { GET_DATA, RESET_PROPS, SET_CONTENT_TYPE_LINKS } from './constants';
|
||||
|
||||
const initialState = {
|
||||
components: [],
|
||||
isLoading: true,
|
||||
status: 'loading',
|
||||
models: [],
|
||||
collectionTypeLinks: [],
|
||||
singleTypeLinks: [],
|
||||
};
|
||||
|
||||
const mainReducer = (state = initialState, action) =>
|
||||
produce(state, draftState => {
|
||||
switch (action.type) {
|
||||
case GET_DATA: {
|
||||
draftState.isLoading = true;
|
||||
break;
|
||||
}
|
||||
case GET_DATA_SUCCEEDED: {
|
||||
draftState.isLoading = false;
|
||||
draftState.components = action.components;
|
||||
draftState.models = action.models;
|
||||
draftState.status = 'loading';
|
||||
break;
|
||||
}
|
||||
case RESET_PROPS: {
|
||||
return initialState;
|
||||
}
|
||||
case SET_CONTENT_TYPE_LINKS: {
|
||||
draftState.collectionTypeLinks = action.data.authorizedCtLinks;
|
||||
draftState.singleTypeLinks = action.data.authorizedStLinks;
|
||||
draftState.components = action.data.components;
|
||||
draftState.models = action.data.contentTypeSchemas;
|
||||
draftState.status = 'resolved';
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return draftState;
|
||||
}
|
||||
|
@ -11,10 +11,23 @@ const makeSelectApp = () =>
|
||||
return substate;
|
||||
});
|
||||
|
||||
const makeSelectModels = () => createSelector(selectAppDomain(), state => state.models);
|
||||
|
||||
const makeSelectModelLinks = () =>
|
||||
createSelector(selectAppDomain(), state => ({
|
||||
collectionTypeLinks: state.collectionTypeLinks,
|
||||
singleTypeLinks: state.singleTypeLinks,
|
||||
}));
|
||||
|
||||
const makeSelectModelAndComponentSchemas = () =>
|
||||
createSelector(selectAppDomain(), ({ components, models }) => ({
|
||||
schemas: [...components, ...models],
|
||||
}));
|
||||
|
||||
export default makeSelectApp;
|
||||
export { makeSelectModelAndComponentSchemas, selectAppDomain };
|
||||
export {
|
||||
makeSelectModelAndComponentSchemas,
|
||||
makeSelectModelLinks,
|
||||
makeSelectModels,
|
||||
selectAppDomain,
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
import produce from 'immer';
|
||||
import { getData, getDataSucceeded, resetProps } from '../actions';
|
||||
import { getData, setContentTypeLinks, resetProps } from '../actions';
|
||||
import mainReducer from '../reducer';
|
||||
|
||||
describe('Content Manager | App | reducer', () => {
|
||||
@ -8,8 +8,10 @@ describe('Content Manager | App | reducer', () => {
|
||||
beforeEach(() => {
|
||||
state = {
|
||||
components: [],
|
||||
isLoading: true,
|
||||
status: 'loading',
|
||||
models: [],
|
||||
collectionTypeLinks: [],
|
||||
singleTypeLinks: [],
|
||||
};
|
||||
});
|
||||
|
||||
@ -18,10 +20,10 @@ describe('Content Manager | App | reducer', () => {
|
||||
});
|
||||
|
||||
it('should handle the getData action correctly', () => {
|
||||
state.isLoading = false;
|
||||
state.status = 'resolved';
|
||||
|
||||
const expected = produce(state, draft => {
|
||||
draft.isLoading = true;
|
||||
draft.status = 'loading';
|
||||
});
|
||||
|
||||
expect(mainReducer(state, getData())).toEqual(expected);
|
||||
@ -29,12 +31,19 @@ describe('Content Manager | App | reducer', () => {
|
||||
|
||||
it('should handle the getData action correctly', () => {
|
||||
const expected = produce(state, draft => {
|
||||
draft.isLoading = false;
|
||||
draft.status = 'resolved';
|
||||
draft.components = ['test'];
|
||||
draft.models = ['test'];
|
||||
draft.collectionTypeLinks = ['authorizedCt'];
|
||||
draft.singleTypeLinks = ['authorizedSt'];
|
||||
});
|
||||
|
||||
expect(mainReducer(state, getDataSucceeded(['test'], ['test']))).toEqual(expected);
|
||||
expect(
|
||||
mainReducer(
|
||||
state,
|
||||
setContentTypeLinks(['authorizedCt'], ['authorizedSt'], ['test'], ['test'])
|
||||
)
|
||||
).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should handle the resetProps action correctly', () => {
|
||||
@ -43,7 +52,9 @@ describe('Content Manager | App | reducer', () => {
|
||||
expect(mainReducer(state, resetProps())).toEqual({
|
||||
components: [],
|
||||
models: [],
|
||||
isLoading: true,
|
||||
collectionTypeLinks: [],
|
||||
singleTypeLinks: [],
|
||||
status: 'loading',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -0,0 +1,63 @@
|
||||
import { request, useNotification, useRBACProvider } from '@strapi/helper-plugin';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { getData, resetProps, setContentTypeLinks } from './actions';
|
||||
import { getRequestUrl } from '../../utils';
|
||||
import { selectAppDomain } from './selectors';
|
||||
import getContentTypeLinks from './utils/getContentTypeLinks';
|
||||
|
||||
const useModels = () => {
|
||||
const dispatch = useDispatch();
|
||||
const toggleNotification = useNotification();
|
||||
const state = useSelector(selectAppDomain());
|
||||
const fetchDataRef = useRef();
|
||||
const { allPermissions } = useRBACProvider();
|
||||
|
||||
const fetchData = async signal => {
|
||||
dispatch(getData());
|
||||
|
||||
try {
|
||||
const [{ data: components }, { data: models }] = await Promise.all(
|
||||
['components', 'content-types'].map(endPoint =>
|
||||
request(getRequestUrl(endPoint), { method: 'GET', signal })
|
||||
)
|
||||
);
|
||||
|
||||
const { authorizedCtLinks, authorizedStLinks } = await getContentTypeLinks(
|
||||
models,
|
||||
allPermissions,
|
||||
toggleNotification
|
||||
);
|
||||
|
||||
const actionToDispatch = setContentTypeLinks(
|
||||
authorizedCtLinks,
|
||||
authorizedStLinks,
|
||||
models,
|
||||
components
|
||||
);
|
||||
|
||||
dispatch(actionToDispatch);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
toggleNotification({ type: 'warning', message: { id: 'notification.error' } });
|
||||
}
|
||||
};
|
||||
|
||||
fetchDataRef.current = fetchData;
|
||||
|
||||
useEffect(() => {
|
||||
const abortController = new AbortController();
|
||||
const { signal } = abortController;
|
||||
|
||||
fetchDataRef.current(signal);
|
||||
|
||||
return () => {
|
||||
abortController.abort();
|
||||
dispatch(resetProps());
|
||||
};
|
||||
}, [dispatch, toggleNotification]);
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
export default useModels;
|
@ -0,0 +1,13 @@
|
||||
import { hasPermissions } from '@strapi/helper-plugin';
|
||||
|
||||
/**
|
||||
* This function resolves an array of Promises<boolean>
|
||||
* It puts at a specific index the status of a specific permission.
|
||||
* While this might look weird, we then iterate on this array
|
||||
* and check the different CT/ST/general/plugin sections
|
||||
* and make an index based comparisons
|
||||
*/
|
||||
const checkPermissions = (userPermissions, permissionsToCheck) =>
|
||||
permissionsToCheck.map(({ permissions }) => hasPermissions(userPermissions, permissions));
|
||||
|
||||
export default checkPermissions;
|
@ -30,12 +30,15 @@ const generateLinks = (links, type, configurations = []) => {
|
||||
}
|
||||
|
||||
return {
|
||||
icon: 'circle',
|
||||
destination: `/plugins/content-manager/${link.kind}/${link.uid}`,
|
||||
isDisplayed: true,
|
||||
label: link.info.label,
|
||||
permissions,
|
||||
search,
|
||||
kind: link.kind,
|
||||
title: link.info.label,
|
||||
to: `/plugins/content-manager/${link.kind}/${link.uid}`,
|
||||
uid: link.uid,
|
||||
// Used for the list item key in the helper plugin
|
||||
name: link.uid,
|
||||
isDisplayed: link.isDisplayed,
|
||||
};
|
||||
});
|
||||
};
|
@ -2,17 +2,14 @@ import { request } from '@strapi/helper-plugin';
|
||||
import generateModelsLinks from './generateModelsLinks';
|
||||
import checkPermissions from './checkPermissions';
|
||||
|
||||
const getCtOrStLinks = async (userPermissions, toggleNotification) => {
|
||||
const requestURL = '/content-manager/content-types';
|
||||
|
||||
const getContentTypeLinks = async (models, userPermissions, toggleNotification) => {
|
||||
try {
|
||||
const {
|
||||
data: contentTypeConfigurations,
|
||||
} = await request('/content-manager/content-types-settings', { method: 'GET' });
|
||||
|
||||
const { data } = await request(requestURL, { method: 'GET' });
|
||||
const { collectionTypesSectionLinks, singleTypesSectionLinks } = generateModelsLinks(
|
||||
data,
|
||||
models,
|
||||
contentTypeConfigurations
|
||||
);
|
||||
|
||||
@ -33,7 +30,7 @@ const getCtOrStLinks = async (userPermissions, toggleNotification) => {
|
||||
(_, index) => stLinksPermissions[index]
|
||||
);
|
||||
|
||||
return { authorizedCtLinks, authorizedStLinks, contentTypes: data };
|
||||
return { authorizedCtLinks, authorizedStLinks };
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
||||
@ -46,4 +43,4 @@ const getCtOrStLinks = async (userPermissions, toggleNotification) => {
|
||||
}
|
||||
};
|
||||
|
||||
export default getCtOrStLinks;
|
||||
export default getContentTypeLinks;
|
@ -0,0 +1,17 @@
|
||||
import checkPermissions from '../checkPermissions';
|
||||
|
||||
jest.mock('@strapi/helper-plugin', () => ({
|
||||
hasPermissions: () => Promise.resolve(true),
|
||||
}));
|
||||
|
||||
describe('checkPermissions', () => {
|
||||
it('creates an array of boolean corresponding to the permission state', async () => {
|
||||
const userPermissions = {};
|
||||
const permissions = [{ permissions: {} }, { permissions: {} }];
|
||||
|
||||
const expected = [true, true];
|
||||
const actual = await Promise.all(checkPermissions(userPermissions, permissions));
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
});
|
@ -20,7 +20,6 @@ describe('ADMIN | LeftMenu | utils', () => {
|
||||
const data = [
|
||||
{
|
||||
isDisplayed: true,
|
||||
|
||||
kind: 'collectionType',
|
||||
uid: 'application::address.address',
|
||||
info: {
|
||||
@ -47,10 +46,8 @@ describe('ADMIN | LeftMenu | utils', () => {
|
||||
|
||||
const expected = [
|
||||
{
|
||||
icon: 'circle',
|
||||
destination: '/plugins/content-manager/collectionType/application::address.address',
|
||||
to: '/plugins/content-manager/collectionType/application::address.address',
|
||||
isDisplayed: true,
|
||||
label: 'Addresses',
|
||||
search: `page=1&pageSize=2&_sort=name:ASC`,
|
||||
permissions: [
|
||||
{
|
||||
@ -62,13 +59,19 @@ describe('ADMIN | LeftMenu | utils', () => {
|
||||
subject: 'application::address.address',
|
||||
},
|
||||
],
|
||||
kind: 'collectionType',
|
||||
title: 'Addresses',
|
||||
uid: 'application::address.address',
|
||||
name: 'application::address.address',
|
||||
},
|
||||
{
|
||||
icon: 'circle',
|
||||
destination: '/plugins/content-manager/singleType/application::test1.test1',
|
||||
to: '/plugins/content-manager/singleType/application::test1.test1',
|
||||
isDisplayed: true,
|
||||
label: 'Test 1',
|
||||
search: null,
|
||||
kind: 'singleType',
|
||||
title: 'Test 1',
|
||||
uid: 'application::test1.test1',
|
||||
name: 'application::test1.test1',
|
||||
permissions: [
|
||||
{
|
||||
action: 'plugins::content-manager.explorer.create',
|
||||
@ -118,11 +121,13 @@ describe('ADMIN | LeftMenu | utils', () => {
|
||||
const expected = {
|
||||
collectionTypesSectionLinks: [
|
||||
{
|
||||
icon: 'circle',
|
||||
destination: '/plugins/content-manager/collectionType/application::address.address',
|
||||
isDisplayed: true,
|
||||
label: 'Addresses',
|
||||
search: null,
|
||||
kind: 'collectionType',
|
||||
title: 'Addresses',
|
||||
to: '/plugins/content-manager/collectionType/application::address.address',
|
||||
uid: 'application::address.address',
|
||||
name: 'application::address.address',
|
||||
permissions: [
|
||||
{
|
||||
action: 'plugins::content-manager.explorer.create',
|
||||
@ -137,11 +142,13 @@ describe('ADMIN | LeftMenu | utils', () => {
|
||||
],
|
||||
singleTypesSectionLinks: [
|
||||
{
|
||||
icon: 'circle',
|
||||
destination: '/plugins/content-manager/singleType/application::test1.test1',
|
||||
isDisplayed: true,
|
||||
label: 'Test 1',
|
||||
kind: 'singleType',
|
||||
search: null,
|
||||
title: 'Test 1',
|
||||
to: '/plugins/content-manager/singleType/application::test1.test1',
|
||||
uid: 'application::test1.test1',
|
||||
name: 'application::test1.test1',
|
||||
permissions: [
|
||||
{
|
||||
action: 'plugins::content-manager.explorer.read',
|
@ -1,5 +1,5 @@
|
||||
import { request, hasPermissions } from '@strapi/helper-plugin';
|
||||
import getCtOrStLinks from '../getCtOrStLinks';
|
||||
import getContentTypeLinks from '../getContentTypeLinks';
|
||||
|
||||
jest.mock('@strapi/helper-plugin');
|
||||
|
||||
@ -128,7 +128,7 @@ describe('checkPermissions', () => {
|
||||
authorizedStLinks: [],
|
||||
contentTypes: data,
|
||||
};
|
||||
const actual = await getCtOrStLinks(userPermissions);
|
||||
const actual = await getContentTypeLinks(userPermissions);
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
@ -142,7 +142,7 @@ describe('checkPermissions', () => {
|
||||
throw new Error('Something went wrong');
|
||||
});
|
||||
|
||||
await getCtOrStLinks(userPermissions, toggleNotification);
|
||||
await getContentTypeLinks(userPermissions, toggleNotification);
|
||||
expect(toggleNotification).toBeCalled();
|
||||
});
|
||||
});
|
@ -1,6 +1,11 @@
|
||||
import styled from 'styled-components';
|
||||
import { BackHeader as BaseBackHeader } from '@strapi/helper-plugin';
|
||||
import { Flex, Text } from '@buffetjs/core';
|
||||
|
||||
const BackHeader = styled(BaseBackHeader)`
|
||||
left: 24rem;
|
||||
`;
|
||||
|
||||
const SubWrapper = styled.div`
|
||||
background: #ffffff;
|
||||
border-radius: 2px;
|
||||
@ -71,4 +76,4 @@ const StatusWrapper = styled.div`
|
||||
`}
|
||||
`;
|
||||
|
||||
export { LinkWrapper, MainWrapper, SubWrapper, DeleteButton, StatusWrapper };
|
||||
export { LinkWrapper, MainWrapper, SubWrapper, DeleteButton, StatusWrapper, BackHeader };
|
||||
|
@ -2,7 +2,6 @@ import React, { memo, useCallback, useMemo } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { get } from 'lodash';
|
||||
import {
|
||||
BackHeader,
|
||||
BaselineAlignment,
|
||||
InjectionZone,
|
||||
LiLink,
|
||||
@ -23,7 +22,7 @@ import EditViewDataManagerProvider from '../../components/EditViewDataManagerPro
|
||||
import SingleTypeFormWrapper from '../../components/SingleTypeFormWrapper';
|
||||
import Header from './Header';
|
||||
import { createAttributesLayout, getFieldsActionMatchingPermissions } from './utils';
|
||||
import { LinkWrapper, SubWrapper } from './components';
|
||||
import { LinkWrapper, SubWrapper, BackHeader } from './components';
|
||||
import DeleteLink from './DeleteLink';
|
||||
import InformationCard from './InformationCard';
|
||||
import { getTrad } from '../../utils';
|
||||
|
@ -18,6 +18,10 @@
|
||||
"components.FiltersPickWrapper.PluginHeader.description": "Set the conditions to apply to filter the entries",
|
||||
"components.FiltersPickWrapper.PluginHeader.title.filter": "Filters",
|
||||
"components.FiltersPickWrapper.hide": "Hide",
|
||||
"components.LeftMenu.collection-types.plural": "Collection Types",
|
||||
"components.LeftMenu.collection-types.singular": "Collection Type",
|
||||
"components.LeftMenu.single-types.plural": "Single Types",
|
||||
"components.LeftMenu.single-types.singular": "Single Type",
|
||||
"components.LimitSelect.itemsPerPage": "Items per page",
|
||||
"components.NotAllowedInput.text": "No permissions to see this field",
|
||||
"components.Search.placeholder": "Search for an entry...",
|
||||
|
@ -3,6 +3,7 @@ import styled from 'styled-components';
|
||||
const Wrapper = styled.div`
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 25rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
|
@ -4,9 +4,9 @@ import { NavLink } from 'react-router-dom';
|
||||
|
||||
import Icon from './Icon';
|
||||
|
||||
function LeftMenuLink({ children, to, CustomComponent }) {
|
||||
function LeftMenuLink({ children, to, search, CustomComponent }) {
|
||||
return (
|
||||
<NavLink to={to}>
|
||||
<NavLink to={`${to}${search ? `?${search}` : ''}`}>
|
||||
<Icon />
|
||||
{CustomComponent ? <CustomComponent /> : <p>{children}</p>}
|
||||
</NavLink>
|
||||
@ -16,11 +16,13 @@ function LeftMenuLink({ children, to, CustomComponent }) {
|
||||
LeftMenuLink.defaultProps = {
|
||||
children: null,
|
||||
CustomComponent: null,
|
||||
search: null,
|
||||
};
|
||||
|
||||
LeftMenuLink.propTypes = {
|
||||
children: PropTypes.node,
|
||||
to: PropTypes.string.isRequired,
|
||||
search: PropTypes.string,
|
||||
};
|
||||
|
||||
export default memo(LeftMenuLink);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import addLocaleToLinksSearch from './utils/addLocaleToLinksSearch';
|
||||
|
||||
const addLocaleToCollectionTypesMiddleware = () => ({ getState }) => next => action => {
|
||||
if (action.type !== 'StrapiAdmin/LeftMenu/SET_CT_OR_ST_LINKS') {
|
||||
if (action.type !== 'ContentManager/App/SET_CONTENT_TYPE_LINKS') {
|
||||
return next(action);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import addLocaleToLinksSearch from './utils/addLocaleToLinksSearch';
|
||||
|
||||
const addLocaleToSingleTypesMiddleware = () => ({ getState }) => next => action => {
|
||||
if (action.type !== 'StrapiAdmin/LeftMenu/SET_CT_OR_ST_LINKS') {
|
||||
if (action.type !== 'ContentManager/App/SET_CONTENT_TYPE_LINKS') {
|
||||
return next(action);
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ describe('i18n | middlewares | addLocaleToCollectionTypesMiddleware', () => {
|
||||
expect(next).toBeCalledWith(action);
|
||||
});
|
||||
|
||||
it('should forward the action when the type is not StrapiAdmin/LeftMenu/SET_CT_OR_ST_LINKS', () => {
|
||||
it('should forward the action when the type is not ContentManager/App/SET_CONTENT_TYPE_LINKS', () => {
|
||||
const action = { test: true, type: 'TEST' };
|
||||
|
||||
const next = jest.fn();
|
||||
@ -46,7 +46,7 @@ describe('i18n | middlewares | addLocaleToCollectionTypesMiddleware', () => {
|
||||
|
||||
it('should forward when the authorizedStLinks array is empty', () => {
|
||||
const action = {
|
||||
type: 'StrapiAdmin/LeftMenu/SET_CT_OR_ST_LINKS',
|
||||
type: 'ContentManager/App/SET_CONTENT_TYPE_LINKS',
|
||||
data: {
|
||||
authorizedCtLinks: [],
|
||||
},
|
||||
@ -62,9 +62,9 @@ describe('i18n | middlewares | addLocaleToCollectionTypesMiddleware', () => {
|
||||
|
||||
it('should not add the search key to a single type link when i18n is not enabled on the single type', () => {
|
||||
const action = {
|
||||
type: 'StrapiAdmin/LeftMenu/SET_CT_OR_ST_LINKS',
|
||||
type: 'ContentManager/App/SET_CONTENT_TYPE_LINKS',
|
||||
data: {
|
||||
authorizedCtLinks: [{ destination: 'cm/collectionType/test' }],
|
||||
authorizedCtLinks: [{ to: 'cm/collectionType/test' }],
|
||||
contentTypeSchemas: [{ uid: 'test', pluginOptions: { i18n: { localized: false } } }],
|
||||
},
|
||||
};
|
||||
@ -84,9 +84,9 @@ describe('i18n | middlewares | addLocaleToCollectionTypesMiddleware', () => {
|
||||
] = [{ properties: { locales: ['en'] } }];
|
||||
|
||||
const action = {
|
||||
type: 'StrapiAdmin/LeftMenu/SET_CT_OR_ST_LINKS',
|
||||
type: 'ContentManager/App/SET_CONTENT_TYPE_LINKS',
|
||||
data: {
|
||||
authorizedCtLinks: [{ destination: 'cm/collectionType/test', search: null }],
|
||||
authorizedCtLinks: [{ to: 'cm/collectionType/test', search: null }],
|
||||
contentTypeSchemas: [{ uid: 'test', pluginOptions: { i18n: { localized: true } } }],
|
||||
},
|
||||
};
|
||||
@ -97,11 +97,9 @@ describe('i18n | middlewares | addLocaleToCollectionTypesMiddleware', () => {
|
||||
middleware(next)(action);
|
||||
|
||||
const expected = {
|
||||
type: 'StrapiAdmin/LeftMenu/SET_CT_OR_ST_LINKS',
|
||||
type: 'ContentManager/App/SET_CONTENT_TYPE_LINKS',
|
||||
data: {
|
||||
authorizedCtLinks: [
|
||||
{ destination: 'cm/collectionType/test', search: 'plugins[i18n][locale]=en' },
|
||||
],
|
||||
authorizedCtLinks: [{ to: 'cm/collectionType/test', search: 'plugins[i18n][locale]=en' }],
|
||||
contentTypeSchemas: [{ uid: 'test', pluginOptions: { i18n: { localized: true } } }],
|
||||
},
|
||||
};
|
||||
@ -116,11 +114,9 @@ describe('i18n | middlewares | addLocaleToCollectionTypesMiddleware', () => {
|
||||
] = [{ properties: { locales: [] } }];
|
||||
|
||||
const action = {
|
||||
type: 'StrapiAdmin/LeftMenu/SET_CT_OR_ST_LINKS',
|
||||
type: 'ContentManager/App/SET_CONTENT_TYPE_LINKS',
|
||||
data: {
|
||||
authorizedCtLinks: [
|
||||
{ destination: 'cm/collectionType/test', search: 'page=1&pageSize=10' },
|
||||
],
|
||||
authorizedCtLinks: [{ to: 'cm/collectionType/test', search: 'page=1&pageSize=10' }],
|
||||
contentTypeSchemas: [{ uid: 'test', pluginOptions: { i18n: { localized: true } } }],
|
||||
},
|
||||
};
|
||||
@ -131,11 +127,11 @@ describe('i18n | middlewares | addLocaleToCollectionTypesMiddleware', () => {
|
||||
middleware(next)(action);
|
||||
|
||||
const expected = {
|
||||
type: 'StrapiAdmin/LeftMenu/SET_CT_OR_ST_LINKS',
|
||||
type: 'ContentManager/App/SET_CONTENT_TYPE_LINKS',
|
||||
data: {
|
||||
authorizedCtLinks: [
|
||||
{
|
||||
destination: 'cm/collectionType/test',
|
||||
to: 'cm/collectionType/test',
|
||||
isDisplayed: false,
|
||||
search: 'page=1&pageSize=10',
|
||||
},
|
||||
@ -154,11 +150,9 @@ describe('i18n | middlewares | addLocaleToCollectionTypesMiddleware', () => {
|
||||
] = [{ properties: { locales: ['en'] } }];
|
||||
|
||||
const action = {
|
||||
type: 'StrapiAdmin/LeftMenu/SET_CT_OR_ST_LINKS',
|
||||
type: 'ContentManager/App/SET_CONTENT_TYPE_LINKS',
|
||||
data: {
|
||||
authorizedCtLinks: [
|
||||
{ destination: 'cm/collectionType/test', search: 'plugins[plugin][test]=test' },
|
||||
],
|
||||
authorizedCtLinks: [{ to: 'cm/collectionType/test', search: 'plugins[plugin][test]=test' }],
|
||||
contentTypeSchemas: [{ uid: 'test', pluginOptions: { i18n: { localized: true } } }],
|
||||
},
|
||||
};
|
||||
@ -169,11 +163,11 @@ describe('i18n | middlewares | addLocaleToCollectionTypesMiddleware', () => {
|
||||
middleware(next)(action);
|
||||
|
||||
const expected = {
|
||||
type: 'StrapiAdmin/LeftMenu/SET_CT_OR_ST_LINKS',
|
||||
type: 'ContentManager/App/SET_CONTENT_TYPE_LINKS',
|
||||
data: {
|
||||
authorizedCtLinks: [
|
||||
{
|
||||
destination: 'cm/collectionType/test',
|
||||
to: 'cm/collectionType/test',
|
||||
search: 'plugins[plugin][test]=test&plugins[i18n][locale]=en',
|
||||
},
|
||||
],
|
||||
|
@ -33,7 +33,7 @@ describe('i18n | middlewares | addLocaleToSingleTypesMiddleware', () => {
|
||||
expect(next).toBeCalledWith(action);
|
||||
});
|
||||
|
||||
it('should forward the action when the type is not StrapiAdmin/LeftMenu/SET_CT_OR_ST_LINKS', () => {
|
||||
it('should forward the action when the type is not ContentManager/App/SET_CONTENT_TYPE_LINKS', () => {
|
||||
const action = { test: true, type: 'TEST' };
|
||||
|
||||
const next = jest.fn();
|
||||
@ -46,7 +46,7 @@ describe('i18n | middlewares | addLocaleToSingleTypesMiddleware', () => {
|
||||
|
||||
it('should forward when the authorizedStLinks array is empty', () => {
|
||||
const action = {
|
||||
type: 'StrapiAdmin/LeftMenu/SET_CT_OR_ST_LINKS',
|
||||
type: 'ContentManager/App/SET_CONTENT_TYPE_LINKS',
|
||||
data: {
|
||||
authorizedStLinks: [],
|
||||
},
|
||||
@ -62,9 +62,9 @@ describe('i18n | middlewares | addLocaleToSingleTypesMiddleware', () => {
|
||||
|
||||
it('should not add the search key to a single type link when i18n is not enabled on the single type', () => {
|
||||
const action = {
|
||||
type: 'StrapiAdmin/LeftMenu/SET_CT_OR_ST_LINKS',
|
||||
type: 'ContentManager/App/SET_CONTENT_TYPE_LINKS',
|
||||
data: {
|
||||
authorizedStLinks: [{ destination: 'cm/singleType/test' }],
|
||||
authorizedStLinks: [{ to: 'cm/singleType/test' }],
|
||||
contentTypeSchemas: [{ uid: 'test', pluginOptions: { i18n: { localized: false } } }],
|
||||
},
|
||||
};
|
||||
@ -84,9 +84,9 @@ describe('i18n | middlewares | addLocaleToSingleTypesMiddleware', () => {
|
||||
] = [{ properties: { locales: ['en'] } }];
|
||||
|
||||
const action = {
|
||||
type: 'StrapiAdmin/LeftMenu/SET_CT_OR_ST_LINKS',
|
||||
type: 'ContentManager/App/SET_CONTENT_TYPE_LINKS',
|
||||
data: {
|
||||
authorizedStLinks: [{ destination: 'cm/singleType/test' }],
|
||||
authorizedStLinks: [{ to: 'cm/singleType/test' }],
|
||||
contentTypeSchemas: [{ uid: 'test', pluginOptions: { i18n: { localized: true } } }],
|
||||
},
|
||||
};
|
||||
@ -97,11 +97,9 @@ describe('i18n | middlewares | addLocaleToSingleTypesMiddleware', () => {
|
||||
middleware(next)(action);
|
||||
|
||||
const expected = {
|
||||
type: 'StrapiAdmin/LeftMenu/SET_CT_OR_ST_LINKS',
|
||||
type: 'ContentManager/App/SET_CONTENT_TYPE_LINKS',
|
||||
data: {
|
||||
authorizedStLinks: [
|
||||
{ destination: 'cm/singleType/test', search: 'plugins[i18n][locale]=en' },
|
||||
],
|
||||
authorizedStLinks: [{ to: 'cm/singleType/test', search: 'plugins[i18n][locale]=en' }],
|
||||
contentTypeSchemas: [{ uid: 'test', pluginOptions: { i18n: { localized: true } } }],
|
||||
},
|
||||
};
|
||||
@ -116,9 +114,9 @@ describe('i18n | middlewares | addLocaleToSingleTypesMiddleware', () => {
|
||||
] = [{ properties: { locales: [] } }];
|
||||
|
||||
const action = {
|
||||
type: 'StrapiAdmin/LeftMenu/SET_CT_OR_ST_LINKS',
|
||||
type: 'ContentManager/App/SET_CONTENT_TYPE_LINKS',
|
||||
data: {
|
||||
authorizedStLinks: [{ destination: 'cm/singleType/test' }],
|
||||
authorizedStLinks: [{ to: 'cm/singleType/test' }],
|
||||
contentTypeSchemas: [{ uid: 'test', pluginOptions: { i18n: { localized: true } } }],
|
||||
},
|
||||
};
|
||||
@ -129,9 +127,9 @@ describe('i18n | middlewares | addLocaleToSingleTypesMiddleware', () => {
|
||||
middleware(next)(action);
|
||||
|
||||
const expected = {
|
||||
type: 'StrapiAdmin/LeftMenu/SET_CT_OR_ST_LINKS',
|
||||
type: 'ContentManager/App/SET_CONTENT_TYPE_LINKS',
|
||||
data: {
|
||||
authorizedStLinks: [{ destination: 'cm/singleType/test', isDisplayed: false }],
|
||||
authorizedStLinks: [{ to: 'cm/singleType/test', isDisplayed: false }],
|
||||
contentTypeSchemas: [{ uid: 'test', pluginOptions: { i18n: { localized: true } } }],
|
||||
},
|
||||
};
|
||||
@ -146,11 +144,9 @@ describe('i18n | middlewares | addLocaleToSingleTypesMiddleware', () => {
|
||||
] = [{ properties: { locales: ['en'] } }];
|
||||
|
||||
const action = {
|
||||
type: 'StrapiAdmin/LeftMenu/SET_CT_OR_ST_LINKS',
|
||||
type: 'ContentManager/App/SET_CONTENT_TYPE_LINKS',
|
||||
data: {
|
||||
authorizedStLinks: [
|
||||
{ destination: 'cm/singleType/test', search: 'plugins[plugin][test]=test' },
|
||||
],
|
||||
authorizedStLinks: [{ to: 'cm/singleType/test', search: 'plugins[plugin][test]=test' }],
|
||||
contentTypeSchemas: [{ uid: 'test', pluginOptions: { i18n: { localized: true } } }],
|
||||
},
|
||||
};
|
||||
@ -161,11 +157,11 @@ describe('i18n | middlewares | addLocaleToSingleTypesMiddleware', () => {
|
||||
middleware(next)(action);
|
||||
|
||||
const expected = {
|
||||
type: 'StrapiAdmin/LeftMenu/SET_CT_OR_ST_LINKS',
|
||||
type: 'ContentManager/App/SET_CONTENT_TYPE_LINKS',
|
||||
data: {
|
||||
authorizedStLinks: [
|
||||
{
|
||||
destination: 'cm/singleType/test',
|
||||
to: 'cm/singleType/test',
|
||||
search: 'plugins[plugin][test]=test&plugins[i18n][locale]=en',
|
||||
},
|
||||
],
|
||||
|
@ -4,7 +4,7 @@ import getDefaultLocale from '../../utils/getDefaultLocale';
|
||||
|
||||
const addLocaleToLinksSearch = (links, kind, contentTypeSchemas, locales, permissions) => {
|
||||
return links.map(link => {
|
||||
const contentTypeUID = link.destination.split(`/${kind}/`)[1];
|
||||
const contentTypeUID = link.to.split(`/${kind}/`)[1];
|
||||
|
||||
const contentTypeSchema = contentTypeSchemas.find(({ uid }) => uid === contentTypeUID);
|
||||
|
||||
|
@ -6,7 +6,7 @@ describe('i18n | middlewares | utils | addLocaleToLinksSearch', () => {
|
||||
});
|
||||
|
||||
it('should not modify the links when i18n is not enabled on a content type', () => {
|
||||
const links = [{ uid: 'test', destination: 'cm/collectionType/test' }];
|
||||
const links = [{ uid: 'test', to: 'cm/collectionType/test' }];
|
||||
const schemas = [{ uid: 'test', pluginOptions: { i18n: { localized: false } } }];
|
||||
|
||||
expect(addLocaleToLinksSearch(links, 'collectionType', schemas)).toEqual(links);
|
||||
@ -14,8 +14,8 @@ describe('i18n | middlewares | utils | addLocaleToLinksSearch', () => {
|
||||
|
||||
it('should set the isDisplayed key to false when the user does not have the permission to read or create a locale on a collection type', () => {
|
||||
const links = [
|
||||
{ uid: 'foo', destination: 'cm/collectionType/foo', isDisplayed: true },
|
||||
{ uid: 'bar', destination: 'cm/collectionType/bar', isDisplayed: true },
|
||||
{ uid: 'foo', to: 'cm/collectionType/foo', isDisplayed: true },
|
||||
{ uid: 'bar', to: 'cm/collectionType/bar', isDisplayed: true },
|
||||
];
|
||||
const schemas = [
|
||||
{ uid: 'foo', pluginOptions: { i18n: { localized: true } } },
|
||||
@ -58,8 +58,8 @@ describe('i18n | middlewares | utils | addLocaleToLinksSearch', () => {
|
||||
},
|
||||
};
|
||||
const expected = [
|
||||
{ uid: 'foo', destination: 'cm/collectionType/foo', isDisplayed: false },
|
||||
{ uid: 'bar', destination: 'cm/collectionType/bar', isDisplayed: false },
|
||||
{ uid: 'foo', to: 'cm/collectionType/foo', isDisplayed: false },
|
||||
{ uid: 'bar', to: 'cm/collectionType/bar', isDisplayed: false },
|
||||
];
|
||||
const locales = [{ code: 'en', isDefault: true }, { code: 'fr' }];
|
||||
|
||||
@ -70,8 +70,8 @@ describe('i18n | middlewares | utils | addLocaleToLinksSearch', () => {
|
||||
|
||||
it('should add the locale to a link search', () => {
|
||||
const links = [
|
||||
{ uid: 'foo', destination: 'cm/collectionType/foo', isDisplayed: true, search: 'page=1' },
|
||||
{ uid: 'bar', destination: 'cm/collectionType/bar', isDisplayed: true },
|
||||
{ uid: 'foo', to: 'cm/collectionType/foo', isDisplayed: true, search: 'page=1' },
|
||||
{ uid: 'bar', to: 'cm/collectionType/bar', isDisplayed: true },
|
||||
];
|
||||
const schemas = [
|
||||
{ uid: 'foo', pluginOptions: { i18n: { localized: true } } },
|
||||
@ -117,13 +117,13 @@ describe('i18n | middlewares | utils | addLocaleToLinksSearch', () => {
|
||||
const expected = [
|
||||
{
|
||||
uid: 'foo',
|
||||
destination: 'cm/collectionType/foo',
|
||||
to: 'cm/collectionType/foo',
|
||||
isDisplayed: true,
|
||||
search: 'page=1&plugins[i18n][locale]=fr',
|
||||
},
|
||||
{
|
||||
uid: 'bar',
|
||||
destination: 'cm/collectionType/bar',
|
||||
to: 'cm/collectionType/bar',
|
||||
isDisplayed: true,
|
||||
search: 'plugins[i18n][locale]=en',
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user