diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/MenuStrategyRemove/DisableEnableStrategyDialog/DisableEnableStrategyDialog.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/MenuStrategyRemove/DisableEnableStrategyDialog/DisableEnableStrategyDialog.tsx
index 1672131e34..5d263342aa 100644
--- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/MenuStrategyRemove/DisableEnableStrategyDialog/DisableEnableStrategyDialog.tsx
+++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/MenuStrategyRemove/DisableEnableStrategyDialog/DisableEnableStrategyDialog.tsx
@@ -47,7 +47,9 @@ export const DisableEnableStrategyDialog = ({
? `Add ${
disabled ? 'enable' : 'disable'
} strategy to change request?`
- : 'Are you sure you want to enable this strategy?'
+ : `Are you sure you want to ${
+ disabled ? 'enable' : 'disable'
+ } this strategy?`
}
open={isOpen}
primaryButtonText={
diff --git a/frontend/src/component/strategies/CreateStrategy/CreateStrategy.tsx b/frontend/src/component/strategies/CreateStrategy/CreateStrategy.tsx
index 3eddca5508..6ce07e1121 100644
--- a/frontend/src/component/strategies/CreateStrategy/CreateStrategy.tsx
+++ b/frontend/src/component/strategies/CreateStrategy/CreateStrategy.tsx
@@ -10,6 +10,7 @@ import { useStrategies } from 'hooks/api/getters/useStrategies/useStrategies';
import { formatUnknownError } from 'utils/formatUnknownError';
import { CreateButton } from 'component/common/CreateButton/CreateButton';
import { GO_BACK } from 'constants/navigate';
+import { CustomStrategyInfo } from '../CustomStrategyInfo/CustomStrategyInfo';
export const CreateStrategy = () => {
const { setToastData, setToastApiError } = useToast();
@@ -78,6 +79,7 @@ export const CreateStrategy = () => {
documentationLinkLabel="Custom strategies documentation"
formatApiCode={formatApiCode}
>
+
(
+ ({
+ marginBottom: theme.spacing(2),
+ })}
+ >
+ {children}
+
+);
+
+export const CustomStrategyInfo: FC<{ alert?: boolean }> = ({ alert }) => {
+ const content = (
+ <>
+
+ We recommend you to use the predefined strategies like Gradual
+ rollout with constraints instead of creating a custom strategy.
+
+
+ If you decide to create a custom strategy be aware of:
+
+ -
+ They require writing custom code and deployments for
+ each SDK you’re using.
+
+ -
+ Differing implementation in each SDK will cause toggles
+ to evaluate differently
+
+ -
+ Requires a lot of configuration in both Unleash admin UI
+ and the SDK.
+
+
+
+
+ Constraints don’t have these problems. They’re configured once
+ in the admin UI and behave in the same way in each SDK without
+ further configuration.
+
+ >
+ );
+
+ if (alert) {
+ return (
+ ({
+ marginBottom: theme.spacing(3),
+ })}
+ >
+ {content}
+
+ );
+ }
+
+ return (
+ ({
+ maxWidth: '720px',
+ padding: theme.spacing(4, 2),
+ margin: '0 auto',
+ })}
+ >
+ {content}
+
+ );
+};
diff --git a/frontend/src/component/strategies/StrategiesList/AddStrategyButton/AddStrategyButton.tsx b/frontend/src/component/strategies/StrategiesList/AddStrategyButton/AddStrategyButton.tsx
index e45285b3a4..57971c1174 100644
--- a/frontend/src/component/strategies/StrategiesList/AddStrategyButton/AddStrategyButton.tsx
+++ b/frontend/src/component/strategies/StrategiesList/AddStrategyButton/AddStrategyButton.tsx
@@ -20,7 +20,7 @@ export const AddStrategyButton = () => {
onClick={() => navigate('/strategies/create')}
permission={CREATE_STRATEGY}
size="large"
- tooltipProps={{ title: 'New strategy type' }}
+ tooltipProps={{ title: 'New custom strategy' }}
>
@@ -32,7 +32,7 @@ export const AddStrategyButton = () => {
permission={CREATE_STRATEGY}
data-testid={ADD_NEW_STRATEGY_ID}
>
- New strategy type
+ New custom strategy
}
/>
diff --git a/frontend/src/component/strategies/StrategiesList/StrategiesList.tsx b/frontend/src/component/strategies/StrategiesList/StrategiesList.tsx
index 7a726349e7..c7736a440f 100644
--- a/frontend/src/component/strategies/StrategiesList/StrategiesList.tsx
+++ b/frontend/src/component/strategies/StrategiesList/StrategiesList.tsx
@@ -1,6 +1,6 @@
-import { useState, useMemo, useCallback } from 'react';
+import { useState, useMemo, useCallback, FC } from 'react';
import { useNavigate } from 'react-router-dom';
-import { Box, styled } from '@mui/material';
+import { Box, Link, Typography, styled } from '@mui/material';
import { Extension } from '@mui/icons-material';
import {
Table,
@@ -31,6 +31,8 @@ import { StrategyEditButton } from './StrategyEditButton/StrategyEditButton';
import { StrategyDeleteButton } from './StrategyDeleteButton/StrategyDeleteButton';
import { Search } from 'component/common/Search/Search';
import { Badge } from 'component/common/Badge/Badge';
+import { HelpIcon } from 'component/common/HelpIcon/HelpIcon';
+import { CustomStrategyInfo } from '../CustomStrategyInfo/CustomStrategyInfo';
interface IDialogueMetaData {
show: boolean;
@@ -43,6 +45,62 @@ const StyledBadge = styled(Badge)(({ theme }) => ({
display: 'inline-block',
}));
+const Subtitle: FC<{
+ title: string;
+ description: string;
+ link: string;
+}> = ({ title, description, link }) => (
+
+ {title}
+
+ ({ marginBottom: theme.spacing(1) })}
+ >
+ {description}
+
+
+ Read more in the documentation
+
+ >
+ }
+ />
+
+);
+
+const PredefinedStrategyTitle = () => (
+ ({ marginBottom: theme.spacing(1.5) })}>
+
+
+);
+
+const CustomStrategyTitle: FC = () => (
+ ({
+ display: 'flex',
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ marginBottom: theme.spacing(1.5),
+ })}
+ >
+
+
+
+);
+
export const StrategiesList = () => {
const navigate = useNavigate();
const [dialogueMetaData, setDialogueMetaData] = useState(
@@ -60,13 +118,18 @@ export const StrategiesList = () => {
const data = useMemo(() => {
if (loading) {
- return Array(5).fill({
+ const mock = Array(5).fill({
name: 'Context name',
description: 'Context description when loading',
});
+ return {
+ all: mock,
+ predefined: mock,
+ custom: mock,
+ };
}
- return strategies.map(
+ const all = strategies.map(
({ name, description, editable, deprecated }) => ({
name,
description,
@@ -74,6 +137,11 @@ export const StrategiesList = () => {
deprecated,
})
);
+ return {
+ all,
+ predefined: all.filter(strategy => !strategy.editable),
+ custom: all.filter(strategy => strategy.editable),
+ };
}, [strategies, loading]);
const onToggle = useCallback(
@@ -181,24 +249,21 @@ export const StrategiesList = () => {
width: '90%',
Cell: ({
row: {
- original: { name, description, deprecated, editable },
+ original: { name, description, deprecated },
},
}: any) => {
- const subTitleText = deprecated
- ? `${description} (deprecated)`
- : description;
return (
(
-
- Predefined
+
+ Disabled
)}
/>
@@ -217,18 +282,28 @@ export const StrategiesList = () => {
deprecated={original.deprecated}
onToggle={onToggle(original)}
/>
-
- onEditStrategy(original)}
- />
- onDeleteStrategy(original)}
+
+
+ onEditStrategy(original)}
+ />
+
+ onDeleteStrategy(original)
+ }
+ />
+ >
+ }
/>
),
width: 150,
+ minWidth: 120,
disableGlobalFilter: true,
disableSortBy: true,
},
@@ -264,7 +339,28 @@ export const StrategiesList = () => {
} = useTable(
{
columns: columns as any[], // TODO: fix after `react-table` v8 update
- data,
+ data: data.predefined,
+ initialState,
+ sortTypes,
+ autoResetGlobalFilter: false,
+ autoResetSortBy: false,
+ disableSortRemove: true,
+ },
+ useGlobalFilter,
+ useSortBy
+ );
+
+ const {
+ getTableProps: customGetTableProps,
+ getTableBodyProps: customGetTableBodyProps,
+ headerGroups: customHeaderGroups,
+ rows: customRows,
+ prepareRow: customPrepareRow,
+ setGlobalFilter: customSetGlobalFilter,
+ } = useTable(
+ {
+ columns: columns as any[], // TODO: fix after `react-table` v8 update
+ data: data.custom,
initialState,
sortTypes,
autoResetGlobalFilter: false,
@@ -292,58 +388,99 @@ export const StrategiesList = () => {
-
-
-
- >
+ {
+ setGlobalFilter(...props);
+ customSetGlobalFilter(...props);
+ }}
+ />
}
/>
}
>
-
-
-
- {rows.map(row => {
- prepareRow(row);
- return (
-
- {row.cells.map(cell => (
-
- {cell.render('Cell')}
-
- ))}
-
- );
- })}
-
-
-
- ({ paddingBottom: theme.spacing(4) })}>
+
+
+
+
+ {rows.map(row => {
+ prepareRow(row);
+ return (
+
+ {row.cells.map(cell => (
+
+ {cell.render('Cell')}
+
+ ))}
+
+ );
+ })}
+
+
0}
+ condition={rows.length === 0}
show={
-
- No strategies found matching “
- {globalFilter}
- ”
-
- }
- elseShow={
-
- No strategies available. Get started by adding
- one.
-
+ 0}
+ show={
+
+ No predefined strategies found matching
+ “
+ {globalFilter}
+ ”
+
+ }
+ elseShow={
+
+ No strategies available.
+
+ }
+ />
}
/>
- }
- />
+
+
+
+
+
+
+ {customRows.map(row => {
+ customPrepareRow(row);
+ return (
+
+ {row.cells.map(cell => (
+
+ {cell.render('Cell')}
+
+ ))}
+
+ );
+ })}
+
+
+ 0}
+ show={
+
+ No custom strategies found matching
+ “
+ {globalFilter}
+ ”
+
+ }
+ elseShow={}
+ />
+ }
+ />
+
+