diff --git a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyForm/NewFeatureStrategyForm.tsx b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyForm/NewFeatureStrategyForm.tsx index ac7b877f0b..3d934431b6 100644 --- a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyForm/NewFeatureStrategyForm.tsx +++ b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyForm/NewFeatureStrategyForm.tsx @@ -1,15 +1,6 @@ import React, { useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import { - Alert, - Button, - styled, - Tabs, - Tab, - Typography, - Divider, - Box, -} from '@mui/material'; +import { Alert, Button, styled, Tabs, Tab, Box, Divider } from '@mui/material'; import { IFeatureStrategy, IFeatureStrategyParameters, @@ -42,6 +33,7 @@ import { FeatureStrategyTitle } from './FeatureStrategyTitle/FeatureStrategyTitl import { FeatureStrategyEnabledDisabled } from './FeatureStrategyEnabledDisabled/FeatureStrategyEnabledDisabled'; import { StrategyVariants } from 'component/feature/StrategyTypes/StrategyVariants'; import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; +import { formatStrategyName } from 'utils/strategyNames'; interface IFeatureStrategyFormProps { feature: IFeatureToggle; @@ -77,8 +69,15 @@ const StyledDividerContent = styled(Box)(({ theme }) => ({ })); const StyledForm = styled('form')(({ theme }) => ({ - display: 'grid', + position: 'relative', + display: 'flex', + flexDirection: 'column', gap: theme.spacing(2), + padding: theme.spacing(6), + paddingBottom: theme.spacing(12), + paddingTop: theme.spacing(4), + overflow: 'auto', + height: '100%', })); const StyledHr = styled('hr')(({ theme }) => ({ @@ -89,11 +88,31 @@ const StyledHr = styled('hr')(({ theme }) => ({ background: theme.palette.background.elevation2, })); -const StyledButtons = styled('div')(({ theme }) => ({ +const StyledTitle = styled('h1')(({ theme }) => ({ + fontWeight: 'normal', display: 'flex', + alignItems: 'center', +})); + +const StyledButtons = styled('div')(({ theme }) => ({ + bottom: 0, + right: 0, + left: 0, + position: 'absolute', + display: 'flex', + padding: theme.spacing(3), + paddingRight: theme.spacing(6), + paddingLeft: theme.spacing(6), + backgroundColor: theme.palette.common.white, justifyContent: 'end', - gap: theme.spacing(2), - paddingBottom: theme.spacing(10), + borderTop: `1px solid ${theme.palette.divider}`, +})); + +const StyledTabs = styled(Tabs)(({ theme }) => ({ + borderTop: `1px solid ${theme.palette.divider}`, + borderBottom: `1px solid ${theme.palette.divider}`, + paddingLeft: theme.spacing(6), + paddingRight: theme.spacing(6), })); const StyledBox = styled(Box)(({ theme }) => ({ @@ -111,6 +130,15 @@ const StyledTargetingHeader = styled('div')(({ theme }) => ({ marginTop: theme.spacing(1.5), })); +const StyledHeaderBox = styled(Box)(({ theme }) => ({ + display: 'flex', + alignItems: 'center', + paddingLeft: theme.spacing(6), + paddingRight: theme.spacing(6), + paddingTop: theme.spacing(2), + paddingBottom: theme.spacing(2), +})); + export const NewFeatureStrategyForm = ({ projectId, feature, @@ -225,173 +253,186 @@ export const NewFeatureStrategyForm = ({ }; return ( - - + <> + + + {formatStrategyName(strategy.name || '')} + + + - - - + + + { + setStrategy((prev) => ({ + ...prev, + title, + })); + }} + /> + + setStrategy((strategyState) => ({ + ...strategyState, + disabled: !strategyState.disabled, + })) + } + /> + + + + } + /> + } + /> + + + + This feature toggle is currently + enabled in the{' '} + {environmentId}{' '} + environment. Any changes made here + will be available to users as soon + as these changes are approved and + applied. + } + elseShow={ + + This feature toggle is currently + enabled in the{' '} + {environmentId}{' '} + environment. Any changes made here + will be available to users as soon + as you hit save. + + } + /> + + + } + /> + + + + Segmentation and constraints allow you to set + filters on your strategies, so that they will + only be evaluated for users and applications + that match the specified preconditions. + + + + + + AND + + + + } + /> + + } /> - - - This feature toggle is currently enabled - in the {environmentId}{' '} - environment. Any changes made here will - be available to users as soon as these - changes are approved and applied. - - } - elseShow={ - - This feature toggle is currently enabled - in the {environmentId}{' '} - environment. Any changes made here will - be available to users as soon as you hit{' '} - save. - - } - /> - - - { - setStrategy((prev) => ({ - ...prev, - title, - })); - }} - /> - - setStrategy((strategyState) => ({ - ...strategyState, - disabled: !strategyState.disabled, - })) - } - /> - - - } - /> - - - - Segmentation and constraints allow you to set - filters on your strategies, so that they will only - be evaluated for users and applications that match - the specified preconditions. - - - - - - AND - - - - } - /> - - - } - /> - } - /> - - - - {isChangeRequest - ? changeRequestButtonText - : 'Save strategy'} - - - setShowProdGuard(false)} - onClick={onSubmit} - loading={loading} - label='Save strategy' /> - - + + + + {isChangeRequest + ? changeRequestButtonText + : 'Save strategy'} + + + setShowProdGuard(false)} + onClick={onSubmit} + loading={loading} + label='Save strategy' + /> + + + ); }; diff --git a/frontend/src/component/feature/FeatureStrategy/NewFeatureStrategyCreate/NewFeatureStrategyCreate.tsx b/frontend/src/component/feature/FeatureStrategy/NewFeatureStrategyCreate/NewFeatureStrategyCreate.tsx index 6724fc1ee1..89db37944d 100644 --- a/frontend/src/component/feature/FeatureStrategy/NewFeatureStrategyCreate/NewFeatureStrategyCreate.tsx +++ b/frontend/src/component/feature/FeatureStrategy/NewFeatureStrategyCreate/NewFeatureStrategyCreate.tsx @@ -180,10 +180,10 @@ export const NewFeatureStrategyCreate = () => { return ( formatAddStrategyApiCode( projectId, diff --git a/frontend/src/component/feature/FeatureStrategy/NewFeatureStrategyEdit/NewFeatureStrategyEdit.tsx b/frontend/src/component/feature/FeatureStrategy/NewFeatureStrategyEdit/NewFeatureStrategyEdit.tsx index 218d416247..627ec11ee1 100644 --- a/frontend/src/component/feature/FeatureStrategy/NewFeatureStrategyEdit/NewFeatureStrategyEdit.tsx +++ b/frontend/src/component/feature/FeatureStrategy/NewFeatureStrategyEdit/NewFeatureStrategyEdit.tsx @@ -200,7 +200,7 @@ export const NewFeatureStrategyEdit = () => { return ( ({ + display: 'flex', + alignItems: 'center', + marginTop: theme.spacing(1), + marginBottom: theme.spacing(1), +})); + +const StyledVariantsHeader = styled('div')(({ theme }) => ({ + color: theme.palette.text.secondary, + marginTop: theme.spacing(1.5), +})); + export const StrategyVariants: FC<{ setStrategy: React.Dispatch< React.SetStateAction> @@ -29,6 +43,8 @@ export const StrategyVariants: FC<{ const { trackEvent } = usePlausibleTracker(); const [variantsEdit, setVariantsEdit] = useState([]); const theme = useTheme(); + const newStrategyConfiguration = useUiFlag('newStrategyConfiguration'); + const stickiness = strategy?.parameters && 'stickiness' in strategy?.parameters ? String(strategy.parameters.stickiness) @@ -91,6 +107,86 @@ export const StrategyVariants: FC<{ }); }; + if (newStrategyConfiguration) { + return ( + <> + + Variants enhance a feature flag by providing a version of + the feature to be enabled + + + Variants + + + Variants in feature toggling allow you to + serve different versions of a feature to + different users. This can be used for A/B + testing, gradual rollouts, and canary + releases. Variants provide a way to control + the user experience at a granular level, + enabling you to test and optimize different + aspects of your features. Read more about + variants{' '} + + here + + + + } + /> + + + + {variantsEdit.map((variant, i) => ( + + updateVariant(updatedVariant, variant.id) + } + removeVariant={() => + setVariantsEdit((variantsEdit) => + updateWeightEdit( + variantsEdit.filter( + (v) => v.id !== variant.id, + ), + 1000, + ), + ) + } + decorationColor={ + theme.palette.variants[ + i % theme.palette.variants.length + ] + } + /> + ))} + + } + > + Add variant + + + + ); + } + return ( <>