mirror of
https://github.com/strapi/strapi.git
synced 2025-09-25 16:29:34 +00:00
Changed displayed headers behaviour, simplify main reducer
Signed-off-by: soupette <cyril.lpz@gmail.com>
This commit is contained in:
parent
78534fca2e
commit
5792cfeea8
@ -1,6 +1,6 @@
|
||||
module.exports = ({ env }) => ({
|
||||
host: env('HOST', '0.0.0.0'),
|
||||
port: env.int('PORT', 1337),
|
||||
port: env.int('PORT', 3000),
|
||||
admin: {
|
||||
auth: {
|
||||
secret: env('ADMIN_JWT_SECRET', 'example-token'),
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { memo, useCallback } from 'react';
|
||||
import React, { memo, useCallback, useRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { get, isEmpty, isNull, isObject, toLower, toString } from 'lodash';
|
||||
import moment from 'moment';
|
||||
@ -67,26 +67,17 @@ const getDisplayedValue = (type, value, name) => {
|
||||
};
|
||||
|
||||
function Row({ canDelete, canUpdate, isBulkable, row, headers }) {
|
||||
const { entriesToDelete, onChangeBulk, onClickDelete, schema } = useListView();
|
||||
const { entriesToDelete, onChangeBulk, onClickDelete } = useListView();
|
||||
const { emitEvent } = useGlobalContext();
|
||||
const emitEventRef = useRef(emitEvent);
|
||||
|
||||
const memoizedDisplayedValue = useCallback(
|
||||
name => {
|
||||
const type = get(schema, ['attributes', name, 'type'], 'string');
|
||||
|
||||
(name, type) => {
|
||||
return getDisplayedValue(type, row[name], name);
|
||||
},
|
||||
[row, schema]
|
||||
[row]
|
||||
);
|
||||
|
||||
const isMedia = useCallback(
|
||||
header => {
|
||||
return get(schema, ['attributes', header.name, 'type']) === 'media';
|
||||
},
|
||||
[schema]
|
||||
);
|
||||
|
||||
const { emitEvent } = useGlobalContext();
|
||||
|
||||
const links = [
|
||||
{
|
||||
icon: canUpdate ? <FontAwesomeIcon icon="pencil-alt" /> : null,
|
||||
@ -95,7 +86,7 @@ function Row({ canDelete, canUpdate, isBulkable, row, headers }) {
|
||||
icon: canDelete ? <FontAwesomeIcon icon="trash-alt" /> : null,
|
||||
onClick: e => {
|
||||
e.stopPropagation();
|
||||
emitEvent('willDeleteEntryFromList');
|
||||
emitEventRef.current('willDeleteEntryFromList');
|
||||
onClickDelete(row.id);
|
||||
},
|
||||
},
|
||||
@ -113,14 +104,16 @@ function Row({ canDelete, canUpdate, isBulkable, row, headers }) {
|
||||
/>
|
||||
</td>
|
||||
)}
|
||||
{headers.map(header => {
|
||||
{headers.map(({ key, name, fieldSchema: { type }, cellFormatter }) => {
|
||||
const isMedia = type === 'media';
|
||||
|
||||
return (
|
||||
<td key={header.key || header.name}>
|
||||
{isMedia(header) && <MediaPreviewList files={memoizedDisplayedValue(header.name)} />}
|
||||
{header.cellFormatter && header.cellFormatter(row)}
|
||||
{!isMedia(header) && !header.cellFormatter && (
|
||||
<td key={key}>
|
||||
{isMedia && <MediaPreviewList files={memoizedDisplayedValue(name, type)} />}
|
||||
{cellFormatter && cellFormatter(row)}
|
||||
{!isMedia && !cellFormatter && (
|
||||
<Truncate>
|
||||
<Truncated>{memoizedDisplayedValue(header.name)}</Truncated>
|
||||
<Truncated>{memoizedDisplayedValue(name, type)}</Truncated>
|
||||
</Truncate>
|
||||
)}
|
||||
</td>
|
||||
|
@ -1,7 +1,8 @@
|
||||
import React, { memo } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useGlobalContext } from 'strapi-helper-plugin';
|
||||
import useListView from '../../hooks/useListView';
|
||||
import { useListView } from '../../hooks';
|
||||
|
||||
import CustomInputCheckbox from '../CustomInputCheckbox';
|
||||
import { Arrow, Thead } from './styledComponents';
|
||||
|
||||
@ -11,10 +12,11 @@ function TableHeader({ headers, isBulkable }) {
|
||||
const {
|
||||
data,
|
||||
entriesToDelete,
|
||||
firstSortableElement,
|
||||
onChangeBulkSelectall,
|
||||
onChangeSearch,
|
||||
_sort,
|
||||
// to keep
|
||||
firstSortableHeader,
|
||||
} = useListView();
|
||||
const { emitEvent } = useGlobalContext();
|
||||
const [sortBy, sortOrder] = _sort.split(':');
|
||||
@ -33,19 +35,19 @@ function TableHeader({ headers, isBulkable }) {
|
||||
/>
|
||||
</th>
|
||||
)}
|
||||
{headers.map(header => {
|
||||
{headers.map(({ key, name, metadatas: { label, sortable } }) => {
|
||||
return (
|
||||
<th
|
||||
key={header.key || header.name}
|
||||
key={key}
|
||||
onClick={() => {
|
||||
if (header.sortable) {
|
||||
if (sortable) {
|
||||
emitEvent('didSortEntries');
|
||||
const isCurrentSort = header.name === sortBy;
|
||||
const isCurrentSort = name === sortBy;
|
||||
const nextOrder = isCurrentSort && sortOrder === 'ASC' ? 'DESC' : 'ASC';
|
||||
let value = `${header.name}:${nextOrder}`;
|
||||
let value = `${name}:${nextOrder}`;
|
||||
|
||||
if (isCurrentSort && sortOrder === 'DESC') {
|
||||
value = `${firstSortableElement}:ASC`;
|
||||
value = `${firstSortableHeader}:ASC`;
|
||||
}
|
||||
|
||||
onChangeSearch({
|
||||
@ -57,12 +59,10 @@ function TableHeader({ headers, isBulkable }) {
|
||||
}
|
||||
}}
|
||||
>
|
||||
<span className={header.sortable ? 'sortable' : ''}>
|
||||
{header.label}
|
||||
<span className={sortable ? 'sortable' : ''}>
|
||||
{label}
|
||||
|
||||
{sortBy === header.name && (
|
||||
<Arrow fill="#212529" isUp={sortOrder === 'ASC' && 'isAsc'} />
|
||||
)}
|
||||
{sortBy === name && <Arrow fill="#212529" isUp={sortOrder === 'ASC' && 'isAsc'} />}
|
||||
</span>
|
||||
</th>
|
||||
);
|
||||
|
@ -1,19 +1,55 @@
|
||||
import React, { memo } from 'react';
|
||||
import React, { memo, useMemo } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useLocation, useHistory } from 'react-router-dom';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { upperFirst } from 'lodash';
|
||||
import { LoadingIndicator } from 'strapi-helper-plugin';
|
||||
import { FormattedMessage, useIntl } from 'react-intl';
|
||||
import { upperFirst, isEmpty } from 'lodash';
|
||||
import { LoadingIndicator, useGlobalContext } from 'strapi-helper-plugin';
|
||||
import useListView from '../../hooks/useListView';
|
||||
import { getTrad } from '../../utils';
|
||||
import State from '../State';
|
||||
import TableHeader from './TableHeader';
|
||||
import { LoadingContainer, LoadingWrapper, Table, TableEmpty, TableRow } from './styledComponents';
|
||||
import ActionCollapse from './ActionCollapse';
|
||||
import Row from './Row';
|
||||
|
||||
const CustomTable = ({ canUpdate, canDelete, data, headers, isBulkable, showLoader }) => {
|
||||
const { emitEvent, entriesToDelete, label, filters, _q } = useListView();
|
||||
const CustomTable = ({
|
||||
canUpdate,
|
||||
canDelete,
|
||||
data,
|
||||
displayedHeaders,
|
||||
hasDraftAndPublish,
|
||||
isBulkable,
|
||||
showLoader,
|
||||
}) => {
|
||||
const { formatMessage } = useIntl();
|
||||
const { entriesToDelete, label, filters, _q } = useListView();
|
||||
const { emitEvent } = useGlobalContext();
|
||||
const { pathname } = useLocation();
|
||||
const { push } = useHistory();
|
||||
const headers = useMemo(() => {
|
||||
if (hasDraftAndPublish) {
|
||||
return [
|
||||
...displayedHeaders,
|
||||
{
|
||||
key: '__published_at_temp_key__',
|
||||
name: 'published_at',
|
||||
fieldSchema: {},
|
||||
metadatas: {
|
||||
label: formatMessage({ id: getTrad('containers.ListPage.table-headers.published_at') }),
|
||||
searchable: false,
|
||||
sortable: true,
|
||||
},
|
||||
cellFormatter: cellData => {
|
||||
const isPublished = !isEmpty(cellData.published_at);
|
||||
|
||||
return <State isPublished={isPublished} />;
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
return displayedHeaders;
|
||||
}, [formatMessage, hasDraftAndPublish, displayedHeaders]);
|
||||
|
||||
const colSpanLength = isBulkable && canDelete ? headers.length + 2 : headers.length + 1;
|
||||
|
||||
@ -93,22 +129,14 @@ const CustomTable = ({ canUpdate, canDelete, data, headers, isBulkable, showLoad
|
||||
);
|
||||
};
|
||||
|
||||
CustomTable.defaultProps = {
|
||||
canDelete: false,
|
||||
canUpdate: false,
|
||||
data: [],
|
||||
headers: [],
|
||||
isBulkable: true,
|
||||
showLoader: false,
|
||||
};
|
||||
|
||||
CustomTable.propTypes = {
|
||||
canDelete: PropTypes.bool,
|
||||
canUpdate: PropTypes.bool,
|
||||
data: PropTypes.array,
|
||||
headers: PropTypes.array,
|
||||
isBulkable: PropTypes.bool,
|
||||
showLoader: PropTypes.bool,
|
||||
canDelete: PropTypes.bool.isRequired,
|
||||
canUpdate: PropTypes.bool.isRequired,
|
||||
data: PropTypes.array.isRequired,
|
||||
displayedHeaders: PropTypes.array.isRequired,
|
||||
hasDraftAndPublish: PropTypes.bool.isRequired,
|
||||
isBulkable: PropTypes.bool.isRequired,
|
||||
showLoader: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default memo(CustomTable);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { memo, useCallback, useRef, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ButtonDropdown } from 'reactstrap';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
@ -13,15 +13,23 @@ import LayoutWrapper from './LayoutWrapper';
|
||||
import MenuDropdown from './MenuDropdown';
|
||||
import Toggle from './Toggle';
|
||||
|
||||
const DisplayedFieldsDropdown = ({
|
||||
isOpen,
|
||||
items,
|
||||
onChange,
|
||||
onClickReset,
|
||||
slug,
|
||||
toggle,
|
||||
}) => {
|
||||
const DisplayedFieldsDropdown = ({ displayedHeaders, items, onChange, onClickReset, slug }) => {
|
||||
const { emitEvent } = useGlobalContext();
|
||||
const emitEventRef = useRef(emitEvent);
|
||||
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const toggle = useCallback(
|
||||
() =>
|
||||
setIsOpen(prev => {
|
||||
if (prev === false) {
|
||||
emitEventRef.current('willChangeListFieldsSettings');
|
||||
}
|
||||
|
||||
return !prev;
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<DropdownWrapper>
|
||||
@ -38,9 +46,7 @@ const DisplayedFieldsDropdown = ({
|
||||
<FormattedMessage id="app.links.configure-view" />
|
||||
</LayoutWrapper>
|
||||
</DropdownItemLink>
|
||||
<FormattedMessage
|
||||
id={`${pluginId}.containers.ListPage.displayedFields`}
|
||||
>
|
||||
<FormattedMessage id={`${pluginId}.containers.ListPage.displayedFields`}>
|
||||
{msg => (
|
||||
<ItemDropdownReset onClick={onClickReset}>
|
||||
<div
|
||||
@ -55,21 +61,18 @@ const DisplayedFieldsDropdown = ({
|
||||
</ItemDropdownReset>
|
||||
)}
|
||||
</FormattedMessage>
|
||||
{items.map(item => (
|
||||
<ItemDropdown
|
||||
key={item.name}
|
||||
toggle={false}
|
||||
onClick={() => onChange(item)}
|
||||
>
|
||||
{items.map(headerName => {
|
||||
const value = displayedHeaders.findIndex(({ name }) => name === headerName) !== -1;
|
||||
const handleChange = () => onChange({ name: headerName, value });
|
||||
|
||||
return (
|
||||
<ItemDropdown key={headerName} toggle={false} onClick={handleChange}>
|
||||
<div>
|
||||
<InputCheckbox
|
||||
onChange={() => onChange(item)}
|
||||
name={item.name}
|
||||
value={item.value}
|
||||
/>
|
||||
<InputCheckbox onChange={handleChange} name={headerName} value={value} />
|
||||
</div>
|
||||
</ItemDropdown>
|
||||
))}
|
||||
);
|
||||
})}
|
||||
</MenuDropdown>
|
||||
</ButtonDropdown>
|
||||
</DropdownWrapper>
|
||||
@ -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);
|
||||
|
@ -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 });
|
||||
|
@ -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 ';
|
||||
|
@ -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 = () => <div>FILTER</div>;
|
||||
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,14 +100,15 @@ 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 {
|
||||
contentType: {
|
||||
attributes,
|
||||
settings: {
|
||||
defaultSortBy,
|
||||
defaultSortOrder,
|
||||
bulkable: isBulkable,
|
||||
@ -116,21 +116,13 @@ function ListView({
|
||||
searchable: isSearchable,
|
||||
pageSize,
|
||||
// mainField,
|
||||
} = contentType.settings;
|
||||
},
|
||||
},
|
||||
} = 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]
|
||||
);
|
||||
|
||||
// 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]);
|
||||
|
||||
useEffect(() => {
|
||||
// TODO
|
||||
const tableHeaders = useMemo(() => {
|
||||
return listLayout;
|
||||
// let headers = listLayout.map(label => {
|
||||
// return { ...getMetaDatas([label, 'list']), name: label };
|
||||
// });
|
||||
console.log('up');
|
||||
setLayout(layout);
|
||||
}, [layout, setLayout]);
|
||||
|
||||
// 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 <State isPublished={isPublished} />;
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
|
||||
// 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;
|
||||
|
||||
// Display a notification if trying to remove the last displayed field
|
||||
if (value && listLayout.length === 1) {
|
||||
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');
|
||||
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update the sort when removing the displayed one
|
||||
if (currentSort.split(':')[0] === name && value) {
|
||||
emitEvent('didChangeDisplayedFields');
|
||||
handleChangeSearch({
|
||||
target: {
|
||||
name: '_sort',
|
||||
value: `${getFirstSortableElement(name)}:ASC`,
|
||||
},
|
||||
});
|
||||
}
|
||||
// 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 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}
|
||||
>
|
||||
<FilterPicker
|
||||
actions={filterPickerActions}
|
||||
@ -587,7 +545,7 @@ function ListView({
|
||||
changeParams={handleChangeFilters}
|
||||
filters={filters}
|
||||
index={key}
|
||||
schema={listSchema}
|
||||
schema={{}}
|
||||
key={key}
|
||||
toggleFilterPickerState={toggleFilterPickerState}
|
||||
isFilterPickerOpen={isFilterPickerOpen}
|
||||
@ -600,14 +558,12 @@ function ListView({
|
||||
<div className="col-2">
|
||||
<CheckPermissions permissions={pluginPermissions.collectionTypesConfigurations}>
|
||||
<DisplayedFieldsDropdown
|
||||
isOpen={isLabelPickerOpen}
|
||||
items={allLabels}
|
||||
displayedHeaders={displayedHeaders}
|
||||
items={allAllowedHeaders}
|
||||
// items={allAllowedHeaders}
|
||||
onChange={handleChangeListLabels}
|
||||
onClickReset={() => {
|
||||
resetListLabels(slug);
|
||||
}}
|
||||
onClickReset={onResetListHeaders}
|
||||
slug={slug}
|
||||
toggle={toggleLabelPickerState}
|
||||
/>
|
||||
</CheckPermissions>
|
||||
</div>
|
||||
@ -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
|
||||
);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
@ -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;
|
@ -0,0 +1,2 @@
|
||||
export { default as getAllAllowedHeaders } from './getAllAllowedHeaders';
|
||||
export { default as getFirstSortableHeader } from './getFirstSortableHeader';
|
@ -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');
|
||||
});
|
||||
});
|
@ -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,
|
||||
|
@ -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';
|
||||
|
@ -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 };
|
||||
|
@ -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);
|
||||
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;
|
||||
|
@ -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': {
|
||||
|
@ -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;
|
||||
}, []);
|
||||
|
Loading…
x
Reference in New Issue
Block a user