mirror of
https://github.com/strapi/strapi.git
synced 2025-11-12 16:22:10 +00:00
feat(review-workflows): Fetch stages a user is allowed to transition into
This commit is contained in:
parent
4341b3db4c
commit
ec99de9ff9
@ -5,6 +5,7 @@ import {
|
|||||||
SingleSelectOption,
|
SingleSelectOption,
|
||||||
Field,
|
Field,
|
||||||
FieldError,
|
FieldError,
|
||||||
|
FieldHint,
|
||||||
Flex,
|
Flex,
|
||||||
Loader,
|
Loader,
|
||||||
Typography,
|
Typography,
|
||||||
@ -24,26 +25,22 @@ import {
|
|||||||
CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME,
|
CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME,
|
||||||
CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME,
|
CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME,
|
||||||
} from '../../../../../../pages/SettingsPage/pages/ReviewWorkflows/constants';
|
} from '../../../../../../pages/SettingsPage/pages/ReviewWorkflows/constants';
|
||||||
import { useReviewWorkflows } from '../../../../../../pages/SettingsPage/pages/ReviewWorkflows/hooks/useReviewWorkflows';
|
import { useReviewWorkflowsStages } from '../../../../../../pages/SettingsPage/pages/ReviewWorkflows/hooks/useReviewWorkflowsStages';
|
||||||
import { getStageColorByHex } from '../../../../../../pages/SettingsPage/pages/ReviewWorkflows/utils/colors';
|
import { getStageColorByHex } from '../../../../../../pages/SettingsPage/pages/ReviewWorkflows/utils/colors';
|
||||||
import { STAGE_ATTRIBUTE_NAME } from '../../constants';
|
import { STAGE_ATTRIBUTE_NAME } from '../../constants';
|
||||||
|
|
||||||
export function StageSelect() {
|
export function StageSelect() {
|
||||||
const {
|
const { initialData, layout: contentType, isSingleType, onChange } = useCMEditViewDataManager();
|
||||||
initialData,
|
|
||||||
layout: { uid },
|
|
||||||
isSingleType,
|
|
||||||
onChange,
|
|
||||||
} = useCMEditViewDataManager();
|
|
||||||
const { put } = useFetchClient();
|
const { put } = useFetchClient();
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
const { formatAPIError } = useAPIErrorHandler();
|
const { formatAPIError } = useAPIErrorHandler();
|
||||||
const toggleNotification = useNotification();
|
const toggleNotification = useNotification();
|
||||||
const {
|
const { meta, stages, isLoading } = useReviewWorkflowsStages(
|
||||||
meta,
|
{ id: initialData.id, layout: contentType },
|
||||||
workflows: [workflow],
|
{
|
||||||
isLoading,
|
enabled: !!initialData?.id,
|
||||||
} = useReviewWorkflows({ filters: { contentTypes: uid } });
|
}
|
||||||
|
);
|
||||||
const { getFeature } = useLicenseLimits();
|
const { getFeature } = useLicenseLimits();
|
||||||
const [showLimitModal, setShowLimitModal] = React.useState(false);
|
const [showLimitModal, setShowLimitModal] = React.useState(false);
|
||||||
|
|
||||||
@ -114,15 +111,14 @@ export function StageSelect() {
|
|||||||
*/
|
*/
|
||||||
} else if (
|
} else if (
|
||||||
limits?.[CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME] &&
|
limits?.[CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME] &&
|
||||||
parseInt(limits[CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME], 10) <
|
parseInt(limits[CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME], 10) < stages.length
|
||||||
workflow.stages.length
|
|
||||||
) {
|
) {
|
||||||
setShowLimitModal('stage');
|
setShowLimitModal('stage');
|
||||||
} else {
|
} else {
|
||||||
mutation.mutateAsync({
|
mutation.mutateAsync({
|
||||||
entityId: initialData.id,
|
entityId: initialData.id,
|
||||||
stageId,
|
stageId,
|
||||||
uid,
|
uid: contentType.uid,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -137,9 +133,20 @@ export function StageSelect() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Field name={STAGE_ATTRIBUTE_NAME} id={STAGE_ATTRIBUTE_NAME}>
|
<Field
|
||||||
|
hint={
|
||||||
|
stages.length === 0 &&
|
||||||
|
formatMessage({
|
||||||
|
id: 'content-manager.reviewWorkflows.stages.no-transition',
|
||||||
|
defaultMessage: 'You don’t have the permission to update this stage.',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
name={STAGE_ATTRIBUTE_NAME}
|
||||||
|
id={STAGE_ATTRIBUTE_NAME}
|
||||||
|
>
|
||||||
<Flex direction="column" gap={2} alignItems="stretch">
|
<Flex direction="column" gap={2} alignItems="stretch">
|
||||||
<SingleSelect
|
<SingleSelect
|
||||||
|
disabled={stages.length === 0}
|
||||||
error={(mutation.error && formatAPIError(mutation.error)) || null}
|
error={(mutation.error && formatAPIError(mutation.error)) || null}
|
||||||
name={STAGE_ATTRIBUTE_NAME}
|
name={STAGE_ATTRIBUTE_NAME}
|
||||||
id={STAGE_ATTRIBUTE_NAME}
|
id={STAGE_ATTRIBUTE_NAME}
|
||||||
@ -150,6 +157,7 @@ export function StageSelect() {
|
|||||||
defaultMessage: 'Review stage',
|
defaultMessage: 'Review stage',
|
||||||
})}
|
})}
|
||||||
startIcon={
|
startIcon={
|
||||||
|
activeWorkflowStage && (
|
||||||
<Flex
|
<Flex
|
||||||
as="span"
|
as="span"
|
||||||
height={2}
|
height={2}
|
||||||
@ -160,23 +168,26 @@ export function StageSelect() {
|
|||||||
width={2}
|
width={2}
|
||||||
marginRight="-3px"
|
marginRight="-3px"
|
||||||
/>
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react/no-unstable-nested-components
|
// eslint-disable-next-line react/no-unstable-nested-components
|
||||||
customizeContent={() => (
|
customizeContent={() => (
|
||||||
<Flex as="span" justifyContent="space-between" alignItems="center" width="100%">
|
<Flex as="span" justifyContent="space-between" alignItems="center" width="100%">
|
||||||
<Typography textColor="neutral800" ellipsis>
|
<Typography textColor="neutral800" ellipsis>
|
||||||
{activeWorkflowStage?.name}
|
{activeWorkflowStage?.name ?? ''}
|
||||||
</Typography>
|
</Typography>
|
||||||
{isLoading ? <Loader small style={{ display: 'flex' }} /> : null}
|
{isLoading ? (
|
||||||
|
<Loader small style={{ display: 'flex' }} data-testid="loader" />
|
||||||
|
) : null}
|
||||||
</Flex>
|
</Flex>
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{workflow
|
{stages.map(({ id, color, name }) => {
|
||||||
? workflow.stages.map(({ id, color, name }) => {
|
|
||||||
const { themeColorName } = getStageColorByHex(color);
|
const { themeColorName } = getStageColorByHex(color);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SingleSelectOption
|
<SingleSelectOption
|
||||||
|
key={id}
|
||||||
startIcon={
|
startIcon={
|
||||||
<Flex
|
<Flex
|
||||||
height={2}
|
height={2}
|
||||||
@ -193,9 +204,9 @@ export function StageSelect() {
|
|||||||
{name}
|
{name}
|
||||||
</SingleSelectOption>
|
</SingleSelectOption>
|
||||||
);
|
);
|
||||||
})
|
})}
|
||||||
: []}
|
|
||||||
</SingleSelect>
|
</SingleSelect>
|
||||||
|
<FieldHint />
|
||||||
<FieldError />
|
<FieldError />
|
||||||
</Flex>
|
</Flex>
|
||||||
</Field>
|
</Field>
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { ThemeProvider, lightTheme } from '@strapi/design-system';
|
import { ThemeProvider, lightTheme } from '@strapi/design-system';
|
||||||
import { useCMEditViewDataManager } from '@strapi/helper-plugin';
|
import { render, waitFor, waitForElementToBeRemoved } from '@testing-library/react';
|
||||||
import { render, waitFor } from '@testing-library/react';
|
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import { rest } from 'msw';
|
import { rest } from 'msw';
|
||||||
import { setupServer } from 'msw/node';
|
import { setupServer } from 'msw/node';
|
||||||
@ -11,45 +10,49 @@ import { QueryClientProvider, QueryClient } from 'react-query';
|
|||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { createStore } from 'redux';
|
import { createStore } from 'redux';
|
||||||
|
|
||||||
import { STAGE_ATTRIBUTE_NAME } from '../../../constants';
|
|
||||||
import { StageSelect } from '../StageSelect';
|
import { StageSelect } from '../StageSelect';
|
||||||
|
|
||||||
const STAGE_1_STATE_FIXTURE = {
|
|
||||||
id: 1,
|
|
||||||
color: '#4945FF',
|
|
||||||
name: 'Stage 1',
|
|
||||||
worklow: 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
const server = setupServer(
|
const server = setupServer(
|
||||||
rest.get('*/review-workflows/workflows/', (req, res, ctx) =>
|
...[
|
||||||
|
rest.get('*/content-manager/:kind/:uid/:id/stages', (req, res, ctx) =>
|
||||||
res(
|
res(
|
||||||
ctx.json({
|
ctx.json({
|
||||||
data: [
|
data: [
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
stages: [
|
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
color: '#4945FF',
|
color: '#4945FF',
|
||||||
name: 'Stage 1',
|
name: 'Stage 1',
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
color: '#4945FF',
|
color: '#4945FF',
|
||||||
name: 'Stage 2',
|
name: 'Stage 2',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
)
|
),
|
||||||
|
|
||||||
|
rest.get('*/license-limit-information', (req, res, ctx) => res(ctx.json({}))),
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
jest.mock('@strapi/helper-plugin', () => ({
|
jest.mock('@strapi/helper-plugin', () => ({
|
||||||
...jest.requireActual('@strapi/helper-plugin'),
|
...jest.requireActual('@strapi/helper-plugin'),
|
||||||
useCMEditViewDataManager: jest.fn(),
|
useCMEditViewDataManager: jest.fn().mockReturnValue({
|
||||||
|
initialData: {
|
||||||
|
id: 1,
|
||||||
|
strapi_stage: {
|
||||||
|
id: 1,
|
||||||
|
color: '#4945FF',
|
||||||
|
name: 'Stage 1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
isCreatingEntry: false,
|
||||||
|
isSingleType: false,
|
||||||
|
layout: { uid: 'api::articles:articles' },
|
||||||
|
}),
|
||||||
useNotification: jest.fn(() => ({
|
useNotification: jest.fn(() => ({
|
||||||
toggleNotification: jest.fn(),
|
toggleNotification: jest.fn(),
|
||||||
})),
|
})),
|
||||||
@ -92,40 +95,36 @@ describe('EE | Content Manager | EditView | InformationBox | StageSelect', () =>
|
|||||||
server.close();
|
server.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders an enabled select input, if the entity is edited', () => {
|
afterEach(() => {
|
||||||
useCMEditViewDataManager.mockReturnValue({
|
jest.clearAllMocks();
|
||||||
initialData: {
|
|
||||||
[STAGE_ATTRIBUTE_NAME]: null,
|
|
||||||
},
|
|
||||||
isCreatingEntry: false,
|
|
||||||
layout: { uid: 'api::articles:articles' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const { queryByRole } = setup();
|
|
||||||
const select = queryByRole('combobox');
|
|
||||||
|
|
||||||
expect(select).toBeInTheDocument();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders a select input, if a workflow stage is assigned to the entity', async () => {
|
it('renders a select input, if a workflow stage is assigned to the entity', async () => {
|
||||||
useCMEditViewDataManager.mockReturnValue({
|
const { queryByRole, getByTestId, getByText, user } = setup();
|
||||||
initialData: {
|
|
||||||
[STAGE_ATTRIBUTE_NAME]: STAGE_1_STATE_FIXTURE,
|
await waitForElementToBeRemoved(() => getByTestId('loader'));
|
||||||
},
|
|
||||||
isCreatingEntry: false,
|
await waitFor(() => expect(getByText('Stage 1')).toBeInTheDocument());
|
||||||
layout: { uid: 'api::articles:articles' },
|
|
||||||
|
await user.click(queryByRole('combobox'));
|
||||||
|
|
||||||
|
await waitFor(() => expect(getByText('Stage 2')).toBeInTheDocument());
|
||||||
});
|
});
|
||||||
|
|
||||||
const { queryByRole, queryByTestId, getByText, user } = setup();
|
it("renders the select as disabled with a hint, if there aren't any stages", async () => {
|
||||||
|
server.use(
|
||||||
|
rest.get('*/content-manager/:kind/:uid/:id/stages', (req, res, ctx) => {
|
||||||
|
return res.once(ctx.json({ data: [] }));
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
await waitFor(() => expect(queryByTestId('loader')).not.toBeInTheDocument());
|
const { queryByRole, getByText, getByTestId } = setup();
|
||||||
|
|
||||||
const select = queryByRole('combobox');
|
await waitForElementToBeRemoved(() => getByTestId('loader'));
|
||||||
|
|
||||||
expect(getByText('Stage 1')).toBeInTheDocument();
|
await waitFor(() => expect(queryByRole('combobox')).toHaveAttribute('aria-disabled', 'true'));
|
||||||
|
await waitFor(() =>
|
||||||
await user.click(select);
|
expect(getByText('You don’t have the permission to update this stage.')).toBeInTheDocument()
|
||||||
|
);
|
||||||
expect(getByText('Stage 2')).toBeInTheDocument();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -0,0 +1,108 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { renderHook, waitFor } from '@testing-library/react';
|
||||||
|
import { rest } from 'msw';
|
||||||
|
import { setupServer } from 'msw/node';
|
||||||
|
import { IntlProvider } from 'react-intl';
|
||||||
|
import { QueryClient, QueryClientProvider } from 'react-query';
|
||||||
|
|
||||||
|
import { useReviewWorkflows } from '../useReviewWorkflows';
|
||||||
|
|
||||||
|
const server = setupServer(
|
||||||
|
rest.get(
|
||||||
|
'*/content-manager/collection-types/api::collection.collection/stages',
|
||||||
|
(req, res, ctx) =>
|
||||||
|
res(
|
||||||
|
ctx.json({
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'Todo',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'Done',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
meta: {
|
||||||
|
workflowCount: 10,
|
||||||
|
stagesCount: 5,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
rest.get('*/content-manager/single-types/api::single.single/stages', (req, res, ctx) =>
|
||||||
|
res(
|
||||||
|
ctx.json({
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'Todo',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: 'Done',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
meta: {
|
||||||
|
workflowCount: 10,
|
||||||
|
stagesCount: 5,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const setup = (...args) =>
|
||||||
|
renderHook(() => useReviewWorkflows(...args), {
|
||||||
|
wrapper({ children }) {
|
||||||
|
const client = new QueryClient({
|
||||||
|
defaultOptions: {
|
||||||
|
queries: {
|
||||||
|
retry: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<QueryClientProvider client={client}>
|
||||||
|
<IntlProvider locale="en" messages={{}}>
|
||||||
|
{children}
|
||||||
|
</IntlProvider>
|
||||||
|
</QueryClientProvider>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('useReviewWorkflows', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
server.listen();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
server.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('fetches many workflows', async () => {
|
||||||
|
const { result } = setup();
|
||||||
|
|
||||||
|
await waitFor(() => result.current.isLoading === false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('fetches one workflow', async () => {
|
||||||
|
const { result } = setup({ id: 1 });
|
||||||
|
|
||||||
|
await waitFor(() => result.current.isLoading === false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('forwards all params except "id" as query params', async () => {
|
||||||
|
const { result } = setup({ id: 1 });
|
||||||
|
|
||||||
|
await waitFor(() => result.current.isLoading === false);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,136 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { renderHook, waitFor } from '@testing-library/react';
|
||||||
|
import { rest } from 'msw';
|
||||||
|
import { setupServer } from 'msw/node';
|
||||||
|
import { IntlProvider } from 'react-intl';
|
||||||
|
import { QueryClient, QueryClientProvider } from 'react-query';
|
||||||
|
|
||||||
|
import { useReviewWorkflowsStages } from '../useReviewWorkflowsStages';
|
||||||
|
|
||||||
|
const server = setupServer(
|
||||||
|
...[
|
||||||
|
rest.get('*/content-manager/collection-types/:uid/:id/stages', (req, res, ctx) =>
|
||||||
|
res(
|
||||||
|
ctx.json({
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'Default',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
meta: {
|
||||||
|
workflowCount: 10,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
rest.get('*/content-manager/single-types/:uid/:id/stages', (req, res, ctx) =>
|
||||||
|
res(
|
||||||
|
ctx.json({
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'Default',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
meta: {
|
||||||
|
workflowCount: 10,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
const setup = (...args) =>
|
||||||
|
renderHook(() => useReviewWorkflowsStages(...args), {
|
||||||
|
wrapper({ children }) {
|
||||||
|
const client = new QueryClient({
|
||||||
|
defaultOptions: {
|
||||||
|
queries: {
|
||||||
|
retry: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<QueryClientProvider client={client}>
|
||||||
|
<IntlProvider locale="en" messages={{}}>
|
||||||
|
{children}
|
||||||
|
</IntlProvider>
|
||||||
|
</QueryClientProvider>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('useReviewWorkflowsStages', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
server.listen();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
server.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('fetches stages for collection-types', async () => {
|
||||||
|
const { result } = setup({
|
||||||
|
id: 1,
|
||||||
|
layout: {
|
||||||
|
uid: 'api::collection.collection',
|
||||||
|
kind: 'collectionType',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => expect(result.current.stages).toStrictEqual([]));
|
||||||
|
await waitFor(() => expect(result.current.meta).toStrictEqual({}));
|
||||||
|
|
||||||
|
await waitFor(() => result.current.isLoading === false);
|
||||||
|
|
||||||
|
expect(result.current.stages).toStrictEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: 1,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result.current.meta).toStrictEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
workflowCount: expect.any(Number),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('fetches stages for single-types', async () => {
|
||||||
|
const { result } = setup({
|
||||||
|
id: 1,
|
||||||
|
layout: {
|
||||||
|
uid: 'api::single.single',
|
||||||
|
kind: 'singleType',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => expect(result.current.stages).toStrictEqual([]));
|
||||||
|
await waitFor(() => expect(result.current.meta).toStrictEqual({}));
|
||||||
|
|
||||||
|
await waitFor(() => result.current.isLoading === false);
|
||||||
|
|
||||||
|
expect(result.current.stages).toStrictEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: 1,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result.current.meta).toStrictEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
workflowCount: expect.any(Number),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { useFetchClient } from '@strapi/helper-plugin';
|
||||||
|
import { useQuery } from 'react-query';
|
||||||
|
|
||||||
|
export function useReviewWorkflowsStages({ id, layout } = {}, queryOptions = {}) {
|
||||||
|
const { kind, uid } = layout;
|
||||||
|
const slug = kind === 'collectionType' ? 'collection-types' : 'single-types';
|
||||||
|
|
||||||
|
const { get } = useFetchClient();
|
||||||
|
|
||||||
|
const { data, isLoading } = useQuery(
|
||||||
|
['content-manager', slug, layout.uid, id, 'stages'],
|
||||||
|
async () => {
|
||||||
|
const { data } = await get(`/admin/content-manager/${slug}/${uid}/${id}/stages`);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryOptions
|
||||||
|
);
|
||||||
|
|
||||||
|
// these return values need to be memoized, because the default value
|
||||||
|
// would lead to infinite rendering loops when used in a dependency array
|
||||||
|
// on an effect
|
||||||
|
const meta = React.useMemo(() => data?.meta ?? {}, [data?.meta]);
|
||||||
|
const stages = React.useMemo(() => data?.data ?? [], [data?.data]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
// meta contains e.g. the total of all workflows. we can not use
|
||||||
|
// the pagination object here, because the list is not paginated.
|
||||||
|
meta,
|
||||||
|
stages,
|
||||||
|
isLoading,
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user