mirror of
https://github.com/Unleash/unleash.git
synced 2025-10-27 11:02:16 +01:00
feat: add change request support for updating milestone progressions (#10819)
This commit is contained in:
parent
022226dd43
commit
795b674133
@ -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';
|
||||
|
||||
@ -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 = ({
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
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 (
|
||||
<p>
|
||||
Update automation for{' '}
|
||||
<StyledBoldSpan>{milestone?.name}</StyledBoldSpan> to
|
||||
proceed after{' '}
|
||||
<StyledBoldSpan>{timeInterval}</StyledBoldSpan> in{' '}
|
||||
{environmentId}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -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}
|
||||
/>
|
||||
|
||||
@ -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}
|
||||
/>
|
||||
) : (
|
||||
<StyledAddAutomationButton
|
||||
|
||||
@ -11,6 +11,8 @@ import {
|
||||
useMilestoneProgressionForm,
|
||||
getTimeValueAndUnitFromMinutes,
|
||||
} from '../hooks/useMilestoneProgressionForm.js';
|
||||
import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
|
||||
import type { UpdateMilestoneProgressionSchema } from 'openapi';
|
||||
|
||||
const StyledDisplayContainer = styled('div')(({ theme }) => ({
|
||||
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',
|
||||
|
||||
@ -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
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</StyledMilestoneContainer>
|
||||
@ -283,6 +292,9 @@ export const ReleasePlanMilestone = ({
|
||||
featureName={featureName}
|
||||
sourceMilestoneId={milestone.id}
|
||||
onUpdate={onUpdate}
|
||||
onUpdateChangeRequestSubmit={
|
||||
onUpdateChangeRequestSubmit
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</StyledMilestoneContainer>
|
||||
|
||||
@ -22,7 +22,8 @@ export interface IChangeSchema {
|
||||
| 'addReleasePlan'
|
||||
| 'deleteReleasePlan'
|
||||
| 'startMilestone'
|
||||
| 'createMilestoneProgression';
|
||||
| 'createMilestoneProgression'
|
||||
| 'updateMilestoneProgression';
|
||||
payload: string | boolean | object | number | undefined;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user