mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-23 00:22:19 +01:00
Feat: strategy variant slider (#4344)
## About the changes 
This commit is contained in:
parent
2b565aeef7
commit
909831db6f
@ -4,6 +4,7 @@ import { HelpIcon } from 'component/common/HelpIcon/HelpIcon';
|
||||
import SelectMenu from 'component/common/select';
|
||||
import { OverrideConfig } from 'component/feature/FeatureView/FeatureVariants/FeatureEnvironmentVariants/EnvironmentVariantsModal/VariantForm/VariantOverrides/VariantOverrides';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
FormControlLabel,
|
||||
IconButton,
|
||||
@ -28,8 +29,20 @@ const StyledVariantForm = styled('div')(({ theme }) => ({
|
||||
padding: theme.spacing(3),
|
||||
marginBottom: theme.spacing(3),
|
||||
borderRadius: theme.shape.borderRadiusLarge,
|
||||
overflow: 'hidden',
|
||||
}));
|
||||
|
||||
const StyledDecoration = styled('div')<{ color?: string }>(
|
||||
({ theme, color }) => ({
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
top: 0,
|
||||
height: '100%',
|
||||
background: color || 'transparent',
|
||||
width: theme.spacing(1),
|
||||
})
|
||||
);
|
||||
|
||||
const StyledDeleteButtonTooltip = styled(Tooltip)(({ theme }) => ({
|
||||
position: 'absolute',
|
||||
top: theme.spacing(2),
|
||||
@ -151,6 +164,7 @@ interface IVariantFormProps {
|
||||
removeVariant: (variantId: string) => void;
|
||||
error?: string;
|
||||
disableOverrides?: boolean;
|
||||
decorationColor?: string;
|
||||
}
|
||||
|
||||
export const VariantForm = ({
|
||||
@ -160,6 +174,7 @@ export const VariantForm = ({
|
||||
removeVariant,
|
||||
error,
|
||||
disableOverrides = false,
|
||||
decorationColor,
|
||||
}: IVariantFormProps) => {
|
||||
const [name, setName] = useState(variant.name);
|
||||
const [customPercentage, setCustomPercentage] = useState(
|
||||
@ -306,6 +321,7 @@ export const VariantForm = ({
|
||||
|
||||
return (
|
||||
<StyledVariantForm data-testid="VARIANT">
|
||||
<StyledDecoration color={decorationColor} />
|
||||
<StyledDeleteButtonTooltip
|
||||
arrow
|
||||
title={
|
||||
|
@ -0,0 +1,72 @@
|
||||
import { Box, Typography, styled } from '@mui/material';
|
||||
|
||||
type SplitPreviewSliderProps = {
|
||||
values: number[];
|
||||
};
|
||||
|
||||
const StyledContainer = styled(Box)(({ theme }) => ({
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
position: 'relative',
|
||||
}));
|
||||
|
||||
const StyledTrack = styled(Box)(({ theme }) => ({
|
||||
position: 'absolute',
|
||||
height: theme.spacing(3),
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
overflow: 'hidden',
|
||||
}));
|
||||
|
||||
const StyledSegment = styled(Box)(({ theme }) => ({
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
}));
|
||||
|
||||
const StyledSegmentTrack = styled(Box)(({ theme }) => ({
|
||||
height: theme.spacing(3),
|
||||
width: '100%',
|
||||
position: 'relative',
|
||||
}));
|
||||
|
||||
const SplitPreviewSlider = ({ values }: SplitPreviewSliderProps) => {
|
||||
if (values.length < 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Box sx={theme => ({ marginTop: theme.spacing(2) })}>
|
||||
<Typography
|
||||
variant="body2"
|
||||
sx={theme => ({ marginY: theme.spacing(1) })}
|
||||
>
|
||||
Split preview
|
||||
</Typography>
|
||||
<StyledContainer>
|
||||
<StyledTrack />
|
||||
{values.map((value, index) => (
|
||||
<StyledSegment key={index} sx={{ width: `${value}%` }}>
|
||||
<StyledSegmentTrack
|
||||
sx={theme => ({
|
||||
background:
|
||||
theme.palette.variants[
|
||||
index % theme.palette.variants.length
|
||||
],
|
||||
})}
|
||||
/>
|
||||
<Typography
|
||||
variant="subtitle2"
|
||||
sx={theme => ({ marginTop: theme.spacing(1) })}
|
||||
>
|
||||
{value}%
|
||||
</Typography>
|
||||
</StyledSegment>
|
||||
))}
|
||||
</StyledContainer>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default SplitPreviewSlider;
|
@ -7,9 +7,10 @@ import { UPDATE_FEATURE_ENVIRONMENT_VARIANTS } from '../../providers/AccessProvi
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { WeightType } from '../../../constants/variantTypes';
|
||||
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
||||
import { styled, Typography } from '@mui/material';
|
||||
import { styled, Typography, useTheme } from '@mui/material';
|
||||
import { useRequiredQueryParam } from 'hooks/useRequiredQueryParam';
|
||||
import { IFeatureStrategy } from 'interfaces/strategy';
|
||||
import SplitPreviewSlider from './SplitPreviewSlider/SplitPreviewSlider';
|
||||
|
||||
const StyledVariantForms = styled('div')({
|
||||
display: 'flex',
|
||||
@ -25,6 +26,7 @@ export const StrategyVariants: FC<{
|
||||
const projectId = useRequiredPathParam('projectId');
|
||||
const environment = useRequiredQueryParam('environmentId');
|
||||
const [variantsEdit, setVariantsEdit] = useState<IFeatureVariantEdit[]>([]);
|
||||
const theme = useTheme();
|
||||
const stickiness =
|
||||
strategy?.parameters && 'stickiness' in strategy?.parameters
|
||||
? String(strategy.parameters.stickiness)
|
||||
@ -88,7 +90,7 @@ export const StrategyVariants: FC<{
|
||||
Variants
|
||||
</Typography>
|
||||
<StyledVariantForms>
|
||||
{variantsEdit.map(variant => (
|
||||
{variantsEdit.map((variant, i) => (
|
||||
<VariantForm
|
||||
disableOverrides={true}
|
||||
key={variant.id}
|
||||
@ -107,6 +109,11 @@ export const StrategyVariants: FC<{
|
||||
)
|
||||
)
|
||||
}
|
||||
decorationColor={
|
||||
theme.palette.variants[
|
||||
i % theme.palette.variants.length
|
||||
]
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</StyledVariantForms>
|
||||
@ -119,6 +126,9 @@ export const StrategyVariants: FC<{
|
||||
>
|
||||
Add variant
|
||||
</PermissionButton>
|
||||
<SplitPreviewSlider
|
||||
values={variantsEdit.map(variant => variant.weight / 10)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -94,4 +94,17 @@ export const colors = {
|
||||
600: '#1f3751',
|
||||
500: '#0e2840',
|
||||
},
|
||||
variants: [
|
||||
'#BEBBF3',
|
||||
'#FFC46F',
|
||||
'#B0D182',
|
||||
'#96D2FA',
|
||||
'#F7E3AE',
|
||||
'#7FBAA9',
|
||||
'#D3B9DB',
|
||||
'#FBC5A0',
|
||||
'#DDE7B5',
|
||||
'#9EC4E3',
|
||||
'#F8B6CC',
|
||||
] as string[],
|
||||
} as const;
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { createTheme } from '@mui/material/styles';
|
||||
import { alpha } from '@mui/material';
|
||||
import { focusable } from 'themes/themeStyles';
|
||||
import { colors } from './colors';
|
||||
|
||||
const actionColors = {
|
||||
0.54: 'rgba(223, 222, 255, 0.54)',
|
||||
@ -271,6 +272,7 @@ const theme = {
|
||||
// A400: '#A6000E',
|
||||
// A700: '#A6000E',
|
||||
},
|
||||
variants: colors.variants,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -257,6 +257,7 @@ const theme = {
|
||||
// A400: '#A6000E',
|
||||
// A700: '#A6000E',
|
||||
},
|
||||
variants: colors.variants,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -112,6 +112,11 @@ declare module '@mui/material/styles' {
|
||||
disabled: string;
|
||||
expanded: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Variants, percentage split in strategies
|
||||
**/
|
||||
variants: string[];
|
||||
}
|
||||
|
||||
interface Theme extends CustomTheme {}
|
||||
|
Loading…
Reference in New Issue
Block a user