mirror of
https://github.com/strapi/strapi.git
synced 2025-08-11 18:27:22 +00:00
Revert "List view: new cog button icon with the view settings in the list view page (#17551)" (#17601)
This reverts commit e786f44833aad311e0ef669a7e98aa21ced2bd0a.
This commit is contained in:
parent
a92367510f
commit
3e0f6d3514
@ -1,6 +1,6 @@
|
||||
import React, { useRef, useState } from 'react';
|
||||
|
||||
import { Button } from '@strapi/design-system';
|
||||
import { Box, Button } from '@strapi/design-system';
|
||||
import { FilterListURLQuery, FilterPopoverURLQuery, useTracking } from '@strapi/helper-plugin';
|
||||
import { Filter } from '@strapi/icons';
|
||||
import PropTypes from 'prop-types';
|
||||
@ -21,6 +21,7 @@ const Filters = ({ displayedFilters }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box paddingTop={1} paddingBottom={1}>
|
||||
<Button
|
||||
variant="tertiary"
|
||||
ref={buttonRef}
|
||||
@ -38,6 +39,7 @@ const Filters = ({ displayedFilters }) => {
|
||||
source={buttonRef}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
<FilterListURLQuery filtersSchema={displayedFilters} />
|
||||
</>
|
||||
);
|
||||
|
@ -233,9 +233,8 @@ describe('Bulk publish selected entries modal', () => {
|
||||
|
||||
await user.click(publishDialogButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(publishDialog).not.toBeInTheDocument();
|
||||
|
||||
await waitFor(async () => {
|
||||
expect(screen.queryByRole('gridcell', { name: 'Entry 1' })).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('gridcell', { name: 'Entry 2' })).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('gridcell', { name: 'Entry 3' })).not.toBeInTheDocument();
|
||||
|
@ -1,93 +1,81 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Flex, BaseCheckbox, TextButton, Typography } from '@strapi/design-system';
|
||||
import { useCollator, useTracking } from '@strapi/helper-plugin';
|
||||
import { Select, Option, Box } from '@strapi/design-system';
|
||||
import { useTracking } from '@strapi/helper-plugin';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { checkIfAttributeIsDisplayable } from '../../../../utils';
|
||||
import { onChangeListHeaders, onResetListHeaders } from '../../actions';
|
||||
import { getTrad, checkIfAttributeIsDisplayable } from '../../../../utils';
|
||||
import { onChangeListHeaders } from '../../actions';
|
||||
import { selectDisplayedHeaders } from '../../selectors';
|
||||
|
||||
const ChackboxWrapper = styled(Flex)`
|
||||
:hover {
|
||||
background-color: ${(props) => props.theme.colors.primary100};
|
||||
}
|
||||
`;
|
||||
|
||||
export const FieldPicker = ({ layout }) => {
|
||||
const dispatch = useDispatch();
|
||||
const displayedHeaders = useSelector(selectDisplayedHeaders);
|
||||
const { trackUsage } = useTracking();
|
||||
const { formatMessage, locale } = useIntl();
|
||||
const formatter = useCollator(locale, {
|
||||
sensitivity: 'base',
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
const allAllowedHeaders = getAllAllowedHeaders(layout.contentType.attributes).map((attrName) => {
|
||||
const metadatas = layout.contentType.metadatas[attrName].list;
|
||||
|
||||
return {
|
||||
name: attrName,
|
||||
intlLabel: { id: metadatas.label, defaultMessage: metadatas.label },
|
||||
};
|
||||
});
|
||||
|
||||
const columns = Object.keys(layout.contentType.attributes)
|
||||
.filter((name) => checkIfAttributeIsDisplayable(layout.contentType.attributes[name]))
|
||||
.map((name) => ({
|
||||
name,
|
||||
label: layout.contentType.metadatas[name].list.label,
|
||||
}))
|
||||
.sort((a, b) => formatter.compare(a.label, b.label));
|
||||
const values = displayedHeaders.map(({ name }) => name);
|
||||
|
||||
const displayedHeaderKeys = displayedHeaders.map(({ name }) => name);
|
||||
|
||||
const handleChange = (name) => {
|
||||
const handleChange = (updatedValues) => {
|
||||
trackUsage('didChangeDisplayedFields');
|
||||
dispatch(onChangeListHeaders({ name, value: displayedHeaderKeys.includes(name) }));
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
dispatch(onResetListHeaders());
|
||||
// removing a header
|
||||
if (updatedValues.length < values.length) {
|
||||
const removedHeader = values.filter((value) => {
|
||||
return updatedValues.indexOf(value) === -1;
|
||||
});
|
||||
|
||||
dispatch(onChangeListHeaders({ name: removedHeader[0], value: true }));
|
||||
} else {
|
||||
const addedHeader = updatedValues.filter((value) => {
|
||||
return values.indexOf(value) === -1;
|
||||
});
|
||||
|
||||
dispatch(onChangeListHeaders({ name: addedHeader[0], value: false }));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Flex as="fieldset" direction="column" alignItems="stretch" gap={3}>
|
||||
<Flex justifyContent="space-between">
|
||||
<Typography as="legend" variant="pi" fontWeight="bold">
|
||||
{formatMessage({
|
||||
id: 'containers.ListPage.displayedFields',
|
||||
defaultMessage: 'Displayed fields',
|
||||
})}
|
||||
</Typography>
|
||||
|
||||
<TextButton onClick={handleReset}>
|
||||
{formatMessage({
|
||||
id: 'app.components.Button.reset',
|
||||
defaultMessage: 'Reset',
|
||||
})}
|
||||
</TextButton>
|
||||
</Flex>
|
||||
|
||||
<Flex direction="column" alignItems="stretch">
|
||||
{columns.map((header) => {
|
||||
const isActive = displayedHeaderKeys.includes(header.name);
|
||||
|
||||
return (
|
||||
<ChackboxWrapper
|
||||
wrap="wrap"
|
||||
gap={2}
|
||||
as="label"
|
||||
background={isActive ? 'primary100' : 'transparent'}
|
||||
hasRadius
|
||||
padding={2}
|
||||
key={header.name}
|
||||
<Box paddingTop={1} paddingBottom={1}>
|
||||
<Select
|
||||
aria-label="change displayed fields"
|
||||
value={values}
|
||||
onChange={handleChange}
|
||||
customizeContent={(values) =>
|
||||
formatMessage(
|
||||
{
|
||||
id: getTrad('select.currently.selected'),
|
||||
defaultMessage: '{count} currently selected',
|
||||
},
|
||||
{ count: values.length }
|
||||
)
|
||||
}
|
||||
multi
|
||||
size="S"
|
||||
>
|
||||
<BaseCheckbox
|
||||
onChange={() => handleChange(header.name)}
|
||||
value={isActive}
|
||||
name={header.name}
|
||||
/>
|
||||
<Typography fontSize={1}>{header.label}</Typography>
|
||||
</ChackboxWrapper>
|
||||
{allAllowedHeaders.map((header) => {
|
||||
return (
|
||||
<Option key={header.name} value={header.name}>
|
||||
{formatMessage({
|
||||
id: header.intlLabel.id || header.name,
|
||||
defaultMessage: header.intlLabel.defaultMessage || header.name,
|
||||
})}
|
||||
</Option>
|
||||
);
|
||||
})}
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Select>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@ -104,3 +92,17 @@ FieldPicker.propTypes = {
|
||||
}).isRequired,
|
||||
}).isRequired,
|
||||
};
|
||||
|
||||
const getAllAllowedHeaders = (attributes) => {
|
||||
const allowedAttributes = Object.keys(attributes).reduce((acc, current) => {
|
||||
const attribute = attributes[current];
|
||||
|
||||
if (checkIfAttributeIsDisplayable(attribute)) {
|
||||
acc.push(current);
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
return allowedAttributes.sort();
|
||||
};
|
||||
|
@ -1,195 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import { lightTheme, ThemeProvider } from '@strapi/design-system';
|
||||
import { render as renderRTL, fireEvent } from '@testing-library/react';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import { Provider } from 'react-redux';
|
||||
import { combineReducers, createStore } from 'redux';
|
||||
|
||||
import reducers from '../../../../../../reducers';
|
||||
import { FieldPicker } from '../index';
|
||||
|
||||
const layout = {
|
||||
contentType: {
|
||||
attributes: {
|
||||
id: { type: 'integer' },
|
||||
name: { type: 'string' },
|
||||
createdAt: { type: 'datetime' },
|
||||
updatedAt: { type: 'datetime' },
|
||||
},
|
||||
metadatas: {
|
||||
id: {
|
||||
list: { label: 'id', searchable: true, sortable: true },
|
||||
},
|
||||
name: {
|
||||
list: { label: 'name', searchable: true, sortable: true },
|
||||
},
|
||||
createdAt: {
|
||||
list: { label: 'createdAt', searchable: true, sortable: true },
|
||||
},
|
||||
updatedAt: {
|
||||
list: { label: 'updatedAt', searchable: true, sortable: true },
|
||||
},
|
||||
},
|
||||
layouts: {
|
||||
list: [],
|
||||
},
|
||||
options: {},
|
||||
settings: {},
|
||||
},
|
||||
};
|
||||
|
||||
const render = () => ({
|
||||
...renderRTL(<FieldPicker layout={layout} />, {
|
||||
wrapper({ children }) {
|
||||
const rootReducer = combineReducers(reducers);
|
||||
|
||||
const store = createStore(rootReducer, {
|
||||
'content-manager_listView': {
|
||||
contentType: {
|
||||
attributes: {
|
||||
id: { type: 'integer' },
|
||||
name: { type: 'string' },
|
||||
createdAt: { type: 'datetime' },
|
||||
updatedAt: { type: 'datetime' },
|
||||
},
|
||||
metadatas: {
|
||||
id: {
|
||||
edit: {},
|
||||
list: { label: 'id', searchable: true, sortable: true },
|
||||
},
|
||||
name: {
|
||||
edit: {
|
||||
label: 'name',
|
||||
description: '',
|
||||
placeholder: '',
|
||||
visible: true,
|
||||
editable: true,
|
||||
},
|
||||
list: { label: 'name', searchable: true, sortable: true },
|
||||
},
|
||||
createdAt: {
|
||||
edit: {
|
||||
label: 'createdAt',
|
||||
description: '',
|
||||
placeholder: '',
|
||||
visible: false,
|
||||
editable: true,
|
||||
},
|
||||
list: { label: 'createdAt', searchable: true, sortable: true },
|
||||
},
|
||||
updatedAt: {
|
||||
edit: {
|
||||
label: 'updatedAt',
|
||||
description: '',
|
||||
placeholder: '',
|
||||
visible: false,
|
||||
editable: true,
|
||||
},
|
||||
list: { label: 'updatedAt', searchable: true, sortable: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
displayedHeaders: [
|
||||
{
|
||||
key: '__id_key__',
|
||||
name: 'id',
|
||||
fieldSchema: { type: 'integer' },
|
||||
metadatas: { label: 'id', searchable: true, sortable: true },
|
||||
},
|
||||
],
|
||||
initialDisplayedHeaders: [
|
||||
{
|
||||
key: '__id_key__',
|
||||
name: 'id',
|
||||
fieldSchema: { type: 'integer' },
|
||||
metadatas: { label: 'id', searchable: true, sortable: true },
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<IntlProvider messages={{}} textComponent="span" locale="en">
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<Provider store={store}>{children}</Provider>
|
||||
</ThemeProvider>
|
||||
</IntlProvider>
|
||||
);
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
describe('FieldPicker', () => {
|
||||
it('should contains all the headers', () => {
|
||||
const { getAllByRole, getByRole } = render();
|
||||
|
||||
const checkboxes = getAllByRole('checkbox');
|
||||
const { attributes } = layout.contentType;
|
||||
const attributesKeys = Object.keys(attributes);
|
||||
|
||||
expect(checkboxes.length).toBe(attributesKeys.length);
|
||||
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (let attributeKey of attributesKeys) {
|
||||
// for each attribute make sure you have a checkbox
|
||||
const checkbox = getByRole('checkbox', {
|
||||
name: attributeKey,
|
||||
});
|
||||
|
||||
expect(checkbox).toBeInTheDocument();
|
||||
}
|
||||
});
|
||||
|
||||
it('should contains the initially selected headers', () => {
|
||||
const { getByRole } = render();
|
||||
|
||||
const checkboxSelected = getByRole('checkbox', {
|
||||
name: 'id',
|
||||
});
|
||||
const checkboxNotSelected = getByRole('checkbox', {
|
||||
name: 'name',
|
||||
});
|
||||
|
||||
expect(checkboxSelected).toHaveAttribute('checked');
|
||||
expect(checkboxNotSelected).not.toHaveAttribute('checked');
|
||||
});
|
||||
|
||||
it('should select an header', async () => {
|
||||
const { getByRole } = render();
|
||||
|
||||
// User can toggle selected headers
|
||||
const checkboxIdHeader = getByRole('checkbox', { name: 'id' });
|
||||
const checkboxNameHeader = getByRole('checkbox', { name: 'name' });
|
||||
expect(checkboxIdHeader).toBeChecked();
|
||||
|
||||
// User can unselect headers
|
||||
fireEvent.click(checkboxIdHeader);
|
||||
|
||||
expect(checkboxIdHeader).not.toBeChecked();
|
||||
|
||||
// User can select headers
|
||||
expect(checkboxNameHeader).not.toBeChecked();
|
||||
|
||||
fireEvent.click(checkboxNameHeader);
|
||||
|
||||
expect(checkboxNameHeader).toBeChecked();
|
||||
});
|
||||
|
||||
it('should show inside the Popover the reset button and when clicked select the initial headers selected', async () => {
|
||||
const { getByRole } = render();
|
||||
|
||||
// select a new header
|
||||
const checkboxNameHeader = getByRole('checkbox', { name: 'name' });
|
||||
fireEvent.click(checkboxNameHeader);
|
||||
|
||||
expect(checkboxNameHeader).toBeChecked();
|
||||
|
||||
const resetBtn = getByRole('button', {
|
||||
name: 'Reset',
|
||||
});
|
||||
fireEvent.click(resetBtn);
|
||||
|
||||
expect(checkboxNameHeader).not.toBeChecked();
|
||||
});
|
||||
});
|
@ -1,74 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Flex, IconButton, Popover } from '@strapi/design-system';
|
||||
import { CheckPermissions, LinkButton } from '@strapi/helper-plugin';
|
||||
import { Cog, Layer } from '@strapi/icons';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { selectAdminPermissions } from '../../../../../pages/App/selectors';
|
||||
import { FieldPicker } from '../FieldPicker';
|
||||
|
||||
export const ViewSettingsMenu = ({ slug, layout }) => {
|
||||
const [isVisible, setIsVisible] = React.useState(false);
|
||||
const cogButtonRef = React.useRef();
|
||||
const permissions = useSelector(selectAdminPermissions);
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
const handleToggle = () => {
|
||||
setIsVisible((prev) => !prev);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<IconButton
|
||||
icon={<Cog />}
|
||||
label={formatMessage({
|
||||
id: 'components.ViewSettings.tooltip',
|
||||
defaultMessage: 'View Settings',
|
||||
})}
|
||||
ref={cogButtonRef}
|
||||
onClick={handleToggle}
|
||||
/>
|
||||
{isVisible && (
|
||||
<Popover placement="bottom-end" source={cogButtonRef} onDismiss={handleToggle} padding={2}>
|
||||
<Flex alignItems="stretch" direction="column" gap={3}>
|
||||
<CheckPermissions
|
||||
permissions={permissions.contentManager.collectionTypesConfigurations}
|
||||
>
|
||||
<LinkButton
|
||||
size="S"
|
||||
startIcon={<Layer />}
|
||||
to={`${slug}/configurations/list`}
|
||||
variant="secondary"
|
||||
>
|
||||
{formatMessage({
|
||||
id: 'app.links.configure-view',
|
||||
defaultMessage: 'Configure the view',
|
||||
})}
|
||||
</LinkButton>
|
||||
</CheckPermissions>
|
||||
|
||||
<FieldPicker layout={layout} />
|
||||
</Flex>
|
||||
</Popover>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
ViewSettingsMenu.propTypes = {
|
||||
slug: PropTypes.string.isRequired,
|
||||
layout: PropTypes.shape({
|
||||
contentType: PropTypes.shape({
|
||||
attributes: PropTypes.object.isRequired,
|
||||
metadatas: PropTypes.object.isRequired,
|
||||
layouts: PropTypes.shape({
|
||||
list: PropTypes.array.isRequired,
|
||||
}).isRequired,
|
||||
options: PropTypes.object.isRequired,
|
||||
settings: PropTypes.object.isRequired,
|
||||
}).isRequired,
|
||||
}).isRequired,
|
||||
};
|
@ -1,156 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import { lightTheme, ThemeProvider } from '@strapi/design-system';
|
||||
import { fireEvent, render as renderRTL, waitFor } from '@testing-library/react';
|
||||
import { createMemoryHistory } from 'history';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import { Provider } from 'react-redux';
|
||||
import { Router } from 'react-router-dom';
|
||||
import { combineReducers, createStore } from 'redux';
|
||||
|
||||
import reducers from '../../../../../../reducers';
|
||||
import { ViewSettingsMenu } from '../index';
|
||||
|
||||
const layout = {
|
||||
contentType: {
|
||||
attributes: {
|
||||
id: { type: 'integer' },
|
||||
name: { type: 'string' },
|
||||
createdAt: { type: 'datetime' },
|
||||
updatedAt: { type: 'datetime' },
|
||||
},
|
||||
metadatas: {
|
||||
id: {
|
||||
list: { label: 'id', searchable: true, sortable: true },
|
||||
},
|
||||
name: {
|
||||
list: { label: 'name', searchable: true, sortable: true },
|
||||
},
|
||||
createdAt: {
|
||||
list: { label: 'createdAt', searchable: true, sortable: true },
|
||||
},
|
||||
updatedAt: {
|
||||
list: { label: 'updatedAt', searchable: true, sortable: true },
|
||||
},
|
||||
},
|
||||
layouts: {
|
||||
list: [],
|
||||
},
|
||||
options: {},
|
||||
settings: {},
|
||||
},
|
||||
};
|
||||
|
||||
jest.mock('@strapi/helper-plugin', () => ({
|
||||
...jest.requireActual('@strapi/helper-plugin'),
|
||||
// eslint-disable-next-line react/prop-types
|
||||
CheckPermissions: ({ children }) => <div>{children}</div>,
|
||||
}));
|
||||
|
||||
const history = createMemoryHistory();
|
||||
|
||||
const render = () => ({
|
||||
...renderRTL(<ViewSettingsMenu layout={layout} slug="api::temp.temp" />, {
|
||||
wrapper({ children }) {
|
||||
const rootReducer = combineReducers(reducers);
|
||||
|
||||
const store = createStore(rootReducer, {
|
||||
'content-manager_listView': {
|
||||
displayedHeaders: [],
|
||||
},
|
||||
admin_app: {
|
||||
permissions: {
|
||||
contentManager: {},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<Router history={history}>
|
||||
<IntlProvider messages={{}} textComponent="span" locale="en">
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<Provider store={store}>{children}</Provider>
|
||||
</ThemeProvider>
|
||||
</IntlProvider>
|
||||
</Router>
|
||||
);
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
describe('Content Manager | List view | ViewSettingsMenu', () => {
|
||||
it('should show the Cog Button', () => {
|
||||
const { getByRole } = render();
|
||||
|
||||
const cogBtn = getByRole('button', {
|
||||
name: 'View Settings',
|
||||
});
|
||||
|
||||
expect(cogBtn).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should open the Popover when you click on the Cog Button', () => {
|
||||
const { getByRole } = render();
|
||||
|
||||
const cogBtn = getByRole('button', {
|
||||
name: 'View Settings',
|
||||
});
|
||||
|
||||
fireEvent.click(cogBtn);
|
||||
|
||||
const configureViewLink = getByRole('link', {
|
||||
name: 'Configure the view',
|
||||
});
|
||||
|
||||
expect(configureViewLink).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show inside the Popover the Configure the view link button', async () => {
|
||||
const { getByRole } = render();
|
||||
|
||||
const cogBtn = getByRole('button', {
|
||||
name: 'View Settings',
|
||||
});
|
||||
|
||||
fireEvent.click(cogBtn);
|
||||
|
||||
const configureViewLink = getByRole('link', {
|
||||
name: 'Configure the view',
|
||||
});
|
||||
|
||||
expect(configureViewLink).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(configureViewLink);
|
||||
await waitFor(() => {
|
||||
expect(history.location.pathname).toBe('/api::temp.temp/configurations/list');
|
||||
});
|
||||
});
|
||||
|
||||
it('should show inside the Popover the title Dysplayed fields title', async () => {
|
||||
const { getByText, getByRole } = render();
|
||||
|
||||
const cogBtn = getByRole('button', {
|
||||
name: 'View Settings',
|
||||
});
|
||||
|
||||
fireEvent.click(cogBtn);
|
||||
|
||||
expect(getByText('Displayed fields')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show inside the Popover the reset button', () => {
|
||||
const { getByRole } = render();
|
||||
|
||||
const cogBtn = getByRole('button', {
|
||||
name: 'View Settings',
|
||||
});
|
||||
|
||||
fireEvent.click(cogBtn);
|
||||
|
||||
const resetBtn = getByRole('button', {
|
||||
name: 'Reset',
|
||||
});
|
||||
|
||||
expect(resetBtn).toBeInTheDocument();
|
||||
});
|
||||
});
|
@ -1,7 +1,9 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import {
|
||||
IconButton,
|
||||
Main,
|
||||
Box,
|
||||
ActionLayout,
|
||||
Button,
|
||||
ContentLayout,
|
||||
@ -16,6 +18,7 @@ import {
|
||||
} from '@strapi/design-system';
|
||||
import {
|
||||
NoPermissions,
|
||||
CheckPermissions,
|
||||
SearchURLQuery,
|
||||
useFetchClient,
|
||||
useFocusWhenNavigate,
|
||||
@ -30,7 +33,7 @@ import {
|
||||
PaginationURLQuery,
|
||||
PageSizeURLQuery,
|
||||
} from '@strapi/helper-plugin';
|
||||
import { ArrowLeft, Plus } from '@strapi/icons';
|
||||
import { ArrowLeft, Cog, Plus } from '@strapi/icons';
|
||||
import axios, { AxiosError } from 'axios';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import PropTypes from 'prop-types';
|
||||
@ -40,9 +43,11 @@ import { useMutation } from 'react-query';
|
||||
import { connect, useSelector } from 'react-redux';
|
||||
import { useHistory, useLocation, Link as ReactRouterLink } from 'react-router-dom';
|
||||
import { bindActionCreators, compose } from 'redux';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { INJECT_COLUMN_IN_TABLE } from '../../../exposedHooks';
|
||||
import { useEnterprise } from '../../../hooks/useEnterprise';
|
||||
import { selectAdminPermissions } from '../../../pages/App/selectors';
|
||||
import { InjectionZone } from '../../../shared/components';
|
||||
import AttributeFilter from '../../components/AttributeFilter';
|
||||
import { getTrad } from '../../utils';
|
||||
@ -51,10 +56,18 @@ import { getData, getDataSucceeded, onChangeListHeaders, onResetListHeaders } fr
|
||||
import { Body } from './components/Body';
|
||||
import BulkActionButtons from './components/BulkActionButtons';
|
||||
import CellContent from './components/CellContent';
|
||||
import { ViewSettingsMenu } from './components/ViewSettingsMenu';
|
||||
import { FieldPicker } from './components/FieldPicker';
|
||||
import makeSelectListView, { selectDisplayedHeaders } from './selectors';
|
||||
import { buildValidGetParams } from './utils';
|
||||
|
||||
const ConfigureLayoutBox = styled(Box)`
|
||||
svg {
|
||||
path {
|
||||
fill: ${({ theme }) => theme.colors.neutral900};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const REVIEW_WORKFLOW_COLUMNS_CE = null;
|
||||
const REVIEW_WORKFLOW_COLUMNS_CELL_CE = () => null;
|
||||
|
||||
@ -87,6 +100,7 @@ function ListView({
|
||||
const fetchPermissionsRef = React.useRef(refetchPermissions);
|
||||
const { notifyStatus } = useNotifyAT();
|
||||
const { formatAPIError } = useAPIErrorHandler(getTrad);
|
||||
const permissions = useSelector(selectAdminPermissions);
|
||||
|
||||
useFocusWhenNavigate();
|
||||
|
||||
@ -468,7 +482,25 @@ function ListView({
|
||||
endActions={
|
||||
<>
|
||||
<InjectionZone area="contentManager.listView.actions" />
|
||||
<ViewSettingsMenu slug={slug} layout={layout} />
|
||||
<FieldPicker layout={layout} />
|
||||
<CheckPermissions
|
||||
permissions={permissions.contentManager.collectionTypesConfigurations}
|
||||
>
|
||||
<ConfigureLayoutBox paddingTop={1} paddingBottom={1}>
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
trackUsage('willEditListLayout');
|
||||
}}
|
||||
forwardedAs={ReactRouterLink}
|
||||
to={{ pathname: `${slug}/configurations/list`, search: pluginsQueryParams }}
|
||||
icon={<Cog />}
|
||||
label={formatMessage({
|
||||
id: 'app.links.configure-view',
|
||||
defaultMessage: 'Configure the view',
|
||||
})}
|
||||
/>
|
||||
</ConfigureLayoutBox>
|
||||
</CheckPermissions>
|
||||
</>
|
||||
}
|
||||
startActions={
|
||||
|
@ -612,7 +612,7 @@
|
||||
"components.PageFooter.select": "Entries per page",
|
||||
"components.ProductionBlocker.description": "For safety purposes we have to disable this plugin in other environments.",
|
||||
"components.ProductionBlocker.header": "This plugin is only available in development.",
|
||||
"components.ViewSettings.tooltip": "View settings",
|
||||
"components.Search.placeholder": "Search...",
|
||||
"components.TableHeader.sort": "Sort on {label}",
|
||||
"components.Wysiwyg.ToggleMode.markdown-mode": "Markdown mode",
|
||||
"components.Wysiwyg.ToggleMode.preview-mode": "Preview mode",
|
||||
|
Loading…
x
Reference in New Issue
Block a user