mirror of
https://github.com/Unleash/unleash.git
synced 2025-08-04 13:48:56 +02:00
chore: split standard and advanced strategy types (#10433)
https://linear.app/unleash/issue/2-3733/update-strategy-types-to-match-the-new-designs This updates our strategy types page to match the new designs. Part of this means visually separating what we are considering "standard" strategies from "advanced" strategies. <img width="1520" height="981" alt="image" src="https://github.com/user-attachments/assets/2682013b-d9df-453d-9427-62871e74d46a" />
This commit is contained in:
parent
0f565c50e9
commit
c5b37fc7c2
@ -31,6 +31,7 @@ import { Badge } from 'component/common/Badge/Badge';
|
||||
import { HelpIcon } from 'component/common/HelpIcon/HelpIcon';
|
||||
import { CustomStrategyInfo } from '../CustomStrategyInfo/CustomStrategyInfo.tsx';
|
||||
import { AddStrategyButton } from './AddStrategyButton/AddStrategyButton.tsx';
|
||||
import { usePageTitle } from 'hooks/usePageTitle.ts';
|
||||
|
||||
interface IDialogueMetaData {
|
||||
show: boolean;
|
||||
@ -38,89 +39,70 @@ interface IDialogueMetaData {
|
||||
onConfirm: () => void;
|
||||
}
|
||||
|
||||
const StyledBox = styled(Box)(({ theme }) => ({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: theme.spacing(2),
|
||||
}));
|
||||
|
||||
const StyledBadge = styled(Badge)(({ theme }) => ({
|
||||
marginLeft: theme.spacing(1),
|
||||
display: 'inline-block',
|
||||
}));
|
||||
|
||||
const StyledTypography = styled(Typography)(({ theme }) => ({
|
||||
const StyledTitle = styled(Box)(({ theme }) => ({
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: theme.spacing(1),
|
||||
fontSize: theme.fontSizes.mainHeader,
|
||||
width: '100%',
|
||||
}));
|
||||
|
||||
const Subtitle: FC<{
|
||||
const StyledSubtitle = styled(Box)(({ theme }) => ({
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
marginBottom: theme.spacing(2),
|
||||
'& > span': {
|
||||
fontWeight: theme.fontWeight.bold,
|
||||
},
|
||||
}));
|
||||
|
||||
const Title: FC<{
|
||||
title: string;
|
||||
description: string;
|
||||
link: string;
|
||||
}> = ({ title, description, link }) => (
|
||||
<StyledTypography>
|
||||
<StyledTitle>
|
||||
{title}
|
||||
<HelpIcon
|
||||
htmlTooltip
|
||||
tooltip={
|
||||
<>
|
||||
<Typography
|
||||
variant='body2'
|
||||
component='p'
|
||||
sx={(theme) => ({ marginBottom: theme.spacing(1) })}
|
||||
>
|
||||
<Typography variant='body2' component='p' sx={{ mb: 1 }}>
|
||||
{description}
|
||||
</Typography>
|
||||
<Link href={link} target='_blank' variant='body2'>
|
||||
<Link
|
||||
href={link}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
variant='body2'
|
||||
>
|
||||
Read more in the documentation
|
||||
</Link>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</StyledTypography>
|
||||
);
|
||||
|
||||
const CustomStrategyTitle: FC = () => (
|
||||
<Box
|
||||
sx={(theme) => ({
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: theme.spacing(1.5),
|
||||
})}
|
||||
>
|
||||
<Subtitle
|
||||
title='Custom strategies'
|
||||
description='Custom activation strategies let you define your own activation strategies to use with Unleash.'
|
||||
link='https://docs.getunleash.io/reference/custom-activation-strategies'
|
||||
/>
|
||||
<AddStrategyButton />
|
||||
</Box>
|
||||
);
|
||||
|
||||
const PredefinedStrategyTitle = () => (
|
||||
<Box>
|
||||
<Subtitle
|
||||
title='Predefined strategies'
|
||||
description='Activation strategies let you enable a feature only for a specified audience. Different strategies use different parameters. Predefined strategies are bundled with Unleash.'
|
||||
link='https://docs.getunleash.io/reference/activation-strategies'
|
||||
/>
|
||||
</Box>
|
||||
</StyledTitle>
|
||||
);
|
||||
|
||||
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{' '}
|
||||
instead using the gradual rollout strategy with{' '}
|
||||
<Link
|
||||
href={
|
||||
'https://docs.getunleash.io/reference/activation-strategies#constraints'
|
||||
}
|
||||
target='_blank'
|
||||
variant='body2'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
constraints
|
||||
</Link>
|
||||
@ -129,6 +111,28 @@ const StrategyDeprecationWarning = () => (
|
||||
</Alert>
|
||||
);
|
||||
|
||||
const RecommendationAlert = () => (
|
||||
<Alert severity='info' sx={{ mb: 2 }}>
|
||||
We recommend using gradual rollout. You can customize it with{' '}
|
||||
<Link
|
||||
href='https://docs.getunleash.io/reference/activation-strategies#constraints'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
constraints
|
||||
</Link>{' '}
|
||||
and{' '}
|
||||
<Link
|
||||
href='https://docs.getunleash.io/reference/activation-strategies#variants'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
variants
|
||||
</Link>
|
||||
.
|
||||
</Alert>
|
||||
);
|
||||
|
||||
export const StrategiesList = () => {
|
||||
const navigate = useNavigate();
|
||||
const [dialogueMetaData, setDialogueMetaData] = useState<IDialogueMetaData>(
|
||||
@ -144,6 +148,8 @@ export const StrategiesList = () => {
|
||||
useStrategiesApi();
|
||||
const { setToastData, setToastApiError } = useToast();
|
||||
|
||||
usePageTitle('Strategy types');
|
||||
|
||||
const data = useMemo(() => {
|
||||
if (loading) {
|
||||
const mock = Array(5).fill({
|
||||
@ -152,22 +158,28 @@ export const StrategiesList = () => {
|
||||
});
|
||||
return {
|
||||
all: mock,
|
||||
predefined: mock,
|
||||
standard: mock,
|
||||
advanced: mock,
|
||||
custom: mock,
|
||||
};
|
||||
}
|
||||
|
||||
const all = strategies.map(
|
||||
({ name, description, editable, deprecated }) => ({
|
||||
({ name, description, editable, deprecated, advanced }) => ({
|
||||
name,
|
||||
description,
|
||||
editable,
|
||||
deprecated,
|
||||
advanced,
|
||||
}),
|
||||
);
|
||||
|
||||
const predefined = all.filter((strategy) => !strategy.editable);
|
||||
|
||||
return {
|
||||
all,
|
||||
predefined: all.filter((strategy) => !strategy.editable),
|
||||
standard: predefined.filter((strategy) => !strategy.advanced),
|
||||
advanced: predefined.filter((strategy) => strategy.advanced),
|
||||
custom: all.filter((strategy) => strategy.editable),
|
||||
};
|
||||
}, [strategies, loading]);
|
||||
@ -350,19 +362,43 @@ export const StrategiesList = () => {
|
||||
[],
|
||||
);
|
||||
|
||||
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } =
|
||||
useTable(
|
||||
{
|
||||
columns: columns as any[], // TODO: fix after `react-table` v8 update
|
||||
data: data.predefined,
|
||||
initialState,
|
||||
sortTypes,
|
||||
autoResetSortBy: false,
|
||||
disableSortRemove: true,
|
||||
autoResetHiddenColumns: false,
|
||||
},
|
||||
useSortBy,
|
||||
);
|
||||
const {
|
||||
getTableProps,
|
||||
getTableBodyProps,
|
||||
headerGroups,
|
||||
rows: standardRows,
|
||||
prepareRow,
|
||||
} = useTable(
|
||||
{
|
||||
columns: columns as any[], // TODO: fix after `react-table` v8 update
|
||||
data: data.standard,
|
||||
initialState,
|
||||
sortTypes,
|
||||
autoResetSortBy: false,
|
||||
disableSortRemove: true,
|
||||
autoResetHiddenColumns: false,
|
||||
},
|
||||
useSortBy,
|
||||
);
|
||||
|
||||
const {
|
||||
getTableProps: advancedGetTableProps,
|
||||
getTableBodyProps: advancedGetTableBodyProps,
|
||||
headerGroups: advancedHeaderGroups,
|
||||
rows: advancedRows,
|
||||
prepareRow: advancedPrepareRow,
|
||||
} = useTable(
|
||||
{
|
||||
columns: columns as any[], // TODO: fix after `react-table` v8 update
|
||||
data: data.advanced,
|
||||
initialState,
|
||||
sortTypes,
|
||||
autoResetSortBy: false,
|
||||
disableSortRemove: true,
|
||||
autoResetHiddenColumns: false,
|
||||
},
|
||||
useSortBy,
|
||||
);
|
||||
|
||||
const {
|
||||
getTableProps: customGetTableProps,
|
||||
@ -392,21 +428,25 @@ export const StrategiesList = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledBox>
|
||||
<>
|
||||
<PageContent
|
||||
isLoading={loading}
|
||||
header={
|
||||
<PageHeader
|
||||
titleElement={<PredefinedStrategyTitle />}
|
||||
title='Strategy types'
|
||||
/>
|
||||
<PageHeader>
|
||||
<Title
|
||||
title='Standard strategies'
|
||||
description='Standard strategies let you enable a feature only for a specified audience. Select a starting setup, then customize your strategy with targeting and variants.'
|
||||
link='https://docs.getunleash.io/reference/activation-strategies'
|
||||
/>
|
||||
</PageHeader>
|
||||
}
|
||||
>
|
||||
<Box>
|
||||
<RecommendationAlert />
|
||||
<Table {...getTableProps()}>
|
||||
<SortableTableHeader headerGroups={headerGroups} />
|
||||
<TableBody {...getTableBodyProps()}>
|
||||
{rows.map((row) => {
|
||||
{standardRows.map((row) => {
|
||||
prepareRow(row);
|
||||
const { key, ...rowProps } = row.getRowProps();
|
||||
return (
|
||||
@ -430,7 +470,7 @@ export const StrategiesList = () => {
|
||||
</TableBody>
|
||||
</Table>
|
||||
<ConditionallyRender
|
||||
condition={rows.length === 0}
|
||||
condition={standardRows.length === 0}
|
||||
show={
|
||||
<TablePlaceholder>
|
||||
No strategies available.
|
||||
@ -455,11 +495,61 @@ export const StrategiesList = () => {
|
||||
isLoading={loading}
|
||||
header={
|
||||
<PageHeader>
|
||||
<CustomStrategyTitle />
|
||||
<Title
|
||||
title='Advanced and custom strategies'
|
||||
description='Advanced strategies let you target based on specific properties. Custom activation strategies let you define your own activation strategies to use with Unleash.'
|
||||
link='https://docs.getunleash.io/reference/custom-activation-strategies'
|
||||
/>
|
||||
</PageHeader>
|
||||
}
|
||||
sx={{ mt: 2 }}
|
||||
>
|
||||
<Box>
|
||||
<StyledSubtitle>
|
||||
<span>Advanced strategies</span>
|
||||
</StyledSubtitle>
|
||||
<Table {...advancedGetTableProps()}>
|
||||
<SortableTableHeader
|
||||
headerGroups={advancedHeaderGroups}
|
||||
/>
|
||||
<TableBody {...advancedGetTableBodyProps()}>
|
||||
{advancedRows.map((row) => {
|
||||
advancedPrepareRow(row);
|
||||
const { key, ...rowProps } = row.getRowProps();
|
||||
return (
|
||||
<TableRow hover key={key} {...rowProps}>
|
||||
{row.cells.map((cell) => {
|
||||
const { key, ...cellProps } =
|
||||
cell.getCellProps();
|
||||
|
||||
return (
|
||||
<TableCell
|
||||
key={key}
|
||||
{...cellProps}
|
||||
>
|
||||
{cell.render('Cell')}
|
||||
</TableCell>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<ConditionallyRender
|
||||
condition={advancedRows.length === 0}
|
||||
show={
|
||||
<TablePlaceholder>
|
||||
No advanced strategies available.
|
||||
</TablePlaceholder>
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
<Box>
|
||||
<StyledSubtitle sx={{ mt: 4 }}>
|
||||
<span>Custom strategies</span>
|
||||
<AddStrategyButton />
|
||||
</StyledSubtitle>
|
||||
<StrategyDeprecationWarning />
|
||||
<Table {...customGetTableProps()}>
|
||||
<SortableTableHeader
|
||||
@ -507,6 +597,6 @@ export const StrategiesList = () => {
|
||||
}
|
||||
/>
|
||||
</PageContent>
|
||||
</StyledBox>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -11,6 +11,13 @@ interface IUseStrategiesOutput {
|
||||
error?: Error;
|
||||
}
|
||||
|
||||
const STANDARD_STRATEGIES = ['flexibleRollout', 'default'];
|
||||
const mapAdvancedStrategies = (strategies: IStrategy[]): IStrategy[] =>
|
||||
strategies.map((strategy) => ({
|
||||
...strategy,
|
||||
advanced: !STANDARD_STRATEGIES.includes(strategy.name),
|
||||
}));
|
||||
|
||||
export const useStrategies = (): IUseStrategiesOutput => {
|
||||
const { data, error } = useSWR(STRATEGIES_PATH, fetcher);
|
||||
|
||||
@ -19,7 +26,9 @@ export const useStrategies = (): IUseStrategiesOutput => {
|
||||
}, []);
|
||||
|
||||
return {
|
||||
strategies: data?.strategies || defaultStrategies,
|
||||
strategies: mapAdvancedStrategies(
|
||||
data?.strategies || defaultStrategies,
|
||||
),
|
||||
refetchStrategies,
|
||||
loading: !error && !data,
|
||||
error,
|
||||
|
@ -41,6 +41,7 @@ export interface IStrategy {
|
||||
displayName: string;
|
||||
editable: boolean;
|
||||
deprecated: boolean;
|
||||
advanced?: boolean;
|
||||
description: string;
|
||||
parameters: IStrategyParameter[];
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user