diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/MilestoneProgressionForm/MilestoneProgressionForm.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/MilestoneProgressionForm/MilestoneProgressionForm.tsx
index b2621a75cc..ec9db97ae1 100644
--- a/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/MilestoneProgressionForm/MilestoneProgressionForm.tsx
+++ b/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/MilestoneProgressionForm/MilestoneProgressionForm.tsx
@@ -20,41 +20,26 @@ const StyledFormContainer = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(1.5),
- padding: theme.spacing(2),
- backgroundColor: theme.palette.background.paper,
- borderRadius: theme.spacing(0.75),
- border: `1px solid ${theme.palette.divider}`,
- boxShadow: theme.boxShadows.elevated,
+ padding: theme.spacing(1.5, 2),
+ backgroundColor: theme.palette.background.elevation1,
+ width: '100%',
+ borderRadius: `${theme.shape.borderRadiusLarge}px`,
position: 'relative',
- marginLeft: theme.spacing(3.25),
- marginTop: theme.spacing(1.5),
- marginBottom: theme.spacing(1.5),
- animation: 'slideDown 0.5s ease-out',
- '@keyframes slideDown': {
- from: {
- opacity: 0,
- transform: 'translateY(-24px)',
- },
- to: {
- opacity: 1,
- transform: 'translateY(0)',
- },
- },
}));
const StyledTopRow = styled('div')(({ theme }) => ({
display: 'flex',
alignItems: 'center',
- gap: theme.spacing(1.5),
+ gap: theme.spacing(1),
}));
const StyledIcon = styled(BoltIcon)(({ theme }) => ({
- color: theme.palette.primary.main,
- fontSize: 20,
+ color: theme.palette.common.white,
+ fontSize: 18,
flexShrink: 0,
- backgroundColor: theme.palette.background.elevation1,
+ backgroundColor: theme.palette.primary.main,
borderRadius: '50%',
- border: `1px solid ${theme.palette.divider}`,
+ padding: theme.spacing(0.25),
}));
const StyledLabel = styled('span')(({ theme }) => ({
@@ -105,8 +90,8 @@ const StyledButtonGroup = styled('div')(({ theme }) => ({
gap: theme.spacing(1),
justifyContent: 'flex-end',
alignItems: 'center',
- paddingTop: theme.spacing(1.5),
- marginTop: theme.spacing(1),
+ paddingTop: theme.spacing(1),
+ marginTop: theme.spacing(0.5),
borderTop: `1px solid ${theme.palette.divider}`,
}));
diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlan.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlan.tsx
index 18436282dc..3e0317cd70 100644
--- a/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlan.tsx
+++ b/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlan.tsx
@@ -1,6 +1,5 @@
import Delete from '@mui/icons-material/Delete';
-import Add from '@mui/icons-material/Add';
-import { styled, IconButton, Button } from '@mui/material';
+import { styled } from '@mui/material';
import { DELETE_FEATURE_STRATEGY } from '@server/types/permissions';
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
import { useReleasePlansApi } from 'hooks/api/actions/useReleasePlansApi/useReleasePlansApi';
@@ -72,47 +71,12 @@ const StyledBody = styled('div')(({ theme }) => ({
}));
const StyledConnection = styled('div')(({ theme }) => ({
- width: 4,
- height: theme.spacing(6),
- backgroundColor: theme.palette.divider,
- marginLeft: theme.spacing(3.25),
-}));
-
-const StyledConnectionSimple = styled('div')(({ theme }) => ({
width: 4,
height: theme.spacing(2),
backgroundColor: theme.palette.divider,
marginLeft: theme.spacing(3.25),
}));
-const StyledConnectionContainer = styled('div')(({ theme }) => ({
- position: 'relative',
- display: 'flex',
- alignItems: 'center',
-}));
-
-const StyledAddAutomationIconButton = styled(IconButton)(({ theme }) => ({
- position: 'absolute',
- left: theme.spacing(2),
- top: '12px',
- width: 24,
- height: 24,
- border: `1px solid ${theme.palette.primary.main}`,
- backgroundColor: theme.palette.background.elevation2,
- zIndex: 1,
- '& svg': {
- fontSize: 16,
- },
-}));
-
-const StyledAddAutomationButton = styled(Button)(({ theme }) => ({
- marginLeft: theme.spacing(3),
- textTransform: 'none',
- fontWeight: theme.typography.fontWeightBold,
- padding: 0,
- minWidth: 'auto',
-}));
-
interface IReleasePlanProps {
plan: IReleasePlan;
environmentIsDisabled?: boolean;
@@ -332,63 +296,27 @@ export const ReleasePlan = ({
: 'not-started'
}
onStartMilestone={onStartMilestone}
+ showAutomation={
+ milestoneProgressionsEnabled &&
+ isNotLastMilestone
+ }
+ onAddAutomation={handleOpenProgressionForm}
+ automationForm={
+ isProgressionFormOpen ? (
+
+ ) : undefined
+ }
/>
- }
- elseShow={
-
-
-
-
-
-
- Add automation
-
-
- }
- />
- }
- elseShow={}
- />
- }
+ show={}
/>
);
diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlanMilestone/MilestoneAutomationSection.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlanMilestone/MilestoneAutomationSection.tsx
new file mode 100644
index 0000000000..9beb220e24
--- /dev/null
+++ b/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlanMilestone/MilestoneAutomationSection.tsx
@@ -0,0 +1,79 @@
+import Add from '@mui/icons-material/Add';
+import { Button, styled } from '@mui/material';
+import type { MilestoneStatus } from './ReleasePlanMilestoneStatus.tsx';
+
+const StyledAutomationContainer = styled('div', {
+ shouldForwardProp: (prop) => prop !== 'status',
+})<{ status?: MilestoneStatus }>(({ theme, status }) => ({
+ border: `1px solid ${status === 'active' ? theme.palette.success.border : theme.palette.divider}`,
+ borderTop: `1px solid ${theme.palette.divider}`,
+ borderRadius: `0 0 ${theme.shape.borderRadiusLarge}px ${theme.shape.borderRadiusLarge}px`,
+ padding: theme.spacing(1.5, 2),
+ backgroundColor: theme.palette.background.paper,
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'stretch',
+ gap: theme.spacing(1),
+ '& > *': {
+ alignSelf: 'flex-start',
+ },
+}));
+
+const StyledAddAutomationButton = styled(Button)(({ theme }) => ({
+ textTransform: 'none',
+ fontWeight: theme.typography.fontWeightBold,
+ fontSize: theme.typography.body2.fontSize,
+ padding: 0,
+ minWidth: 'auto',
+ gap: theme.spacing(1),
+ '&:hover': {
+ backgroundColor: 'transparent',
+ },
+ '& .MuiButton-startIcon': {
+ margin: 0,
+ width: 20,
+ height: 20,
+ border: `1px solid ${theme.palette.primary.main}`,
+ backgroundColor: theme.palette.background.elevation2,
+ borderRadius: '50%',
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ '& svg': {
+ fontSize: 14,
+ color: theme.palette.primary.main,
+ },
+ },
+}));
+
+interface IMilestoneAutomationSectionProps {
+ showAutomation?: boolean;
+ status?: MilestoneStatus;
+ onAddAutomation?: () => void;
+ automationForm?: React.ReactNode;
+}
+
+export const MilestoneAutomationSection = ({
+ showAutomation,
+ status,
+ onAddAutomation,
+ automationForm,
+}: IMilestoneAutomationSectionProps) => {
+ if (!showAutomation) return null;
+
+ return (
+
+ {automationForm ? (
+ automationForm
+ ) : (
+ }
+ >
+ Add automation
+
+ )}
+
+ );
+};
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 c8ec8a6504..ba7289d7ae 100644
--- a/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlanMilestone/ReleasePlanMilestone.tsx
+++ b/frontend/src/component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlanMilestone/ReleasePlanMilestone.tsx
@@ -16,19 +16,28 @@ import { StrategySeparator } from 'component/common/StrategySeparator/StrategySe
import { StrategyItem } from '../../FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyItem.tsx';
import { StrategyList } from 'component/common/StrategyList/StrategyList';
import { StrategyListItem } from 'component/common/StrategyList/StrategyListItem';
+import { MilestoneAutomationSection } from './MilestoneAutomationSection.tsx';
const StyledAccordion = styled(Accordion, {
- shouldForwardProp: (prop) => prop !== 'status',
-})<{ status: MilestoneStatus }>(({ theme, status }) => ({
- border: `1px solid ${status === 'active' ? theme.palette.success.border : theme.palette.divider}`,
- overflow: 'hidden',
- boxShadow: 'none',
- margin: 0,
- backgroundColor: theme.palette.background.paper,
- '&:before': {
- display: 'none',
- },
-}));
+ shouldForwardProp: (prop) => prop !== 'status' && prop !== 'hasAutomation',
+})<{ status: MilestoneStatus; hasAutomation?: boolean }>(
+ ({ theme, status, hasAutomation }) => ({
+ border: `1px solid ${status === 'active' ? theme.palette.success.border : theme.palette.divider}`,
+ borderBottom: hasAutomation
+ ? 'none'
+ : `1px solid ${status === 'active' ? theme.palette.success.border : theme.palette.divider}`,
+ overflow: 'hidden',
+ boxShadow: 'none',
+ margin: 0,
+ backgroundColor: theme.palette.background.paper,
+ borderRadius: hasAutomation
+ ? `${theme.shape.borderRadiusLarge}px ${theme.shape.borderRadiusLarge}px 0 0 !important`
+ : `${theme.shape.borderRadiusLarge}px`,
+ '&:before': {
+ display: 'none',
+ },
+ }),
+);
const StyledAccordionSummary = styled(AccordionSummary)({
'& .MuiAccordionSummary-content': {
@@ -58,11 +67,18 @@ const StyledAccordionDetails = styled(AccordionDetails)(({ theme }) => ({
padding: 0,
}));
+const StyledMilestoneContainer = styled('div')({
+ position: 'relative',
+});
+
interface IReleasePlanMilestoneProps {
milestone: IReleasePlanMilestone;
status?: MilestoneStatus;
onStartMilestone?: (milestone: IReleasePlanMilestone) => void;
readonly?: boolean;
+ showAutomation?: boolean;
+ onAddAutomation?: () => void;
+ automationForm?: React.ReactNode;
}
export const ReleasePlanMilestone = ({
@@ -70,13 +86,51 @@ export const ReleasePlanMilestone = ({
status = 'not-started',
onStartMilestone,
readonly,
+ showAutomation,
+ onAddAutomation,
+ automationForm,
}: IReleasePlanMilestoneProps) => {
const [expanded, setExpanded] = useState(false);
if (!milestone.strategies.length) {
return (
-
-
+
+
+
+
+ {milestone.name}
+ {!readonly && onStartMilestone && (
+
+ onStartMilestone(milestone)
+ }
+ />
+ )}
+
+
+ No strategies
+
+
+
+
+
+ );
+ }
+
+ return (
+
+ setExpanded(expanded)}
+ >
+ }>
{milestone.name}
{!readonly && onStartMilestone && (
@@ -88,53 +142,39 @@ export const ReleasePlanMilestone = ({
/>
)}
- No strategies
+
+ {milestone.strategies.length === 1
+ ? `${expanded ? 'Hide' : 'View'} strategy`
+ : `${expanded ? 'Hide' : 'View'} ${milestone.strategies.length} strategies`}
+
+
+
+ {milestone.strategies.map((strategy, index) => (
+
+ {index > 0 ? : null}
+
+
+
+ ))}
+
+
- );
- }
-
- return (
- setExpanded(expanded)}
- >
- }>
-
- {milestone.name}
- {!readonly && onStartMilestone && (
- onStartMilestone(milestone)}
- />
- )}
-
-
- {milestone.strategies.length === 1
- ? `${expanded ? 'Hide' : 'View'} strategy`
- : `${expanded ? 'Hide' : 'View'} ${milestone.strategies.length} strategies`}
-
-
-
-
- {milestone.strategies.map((strategy, index) => (
-
- {index > 0 ? : null}
-
-
-
- ))}
-
-
-
+
+
);
};