Temp commit before layout refacto

Signed-off-by: soupette <cyril.lpz@gmail.com>
This commit is contained in:
soupette 2020-11-03 17:07:56 +01:00
parent 5c11e0aeb8
commit b834aea0c9
9 changed files with 244 additions and 281 deletions

View File

@ -124,6 +124,7 @@ module.exports = {
'react/destructuring-assignment': 0, 'react/destructuring-assignment': 0,
'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }], 'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }],
'react/forbid-prop-types': 0, 'react/forbid-prop-types': 0,
'react/no-unused-prop-types': 2,
'react/jsx-props-no-spreading': 0, 'react/jsx-props-no-spreading': 0,
'react/jsx-one-expression-per-line': 0, 'react/jsx-one-expression-per-line': 0,
'react/state-in-constructor': 0, 'react/state-in-constructor': 0,

View File

@ -8,17 +8,17 @@ const EditSettingsView = lazy(() => import('../EditSettingsView'));
const ListView = lazy(() => import('../ListView')); const ListView = lazy(() => import('../ListView'));
const ListSettingsView = lazy(() => import('../ListSettingsView')); const ListSettingsView = lazy(() => import('../ListSettingsView'));
const CollectionTypeRecursivePath = props => { const CollectionTypeRecursivePath = () => {
const { url } = useRouteMatch(); const { url } = useRouteMatch();
const { slug } = useParams(); const { slug } = useParams();
const renderRoute = (routeProps, Component) => { const renderRoute = (routeProps, Component) => {
return <Component {...props} {...routeProps} slug={slug} />; return <Component {...routeProps} slug={slug} />;
}; };
const renderPermissionsRoute = (routeProps, Component) => { const renderPermissionsRoute = (routeProps, Component) => {
return ( return (
<CheckPagePermissions permissions={pluginPermissions.collectionTypesConfigurations}> <CheckPagePermissions permissions={pluginPermissions.collectionTypesConfigurations}>
<Component {...props} {...routeProps} slug={slug} /> <Component {...routeProps} slug={slug} />
</CheckPagePermissions> </CheckPagePermissions>
); );
}; };

View File

@ -11,6 +11,7 @@ import {
generateFiltersFromSearch, generateFiltersFromSearch,
request, request,
CheckPermissions, CheckPermissions,
useGlobalContext,
useUserPermissions, useUserPermissions,
useQuery, useQuery,
} from 'strapi-helper-plugin'; } from 'strapi-helper-plugin';
@ -26,11 +27,12 @@ import {
import DisplayedFieldsDropdown from '../../components/DisplayedFieldsDropdown'; import DisplayedFieldsDropdown from '../../components/DisplayedFieldsDropdown';
import Container from '../../components/Container'; import Container from '../../components/Container';
import CustomTable from '../../components/CustomTable'; import CustomTable from '../../components/CustomTable';
import FilterPicker from '../../components/FilterPicker';
// import FilterPicker from '../../components/FilterPicker';
import Search from '../../components/Search'; import Search from '../../components/Search';
import State from '../../components/State'; import State from '../../components/State';
import ListViewProvider from '../ListViewProvider'; import ListViewProvider from '../ListViewProvider';
import { onChangeListLabels, resetListLabels } from '../Main/actions'; // import { onChangeListLabels, resetListLabels } from '../Main/actions';
import { AddFilterCta, FilterIcon, Wrapper } from './components'; import { AddFilterCta, FilterIcon, Wrapper } from './components';
import Filter from './Filter'; import Filter from './Filter';
import Footer from './Footer'; import Footer from './Footer';
@ -52,11 +54,15 @@ import makeSelectListView from './selectors';
/* eslint-disable react/no-array-index-key */ /* eslint-disable react/no-array-index-key */
const FilterPicker = () => <div>FILTER</div>;
const onChangeListLabels = () => console.log('todo');
const resetListLabels = () => console.log('todo');
function ListView({ function ListView({
count, count,
data, data,
didDeleteData, didDeleteData,
emitEvent, // emitEvent,
entriesToDelete, entriesToDelete,
isLoading, isLoading,
location: { pathname }, location: { pathname },
@ -80,6 +86,7 @@ function ListView({
toggleModalDelete, toggleModalDelete,
toggleModalDeleteAll, toggleModalDeleteAll,
}) { }) {
const { emitEvent } = useGlobalContext();
const viewPermissions = useMemo(() => generatePermissionsObject(slug), [slug]); const viewPermissions = useMemo(() => generatePermissionsObject(slug), [slug]);
const { const {
isLoading: isLoadingForPermissions, isLoading: isLoadingForPermissions,
@ -656,7 +663,7 @@ ListView.propTypes = {
count: PropTypes.number.isRequired, count: PropTypes.number.isRequired,
data: PropTypes.array.isRequired, data: PropTypes.array.isRequired,
didDeleteData: PropTypes.bool.isRequired, didDeleteData: PropTypes.bool.isRequired,
emitEvent: PropTypes.func.isRequired, // emitEvent: PropTypes.func.isRequired,
entriesToDelete: PropTypes.array.isRequired, entriesToDelete: PropTypes.array.isRequired,
isLoading: PropTypes.bool.isRequired, isLoading: PropTypes.bool.isRequired,
layouts: PropTypes.object, layouts: PropTypes.object,
@ -664,7 +671,7 @@ ListView.propTypes = {
pathname: PropTypes.string.isRequired, pathname: PropTypes.string.isRequired,
search: PropTypes.string.isRequired, search: PropTypes.string.isRequired,
}).isRequired, }).isRequired,
models: PropTypes.array.isRequired, // models: PropTypes.array.isRequired,
getData: PropTypes.func.isRequired, getData: PropTypes.func.isRequired,
getDataSucceeded: PropTypes.func.isRequired, getDataSucceeded: PropTypes.func.isRequired,
history: PropTypes.shape({ history: PropTypes.shape({

View File

@ -1,61 +1,75 @@
import { import {
DELETE_LAYOUT, // DELETE_LAYOUT,
DELETE_LAYOUTS, // DELETE_LAYOUTS,
GET_DATA,
GET_DATA_SUCCEEDED, GET_DATA_SUCCEEDED,
GET_LAYOUT_SUCCEEDED, // GET_LAYOUT_SUCCEEDED,
ON_CHANGE_LIST_LABELS, // ON_CHANGE_LIST_LABELS,
RESET_LIST_LABELS, // RESET_LIST_LABELS,
RESET_PROPS, RESET_PROPS,
} from './constants'; } from './constants';
export function deleteLayout(uid) { // export function deleteLayout(uid) {
return { // return {
type: DELETE_LAYOUT, // type: DELETE_LAYOUT,
uid, // uid,
}; // };
} // }
export function deleteLayouts() { // export function deleteLayouts() {
return { // return {
type: DELETE_LAYOUTS, // type: DELETE_LAYOUTS,
}; // };
} // }
export function getDataSucceeded(components, models, mainFields) { // export function getDataSucceeded(components, models, mainFields) {
return { // return {
// type: GET_DATA_SUCCEEDED,
// components,
// models: models.filter(model => model.isDisplayed === true),
// mainFields,
// };
// }
// export function getLayoutSucceeded(layout, uid) {
// return {
// type: GET_LAYOUT_SUCCEEDED,
// layout,
// uid,
// };
// }
// export function onChangeListLabels({ target: { name, slug, value } }) {
// return {
// type: ON_CHANGE_LIST_LABELS,
// name,
// slug,
// value,
// };
// }
// export function resetListLabels(slug) {
// return {
// type: RESET_LIST_LABELS,
// slug,
// };
// }
// export function resetProps() {
// return {
// type: RESET_PROPS,
// };
// }
//
export const getData = () => ({
type: GET_DATA,
});
export const getDataSucceeded = (models, components) => ({
type: GET_DATA_SUCCEEDED, type: GET_DATA_SUCCEEDED,
components, components,
models: models.filter(model => model.isDisplayed === true), models,
mainFields, });
};
}
export function getLayoutSucceeded(layout, uid) { export const resetProps = () => ({ type: RESET_PROPS });
return {
type: GET_LAYOUT_SUCCEEDED,
layout,
uid,
};
}
export function onChangeListLabels({ target: { name, slug, value } }) {
return {
type: ON_CHANGE_LIST_LABELS,
name,
slug,
value,
};
}
export function resetListLabels(slug) {
return {
type: RESET_LIST_LABELS,
slug,
};
}
export function resetProps() {
return {
type: RESET_PROPS,
};
}

View File

@ -1,7 +1,9 @@
export const DELETE_LAYOUT = 'ContentManager/Main/DELETE_LAYOUT'; export const GET_DATA = 'ContentManager/Main/GET_DATA';
export const DELETE_LAYOUTS = 'ContentManager/Main/DELETE_LAYOUTS';
export const GET_DATA_SUCCEEDED = 'ContentManager/Main/GET_DATA_SUCCEEDED'; export const GET_DATA_SUCCEEDED = 'ContentManager/Main/GET_DATA_SUCCEEDED';
export const GET_LAYOUT_SUCCEEDED = 'ContentManager/Main/GET_LAYOUT_SUCCEEDED';
export const ON_CHANGE_LIST_LABELS = 'ContentManager/Main/ON_CHANGE_LIST_LABELS';
export const RESET_LIST_LABELS = 'ContentManager/Main/RESET_LIST_LABELS';
export const RESET_PROPS = 'ContentManager/Main/RESET_PROPS'; export const RESET_PROPS = 'ContentManager/Main/RESET_PROPS';
// export const DELETE_LAYOUT = 'ContentManager/Main/DELETE_LAYOUT';
// export const DELETE_LAYOUTS = 'ContentManager/Main/DELETE_LAYOUTS';
// export const GET_LAYOUT_SUCCEEDED = 'ContentManager/Main/GET_LAYOUT_SUCCEEDED';
// export const ON_CHANGE_LIST_LABELS = 'ContentManager/Main/ON_CHANGE_LIST_LABELS';
// export const RESET_LIST_LABELS = 'ContentManager/Main/RESET_LIST_LABELS';

View File

@ -1,156 +1,90 @@
import React, { Suspense, lazy, useEffect, useRef } from 'react'; import React, { useEffect } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { bindActionCreators, compose } from 'redux'; import { bindActionCreators, compose } from 'redux';
import { Switch, Route, useRouteMatch } from 'react-router-dom'; import { Switch, Route } from 'react-router-dom';
import { import { LoadingIndicatorPage, request, CheckPagePermissions } from 'strapi-helper-plugin';
LoadingIndicatorPage,
useGlobalContext,
request,
CheckPagePermissions,
} from 'strapi-helper-plugin';
import { DndProvider } from 'react-dnd'; import { DndProvider } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend'; import HTML5Backend from 'react-dnd-html5-backend';
import pluginId from '../../pluginId'; import pluginId from '../../pluginId';
import pluginPermissions from '../../permissions'; import pluginPermissions from '../../permissions';
import DragLayer from '../../components/DragLayer'; import DragLayer from '../../components/DragLayer';
import getRequestUrl from '../../utils/getRequestUrl'; import getRequestUrl from '../../utils/getRequestUrl';
import createPossibleMainFieldsForModelsAndComponents from './utils/createPossibleMainFieldsForModelsAndComponents'; import CollectionTypeRecursivePath from '../CollectionTypeRecursivePath';
import { import EditSettingsView from '../EditSettingsView';
deleteLayout, import SingleTypeRecursivePath from '../SingleTypeRecursivePath';
deleteLayouts, // import createPossibleMainFieldsForModelsAndComponents from './utils/createPossibleMainFieldsForModelsAndComponents';
getDataSucceeded, import { getData, getDataSucceeded, resetProps } from './actions';
getLayoutSucceeded,
resetProps,
} from './actions';
import makeSelectMain from './selectors'; import makeSelectMain from './selectors';
const EditSettingsView = lazy(() => import('../EditSettingsView')); // const EditSettingsView = lazy(() => import('../EditSettingsView'));
const CollectionTypeRecursivePath = lazy(() => import('../CollectionTypeRecursivePath')); // const CollectionTypeRecursivePath = lazy(() => import('../CollectionTypeRecursivePath'));
const SingleTypeRecursivePath = lazy(() => import('../SingleTypeRecursivePath')); // const SingleTypeRecursivePath = lazy(() => import('../SingleTypeRecursivePath'));
function Main({ function Main({ getData, getDataSucceeded, isLoading, resetProps }) {
deleteLayout, useEffect(() => {
deleteLayouts, const abortController = new AbortController();
getDataSucceeded, const { signal } = abortController;
getLayoutSucceeded,
components, const fetchData = async signal => {
componentsAndModelsMainPossibleMainFields, getData();
isLoading, console.log('up');
layouts,
location: { pathname },
global: { currentEnvironment, plugins },
models,
resetProps,
}) {
const { emitEvent } = useGlobalContext();
const {
params: { slug },
} = useRouteMatch('/plugins/content-manager/:contentType/:slug');
const getDataRef = useRef();
const getLayoutRef = useRef();
const resetPropsRef = useRef();
getDataRef.current = async () => {
try { try {
const [{ data: components }, { data: models }] = await Promise.all( const [{ data: components }, { data: models }] = await Promise.all(
['components', 'content-types'].map(endPoint => ['components', 'content-types'].map(endPoint =>
request(getRequestUrl(endPoint), { method: 'GET' }) request(getRequestUrl(endPoint), { method: 'GET', signal })
) )
); );
getDataSucceeded(components, models, { getDataSucceeded(models, components);
...createPossibleMainFieldsForModelsAndComponents(components),
...createPossibleMainFieldsForModelsAndComponents(models),
});
} catch (err) { } catch (err) {
console.error('CM/main', err);
// TODO: new notif API
strapi.notification.error('notification.error'); strapi.notification.error('notification.error');
} }
}; };
getLayoutRef.current = async uid => { fetchData(signal);
try {
const { data: layout } = await request(getRequestUrl(`content-types/${uid}`), {
method: 'GET',
});
getLayoutSucceeded(layout, uid);
} catch (err) {
strapi.notification.error('notification.error');
}
};
resetPropsRef.current = resetProps;
// TODO change the layouts logic
const shouldShowLoader = !pathname.includes('ctm-configurations/') && layouts[slug] === undefined;
useEffect(() => {
getDataRef.current();
return () => { return () => {
resetPropsRef.current(); abortController.abort();
resetProps();
}; };
}, [getDataRef]); }, [getData, getDataSucceeded, resetProps]);
// This effect is fetching the layout of each content type, however the logic of fetching a specific if (isLoading) {
// ct has been re introduced in the EditView with the useFetchContentType hook this causes, sometimes, the layout to be fetched twice
// I am leaving this legacy for now and will redo the logic when the back-end when the endpoints for the single types and the collection types will be split
useEffect(() => {
if (shouldShowLoader) {
getLayoutRef.current(slug);
}
}, [getLayoutRef, shouldShowLoader, slug]);
if (isLoading || shouldShowLoader) {
return <LoadingIndicatorPage />; return <LoadingIndicatorPage />;
} }
const renderRoute = (props, Component) => (
<Component
currentEnvironment={currentEnvironment}
deleteLayout={deleteLayout}
deleteLayouts={deleteLayouts}
emitEvent={emitEvent}
components={components}
componentsAndModelsMainPossibleMainFields={componentsAndModelsMainPossibleMainFields}
layouts={layouts}
models={models}
plugins={plugins}
{...props}
/>
);
const routes = [ const routes = [
{ path: 'singleType/:slug', comp: SingleTypeRecursivePath }, { path: 'singleType/:slug', comp: SingleTypeRecursivePath },
{ path: 'collectionType/:slug', comp: CollectionTypeRecursivePath }, { path: 'collectionType/:slug', comp: CollectionTypeRecursivePath },
].map(({ path, comp }) => ( ].map(({ path, comp }) => (
<Route <Route key={path} path={`/plugins/${pluginId}/${path}`} component={comp} />
key={path}
path={`/plugins/${pluginId}/${path}`}
render={props => renderRoute(props, comp)}
/>
)); ));
return ( return (
<DndProvider backend={HTML5Backend}> <DndProvider backend={HTML5Backend}>
<DragLayer /> <DragLayer />
<Suspense fallback={<LoadingIndicatorPage />}>
<Switch> <Switch>
<Route <Route
path={`/plugins/${pluginId}/ctm-configurations/edit-settings/:type/:componentSlug`} path={`/plugins/${pluginId}/ctm-configurations/edit-settings/:type/:componentSlug`}
render={routeProps => ( render={routeProps => (
<CheckPagePermissions permissions={pluginPermissions.componentsConfigurations}> <CheckPagePermissions permissions={pluginPermissions.componentsConfigurations}>
<EditSettingsView <EditSettingsView
currentEnvironment={currentEnvironment} // currentEnvironment={currentEnvironment}
deleteLayout={deleteLayout} // deleteLayout={deleteLayout}
deleteLayouts={deleteLayouts} // deleteLayouts={deleteLayouts}
emitEvent={emitEvent} // emitEvent={emitEvent}
components={components} // components={components}
componentsAndModelsMainPossibleMainFields={ // componentsAndModelsMainPossibleMainFields={
componentsAndModelsMainPossibleMainFields // componentsAndModelsMainPossibleMainFields
} // }
layouts={layouts} // layouts={layouts}
models={models} // models={models}
plugins={plugins} // plugins={plugins}
{...routeProps} {...routeProps}
/> />
</CheckPagePermissions> </CheckPagePermissions>
@ -158,29 +92,14 @@ function Main({
/> />
{routes} {routes}
</Switch> </Switch>
</Suspense>
</DndProvider> </DndProvider>
); );
} }
Main.propTypes = { Main.propTypes = {
deleteLayout: PropTypes.func.isRequired, getData: PropTypes.func.isRequired,
deleteLayouts: PropTypes.func.isRequired,
getDataSucceeded: PropTypes.func.isRequired, getDataSucceeded: PropTypes.func.isRequired,
getLayoutSucceeded: PropTypes.func.isRequired,
global: PropTypes.shape({
currentEnvironment: PropTypes.string.isRequired,
plugins: PropTypes.object,
}).isRequired,
components: PropTypes.array.isRequired,
componentsAndModelsMainPossibleMainFields: PropTypes.object.isRequired,
isLoading: PropTypes.bool.isRequired, isLoading: PropTypes.bool.isRequired,
layouts: PropTypes.object.isRequired,
location: PropTypes.shape({
pathname: PropTypes.string.isRequired,
search: PropTypes.string,
}).isRequired,
models: PropTypes.array.isRequired,
resetProps: PropTypes.func.isRequired, resetProps: PropTypes.func.isRequired,
}; };
@ -189,10 +108,8 @@ const mapStateToProps = makeSelectMain();
export function mapDispatchToProps(dispatch) { export function mapDispatchToProps(dispatch) {
return bindActionCreators( return bindActionCreators(
{ {
deleteLayout, getData,
deleteLayouts,
getDataSucceeded, getDataSucceeded,
getLayoutSucceeded,
resetProps, resetProps,
}, },
dispatch dispatch

View File

@ -2,68 +2,97 @@
* *
* main reducer * main reducer
*/ */
/* eslint-disable consistent-return */
import { fromJS } from 'immutable'; import produce from 'immer';
import { import {
DELETE_LAYOUT, // DELETE_LAYOUT,
DELETE_LAYOUTS, // DELETE_LAYOUTS,
GET_DATA,
GET_DATA_SUCCEEDED, GET_DATA_SUCCEEDED,
GET_LAYOUT_SUCCEEDED, // GET_LAYOUT_SUCCEEDED,
ON_CHANGE_LIST_LABELS, // ON_CHANGE_LIST_LABELS,
RESET_LIST_LABELS, // RESET_LIST_LABELS,
RESET_PROPS, RESET_PROPS,
} from './constants'; } from './constants';
// import { fromJS } from 'immutable';
export const initialState = fromJS({ const initialState = {
componentsAndModelsMainPossibleMainFields: {}, // TODO!
// componentsAndModelsMainPossibleMainFields: {},
// TODO!
components: [], components: [],
initialLayouts: {},
isLoading: true, isLoading: true,
layouts: {},
models: [], models: [],
};
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;
break;
}
case RESET_PROPS: {
draftState = initialState;
break;
}
default:
return draftState;
}
}); });
function mainReducer(state = initialState, action) { // export const initialState = fromJS({
switch (action.type) { // componentsAndModelsMainPossibleMainFields: {},
case DELETE_LAYOUT: // components: [],
return state.removeIn(['layouts', action.uid]); // initialLayouts: {},
case DELETE_LAYOUTS: // isLoading: true,
return state.update('layouts', () => fromJS({})); // layouts: {},
case GET_DATA_SUCCEEDED: // models: [],
return state // });
.update('components', () => fromJS(action.components))
.update('models', () => fromJS(action.models))
.update('componentsAndModelsMainPossibleMainFields', () =>
fromJS(action.mainFields)
)
.update('isLoading', () => false);
case GET_LAYOUT_SUCCEEDED:
return state
.updateIn(['layouts', action.uid], () => fromJS(action.layout))
.updateIn(['initialLayouts', action.uid], () => fromJS(action.layout));
case ON_CHANGE_LIST_LABELS: {
const { name, slug, value } = action;
return state.updateIn( // function mainReducer(state = initialState, action) {
['layouts', slug, 'contentType', 'layouts', 'list'], // switch (action.type) {
list => { // case DELETE_LAYOUT:
if (value) { // return state.removeIn(['layouts', action.uid]);
return list.push(name); // case DELETE_LAYOUTS:
} // return state.update('layouts', () => fromJS({}));
// case GET_DATA_SUCCEEDED:
// return state
// .update('components', () => fromJS(action.components))
// .update('models', () => fromJS(action.models))
// .update('componentsAndModelsMainPossibleMainFields', () => fromJS(action.mainFields))
// .update('isLoading', () => false);
// case GET_LAYOUT_SUCCEEDED:
// return state
// .updateIn(['layouts', action.uid], () => fromJS(action.layout))
// .updateIn(['initialLayouts', action.uid], () => fromJS(action.layout));
// case ON_CHANGE_LIST_LABELS: {
// const { name, slug, value } = action;
return list.filter(l => l !== name); // return state.updateIn(['layouts', slug, 'contentType', 'layouts', 'list'], list => {
} // if (value) {
); // return list.push(name);
} // }
case RESET_LIST_LABELS:
return state.updateIn(['layouts', action.slug], () => // return list.filter(l => l !== name);
state.getIn(['initialLayouts', action.slug]) // });
); // }
case RESET_PROPS: // case RESET_LIST_LABELS:
return initialState; // return state.updateIn(['layouts', action.slug], () =>
default: // state.getIn(['initialLayouts', action.slug])
return state; // );
} // case RESET_PROPS:
} // return initialState;
// default:
// return state;
// }
// }
export default mainReducer; export default mainReducer;
export { initialState };

View File

@ -2,29 +2,20 @@ import { createSelector } from 'reselect';
import pluginId from '../../pluginId'; import pluginId from '../../pluginId';
import { initialState } from './reducer'; import { initialState } from './reducer';
/** const selectMainDomain = () => state => {
* Direct selector to the main state domain return state.get(`${pluginId}_main`) || initialState;
*/ };
const selectMainDomain = () => state => state.get(`${pluginId}_main`) || initialState;
/**
* Other specific selectors
*/
/**
* Default selector used by Main
*/
const makeSelectMain = () => const makeSelectMain = () =>
createSelector(selectMainDomain(), substate => { createSelector(selectMainDomain(), substate => {
return substate.toJS(); return substate;
}); });
const makeSelectModels = () => const makeSelectModels = () =>
createSelector(selectMainDomain(), substate => { createSelector(selectMainDomain(), substate => {
const allModels = substate.get('models').toJS(); const { models } = substate;
return allModels.filter(model => model.isDisplayed === true).map(({ uid }) => uid); return models.filter(model => model.isDisplayed === true).map(({ uid }) => uid);
}); });
export default makeSelectMain; export default makeSelectMain;

View File

@ -1,3 +1,5 @@
// TODO
import { get } from 'lodash'; import { get } from 'lodash';
const createPossibleMainFieldsForModelsAndComponents = array => { const createPossibleMainFieldsForModelsAndComponents = array => {