1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-26 13:48:33 +02:00

fix: add strategy release templates visibility for non Enterprise (#10401)

https://linear.app/unleash/issue/2-3711/add-strategy-modal-shows-release-templates-section-for-non-enterprise

Fixes a bug for non-Enterprise where release templates were mentioned
(and even linked to) even though they were not available for these
plans. When following the link the result was a page that did not
render.

Also slightly refactors and improves this component.

<img width="870" height="496" alt="image"
src="https://github.com/user-attachments/assets/47499e21-73fc-4ddf-8eed-6146be31b074"
/>
This commit is contained in:
Nuno Góis 2025-07-23 20:17:22 +01:00 committed by GitHub
parent 0e015d6686
commit 45e5b217aa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -8,7 +8,6 @@ import {
} from '@mui/material';
import { useStrategies } from 'hooks/api/getters/useStrategies/useStrategies';
import { FeatureStrategyMenuCard } from '../FeatureStrategyMenuCard/FeatureStrategyMenuCard.tsx';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useReleasePlanTemplates } from 'hooks/api/getters/useReleasePlanTemplates/useReleasePlanTemplates';
import { FeatureReleasePlanCard } from '../FeatureReleasePlanCard/FeatureReleasePlanCard.tsx';
import type { IReleasePlanTemplate } from 'interfaces/releasePlans';
@ -16,6 +15,8 @@ import { useNavigate } from 'react-router-dom';
import CloseIcon from '@mui/icons-material/Close';
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
import FactCheckOutlinedIcon from '@mui/icons-material/FactCheckOutlined';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig.ts';
import { useUiFlag } from 'hooks/useUiFlag.ts';
interface IFeatureStrategyMenuCardsProps {
projectId: string;
@ -27,17 +28,6 @@ interface IFeatureStrategyMenuCardsProps {
onClose: () => void;
}
const StyledTypography = styled(Typography)(({ theme }) => ({
fontSize: theme.fontSizes.smallBody,
padding: theme.spacing(1, 4),
width: '100%',
}));
const StyledLink = styled(Link)(({ theme }) => ({
fontSize: theme.fontSizes.smallBody,
cursor: 'pointer',
})) as typeof Link;
const GridContainer = styled(Box)(() => ({
width: '100%',
display: 'flex',
@ -48,15 +38,17 @@ const ScrollableContent = styled(Box)(({ theme }) => ({
width: '100%',
maxHeight: '70vh',
overflowY: 'auto',
padding: theme.spacing(1, 0, 1, 0),
padding: theme.spacing(4),
paddingTop: 0,
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(3),
}));
const GridSection = styled(Box)(({ theme }) => ({
display: 'grid',
gridTemplateColumns: 'repeat(2, 1fr)',
gap: theme.spacing(1.5),
padding: theme.spacing(0, 4),
marginBottom: theme.spacing(3),
width: '100%',
}));
@ -82,7 +74,7 @@ const SectionTitle = styled(Box)(({ theme }) => ({
display: 'flex',
alignItems: 'center',
gap: theme.spacing(0.5),
padding: theme.spacing(0, 4, 1, 4),
marginBottom: theme.spacing(1),
width: '100%',
}));
@ -110,7 +102,6 @@ const EmptyStateContainer = styled(Box)(({ theme }) => ({
backgroundColor: theme.palette.neutral.light,
borderRadius: theme.shape.borderRadiusMedium,
padding: theme.spacing(3),
margin: theme.spacing(0, 4),
width: 'auto',
}));
@ -144,10 +135,12 @@ export const FeatureStrategyMenuCards = ({
onReviewReleasePlan,
onClose,
}: IFeatureStrategyMenuCardsProps) => {
const { isEnterprise } = useUiConfig();
const releasePlansEnabled = useUiFlag('releasePlans');
const { strategies } = useStrategies();
const { templates } = useReleasePlanTemplates();
const navigate = useNavigate();
const allStrategies = !onlyReleasePlans;
const preDefinedStrategies = strategies.filter(
(strategy) => !strategy.deprecated && !strategy.editable,
@ -163,6 +156,65 @@ export const FeatureStrategyMenuCards = ({
description:
'This is the default strategy defined for this environment in the project',
};
const renderReleasePlanTemplates = () => {
if (!isEnterprise() || !releasePlansEnabled) {
return null;
}
if (!templates.length) {
return (
<EmptyStateContainer>
<EmptyStateTitle>
<StyledIcon>
<FactCheckOutlinedIcon />
</StyledIcon>
Create your own release templates
</EmptyStateTitle>
<EmptyStateDescription>
Standardize your rollouts and save time by reusing
predefined strategies. Find release templates in the
side menu under{' '}
<ClickableBoldText
onClick={() => navigate('/release-templates')}
>
Configure &gt; Release templates
</ClickableBoldText>
</EmptyStateDescription>
</EmptyStateContainer>
);
}
return (
<Box>
<SectionTitle>
<Typography color='inherit' variant='body2'>
Apply a release template
</Typography>
<Tooltip
title='Use a predefined template to roll out features to users'
arrow
>
<StyledInfoIcon />
</Tooltip>
</SectionTitle>
<GridSection>
{templates.map((template) => (
<CardWrapper key={template.id}>
<FeatureReleasePlanCard
template={template}
onClick={() => onAddReleasePlan(template)}
onPreviewClick={() =>
onReviewReleasePlan(template)
}
/>
</CardWrapper>
))}
</GridSection>
</Box>
);
};
return (
<GridContainer>
<TitleRow>
@ -179,167 +231,77 @@ export const FeatureStrategyMenuCards = ({
</IconButton>
</TitleRow>
<ScrollableContent>
{allStrategies ? (
{onlyReleasePlans ? (
renderReleasePlanTemplates()
) : (
<>
<SectionTitle>
<Typography color='inherit' variant='body2'>
Pre-defined strategy types
</Typography>
<Tooltip
title='Select a starting setup, and customize the strategy to your need with targeting and variants'
arrow
>
<StyledInfoIcon />
</Tooltip>
</SectionTitle>
<GridSection>
<CardWrapper key={defaultStrategy.name}>
<FeatureStrategyMenuCard
projectId={projectId}
featureId={featureId}
environmentId={environmentId}
strategy={defaultStrategy}
defaultStrategy={true}
onClose={onClose}
/>
</CardWrapper>
{preDefinedStrategies.map((strategy) => (
<CardWrapper key={strategy.name}>
<FeatureStrategyMenuCard
projectId={projectId}
featureId={featureId}
environmentId={environmentId}
strategy={strategy}
onClose={onClose}
/>
</CardWrapper>
))}
</GridSection>
</>
) : null}
<ConditionallyRender
condition={templates.length > 0}
show={
<>
<Box>
<SectionTitle>
<Typography color='inherit' variant='body2'>
Apply a release template
Pre-defined strategy types
</Typography>
<Tooltip
title='Use one of the pre-defined templates defined in your company for rolling out features to users'
title='Select a starting setup, and customize the strategy to your need with targeting and variants'
arrow
>
<StyledInfoIcon />
</Tooltip>
</SectionTitle>
<GridSection>
{templates.map((template) => (
<CardWrapper key={template.id}>
<FeatureReleasePlanCard
template={template}
onClick={() =>
onAddReleasePlan(template)
}
onPreviewClick={() =>
onReviewReleasePlan(template)
}
<CardWrapper key={defaultStrategy.name}>
<FeatureStrategyMenuCard
projectId={projectId}
featureId={featureId}
environmentId={environmentId}
strategy={defaultStrategy}
defaultStrategy
onClose={onClose}
/>
</CardWrapper>
{preDefinedStrategies.map((strategy) => (
<CardWrapper key={strategy.name}>
<FeatureStrategyMenuCard
projectId={projectId}
featureId={featureId}
environmentId={environmentId}
strategy={strategy}
onClose={onClose}
/>
</CardWrapper>
))}
</GridSection>
</>
}
elseShow={
<EmptyStateContainer>
<EmptyStateTitle>
<StyledIcon>
<FactCheckOutlinedIcon />
</StyledIcon>
Create your own templates
</EmptyStateTitle>
<EmptyStateDescription>
Standardize how you do rollouts and make it more
efficient without having to set up the same
stategies from time to time. You find it in the
sidemenu under{' '}
<ClickableBoldText
onClick={() =>
navigate('/release-templates')
}
>
Configure &gt; Release templates
</ClickableBoldText>
</EmptyStateDescription>
</EmptyStateContainer>
}
/>
<ConditionallyRender
condition={templates.length === 0 && onlyReleasePlans}
show={
<>
<StyledTypography
color='textSecondary'
sx={{
padding: (theme) =>
theme.spacing(1, 2, 0, 2),
}}
>
<p>No templates created.</p>
<p>
Go to&nbsp;
<StyledLink
onClick={() =>
navigate('/release-templates')
}
</Box>
{renderReleasePlanTemplates()}
{customStrategies.length > 0 && (
<Box>
<SectionTitle>
<Typography color='inherit' variant='body2'>
Custom strategies
</Typography>
<Tooltip
title='Custom strategies you have defined in Unleash'
arrow
>
Release templates
</StyledLink>
&nbsp;to get started
</p>
</StyledTypography>
</>
}
/>
{allStrategies ? (
<>
<ConditionallyRender
condition={customStrategies.length > 0}
show={
<>
<SectionTitle>
<Typography
color='inherit'
variant='body2'
>
Custom strategies
</Typography>
<Tooltip
title='Custom strategies you have defined in Unleash'
arrow
>
<StyledInfoIcon />
</Tooltip>
</SectionTitle>
<GridSection>
{customStrategies.map((strategy) => (
<CardWrapper key={strategy.name}>
<FeatureStrategyMenuCard
projectId={projectId}
featureId={featureId}
environmentId={
environmentId
}
strategy={strategy}
onClose={onClose}
/>
</CardWrapper>
))}
</GridSection>
</>
}
/>
<StyledInfoIcon />
</Tooltip>
</SectionTitle>
<GridSection>
{customStrategies.map((strategy) => (
<CardWrapper key={strategy.name}>
<FeatureStrategyMenuCard
projectId={projectId}
featureId={featureId}
environmentId={environmentId}
strategy={strategy}
onClose={onClose}
/>
</CardWrapper>
))}
</GridSection>
</Box>
)}
</>
) : null}
)}
</ScrollableContent>
</GridContainer>
);