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

chore: add feature configuration based on addConfiguration flag

This commit is contained in:
Nuno Góis 2025-07-28 16:17:22 +01:00
parent 0a9d6437c5
commit cd16a1dfe4
No known key found for this signature in database
GPG Key ID: 71ECC689F1091765
7 changed files with 149 additions and 122 deletions

View File

@ -27,7 +27,10 @@ const CardContent = styled('div')(({ theme }) => ({
const HoverButtonsContainer = styled('div')(({ theme }) => ({ const HoverButtonsContainer = styled('div')(({ theme }) => ({
position: 'absolute', position: 'absolute',
right: theme.spacing(2), background: theme.palette.background.paper,
padding: theme.spacing(1),
top: theme.spacing(1),
right: theme.spacing(1),
display: 'flex', display: 'flex',
gap: theme.spacing(1), gap: theme.spacing(1),
opacity: 0, opacity: 0,

View File

@ -75,9 +75,10 @@ export const FeatureStrategyMenu = ({
usePendingChangeRequests(projectId); usePendingChangeRequests(projectId);
const { refetch } = useReleasePlans(projectId, featureId, environmentId); const { refetch } = useReleasePlans(projectId, featureId, environmentId);
const { addReleasePlanToFeature } = useReleasePlansApi(); const { addReleasePlanToFeature } = useReleasePlansApi();
const { isOss } = useUiConfig(); const { isEnterprise } = useUiConfig();
const addConfigurationEnabled = useUiFlag('addConfiguration');
const releasePlansEnabled = useUiFlag('releasePlans'); const releasePlansEnabled = useUiFlag('releasePlans');
const displayReleasePlanButton = !isOss() && releasePlansEnabled; const displayReleasePlanButton = isEnterprise() && releasePlansEnabled;
const crProtected = const crProtected =
releasePlansEnabled && isChangeRequestConfigured(environmentId); releasePlansEnabled && isChangeRequestConfigured(environmentId);
@ -161,56 +162,81 @@ export const FeatureStrategyMenu = ({
return ( return (
<StyledStrategyMenu onClick={(event) => event.stopPropagation()}> <StyledStrategyMenu onClick={(event) => event.stopPropagation()}>
{displayReleasePlanButton ? ( {addConfigurationEnabled ? (
<PermissionButton <PermissionButton
data-testid='ADD_TEMPLATE_BUTTON' data-testid='ADD_STRATEGY_BUTTON'
permission={CREATE_FEATURE_STRATEGY} permission={CREATE_FEATURE_STRATEGY}
projectId={projectId} projectId={projectId}
environmentId={environmentId} environmentId={environmentId}
onClick={openReleasePlans} onClick={openMoreStrategies}
aria-labelledby={dialogId} aria-labelledby={dialogId}
variant='outlined' variant={variant}
sx={{ minWidth: matchWidth ? '282px' : 'auto' }} sx={{ minWidth: matchWidth ? '282px' : 'auto' }}
disabled={Boolean(disableReason)} disabled={Boolean(disableReason)}
tooltipProps={{ tooltipProps={{
title: disableReason ? disableReason : undefined, title: disableReason ? disableReason : undefined,
}} }}
> >
Use template Add configuration
</PermissionButton> </PermissionButton>
) : null} ) : (
<>
{displayReleasePlanButton ? (
<PermissionButton
data-testid='ADD_TEMPLATE_BUTTON'
permission={CREATE_FEATURE_STRATEGY}
projectId={projectId}
environmentId={environmentId}
onClick={openReleasePlans}
aria-labelledby={dialogId}
variant='outlined'
sx={{ minWidth: matchWidth ? '282px' : 'auto' }}
disabled={Boolean(disableReason)}
tooltipProps={{
title: disableReason
? disableReason
: undefined,
}}
>
Use template
</PermissionButton>
) : null}
<PermissionButton <PermissionButton
data-testid='ADD_STRATEGY_BUTTON' data-testid='ADD_STRATEGY_BUTTON'
permission={CREATE_FEATURE_STRATEGY} permission={CREATE_FEATURE_STRATEGY}
projectId={projectId} projectId={projectId}
environmentId={environmentId} environmentId={environmentId}
onClick={openDefaultStrategyCreationModal} onClick={openDefaultStrategyCreationModal}
aria-labelledby={dialogId} aria-labelledby={dialogId}
variant={variant} variant={variant}
sx={{ minWidth: matchWidth ? '282px' : 'auto' }} sx={{ minWidth: matchWidth ? '282px' : 'auto' }}
disabled={Boolean(disableReason)} disabled={Boolean(disableReason)}
tooltipProps={{ tooltipProps={{
title: disableReason ? disableReason : undefined, title: disableReason ? disableReason : undefined,
}} }}
> >
{label} {label}
</PermissionButton> </PermissionButton>
<StyledAdditionalMenuButton <StyledAdditionalMenuButton
permission={CREATE_FEATURE_STRATEGY} permission={CREATE_FEATURE_STRATEGY}
projectId={projectId} projectId={projectId}
environmentId={environmentId} environmentId={environmentId}
onClick={openMoreStrategies} onClick={openMoreStrategies}
variant='outlined' variant='outlined'
hideLockIcon hideLockIcon
disabled={Boolean(disableReason)} disabled={Boolean(disableReason)}
tooltipProps={{ tooltipProps={{
title: disableReason ? disableReason : 'More strategies', title: disableReason
}} ? disableReason
> : 'More strategies',
<MoreVert /> }}
</StyledAdditionalMenuButton> >
<MoreVert />
</StyledAdditionalMenuButton>
</>
)}
<Dialog <Dialog
open={isStrategyMenuDialogOpen} open={isStrategyMenuDialogOpen}
onClose={onClose} onClose={onClose}

View File

@ -1,11 +1,4 @@
import { import { Link, styled, Typography, Box, IconButton } from '@mui/material';
Link,
styled,
Typography,
Box,
IconButton,
Tooltip,
} from '@mui/material';
import { useStrategies } from 'hooks/api/getters/useStrategies/useStrategies'; import { useStrategies } from 'hooks/api/getters/useStrategies/useStrategies';
import { FeatureStrategyMenuCard } from '../FeatureStrategyMenuCard/FeatureStrategyMenuCard.tsx'; import { FeatureStrategyMenuCard } from '../FeatureStrategyMenuCard/FeatureStrategyMenuCard.tsx';
import { useReleasePlanTemplates } from 'hooks/api/getters/useReleasePlanTemplates/useReleasePlanTemplates'; import { useReleasePlanTemplates } from 'hooks/api/getters/useReleasePlanTemplates/useReleasePlanTemplates';
@ -13,10 +6,10 @@ import { FeatureReleasePlanCard } from '../FeatureReleasePlanCard/FeatureRelease
import type { IReleasePlanTemplate } from 'interfaces/releasePlans'; import type { IReleasePlanTemplate } from 'interfaces/releasePlans';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import CloseIcon from '@mui/icons-material/Close'; import CloseIcon from '@mui/icons-material/Close';
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
import FactCheckOutlinedIcon from '@mui/icons-material/FactCheckOutlined'; import FactCheckOutlinedIcon from '@mui/icons-material/FactCheckOutlined';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig.ts'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig.ts';
import { useUiFlag } from 'hooks/useUiFlag.ts'; import { useUiFlag } from 'hooks/useUiFlag.ts';
import { HelpIcon } from 'component/common/HelpIcon/HelpIcon.tsx';
interface IFeatureStrategyMenuCardsProps { interface IFeatureStrategyMenuCardsProps {
projectId: string; projectId: string;
@ -78,11 +71,6 @@ const SectionTitle = styled(Box)(({ theme }) => ({
width: '100%', width: '100%',
})); }));
const StyledInfoIcon = styled(InfoOutlinedIcon)(({ theme }) => ({
fontSize: theme.typography.body2.fontSize,
color: theme.palette.text.secondary,
}));
const StyledIcon = styled('span')(({ theme }) => ({ const StyledIcon = styled('span')(({ theme }) => ({
width: theme.spacing(3), width: theme.spacing(3),
'& > svg': { '& > svg': {
@ -162,55 +150,51 @@ export const FeatureStrategyMenuCards = ({
return null; 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 ( return (
<Box> <Box>
<SectionTitle> <SectionTitle>
<Typography color='inherit' variant='body2'> <Typography color='inherit' variant='body2'>
Apply a release template Release templates
</Typography> </Typography>
<Tooltip <HelpIcon
title='Use a predefined template to roll out features to users' tooltip='Use a predefined template to roll out features to users'
arrow size='16px'
> />
<StyledInfoIcon />
</Tooltip>
</SectionTitle> </SectionTitle>
<GridSection> {!templates.length ? (
{templates.map((template) => ( <EmptyStateContainer>
<CardWrapper key={template.id}> <EmptyStateTitle>
<FeatureReleasePlanCard <StyledIcon>
template={template} <FactCheckOutlinedIcon />
onClick={() => onAddReleasePlan(template)} </StyledIcon>
onPreviewClick={() => Create your own release templates
onReviewReleasePlan(template) </EmptyStateTitle>
} <EmptyStateDescription>
/> Standardize your rollouts and save time by reusing
</CardWrapper> predefined strategies. Find release templates in the
))} side menu under{' '}
</GridSection> <ClickableBoldText
onClick={() => navigate('/release-templates')}
>
Configure &gt; Release templates
</ClickableBoldText>
</EmptyStateDescription>
</EmptyStateContainer>
) : (
<GridSection>
{templates.map((template) => (
<CardWrapper key={template.id}>
<FeatureReleasePlanCard
template={template}
onClick={() => onAddReleasePlan(template)}
onPreviewClick={() =>
onReviewReleasePlan(template)
}
/>
</CardWrapper>
))}
</GridSection>
)}
</Box> </Box>
); );
}; };
@ -219,7 +203,7 @@ export const FeatureStrategyMenuCards = ({
<GridContainer> <GridContainer>
<TitleRow> <TitleRow>
<TitleText variant='h2'> <TitleText variant='h2'>
{onlyReleasePlans ? 'Select template' : 'Select strategy'} {onlyReleasePlans ? 'Select template' : 'Add configuration'}
</TitleText> </TitleText>
<IconButton <IconButton
size='small' size='small'
@ -238,14 +222,12 @@ export const FeatureStrategyMenuCards = ({
<Box> <Box>
<SectionTitle> <SectionTitle>
<Typography color='inherit' variant='body2'> <Typography color='inherit' variant='body2'>
Pre-defined strategy types Standard strategies
</Typography> </Typography>
<Tooltip <HelpIcon
title='Select a starting setup, and customize the strategy to your need with targeting and variants' tooltip='Select a starting setup, then customize your strategy with targeting and variants'
arrow size='16px'
> />
<StyledInfoIcon />
</Tooltip>
</SectionTitle> </SectionTitle>
<GridSection> <GridSection>
<CardWrapper key={defaultStrategy.name}> <CardWrapper key={defaultStrategy.name}>
@ -278,12 +260,10 @@ export const FeatureStrategyMenuCards = ({
<Typography color='inherit' variant='body2'> <Typography color='inherit' variant='body2'>
Custom strategies Custom strategies
</Typography> </Typography>
<Tooltip <HelpIcon
title='Custom strategies you have defined in Unleash' tooltip='Custom strategies you have defined in Unleash'
arrow size='16px'
> />
<StyledInfoIcon />
</Tooltip>
</SectionTitle> </SectionTitle>
<GridSection> <GridSection>
{customStrategies.map((strategy) => ( {customStrategies.map((strategy) => (

View File

@ -2,6 +2,8 @@ import type { FC } from 'react';
import { styled, Link } from '@mui/material'; import { styled, Link } from '@mui/material';
import type { Link as RouterLink } from 'react-router-dom'; import type { Link as RouterLink } from 'react-router-dom';
import { RELEASE_TEMPLATE_FEEDBACK } from 'constants/links'; import { RELEASE_TEMPLATE_FEEDBACK } from 'constants/links';
import { useUiFlag } from 'hooks/useUiFlag';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
const StyledLink = styled(Link<typeof RouterLink | 'a'>)(({ theme }) => ({ const StyledLink = styled(Link<typeof RouterLink | 'a'>)(({ theme }) => ({
display: 'flex', display: 'flex',
@ -13,14 +15,23 @@ const StyledLink = styled(Link<typeof RouterLink | 'a'>)(({ theme }) => ({
marginRight: 'auto', marginRight: 'auto',
})); }));
export const ReleaseTemplatesFeedback: FC = () => ( export const ReleaseTemplatesFeedback: FC = () => {
<StyledLink const { isEnterprise } = useUiConfig();
component='a' const releaseTemplatesEnabled = useUiFlag('releasePlans');
href={RELEASE_TEMPLATE_FEEDBACK}
underline='hover' if (!isEnterprise() || !releaseTemplatesEnabled) {
rel='noopener noreferrer' return null;
target='_blank' }
>
Give feedback to release templates return (
</StyledLink> <StyledLink
); component='a'
href={RELEASE_TEMPLATE_FEEDBACK}
underline='hover'
rel='noopener noreferrer'
target='_blank'
>
Give feedback to release templates
</StyledLink>
);
};

View File

@ -95,6 +95,7 @@ export type UiFlags = {
timestampsInChangeRequestTimeline?: boolean; timestampsInChangeRequestTimeline?: boolean;
reportUnknownFlags?: boolean; reportUnknownFlags?: boolean;
lifecycleGraphs?: boolean; lifecycleGraphs?: boolean;
addConfiguration?: boolean;
}; };
export interface IVersionInfo { export interface IVersionInfo {

View File

@ -65,7 +65,8 @@ export type IFlagKey =
| 'paygInstanceStatsEvents' | 'paygInstanceStatsEvents'
| 'timestampsInChangeRequestTimeline' | 'timestampsInChangeRequestTimeline'
| 'lifecycleGraphs' | 'lifecycleGraphs'
| 'githubAuth'; | 'githubAuth'
| 'addConfiguration';
export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>; export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>;
@ -305,6 +306,10 @@ const flags: IFlags = {
process.env.UNLEASH_EXPERIMENTAL_GITHUB_AUTH, process.env.UNLEASH_EXPERIMENTAL_GITHUB_AUTH,
false, false,
), ),
addConfiguration: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_ADD_CONFIGURATION,
false,
),
}; };
export const defaultExperimentalOptions: IExperimentalOptions = { export const defaultExperimentalOptions: IExperimentalOptions = {

View File

@ -61,6 +61,7 @@ process.nextTick(async () => {
paygTrialEvents: true, paygTrialEvents: true,
timestampsInChangeRequestTimeline: true, timestampsInChangeRequestTimeline: true,
lifecycleGraphs: true, lifecycleGraphs: true,
addConfiguration: true,
}, },
}, },
authentication: { authentication: {