diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ChangeRequest/CreateMilestoneProgressionChangeRequestDialog.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ChangeRequest/CreateMilestoneProgressionChangeRequestDialog.tsx deleted file mode 100644 index eeb301f306..0000000000 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ChangeRequest/CreateMilestoneProgressionChangeRequestDialog.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { Dialogue } from 'component/common/Dialogue/Dialogue'; -import { styled, Button } from '@mui/material'; -import type { IReleasePlan } from 'interfaces/releasePlans'; -import type { CreateMilestoneProgressionSchema } from 'openapi'; -import { getTimeValueAndUnitFromMinutes } from '../hooks/useMilestoneProgressionForm.js'; - -const StyledBoldSpan = styled('span')(({ theme }) => ({ - fontWeight: theme.typography.fontWeightBold, -})); - -interface ICreateMilestoneProgressionChangeRequestDialogProps { - environmentId: string; - releasePlan: IReleasePlan; - payload: CreateMilestoneProgressionSchema; - isOpen: boolean; - onConfirm: () => Promise; - onClosing: () => void; -} - -export const CreateMilestoneProgressionChangeRequestDialog = ({ - environmentId, - releasePlan, - payload, - isOpen, - onConfirm, - onClosing, -}: ICreateMilestoneProgressionChangeRequestDialogProps) => { - if (!payload) { - return null; - } - - const sourceMilestone = releasePlan.milestones.find( - (milestone) => milestone.id === payload.sourceMilestone, - ); - const targetMilestone = releasePlan.milestones.find( - (milestone) => milestone.id === payload.targetMilestone, - ); - - const { value, unit } = getTimeValueAndUnitFromMinutes( - payload.transitionCondition.intervalMinutes, - ); - const timeInterval = `${value} ${unit}`; - - return ( - - Add suggestion to draft - - } - > -

- Create automation to proceed from{' '} - {sourceMilestone?.name} to{' '} - {targetMilestone?.name} after{' '} - {timeInterval} in{' '} - {environmentId} -

-
- ); -}; diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ChangeRequest/ReleasePlanChangeRequestDialog.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ChangeRequest/ReleasePlanChangeRequestDialog.tsx new file mode 100644 index 0000000000..50849ab4f2 --- /dev/null +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ChangeRequest/ReleasePlanChangeRequestDialog.tsx @@ -0,0 +1,131 @@ +import { Dialogue } from 'component/common/Dialogue/Dialogue'; +import { styled, Button, Alert } from '@mui/material'; +import type { + IReleasePlan, + IReleasePlanMilestone, +} from 'interfaces/releasePlans'; +import type { CreateMilestoneProgressionSchema } from 'openapi'; +import { getTimeValueAndUnitFromMinutes } from '../hooks/useMilestoneProgressionForm.js'; + +const StyledBoldSpan = styled('span')(({ theme }) => ({ + fontWeight: theme.typography.fontWeightBold, +})); + +type ChangeRequestAction = + | { + type: 'removeReleasePlan'; + environmentActive: boolean; + } + | { + type: 'startMilestone'; + milestone: IReleasePlanMilestone; + } + | { + type: 'createMilestoneProgression'; + payload: CreateMilestoneProgressionSchema; + }; + +interface IReleasePlanChangeRequestDialogProps { + featureId: string; + environmentId: string; + releasePlan: IReleasePlan; + action: ChangeRequestAction | null; + isOpen: boolean; + onConfirm: () => Promise; + onClose: () => void; +} + +export const ReleasePlanChangeRequestDialog = ({ + featureId, + environmentId, + releasePlan, + action, + isOpen, + onConfirm, + onClose, +}: IReleasePlanChangeRequestDialogProps) => { + if (!action) return null; + + const renderContent = () => { + switch (action.type) { + case 'removeReleasePlan': + return ( + <> + {action.environmentActive && ( + + This release plan currently has one active + milestone. Removing the release plan will change + which users receive access to the feature. + + )} +

+ Remove release plan{' '} + {releasePlan.name}{' '} + from {featureId} in{' '} + {environmentId} +

+ + ); + + case 'startMilestone': + return ( +

+ Start milestone{' '} + {action.milestone.name}{' '} + in release plan{' '} + {releasePlan.name} for{' '} + {featureId} in{' '} + {environmentId} +

+ ); + + case 'createMilestoneProgression': { + const sourceMilestone = releasePlan.milestones.find( + (milestone) => + milestone.id === action.payload.sourceMilestone, + ); + const targetMilestone = releasePlan.milestones.find( + (milestone) => + milestone.id === action.payload.targetMilestone, + ); + + const { value, unit } = getTimeValueAndUnitFromMinutes( + action.payload.transitionCondition.intervalMinutes, + ); + const timeInterval = `${value} ${unit}`; + + return ( +

+ Create automation to proceed from{' '} + {sourceMilestone?.name}{' '} + to{' '} + {targetMilestone?.name}{' '} + after {timeInterval} in{' '} + {environmentId} +

+ ); + } + } + }; + + return ( + + Add suggestion to draft + + } + > + {renderContent()} + + ); +}; diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ChangeRequest/RemoveReleasePlanChangeRequestDialog.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ChangeRequest/RemoveReleasePlanChangeRequestDialog.tsx deleted file mode 100644 index ef7bafafd6..0000000000 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ChangeRequest/RemoveReleasePlanChangeRequestDialog.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { Dialogue } from 'component/common/Dialogue/Dialogue'; -import { styled, Button, Alert } from '@mui/material'; -import type { IReleasePlan } from 'interfaces/releasePlans'; - -const StyledBoldSpan = styled('span')(({ theme }) => ({ - fontWeight: theme.typography.fontWeightBold, -})); - -interface IRemoveReleasePlanChangeRequestDialogProps { - featureId: string; - environmentId: string; - releasePlan?: IReleasePlan | undefined; - environmentActive: boolean; - isOpen: boolean; - onConfirm: () => Promise; - onClosing: () => void; -} - -export const RemoveReleasePlanChangeRequestDialog = ({ - featureId, - environmentId, - releasePlan, - environmentActive, - isOpen, - onConfirm, - onClosing, -}: IRemoveReleasePlanChangeRequestDialogProps) => { - return ( - - Add suggestion to draft - - } - > - <> - {environmentActive && ( - - This release plan currently has one active milestone. - Removing the release plan will change which users - receive access to the feature. - - )} -

- Remove release plan{' '} - {releasePlan?.name} from{' '} - {featureId} in{' '} - {environmentId} -

- -
- ); -}; diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ChangeRequest/StartMilestoneChangeRequestDialog.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ChangeRequest/StartMilestoneChangeRequestDialog.tsx deleted file mode 100644 index e14d718bf3..0000000000 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ChangeRequest/StartMilestoneChangeRequestDialog.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { Dialogue } from 'component/common/Dialogue/Dialogue'; -import { styled, Button } from '@mui/material'; -import type { - IReleasePlan, - IReleasePlanMilestone, -} from 'interfaces/releasePlans'; - -const StyledBoldSpan = styled('span')(({ theme }) => ({ - fontWeight: theme.typography.fontWeightBold, -})); - -interface IStartMilestoneChangeRequestDialogProps { - featureId: string; - environmentId: string; - releasePlan?: IReleasePlan | undefined; - milestone?: IReleasePlanMilestone | undefined; - isOpen: boolean; - onConfirm: () => Promise; - onClosing: () => void; -} - -export const StartMilestoneChangeRequestDialog = ({ - featureId, - environmentId, - releasePlan, - milestone, - isOpen, - onConfirm, - onClosing, -}: IStartMilestoneChangeRequestDialogProps) => { - return ( - - Add suggestion to draft - - } - > -

- Start milestone{' '} - {milestone?.name} in release - plan {releasePlan?.name} for{' '} - {featureId} in{' '} - {environmentId} -

-
- ); -}; diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlan.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlan.tsx index 99b1a89f58..03a83a3e37 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlan.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlan.tsx @@ -18,9 +18,7 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled'; import { useChangeRequestApi } from 'hooks/api/actions/useChangeRequestApi/useChangeRequestApi'; import { usePendingChangeRequests } from 'hooks/api/getters/usePendingChangeRequests/usePendingChangeRequests'; -import { RemoveReleasePlanChangeRequestDialog } from './ChangeRequest/RemoveReleasePlanChangeRequestDialog.tsx'; -import { StartMilestoneChangeRequestDialog } from './ChangeRequest/StartMilestoneChangeRequestDialog.tsx'; -import { CreateMilestoneProgressionChangeRequestDialog } from './ChangeRequest/CreateMilestoneProgressionChangeRequestDialog.tsx'; +import { ReleasePlanChangeRequestDialog } from './ChangeRequest/ReleasePlanChangeRequestDialog.tsx'; import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; import { Truncator } from 'component/common/Truncator/Truncator'; import { useUiFlag } from 'hooks/useUiFlag'; @@ -119,22 +117,15 @@ export const ReleasePlan = ({ const { trackEvent } = usePlausibleTracker(); const [removeOpen, setRemoveOpen] = useState(false); - const [changeRequestDialogRemoveOpen, setChangeRequestDialogRemoveOpen] = - useState(false); - const [ - changeRequestDialogStartMilestoneOpen, - setChangeRequestDialogStartMilestoneOpen, - ] = useState(false); - const [ - changeRequestDialogCreateProgressionOpen, - setChangeRequestDialogCreateProgressionOpen, - ] = useState(false); - const [ - milestoneForChangeRequestDialog, - setMilestoneForChangeRequestDialog, - ] = useState(); - const [progressionDataForCR, setProgressionDataForCR] = - useState(null); + const [changeRequestAction, setChangeRequestAction] = useState< + | { type: 'removeReleasePlan'; environmentActive: boolean } + | { type: 'startMilestone'; milestone: IReleasePlanMilestone } + | { + type: 'createMilestoneProgression'; + payload: CreateMilestoneProgressionSchema; + } + | null + >(null); const { isChangeRequestConfigured } = useChangeRequestsEnabled(projectId); const { addChange } = useChangeRequestApi(); const { refetch: refetchChangeRequests } = @@ -147,14 +138,40 @@ export const ReleasePlan = ({ useState(null); const [isDeletingProgression, setIsDeletingProgression] = useState(false); - const onAddRemovePlanChangesConfirm = async () => { - await addChange(projectId, environment, { - feature: featureName, - action: 'deleteReleasePlan', - payload: { - planId: plan.id, - }, - }); + const onChangeRequestConfirm = async () => { + if (!changeRequestAction) return; + + switch (changeRequestAction.type) { + case 'removeReleasePlan': + await addChange(projectId, environment, { + feature: featureName, + action: 'deleteReleasePlan', + payload: { + planId: plan.id, + }, + }); + break; + + case 'startMilestone': + await addChange(projectId, environment, { + feature: featureName, + action: 'startMilestone', + payload: { + planId: plan.id, + milestoneId: changeRequestAction.milestone.id, + }, + }); + break; + + case 'createMilestoneProgression': + await addChange(projectId, environment, { + feature: featureName, + action: 'createMilestoneProgression', + payload: changeRequestAction.payload, + }); + setProgressionFormOpenIndex(null); + break; + } await refetchChangeRequests(); @@ -163,53 +180,15 @@ export const ReleasePlan = ({ text: 'Added to draft', }); - setChangeRequestDialogRemoveOpen(false); - }; - - const onAddStartMilestoneChangesConfirm = async () => { - await addChange(projectId, environment, { - feature: featureName, - action: 'startMilestone', - payload: { - planId: plan.id, - milestoneId: milestoneForChangeRequestDialog?.id, - }, - }); - - await refetchChangeRequests(); - - setToastData({ - type: 'success', - text: 'Added to draft', - }); - - setChangeRequestDialogStartMilestoneOpen(false); - }; - - const onAddCreateProgressionChangesConfirm = async () => { - if (!progressionDataForCR) return; - - await addChange(projectId, environment, { - feature: featureName, - action: 'createMilestoneProgression', - payload: progressionDataForCR, - }); - - await refetchChangeRequests(); - - setToastData({ - type: 'success', - text: 'Added to draft', - }); - - setChangeRequestDialogCreateProgressionOpen(false); - setProgressionFormOpenIndex(null); - setProgressionDataForCR(null); + setChangeRequestAction(null); }; const confirmRemoveReleasePlan = () => { if (isChangeRequestConfigured(environment)) { - setChangeRequestDialogRemoveOpen(true); + setChangeRequestAction({ + type: 'removeReleasePlan', + environmentActive: !environmentIsDisabled, + }); } else { setRemoveOpen(true); } @@ -244,8 +223,10 @@ export const ReleasePlan = ({ const onStartMilestone = async (milestone: IReleasePlanMilestone) => { if (isChangeRequestConfigured(environment)) { - setMilestoneForChangeRequestDialog(milestone); - setChangeRequestDialogStartMilestoneOpen(true); + setChangeRequestAction({ + type: 'startMilestone', + milestone, + }); } else { try { await startReleasePlanMilestone( @@ -286,8 +267,10 @@ export const ReleasePlan = ({ const handleProgressionChangeRequestSubmit = ( payload: CreateMilestoneProgressionSchema, ) => { - setProgressionDataForCR(payload); - setChangeRequestDialogCreateProgressionOpen(true); + setChangeRequestAction({ + type: 'createMilestoneProgression', + payload, + }); }; const handleDeleteProgression = (milestone: IReleasePlanMilestone) => { @@ -437,40 +420,15 @@ export const ReleasePlan = ({ onConfirm={onRemoveConfirm} environmentActive={!environmentIsDisabled} /> - setChangeRequestDialogRemoveOpen(false)} - releasePlan={plan} - environmentActive={!environmentIsDisabled} - /> - { - setMilestoneForChangeRequestDialog(undefined); - setChangeRequestDialogStartMilestoneOpen(false); - }} releasePlan={plan} - milestone={milestoneForChangeRequestDialog} + action={changeRequestAction} + isOpen={changeRequestAction !== null} + onConfirm={onChangeRequestConfirm} + onClose={() => setChangeRequestAction(null)} /> - {progressionDataForCR && ( - { - setChangeRequestDialogCreateProgressionOpen(false); - setProgressionDataForCR(null); - }} - releasePlan={plan} - payload={progressionDataForCR} - /> - )} {milestoneToDeleteProgression && (