1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-10-13 11:17:26 +02:00
unleash.unleash/frontend/src/component/feature/FeatureStrategy/FeatureStrategyMenu/FeatureStrategyMenuCards/FeatureStrategyMenuCardsReleaseTemplates.tsx
Nuno Góis be4665f3f1
chore: update release templates empty states in new add strategy modal (#10656)
https://linear.app/unleash/issue/2-3876/update-the-release-templates-section-accordingly

Updates the release templates empty states in the new add strategy modal
to match the new design sketches.

Also fixes a few details in the modal base design.

<img width="989" height="583" alt="image"
src="https://github.com/user-attachments/assets/b3148fe1-eb61-48d5-84cb-3dc4381f7c0c"
/>

<img width="981" height="581" alt="image"
src="https://github.com/user-attachments/assets/54f9a4d7-8cde-4f4b-bc9d-dc7114d7e17f"
/>
2025-09-11 11:19:55 +01:00

179 lines
6.4 KiB
TypeScript

import { useReleasePlanTemplates } from 'hooks/api/getters/useReleasePlanTemplates/useReleasePlanTemplates';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { ReactComponent as ReleaseTemplateIcon } from 'assets/img/releaseTemplates.svg';
import { FeatureReleasePlanCard } from '../FeatureReleasePlanCard/FeatureReleasePlanCard.tsx';
import type { IReleasePlanTemplate } from 'interfaces/releasePlans.ts';
import { Box, Button, styled } from '@mui/material';
import type { StrategyFilterValue } from './FeatureStrategyMenuCards.tsx';
import type { Dispatch, SetStateAction } from 'react';
import { Link as RouterLink } from 'react-router-dom';
import {
FeatureStrategyMenuCardsSection,
StyledStrategyModalSectionHeader,
} from './FeatureStrategyMenuCardsSection.tsx';
const RELEASE_TEMPLATE_DISPLAY_LIMIT = 5;
const StyledIcon = styled('span', {
shouldForwardProp: (prop) => prop !== 'solo',
})<{ solo?: boolean }>(({ theme, solo }) => ({
'& > svg': {
fill: theme.palette.primary.main,
width: theme.spacing(6),
height: theme.spacing(6),
...(solo && {
width: theme.spacing(10),
height: theme.spacing(10),
}),
},
display: 'flex',
alignItems: 'center',
}));
const StyledNoTemplatesContainer = styled(Box, {
shouldForwardProp: (prop) => prop !== 'solo',
})<{ solo?: boolean }>(({ theme, solo }) => ({
display: 'flex',
alignItems: 'center',
backgroundColor: theme.palette.neutral.light,
borderRadius: theme.shape.borderRadiusMedium,
padding: theme.spacing(2),
gap: theme.spacing(1),
width: 'auto',
...(solo && {
backgroundColor: undefined,
flexDirection: 'column',
maxWidth: theme.spacing(70),
margin: 'auto',
gap: theme.spacing(2.5),
}),
}));
const StyledNoTemplatesBody = styled(Box, {
shouldForwardProp: (prop) => prop !== 'solo',
})<{ solo?: boolean }>(({ theme, solo }) => ({
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(0.5),
fontSize: theme.typography.caption.fontSize,
...(solo && {
alignItems: 'center',
textAlign: 'center',
gap: theme.spacing(2),
fontSize: theme.typography.body2.fontSize,
}),
}));
const StyledNoTemplatesTitle = styled('p')(({ theme }) => ({
fontWeight: theme.typography.fontWeightBold,
}));
const StyledNoTemplatesDescription = styled('p')(({ theme }) => ({
color: theme.palette.text.secondary,
}));
const StyledViewAllTemplates = styled(Box)({
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: '100%',
});
const StyledLink = styled(RouterLink)({
textDecoration: 'none',
'&:hover': {
textDecoration: 'underline',
},
});
interface IFeatureStrategyMenuCardsReleaseTemplatesProps {
onAddReleasePlan: (template: IReleasePlanTemplate) => void;
onReviewReleasePlan: (template: IReleasePlanTemplate) => void;
filter: StrategyFilterValue;
setFilter: Dispatch<SetStateAction<StrategyFilterValue>>;
}
export const FeatureStrategyMenuCardsReleaseTemplates = ({
onAddReleasePlan,
onReviewReleasePlan,
filter,
setFilter,
}: IFeatureStrategyMenuCardsReleaseTemplatesProps) => {
const { isEnterprise } = useUiConfig();
const { templates } = useReleasePlanTemplates();
if (!isEnterprise()) {
return null;
}
const isFiltered = filter === 'releaseTemplates';
const shouldShowHeader = !isFiltered || templates.length > 0;
const slicedTemplates = isFiltered
? templates
: templates.slice(0, RELEASE_TEMPLATE_DISPLAY_LIMIT);
return (
<Box>
{shouldShowHeader && (
<StyledStrategyModalSectionHeader>
Release templates
</StyledStrategyModalSectionHeader>
)}
{!templates.length ? (
<StyledNoTemplatesContainer solo={isFiltered}>
<StyledIcon solo={isFiltered}>
<ReleaseTemplateIcon />
</StyledIcon>
<StyledNoTemplatesBody solo={isFiltered}>
<StyledNoTemplatesTitle>
You don't have any release templates set up yet
</StyledNoTemplatesTitle>
<StyledNoTemplatesDescription>
Go to{' '}
<StyledLink to='/release-templates'>
Configure &gt; Release templates
</StyledLink>{' '}
in the side menu to make your rollouts more
efficient and streamlined. Read more in our{' '}
<StyledLink
to='https://docs.getunleash.io/reference/release-templates'
target='_blank'
rel='noreferrer'
>
documentation
</StyledLink>
.
</StyledNoTemplatesDescription>
</StyledNoTemplatesBody>
</StyledNoTemplatesContainer>
) : (
<FeatureStrategyMenuCardsSection>
{slicedTemplates.map((template) => (
<FeatureReleasePlanCard
key={template.id}
template={template}
onClick={() => onAddReleasePlan(template)}
onPreviewClick={() => onReviewReleasePlan(template)}
/>
))}
{slicedTemplates.length < templates.length &&
templates.length > RELEASE_TEMPLATE_DISPLAY_LIMIT && (
<StyledViewAllTemplates>
<Button
variant='text'
size='small'
onClick={() =>
setFilter('releaseTemplates')
}
>
View all available templates
</Button>
</StyledViewAllTemplates>
)}
</FeatureStrategyMenuCardsSection>
)}
</Box>
);
};