diff --git a/frontend/src/component/changeRequest/changeRequest.types.ts b/frontend/src/component/changeRequest/changeRequest.types.ts
index 04646edc5b..e12f40084c 100644
--- a/frontend/src/component/changeRequest/changeRequest.types.ts
+++ b/frontend/src/component/changeRequest/changeRequest.types.ts
@@ -5,6 +5,7 @@ import type { IUser } from '../../interfaces/user.js';
import type {
SetStrategySortOrderSchema,
CreateMilestoneProgressionSchema,
+ UpdateMilestoneProgressionSchema,
} from 'openapi';
import type { IReleasePlan } from 'interfaces/releasePlans';
@@ -135,7 +136,8 @@ type ChangeRequestPayload =
| ChangeRequestAddReleasePlan
| ChangeRequestDeleteReleasePlan
| ChangeRequestStartMilestone
- | ChangeRequestCreateMilestoneProgression;
+ | ChangeRequestCreateMilestoneProgression
+ | ChangeRequestUpdateMilestoneProgression;
export interface IChangeRequestAddStrategy extends IChangeRequestChangeBase {
action: 'addStrategy';
@@ -198,6 +200,12 @@ export interface IChangeRequestCreateMilestoneProgression
payload: ChangeRequestCreateMilestoneProgression;
}
+export interface IChangeRequestUpdateMilestoneProgression
+ extends IChangeRequestChangeBase {
+ action: 'updateMilestoneProgression';
+ payload: ChangeRequestUpdateMilestoneProgression;
+}
+
export interface IChangeRequestReorderStrategy
extends IChangeRequestChangeBase {
action: 'reorderStrategy';
@@ -246,7 +254,8 @@ export type IFeatureChange =
| IChangeRequestAddReleasePlan
| IChangeRequestDeleteReleasePlan
| IChangeRequestStartMilestone
- | IChangeRequestCreateMilestoneProgression;
+ | IChangeRequestCreateMilestoneProgression
+ | IChangeRequestUpdateMilestoneProgression;
export type ISegmentChange =
| IChangeRequestUpdateSegment
@@ -281,6 +290,11 @@ type ChangeRequestStartMilestone = {
type ChangeRequestCreateMilestoneProgression = CreateMilestoneProgressionSchema;
+type ChangeRequestUpdateMilestoneProgression =
+ UpdateMilestoneProgressionSchema & {
+ sourceMilestoneId: string;
+ };
+
export type ChangeRequestAddStrategy = Pick<
IFeatureStrategy,
| 'parameters'
@@ -319,4 +333,5 @@ export type ChangeRequestAction =
| 'addReleasePlan'
| 'deleteReleasePlan'
| 'startMilestone'
- | 'createMilestoneProgression';
+ | 'createMilestoneProgression'
+ | 'updateMilestoneProgression';
diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ChangeRequest/ReleasePlanChangeRequestDialog.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ChangeRequest/ReleasePlanChangeRequestDialog.tsx
index 50849ab4f2..5f6f2fe018 100644
--- a/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ChangeRequest/ReleasePlanChangeRequestDialog.tsx
+++ b/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ChangeRequest/ReleasePlanChangeRequestDialog.tsx
@@ -4,7 +4,10 @@ import type {
IReleasePlan,
IReleasePlanMilestone,
} from 'interfaces/releasePlans';
-import type { CreateMilestoneProgressionSchema } from 'openapi';
+import type {
+ CreateMilestoneProgressionSchema,
+ UpdateMilestoneProgressionSchema,
+} from 'openapi';
import { getTimeValueAndUnitFromMinutes } from '../hooks/useMilestoneProgressionForm.js';
const StyledBoldSpan = styled('span')(({ theme }) => ({
@@ -23,6 +26,11 @@ type ChangeRequestAction =
| {
type: 'createMilestoneProgression';
payload: CreateMilestoneProgressionSchema;
+ }
+ | {
+ type: 'updateMilestoneProgression';
+ sourceMilestoneId: string;
+ payload: UpdateMilestoneProgressionSchema;
};
interface IReleasePlanChangeRequestDialogProps {
@@ -105,6 +113,27 @@ export const ReleasePlanChangeRequestDialog = ({
);
}
+
+ case 'updateMilestoneProgression': {
+ const milestone = releasePlan.milestones.find(
+ (milestone) => milestone.id === action.sourceMilestoneId,
+ );
+
+ const { value, unit } = getTimeValueAndUnitFromMinutes(
+ action.payload.transitionCondition.intervalMinutes,
+ );
+ const timeInterval = `${value} ${unit}`;
+
+ return (
+
+ Update automation for{' '}
+ {milestone?.name} to
+ proceed after{' '}
+ {timeInterval} 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 03a83a3e37..f84d4368e5 100644
--- a/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlan.tsx
+++ b/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlan.tsx
@@ -25,7 +25,10 @@ import { useUiFlag } from 'hooks/useUiFlag';
import { MilestoneProgressionForm } from './MilestoneProgressionForm/MilestoneProgressionForm.tsx';
import { useMilestoneProgressionsApi } from 'hooks/api/actions/useMilestoneProgressionsApi/useMilestoneProgressionsApi';
import { DeleteProgressionDialog } from './DeleteProgressionDialog.tsx';
-import type { CreateMilestoneProgressionSchema } from 'openapi';
+import type {
+ CreateMilestoneProgressionSchema,
+ UpdateMilestoneProgressionSchema,
+} from 'openapi';
const StyledContainer = styled('div')(({ theme }) => ({
padding: theme.spacing(2),
@@ -124,6 +127,11 @@ export const ReleasePlan = ({
type: 'createMilestoneProgression';
payload: CreateMilestoneProgressionSchema;
}
+ | {
+ type: 'updateMilestoneProgression';
+ sourceMilestoneId: string;
+ payload: UpdateMilestoneProgressionSchema;
+ }
| null
>(null);
const { isChangeRequestConfigured } = useChangeRequestsEnabled(projectId);
@@ -171,6 +179,17 @@ export const ReleasePlan = ({
});
setProgressionFormOpenIndex(null);
break;
+
+ case 'updateMilestoneProgression':
+ await addChange(projectId, environment, {
+ feature: featureName,
+ action: 'updateMilestoneProgression',
+ payload: {
+ sourceMilestone: changeRequestAction.sourceMilestoneId,
+ ...changeRequestAction.payload,
+ },
+ });
+ break;
}
await refetchChangeRequests();
@@ -273,6 +292,17 @@ export const ReleasePlan = ({
});
};
+ const handleUpdateProgressionChangeRequestSubmit = (
+ sourceMilestoneId: string,
+ payload: UpdateMilestoneProgressionSchema,
+ ) => {
+ setChangeRequestAction({
+ type: 'updateMilestoneProgression',
+ sourceMilestoneId,
+ payload,
+ });
+ };
+
const handleDeleteProgression = (milestone: IReleasePlanMilestone) => {
setMilestoneToDeleteProgression(milestone);
};
@@ -398,6 +428,9 @@ export const ReleasePlan = ({
environment={environment}
featureName={featureName}
onUpdate={refetch}
+ onUpdateChangeRequestSubmit={
+ handleUpdateProgressionChangeRequestSubmit
+ }
allMilestones={milestones}
activeMilestoneId={activeMilestoneId}
/>
diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlanMilestone/MilestoneAutomationSection.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlanMilestone/MilestoneAutomationSection.tsx
index d3da89530c..1e13a5b9da 100644
--- a/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlanMilestone/MilestoneAutomationSection.tsx
+++ b/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlanMilestone/MilestoneAutomationSection.tsx
@@ -2,6 +2,7 @@ import Add from '@mui/icons-material/Add';
import { Button, styled } from '@mui/material';
import type { MilestoneStatus } from './ReleasePlanMilestoneStatus.tsx';
import { MilestoneTransitionDisplay } from './MilestoneTransitionDisplay.tsx';
+import type { UpdateMilestoneProgressionSchema } from 'openapi';
const StyledAutomationContainer = styled('div', {
shouldForwardProp: (prop) => prop !== 'status',
@@ -65,6 +66,10 @@ interface IMilestoneAutomationSectionProps {
featureName: string;
sourceMilestoneId: string;
onUpdate: () => void;
+ onUpdateChangeRequestSubmit?: (
+ sourceMilestoneId: string,
+ payload: UpdateMilestoneProgressionSchema,
+ ) => void;
}
export const MilestoneAutomationSection = ({
@@ -80,6 +85,7 @@ export const MilestoneAutomationSection = ({
featureName,
sourceMilestoneId,
onUpdate,
+ onUpdateChangeRequestSubmit,
}: IMilestoneAutomationSectionProps) => {
if (!showAutomation) return null;
@@ -98,6 +104,7 @@ export const MilestoneAutomationSection = ({
featureName={featureName}
sourceMilestoneId={sourceMilestoneId}
onUpdate={onUpdate}
+ onChangeRequestSubmit={onUpdateChangeRequestSubmit}
/>
) : (
({
display: 'flex',
@@ -67,6 +69,10 @@ interface IMilestoneTransitionDisplayProps {
featureName: string;
sourceMilestoneId: string;
onUpdate: () => void;
+ onChangeRequestSubmit?: (
+ sourceMilestoneId: string,
+ payload: UpdateMilestoneProgressionSchema,
+ ) => void;
}
export const MilestoneTransitionDisplay = ({
@@ -79,9 +85,11 @@ export const MilestoneTransitionDisplay = ({
featureName,
sourceMilestoneId,
onUpdate,
+ onChangeRequestSubmit,
}: IMilestoneTransitionDisplayProps) => {
const { updateMilestoneProgression } = useMilestoneProgressionsApi();
const { setToastData, setToastApiError } = useToast();
+ const { isChangeRequestConfigured } = useChangeRequestsEnabled(projectId);
const initial = getTimeValueAndUnitFromMinutes(intervalMinutes);
const form = useMilestoneProgressionForm(
@@ -100,6 +108,17 @@ export const MilestoneTransitionDisplay = ({
const handleSave = async () => {
if (isSubmitting || !hasChanged) return;
+ const payload: UpdateMilestoneProgressionSchema = {
+ transitionCondition: {
+ intervalMinutes: currentIntervalMinutes,
+ },
+ };
+
+ if (isChangeRequestConfigured(environment) && onChangeRequestSubmit) {
+ onChangeRequestSubmit(sourceMilestoneId, payload);
+ return;
+ }
+
setIsSubmitting(true);
try {
await updateMilestoneProgression(
@@ -107,11 +126,7 @@ export const MilestoneTransitionDisplay = ({
environment,
featureName,
sourceMilestoneId,
- {
- transitionCondition: {
- intervalMinutes: currentIntervalMinutes,
- },
- },
+ payload,
);
setToastData({
type: 'success',
diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlanMilestone/ReleasePlanMilestone.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlanMilestone/ReleasePlanMilestone.tsx
index 4130e1c75c..9e467ce69c 100644
--- a/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlanMilestone/ReleasePlanMilestone.tsx
+++ b/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlanMilestone/ReleasePlanMilestone.tsx
@@ -19,6 +19,7 @@ import { StrategyList } from 'component/common/StrategyList/StrategyList';
import { StrategyListItem } from 'component/common/StrategyList/StrategyListItem';
import { MilestoneAutomationSection } from './MilestoneAutomationSection.tsx';
import { formatDateYMDHMS } from 'utils/formatDate';
+import type { UpdateMilestoneProgressionSchema } from 'openapi';
const StyledAccordion = styled(Accordion, {
shouldForwardProp: (prop) => prop !== 'status' && prop !== 'hasAutomation',
@@ -107,6 +108,10 @@ interface IReleasePlanMilestoneProps {
environment?: string;
featureName?: string;
onUpdate?: () => void;
+ onUpdateChangeRequestSubmit?: (
+ sourceMilestoneId: string,
+ payload: UpdateMilestoneProgressionSchema,
+ ) => void;
allMilestones: IReleasePlanMilestone[];
activeMilestoneId?: string;
}
@@ -124,6 +129,7 @@ export const ReleasePlanMilestone = ({
environment,
featureName,
onUpdate,
+ onUpdateChangeRequestSubmit,
allMilestones,
activeMilestoneId,
}: IReleasePlanMilestoneProps) => {
@@ -193,6 +199,9 @@ export const ReleasePlanMilestone = ({
featureName={featureName}
sourceMilestoneId={milestone.id}
onUpdate={onUpdate}
+ onUpdateChangeRequestSubmit={
+ onUpdateChangeRequestSubmit
+ }
/>
)}
@@ -283,6 +292,9 @@ export const ReleasePlanMilestone = ({
featureName={featureName}
sourceMilestoneId={milestone.id}
onUpdate={onUpdate}
+ onUpdateChangeRequestSubmit={
+ onUpdateChangeRequestSubmit
+ }
/>
)}
diff --git a/frontend/src/hooks/api/actions/useChangeRequestApi/useChangeRequestApi.ts b/frontend/src/hooks/api/actions/useChangeRequestApi/useChangeRequestApi.ts
index 65b9ce1729..6430ba9aa4 100644
--- a/frontend/src/hooks/api/actions/useChangeRequestApi/useChangeRequestApi.ts
+++ b/frontend/src/hooks/api/actions/useChangeRequestApi/useChangeRequestApi.ts
@@ -22,7 +22,8 @@ export interface IChangeSchema {
| 'addReleasePlan'
| 'deleteReleasePlan'
| 'startMilestone'
- | 'createMilestoneProgression';
+ | 'createMilestoneProgression'
+ | 'updateMilestoneProgression';
payload: string | boolean | object | number | undefined;
}