mirror of
https://github.com/strapi/strapi.git
synced 2025-11-03 11:25:17 +00:00
Enhancement: Combine content-type reassignment + stage prompts
This commit is contained in:
parent
37d0f58de2
commit
9c8d157f5d
@ -1,15 +1,37 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { Grid, GridItem, MultiSelectNested, TextInput } from '@strapi/design-system';
|
||||
import {
|
||||
Grid,
|
||||
GridItem,
|
||||
MultiSelect,
|
||||
MultiSelectGroup,
|
||||
MultiSelectOption,
|
||||
TextInput,
|
||||
Typography,
|
||||
} from '@strapi/design-system';
|
||||
import { useCollator } from '@strapi/helper-plugin';
|
||||
import { useField } from 'formik';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { updateWorkflow } from '../../actions';
|
||||
|
||||
export function WorkflowAttributes({ canUpdate, contentTypes: { collectionTypes, singleTypes } }) {
|
||||
const NestedOption = styled(MultiSelectOption)`
|
||||
padding-left: ${({ theme }) => theme.spaces[7]};
|
||||
`;
|
||||
|
||||
const ContentTypeTakeNotice = styled(Typography)`
|
||||
font-style: italic;
|
||||
`;
|
||||
|
||||
export function WorkflowAttributes({
|
||||
canUpdate,
|
||||
contentTypes: { collectionTypes, singleTypes },
|
||||
currentWorkflow,
|
||||
workflows,
|
||||
}) {
|
||||
const { formatMessage, locale } = useIntl();
|
||||
const dispatch = useDispatch();
|
||||
const [nameField, nameMeta, nameHelper] = useField('name');
|
||||
@ -39,7 +61,7 @@ export function WorkflowAttributes({ canUpdate, contentTypes: { collectionTypes,
|
||||
</GridItem>
|
||||
|
||||
<GridItem col={6}>
|
||||
<MultiSelectNested
|
||||
<MultiSelect
|
||||
{...contentTypesField}
|
||||
customizeContent={(value) =>
|
||||
formatMessage(
|
||||
@ -62,7 +84,12 @@ export function WorkflowAttributes({ canUpdate, contentTypes: { collectionTypes,
|
||||
dispatch(updateWorkflow({ contentTypes: values }));
|
||||
contentTypesHelper.setValue(values);
|
||||
}}
|
||||
options={[
|
||||
placeholder={formatMessage({
|
||||
id: 'Settings.review-workflows.workflow.contentTypes.placeholder',
|
||||
defaultMessage: 'Select',
|
||||
})}
|
||||
>
|
||||
{[
|
||||
...(collectionTypes.length > 0
|
||||
? [
|
||||
{
|
||||
@ -94,12 +121,53 @@ export function WorkflowAttributes({ canUpdate, contentTypes: { collectionTypes,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
]}
|
||||
placeholder={formatMessage({
|
||||
id: 'Settings.review-workflows.workflow.contentTypes.placeholder',
|
||||
defaultMessage: 'Select',
|
||||
].map((opt) => {
|
||||
if ('children' in opt) {
|
||||
return (
|
||||
<MultiSelectGroup
|
||||
key={opt.label}
|
||||
label={opt.label}
|
||||
values={opt.children.map((child) => child.value.toString())}
|
||||
>
|
||||
{opt.children.map((child) => {
|
||||
const { name: assignedWorkflowName } =
|
||||
workflows.find(
|
||||
(workflow) =>
|
||||
((currentWorkflow && workflow.id !== currentWorkflow.id) ||
|
||||
!currentWorkflow) &&
|
||||
workflow.contentTypes.includes(child.value)
|
||||
) ?? {};
|
||||
|
||||
return (
|
||||
<NestedOption key={child.value} value={child.value}>
|
||||
{formatMessage(
|
||||
{
|
||||
id: 'Settings.review-workflows.workflow.contentTypes.assigned.notice',
|
||||
defaultMessage:
|
||||
'{label} {name, select, undefined {} other {<i>(assigned to {name} workflow)</i>}}',
|
||||
},
|
||||
{
|
||||
label: child.label,
|
||||
name: assignedWorkflowName,
|
||||
i: (...children) => (
|
||||
<ContentTypeTakeNotice>{children}</ContentTypeTakeNotice>
|
||||
),
|
||||
}
|
||||
)}
|
||||
</NestedOption>
|
||||
);
|
||||
})}
|
||||
</MultiSelectGroup>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<MultiSelectOption key={opt.value} value={opt.value}>
|
||||
{opt.label}
|
||||
</MultiSelectOption>
|
||||
);
|
||||
})}
|
||||
/>
|
||||
</MultiSelect>
|
||||
</GridItem>
|
||||
</Grid>
|
||||
);
|
||||
@ -114,6 +182,7 @@ const ContentTypeType = PropTypes.shape({
|
||||
|
||||
WorkflowAttributes.defaultProps = {
|
||||
canUpdate: true,
|
||||
currentWorkflow: undefined,
|
||||
};
|
||||
|
||||
WorkflowAttributes.propTypes = {
|
||||
@ -122,4 +191,6 @@ WorkflowAttributes.propTypes = {
|
||||
collectionTypes: PropTypes.arrayOf(ContentTypeType).isRequired,
|
||||
singleTypes: PropTypes.arrayOf(ContentTypeType).isRequired,
|
||||
}).isRequired,
|
||||
currentWorkflow: PropTypes.object,
|
||||
workflows: PropTypes.array.isRequired,
|
||||
};
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { Button, Flex, Loader } from '@strapi/design-system';
|
||||
import { Button, Flex, Loader, Typography } from '@strapi/design-system';
|
||||
import {
|
||||
ConfirmDialog,
|
||||
useAPIErrorHandler,
|
||||
useFetchClient,
|
||||
useNotification,
|
||||
@ -42,6 +43,7 @@ export function ReviewWorkflowsCreateView() {
|
||||
const permissions = useSelector(selectAdminPermissions);
|
||||
const toggleNotification = useNotification();
|
||||
const { collectionTypes, singleTypes, isLoading: isLoadingModels } = useContentTypes();
|
||||
const { isLoading: isWorkflowLoading, meta, workflows } = useReviewWorkflows();
|
||||
const {
|
||||
clientState: {
|
||||
currentWorkflow: { data: currentWorkflow, isDirty: currentWorkflowIsDirty },
|
||||
@ -52,8 +54,11 @@ export function ReviewWorkflowsCreateView() {
|
||||
} = useRBAC(permissions.settings['review-workflows']);
|
||||
const [showLimitModal, setShowLimitModal] = React.useState(false);
|
||||
const { isLoading: isLicenseLoading, getFeature } = useLicenseLimits();
|
||||
const { meta, isLoading: isWorkflowLoading } = useReviewWorkflows();
|
||||
const [initialErrors, setInitialErrors] = React.useState(null);
|
||||
const [savePrompts, setSavePrompts] = React.useState({});
|
||||
|
||||
const limits = getFeature('review-workflows');
|
||||
const contentTypesFromOtherWorkflows = workflows.flatMap((workflow) => workflow.contentTypes);
|
||||
|
||||
const { mutateAsync, isLoading } = useMutation(
|
||||
async ({ workflow }) => {
|
||||
@ -79,6 +84,8 @@ export function ReviewWorkflowsCreateView() {
|
||||
);
|
||||
|
||||
const submitForm = async () => {
|
||||
setSavePrompts({});
|
||||
|
||||
try {
|
||||
const workflow = await mutateAsync({ workflow: currentWorkflow });
|
||||
|
||||
@ -110,13 +117,23 @@ export function ReviewWorkflowsCreateView() {
|
||||
}
|
||||
};
|
||||
|
||||
const limits = getFeature('review-workflows');
|
||||
const handleConfirmDeleteDialog = async () => {
|
||||
await submitForm();
|
||||
};
|
||||
|
||||
const handleConfirmClose = () => {
|
||||
setSavePrompts({});
|
||||
};
|
||||
|
||||
const formik = useFormik({
|
||||
enableReinitialize: true,
|
||||
initialErrors,
|
||||
initialValues: currentWorkflow,
|
||||
async onSubmit() {
|
||||
const isContentTypeReassignment = currentWorkflow.contentTypes.some((contentType) =>
|
||||
contentTypesFromOtherWorkflows.includes(contentType)
|
||||
);
|
||||
|
||||
/**
|
||||
* If the current license has a limit, check if the total count of workflows
|
||||
* exceeds that limit and display the limits modal instead of sending the
|
||||
@ -140,6 +157,8 @@ export function ReviewWorkflowsCreateView() {
|
||||
parseInt(limits[CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME], 10)
|
||||
) {
|
||||
setShowLimitModal('stage');
|
||||
} else if (isContentTypeReassignment) {
|
||||
setSavePrompts((prev) => ({ ...prev, hasReassignedContentTypes: true }));
|
||||
} else {
|
||||
submitForm();
|
||||
}
|
||||
@ -243,7 +262,10 @@ export function ReviewWorkflowsCreateView() {
|
||||
</Loader>
|
||||
) : (
|
||||
<Flex alignItems="stretch" direction="column" gap={7}>
|
||||
<WorkflowAttributes contentTypes={{ collectionTypes, singleTypes }} />
|
||||
<WorkflowAttributes
|
||||
contentTypes={{ collectionTypes, singleTypes }}
|
||||
workflows={workflows}
|
||||
/>
|
||||
<Stages stages={formik.values?.stages} />
|
||||
</Flex>
|
||||
)}
|
||||
@ -252,6 +274,41 @@ export function ReviewWorkflowsCreateView() {
|
||||
</Form>
|
||||
</FormikProvider>
|
||||
|
||||
<ConfirmDialog.Root
|
||||
isConfirmButtonLoading={isLoading}
|
||||
isOpen={Object.keys(savePrompts).length > 0}
|
||||
onToggleDialog={handleConfirmClose}
|
||||
onConfirm={handleConfirmDeleteDialog}
|
||||
>
|
||||
<ConfirmDialog.Body>
|
||||
<Flex direction="column" gap={5}>
|
||||
{savePrompts.hasReassignedContentTypes && (
|
||||
<Typography textAlign="center" variant="omega">
|
||||
{formatMessage(
|
||||
{
|
||||
id: 'Settings.review-workflows.page.delete.confirm.contentType.body',
|
||||
defaultMessage:
|
||||
'{count} {count, plural, one {content-type} other {content-types}} {count, plural, one {is} other {are}} already mapped to {count, plural, one {another workflow} other {other workflows}}. If you save changes, {count, plural, one {this} other {these}} {count, plural, one {content-type} other {{count} content-types}} will no more be mapped to the {count, plural, one {another workflow} other {other workflows}} and all corresponding information will be removed.',
|
||||
},
|
||||
{
|
||||
count: contentTypesFromOtherWorkflows.filter((contentType) =>
|
||||
currentWorkflow.contentTypes.includes(contentType)
|
||||
).length,
|
||||
}
|
||||
)}
|
||||
</Typography>
|
||||
)}
|
||||
|
||||
<Typography textAlign="center" variant="omega">
|
||||
{formatMessage({
|
||||
id: 'Settings.review-workflows.page.delete.confirm.confirm',
|
||||
defaultMessage: 'Are you sure you want to save?',
|
||||
})}
|
||||
</Typography>
|
||||
</Flex>
|
||||
</ConfirmDialog.Body>
|
||||
</ConfirmDialog.Root>
|
||||
|
||||
<LimitsModal.Root
|
||||
isOpen={showLimitModal === 'workflow'}
|
||||
onClose={() => setShowLimitModal(false)}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { Button, Flex, Loader } from '@strapi/design-system';
|
||||
import { Button, Flex, Loader, Typography } from '@strapi/design-system';
|
||||
import {
|
||||
ConfirmDialog,
|
||||
useAPIErrorHandler,
|
||||
@ -45,10 +45,10 @@ export function ReviewWorkflowsEditView() {
|
||||
const {
|
||||
isLoading: isWorkflowLoading,
|
||||
meta,
|
||||
workflows: [workflow],
|
||||
workflows,
|
||||
status: workflowStatus,
|
||||
refetch,
|
||||
} = useReviewWorkflows({ id: workflowId });
|
||||
} = useReviewWorkflows();
|
||||
const { collectionTypes, singleTypes, isLoading: isLoadingModels } = useContentTypes();
|
||||
const {
|
||||
status,
|
||||
@ -56,18 +56,23 @@ export function ReviewWorkflowsEditView() {
|
||||
currentWorkflow: {
|
||||
data: currentWorkflow,
|
||||
isDirty: currentWorkflowIsDirty,
|
||||
hasDeletedServerStages: currentWorkflowHasDeletedServerStages,
|
||||
hasDeletedServerStages,
|
||||
},
|
||||
},
|
||||
} = useSelector((state) => state?.[REDUX_NAMESPACE] ?? initialState);
|
||||
const {
|
||||
allowedActions: { canDelete, canUpdate },
|
||||
} = useRBAC(permissions.settings['review-workflows']);
|
||||
const [isConfirmDeleteDialogOpen, setIsConfirmDeleteDialogOpen] = React.useState(false);
|
||||
const [savePrompts, setSavePrompts] = React.useState({});
|
||||
const { getFeature, isLoading: isLicenseLoading } = useLicenseLimits();
|
||||
const [showLimitModal, setShowLimitModal] = React.useState(false);
|
||||
const [initialErrors, setInitialErrors] = React.useState(null);
|
||||
|
||||
const workflow = workflows.find((workflow) => workflow.id === parseInt(workflowId, 10));
|
||||
const contentTypesFromOtherWorkflows = workflows
|
||||
.filter((workflow) => workflow.id !== parseInt(workflowId, 10))
|
||||
.flatMap((workflow) => workflow.contentTypes);
|
||||
|
||||
const { mutateAsync, isLoading } = useMutation(
|
||||
async ({ workflow }) => {
|
||||
const {
|
||||
@ -125,15 +130,15 @@ export function ReviewWorkflowsEditView() {
|
||||
await updateWorkflow(currentWorkflow);
|
||||
await refetch();
|
||||
|
||||
setIsConfirmDeleteDialogOpen(false);
|
||||
setSavePrompts({});
|
||||
};
|
||||
|
||||
const handleConfirmDeleteDialog = async () => {
|
||||
await submitForm();
|
||||
};
|
||||
|
||||
const toggleConfirmDeleteDialog = () => {
|
||||
setIsConfirmDeleteDialogOpen((prev) => !prev);
|
||||
const handleConfirmClose = () => {
|
||||
setSavePrompts({});
|
||||
};
|
||||
|
||||
const formik = useFormik({
|
||||
@ -141,9 +146,11 @@ export function ReviewWorkflowsEditView() {
|
||||
initialErrors,
|
||||
initialValues: currentWorkflow,
|
||||
async onSubmit() {
|
||||
if (currentWorkflowHasDeletedServerStages) {
|
||||
setIsConfirmDeleteDialogOpen(true);
|
||||
} else if (
|
||||
const isContentTypeReassignment = currentWorkflow.contentTypes.some((contentType) =>
|
||||
contentTypesFromOtherWorkflows.includes(contentType)
|
||||
);
|
||||
|
||||
if (
|
||||
limits?.[CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME] &&
|
||||
meta?.workflowCount > parseInt(limits[CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME], 10)
|
||||
) {
|
||||
@ -165,6 +172,14 @@ export function ReviewWorkflowsEditView() {
|
||||
parseInt(limits[CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME], 10)
|
||||
) {
|
||||
setShowLimitModal('stage');
|
||||
} else if (hasDeletedServerStages || isContentTypeReassignment) {
|
||||
if (hasDeletedServerStages) {
|
||||
setSavePrompts((prev) => ({ ...prev, hasDeletedServerStages: true }));
|
||||
}
|
||||
|
||||
if (isContentTypeReassignment) {
|
||||
setSavePrompts((prev) => ({ ...prev, hasReassignedContentTypes: true }));
|
||||
}
|
||||
} else {
|
||||
submitForm();
|
||||
}
|
||||
@ -243,7 +258,7 @@ export function ReviewWorkflowsEditView() {
|
||||
disabled={!currentWorkflowIsDirty || !canUpdate}
|
||||
// if the confirm dialog is open the loading state is on
|
||||
// the confirm button already
|
||||
loading={!isConfirmDeleteDialogOpen && isLoading}
|
||||
loading={!Object.keys(savePrompts).length > 0 && isLoading}
|
||||
>
|
||||
{formatMessage({
|
||||
id: 'global.save',
|
||||
@ -279,6 +294,8 @@ export function ReviewWorkflowsEditView() {
|
||||
<WorkflowAttributes
|
||||
canUpdate={canUpdate}
|
||||
contentTypes={{ collectionTypes, singleTypes }}
|
||||
currentWorkflow={currentWorkflow}
|
||||
workflows={workflows}
|
||||
/>
|
||||
<Stages
|
||||
canDelete={canDelete}
|
||||
@ -291,17 +308,50 @@ export function ReviewWorkflowsEditView() {
|
||||
</Form>
|
||||
</FormikProvider>
|
||||
|
||||
<ConfirmDialog
|
||||
bodyText={{
|
||||
id: 'Settings.review-workflows.page.delete.confirm.body',
|
||||
defaultMessage:
|
||||
'All entries assigned to deleted stages will be moved to the previous stage. Are you sure you want to save?',
|
||||
}}
|
||||
<ConfirmDialog.Root
|
||||
isConfirmButtonLoading={isLoading}
|
||||
isOpen={isConfirmDeleteDialogOpen}
|
||||
onToggleDialog={toggleConfirmDeleteDialog}
|
||||
isOpen={Object.keys(savePrompts).length > 0}
|
||||
onToggleDialog={handleConfirmClose}
|
||||
onConfirm={handleConfirmDeleteDialog}
|
||||
/>
|
||||
>
|
||||
<ConfirmDialog.Body>
|
||||
<Flex direction="column" gap={5}>
|
||||
{savePrompts.hasDeletedServerStages && (
|
||||
<Typography textAlign="center" variant="omega">
|
||||
{formatMessage({
|
||||
id: 'Settings.review-workflows.page.delete.confirm.stages.body',
|
||||
defaultMessage:
|
||||
'All entries assigned to deleted stages will be moved to the previous stage.',
|
||||
})}
|
||||
</Typography>
|
||||
)}
|
||||
|
||||
{savePrompts.hasReassignedContentTypes && (
|
||||
<Typography textAlign="center" variant="omega">
|
||||
{formatMessage(
|
||||
{
|
||||
id: 'Settings.review-workflows.page.delete.confirm.contentType.body',
|
||||
defaultMessage:
|
||||
'{count} {count, plural, one {content-type} other {content-types}} {count, plural, one {is} other {are}} already mapped to {count, plural, one {another workflow} other {other workflows}}. If you save changes, {count, plural, one {this} other {these}} {count, plural, one {content-type} other {{count} content-types}} will no more be mapped to the {count, plural, one {another workflow} other {other workflows}} and all corresponding information will be removed.',
|
||||
},
|
||||
{
|
||||
count: contentTypesFromOtherWorkflows.filter((contentType) =>
|
||||
currentWorkflow.contentTypes.includes(contentType)
|
||||
).length,
|
||||
}
|
||||
)}
|
||||
</Typography>
|
||||
)}
|
||||
|
||||
<Typography textAlign="center" variant="omega">
|
||||
{formatMessage({
|
||||
id: 'Settings.review-workflows.page.delete.confirm.confirm',
|
||||
defaultMessage: 'Are you sure you want to save?',
|
||||
})}
|
||||
</Typography>
|
||||
</Flex>
|
||||
</ConfirmDialog.Body>
|
||||
</ConfirmDialog.Root>
|
||||
|
||||
<LimitsModal.Root
|
||||
isOpen={showLimitModal === 'workflow'}
|
||||
|
||||
@ -73,7 +73,7 @@ export function reducer(state = initialState, action) {
|
||||
|
||||
if (!currentWorkflow.hasDeletedServerStages) {
|
||||
draft.clientState.currentWorkflow.hasDeletedServerStages = !!(
|
||||
state.serverState.currentWorkflow?.stages ?? []
|
||||
state.serverState.workflow?.stages ?? []
|
||||
).find((stage) => stage.id === stageId);
|
||||
}
|
||||
|
||||
|
||||
@ -1,18 +1,25 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Button, Dialog, DialogBody, DialogFooter, Flex, Typography } from '@strapi/design-system';
|
||||
import {
|
||||
Button,
|
||||
Box,
|
||||
Dialog,
|
||||
DialogBody,
|
||||
DialogFooter,
|
||||
Flex,
|
||||
Typography,
|
||||
} from '@strapi/design-system';
|
||||
import { ExclamationMarkCircle, Trash } from '@strapi/icons';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
const ConfirmDialog = ({
|
||||
bodyText,
|
||||
export const Root = ({
|
||||
children,
|
||||
iconRightButton,
|
||||
iconBody,
|
||||
isConfirmButtonLoading,
|
||||
leftButtonText,
|
||||
onToggleDialog,
|
||||
onConfirm,
|
||||
onToggleDialog,
|
||||
rightButtonText,
|
||||
title,
|
||||
variantRightButton,
|
||||
@ -31,46 +38,165 @@ const ConfirmDialog = ({
|
||||
describedBy="confirm-description"
|
||||
{...props}
|
||||
>
|
||||
<DialogBody icon={iconBody}>
|
||||
<Flex direction="column" alignItems="stretch" gap={2}>
|
||||
<Flex justifyContent="center">
|
||||
<Typography variant="omega" id="confirm-description">
|
||||
{formatMessage({
|
||||
id: bodyText.id,
|
||||
defaultMessage: bodyText.defaultMessage,
|
||||
})}
|
||||
</Typography>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</DialogBody>
|
||||
<DialogFooter
|
||||
startAction={
|
||||
<Button onClick={onToggleDialog} variant="tertiary">
|
||||
{formatMessage({
|
||||
id: leftButtonText.id,
|
||||
defaultMessage: leftButtonText.defaultMessage,
|
||||
})}
|
||||
</Button>
|
||||
}
|
||||
endAction={
|
||||
<Button
|
||||
onClick={onConfirm}
|
||||
variant={variantRightButton}
|
||||
startIcon={iconRightButton}
|
||||
id="confirm-delete"
|
||||
loading={isConfirmButtonLoading}
|
||||
>
|
||||
{formatMessage({
|
||||
id: rightButtonText.id,
|
||||
defaultMessage: rightButtonText.defaultMessage,
|
||||
})}
|
||||
</Button>
|
||||
}
|
||||
<Box id="confirm-description">{children}</Box>
|
||||
|
||||
<Footer
|
||||
iconRightButton={iconRightButton}
|
||||
isConfirmButtonLoading={isConfirmButtonLoading}
|
||||
leftButtonText={leftButtonText}
|
||||
onConfirm={onConfirm}
|
||||
onToggleDialog={onToggleDialog}
|
||||
rightButtonText={rightButtonText}
|
||||
variantRightButton={variantRightButton}
|
||||
/>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
Root.defaultProps = {
|
||||
iconBody: <ExclamationMarkCircle />,
|
||||
iconRightButton: <Trash />,
|
||||
isConfirmButtonLoading: false,
|
||||
leftButtonText: {
|
||||
id: 'app.components.Button.cancel',
|
||||
defaultMessage: 'Cancel',
|
||||
},
|
||||
rightButtonText: {
|
||||
id: 'app.components.Button.confirm',
|
||||
defaultMessage: 'Confirm',
|
||||
},
|
||||
title: {
|
||||
id: 'app.components.ConfirmDialog.title',
|
||||
defaultMessage: 'Confirmation',
|
||||
},
|
||||
variantRightButton: 'danger-light',
|
||||
};
|
||||
|
||||
Root.propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
iconBody: PropTypes.node,
|
||||
iconRightButton: PropTypes.node,
|
||||
isConfirmButtonLoading: PropTypes.bool,
|
||||
onConfirm: PropTypes.func.isRequired,
|
||||
onToggleDialog: PropTypes.func.isRequired,
|
||||
leftButtonText: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
defaultMessage: PropTypes.string,
|
||||
}),
|
||||
rightButtonText: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
defaultMessage: PropTypes.string,
|
||||
}),
|
||||
title: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
defaultMessage: PropTypes.string,
|
||||
}),
|
||||
variantRightButton: PropTypes.string,
|
||||
};
|
||||
|
||||
export const Body = ({ iconBody, children }) => {
|
||||
return (
|
||||
<DialogBody icon={iconBody}>
|
||||
<Flex direction="column" alignItems="stretch" gap={2}>
|
||||
<Flex justifyContent="center">{children}</Flex>
|
||||
</Flex>
|
||||
</DialogBody>
|
||||
);
|
||||
};
|
||||
|
||||
Body.defaultProps = {
|
||||
iconBody: <ExclamationMarkCircle />,
|
||||
};
|
||||
|
||||
Body.propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
iconBody: PropTypes.node,
|
||||
};
|
||||
|
||||
const Footer = ({
|
||||
iconRightButton,
|
||||
isConfirmButtonLoading,
|
||||
leftButtonText,
|
||||
onConfirm,
|
||||
onToggleDialog,
|
||||
rightButtonText,
|
||||
variantRightButton,
|
||||
}) => {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
return (
|
||||
<DialogFooter
|
||||
startAction={
|
||||
<Button onClick={onToggleDialog} variant="tertiary">
|
||||
{formatMessage({
|
||||
id: leftButtonText.id,
|
||||
defaultMessage: leftButtonText.defaultMessage,
|
||||
})}
|
||||
</Button>
|
||||
}
|
||||
endAction={
|
||||
<Button
|
||||
onClick={onConfirm}
|
||||
variant={variantRightButton}
|
||||
startIcon={iconRightButton}
|
||||
id="confirm-delete"
|
||||
loading={isConfirmButtonLoading}
|
||||
>
|
||||
{formatMessage({
|
||||
id: rightButtonText.id,
|
||||
defaultMessage: rightButtonText.defaultMessage,
|
||||
})}
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
Footer.propTypes = {
|
||||
iconRightButton: PropTypes.node.isRequired,
|
||||
isConfirmButtonLoading: PropTypes.bool.isRequired,
|
||||
onConfirm: PropTypes.func.isRequired,
|
||||
onToggleDialog: PropTypes.func.isRequired,
|
||||
leftButtonText: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
defaultMessage: PropTypes.string,
|
||||
}).isRequired,
|
||||
rightButtonText: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
defaultMessage: PropTypes.string,
|
||||
}).isRequired,
|
||||
variantRightButton: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
const ConfirmDialog = ({
|
||||
bodyText,
|
||||
iconRightButton,
|
||||
iconBody,
|
||||
isConfirmButtonLoading,
|
||||
leftButtonText,
|
||||
onToggleDialog,
|
||||
onConfirm,
|
||||
rightButtonText,
|
||||
title,
|
||||
variantRightButton,
|
||||
...props
|
||||
}) => {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
return (
|
||||
<Root onConfirm={onConfirm} onToggleDialog={onToggleDialog} title={title} {...props}>
|
||||
<Body>
|
||||
<Typography variant="omega">
|
||||
{formatMessage({
|
||||
id: bodyText.id,
|
||||
defaultMessage: bodyText.defaultMessage,
|
||||
})}
|
||||
</Typography>
|
||||
</Body>
|
||||
</Root>
|
||||
);
|
||||
};
|
||||
|
||||
ConfirmDialog.defaultProps = {
|
||||
bodyText: {
|
||||
id: 'components.popUpWarning.message',
|
||||
@ -119,4 +245,7 @@ ConfirmDialog.propTypes = {
|
||||
variantRightButton: PropTypes.string,
|
||||
};
|
||||
|
||||
export default ConfirmDialog;
|
||||
ConfirmDialog.Root = Root;
|
||||
ConfirmDialog.Body = Body;
|
||||
|
||||
export { ConfirmDialog };
|
||||
|
||||
@ -4,7 +4,7 @@ import { lightTheme, ThemeProvider } from '@strapi/design-system';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
|
||||
import ConfirmDialog from '../index';
|
||||
import { ConfirmDialog } from '../index';
|
||||
|
||||
const App = (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
|
||||
@ -7,7 +7,7 @@ import { useIntl } from 'react-intl';
|
||||
|
||||
import { useTracking } from '../../features/Tracking';
|
||||
import useQueryParams from '../../hooks/useQueryParams';
|
||||
import ConfirmDialog from '../ConfirmDialog';
|
||||
import { ConfirmDialog } from '../ConfirmDialog';
|
||||
import EmptyBodyTable from '../EmptyBodyTable';
|
||||
|
||||
import TableHead from './TableHead';
|
||||
|
||||
@ -23,7 +23,7 @@ import { useIntl } from 'react-intl';
|
||||
|
||||
import useQueryParams from '../../hooks/useQueryParams';
|
||||
import SortIcon from '../../icons/SortIcon';
|
||||
import ConfirmDialog from '../ConfirmDialog';
|
||||
import { ConfirmDialog } from '../ConfirmDialog';
|
||||
import EmptyStateLayout from '../EmptyStateLayout';
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
|
||||
@ -7,7 +7,7 @@ import { getOtherInfos, getType } from './content-manager/utils/getAttributeInfo
|
||||
export { default as AnErrorOccurred } from './components/AnErrorOccurred';
|
||||
export { default as CheckPagePermissions } from './components/CheckPagePermissions';
|
||||
export { default as CheckPermissions } from './components/CheckPermissions';
|
||||
export { default as ConfirmDialog } from './components/ConfirmDialog';
|
||||
export * from './components/ConfirmDialog';
|
||||
export { default as ContentBox } from './components/ContentBox';
|
||||
export { default as DateTimePicker } from './components/DateTimePicker';
|
||||
export { default as DynamicTable } from './components/DynamicTable';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user