1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-25 00:07:47 +01:00

chore: deprecate custom strategies (#7186)

This commit is contained in:
Simon Hornby 2024-05-28 12:33:53 +02:00 committed by GitHub
parent 0c4d4643bd
commit f16f8594f5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 127 additions and 42 deletions

View File

@ -10,6 +10,7 @@ import {
Box, Box,
Divider, Divider,
Typography, Typography,
Link,
} from '@mui/material'; } from '@mui/material';
import type { import type {
IFeatureStrategy, IFeatureStrategy,
@ -42,7 +43,7 @@ import { useHasProjectEnvironmentAccess } from 'hooks/useHasAccess';
import { FeatureStrategyTitle } from './FeatureStrategyTitle/FeatureStrategyTitle'; import { FeatureStrategyTitle } from './FeatureStrategyTitle/FeatureStrategyTitle';
import { FeatureStrategyEnabledDisabled } from './FeatureStrategyEnabledDisabled/FeatureStrategyEnabledDisabled'; import { FeatureStrategyEnabledDisabled } from './FeatureStrategyEnabledDisabled/FeatureStrategyEnabledDisabled';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
import { formatStrategyName } from 'utils/strategyNames'; import { BuiltInStrategies, formatStrategyName } from 'utils/strategyNames';
import { Badge } from 'component/common/Badge/Badge'; import { Badge } from 'component/common/Badge/Badge';
import EnvironmentIcon from 'component/common/EnvironmentIcon/EnvironmentIcon'; import EnvironmentIcon from 'component/common/EnvironmentIcon/EnvironmentIcon';
@ -389,6 +390,29 @@ export const FeatureStrategyForm = ({
/> />
} }
/> />
<ConditionallyRender
condition={
!BuiltInStrategies.includes(strategy.name || 'default')
}
show={
<Alert severity='warning'>
Custom strategies are deprecated. We recommend not
adding them to any flags going forward and using the
predefined strategies like Gradual rollout with{' '}
<Link
href={
'https://docs.getunleash.io/reference/strategy-constraints'
}
target='_blank'
variant='body2'
>
constraints
</Link>{' '}
instead.
</Alert>
}
/>
<FeatureStrategyEnabled <FeatureStrategyEnabled
projectId={feature.project} projectId={feature.project}
featureId={feature.name} featureId={feature.name}

View File

@ -1,5 +1,5 @@
import { Fragment, useMemo, type VFC } from 'react'; import { Fragment, useMemo, type VFC } from 'react';
import { Box, Chip, styled } from '@mui/material'; import { Alert, Box, Chip, Link, styled } from '@mui/material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import PercentageCircle from 'component/common/PercentageCircle/PercentageCircle'; import PercentageCircle from 'component/common/PercentageCircle/PercentageCircle';
import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator'; import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator';
@ -17,6 +17,7 @@ import StringTruncator from 'component/common/StringTruncator/StringTruncator';
import { Badge } from 'component/common/Badge/Badge'; import { Badge } from 'component/common/Badge/Badge';
import type { CreateFeatureStrategySchema } from 'openapi'; import type { CreateFeatureStrategySchema } from 'openapi';
import type { IFeatureStrategyPayload } from 'interfaces/strategy'; import type { IFeatureStrategyPayload } from 'interfaces/strategy';
import { BuiltInStrategies } from 'utils/strategyNames';
interface IStrategyExecutionProps { interface IStrategyExecutionProps {
strategy: IFeatureStrategyPayload | CreateFeatureStrategySchema; strategy: IFeatureStrategyPayload | CreateFeatureStrategySchema;
@ -41,6 +42,20 @@ const StyledContainer = styled(Box, {
}, },
})); }));
const CustomStrategyDeprecationWarning = () => (
<Alert severity='warning' sx={{ mb: 2 }}>
Custom strategies are deprecated and may be removed in a future major
version. Consider rewriting this strategy as a predefined strategy with{' '}
<Link
href={'https://docs.getunleash.io/reference/strategy-constraints'}
target='_blank'
variant='body2'
>
constraints.
</Link>
</Alert>
);
const NoItems: VFC = () => ( const NoItems: VFC = () => (
<Box sx={{ px: 3, color: 'text.disabled' }}> <Box sx={{ px: 3, color: 'text.disabled' }}>
This strategy does not have constraints or parameters. This strategy does not have constraints or parameters.
@ -299,22 +314,31 @@ export const StrategyExecution: VFC<IStrategyExecutionProps> = ({
].filter(Boolean); ].filter(Boolean);
return ( return (
<ConditionallyRender <>
condition={listItems.length > 0} <ConditionallyRender
show={ condition={
<StyledContainer disabled={Boolean(strategy.disabled)}> !BuiltInStrategies.includes(strategy.name || 'default')
{listItems.map((item, index) => ( }
<Fragment key={index}> show={<CustomStrategyDeprecationWarning />}
<ConditionallyRender />
condition={index > 0}
show={<StrategySeparator text='AND' />} <ConditionallyRender
/> condition={listItems.length > 0}
{item} show={
</Fragment> <StyledContainer disabled={Boolean(strategy.disabled)}>
))} {listItems.map((item, index) => (
</StyledContainer> <Fragment key={index}>
} <ConditionallyRender
elseShow={<NoItems />} condition={index > 0}
/> show={<StrategySeparator text='AND' />}
/>
{item}
</Fragment>
))}
</StyledContainer>
}
elseShow={<NoItems />}
/>
</>
); );
}; };

View File

@ -1,15 +1,5 @@
import type { PlaygroundFeatureSchema } from 'openapi'; import type { PlaygroundFeatureSchema } from 'openapi';
import { BuiltInStrategies } from 'utils/strategyNames';
export const DEFAULT_STRATEGIES = [
'default',
'applicationHostname',
'flexibleRollout',
'gradualRolloutRandom',
'gradualRolloutSessionId',
'gradualRolloutUserId',
'remoteAddress',
'userWithId',
];
export function checkForEmptyValues(object?: Object): boolean { export function checkForEmptyValues(object?: Object): boolean {
if (object === undefined) { if (object === undefined) {
@ -22,7 +12,7 @@ export function checkForEmptyValues(object?: Object): boolean {
export const hasCustomStrategies = (feature: PlaygroundFeatureSchema) => { export const hasCustomStrategies = (feature: PlaygroundFeatureSchema) => {
return feature.strategies?.data?.find( return feature.strategies?.data?.find(
(strategy) => !DEFAULT_STRATEGIES.includes(strategy.name), (strategy) => !BuiltInStrategies.includes(strategy.name),
); );
}; };
@ -30,7 +20,7 @@ export const hasOnlyCustomStrategies = (feature: PlaygroundFeatureSchema) => {
return ( return (
feature.strategies?.data?.length > 0 && feature.strategies?.data?.length > 0 &&
!feature.strategies?.data?.find((strategy) => !feature.strategies?.data?.find((strategy) =>
DEFAULT_STRATEGIES.includes(strategy.name), BuiltInStrategies.includes(strategy.name),
) )
); );
}; };

View File

@ -1,4 +1,4 @@
import { useNavigate } from 'react-router-dom'; import { useNavigate, Link } from 'react-router-dom';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import useToast from 'hooks/useToast'; import useToast from 'hooks/useToast';
import FormTemplate from 'component/common/FormTemplate/FormTemplate'; import FormTemplate from 'component/common/FormTemplate/FormTemplate';
@ -11,6 +11,25 @@ import { formatUnknownError } from 'utils/formatUnknownError';
import { CreateButton } from 'component/common/CreateButton/CreateButton'; import { CreateButton } from 'component/common/CreateButton/CreateButton';
import { GO_BACK } from 'constants/navigate'; import { GO_BACK } from 'constants/navigate';
import { CustomStrategyInfo } from '../CustomStrategyInfo/CustomStrategyInfo'; import { CustomStrategyInfo } from '../CustomStrategyInfo/CustomStrategyInfo';
import { Alert } from '@mui/material';
const CreateStrategyDeprecationWarning = () => (
<Alert
severity='warning'
sx={(theme) => ({
marginBottom: theme.spacing(3),
})}
>
Custom strategies are deprecated and may be removed in a future major
release. We recommend using the predefined strategies like Gradual
rollout with{' '}
<Link to='https://docs.getunleash.io/reference/strategy-constraints'>
{' '}
constraints
</Link>{' '}
instead of creating a custom strategy.
</Alert>
);
export const CreateStrategy = () => { export const CreateStrategy = () => {
const { setToastData, setToastApiError } = useToast(); const { setToastData, setToastApiError } = useToast();
@ -77,6 +96,7 @@ export const CreateStrategy = () => {
documentationLinkLabel='Custom strategies documentation' documentationLinkLabel='Custom strategies documentation'
formatApiCode={formatApiCode} formatApiCode={formatApiCode}
> >
<CreateStrategyDeprecationWarning />
<CustomStrategyInfo alert /> <CustomStrategyInfo alert />
<StrategyForm <StrategyForm
errors={errors} errors={errors}

View File

@ -17,11 +17,8 @@ export const CustomStrategyInfo: FC<{ alert?: boolean }> = ({ alert }) => {
const content = ( const content = (
<> <>
<Paragraph> <Paragraph>
We recommend you to use the predefined strategies like Gradual If you decide to create a custom strategy be aware of the
rollout with constraints instead of creating a custom strategy. following:
</Paragraph>
<Paragraph>
If you decide to create a custom strategy be aware of:
<ul> <ul>
<li> <li>
They require writing custom code and deployments for They require writing custom code and deployments for
@ -32,8 +29,8 @@ export const CustomStrategyInfo: FC<{ alert?: boolean }> = ({ alert }) => {
to evaluate differently to evaluate differently
</li> </li>
<li> <li>
Requires a lot of configuration in both Unleash admin UI Custom strategies require a lot of configuration in both
and the SDK. Unleash admin UI and the SDK.
</li> </li>
</ul> </ul>
</Paragraph> </Paragraph>

View File

@ -1,6 +1,6 @@
import { useState, useMemo, useCallback, type FC } from 'react'; import { useState, useMemo, useCallback, type FC } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { Box, Link, Typography, styled } from '@mui/material'; import { Alert, Box, Link, Typography, styled } from '@mui/material';
import Extension from '@mui/icons-material/Extension'; import Extension from '@mui/icons-material/Extension';
import { import {
Table, Table,
@ -110,6 +110,23 @@ const PredefinedStrategyTitle = () => (
</Box> </Box>
); );
const StrategyDeprecationWarning = () => (
<Alert severity='warning' sx={{ mb: 2 }}>
Custom strategies are deprecated and may be removed in a future major
version. We recommend not using custom strategies going forward and
instead using the predefined strategies with{' '}
<Link
href={'https://docs.getunleash.io/reference/strategy-constraints'}
target='_blank'
variant='body2'
>
constraints
</Link>
. If you have a need for custom strategies that you cannot support with
constraints, please reach out to us.
</Alert>
);
export const StrategiesList = () => { export const StrategiesList = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const [dialogueMetaData, setDialogueMetaData] = useState<IDialogueMetaData>( const [dialogueMetaData, setDialogueMetaData] = useState<IDialogueMetaData>(
@ -434,6 +451,7 @@ export const StrategiesList = () => {
} }
> >
<Box> <Box>
<StrategyDeprecationWarning />
<Table {...customGetTableProps()}> <Table {...customGetTableProps()}>
<SortableTableHeader <SortableTableHeader
headerGroups={customHeaderGroups} headerGroups={customHeaderGroups}

View File

@ -36,6 +36,17 @@ export const getFeatureStrategyIcon = (strategyName: string) => {
} }
}; };
export const BuiltInStrategies = [
'default',
'applicationHostname',
'flexibleRollout',
'gradualRolloutRandom',
'gradualRolloutSessionId',
'gradualRolloutUserId',
'remoteAddress',
'userWithId',
];
export const GetFeatureStrategyIcon: FC<{ strategyName: string }> = ({ export const GetFeatureStrategyIcon: FC<{ strategyName: string }> = ({
strategyName, strategyName,
}) => { }) => {

View File

@ -122,11 +122,12 @@ class StrategyController extends Controller {
permission: CREATE_STRATEGY, permission: CREATE_STRATEGY,
middleware: [ middleware: [
openApiService.validPath({ openApiService.validPath({
deprecated: true,
tags: ['Strategies'], tags: ['Strategies'],
operationId: 'createStrategy', operationId: 'createStrategy',
summary: 'Create a strategy', summary: 'Create a strategy',
description: description:
'Creates a strategy type based on the supplied data.', 'Creates a custom strategy type based on the supplied data. Custom strategies are deprecated and should not be used. Prefer using built in strategies with constraints instead.',
requestBody: createRequestSchema('createStrategySchema'), requestBody: createRequestSchema('createStrategySchema'),
responses: { responses: {
201: resourceCreatedResponseSchema('strategySchema'), 201: resourceCreatedResponseSchema('strategySchema'),