1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-21 13:47:39 +02:00

chore: remove newStrategyDropdown flag (#9952)

This commit is contained in:
Jaanus Sellin 2025-05-12 11:11:25 +03:00 committed by GitHub
parent 920b550051
commit 095d4d7074
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 3 additions and 603 deletions

View File

@ -1,68 +0,0 @@
import { getFeatureStrategyIcon } from 'utils/strategyNames';
import StringTruncator from 'component/common/StringTruncator/StringTruncator';
import { Button, styled } from '@mui/material';
import type { IReleasePlanTemplate } from 'interfaces/releasePlans';
const StyledIcon = styled('div')(({ theme }) => ({
width: theme.spacing(4),
height: 'auto',
'& > svg': {
fill: theme.palette.primary.main,
},
'& > div': {
height: theme.spacing(2),
marginLeft: '-.75rem',
color: theme.palette.primary.main,
},
}));
const StyledDescription = styled('div')(({ theme }) => ({
fontSize: theme.fontSizes.smallBody,
fontWeight: theme.fontWeight.medium,
}));
const StyledName = styled(StringTruncator)(({ theme }) => ({
fontWeight: theme.fontWeight.bold,
}));
const StyledCard = styled(Button)(({ theme }) => ({
display: 'grid',
gridTemplateColumns: '3rem 1fr',
width: '20rem',
padding: theme.spacing(2),
color: 'inherit',
textDecoration: 'inherit',
lineHeight: 1.25,
borderWidth: '1px',
borderStyle: 'solid',
borderColor: theme.palette.divider,
borderRadius: theme.spacing(1),
textAlign: 'left',
'&:hover, &:focus': {
borderColor: theme.palette.primary.main,
},
}));
interface IFeatureReleasePlanCardProps {
template: IReleasePlanTemplate;
onClick: () => void;
}
export const OldFeatureReleasePlanCard = ({
template: { name, description },
onClick,
}: IFeatureReleasePlanCardProps) => {
const Icon = getFeatureStrategyIcon('releasePlanTemplate');
return (
<StyledCard onClick={onClick}>
<StyledIcon>
<Icon />
</StyledIcon>
<div>
<StyledName text={name} maxWidth='200' maxLength={25} />
<StyledDescription>{description}</StyledDescription>
</div>
</StyledCard>
);
};

View File

@ -21,7 +21,6 @@ import { formatUnknownError } from 'utils/formatUnknownError';
import { useUiFlag } from 'hooks/useUiFlag';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { ReleasePlanReviewDialog } from '../../FeatureView/FeatureOverview/ReleasePlan/ReleasePlanReviewDialog';
import { OldFeatureStrategyMenu } from './OldFeatureStrategyMenu';
interface IFeatureStrategyMenuProps {
label: string;
@ -48,18 +47,6 @@ const StyledAdditionalMenuButton = styled(PermissionButton)(({ theme }) => ({
paddingBlock: 0,
}));
export const FeatureStrategyMenuWrapper = (
props: IFeatureStrategyMenuProps,
) => {
const newStrategyDropdownEnabled = useUiFlag('newStrategyDropdown');
if (newStrategyDropdownEnabled) {
return <FeatureStrategyMenu {...props} />;
}
return <OldFeatureStrategyMenu {...props} />;
};
export const FeatureStrategyMenu = ({
label,
projectId,

View File

@ -1,103 +0,0 @@
import type { IStrategy } from 'interfaces/strategy';
import { Link } from 'react-router-dom';
import {
getFeatureStrategyIcon,
formatStrategyName,
} from 'utils/strategyNames';
import { formatCreateStrategyPath } from 'component/feature/FeatureStrategy/FeatureStrategyCreate/FeatureStrategyCreate';
import StringTruncator from 'component/common/StringTruncator/StringTruncator';
import { styled } from '@mui/material';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
interface IFeatureStrategyMenuCardProps {
projectId: string;
featureId: string;
environmentId: string;
strategy: Pick<IStrategy, 'name' | 'displayName' | 'description'> &
Partial<IStrategy>;
defaultStrategy?: boolean;
}
const StyledIcon = styled('div')(({ theme }) => ({
width: theme.spacing(4),
height: 'auto',
'& > svg': {
// Styling for SVG icons.
fill: theme.palette.primary.main,
},
'& > div': {
// Styling for the Rollout icon.
height: theme.spacing(2),
marginLeft: '-.75rem',
color: theme.palette.primary.main,
},
}));
const StyledDescription = styled('div')(({ theme }) => ({
fontSize: theme.fontSizes.smallBody,
}));
const StyledName = styled(StringTruncator)(({ theme }) => ({
fontWeight: theme.fontWeight.bold,
}));
const StyledCard = styled(Link)(({ theme }) => ({
display: 'grid',
gridTemplateColumns: '3rem 1fr',
width: '20rem',
padding: theme.spacing(2),
color: 'inherit',
textDecoration: 'inherit',
lineHeight: 1.25,
borderWidth: '1px',
borderStyle: 'solid',
borderColor: theme.palette.divider,
borderRadius: theme.spacing(1),
'&:hover, &:focus': {
borderColor: theme.palette.primary.main,
},
}));
export const OldFeatureStrategyMenuCard = ({
projectId,
featureId,
environmentId,
strategy,
defaultStrategy,
}: IFeatureStrategyMenuCardProps) => {
const StrategyIcon = getFeatureStrategyIcon(strategy.name);
const strategyName = formatStrategyName(strategy.name);
const { trackEvent } = usePlausibleTracker();
const createStrategyPath = formatCreateStrategyPath(
projectId,
featureId,
environmentId,
strategy.name,
defaultStrategy,
);
const openStrategyCreationModal = () => {
trackEvent('strategy-add', {
props: {
buttonTitle: strategy.displayName || strategyName,
},
});
};
return (
<StyledCard to={createStrategyPath} onClick={openStrategyCreationModal}>
<StyledIcon>
<StrategyIcon />
</StyledIcon>
<div>
<StyledName
text={strategy.displayName || strategyName}
maxWidth='200'
maxLength={25}
/>
<StyledDescription>{strategy.description}</StyledDescription>
</div>
</StyledCard>
);
};

View File

@ -1,155 +0,0 @@
import { Link, List, ListItem, styled, Typography } from '@mui/material';
import { useStrategies } from 'hooks/api/getters/useStrategies/useStrategies';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useReleasePlanTemplates } from 'hooks/api/getters/useReleasePlanTemplates/useReleasePlanTemplates';
import type { IReleasePlanTemplate } from 'interfaces/releasePlans';
import { useNavigate } from 'react-router-dom';
import { OldFeatureStrategyMenuCard } from '../FeatureStrategyMenuCard/OldFeatureStrategyMenuCard';
import { OldFeatureReleasePlanCard } from '../FeatureReleasePlanCard/OldFeatureReleasePlanCard';
interface IFeatureStrategyMenuCardsProps {
projectId: string;
featureId: string;
environmentId: string;
onlyReleasePlans: boolean;
onAddReleasePlan: (template: IReleasePlanTemplate) => void;
}
const StyledTypography = styled(Typography)(({ theme }) => ({
fontSize: theme.fontSizes.smallBody,
padding: theme.spacing(1, 2),
}));
const StyledLink = styled(Link)(({ theme }) => ({
fontSize: theme.fontSizes.smallBody,
cursor: 'pointer',
})) as typeof Link;
export const OldFeatureStrategyMenuCards = ({
projectId,
featureId,
environmentId,
onlyReleasePlans,
onAddReleasePlan,
}: IFeatureStrategyMenuCardsProps) => {
const { strategies } = useStrategies();
const { templates } = useReleasePlanTemplates();
const navigate = useNavigate();
const allStrategies = !onlyReleasePlans;
const preDefinedStrategies = strategies.filter(
(strategy) => !strategy.deprecated && !strategy.editable,
);
const customStrategies = strategies.filter(
(strategy) => !strategy.deprecated && strategy.editable,
);
const defaultStrategy = {
name: 'flexibleRollout',
displayName: 'Default strategy',
description:
'This is the default strategy defined for this environment in the project',
};
return (
<List dense>
{allStrategies ? (
<>
<StyledTypography color='textSecondary'>
Default strategy for {environmentId} environment
</StyledTypography>
<ListItem key={defaultStrategy.name}>
<OldFeatureStrategyMenuCard
projectId={projectId}
featureId={featureId}
environmentId={environmentId}
strategy={defaultStrategy}
defaultStrategy={true}
/>
</ListItem>
</>
) : null}
<ConditionallyRender
condition={templates.length > 0}
show={
<>
<StyledTypography color='textSecondary'>
Release templates
</StyledTypography>
{templates.map((template) => (
<ListItem key={template.id}>
<OldFeatureReleasePlanCard
template={template}
onClick={() => onAddReleasePlan(template)}
/>
</ListItem>
))}
</>
}
/>
<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')
}
>
Release templates
</StyledLink>
&nbsp;to get started
</p>
</StyledTypography>
</>
}
/>
{allStrategies ? (
<>
<StyledTypography color='textSecondary'>
Predefined strategy types
</StyledTypography>
{preDefinedStrategies.map((strategy) => (
<ListItem key={strategy.name}>
<OldFeatureStrategyMenuCard
projectId={projectId}
featureId={featureId}
environmentId={environmentId}
strategy={strategy}
/>
</ListItem>
))}
<ConditionallyRender
condition={customStrategies.length > 0}
show={
<>
<StyledTypography color='textSecondary'>
Custom strategies
</StyledTypography>
{customStrategies.map((strategy) => (
<ListItem key={strategy.name}>
<OldFeatureStrategyMenuCard
projectId={projectId}
featureId={featureId}
environmentId={environmentId}
strategy={strategy}
/>
</ListItem>
))}
</>
}
/>
</>
) : null}
</List>
);
};

View File

@ -1,254 +0,0 @@
import type React from 'react';
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import PermissionButton, {
type IPermissionButtonProps,
} from 'component/common/PermissionButton/PermissionButton';
import { CREATE_FEATURE_STRATEGY } from 'component/providers/AccessProvider/permissions';
import { Popover, styled } from '@mui/material';
import { formatCreateStrategyPath } from '../FeatureStrategyCreate/FeatureStrategyCreate';
import MoreVert from '@mui/icons-material/MoreVert';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
import type { IReleasePlanTemplate } from 'interfaces/releasePlans';
import { useChangeRequestApi } from 'hooks/api/actions/useChangeRequestApi/useChangeRequestApi';
import { usePendingChangeRequests } from 'hooks/api/getters/usePendingChangeRequests/usePendingChangeRequests';
import useToast from 'hooks/useToast';
import { ReleasePlanAddDialog } from 'component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlanAddDialog';
import { useReleasePlansApi } from 'hooks/api/actions/useReleasePlansApi/useReleasePlansApi';
import { useReleasePlans } from 'hooks/api/getters/useReleasePlans/useReleasePlans';
import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
import { formatUnknownError } from 'utils/formatUnknownError';
import { useUiFlag } from 'hooks/useUiFlag';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { OldFeatureStrategyMenuCards } from './FeatureStrategyMenuCards/OldFeatureStrategyMenuCards';
interface IFeatureStrategyMenuProps {
label: string;
projectId: string;
featureId: string;
environmentId: string;
variant?: IPermissionButtonProps['variant'];
matchWidth?: boolean;
size?: IPermissionButtonProps['size'];
disableReason?: string;
}
const StyledStrategyMenu = styled('div')(({ theme }) => ({
display: 'flex',
flexFlow: 'row',
justifyContent: 'flex-end',
gap: theme.spacing(1),
}));
const StyledAdditionalMenuButton = styled(PermissionButton)(({ theme }) => ({
minWidth: 0,
width: theme.spacing(4.5),
alignSelf: 'stretch',
paddingBlock: 0,
}));
export const OldFeatureStrategyMenu = ({
label,
projectId,
featureId,
environmentId,
variant,
size,
matchWidth,
disableReason,
}: IFeatureStrategyMenuProps) => {
const [anchor, setAnchor] = useState<Element>();
const [onlyReleasePlans, setOnlyReleasePlans] = useState<boolean>(false);
const navigate = useNavigate();
const { trackEvent } = usePlausibleTracker();
const [selectedTemplate, setSelectedTemplate] =
useState<IReleasePlanTemplate>();
const [addReleasePlanOpen, setAddReleasePlanOpen] = useState(false);
const isPopoverOpen = Boolean(anchor);
const popoverId = isPopoverOpen ? 'FeatureStrategyMenuPopover' : undefined;
const { setToastApiError, setToastData } = useToast();
const { isChangeRequestConfigured } = useChangeRequestsEnabled(projectId);
const { addChange } = useChangeRequestApi();
const { refetch: refetchChangeRequests } =
usePendingChangeRequests(projectId);
const { refetch } = useReleasePlans(projectId, featureId, environmentId);
const { addReleasePlanToFeature } = useReleasePlansApi();
const { isOss } = useUiConfig();
const releasePlansEnabled = useUiFlag('releasePlans');
const displayReleasePlanButton = !isOss() && releasePlansEnabled;
const crProtected =
releasePlansEnabled && isChangeRequestConfigured(environmentId);
const onClose = () => {
setAnchor(undefined);
};
const openDefaultStrategyCreationModal = (event: React.SyntheticEvent) => {
trackEvent('strategy-add', {
props: {
buttonTitle: label,
},
});
navigate(createStrategyPath);
};
const openMoreStrategies = (event: React.SyntheticEvent) => {
setOnlyReleasePlans(false);
setAnchor(event.currentTarget);
};
const openReleasePlans = (event: React.SyntheticEvent) => {
setOnlyReleasePlans(true);
setAnchor(event.currentTarget);
};
const addReleasePlan = async () => {
if (!selectedTemplate) return;
try {
if (crProtected) {
await addChange(projectId, environmentId, {
feature: featureId,
action: 'addReleasePlan',
payload: {
templateId: selectedTemplate.id,
},
});
setToastData({
type: 'success',
text: 'Added to draft',
});
refetchChangeRequests();
} else {
await addReleasePlanToFeature(
featureId,
selectedTemplate.id,
projectId,
environmentId,
);
setToastData({
type: 'success',
text: 'Release plan added',
});
refetch();
}
trackEvent('release-management', {
props: {
eventType: 'add-plan',
plan: selectedTemplate.name,
},
});
} catch (error: unknown) {
setToastApiError(formatUnknownError(error));
} finally {
setAddReleasePlanOpen(false);
setSelectedTemplate(undefined);
}
};
const createStrategyPath = formatCreateStrategyPath(
projectId,
featureId,
environmentId,
'flexibleRollout',
true,
);
return (
<StyledStrategyMenu onClick={(event) => event.stopPropagation()}>
{displayReleasePlanButton ? (
<PermissionButton
data-testid='ADD_TEMPLATE_BUTTON'
permission={CREATE_FEATURE_STRATEGY}
projectId={projectId}
environmentId={environmentId}
onClick={openReleasePlans}
aria-labelledby={popoverId}
variant='outlined'
sx={{ minWidth: matchWidth ? '282px' : 'auto' }}
disabled={Boolean(disableReason)}
tooltipProps={{
title: disableReason ? disableReason : undefined,
}}
>
Use template
</PermissionButton>
) : null}
<PermissionButton
data-testid='ADD_STRATEGY_BUTTON'
permission={CREATE_FEATURE_STRATEGY}
projectId={projectId}
environmentId={environmentId}
onClick={openDefaultStrategyCreationModal}
aria-labelledby={popoverId}
variant={variant}
sx={{ minWidth: matchWidth ? '282px' : 'auto' }}
disabled={Boolean(disableReason)}
tooltipProps={{
title: disableReason ? disableReason : undefined,
}}
>
{label}
</PermissionButton>
<StyledAdditionalMenuButton
permission={CREATE_FEATURE_STRATEGY}
projectId={projectId}
environmentId={environmentId}
onClick={openMoreStrategies}
variant='outlined'
hideLockIcon
disabled={Boolean(disableReason)}
tooltipProps={{
title: disableReason ? disableReason : 'More strategies',
}}
>
<MoreVert />
</StyledAdditionalMenuButton>
<Popover
id={popoverId}
open={isPopoverOpen}
anchorEl={anchor}
onClose={onClose}
onClick={onClose}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'left',
}}
PaperProps={{
sx: (theme) => ({
paddingBottom: theme.spacing(1),
}),
}}
>
<OldFeatureStrategyMenuCards
projectId={projectId}
featureId={featureId}
environmentId={environmentId}
onlyReleasePlans={onlyReleasePlans}
onAddReleasePlan={(template) => {
setSelectedTemplate(template);
setAddReleasePlanOpen(true);
}}
/>
</Popover>
{selectedTemplate && (
<ReleasePlanAddDialog
open={addReleasePlanOpen}
setOpen={setAddReleasePlanOpen}
onConfirm={addReleasePlan}
template={selectedTemplate}
projectId={projectId}
featureName={featureId}
environment={environmentId}
crProtected={crProtected}
/>
)}
</StyledStrategyMenu>
);
};

View File

@ -3,7 +3,7 @@ import type {
IFeatureEnvironment,
IFeatureEnvironmentMetrics,
} from 'interfaces/featureToggle';
import { FeatureStrategyMenuWrapper } from 'component/feature/FeatureStrategy/FeatureStrategyMenu/FeatureStrategyMenu';
import { FeatureStrategyMenu } from 'component/feature/FeatureStrategy/FeatureStrategyMenu/FeatureStrategyMenu';
import { FEATURE_ENVIRONMENT_ACCORDION } from 'utils/testIds';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import { UpgradeChangeRequests } from './UpgradeChangeRequests/UpgradeChangeRequests';
@ -103,7 +103,7 @@ export const FeatureOverviewEnvironment = ({
environment={environment}
/>
{!hasActivations ? (
<FeatureStrategyMenuWrapper
<FeatureStrategyMenu
label='Add strategy'
projectId={projectId}
featureId={featureId}
@ -129,7 +129,7 @@ export const FeatureOverviewEnvironment = ({
<Box sx={{ display: 'flex', flexDirection: 'row' }}>
<ReleaseTemplatesFeedback />
<Box ml='auto'>
<FeatureStrategyMenuWrapper
<FeatureStrategyMenu
label='Add strategy'
projectId={projectId}
featureId={featureId}

View File

@ -91,7 +91,6 @@ export type UiFlags = {
edgeObservability?: boolean;
tagTypeColor?: boolean;
addEditStrategy?: boolean;
newStrategyDropdown?: boolean;
flagsReleaseManagementUI?: boolean;
cleanupReminder?: boolean;
registerFrontendClient?: boolean;

View File

@ -62,7 +62,6 @@ export type IFlagKey =
| 'edgeObservability'
| 'tagTypeColor'
| 'addEditStrategy'
| 'newStrategyDropdown'
| 'flagsOverviewSearch'
| 'flagsReleaseManagementUI'
| 'cleanupReminder'
@ -299,10 +298,6 @@ const flags: IFlags = {
process.env.UNLEASH_EXPERIMENTAL_ADD_EDIT_STRATEGY,
false,
),
newStrategyDropdown: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_NEW_STRATEGY_DROPDOWN,
false,
),
flagsOverviewSearch: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_FLAGS_OVERVIEW_SEARCH,
false,

View File

@ -55,7 +55,6 @@ process.nextTick(async () => {
filterExistingFlagNames: true,
teamsIntegrationChangeRequests: true,
tagTypeColor: true,
newStrategyDropdown: true,
addEditStrategy: true,
flagsOverviewSearch: true,
cleanupReminder: true,