mirror of
https://github.com/strapi/strapi.git
synced 2025-11-02 02:44:55 +00:00
Fix after PR feedback
Signed-off-by: HichamELBSI <elabbassih@gmail.com>
This commit is contained in:
parent
a68384567f
commit
e73a145535
@ -0,0 +1,57 @@
|
||||
import selectMenuLinks from '../selectors';
|
||||
import { fixtures } from '../../../../../../../admin-test-utils';
|
||||
|
||||
describe('CONTENT MANAGER | Containers | CollectionTypeFormWrapper | selectors', () => {
|
||||
let store;
|
||||
|
||||
beforeEach(() => {
|
||||
store = { ...fixtures.store.state };
|
||||
});
|
||||
|
||||
describe('selectMenuLinks', () => {
|
||||
it('should extract the collection type links from the global state', () => {
|
||||
store['content-manager_app'] = {
|
||||
collectionTypeLinks: [
|
||||
{
|
||||
kind: 'collectionType',
|
||||
name: 'application::address.address',
|
||||
search: 'page=1&pageSize=50&_sort=city:ASC&plugins[i18n][locale]=fr',
|
||||
title: 'Addresses',
|
||||
to: '/plugins/content-manager/collectionType/application::address.address',
|
||||
uid: 'application::address.address',
|
||||
},
|
||||
{
|
||||
kind: 'collectionType',
|
||||
name: 'application::category.category',
|
||||
search: 'page=1&pageSize=50&_sort=city:ASC&plugins[i18n][locale]=fr',
|
||||
title: 'Categories',
|
||||
to: '/plugins/content-manager/collectionType/application::category.category',
|
||||
uid: 'application::category.category',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const actual = selectMenuLinks(store);
|
||||
const expected = [
|
||||
{
|
||||
kind: 'collectionType',
|
||||
name: 'application::address.address',
|
||||
search: 'page=1&pageSize=50&_sort=city:ASC&plugins[i18n][locale]=fr',
|
||||
title: 'Addresses',
|
||||
to: '/plugins/content-manager/collectionType/application::address.address',
|
||||
uid: 'application::address.address',
|
||||
},
|
||||
{
|
||||
kind: 'collectionType',
|
||||
name: 'application::category.category',
|
||||
search: 'page=1&pageSize=50&_sort=city:ASC&plugins[i18n][locale]=fr',
|
||||
title: 'Categories',
|
||||
to: '/plugins/content-manager/collectionType/application::category.category',
|
||||
uid: 'application::category.category',
|
||||
},
|
||||
];
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,6 +1,6 @@
|
||||
import getRedirectionLink, { mergeParams } from '../getRedirectionLink';
|
||||
|
||||
describe('CONTENT MANAGER | Containers | CollectionTypeFormWrapper | utils ', () => {
|
||||
describe('CONTENT MANAGER | Containers | CollectionTypeFormWrapper | utils', () => {
|
||||
describe('getRedirectionLink', () => {
|
||||
it('should return an when no links is matching the slug', () => {
|
||||
const links = [
|
||||
|
||||
@ -37,7 +37,7 @@ export default {
|
||||
pluginsSectionLinks: [
|
||||
{
|
||||
destination: `/plugins/${pluginId}`,
|
||||
icon,
|
||||
icon: 'book-open',
|
||||
label: {
|
||||
id: `${pluginId}.plugin.name`,
|
||||
defaultMessage: 'Content manager',
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Switch, Route, useRouteMatch, Redirect } from 'react-router-dom';
|
||||
import { Switch, Route, useRouteMatch, Redirect, useLocation } from 'react-router-dom';
|
||||
import { CheckPagePermissions, LoadingIndicatorPage, NotFound } from '@strapi/helper-plugin';
|
||||
import { DndProvider } from 'react-dnd';
|
||||
import HTML5Backend from 'react-dnd-html5-backend';
|
||||
@ -14,15 +14,36 @@ import useModels from './useModels';
|
||||
|
||||
const App = () => {
|
||||
const contentTypeMatch = useRouteMatch(`/plugins/${pluginId}/:kind/:uid`);
|
||||
const { status, collectionTypeLinks, singleTypeLinks } = useModels();
|
||||
const models = [...collectionTypeLinks, ...singleTypeLinks];
|
||||
const { status, collectionTypeLinks, singleTypeLinks, models } = useModels();
|
||||
const authorisedModels = [...collectionTypeLinks, ...singleTypeLinks];
|
||||
const { pathname } = useLocation();
|
||||
|
||||
if (status === 'loading') {
|
||||
return <LoadingIndicatorPage />;
|
||||
}
|
||||
|
||||
if (!contentTypeMatch && models.length > 0) {
|
||||
return <Redirect to={`${models[0].to}${models[0].search ? `?${models[0].search}` : ''}`} />;
|
||||
// Redirect the user to the 403 page
|
||||
if (
|
||||
authorisedModels.length === 0 &&
|
||||
models.length > 0 &&
|
||||
pathname !== `/plugins/${pluginId}/403`
|
||||
) {
|
||||
return <Redirect to={`/plugins/${pluginId}/403`} />;
|
||||
}
|
||||
|
||||
// Redirect the user to the create content type page
|
||||
if (models.length === 0 && pathname !== '/plugins/content-manager/no-content-types') {
|
||||
return <Redirect to={`/plugins/${pluginId}/no-content-types`} />;
|
||||
}
|
||||
|
||||
if (!contentTypeMatch && authorisedModels.length > 0) {
|
||||
return (
|
||||
<Redirect
|
||||
to={`${authorisedModels[0].to}${
|
||||
authorisedModels[0].search ? `?${authorisedModels[0].search}` : ''
|
||||
}`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
@ -47,6 +68,16 @@ const App = () => {
|
||||
path={`/plugins/${pluginId}/singleType/:slug`}
|
||||
component={SingleTypeRecursivePath}
|
||||
/>
|
||||
|
||||
{/* These pages must be defined */}
|
||||
<Route
|
||||
path={`/plugins/${pluginId}/403`}
|
||||
render={() => <div>TBD No rights to see the content types</div>}
|
||||
/>
|
||||
<Route
|
||||
path={`/plugins/${pluginId}/no-content-types`}
|
||||
render={() => <div>TBD No ct</div>}
|
||||
/>
|
||||
<Route path="" component={NotFound} />
|
||||
</Switch>
|
||||
</div>
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
import { setContentTypeLinks } from '../actions';
|
||||
|
||||
describe('Content Manager | App | actions', () => {
|
||||
it('should format the setContentTypeLinks action', () => {
|
||||
const authorizedCtLinks = [{ title: 'addresses', uid: 'address' }];
|
||||
const authorizedStLinks = [{ title: 'Home page', uid: 'homepage' }];
|
||||
const models = [
|
||||
{ kind: 'singleType', uid: 'homepage' },
|
||||
{ kind: 'collectionType', uid: 'address' },
|
||||
];
|
||||
const components = [];
|
||||
|
||||
const expected = {
|
||||
type: 'ContentManager/App/SET_CONTENT_TYPE_LINKS',
|
||||
data: {
|
||||
authorizedCtLinks,
|
||||
authorizedStLinks,
|
||||
contentTypeSchemas: models,
|
||||
components,
|
||||
},
|
||||
};
|
||||
|
||||
expect(setContentTypeLinks(authorizedCtLinks, authorizedStLinks, models, components)).toEqual(
|
||||
expected
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,474 @@
|
||||
/* eslint-disable no-irregular-whitespace */
|
||||
import React from 'react';
|
||||
import { createStore, combineReducers } from 'redux';
|
||||
import { Router } from 'react-router-dom';
|
||||
import { createMemoryHistory } from 'history';
|
||||
import { Provider } from 'react-redux';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import ContentManagerApp from '..';
|
||||
import cmReducers from '../../../reducers';
|
||||
import pluginId from '../../../pluginId';
|
||||
import useModels from '../useModels';
|
||||
|
||||
jest.mock('../useModels', () =>
|
||||
jest.fn(() => {
|
||||
return {};
|
||||
})
|
||||
);
|
||||
|
||||
jest.mock('react-intl', () => ({
|
||||
FormattedMessage: () => 'label',
|
||||
useIntl: () => ({ formatMessage: jest.fn(() => 'label') }),
|
||||
}));
|
||||
jest.mock('@fortawesome/react-fontawesome', () => ({
|
||||
FontAwesomeIcon: () => null,
|
||||
}));
|
||||
|
||||
describe('Content manager | App | main', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetModules(); // Most important - it clears the cache
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it('should not crash', () => {
|
||||
const contentManagerState = {
|
||||
collectionTypeLinks: [
|
||||
{
|
||||
uid: 'category',
|
||||
title: 'Categories',
|
||||
name: 'category',
|
||||
to: '/category',
|
||||
kind: 'collectionType',
|
||||
isDisplayed: true,
|
||||
permissions: [
|
||||
{
|
||||
action: 'plugins::content-manager.explorer.read',
|
||||
subject: 'category',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
singleTypeLinks: [
|
||||
{
|
||||
uid: 'homepage',
|
||||
title: 'Home page',
|
||||
name: 'homepage',
|
||||
to: '/homepage',
|
||||
kind: 'singleType',
|
||||
isDisplayed: true,
|
||||
permissions: [
|
||||
{
|
||||
action: 'plugins::content-manager.explorer.read',
|
||||
subject: 'homepage',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
models: [
|
||||
{
|
||||
kind: 'collectionType',
|
||||
uid: 'category',
|
||||
info: { label: 'Categories', name: 'category' },
|
||||
},
|
||||
{ kind: 'singleType', uid: 'homepage', info: { label: 'Home page', name: 'homepage' } },
|
||||
],
|
||||
components: [],
|
||||
status: 'resolved',
|
||||
};
|
||||
useModels.mockImplementation(() => contentManagerState);
|
||||
const rootReducer = combineReducers(cmReducers);
|
||||
const store = createStore(rootReducer, { [`${pluginId}_app`]: contentManagerState });
|
||||
const history = createMemoryHistory();
|
||||
history.push('/plugins/content-manager/collectionType/category');
|
||||
|
||||
const { container } = render(
|
||||
<Provider store={store}>
|
||||
<Router history={history}>
|
||||
<ContentManagerApp />
|
||||
</Router>
|
||||
</Provider>
|
||||
);
|
||||
|
||||
expect(screen.getByText('Home page')).toBeVisible();
|
||||
expect(screen.getByText('Categories')).toBeVisible();
|
||||
expect(container.firstChild).toMatchInlineSnapshot(`
|
||||
.c2 {
|
||||
margin-bottom: 0;
|
||||
padding-left: 0;
|
||||
max-height: 182px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.c2::-webkit-scrollbar {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.c2::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.c2::-webkit-scrollbar-track:hover {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.c2 li {
|
||||
position: relative;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.c2 a {
|
||||
display: block;
|
||||
padding-left: 30px;
|
||||
height: 34px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.c2 a p {
|
||||
color: #2D3138;
|
||||
font-size: 13px;
|
||||
line-height: 34px;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: justify;
|
||||
-webkit-justify-content: space-between;
|
||||
-ms-flex-pack: justify;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.c2 a.active {
|
||||
background-color: #e9eaeb;
|
||||
}
|
||||
|
||||
.c2 a.active p {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.c2 a.active svg {
|
||||
color: #2D3138;
|
||||
}
|
||||
|
||||
.c2 a:hover {
|
||||
-webkit-text-decoration: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.c1 {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.c1 button {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.c1 .count-info {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
height: 14px;
|
||||
min-width: 14px;
|
||||
margin-top: 2px;
|
||||
padding: 1px 3px;
|
||||
text-align: center;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.c1 .count-info:before {
|
||||
content: attr(datadescr);
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
height: 14px;
|
||||
min-width: 14px;
|
||||
padding: 0px 3px;
|
||||
background-color: #E9EAEB;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.c1 .list-header {
|
||||
color: #919bae;
|
||||
}
|
||||
|
||||
.c1 .list-header > div {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.c1 .list-header h3 {
|
||||
margin-bottom: 10px;
|
||||
padding-right: 20px;
|
||||
padding-top: 2px;
|
||||
font-family: Lato;
|
||||
font-size: 1.1rem;
|
||||
line-height: normal;
|
||||
-webkit-letter-spacing: 0.1rem;
|
||||
-moz-letter-spacing: 0.1rem;
|
||||
-ms-letter-spacing: 0.1rem;
|
||||
letter-spacing: 0.1rem;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.c1 .list-header h3 + button {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: 0;
|
||||
padding: 2px 0 0px 5px;
|
||||
line-height: 11px;
|
||||
}
|
||||
|
||||
.c1 .list-header h3 + button i,
|
||||
.c1 .list-header h3 + button svg {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.c1 .list-header .search-wrapper {
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
.c1 .list-header .search-wrapper::after {
|
||||
display: block;
|
||||
content: '';
|
||||
height: 2px;
|
||||
width: calc(100% - 20px);
|
||||
background: #E9EAEB;
|
||||
}
|
||||
|
||||
.c1 .list-header .search-wrapper > svg {
|
||||
position: absolute;
|
||||
bottom: 6px;
|
||||
left: 0;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.c1 .list-header .search-wrapper button {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: 5px 0 0px 5px;
|
||||
line-height: 11px;
|
||||
}
|
||||
|
||||
.c1 .list-header .search-wrapper button i,
|
||||
.c1 .list-header .search-wrapper button svg {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.c1 ul {
|
||||
list-style: none;
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.c1 ul li a {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.c3 {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
-webkit-box-pack: space-around;
|
||||
-webkit-justify-content: space-around;
|
||||
-ms-flex-pack: space-around;
|
||||
justify-content: space-around;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.c3 > div {
|
||||
margin: auto;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 6px solid #f3f3f3;
|
||||
border-top: 6px solid #1c91e7;
|
||||
border-radius: 50%;
|
||||
-webkit-animation: fEWCgj 2s linear infinite;
|
||||
animation: fEWCgj 2s linear infinite;
|
||||
}
|
||||
|
||||
.c0 {
|
||||
width: 100%;
|
||||
min-height: calc(100vh - 6rem);
|
||||
background-color: #f2f3f4;
|
||||
padding-top: 3.1rem;
|
||||
padding-left: 2rem;
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
<div
|
||||
class="container-fluid"
|
||||
>
|
||||
<div
|
||||
class="row"
|
||||
>
|
||||
<div
|
||||
class="c0 col-md-3"
|
||||
>
|
||||
<div
|
||||
class="c1"
|
||||
>
|
||||
<div
|
||||
class="list-header"
|
||||
>
|
||||
<div
|
||||
class="title-wrapper"
|
||||
>
|
||||
<h3>
|
||||
label
|
||||
|
||||
<span
|
||||
class="count-info"
|
||||
datadescr="1"
|
||||
>
|
||||
1
|
||||
</span>
|
||||
</h3>
|
||||
<button />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<ul
|
||||
class="c2"
|
||||
>
|
||||
<li>
|
||||
<a
|
||||
href="/category"
|
||||
>
|
||||
<p>
|
||||
Categories
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="c1"
|
||||
>
|
||||
<div
|
||||
class="list-header"
|
||||
>
|
||||
<div
|
||||
class="title-wrapper"
|
||||
>
|
||||
<h3>
|
||||
label
|
||||
|
||||
<span
|
||||
class="count-info"
|
||||
datadescr="1"
|
||||
>
|
||||
1
|
||||
</span>
|
||||
</h3>
|
||||
<button />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<ul
|
||||
class="c2"
|
||||
>
|
||||
<li>
|
||||
<a
|
||||
href="/homepage"
|
||||
>
|
||||
<p>
|
||||
Home page
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="col-md-9 content"
|
||||
style="padding: 0px 30px;"
|
||||
>
|
||||
<div
|
||||
class="c3"
|
||||
>
|
||||
<div />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
});
|
||||
|
||||
it('should redirect to 403 page', () => {
|
||||
const history = createMemoryHistory();
|
||||
const contentManagerState = {
|
||||
collectionTypeLinks: [],
|
||||
singleTypeLinks: [],
|
||||
models: [
|
||||
{
|
||||
kind: 'collectionType',
|
||||
uid: 'category',
|
||||
info: { label: 'Categories', name: 'category' },
|
||||
},
|
||||
{ kind: 'singleType', uid: 'homepage', info: { label: 'Home page', name: 'homepage' } },
|
||||
],
|
||||
components: [],
|
||||
status: 'resolved',
|
||||
};
|
||||
useModels.mockImplementation(() => contentManagerState);
|
||||
jest.mock('../useModels', () =>
|
||||
jest.fn(() => {
|
||||
return contentManagerState;
|
||||
})
|
||||
);
|
||||
const rootReducer = combineReducers(cmReducers);
|
||||
const store = createStore(rootReducer, { [`${pluginId}_app`]: contentManagerState });
|
||||
history.push('/plugins/content-manager/collectionType/category');
|
||||
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<Router history={history}>
|
||||
<ContentManagerApp />
|
||||
</Router>
|
||||
</Provider>
|
||||
);
|
||||
|
||||
expect(history.location.pathname).toEqual(`/plugins/${pluginId}/403`);
|
||||
});
|
||||
|
||||
it('should redirect to the no-content-types page', () => {
|
||||
const history = createMemoryHistory();
|
||||
const contentManagerState = {
|
||||
collectionTypeLinks: [],
|
||||
singleTypeLinks: [],
|
||||
models: [],
|
||||
components: [],
|
||||
status: 'resolved',
|
||||
};
|
||||
useModels.mockImplementation(() => contentManagerState);
|
||||
jest.mock('../useModels', () =>
|
||||
jest.fn(() => {
|
||||
return contentManagerState;
|
||||
})
|
||||
);
|
||||
const rootReducer = combineReducers(cmReducers);
|
||||
const store = createStore(rootReducer, { [`${pluginId}_app`]: contentManagerState });
|
||||
history.push('/plugins/content-manager/collectionType/category');
|
||||
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<Router
|
||||
history={history}
|
||||
// initialEntries={['/plugins/content-manager/collectionType/category']}
|
||||
>
|
||||
<ContentManagerApp />
|
||||
</Router>
|
||||
</Provider>
|
||||
);
|
||||
|
||||
expect(history.location.pathname).toEqual(`/plugins/${pluginId}/no-content-types`);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,24 @@
|
||||
import { fixtures } from '../../../../../../../admin-test-utils';
|
||||
import { makeSelectModels } from '../selectors';
|
||||
|
||||
describe('Content Manager | App | selectors', () => {
|
||||
let store;
|
||||
|
||||
beforeEach(() => {
|
||||
store = { ...fixtures.store.state };
|
||||
});
|
||||
|
||||
describe('makeSelectModels', () => {
|
||||
it('should extract the models from the content manager state in the global store', () => {
|
||||
store['content-manager_app'] = {
|
||||
models: [{ uid: 'category' }, { uid: 'address' }],
|
||||
};
|
||||
|
||||
const modelSelector = makeSelectModels();
|
||||
const actual = modelSelector(store);
|
||||
const expected = [{ uid: 'category' }, { uid: 'address' }];
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -163,6 +163,7 @@
|
||||
"permissions.not-allowed.update": "You are not allowed to see this document",
|
||||
"plugin.description.long": "Quick way to see, edit and delete the data in your database.",
|
||||
"plugin.description.short": "Quick way to see, edit and delete the data in your database.",
|
||||
"plugin.name": "Content manager",
|
||||
"popUpWarning.bodyMessage.contentType.delete": "Are you sure you want to delete this entry?",
|
||||
"popUpWarning.bodyMessage.contentType.delete.all": "Are you sure you want to delete these entries?",
|
||||
"popUpWarning.warning.cancelAllSettings": "Are you sure you want to cancel your modifications?",
|
||||
|
||||
@ -3,7 +3,7 @@ import styled from 'styled-components';
|
||||
const Wrapper = styled.div`
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 25rem;
|
||||
left: 27rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user