mirror of
https://github.com/strapi/strapi.git
synced 2025-09-17 20:40:17 +00:00
Feature: Add review workflow stages to CM list-view filter
This commit is contained in:
parent
12047e3083
commit
3c4f28dad7
@ -1,101 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { useQueryParams } from '@strapi/helper-plugin';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { useIntl } from 'react-intl';
|
|
||||||
|
|
||||||
import { useAdminUsers } from '../../../hooks/useAdminUsers';
|
|
||||||
import { getDisplayName } from '../../utils';
|
|
||||||
|
|
||||||
import { AdminUsersFilter } from './AdminUsersFilter';
|
|
||||||
import Filters from './Filters';
|
|
||||||
import useAllowedAttributes from './hooks/useAllowedAttributes';
|
|
||||||
|
|
||||||
const CREATOR_ATTRIBUTES = ['createdBy', 'updatedBy'];
|
|
||||||
|
|
||||||
const AttributeFilter = ({ contentType, slug, metadatas }) => {
|
|
||||||
const { formatMessage } = useIntl();
|
|
||||||
|
|
||||||
const [{ query }] = useQueryParams();
|
|
||||||
// We get the users selected' ids
|
|
||||||
const selectedUsers =
|
|
||||||
query?.filters?.$and?.reduce((acc, filter) => {
|
|
||||||
const [key, value] = Object.entries(filter)[0];
|
|
||||||
const id = value.id?.$eq || value.id?.$ne;
|
|
||||||
|
|
||||||
if (CREATOR_ATTRIBUTES.includes(key) && !acc.includes(id)) {
|
|
||||||
acc.push(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
}, []) ?? [];
|
|
||||||
const { users, isLoading } = useAdminUsers(
|
|
||||||
{ filter: { id: { in: selectedUsers } } },
|
|
||||||
{
|
|
||||||
enabled: selectedUsers.length > 0,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const allowedAttributes = useAllowedAttributes(contentType, slug);
|
|
||||||
const displayedFilters = allowedAttributes.map((name) => {
|
|
||||||
const attribute = contentType.attributes[name];
|
|
||||||
const { type, enum: options } = attribute;
|
|
||||||
|
|
||||||
const trackedEvent = {
|
|
||||||
name: 'didFilterEntries',
|
|
||||||
properties: { useRelation: type === 'relation' },
|
|
||||||
};
|
|
||||||
|
|
||||||
const { mainField, label } = metadatas[name].list;
|
|
||||||
|
|
||||||
const filter = {
|
|
||||||
name,
|
|
||||||
metadatas: { label: formatMessage({ id: label, defaultMessage: label }) },
|
|
||||||
fieldSchema: { type, options, mainField },
|
|
||||||
trackedEvent,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (attribute.type === 'relation' && attribute.target === 'admin::user') {
|
|
||||||
filter.metadatas = {
|
|
||||||
...filter.metadatas,
|
|
||||||
customOperators: [
|
|
||||||
{
|
|
||||||
intlLabel: { id: 'components.FilterOptions.FILTER_TYPES.$eq', defaultMessage: 'is' },
|
|
||||||
value: '$eq',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
intlLabel: {
|
|
||||||
id: 'components.FilterOptions.FILTER_TYPES.$ne',
|
|
||||||
defaultMessage: 'is not',
|
|
||||||
},
|
|
||||||
value: '$ne',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
customInput: AdminUsersFilter,
|
|
||||||
options: users.map((user) => ({
|
|
||||||
label: getDisplayName(user, formatMessage),
|
|
||||||
customValue: user.id.toString(),
|
|
||||||
})),
|
|
||||||
};
|
|
||||||
filter.fieldSchema.mainField = {
|
|
||||||
name: 'id',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return filter;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isLoading) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return <Filters displayedFilters={displayedFilters} />;
|
|
||||||
};
|
|
||||||
|
|
||||||
AttributeFilter.propTypes = {
|
|
||||||
contentType: PropTypes.object.isRequired,
|
|
||||||
metadatas: PropTypes.object.isRequired,
|
|
||||||
slug: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AttributeFilter;
|
|
@ -4,8 +4,8 @@ import { Combobox, ComboboxOption } from '@strapi/design-system';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
import { useAdminUsers } from '../../../hooks/useAdminUsers';
|
import { useAdminUsers } from '../../../../hooks/useAdminUsers';
|
||||||
import { getDisplayName } from '../../utils';
|
import { getDisplayName } from '../../../utils';
|
||||||
|
|
||||||
const AdminUsersFilter = ({ value, onChange }) => {
|
const AdminUsersFilter = ({ value, onChange }) => {
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
@ -2,11 +2,11 @@ import React, { useRef, useState } from 'react';
|
|||||||
|
|
||||||
import { Box, Button } from '@strapi/design-system';
|
import { Box, Button } from '@strapi/design-system';
|
||||||
import { FilterListURLQuery, FilterPopoverURLQuery, useTracking } from '@strapi/helper-plugin';
|
import { FilterListURLQuery, FilterPopoverURLQuery, useTracking } from '@strapi/helper-plugin';
|
||||||
import { Filter } from '@strapi/icons';
|
import { Filter as FilterIcon } from '@strapi/icons';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
const Filters = ({ displayedFilters }) => {
|
export const Filter = ({ displayedFilters }) => {
|
||||||
const [isVisible, setIsVisible] = useState(false);
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
const buttonRef = useRef();
|
const buttonRef = useRef();
|
||||||
@ -25,7 +25,7 @@ const Filters = ({ displayedFilters }) => {
|
|||||||
<Button
|
<Button
|
||||||
variant="tertiary"
|
variant="tertiary"
|
||||||
ref={buttonRef}
|
ref={buttonRef}
|
||||||
startIcon={<Filter />}
|
startIcon={<FilterIcon />}
|
||||||
onClick={handleToggle}
|
onClick={handleToggle}
|
||||||
size="S"
|
size="S"
|
||||||
>
|
>
|
||||||
@ -45,7 +45,7 @@ const Filters = ({ displayedFilters }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
Filters.propTypes = {
|
Filter.propTypes = {
|
||||||
displayedFilters: PropTypes.arrayOf(
|
displayedFilters: PropTypes.arrayOf(
|
||||||
PropTypes.shape({
|
PropTypes.shape({
|
||||||
name: PropTypes.string.isRequired,
|
name: PropTypes.string.isRequired,
|
||||||
@ -54,5 +54,3 @@ Filters.propTypes = {
|
|||||||
})
|
})
|
||||||
).isRequired,
|
).isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Filters;
|
|
@ -0,0 +1 @@
|
|||||||
|
export * from './Filter';
|
@ -1,17 +1,11 @@
|
|||||||
import { findMatchingPermissions, useRBACProvider, useCollator } from '@strapi/helper-plugin';
|
import { useRBACProvider, findMatchingPermissions } from '@strapi/helper-plugin';
|
||||||
import { useIntl } from 'react-intl';
|
|
||||||
|
|
||||||
const NOT_ALLOWED_FILTERS = ['json', 'component', 'media', 'richtext', 'dynamiczone', 'password'];
|
const NOT_ALLOWED_FILTERS = ['json', 'component', 'media', 'richtext', 'dynamiczone', 'password'];
|
||||||
const TIMESTAMPS = ['createdAt', 'updatedAt'];
|
const TIMESTAMPS = ['createdAt', 'updatedAt'];
|
||||||
const CREATOR_ATTRIBUTES = ['createdBy', 'updatedBy'];
|
const CREATOR_ATTRIBUTES = ['createdBy', 'updatedBy'];
|
||||||
|
|
||||||
const useAllowedAttributes = (contentType, slug) => {
|
export const useAllowedAttributes = (contentType, slug) => {
|
||||||
const { allPermissions } = useRBACProvider();
|
const { allPermissions } = useRBACProvider();
|
||||||
const { locale } = useIntl();
|
|
||||||
|
|
||||||
const formatter = useCollator(locale, {
|
|
||||||
sensitivity: 'base',
|
|
||||||
});
|
|
||||||
|
|
||||||
const readPermissionsForSlug = findMatchingPermissions(allPermissions, [
|
const readPermissionsForSlug = findMatchingPermissions(allPermissions, [
|
||||||
{
|
{
|
||||||
@ -43,14 +37,11 @@ const useAllowedAttributes = (contentType, slug) => {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
const allowedAndDefaultAttributes = [
|
|
||||||
|
return [
|
||||||
'id',
|
'id',
|
||||||
...allowedAttributes,
|
...allowedAttributes,
|
||||||
...TIMESTAMPS,
|
...TIMESTAMPS,
|
||||||
...(canReadAdminUsers ? CREATOR_ATTRIBUTES : []),
|
...(canReadAdminUsers ? CREATOR_ATTRIBUTES : []),
|
||||||
];
|
];
|
||||||
|
|
||||||
return allowedAndDefaultAttributes.sort((a, b) => formatter.compare(a, b));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useAllowedAttributes;
|
|
@ -28,6 +28,7 @@ import {
|
|||||||
useTracking,
|
useTracking,
|
||||||
Link,
|
Link,
|
||||||
useAPIErrorHandler,
|
useAPIErrorHandler,
|
||||||
|
useCollator,
|
||||||
useStrapiApp,
|
useStrapiApp,
|
||||||
Table,
|
Table,
|
||||||
PaginationURLQuery,
|
PaginationURLQuery,
|
||||||
@ -46,10 +47,13 @@ import { bindActionCreators, compose } from 'redux';
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import { INJECT_COLUMN_IN_TABLE } from '../../../exposedHooks';
|
import { INJECT_COLUMN_IN_TABLE } from '../../../exposedHooks';
|
||||||
|
import { useAdminUsers } from '../../../hooks/useAdminUsers';
|
||||||
import { useEnterprise } from '../../../hooks/useEnterprise';
|
import { useEnterprise } from '../../../hooks/useEnterprise';
|
||||||
import { selectAdminPermissions } from '../../../pages/App/selectors';
|
import { selectAdminPermissions } from '../../../pages/App/selectors';
|
||||||
import { InjectionZone } from '../../../shared/components';
|
import { InjectionZone } from '../../../shared/components';
|
||||||
import AttributeFilter from '../../components/AttributeFilter';
|
import { Filter } from '../../components/Filter';
|
||||||
|
import { AdminUsersFilter } from '../../components/Filter/CustomInputs/AdminUsersFilter';
|
||||||
|
import { useAllowedAttributes } from '../../hooks/useAllowedAttributes';
|
||||||
import { getTrad, getDisplayName } from '../../utils';
|
import { getTrad, getDisplayName } from '../../utils';
|
||||||
|
|
||||||
import { getData, getDataSucceeded, onChangeListHeaders, onResetListHeaders } from './actions';
|
import { getData, getDataSucceeded, onChangeListHeaders, onResetListHeaders } from './actions';
|
||||||
@ -70,6 +74,8 @@ const ConfigureLayoutBox = styled(Box)`
|
|||||||
|
|
||||||
const REVIEW_WORKFLOW_COLUMNS_CE = null;
|
const REVIEW_WORKFLOW_COLUMNS_CE = null;
|
||||||
const REVIEW_WORKFLOW_COLUMNS_CELL_CE = () => null;
|
const REVIEW_WORKFLOW_COLUMNS_CELL_CE = () => null;
|
||||||
|
const REVIEW_WORKFLOW_FILTER_CE = [];
|
||||||
|
const CREATOR_ATTRIBUTES = ['createdBy', 'updatedBy'];
|
||||||
|
|
||||||
function ListView({
|
function ListView({
|
||||||
canCreate,
|
canCreate,
|
||||||
@ -101,17 +107,90 @@ function ListView({
|
|||||||
const { notifyStatus } = useNotifyAT();
|
const { notifyStatus } = useNotifyAT();
|
||||||
const { formatAPIError } = useAPIErrorHandler(getTrad);
|
const { formatAPIError } = useAPIErrorHandler(getTrad);
|
||||||
const permissions = useSelector(selectAdminPermissions);
|
const permissions = useSelector(selectAdminPermissions);
|
||||||
|
const allowedAttributes = useAllowedAttributes(contentType, slug);
|
||||||
|
const [{ query }] = useQueryParams();
|
||||||
|
const { pathname } = useLocation();
|
||||||
|
const { push } = useHistory();
|
||||||
|
const { formatMessage, locale } = useIntl();
|
||||||
|
const fetchClient = useFetchClient();
|
||||||
|
const formatter = useCollator(locale, {
|
||||||
|
sensitivity: 'base',
|
||||||
|
});
|
||||||
|
|
||||||
|
const selectedUserIds =
|
||||||
|
query?.filters?.$and?.reduce((acc, filter) => {
|
||||||
|
const [key, value] = Object.entries(filter)[0];
|
||||||
|
const id = value.id?.$eq || value.id?.$ne;
|
||||||
|
|
||||||
|
if (CREATOR_ATTRIBUTES.includes(key) && !acc.includes(id)) {
|
||||||
|
acc.push(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, []) ?? [];
|
||||||
|
|
||||||
|
const { users, isLoading: isLoadingAdminUsers } = useAdminUsers(
|
||||||
|
{ filter: { id: { in: selectedUserIds } } },
|
||||||
|
{
|
||||||
|
enabled: selectedUserIds.length > 0,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
useFocusWhenNavigate();
|
useFocusWhenNavigate();
|
||||||
|
|
||||||
const [{ query }] = useQueryParams();
|
|
||||||
const params = React.useMemo(() => buildValidGetParams(query), [query]);
|
const params = React.useMemo(() => buildValidGetParams(query), [query]);
|
||||||
const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
|
const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
|
||||||
|
|
||||||
const { pathname } = useLocation();
|
const displayedAttributeFilters = allowedAttributes.map((name) => {
|
||||||
const { push } = useHistory();
|
const attribute = contentType.attributes[name];
|
||||||
const { formatMessage } = useIntl();
|
const { type, enum: options } = attribute;
|
||||||
const fetchClient = useFetchClient();
|
|
||||||
|
const trackedEvent = {
|
||||||
|
name: 'didFilterEntries',
|
||||||
|
properties: { useRelation: type === 'relation' },
|
||||||
|
};
|
||||||
|
|
||||||
|
const { mainField, label } = metadatas[name].list;
|
||||||
|
|
||||||
|
const filter = {
|
||||||
|
name,
|
||||||
|
metadatas: { label: formatMessage({ id: label, defaultMessage: label }) },
|
||||||
|
fieldSchema: { type, options, mainField },
|
||||||
|
trackedEvent,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (attribute.type === 'relation' && attribute.target === 'admin::user') {
|
||||||
|
filter.metadatas = {
|
||||||
|
...filter.metadatas,
|
||||||
|
customOperators: [
|
||||||
|
{
|
||||||
|
intlLabel: {
|
||||||
|
id: 'components.FilterOptions.FILTER_TYPES.$eq',
|
||||||
|
defaultMessage: 'is',
|
||||||
|
},
|
||||||
|
value: '$eq',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
intlLabel: {
|
||||||
|
id: 'components.FilterOptions.FILTER_TYPES.$ne',
|
||||||
|
defaultMessage: 'is not',
|
||||||
|
},
|
||||||
|
value: '$ne',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
customInput: AdminUsersFilter,
|
||||||
|
options: users.map((user) => ({
|
||||||
|
label: getDisplayName(user, formatMessage),
|
||||||
|
customValue: user.id.toString(),
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
filter.fieldSchema.mainField = {
|
||||||
|
name: 'id',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return filter;
|
||||||
|
});
|
||||||
|
|
||||||
const hasDraftAndPublish = options?.draftAndPublish ?? false;
|
const hasDraftAndPublish = options?.draftAndPublish ?? false;
|
||||||
const hasReviewWorkflows = options?.reviewWorkflows ?? false;
|
const hasReviewWorkflows = options?.reviewWorkflows ?? false;
|
||||||
@ -142,6 +221,34 @@ function ListView({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const reviewWorkflowFilter = useEnterprise(
|
||||||
|
REVIEW_WORKFLOW_FILTER_CE,
|
||||||
|
async () =>
|
||||||
|
(
|
||||||
|
await import(
|
||||||
|
'../../../../../ee/admin/content-manager/components/Filter/CustomInputs/ReviewWorkflows/constants'
|
||||||
|
)
|
||||||
|
).REVIEW_WORKFLOW_STAGE_FILTER,
|
||||||
|
{
|
||||||
|
combine(ceFilters, eeFilter) {
|
||||||
|
return [
|
||||||
|
...ceFilters,
|
||||||
|
{
|
||||||
|
...eeFilter,
|
||||||
|
metadatas: {
|
||||||
|
...eeFilter.metadatas,
|
||||||
|
label: formatMessage(eeFilter.metadatas.label),
|
||||||
|
uid: contentType.uid,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
|
|
||||||
|
defaultValue: [],
|
||||||
|
enabled: hasReviewWorkflows,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const { post, del } = fetchClient;
|
const { post, del } = fetchClient;
|
||||||
|
|
||||||
const bulkUnpublishMutation = useMutation(
|
const bulkUnpublishMutation = useMutation(
|
||||||
@ -550,8 +657,12 @@ function ListView({
|
|||||||
trackedEvent="didSearch"
|
trackedEvent="didSearch"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{isFilterable && (
|
{isFilterable && !isLoadingAdminUsers && (
|
||||||
<AttributeFilter contentType={contentType} slug={slug} metadatas={metadatas} />
|
<Filter
|
||||||
|
displayedFilters={[...displayedAttributeFilters, ...reviewWorkflowFilter].sort(
|
||||||
|
(a, b) => formatter.compare(a.metadatas.label, b.metadatas.label)
|
||||||
|
)}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,70 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { Flex, Loader, SingleSelect, SingleSelectOption, Typography } from '@strapi/design-system';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
|
import { useReviewWorkflows } from '../../../../../pages/SettingsPage/pages/ReviewWorkflows/hooks/useReviewWorkflows';
|
||||||
|
import { getStageColorByHex } from '../../../../../pages/SettingsPage/pages/ReviewWorkflows/utils/colors';
|
||||||
|
|
||||||
|
export const ReviewWorkflowsFilter = ({ value, onChange, uid }) => {
|
||||||
|
const { formatMessage } = useIntl();
|
||||||
|
const {
|
||||||
|
workflows: [workflow],
|
||||||
|
isLoading,
|
||||||
|
} = useReviewWorkflows({ filters: { contentTypes: uid } });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SingleSelect
|
||||||
|
aria-label={formatMessage({
|
||||||
|
id: 'content-manager.components.Filters.reviewWorkflows.label',
|
||||||
|
defaultMessage: 'Search and select an workflow stage to filter',
|
||||||
|
})}
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
loading={isLoading}
|
||||||
|
// eslint-disable-next-line react/no-unstable-nested-components
|
||||||
|
customizeContent={() => (
|
||||||
|
<Flex as="span" justifyContent="space-between" alignItems="center" width="100%">
|
||||||
|
<Typography textColor="neutral800" ellipsis>
|
||||||
|
{value}
|
||||||
|
</Typography>
|
||||||
|
{isLoading ? <Loader small style={{ display: 'flex' }} /> : null}
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{(workflow?.stages ?? []).map(({ id, color, name }) => {
|
||||||
|
const { themeColorName } = getStageColorByHex(color);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SingleSelectOption
|
||||||
|
key={id}
|
||||||
|
startIcon={
|
||||||
|
<Flex
|
||||||
|
height={2}
|
||||||
|
background={color}
|
||||||
|
borderColor={themeColorName === 'neutral0' ? 'neutral150' : 'transparent'}
|
||||||
|
hasRadius
|
||||||
|
shrink={0}
|
||||||
|
width={2}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
value={name}
|
||||||
|
>
|
||||||
|
{name}
|
||||||
|
</SingleSelectOption>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</SingleSelect>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
ReviewWorkflowsFilter.defaultProps = {
|
||||||
|
value: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
ReviewWorkflowsFilter.propTypes = {
|
||||||
|
onChange: PropTypes.func.isRequired,
|
||||||
|
uid: PropTypes.string.isRequired,
|
||||||
|
value: PropTypes.string,
|
||||||
|
};
|
@ -0,0 +1,27 @@
|
|||||||
|
import { getTrad } from '../../../../../../../admin/src/content-manager/utils';
|
||||||
|
|
||||||
|
import { ReviewWorkflowsFilter } from './ReviewWorkflowsFilter';
|
||||||
|
|
||||||
|
export const REVIEW_WORKFLOW_STAGE_FILTER = {
|
||||||
|
fieldSchema: {
|
||||||
|
type: 'relation',
|
||||||
|
mainField: {
|
||||||
|
name: 'name',
|
||||||
|
|
||||||
|
schema: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
metadatas: {
|
||||||
|
customInput: ReviewWorkflowsFilter,
|
||||||
|
|
||||||
|
label: {
|
||||||
|
id: getTrad(`containers.ListPage.table-headers.reviewWorkflows.stage`),
|
||||||
|
defaultMessage: 'Review stage',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
name: 'strapi_stage',
|
||||||
|
};
|
@ -0,0 +1,83 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { ThemeProvider, lightTheme } from '@strapi/design-system';
|
||||||
|
import { render, waitFor } from '@testing-library/react';
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
|
import { rest } from 'msw';
|
||||||
|
import { setupServer } from 'msw/node';
|
||||||
|
import { IntlProvider } from 'react-intl';
|
||||||
|
import { QueryClientProvider, QueryClient } from 'react-query';
|
||||||
|
|
||||||
|
import { ReviewWorkflowsFilter } from '../ReviewWorkflowsFilter';
|
||||||
|
|
||||||
|
const server = setupServer(
|
||||||
|
rest.get('*/admin/review-workflows/workflows', (req, res, ctx) => {
|
||||||
|
return res(
|
||||||
|
ctx.json({
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
stages: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'To Review',
|
||||||
|
color: '#FFFFFF',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const queryClient = new QueryClient();
|
||||||
|
|
||||||
|
const setup = (props) => {
|
||||||
|
return {
|
||||||
|
...render(<ReviewWorkflowsFilter uid="api::address.address" onChange={() => {}} {...props} />, {
|
||||||
|
wrapper: ({ children }) => (
|
||||||
|
<ThemeProvider theme={lightTheme}>
|
||||||
|
<QueryClientProvider client={queryClient}>
|
||||||
|
<IntlProvider locale="en" messages={{}} defaultLocale="en">
|
||||||
|
{children}
|
||||||
|
</IntlProvider>
|
||||||
|
</QueryClientProvider>
|
||||||
|
</ThemeProvider>
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
user: userEvent.setup(),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Content-Manger | List View | Filter | ReviewWorkflowsFilter', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
server.listen();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
server.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display stages', async () => {
|
||||||
|
const { getByText, user, getByRole } = setup();
|
||||||
|
|
||||||
|
await user.click(getByRole('combobox'));
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(getByText('To Review')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use the stage name as filter value', async () => {
|
||||||
|
const spy = jest.fn();
|
||||||
|
const { getByText, user, getByRole } = setup({ onChange: spy });
|
||||||
|
|
||||||
|
await user.click(getByRole('combobox'));
|
||||||
|
await user.click(getByText('To Review'));
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(spy).toHaveBeenCalledWith('To Review');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user