1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-04-24 01:18:01 +02:00

chore: release plan replacement UI (#9400)

This commit is contained in:
Nuno Góis 2025-02-28 13:14:34 +00:00 committed by GitHub
parent da91ae6afe
commit 8d0820fc8b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 122 additions and 49 deletions

View File

@ -1,5 +1,5 @@
import type React from 'react';
import type { FC, ReactNode } from 'react';
import { useRef, useState, type FC, type ReactNode } from 'react';
import { Box, styled, Typography } from '@mui/material';
import type {
ChangeRequestState,
@ -13,6 +13,7 @@ import { TooltipLink } from 'component/common/TooltipLink/TooltipLink';
import EventDiff from 'component/events/EventDiff/EventDiff';
import { ReleasePlan } from 'component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlan';
import { ReleasePlanMilestone } from 'component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlanMilestone/ReleasePlanMilestone';
import type { IReleasePlan } from 'interfaces/releasePlans';
export const ChangeItemWrapper = styled(Box)({
display: 'flex',
@ -55,26 +56,10 @@ const StyledCodeSection = styled('div')(({ theme }) => ({
const DeleteReleasePlan: FC<{
change: IChangeRequestDeleteReleasePlan;
environmentName: string;
featureName: string;
projectId: string;
currentReleasePlan?: IReleasePlan;
changeRequestState: ChangeRequestState;
actions?: ReactNode;
}> = ({
change,
environmentName,
featureName,
projectId,
changeRequestState,
actions,
}) => {
const { releasePlans } = useReleasePlans(
projectId,
featureName,
environmentName,
);
const currentReleasePlan = releasePlans[0];
}> = ({ change, currentReleasePlan, changeRequestState, actions }) => {
const releasePlan =
changeRequestState === 'Applied' && change.payload.snapshot
? change.payload.snapshot
@ -104,26 +89,10 @@ const DeleteReleasePlan: FC<{
const StartMilestone: FC<{
change: IChangeRequestStartMilestone;
environmentName: string;
featureName: string;
projectId: string;
currentReleasePlan?: IReleasePlan;
changeRequestState: ChangeRequestState;
actions?: ReactNode;
}> = ({
change,
environmentName,
featureName,
projectId,
changeRequestState,
actions,
}) => {
const { releasePlans } = useReleasePlans(
projectId,
featureName,
environmentName,
);
const currentReleasePlan = releasePlans[0];
}> = ({ change, currentReleasePlan, changeRequestState, actions }) => {
const releasePlan =
changeRequestState === 'Applied' && change.payload.snapshot
? change.payload.snapshot
@ -177,24 +146,107 @@ const StartMilestone: FC<{
const AddReleasePlan: FC<{
change: IChangeRequestAddReleasePlan;
currentReleasePlan?: IReleasePlan;
environmentName: string;
featureName: string;
actions?: ReactNode;
}> = ({ change, environmentName, featureName, actions }) => {
}> = ({
change,
currentReleasePlan,
environmentName,
featureName,
actions,
}) => {
const [currentTooltipOpen, setCurrentTooltipOpen] = useState(false);
const currentTooltipCloseTimeoutRef = useRef<NodeJS.Timeout>();
const openCurrentTooltip = () => {
if (currentTooltipCloseTimeoutRef.current) {
clearTimeout(currentTooltipCloseTimeoutRef.current);
}
setCurrentTooltipOpen(true);
};
const closeCurrentTooltip = () => {
currentTooltipCloseTimeoutRef.current = setTimeout(() => {
setCurrentTooltipOpen(false);
}, 100);
};
const planPreview = useReleasePlanPreview(
change.payload.templateId,
featureName,
environmentName,
);
const planPreviewDiff = {
...planPreview,
discriminator: 'plan',
releasePlanTemplateId: change.payload.templateId,
};
return (
<>
<ChangeItemCreateEditDeleteWrapper>
<ChangeItemInfo>
<Typography color='success.dark'>
+ Adding release plan:
</Typography>
{currentReleasePlan ? (
<Typography>
Replacing{' '}
<TooltipLink
tooltip={
<div
onMouseEnter={() =>
openCurrentTooltip()
}
onMouseLeave={() =>
closeCurrentTooltip()
}
>
<ReleasePlan
plan={currentReleasePlan}
readonly
/>
</div>
}
tooltipProps={{
open: currentTooltipOpen,
maxWidth: 500,
maxHeight: 600,
}}
>
<span
onMouseEnter={() => openCurrentTooltip()}
onMouseLeave={() => closeCurrentTooltip()}
>
current
</span>
</TooltipLink>{' '}
release plan with:
</Typography>
) : (
<Typography color='success.dark'>
+ Adding release plan:
</Typography>
)}
<Typography>{planPreview.name}</Typography>
{currentReleasePlan && (
<TooltipLink
tooltip={
<StyledCodeSection>
<EventDiff
entry={{
preData: currentReleasePlan,
data: planPreviewDiff,
}}
/>
</StyledCodeSection>
}
tooltipProps={{
maxWidth: 500,
maxHeight: 600,
}}
>
<ViewDiff>View Diff</ViewDiff>
</TooltipLink>
)}
</ChangeItemInfo>
<div>{actions}</div>
</ChangeItemCreateEditDeleteWrapper>
@ -221,11 +273,19 @@ export const ReleasePlanChange: FC<{
projectId,
changeRequestState,
}) => {
const { releasePlans } = useReleasePlans(
projectId,
featureName,
environmentName,
);
const currentReleasePlan = releasePlans[0];
return (
<>
{change.action === 'addReleasePlan' && (
<AddReleasePlan
change={change}
currentReleasePlan={currentReleasePlan}
environmentName={environmentName}
featureName={featureName}
actions={actions}
@ -234,9 +294,7 @@ export const ReleasePlanChange: FC<{
{change.action === 'deleteReleasePlan' && (
<DeleteReleasePlan
change={change}
environmentName={environmentName}
featureName={featureName}
projectId={projectId}
currentReleasePlan={currentReleasePlan}
changeRequestState={changeRequestState}
actions={actions}
/>
@ -244,9 +302,7 @@ export const ReleasePlanChange: FC<{
{change.action === 'startMilestone' && (
<StartMilestone
change={change}
environmentName={environmentName}
featureName={featureName}
projectId={projectId}
currentReleasePlan={currentReleasePlan}
changeRequestState={changeRequestState}
actions={actions}
/>

View File

@ -4,6 +4,7 @@ import { ReleasePlan } from './ReleasePlan';
import { useReleasePlanPreview } from 'hooks/useReleasePlanPreview';
import { styled, Typography, Alert } from '@mui/material';
import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
import { useReleasePlans } from 'hooks/api/getters/useReleasePlans/useReleasePlans';
const StyledReleasePlanContainer = styled('div')(({ theme }) => ({
margin: theme.spacing(2, 0),
@ -30,6 +31,13 @@ export const ReleasePlanAddDialog = ({
crProtected,
}: IReleasePlanAddDialogProps) => {
const { feature } = useFeature(projectId, featureName);
const { releasePlans } = useReleasePlans(
projectId,
featureName,
environment,
);
const activeReleasePlan = releasePlans[0];
const environmentData = feature?.environments.find(
({ name }) => name === environment,
@ -55,6 +63,15 @@ export const ReleasePlanAddDialog = ({
onClick={onConfirm}
onClose={() => setOpen(false)}
>
{activeReleasePlan && (
<Alert severity='error' sx={{ mb: 1 }}>
This feature environment currently has{' '}
<strong>{activeReleasePlan.name}</strong> -{' '}
<strong>{activeReleasePlan.milestones[0].name}</strong>
{environmentEnabled ? ' running' : ' paused'}. Adding a new
release plan will replace the existing release plan.
</Alert>
)}
{environmentEnabled ? (
<Alert severity='info'>
This environment is currently <strong>enabled</strong>.
@ -70,8 +87,8 @@ export const ReleasePlanAddDialog = ({
<Alert severity='warning'>
This environment is currently <strong>disabled</strong>.
<p>
The milestones will not start automatically after adding
the release plan. They will remain paused until the
Milestones will not start automatically after adding the
release plan. They will remain paused until the
environment is enabled.
</p>
</Alert>