Skip to content

Commit

Permalink
feat: release plan template milestone UI listing strategies (#8933)
Browse files Browse the repository at this point in the history
  • Loading branch information
daveleek authored Dec 9, 2024
1 parent e8179d4 commit 15950e4
Show file tree
Hide file tree
Showing 9 changed files with 585 additions and 150 deletions.
378 changes: 306 additions & 72 deletions frontend/src/component/releases/ReleasePlanTemplate/MilestoneCard.tsx

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import type {
IReleasePlanMilestoneStrategy,
} from 'interfaces/releasePlans';
import { MilestoneCard } from './MilestoneCard';
import { styled } from '@mui/material';
import { Button } from '@mui/material';
import { styled, Button } from '@mui/material';
import Add from '@mui/icons-material/Add';
import { v4 as uuidv4 } from 'uuid';

Expand All @@ -19,6 +18,7 @@ interface IMilestoneListProps {
) => void;
errors: { [key: string]: string };
clearErrors: () => void;
milestoneChanged: (milestone: IReleasePlanMilestonePayload) => void;
}

const StyledAddMilestoneButton = styled(Button)(({ theme }) => ({
Expand All @@ -32,24 +32,15 @@ export const MilestoneList = ({
openAddStrategyForm,
errors,
clearErrors,
milestoneChanged,
}: IMilestoneListProps) => {
const milestoneNameChanged = (milestoneId: string, name: string) => {
setMilestones((prev) =>
prev.map((milestone) =>
milestone.id === milestoneId
? { ...milestone, name }
: milestone,
),
);
};

return (
<>
{milestones.map((milestone) => (
<MilestoneCard
key={milestone.id}
milestone={milestone}
milestoneNameChanged={milestoneNameChanged}
milestoneChanged={milestoneChanged}
showAddStrategyDialog={openAddStrategyForm}
errors={errors}
clearErrors={clearErrors}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import type { IReleasePlanMilestoneStrategy } from 'interfaces/releasePlans';
import { type DragEventHandler, type RefObject, useRef } from 'react';
import { Box, IconButton } from '@mui/material';
import Edit from '@mui/icons-material/Edit';
import Delete from '@mui/icons-material/DeleteOutlined';
import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator';
import { MilestoneStrategyItem } from './MilestoneStrategyItem';

interface IMilestoneStrategyDraggableItemProps {
strategy: Omit<IReleasePlanMilestoneStrategy, 'milestoneId'>;
index: number;
isDragging?: boolean;
onDragStartRef: (
ref: RefObject<HTMLDivElement>,
index: number,
) => DragEventHandler<HTMLButtonElement>;
onDragOver: (
ref: RefObject<HTMLDivElement>,
index: number,
) => DragEventHandler<HTMLDivElement>;
onDragEnd: () => void;
onDeleteClick: () => void;
onEditClick: () => void;
}

export const MilestoneStrategyDraggableItem = ({
strategy,
index,
isDragging,
onDragStartRef,
onDragOver,
onDragEnd,
onDeleteClick,
onEditClick,
}: IMilestoneStrategyDraggableItemProps) => {
const ref = useRef<HTMLDivElement>(null);
return (
<Box
key={strategy.id}
ref={ref}
onDragOver={onDragOver(ref, index)}
sx={{ opacity: isDragging ? '0.5' : '1' }}
>
{index > 0 && <StrategySeparator text='OR' />}
<MilestoneStrategyItem
strategy={strategy}
onDragStart={onDragStartRef(ref, index)}
onDragEnd={onDragEnd}
actions={
<>
<IconButton title='Edit strategy' onClick={onEditClick}>
<Edit />
</IconButton>
<IconButton
title='Remove release plan'
onClick={onDeleteClick}
>
<Delete />
</IconButton>
</>
}
/>
</Box>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { Box, IconButton, styled } from '@mui/material';
import SplitPreviewSlider from 'component/feature/StrategyTypes/SplitPreviewSlider/SplitPreviewSlider';
import {
formatStrategyName,
getFeatureStrategyIcon,
} from 'utils/strategyNames';
import type { IFeatureStrategy } from 'interfaces/strategy';
import { StrategyExecution } from 'component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/StrategyExecution';
import type { DragEventHandler, ReactNode } from 'react';
import DragIndicator from '@mui/icons-material/DragIndicator';

const StyledStrategy = styled('div')(({ theme }) => ({
background: theme.palette.background.paper,
}));

const DragIcon = styled(IconButton)({
padding: 0,
cursor: 'inherit',
transition: 'color 0.2s ease-in-out',
});

const StyledHeader = styled('div', {
shouldForwardProp: (prop) => prop !== 'draggable',
})<{ draggable: boolean }>(({ theme, draggable }) => ({
display: 'flex',
padding: theme.spacing(2),
gap: theme.spacing(1),
alignItems: 'center',
color: theme.palette.text.primary,
'& > svg': {
fill: theme.palette.action.disabled,
},
borderBottom: `1px solid ${theme.palette.divider}`,
}));

const StyledStrategyExecution = styled('div')(({ theme }) => ({
padding: theme.spacing(2),
}));

interface IReleasePlanMilestoneStrategyProps {
strategy: IFeatureStrategy;
onDragStart?: DragEventHandler<HTMLButtonElement>;
onDragEnd?: DragEventHandler<HTMLButtonElement>;
actions?: ReactNode;
}

export const MilestoneStrategyItem = ({
strategy,
onDragStart,
onDragEnd,
actions,
}: IReleasePlanMilestoneStrategyProps) => {
const Icon = getFeatureStrategyIcon(strategy.strategyName);

return (
<StyledStrategy>
<StyledHeader draggable={Boolean(onDragStart)}>
<DragIcon
draggable
disableRipple
size='small'
onDragStart={onDragStart}
onDragEnd={onDragEnd}
sx={{ cursor: 'move' }}
>
<DragIndicator
titleAccess='Drag to reorder'
cursor='grab'
sx={{ color: 'action.active' }}
/>
</DragIcon>
<Icon />
{`${formatStrategyName(String(strategy.strategyName))}${strategy.title ? `: ${strategy.title}` : ''}`}
<Box
sx={{
marginLeft: 'auto',
display: 'flex',
minHeight: (theme) => theme.spacing(6),
alignItems: 'center',
}}
>
{actions}
</Box>
</StyledHeader>
<StyledStrategyExecution>
<StrategyExecution strategy={strategy} />
{strategy.variants &&
strategy.variants.length > 0 &&
(strategy.disabled ? (
<Box sx={{ opacity: '0.5' }}>
<SplitPreviewSlider variants={strategy.variants} />
</Box>
) : (
<SplitPreviewSlider variants={strategy.variants} />
))}
</StyledStrategyExecution>
</StyledStrategy>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,16 @@ export const MilestoneStrategyMenuCard = ({
<StyledCard
onClick={() => {
const strat = createFeatureStrategy('', strategy);
if (strat.name === 'flexibleRollout') {
strat.parameters = {
...strat.parameters,
groupId: '{{featureName}}',
};
}
onClick({
id: uuidv4(),
name: strat.name,
strategyName: strat.name,
title: '',
constraints: strat.constraints,
parameters: strat.parameters,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,13 @@ const StyledTypography = styled(Typography)(({ theme }) => ({
}));

interface IMilestoneStrategyMenuCardsProps {
milestoneId: string;
openAddStrategy: (
milestoneId: string,
openEditAddStrategy: (
strategy: Omit<IReleasePlanMilestoneStrategy, 'milestoneId'>,
) => void;
}

export const MilestoneStrategyMenuCards = ({
milestoneId,
openAddStrategy,
openEditAddStrategy,
}: IMilestoneStrategyMenuCardsProps) => {
const { strategies } = useStrategies();

Expand All @@ -29,7 +26,7 @@ export const MilestoneStrategyMenuCards = ({
const onClick = (
strategy: Omit<IReleasePlanMilestoneStrategy, 'milestoneId'>,
) => {
openAddStrategy(milestoneId, strategy);
openEditAddStrategy(strategy);
};

return (
Expand Down
Loading

0 comments on commit 15950e4

Please sign in to comment.