Skip to content

Commit b44ac06

Browse files
authored
feat: new feature strategy menu (#9678)
1 parent 18346d1 commit b44ac06

File tree

10 files changed

+512
-68
lines changed

10 files changed

+512
-68
lines changed

frontend/src/component/feature/FeatureStrategy/FeatureStrategyMenu/FeatureReleasePlanCard/FeatureReleasePlanCard.tsx

+26-9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { getFeatureStrategyIcon } from 'utils/strategyNames';
22
import StringTruncator from 'component/common/StringTruncator/StringTruncator';
33
import { Button, styled } from '@mui/material';
44
import type { IReleasePlanTemplate } from 'interfaces/releasePlans';
5+
import { Truncator } from 'component/common/Truncator/Truncator';
56

67
const StyledIcon = styled('div')(({ theme }) => ({
78
width: theme.spacing(4),
@@ -16,19 +17,22 @@ const StyledIcon = styled('div')(({ theme }) => ({
1617
},
1718
}));
1819

19-
const StyledDescription = styled('div')(({ theme }) => ({
20-
fontSize: theme.fontSizes.smallBody,
21-
fontWeight: theme.fontWeight.medium,
20+
const StyledContentContainer = styled('div')(() => ({
21+
overflow: 'hidden',
22+
width: '100%',
2223
}));
2324

2425
const StyledName = styled(StringTruncator)(({ theme }) => ({
25-
fontWeight: theme.fontWeight.bold,
26+
fontWeight: theme.typography.fontWeightBold,
27+
display: 'block',
28+
marginBottom: theme.spacing(0.5),
2629
}));
2730

2831
const StyledCard = styled(Button)(({ theme }) => ({
2932
display: 'grid',
30-
gridTemplateColumns: '3rem 1fr',
31-
width: '20rem',
33+
gridTemplateColumns: '2.5rem 1fr',
34+
width: '100%',
35+
maxWidth: '30rem',
3236
padding: theme.spacing(2),
3337
color: 'inherit',
3438
textDecoration: 'inherit',
@@ -38,6 +42,7 @@ const StyledCard = styled(Button)(({ theme }) => ({
3842
borderColor: theme.palette.divider,
3943
borderRadius: theme.spacing(1),
4044
textAlign: 'left',
45+
overflow: 'hidden',
4146
'&:hover, &:focus': {
4247
borderColor: theme.palette.primary.main,
4348
},
@@ -59,10 +64,22 @@ export const FeatureReleasePlanCard = ({
5964
<StyledIcon>
6065
<Icon />
6166
</StyledIcon>
62-
<div>
67+
<StyledContentContainer>
6368
<StyledName text={name} maxWidth='200' maxLength={25} />
64-
<StyledDescription>{description}</StyledDescription>
65-
</div>
69+
<Truncator
70+
lines={1}
71+
title={description}
72+
arrow
73+
sx={{
74+
fontSize: (theme) => theme.typography.body2.fontSize,
75+
fontWeight: (theme) =>
76+
theme.typography.fontWeightRegular,
77+
width: '100%',
78+
}}
79+
>
80+
{description}
81+
</Truncator>
82+
</StyledContentContainer>
6683
</StyledCard>
6784
);
6885
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { getFeatureStrategyIcon } from 'utils/strategyNames';
2+
import StringTruncator from 'component/common/StringTruncator/StringTruncator';
3+
import { Button, styled } from '@mui/material';
4+
import type { IReleasePlanTemplate } from 'interfaces/releasePlans';
5+
6+
const StyledIcon = styled('div')(({ theme }) => ({
7+
width: theme.spacing(4),
8+
height: 'auto',
9+
'& > svg': {
10+
fill: theme.palette.primary.main,
11+
},
12+
'& > div': {
13+
height: theme.spacing(2),
14+
marginLeft: '-.75rem',
15+
color: theme.palette.primary.main,
16+
},
17+
}));
18+
19+
const StyledDescription = styled('div')(({ theme }) => ({
20+
fontSize: theme.fontSizes.smallBody,
21+
fontWeight: theme.fontWeight.medium,
22+
}));
23+
24+
const StyledName = styled(StringTruncator)(({ theme }) => ({
25+
fontWeight: theme.fontWeight.bold,
26+
}));
27+
28+
const StyledCard = styled(Button)(({ theme }) => ({
29+
display: 'grid',
30+
gridTemplateColumns: '3rem 1fr',
31+
width: '20rem',
32+
padding: theme.spacing(2),
33+
color: 'inherit',
34+
textDecoration: 'inherit',
35+
lineHeight: 1.25,
36+
borderWidth: '1px',
37+
borderStyle: 'solid',
38+
borderColor: theme.palette.divider,
39+
borderRadius: theme.spacing(1),
40+
textAlign: 'left',
41+
'&:hover, &:focus': {
42+
borderColor: theme.palette.primary.main,
43+
},
44+
}));
45+
46+
interface IFeatureReleasePlanCardProps {
47+
template: IReleasePlanTemplate;
48+
onClick: () => void;
49+
}
50+
51+
export const OldFeatureReleasePlanCard = ({
52+
template: { name, description },
53+
onClick,
54+
}: IFeatureReleasePlanCardProps) => {
55+
const Icon = getFeatureStrategyIcon('releasePlanTemplate');
56+
57+
return (
58+
<StyledCard onClick={onClick}>
59+
<StyledIcon>
60+
<Icon />
61+
</StyledIcon>
62+
<div>
63+
<StyledName text={name} maxWidth='200' maxLength={25} />
64+
<StyledDescription>{description}</StyledDescription>
65+
</div>
66+
</StyledCard>
67+
);
68+
};

frontend/src/component/feature/FeatureStrategy/FeatureStrategyMenu/FeatureStrategyMenu.tsx

+29-10
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
2121
import { formatUnknownError } from 'utils/formatUnknownError';
2222
import { useUiFlag } from 'hooks/useUiFlag';
2323
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
24+
import { OldFeatureStrategyMenuCards } from './FeatureStrategyMenuCards/OldFeatureStrategyMenuCards';
2425

2526
interface IFeatureStrategyMenuProps {
2627
label: string;
@@ -75,6 +76,7 @@ export const FeatureStrategyMenu = ({
7576
const { addReleasePlanToFeature } = useReleasePlansApi();
7677
const { isOss } = useUiConfig();
7778
const releasePlansEnabled = useUiFlag('releasePlans');
79+
const newStrategyDropdownEnabled = useUiFlag('newStrategyDropdown');
7880
const displayReleasePlanButton = !isOss() && releasePlansEnabled;
7981
const crProtected =
8082
releasePlansEnabled && isChangeRequestConfigured(environmentId);
@@ -223,19 +225,36 @@ export const FeatureStrategyMenu = ({
223225
PaperProps={{
224226
sx: (theme) => ({
225227
paddingBottom: theme.spacing(1),
228+
width: 'auto',
229+
maxWidth: '95vw',
230+
overflow: 'hidden',
226231
}),
227232
}}
228233
>
229-
<FeatureStrategyMenuCards
230-
projectId={projectId}
231-
featureId={featureId}
232-
environmentId={environmentId}
233-
onlyReleasePlans={onlyReleasePlans}
234-
onAddReleasePlan={(template) => {
235-
setSelectedTemplate(template);
236-
setAddReleasePlanOpen(true);
237-
}}
238-
/>
234+
{newStrategyDropdownEnabled ? (
235+
<FeatureStrategyMenuCards
236+
projectId={projectId}
237+
featureId={featureId}
238+
environmentId={environmentId}
239+
onlyReleasePlans={onlyReleasePlans}
240+
onAddReleasePlan={(template) => {
241+
setSelectedTemplate(template);
242+
setAddReleasePlanOpen(true);
243+
}}
244+
onClose={onClose}
245+
/>
246+
) : (
247+
<OldFeatureStrategyMenuCards
248+
projectId={projectId}
249+
featureId={featureId}
250+
environmentId={environmentId}
251+
onlyReleasePlans={onlyReleasePlans}
252+
onAddReleasePlan={(template) => {
253+
setSelectedTemplate(template);
254+
setAddReleasePlanOpen(true);
255+
}}
256+
/>
257+
)}
239258
</Popover>
240259
{selectedTemplate && (
241260
<ReleasePlanAddDialog

frontend/src/component/feature/FeatureStrategy/FeatureStrategyMenu/FeatureStrategyMenuCard/FeatureStrategyMenuCard.tsx

+24-8
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { formatCreateStrategyPath } from 'component/feature/FeatureStrategy/Feat
88
import StringTruncator from 'component/common/StringTruncator/StringTruncator';
99
import { styled } from '@mui/material';
1010
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
11+
import { Truncator } from 'component/common/Truncator/Truncator';
1112

1213
interface IFeatureStrategyMenuCardProps {
1314
projectId: string;
@@ -33,18 +34,22 @@ const StyledIcon = styled('div')(({ theme }) => ({
3334
},
3435
}));
3536

36-
const StyledDescription = styled('div')(({ theme }) => ({
37-
fontSize: theme.fontSizes.smallBody,
37+
const StyledContentContainer = styled('div')(() => ({
38+
overflow: 'hidden',
39+
width: '100%',
3840
}));
3941

4042
const StyledName = styled(StringTruncator)(({ theme }) => ({
41-
fontWeight: theme.fontWeight.bold,
43+
fontWeight: theme.typography.fontWeightBold,
44+
display: 'block',
45+
marginBottom: theme.spacing(0.5),
4246
}));
4347

4448
const StyledCard = styled(Link)(({ theme }) => ({
4549
display: 'grid',
46-
gridTemplateColumns: '3rem 1fr',
47-
width: '20rem',
50+
gridTemplateColumns: '2.5rem 1fr',
51+
width: '100%',
52+
maxWidth: '30rem',
4853
padding: theme.spacing(2),
4954
color: 'inherit',
5055
textDecoration: 'inherit',
@@ -53,6 +58,7 @@ const StyledCard = styled(Link)(({ theme }) => ({
5358
borderStyle: 'solid',
5459
borderColor: theme.palette.divider,
5560
borderRadius: theme.spacing(1),
61+
overflow: 'hidden',
5662
'&:hover, &:focus': {
5763
borderColor: theme.palette.primary.main,
5864
},
@@ -90,14 +96,24 @@ export const FeatureStrategyMenuCard = ({
9096
<StyledIcon>
9197
<StrategyIcon />
9298
</StyledIcon>
93-
<div>
99+
<StyledContentContainer>
94100
<StyledName
95101
text={strategy.displayName || strategyName}
96102
maxWidth='200'
97103
maxLength={25}
98104
/>
99-
<StyledDescription>{strategy.description}</StyledDescription>
100-
</div>
105+
<Truncator
106+
lines={1}
107+
title={strategy.description}
108+
arrow
109+
sx={{
110+
fontSize: (theme) => theme.typography.body2.fontSize,
111+
width: '100%',
112+
}}
113+
>
114+
{strategy.description}
115+
</Truncator>
116+
</StyledContentContainer>
101117
</StyledCard>
102118
);
103119
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import type { IStrategy } from 'interfaces/strategy';
2+
import { Link } from 'react-router-dom';
3+
import {
4+
getFeatureStrategyIcon,
5+
formatStrategyName,
6+
} from 'utils/strategyNames';
7+
import { formatCreateStrategyPath } from 'component/feature/FeatureStrategy/FeatureStrategyCreate/FeatureStrategyCreate';
8+
import StringTruncator from 'component/common/StringTruncator/StringTruncator';
9+
import { styled } from '@mui/material';
10+
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
11+
12+
interface IFeatureStrategyMenuCardProps {
13+
projectId: string;
14+
featureId: string;
15+
environmentId: string;
16+
strategy: Pick<IStrategy, 'name' | 'displayName' | 'description'> &
17+
Partial<IStrategy>;
18+
defaultStrategy?: boolean;
19+
}
20+
21+
const StyledIcon = styled('div')(({ theme }) => ({
22+
width: theme.spacing(4),
23+
height: 'auto',
24+
'& > svg': {
25+
// Styling for SVG icons.
26+
fill: theme.palette.primary.main,
27+
},
28+
'& > div': {
29+
// Styling for the Rollout icon.
30+
height: theme.spacing(2),
31+
marginLeft: '-.75rem',
32+
color: theme.palette.primary.main,
33+
},
34+
}));
35+
36+
const StyledDescription = styled('div')(({ theme }) => ({
37+
fontSize: theme.fontSizes.smallBody,
38+
}));
39+
40+
const StyledName = styled(StringTruncator)(({ theme }) => ({
41+
fontWeight: theme.fontWeight.bold,
42+
}));
43+
44+
const StyledCard = styled(Link)(({ theme }) => ({
45+
display: 'grid',
46+
gridTemplateColumns: '3rem 1fr',
47+
width: '20rem',
48+
padding: theme.spacing(2),
49+
color: 'inherit',
50+
textDecoration: 'inherit',
51+
lineHeight: 1.25,
52+
borderWidth: '1px',
53+
borderStyle: 'solid',
54+
borderColor: theme.palette.divider,
55+
borderRadius: theme.spacing(1),
56+
'&:hover, &:focus': {
57+
borderColor: theme.palette.primary.main,
58+
},
59+
}));
60+
61+
export const OldFeatureStrategyMenuCard = ({
62+
projectId,
63+
featureId,
64+
environmentId,
65+
strategy,
66+
defaultStrategy,
67+
}: IFeatureStrategyMenuCardProps) => {
68+
const StrategyIcon = getFeatureStrategyIcon(strategy.name);
69+
const strategyName = formatStrategyName(strategy.name);
70+
const { trackEvent } = usePlausibleTracker();
71+
72+
const createStrategyPath = formatCreateStrategyPath(
73+
projectId,
74+
featureId,
75+
environmentId,
76+
strategy.name,
77+
defaultStrategy,
78+
);
79+
80+
const openStrategyCreationModal = () => {
81+
trackEvent('strategy-add', {
82+
props: {
83+
buttonTitle: strategy.displayName || strategyName,
84+
},
85+
});
86+
};
87+
88+
return (
89+
<StyledCard to={createStrategyPath} onClick={openStrategyCreationModal}>
90+
<StyledIcon>
91+
<StrategyIcon />
92+
</StyledIcon>
93+
<div>
94+
<StyledName
95+
text={strategy.displayName || strategyName}
96+
maxWidth='200'
97+
maxLength={25}
98+
/>
99+
<StyledDescription>{strategy.description}</StyledDescription>
100+
</div>
101+
</StyledCard>
102+
);
103+
};

0 commit comments

Comments
 (0)