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