mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: improve milestone visual states in release plans (#10775)
This commit is contained in:
		
							parent
							
								
									0b7c141e70
								
							
						
					
					
						commit
						4500f484ec
					
				@ -72,10 +72,14 @@ const StyledBody = styled('div')(({ theme }) => ({
 | 
				
			|||||||
    flexDirection: 'column',
 | 
					    flexDirection: 'column',
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const StyledConnection = styled('div')(({ theme }) => ({
 | 
					const StyledConnection = styled('div', {
 | 
				
			||||||
    width: 4,
 | 
					    shouldForwardProp: (prop) => prop !== 'isCompleted',
 | 
				
			||||||
 | 
					})<{ isCompleted: boolean }>(({ theme, isCompleted }) => ({
 | 
				
			||||||
 | 
					    width: 2,
 | 
				
			||||||
    height: theme.spacing(2),
 | 
					    height: theme.spacing(2),
 | 
				
			||||||
    backgroundColor: theme.palette.divider,
 | 
					    backgroundColor: isCompleted
 | 
				
			||||||
 | 
					        ? theme.palette.divider
 | 
				
			||||||
 | 
					        : theme.palette.primary.main,
 | 
				
			||||||
    marginLeft: theme.spacing(3.25),
 | 
					    marginLeft: theme.spacing(3.25),
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -367,7 +371,11 @@ export const ReleasePlan = ({
 | 
				
			|||||||
                            />
 | 
					                            />
 | 
				
			||||||
                            <ConditionallyRender
 | 
					                            <ConditionallyRender
 | 
				
			||||||
                                condition={isNotLastMilestone}
 | 
					                                condition={isNotLastMilestone}
 | 
				
			||||||
                                show={<StyledConnection />}
 | 
					                                show={
 | 
				
			||||||
 | 
					                                    <StyledConnection
 | 
				
			||||||
 | 
					                                        isCompleted={index < activeIndex}
 | 
				
			||||||
 | 
					                                    />
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
                            />
 | 
					                            />
 | 
				
			||||||
                        </div>
 | 
					                        </div>
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
 | 
				
			|||||||
@ -6,11 +6,14 @@ import { MilestoneTransitionDisplay } from './MilestoneTransitionDisplay.tsx';
 | 
				
			|||||||
const StyledAutomationContainer = styled('div', {
 | 
					const StyledAutomationContainer = styled('div', {
 | 
				
			||||||
    shouldForwardProp: (prop) => prop !== 'status',
 | 
					    shouldForwardProp: (prop) => prop !== 'status',
 | 
				
			||||||
})<{ status?: MilestoneStatus }>(({ theme, status }) => ({
 | 
					})<{ status?: MilestoneStatus }>(({ theme, status }) => ({
 | 
				
			||||||
    border: `1px solid ${status === 'active' ? theme.palette.success.border : theme.palette.divider}`,
 | 
					    border: `${status === 'active' ? '1.25px' : '1px'} solid ${status === 'active' ? theme.palette.success.border : theme.palette.divider}`,
 | 
				
			||||||
    borderTop: `1px solid ${theme.palette.divider}`,
 | 
					    borderTop: `1px solid ${theme.palette.divider}`,
 | 
				
			||||||
    borderRadius: `0 0 ${theme.shape.borderRadiusLarge}px ${theme.shape.borderRadiusLarge}px`,
 | 
					    borderRadius: `0 0 ${theme.shape.borderRadiusLarge}px ${theme.shape.borderRadiusLarge}px`,
 | 
				
			||||||
    padding: theme.spacing(1.5, 2),
 | 
					    padding: theme.spacing(1.5, 2),
 | 
				
			||||||
    backgroundColor: theme.palette.background.paper,
 | 
					    backgroundColor:
 | 
				
			||||||
 | 
					        status === 'completed'
 | 
				
			||||||
 | 
					            ? theme.palette.background.default
 | 
				
			||||||
 | 
					            : theme.palette.background.paper,
 | 
				
			||||||
    display: 'flex',
 | 
					    display: 'flex',
 | 
				
			||||||
    flexDirection: 'column',
 | 
					    flexDirection: 'column',
 | 
				
			||||||
    alignItems: 'stretch',
 | 
					    alignItems: 'stretch',
 | 
				
			||||||
@ -79,6 +82,7 @@ export const MilestoneAutomationSection = ({
 | 
				
			|||||||
                    intervalMinutes={transitionCondition.intervalMinutes}
 | 
					                    intervalMinutes={transitionCondition.intervalMinutes}
 | 
				
			||||||
                    onDelete={onDeleteAutomation!}
 | 
					                    onDelete={onDeleteAutomation!}
 | 
				
			||||||
                    milestoneName={milestoneName}
 | 
					                    milestoneName={milestoneName}
 | 
				
			||||||
 | 
					                    status={status}
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
            ) : (
 | 
					            ) : (
 | 
				
			||||||
                <StyledAddAutomationButton
 | 
					                <StyledAddAutomationButton
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,7 @@ import BoltIcon from '@mui/icons-material/Bolt';
 | 
				
			|||||||
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
 | 
					import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
 | 
				
			||||||
import { IconButton, styled } from '@mui/material';
 | 
					import { IconButton, styled } from '@mui/material';
 | 
				
			||||||
import { formatDuration, intervalToDuration } from 'date-fns';
 | 
					import { formatDuration, intervalToDuration } from 'date-fns';
 | 
				
			||||||
 | 
					import type { MilestoneStatus } from './ReleasePlanMilestoneStatus.tsx';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const StyledDisplayContainer = styled('div')(({ theme }) => ({
 | 
					const StyledDisplayContainer = styled('div')(({ theme }) => ({
 | 
				
			||||||
    display: 'flex',
 | 
					    display: 'flex',
 | 
				
			||||||
@ -17,17 +18,27 @@ const StyledContentGroup = styled('div')(({ theme }) => ({
 | 
				
			|||||||
    gap: theme.spacing(1),
 | 
					    gap: theme.spacing(1),
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const StyledIcon = styled(BoltIcon)(({ theme }) => ({
 | 
					const StyledIcon = styled(BoltIcon, {
 | 
				
			||||||
 | 
					    shouldForwardProp: (prop) => prop !== 'status',
 | 
				
			||||||
 | 
					})<{ status?: MilestoneStatus }>(({ theme, status }) => ({
 | 
				
			||||||
    color: theme.palette.common.white,
 | 
					    color: theme.palette.common.white,
 | 
				
			||||||
    fontSize: 18,
 | 
					    fontSize: 18,
 | 
				
			||||||
    flexShrink: 0,
 | 
					    flexShrink: 0,
 | 
				
			||||||
    backgroundColor: theme.palette.primary.main,
 | 
					    backgroundColor:
 | 
				
			||||||
 | 
					        status === 'completed'
 | 
				
			||||||
 | 
					            ? theme.palette.neutral.border
 | 
				
			||||||
 | 
					            : theme.palette.primary.main,
 | 
				
			||||||
    borderRadius: '50%',
 | 
					    borderRadius: '50%',
 | 
				
			||||||
    padding: theme.spacing(0.25),
 | 
					    padding: theme.spacing(0.25),
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const StyledText = styled('span')(({ theme }) => ({
 | 
					const StyledText = styled('span', {
 | 
				
			||||||
    color: theme.palette.text.primary,
 | 
					    shouldForwardProp: (prop) => prop !== 'status',
 | 
				
			||||||
 | 
					})<{ status?: MilestoneStatus }>(({ theme, status }) => ({
 | 
				
			||||||
 | 
					    color:
 | 
				
			||||||
 | 
					        status === 'completed'
 | 
				
			||||||
 | 
					            ? theme.palette.text.secondary
 | 
				
			||||||
 | 
					            : theme.palette.text.primary,
 | 
				
			||||||
    fontSize: theme.typography.body2.fontSize,
 | 
					    fontSize: theme.typography.body2.fontSize,
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -35,6 +46,7 @@ interface IMilestoneTransitionDisplayProps {
 | 
				
			|||||||
    intervalMinutes: number;
 | 
					    intervalMinutes: number;
 | 
				
			||||||
    onDelete: () => void;
 | 
					    onDelete: () => void;
 | 
				
			||||||
    milestoneName: string;
 | 
					    milestoneName: string;
 | 
				
			||||||
 | 
					    status?: MilestoneStatus;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const formatInterval = (minutes: number): string => {
 | 
					const formatInterval = (minutes: number): string => {
 | 
				
			||||||
@ -55,12 +67,13 @@ export const MilestoneTransitionDisplay = ({
 | 
				
			|||||||
    intervalMinutes,
 | 
					    intervalMinutes,
 | 
				
			||||||
    onDelete,
 | 
					    onDelete,
 | 
				
			||||||
    milestoneName,
 | 
					    milestoneName,
 | 
				
			||||||
 | 
					    status,
 | 
				
			||||||
}: IMilestoneTransitionDisplayProps) => {
 | 
					}: IMilestoneTransitionDisplayProps) => {
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <StyledDisplayContainer>
 | 
					        <StyledDisplayContainer>
 | 
				
			||||||
            <StyledContentGroup>
 | 
					            <StyledContentGroup>
 | 
				
			||||||
                <StyledIcon />
 | 
					                <StyledIcon status={status} />
 | 
				
			||||||
                <StyledText>
 | 
					                <StyledText status={status}>
 | 
				
			||||||
                    Proceed to the next milestone after{' '}
 | 
					                    Proceed to the next milestone after{' '}
 | 
				
			||||||
                    {formatInterval(intervalMinutes)}
 | 
					                    {formatInterval(intervalMinutes)}
 | 
				
			||||||
                </StyledText>
 | 
					                </StyledText>
 | 
				
			||||||
 | 
				
			|||||||
@ -22,14 +22,17 @@ const StyledAccordion = styled(Accordion, {
 | 
				
			|||||||
    shouldForwardProp: (prop) => prop !== 'status' && prop !== 'hasAutomation',
 | 
					    shouldForwardProp: (prop) => prop !== 'status' && prop !== 'hasAutomation',
 | 
				
			||||||
})<{ status: MilestoneStatus; hasAutomation?: boolean }>(
 | 
					})<{ status: MilestoneStatus; hasAutomation?: boolean }>(
 | 
				
			||||||
    ({ theme, status, hasAutomation }) => ({
 | 
					    ({ theme, status, hasAutomation }) => ({
 | 
				
			||||||
        border: `1px solid ${status === 'active' ? theme.palette.success.border : theme.palette.divider}`,
 | 
					        border: `${status === 'active' ? '1.25px' : '1px'} solid ${status === 'active' ? theme.palette.success.border : theme.palette.divider}`,
 | 
				
			||||||
        borderBottom: hasAutomation
 | 
					        borderBottom: hasAutomation
 | 
				
			||||||
            ? 'none'
 | 
					            ? 'none'
 | 
				
			||||||
            : `1px solid ${status === 'active' ? theme.palette.success.border : theme.palette.divider}`,
 | 
					            : `${status === 'active' ? '1.25px' : '1px'} solid ${status === 'active' ? theme.palette.success.border : theme.palette.divider}`,
 | 
				
			||||||
        overflow: 'hidden',
 | 
					        overflow: 'hidden',
 | 
				
			||||||
        boxShadow: 'none',
 | 
					        boxShadow: 'none',
 | 
				
			||||||
        margin: 0,
 | 
					        margin: 0,
 | 
				
			||||||
        backgroundColor: theme.palette.background.paper,
 | 
					        backgroundColor:
 | 
				
			||||||
 | 
					            status === 'completed'
 | 
				
			||||||
 | 
					                ? theme.palette.background.default
 | 
				
			||||||
 | 
					                : theme.palette.background.paper,
 | 
				
			||||||
        borderRadius: hasAutomation
 | 
					        borderRadius: hasAutomation
 | 
				
			||||||
            ? `${theme.shape.borderRadiusLarge}px ${theme.shape.borderRadiusLarge}px 0 0 !important`
 | 
					            ? `${theme.shape.borderRadiusLarge}px ${theme.shape.borderRadiusLarge}px 0 0 !important`
 | 
				
			||||||
            : `${theme.shape.borderRadiusLarge}px`,
 | 
					            : `${theme.shape.borderRadiusLarge}px`,
 | 
				
			||||||
@ -54,8 +57,14 @@ const StyledTitleContainer = styled('div')(({ theme }) => ({
 | 
				
			|||||||
    gap: theme.spacing(0.5),
 | 
					    gap: theme.spacing(0.5),
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const StyledTitle = styled('span')(({ theme }) => ({
 | 
					const StyledTitle = styled('span', {
 | 
				
			||||||
 | 
					    shouldForwardProp: (prop) => prop !== 'status',
 | 
				
			||||||
 | 
					})<{ status?: MilestoneStatus }>(({ theme, status }) => ({
 | 
				
			||||||
    fontWeight: theme.fontWeight.bold,
 | 
					    fontWeight: theme.fontWeight.bold,
 | 
				
			||||||
 | 
					    color:
 | 
				
			||||||
 | 
					        status === 'completed'
 | 
				
			||||||
 | 
					            ? theme.palette.text.secondary
 | 
				
			||||||
 | 
					            : theme.palette.text.primary,
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const StyledSecondaryLabel = styled('span')(({ theme }) => ({
 | 
					const StyledSecondaryLabel = styled('span')(({ theme }) => ({
 | 
				
			||||||
@ -100,7 +109,9 @@ export const ReleasePlanMilestone = ({
 | 
				
			|||||||
                <StyledAccordion status={status} hasAutomation={showAutomation}>
 | 
					                <StyledAccordion status={status} hasAutomation={showAutomation}>
 | 
				
			||||||
                    <StyledAccordionSummary>
 | 
					                    <StyledAccordionSummary>
 | 
				
			||||||
                        <StyledTitleContainer>
 | 
					                        <StyledTitleContainer>
 | 
				
			||||||
                            <StyledTitle>{milestone.name}</StyledTitle>
 | 
					                            <StyledTitle status={status}>
 | 
				
			||||||
 | 
					                                {milestone.name}
 | 
				
			||||||
 | 
					                            </StyledTitle>
 | 
				
			||||||
                            {!readonly && onStartMilestone && (
 | 
					                            {!readonly && onStartMilestone && (
 | 
				
			||||||
                                <ReleasePlanMilestoneStatus
 | 
					                                <ReleasePlanMilestoneStatus
 | 
				
			||||||
                                    status={status}
 | 
					                                    status={status}
 | 
				
			||||||
@ -137,7 +148,9 @@ export const ReleasePlanMilestone = ({
 | 
				
			|||||||
            >
 | 
					            >
 | 
				
			||||||
                <StyledAccordionSummary expandIcon={<ExpandMore />}>
 | 
					                <StyledAccordionSummary expandIcon={<ExpandMore />}>
 | 
				
			||||||
                    <StyledTitleContainer>
 | 
					                    <StyledTitleContainer>
 | 
				
			||||||
                        <StyledTitle>{milestone.name}</StyledTitle>
 | 
					                        <StyledTitle status={status}>
 | 
				
			||||||
 | 
					                            {milestone.name}
 | 
				
			||||||
 | 
					                        </StyledTitle>
 | 
				
			||||||
                        {!readonly && onStartMilestone && (
 | 
					                        {!readonly && onStartMilestone && (
 | 
				
			||||||
                            <ReleasePlanMilestoneStatus
 | 
					                            <ReleasePlanMilestoneStatus
 | 
				
			||||||
                                status={status}
 | 
					                                status={status}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user