)}
- {items.map(item => (
-
onChange(item)}
- >
-
- onChange(item)}
- name={item.name}
- value={item.value}
- />
-
-
- ))}
+ {items.map(headerName => {
+ const value = displayedHeaders.findIndex(({ name }) => name === headerName) !== -1;
+ const handleChange = () => onChange({ name: headerName, value });
+
+ return (
+
+
+
+
+
+ );
+ })}
@@ -77,12 +80,11 @@ const DisplayedFieldsDropdown = ({
};
DisplayedFieldsDropdown.propTypes = {
- isOpen: PropTypes.bool.isRequired,
+ displayedHeaders: PropTypes.array.isRequired,
items: PropTypes.array.isRequired,
onChange: PropTypes.func.isRequired,
onClickReset: PropTypes.func.isRequired,
slug: PropTypes.string.isRequired,
- toggle: PropTypes.func.isRequired,
};
-export default DisplayedFieldsDropdown;
+export default memo(DisplayedFieldsDropdown);
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 c61c781b94..69ffbeeb9e 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
@@ -3,10 +3,17 @@ import {
GET_DATA_SUCCEEDED,
ON_CHANGE_BULK,
ON_CHANGE_BULK_SELECT_ALL,
+ //
+ ON_CHANGE_LIST_HEADERS,
+ ON_RESET_LIST_HEADERS,
+ //
ON_DELETE_DATA_ERROR,
ON_DELETE_DATA_SUCCEEDED,
ON_DELETE_SEVERAL_DATA_SUCCEEDED,
RESET_PROPS,
+ //
+ SET_LIST_LAYOUT,
+ //
SET_MODAL_LOADING_STATE,
TOGGLE_MODAL_DELETE,
TOGGLE_MODAL_DELETE_ALL,
@@ -57,6 +64,8 @@ export function onDeleteSeveralDataSucceeded() {
};
}
+export const onResetListHeaders = () => ({ type: ON_RESET_LIST_HEADERS });
+
export function resetProps() {
return { type: RESET_PROPS };
}
@@ -78,3 +87,7 @@ export function toggleModalDelete() {
type: TOGGLE_MODAL_DELETE,
};
}
+
+export const setLayout = layout => ({ layout, type: SET_LIST_LAYOUT });
+
+export const onChangeListHeaders = target => ({ type: ON_CHANGE_LIST_HEADERS, target });
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 bba1d0f742..1a60f4a514 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
@@ -10,3 +10,7 @@ export const RESET_PROPS = 'ContentManager/ListView/RESET_PROPS';
export const TOGGLE_MODAL_DELETE_ALL = 'ContentManager/ListView/TOGGLE_MODAL_DELETE_ALL';
export const TOGGLE_MODAL_DELETE = 'ContentManager/ListView/TOGGLE_MODAL_DELETE';
export const SET_MODAL_LOADING_STATE = 'ContentManager/ListView/SET_MODAL_LOADING_STATE';
+
+export const ON_CHANGE_LIST_HEADERS = 'ContentManager/ListView/ON_CHANGE_LIST_HEADERS ';
+export const ON_RESET_LIST_HEADERS = 'ContentManager/ListView/ON_RESET_LIST_HEADERS ';
+export const SET_LIST_LAYOUT = 'ContentManager/ListView/SET_LIST_LAYOUT ';
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 a3b5e8fcfb..e0fda77a2c 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
@@ -2,7 +2,7 @@ import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from '
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { bindActionCreators, compose } from 'redux';
-import { get, isEmpty, sortBy } from 'lodash';
+import { get, isEmpty } from 'lodash';
import { FormattedMessage, useIntl } from 'react-intl';
import { useHistory, useLocation } from 'react-router-dom';
import { Header } from '@buffetjs/custom';
@@ -17,12 +17,7 @@ import {
} from 'strapi-helper-plugin';
import pluginId from '../../pluginId';
import pluginPermissions from '../../permissions';
-import {
- checkIfAttributeIsDisplayable,
- generatePermissionsObject,
- getRequestUrl,
- getTrad,
-} from '../../utils';
+import { generatePermissionsObject, getRequestUrl, getTrad } from '../../utils';
import DisplayedFieldsDropdown from '../../components/DisplayedFieldsDropdown';
import Container from '../../components/Container';
@@ -30,9 +25,7 @@ import CustomTable from '../../components/CustomTable';
// import FilterPicker from '../../components/FilterPicker';
import Search from '../../components/Search';
-import State from '../../components/State';
import ListViewProvider from '../ListViewProvider';
-// import { onChangeListLabels, resetListLabels } from '../Main/actions';
import { AddFilterCta, FilterIcon, Wrapper } from './components';
import Filter from './Filter';
import Footer from './Footer';
@@ -48,35 +41,36 @@ import {
setModalLoadingState,
toggleModalDelete,
toggleModalDeleteAll,
+ //
+ setLayout,
+ onChangeListHeaders,
+ onResetListHeaders,
} from './actions';
-
import makeSelectListView from './selectors';
+import { getAllAllowedHeaders, getFirstSortableHeader } from './utils';
+
/* eslint-disable react/no-array-index-key */
const FilterPicker = () =>
FILTER
;
-const onChangeListLabels = () => console.log('todo');
-const resetListLabels = () => console.log('todo');
function ListView({
count,
data,
didDeleteData,
- // emitEvent,
+
entriesToDelete,
isLoading,
// location: { pathname },
getData,
getDataSucceeded,
- layouts,
- // history: { push },
+
onChangeBulk,
onChangeBulkSelectall,
- onChangeListLabels,
onDeleteDataError,
onDeleteDataSucceeded,
onDeleteSeveralDataSucceeded,
- resetListLabels,
+
resetProps,
setModalLoadingState,
showWarningDelete,
@@ -87,7 +81,12 @@ function ListView({
toggleModalDeleteAll,
// NEW
+ // allAllowedHeaders,
+ displayedHeaders,
layout,
+ onChangeListHeaders,
+ onResetListHeaders,
+ setLayout,
}) {
const { emitEvent } = useGlobalContext();
const viewPermissions = useMemo(() => generatePermissionsObject(slug), [slug]);
@@ -101,36 +100,29 @@ function ListView({
const isFirstRender = useRef(true);
const { formatMessage } = useIntl();
- const [isLabelPickerOpen, setLabelPickerState] = useState(false);
+
const [isFilterPickerOpen, setFilterPickerState] = useState(false);
const [idToDelete, setIdToDelete] = useState(null);
- console.log({ layout });
-
const contentType = layout.contentType;
const {
- defaultSortBy,
- defaultSortOrder,
- bulkable: isBulkable,
- filterable: isFilterable,
- searchable: isSearchable,
- pageSize,
- // mainField,
- } = contentType.settings;
+ contentType: {
+ attributes,
+ settings: {
+ defaultSortBy,
+ defaultSortOrder,
+ bulkable: isBulkable,
+ filterable: isFilterable,
+ searchable: isSearchable,
+ pageSize,
+ // mainField,
+ },
+ },
+ } = layout;
+
const hasDraftAndPublish = contentType.options.draftAndPublish;
const defaultSort = `${defaultSortBy}:${defaultSortOrder}`;
- const listLayout = contentType.layouts.list;
-
- console.log({ isBulkable });
-
- const contentTypePath = useMemo(() => {
- return [slug, 'contentType'];
- }, [slug]);
-
- // Related to the search
- // const defaultSort = useMemo(() => {
- // return `${getLayoutSetting('defaultSortBy')}:${getLayoutSetting('defaultSortOrder')}`;
- // }, [getLayoutSetting]);
+ const allAllowedHeaders = getAllAllowedHeaders(attributes);
const filters = useMemo(() => {
const currentSearch = new URLSearchParams(search);
@@ -157,6 +149,7 @@ function ListView({
// TODO
const _sort = query.get('_sort') || defaultSort;
+ const label = contentType.info.label;
const _start = useMemo(() => {
return (_page - 1) * parseInt(_limit, 10);
@@ -182,94 +175,70 @@ function ListView({
const fetchData = async (search = searchToSendForRequest) => {
try {
- getDataActionRef.current();
- const [{ count }, data] = await Promise.all([
- request(getRequestUrl(`explorer/${slug}/count?${search}`), {
- method: 'GET',
- }),
- request(getRequestUrl(`explorer/${slug}?${search}`), {
- method: 'GET',
- }),
- ]);
+ // getDataActionRef.current();
+ // const [{ count }, data] = await Promise.all([
+ // request(getRequestUrl(`explorer/${slug}/count?${search}`), {
+ // method: 'GET',
+ // }),
+ // request(getRequestUrl(`explorer/${slug}?${search}`), {
+ // method: 'GET',
+ // }),
+ // ]);
- getDataSucceededRef.current(count, data);
+ // const c = await request(getRequestUrl(`collection-types/${slug}?${search}`));
+ // console.log({ c });
+ const data = [
+ {
+ id: 16,
+ postal_coder: 'kkkk',
+ city: 'kljkojihv',
+ created_by: {
+ id: 1,
+ firstname: 'cyril',
+ lastname: 'lopez',
+ username: null,
+ email: 'cyril@strapi.io',
+ resetPasswordToken: null,
+ registrationToken: null,
+ isActive: true,
+ blocked: null,
+ },
+ updated_by: {
+ id: 1,
+ firstname: 'cyril',
+ lastname: 'lopez',
+ username: null,
+ email: 'cyril@strapi.io',
+ resetPasswordToken: null,
+ registrationToken: null,
+ isActive: true,
+ blocked: null,
+ },
+ created_at: '2020-10-28T09:03:20.905Z',
+ updated_at: '2020-10-28T13:51:35.381Z',
+ published_at: '2020-10-28T13:51:35.351Z',
+ cover: null,
+ images: [],
+ categories: [],
+ likes: [],
+ },
+ ];
+
+ getDataSucceededRef.current(1, data);
} catch (err) {
strapi.notification.error(`${pluginId}.error.model.fetch`);
}
};
- const getMetaDatas = useCallback(
- (path = []) => {
- return get(layouts, [...contentTypePath, 'metadatas', ...path], {});
- },
- [contentTypePath, layouts]
- );
+ useEffect(() => {
+ // TODO
+ console.log('up');
+ setLayout(layout);
+ }, [layout, setLayout]);
- // const listLayout = useMemo(() => {
- // return get(layouts, [...contentTypePath, 'layouts', 'list'], []);
- // }, [contentTypePath, layouts]);
-
- const listSchema = useMemo(() => {
- return get(layouts, [...contentTypePath, 'schema'], {});
- }, [layouts, contentTypePath]);
-
- const label = useMemo(() => {
- return get(listSchema, ['info', 'name'], '');
- }, [listSchema]);
-
- // TODO
- const tableHeaders = useMemo(() => {
- return listLayout;
- // let headers = listLayout.map(label => {
- // return { ...getMetaDatas([label, 'list']), name: label };
- // });
-
- // if (hasDraftAndPublish) {
- // headers.push({
- // label: formatMessage({ id: getTrad('containers.ListPage.table-headers.published_at') }),
- // searchable: false,
- // sortable: true,
- // name: 'published_at',
- // key: '__published_at__',
- // cellFormatter: cellData => {
- // const isPublished = !isEmpty(cellData.published_at);
-
- // return
;
- // },
- // });
- // }
-
- // return headers;
- }, [formatMessage, getMetaDatas, hasDraftAndPublish, listLayout]);
-
- const getFirstSortableElement = useCallback(
- (name = '') => {
- return get(
- listLayout.filter(h => {
- return h !== name && getMetaDatas([h, 'list', 'sortable']) === true;
- }),
- ['0'],
- 'id'
- );
- },
- [getMetaDatas, listLayout]
- );
-
- const allLabels = useMemo(() => {
- const filteredMetadatas = getMetaDatas();
-
- return sortBy(
- Object.keys(filteredMetadatas)
- .filter(key => {
- return checkIfAttributeIsDisplayable(get(listSchema, ['attributes', key], {}));
- })
- .map(label => ({
- name: label,
- value: listLayout.includes(label),
- })),
- ['label', 'name']
- );
- }, [getMetaDatas, listLayout, listSchema]);
+ const firstSortableHeader = useMemo(() => getFirstSortableHeader(displayedHeaders), [
+ displayedHeaders,
+ ]);
useEffect(() => {
return () => {
@@ -358,36 +327,32 @@ function ListView({
}
}, [entriesToDelete, onDeleteSeveralDataSucceeded, slug, setModalLoadingState]);
- const handleChangeListLabels = ({ name, value }) => {
- const currentSort = _sort;
+ const handleChangeListLabels = useCallback(
+ ({ name, value }) => {
+ // const currentSort = _sort;
+ // // Display a notification if trying to remove the last displayed field
+ if (value && displayedHeaders.length === 1) {
+ strapi.notification.error('content-manager.notification.error.displayedFields');
- // Display a notification if trying to remove the last displayed field
- if (value && listLayout.length === 1) {
- strapi.notification.error('content-manager.notification.error.displayedFields');
+ return false;
+ }
- return;
- }
+ // TODO
+ // // Update the sort when removing the displayed one
+ // if (currentSort.split(':')[0] === name && value) {
+ // emitEvent('didChangeDisplayedFields');
+ // handleChangeSearch({
+ // target: {
+ // name: '_sort',
+ // value: `${firstSortableHeader}:ASC`,
+ // },
+ // });
+ // }
- // Update the sort when removing the displayed one
- if (currentSort.split(':')[0] === name && value) {
- emitEvent('didChangeDisplayedFields');
- handleChangeSearch({
- target: {
- name: '_sort',
- value: `${getFirstSortableElement(name)}:ASC`,
- },
- });
- }
-
- // Update the Main reducer
- onChangeListLabels({
- target: {
- name,
- slug,
- value: !value,
- },
- });
- };
+ onChangeListHeaders({ name, value });
+ },
+ [displayedHeaders, onChangeListHeaders]
+ );
const handleChangeFilters = ({ target: { value } }) => {
const newSearch = new URLSearchParams();
@@ -449,14 +414,6 @@ function ListView({
setFilterPickerState(prevState => !prevState);
};
- const toggleLabelPickerState = () => {
- if (!isLabelPickerOpen) {
- emitEvent('willChangeListFieldsSettings');
- }
-
- setLabelPickerState(prevState => !prevState);
- };
-
const filterPickerActions = [
{
label: `${pluginId}.components.FiltersPickWrapper.PluginHeader.actions.clearAll`,
@@ -533,7 +490,6 @@ function ListView({
actions: headerAction,
};
/* eslint-enable indent */
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [count, headerAction, label, canRead, formatMessage]);
return (
@@ -543,13 +499,13 @@ function ListView({
count={count}
entriesToDelete={entriesToDelete}
emitEvent={emitEvent}
- firstSortableElement={getFirstSortableElement()}
label={label}
onChangeBulk={onChangeBulk}
onChangeBulkSelectall={onChangeBulkSelectall}
onChangeSearch={handleChangeSearch}
onClickDelete={handleClickDelete}
- schema={listSchema}
+ // schema={listSchema}
+ schema={{}}
slug={slug}
toggleModalDeleteAll={toggleModalDeleteAll}
_limit={_limit}
@@ -557,6 +513,8 @@ function ListView({
filters={filters}
_q={_q}
_sort={_sort}
+ // to keep
+ firstSortableHeader={firstSortableHeader}
>
{
- resetListLabels(slug);
- }}
+ onClickReset={onResetListHeaders}
slug={slug}
- toggle={toggleLabelPickerState}
/>
@@ -618,7 +574,8 @@ function ListView({
data={data}
canDelete={canDelete}
canUpdate={canUpdate}
- headers={tableHeaders}
+ displayedHeaders={displayedHeaders}
+ hasDraftAndPublish={hasDraftAndPublish}
isBulkable={isBulkable}
onChangeParams={handleChangeSearch}
showLoader={isLoading}
@@ -664,9 +621,16 @@ ListView.defaultProps = {
};
ListView.propTypes = {
+ // allAllowedHeaders: PropTypes.array.isRequired,
+ displayedHeaders: PropTypes.array.isRequired,
layout: PropTypes.exact({
components: PropTypes.object.isRequired,
contentType: PropTypes.shape({
+ attributes: PropTypes.object.isRequired,
+ info: PropTypes.shape({ label: PropTypes.string.isRequired }).isRequired,
+ layouts: PropTypes.shape({
+ list: PropTypes.array.isRequired,
+ }).isRequired,
options: PropTypes.object.isRequired,
settings: PropTypes.object.isRequired,
}).isRequired,
@@ -690,11 +654,11 @@ ListView.propTypes = {
// }).isRequired,
// onChangeBulk: PropTypes.func.isRequired,
// onChangeBulkSelectall: PropTypes.func.isRequired,
- // onChangeListLabels: PropTypes.func.isRequired,
+ onChangeListHeaders: PropTypes.func.isRequired,
// onDeleteDataError: PropTypes.func.isRequired,
// onDeleteDataSucceeded: PropTypes.func.isRequired,
// onDeleteSeveralDataSucceeded: PropTypes.func.isRequired,
- // resetListLabels: PropTypes.func.isRequired,
+ onResetListHeaders: PropTypes.func.isRequired,
// resetProps: PropTypes.func.isRequired,
// setModalLoadingState: PropTypes.func.isRequired,
// showModalConfirmButtonLoading: PropTypes.bool.isRequired,
@@ -703,6 +667,7 @@ ListView.propTypes = {
// slug: PropTypes.string.isRequired,
// toggleModalDelete: PropTypes.func.isRequired,
// toggleModalDeleteAll: PropTypes.func.isRequired,
+ setLayout: PropTypes.func.isRequired,
};
const mapStateToProps = makeSelectListView();
@@ -714,15 +679,16 @@ export function mapDispatchToProps(dispatch) {
getDataSucceeded,
onChangeBulk,
onChangeBulkSelectall,
- onChangeListLabels,
+ onChangeListHeaders,
onDeleteDataError,
onDeleteDataSucceeded,
onDeleteSeveralDataSucceeded,
- resetListLabels,
+ onResetListHeaders,
resetProps,
setModalLoadingState,
toggleModalDelete,
toggleModalDeleteAll,
+ setLayout,
},
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 7bec9e4a29..e35e7f25a4 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
@@ -15,6 +15,11 @@ import {
ON_DELETE_SEVERAL_DATA_SUCCEEDED,
TOGGLE_MODAL_DELETE,
TOGGLE_MODAL_DELETE_ALL,
+ //
+ ON_CHANGE_LIST_HEADERS,
+ ON_RESET_LIST_HEADERS,
+ SET_LIST_LAYOUT,
+ //
SET_MODAL_LOADING_STATE,
} from './constants';
@@ -27,6 +32,11 @@ export const initialState = {
showModalConfirmButtonLoading: false,
showWarningDelete: false,
showWarningDeleteAll: false,
+ //
+
+ contentType: {},
+ initialDisplayedHeaders: [],
+ displayedHeaders: [],
};
const listViewReducer = (state = initialState, action) =>
@@ -66,6 +76,27 @@ const listViewReducer = (state = initialState, action) =>
break;
}
+ case ON_CHANGE_LIST_HEADERS: {
+ const {
+ target: { name, value },
+ } = action;
+
+ if (!value) {
+ const { metadatas, attributes } = state.contentType;
+ drafState.displayedHeaders.push({
+ name,
+ fieldSchema: attributes[name],
+ metadatas: metadatas[name].list,
+ key: `__${name}_key__`,
+ });
+ } else {
+ drafState.displayedHeaders = state.displayedHeaders.filter(
+ header => header.name !== name
+ );
+ }
+
+ break;
+ }
case ON_DELETE_DATA_SUCCEEDED: {
drafState.didDeleteData = true;
drafState.showWarningDelete = false;
@@ -81,6 +112,10 @@ const listViewReducer = (state = initialState, action) =>
drafState.showWarningDeleteAll = false;
break;
}
+ case ON_RESET_LIST_HEADERS: {
+ drafState.displayedHeaders = state.initialDisplayedHeaders;
+ break;
+ }
case RESET_PROPS: {
return initialState;
}
@@ -113,6 +148,15 @@ const listViewReducer = (state = initialState, action) =>
break;
}
+ case SET_LIST_LAYOUT: {
+ const { contentType } = action.layout;
+
+ drafState.contentType = contentType;
+ drafState.displayedHeaders = contentType.layouts.list;
+ drafState.initialDisplayedHeaders = contentType.layouts.list;
+
+ break;
+ }
default:
return drafState;
diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/ListView/utils/getAllAllowedHeaders.js b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/utils/getAllAllowedHeaders.js
new file mode 100644
index 0000000000..5150097d4f
--- /dev/null
+++ b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/utils/getAllAllowedHeaders.js
@@ -0,0 +1,18 @@
+import { sortBy } from 'lodash';
+import { checkIfAttributeIsDisplayable } from '../../../utils';
+
+const getAllAllowedHeaders = attributes => {
+ const allowedAttributes = Object.keys(attributes).reduce((acc, current) => {
+ const attribute = attributes[current];
+
+ if (checkIfAttributeIsDisplayable(attribute)) {
+ acc.push(current);
+ }
+
+ return acc;
+ }, []);
+
+ return sortBy(allowedAttributes, ['name']);
+};
+
+export default getAllAllowedHeaders;
diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/ListView/utils/getFirstSortableHeader.js b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/utils/getFirstSortableHeader.js
new file mode 100644
index 0000000000..ec0a1d11ec
--- /dev/null
+++ b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/utils/getFirstSortableHeader.js
@@ -0,0 +1,9 @@
+import { get } from 'lodash';
+
+const getFirstSortableHeader = headers => {
+ const matched = headers.find(header => header.metadatas.sortable === true);
+
+ return get(matched, 'name', 'id');
+};
+
+export default getFirstSortableHeader;
diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/ListView/utils/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/utils/index.js
new file mode 100644
index 0000000000..7c5cfa3bd8
--- /dev/null
+++ b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/utils/index.js
@@ -0,0 +1,2 @@
+export { default as getAllAllowedHeaders } from './getAllAllowedHeaders';
+export { default as getFirstSortableHeader } from './getFirstSortableHeader';
diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/ListView/utils/tests/getFirstSortableHeader.test.js b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/utils/tests/getFirstSortableHeader.test.js
new file mode 100644
index 0000000000..d5d61be394
--- /dev/null
+++ b/packages/strapi-plugin-content-manager/admin/src/containers/ListView/utils/tests/getFirstSortableHeader.test.js
@@ -0,0 +1,26 @@
+import getFirstSortableHeader from '../getFirstSortableHeader';
+
+describe('CONTENT MANAGER | containers | ListView | utils | getFirstSortableHeader', () => {
+ it('should return id if the array is empty', () => {
+ expect(getFirstSortableHeader([])).toEqual('id');
+ });
+
+ it('should return the first sortable element', () => {
+ const headers = [
+ {
+ name: 'un',
+ metadatas: { sortable: false },
+ },
+ {
+ name: 'two',
+ metadatas: { sortable: true },
+ },
+ {
+ name: 'three',
+ metadatas: { sortable: true },
+ },
+ ];
+
+ expect(getFirstSortableHeader(headers)).toBe('two');
+ });
+});
diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/Main/actions.js b/packages/strapi-plugin-content-manager/admin/src/containers/Main/actions.js
index 7a7d934111..c416f9cd1d 100644
--- a/packages/strapi-plugin-content-manager/admin/src/containers/Main/actions.js
+++ b/packages/strapi-plugin-content-manager/admin/src/containers/Main/actions.js
@@ -1,66 +1,4 @@
-import {
- // DELETE_LAYOUT,
- // DELETE_LAYOUTS,
- GET_DATA,
- GET_DATA_SUCCEEDED,
- // GET_LAYOUT_SUCCEEDED,
- // ON_CHANGE_LIST_LABELS,
- // RESET_LIST_LABELS,
- RESET_PROPS,
-} from './constants';
-
-// export function deleteLayout(uid) {
-// return {
-// type: DELETE_LAYOUT,
-// uid,
-// };
-// }
-
-// export function deleteLayouts() {
-// return {
-// type: DELETE_LAYOUTS,
-// };
-// }
-
-// export function getDataSucceeded(components, models, mainFields) {
-// 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,
-// };
-// }
-//
+import { GET_DATA, GET_DATA_SUCCEEDED, RESET_PROPS } from './constants';
export const getData = () => ({
type: GET_DATA,
diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/Main/constants.js b/packages/strapi-plugin-content-manager/admin/src/containers/Main/constants.js
index 92672bfc5d..47237d155d 100644
--- a/packages/strapi-plugin-content-manager/admin/src/containers/Main/constants.js
+++ b/packages/strapi-plugin-content-manager/admin/src/containers/Main/constants.js
@@ -1,9 +1,3 @@
export const GET_DATA = 'ContentManager/Main/GET_DATA';
export const GET_DATA_SUCCEEDED = 'ContentManager/Main/GET_DATA_SUCCEEDED';
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';
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 52b30da2f0..36c26cce36 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
@@ -4,17 +4,7 @@
*/
/* eslint-disable consistent-return */
import produce from 'immer';
-import {
- // DELETE_LAYOUT,
- // DELETE_LAYOUTS,
- GET_DATA,
- GET_DATA_SUCCEEDED,
- // GET_LAYOUT_SUCCEEDED,
- // ON_CHANGE_LIST_LABELS,
- // RESET_LIST_LABELS,
- RESET_PROPS,
-} from './constants';
-// import { fromJS } from 'immutable';
+import { GET_DATA, GET_DATA_SUCCEEDED, RESET_PROPS } from './constants';
const initialState = {
// TODO!
@@ -47,52 +37,5 @@ const mainReducer = (state = initialState, action) =>
}
});
-// export const initialState = fromJS({
-// componentsAndModelsMainPossibleMainFields: {},
-// components: [],
-// initialLayouts: {},
-// isLoading: true,
-// layouts: {},
-// models: [],
-// });
-
-// function mainReducer(state = initialState, action) {
-// switch (action.type) {
-// case DELETE_LAYOUT:
-// return state.removeIn(['layouts', action.uid]);
-// 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 state.updateIn(['layouts', slug, 'contentType', 'layouts', 'list'], list => {
-// if (value) {
-// return list.push(name);
-// }
-
-// return list.filter(l => l !== name);
-// });
-// }
-// case RESET_LIST_LABELS:
-// return state.updateIn(['layouts', action.slug], () =>
-// state.getIn(['initialLayouts', action.slug])
-// );
-// case RESET_PROPS:
-// return initialState;
-// default:
-// return state;
-// }
-// }
-
export default mainReducer;
export { initialState };
diff --git a/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/index.js b/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/index.js
index f331f2e827..90b3fdf3f8 100644
--- a/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/index.js
+++ b/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/index.js
@@ -1,4 +1,4 @@
-import { useCallback, useEffect, useMemo, useReducer } from 'react';
+import { useCallback, useEffect, useMemo, useReducer, useRef } from 'react';
import { useSelector } from 'react-redux';
import { request } from 'strapi-helper-plugin';
import formatLayouts from './utils/formatLayouts';
@@ -9,6 +9,7 @@ const useFetchContentTypeLayout = contentTypeUID => {
const [{ error, isLoading, layout, layouts }, dispatch] = useReducer(reducer, initialState);
const schemasSelector = useMemo(makeSelectModelAndComponentSchemas, []);
const { schemas } = useSelector(state => schemasSelector(state), []);
+ const isMounted = useRef(true);
const getData = useCallback(
async (uid, abortSignal = false) => {
@@ -33,13 +34,20 @@ const useFetchContentTypeLayout = contentTypeUID => {
data: formatLayouts(data, schemas),
});
} catch (error) {
- console.error(error);
- dispatch({ type: 'GET_DATA_ERROR', error });
+ if (isMounted.current && error.name !== 'AbortError') {
+ dispatch({ type: 'GET_DATA_ERROR', error });
+ }
}
},
[schemas, layouts]
);
+ useEffect(() => {
+ return () => {
+ isMounted.current = false;
+ };
+ }, []);
+
useEffect(() => {
const abortController = new AbortController();
const { signal } = abortController;
diff --git a/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/reducer.js b/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/reducer.js
index 6d0e6c48c6..fce858d1d8 100644
--- a/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/reducer.js
+++ b/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/reducer.js
@@ -20,9 +20,9 @@ const reducer = (state, action) =>
case 'GET_DATA_SUCCEEDED': {
const contentTypeUid = action.data.contentType.uid;
- draftState.isLoading = false;
draftState.layout = action.data;
draftState.layouts[contentTypeUid] = action.data;
+ draftState.isLoading = false;
break;
}
case 'GET_DATA_ERROR': {
diff --git a/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/formatLayouts.js b/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/formatLayouts.js
index bd288559f9..9803481f2b 100644
--- a/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/formatLayouts.js
+++ b/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/formatLayouts.js
@@ -94,7 +94,7 @@ const formatListLayoutWithMetas = obj => {
const fieldSchema = get(obj, ['attributes', current], {});
const metadatas = get(obj, ['metadatas', current, 'list'], {});
- acc.push({ name: current, fieldSchema, metadatas });
+ acc.push({ key: `__${current}_key__`, name: current, fieldSchema, metadatas });
return acc;
}, []);