From a733571e32221000b4fee48a4b09970f791180ec Mon Sep 17 00:00:00 2001 From: soupette Date: Mon, 8 Jul 2019 20:27:38 +0200 Subject: [PATCH] Fix getdata records, loaders --- .eslintrc.js | 5 +- package.json | 1 + .../admin/src/components/Search/index.js | 30 +-- .../admin/src/components/Table/index.js | 2 + .../admin/src/containers/ListView/actions.js | 21 ++ .../src/containers/ListView/constants.js | 3 + .../admin/src/containers/ListView/index.js | 123 +++++++++-- .../admin/src/containers/ListView/reducer.js | 17 +- .../admin/src/containers/ListView/saga.js | 59 ++++-- .../admin/src/containers/Main/index.js | 29 ++- .../admin/src/containers/Main/reducer.js | 6 +- .../src/containers/SettingViewModel/index.js | 4 +- .../src/containers/SettingsView/index.js | 7 +- .../controllers/ContentManagerFixtures.js | 191 ++++++++++++++++++ yarn.lock | 5 + 15 files changed, 433 insertions(+), 70 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 5212d550ab..dd6db54c09 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -4,9 +4,10 @@ module.exports = { 'eslint:recommended', 'plugin:react/recommended', 'plugin:redux-saga/recommended', + 'prettier', ], - plugins: ['react', 'redux-saga'], + plugins: ['react', 'redux-saga', 'react-hooks'], env: { browser: true, commonjs: true, @@ -41,6 +42,8 @@ module.exports = { rules: { 'generator-star-spacing': 0, 'no-console': 0, + 'react-hooks/rules-of-hooks': 'error', + 'react-hooks/exhaustive-deps': 'warn', }, settings: { react: { diff --git a/package.json b/package.json index b68bede1fa..5581529ca6 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "eslint": "^5.16.0", "eslint-config-prettier": "^4.3.0", "eslint-plugin-react": "^7.13.0", + "eslint-plugin-react-hooks": "^1.6.1", "eslint-plugin-redux-saga": "^1.0.0", "execa": "^1.0.0", "husky": "^2.3.0", diff --git a/packages/strapi-plugin-content-manager/admin/src/components/Search/index.js b/packages/strapi-plugin-content-manager/admin/src/components/Search/index.js index 8a38c669b2..3d0efd9640 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/Search/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/Search/index.js @@ -1,8 +1,8 @@ /* -* -* Search -* -*/ + * + * Search + * + */ import React from 'react'; import { isEmpty, upperFirst } from 'lodash'; @@ -20,7 +20,10 @@ class Search extends React.Component { componentDidUpdate(prevProps) { const { model, value } = this.props; - if (prevProps.model !== model || !isEmpty(prevProps.value) && isEmpty(value)) { + if ( + prevProps.model !== model || + (!isEmpty(prevProps.value) && isEmpty(value)) + ) { this.resetState(); } } @@ -33,21 +36,20 @@ class Search extends React.Component { clearTimeout(this.timer); this.setState({ value: target.value }); this.timer = setTimeout(() => this.triggerChange(target.value), WAIT); - } + }; handleClick = () => { this.setState({ value: '' }); this.triggerChange(''); - } + }; - triggerChange = (value) => ( + triggerChange = value => this.props.changeParams({ target: { - name: 'params._q', + name: '_q', value, }, - }) - ); + }); render() { const { model } = this.props; @@ -57,7 +59,7 @@ class Search extends React.Component {
- {(message) => ( + {message => ( )} - {value !== '' &&
} + {value !== '' && ( +
+ )}
filter_logo diff --git a/packages/strapi-plugin-content-manager/admin/src/components/Table/index.js b/packages/strapi-plugin-content-manager/admin/src/components/Table/index.js index f2c1534373..e18cc0a8a3 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/Table/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/Table/index.js @@ -90,6 +90,8 @@ Table.defaultProps = { enableBulkActions: true, entriesToDelete: [], handleDelete: () => {}, + records: [], + routeParams: {}, search: '', showLoader: false, }; diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/ListView/actions.js b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/actions.js index e69de29bb2..89430a0575 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/ListView/actions.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/actions.js @@ -0,0 +1,21 @@ +import { GET_DATA, GET_DATA_SUCCEEDED, RESET_PROPS } from './constants'; + +export function getData(uid, params) { + return { + type: GET_DATA, + uid, + params, + }; +} + +export function getDataSucceeded(count, data) { + return { + type: GET_DATA_SUCCEEDED, + count, + data, + }; +} + +export function resetProps() { + return { type: RESET_PROPS }; +} diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/ListView/constants.js b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/constants.js index e69de29bb2..3f9ecafb04 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/ListView/constants.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/constants.js @@ -0,0 +1,3 @@ +export const GET_DATA = 'ContentManager/ListView/GET_DATA'; +export const GET_DATA_SUCCEEDED = 'ContentManager/ListView/GET_DATA_SUCCEEDED'; +export const RESET_PROPS = 'ContentManager/ListView/RESET_PROPS'; diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/ListView/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/index.js index 89a4b1796c..1c681a275e 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/ListView/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/index.js @@ -1,45 +1,124 @@ -import React, { memo, useEffect } from 'react'; +import React, { memo, useCallback, useEffect } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { bindActionCreators, compose } from 'redux'; +import { capitalize, get } from 'lodash'; -import { LoadingIndicatorPage } from 'strapi-helper-plugin'; +import { PluginHeader, getQueryParameters } from 'strapi-helper-plugin'; import pluginId from '../../pluginId'; -import { getLayout } from '../Main/actions'; +import Container from '../../components/Container'; +import Search from '../../components/Search'; +import { getData, resetProps } from './actions'; import reducer from './reducer'; import saga from './saga'; import makeSelectListView from './selectors'; function ListView({ - getLayout, + count, + emitEvent, + location: { search }, + getData, layouts, + isLoading, + history: { push }, match: { params: { slug }, }, + resetProps, }) { strapi.useInjectReducer({ key: 'listView', reducer, pluginId }); strapi.useInjectSaga({ key: 'listView', saga, pluginId }); - // Display a loader if the layout from the main reducer is empty - const shouldShowLoader = layouts[slug] === undefined; + const getLayoutSetting = useCallback( + settingName => get(layouts, [slug, 'settings', settingName], ''), + [layouts, slug] + ); + + const generateSearchParams = useCallback( + (updatedParams = {}) => { + return { + _limit: + getQueryParameters(search, '_limit') || getLayoutSetting('pageSize'), + _page: getQueryParameters(search, '_page') || 1, + _q: getQueryParameters(search, '_q') || '', + _sort: + getQueryParameters(search, '_sort') || + `${getLayoutSetting('defaultSortBy')}:${getLayoutSetting( + 'defaultSortOrder' + )}`, + source: getQueryParameters(search, 'source'), + ...updatedParams, + }; + }, + [getLayoutSetting, search] + ); useEffect(() => { - if (shouldShowLoader) { - getLayout(slug); - } - }, [shouldShowLoader]); + getData(slug, generateSearchParams()); - if (shouldShowLoader) { - return ; - } + return () => { + resetProps(); + }; + /* eslint-disable-next-line react-hooks/exhaustive-deps */ + }, [slug]); + console.log(getLayoutSetting('layouts.list')); + + const pluginHeaderActions = [ + { + id: 'addEntry', + label: 'content-manager.containers.List.addAnEntry', + labelValues: { + entity: capitalize(slug) || 'Content Manager', + }, + kind: 'primaryAddShape', + onClick: () => { + emitEvent('willCreateEntry'); + }, + }, + ]; + const handleChangeParams = ({ target: { name, value } }) => { + const updatedSearch = generateSearchParams({ [name]: value }); + const newSearch = Object.keys(updatedSearch) + .map(key => `${key}=${updatedSearch[key]}`) + .join('&'); + + push({ search: newSearch }); + resetProps(); + getData(slug, updatedSearch); + }; return ( -
-
Coming
-
+ <> + + 1 + ? `${pluginId}.containers.List.pluginHeaderDescription` + : `${pluginId}.containers.List.pluginHeaderDescription.singular`, + values: { + label: count, + }, + }} + title={{ + id: slug || 'Content Manager', + }} + withDescriptionAnim={isLoading} + /> + {getLayoutSetting('searchable') && ( + + )} + + ); } ListView.defaultProps = { @@ -47,13 +126,20 @@ ListView.defaultProps = { }; ListView.propTypes = { - getLayout: PropTypes.func.isRequired, + count: PropTypes.number.isRequired, + emitEvent: PropTypes.func.isRequired, layouts: PropTypes.object, + location: PropTypes.shape({ + search: PropTypes.string.isRequired, + }), + getData: PropTypes.func.isRequired, + isLoading: PropTypes.bool.isRequired, match: PropTypes.shape({ params: PropTypes.shape({ slug: PropTypes.string.isRequired, }), }), + resetProps: PropTypes.func.isRequired, }; const mapStateToProps = makeSelectListView(); @@ -61,7 +147,8 @@ const mapStateToProps = makeSelectListView(); export function mapDispatchToProps(dispatch) { return bindActionCreators( { - getLayout, + getData, + resetProps, }, dispatch ); diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/ListView/reducer.js b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/reducer.js index 279372e1bc..24a4cfc163 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/ListView/reducer.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/reducer.js @@ -3,13 +3,24 @@ * listView reducer */ -import { fromJS } from 'immutable'; -// import { } from './constants'; +import { fromJS, List } from 'immutable'; +import { GET_DATA_SUCCEEDED, RESET_PROPS } from './constants'; -export const initialState = fromJS({}); +export const initialState = fromJS({ + count: 0, + data: List([]), + isLoading: true, +}); function listViewReducer(state = initialState, action) { switch (action.type) { + case GET_DATA_SUCCEEDED: + return state + .update('count', () => action.count) + .update('data', () => List(action.data)) + .update('isLoading', () => false); + case RESET_PROPS: + return initialState; default: return state; } diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/ListView/saga.js b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/saga.js index b1193b55e8..1528a366b0 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/ListView/saga.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/saga.js @@ -1,29 +1,50 @@ -// import { all, fork, put, call, takeLatest, select } from 'redux-saga/effects'; -// import { request } from 'strapi-helper-plugin'; +import { all, fork, put, call, takeLatest, select } from 'redux-saga/effects'; +import { request } from 'strapi-helper-plugin'; +import { set, unset } from 'lodash'; +import pluginId from '../../pluginId'; -// import pluginId from '../../pluginId'; - -// import { } from './actions'; -// import { } from './constants'; +import { getDataSucceeded } from './actions'; +import { GET_DATA } from './constants'; // import {} from './selectors'; -// const getRequestUrl = path => `/${pluginId}/fixtures/${path}`; +const getRequestUrl = path => `/${pluginId}/explorer/${path}`; -export function* getData() { - // try { - // } catch (err) { - // strapi.notification.error('content-manager.error.model.fetch'); - // } +// eslint-disable-next-line require-yield +export function* getData({ uid, params }) { + try { + const _start = (params._page - 1) * parseInt(params._limit, 10); + + set(params, '_start', _start); + unset(params, '_page'); + + if (params._q === '') { + unset(params, '_q'); + } + + const [{ count }, data] = yield all([ + call(request, getRequestUrl(`${uid}/count`), { + method: 'GET', + params, + }), + call(request, getRequestUrl(`${uid}`), { + method: 'GET', + params, + }), + ]); + + yield put(getDataSucceeded(count, data)); + } catch (err) { + console.log({ err }); + strapi.notification.error('content-manager.error.model.fetch'); + } } function* defaultSaga() { - // try { - // yield all([ - // fork(takeLatest, GET_DATA, getData) - // ]); - // } catch (err) { - // // Do nothing - // } + try { + yield all([fork(takeLatest, GET_DATA, getData)]); + } catch (err) { + // Do nothing + } } export default defaultSaga; diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/Main/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/Main/index.js index 172db7e051..8b145920a7 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/Main/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/Main/index.js @@ -1,4 +1,4 @@ -import React, { memo } from 'react'; +import React, { memo, useEffect } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { bindActionCreators, compose } from 'redux'; @@ -12,15 +12,25 @@ import SettingViewModel from '../SettingViewModel'; import SettingViewGroup from '../SettingViewGroup'; import SettingsView from '../SettingsView'; +import { getLayout } from './actions'; import reducer from './reducer'; import saga from './saga'; import makeSelectMain from './selectors'; -function Main({ isLoading, emitEvent, layouts }) { +function Main({ emitEvent, getLayout, layouts, location: { pathname } }) { strapi.useInjectReducer({ key: 'main', reducer, pluginId }); strapi.useInjectSaga({ key: 'main', saga, pluginId }); + const slug = pathname.split('/')[3]; + const shouldShowLoader = + slug !== 'ctm-configurations' && layouts[slug] === undefined; - if (isLoading) { + useEffect(() => { + if (shouldShowLoader) { + getLayout(slug); + } + }, [getLayout, shouldShowLoader, slug]); + + if (shouldShowLoader) { return ; } @@ -52,14 +62,23 @@ function Main({ isLoading, emitEvent, layouts }) { Main.propTypes = { emitEvent: PropTypes.func.isRequired, - isLoading: PropTypes.bool.isRequired, + getLayout: PropTypes.func.isRequired, + layouts: PropTypes.object.isRequired, + location: PropTypes.shape({ + pathname: PropTypes.string.isRequired, + }), }; const mapStateToProps = makeSelectMain(); export function mapDispatchToProps(dispatch) { - return bindActionCreators({}, dispatch); + return bindActionCreators( + { + getLayout, + }, + dispatch + ); } const withConnect = connect( mapStateToProps, diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/Main/reducer.js b/packages/strapi-plugin-content-manager/admin/src/containers/Main/reducer.js index 94ccef3577..170104cc42 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/Main/reducer.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/Main/reducer.js @@ -11,16 +11,12 @@ import { } from './constants'; export const initialState = fromJS({ - isLoading: false, - layouts: fromJS({ - article: {}, - }), + layouts: fromJS({}), }); function mainReducer(state = initialState, action) { switch (action.type) { case DELETE_LAYOUT: - console.log({ action }); return state.removeIn(['layouts', action.uid]); case DELETE_LAYOUTS: return state.update('layouts', () => fromJS({})); diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/index.js index 15d8398c81..cbc14b08da 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/SettingViewModel/index.js @@ -79,13 +79,13 @@ function SettingViewModel({ return () => { resetProps(); }; - }, []); + }, [getData, name, resetProps]); useEffect(() => { if (showWarningSubmit) { toggleWarningSubmit(); } - }, [shouldToggleModalSubmit]); + }, [shouldToggleModalSubmit, showWarningSubmit]); if (isLoading) { return ; diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/SettingsView/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/SettingsView/index.js index 2a099c73e6..627f712335 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/SettingsView/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/SettingsView/index.js @@ -53,19 +53,18 @@ function SettingsView({ const [showWarningCancel, setWarningCancel] = useState(false); const [showWarningSubmit, setWarningSubmit] = useState(false); const toggleWarningCancel = () => setWarningCancel(prevState => !prevState); - const toggleWarningSubmit = () => - setWarningSubmit(prevState => !prevState); + const toggleWarningSubmit = () => setWarningSubmit(prevState => !prevState); useEffect(() => { if (showWarningSubmit) { toggleWarningSubmit(); } - }, [shouldToggleModalSubmit]); + }, [shouldToggleModalSubmit, showWarningSubmit]); useEffect(() => { if (isEmpty(initialData)) { getData(); } - }, [initialData]); + }, [getData, initialData]); if (isLoading) { return ; diff --git a/packages/strapi-plugin-content-manager/controllers/ContentManagerFixtures.js b/packages/strapi-plugin-content-manager/controllers/ContentManagerFixtures.js index b9118c0e79..8c7e1b6382 100644 --- a/packages/strapi-plugin-content-manager/controllers/ContentManagerFixtures.js +++ b/packages/strapi-plugin-content-manager/controllers/ContentManagerFixtures.js @@ -24,6 +24,192 @@ module.exports = { getLayout: ctx => { const layouts = { + tag: { + uid: 'article', + schema: { + // good old schema + connection: 'default', + collectionName: 'articles', + options: {}, + infos: { + name: 'article', + description: '', + }, + attributes: { + title: { + type: 'string', + }, + content: { + type: 'text', + }, + json: { + type: 'string', + }, + number: { + type: 'integer', + }, + date: { + type: 'date', + }, + enum: { + enum: ['morning,', 'noon'], + type: 'enumeration', + }, + pic: { + model: 'file', + via: 'related', + plugin: 'upload', + }, + bool: { + type: 'boolean', + }, + tags: { + collection: 'tag', + via: 'articles', + }, + }, + }, + settings: { + mainField: 'id', + defaultSortBy: 'id', + defaultSortOrder: 'ASC', + searchable: true, + filterable: true, + bulkable: false, + pageSize: 10, + }, + metadata: { + id: { + edit: {}, + list: { + label: 'Id', + searchable: true, + sortable: true, + }, + }, + title: { + edit: { + label: 'title', + description: '....', + editable: true, + visible: true, + }, + list: { + label: 'title', + searchable: true, + sortable: true, + }, + }, + content: { + edit: { + label: 'content', + description: '....', + editable: true, + visible: true, + }, + list: { + label: 'content', + searchable: true, + sortable: true, + }, + }, + json: { + edit: { + label: 'json', + description: '....', + editable: true, + visible: true, + }, + list: {}, + }, + number: { + edit: { + label: 'number', + description: '....', + editable: true, + visible: true, + }, + list: { + label: 'number', + searchable: true, + sortable: true, + }, + }, + date: { + edit: { + label: 'date', + description: '....', + editable: true, + visible: true, + }, + list: { + label: 'date', + searchable: true, + sortable: true, + }, + }, + enum: { + edit: { + label: 'enum', + description: '....', + editable: true, + visible: true, + }, + list: { + label: 'enum', + searchable: true, + sortable: true, + }, + }, + pic: { + edit: { + label: 'pic', + description: '....', + editable: true, + visible: true, + }, + list: {}, + }, + tags: { + edit: { + label: 'tags', + description: '....', + editable: true, + visible: true, + }, + list: {}, + }, + bool: { + edit: { + label: 'bool', + description: '....', + editable: true, + visible: true, + }, + list: { + label: 'bool', + searchable: true, + sortable: true, + }, + }, + }, + layouts: { + list: ['id', 'title', 'content'], + editRelations: [], + edit: [ + [ + { + name: 'title', + size: 6, + }, + { + name: 'content', + size: 6, + }, + ], + ], + }, + }, article: { uid: 'article', schema: { @@ -405,6 +591,11 @@ module.exports = { label: 'Article', destination: 'article', }, + { + name: 'tag', + label: 'Tag', + destination: 'tag', + }, { name: 'administrator', label: 'Administrator', diff --git a/yarn.lock b/yarn.lock index a9f7c02701..f8433c6f28 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6544,6 +6544,11 @@ eslint-config-prettier@^4.3.0: dependencies: get-stdin "^6.0.0" +eslint-plugin-react-hooks@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.6.1.tgz#3c66a5515ea3e0a221ffc5d4e75c971c217b1a4c" + integrity sha512-wHhmGJyVuijnYIJXZJHDUF2WM+rJYTjulUTqF9k61d3BTk8etydz+M4dXUVH7M76ZRS85rqBTCx0Es/lLsrjnA== + eslint-plugin-react@^7.13.0: version "7.13.0" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.13.0.tgz#bc13fd7101de67996ea51b33873cd9dc2b7e5758"