mirror of
https://github.com/Unleash/unleash.git
synced 2024-12-22 19:07:54 +01:00
feat: strategy variants on strategy overview (#4776)
Refactors the breakdown of feature variants per strategy on the environment overview level:
This commit is contained in:
parent
5799d0c90f
commit
6884f9cdc9
@ -18,7 +18,6 @@ export const TooltipResolver = ({
|
||||
if (!title && !titleComponent) {
|
||||
return children;
|
||||
}
|
||||
|
||||
if (variant === 'custom') {
|
||||
return (
|
||||
<HtmlTooltip {...rest} title={title || titleComponent} arrow>
|
||||
|
@ -12,6 +12,7 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit
|
||||
import { CopyStrategyIconMenu } from './CopyStrategyIconMenu/CopyStrategyIconMenu';
|
||||
import { StrategyItemContainer } from 'component/common/StrategyItemContainer/StrategyItemContainer';
|
||||
import MenuStrategyRemove from './MenuStrategyRemove/MenuStrategyRemove';
|
||||
import SplitPreviewSlider from 'component/feature/StrategyTypes/SplitPreviewSlider/SplitPreviewSlider';
|
||||
|
||||
interface IStrategyItemProps {
|
||||
environmentId: string;
|
||||
@ -86,6 +87,9 @@ export const StrategyItem: FC<IStrategyItemProps> = ({
|
||||
}
|
||||
>
|
||||
<StrategyExecution strategy={strategy} />
|
||||
{strategy.variants ? (
|
||||
<SplitPreviewSlider variants={strategy.variants} />
|
||||
) : null}
|
||||
</StrategyItemContainer>
|
||||
);
|
||||
};
|
||||
|
@ -1,10 +1,9 @@
|
||||
import { Box, Typography, styled } from '@mui/material';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { TooltipResolver } from 'component/common/TooltipResolver/TooltipResolver';
|
||||
import { IFeatureVariant } from 'interfaces/featureToggle';
|
||||
|
||||
type SplitPreviewSliderProps = {
|
||||
values: number[];
|
||||
};
|
||||
|
||||
const StyledContainer = styled(Box)(({ theme }) => ({
|
||||
const StyledContainer = styled(Box)(() => ({
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
position: 'relative',
|
||||
@ -18,55 +17,188 @@ const StyledTrack = styled(Box)(({ theme }) => ({
|
||||
overflow: 'hidden',
|
||||
}));
|
||||
|
||||
const StyledSegment = styled(Box)(({ theme }) => ({
|
||||
const StyledSegment = styled(Box)(() => ({
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
width: '100%',
|
||||
}));
|
||||
|
||||
const StyledSegmentTrack = styled(Box)(({ theme }) => ({
|
||||
height: theme.spacing(3),
|
||||
const StyledSegmentTrack = styled(Box, {
|
||||
shouldForwardProp: prop => prop !== 'index',
|
||||
})<{ index: number }>(({ theme, index }) => ({
|
||||
height: theme.spacing(1.8),
|
||||
width: '100%',
|
||||
position: 'relative',
|
||||
background: theme.palette.variants[index % theme.palette.variants.length],
|
||||
}));
|
||||
|
||||
const SplitPreviewSlider = ({ values }: SplitPreviewSliderProps) => {
|
||||
if (values.length < 2) {
|
||||
const StyledHeaderContainer = styled(Box)(({ theme }) => ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
marginBottom: theme.spacing(1),
|
||||
}));
|
||||
|
||||
const StyledTypography = styled(Typography)(({ theme }) => ({
|
||||
marginY: theme.spacing(1),
|
||||
}));
|
||||
|
||||
const StyledVariantBoxContainer = styled(Box)(() => ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
marginLeft: 'auto',
|
||||
}));
|
||||
|
||||
const StyledVariantBox = styled(Box, {
|
||||
shouldForwardProp: prop => prop !== 'index',
|
||||
})<{ index: number }>(({ theme, index }) => ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
marginRight: theme.spacing(2),
|
||||
'& div': {
|
||||
width: theme.spacing(1.6),
|
||||
height: theme.spacing(1.6),
|
||||
borderRadius: '50%',
|
||||
marginRight: theme.spacing(1),
|
||||
background:
|
||||
theme.palette.variants[index % theme.palette.variants.length],
|
||||
},
|
||||
}));
|
||||
|
||||
const StyledTypographySubtitle = styled(Typography)(({ theme }) => ({
|
||||
marginTop: theme.spacing(1),
|
||||
}));
|
||||
|
||||
interface ISplitPreviewSliderProps {
|
||||
variants: IFeatureVariant[];
|
||||
}
|
||||
|
||||
const SplitPreviewSlider = ({ variants }: ISplitPreviewSliderProps) => {
|
||||
if (variants.length < 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Box sx={theme => ({ marginTop: theme.spacing(2) })}>
|
||||
<Typography
|
||||
variant="body2"
|
||||
sx={theme => ({ marginY: theme.spacing(1) })}
|
||||
>
|
||||
Split preview
|
||||
</Typography>
|
||||
<SplitPreviewHeader variants={variants} />
|
||||
<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) })}
|
||||
|
||||
{variants.map((variant, index) => {
|
||||
const value = variant.weight / 10;
|
||||
return (
|
||||
<TooltipResolver
|
||||
variant="custom"
|
||||
key={index}
|
||||
arrow
|
||||
onClick={e => e.preventDefault()}
|
||||
titleComponent={
|
||||
<SplitPreviewTooltip
|
||||
variant={variant}
|
||||
index={index}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{value}%
|
||||
</Typography>
|
||||
</StyledSegment>
|
||||
))}
|
||||
<Box
|
||||
style={{
|
||||
width: `${value}%`,
|
||||
}}
|
||||
>
|
||||
{' '}
|
||||
<StyledSegment>
|
||||
<StyledSegmentTrack index={index} />
|
||||
<StyledTypographySubtitle variant="subtitle2">
|
||||
{value}%
|
||||
</StyledTypographySubtitle>
|
||||
</StyledSegment>
|
||||
</Box>
|
||||
</TooltipResolver>
|
||||
);
|
||||
})}
|
||||
</StyledContainer>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
const SplitPreviewHeader = ({ variants }: ISplitPreviewSliderProps) => {
|
||||
return (
|
||||
<StyledHeaderContainer>
|
||||
<StyledTypography variant="body2">
|
||||
Feature variants ({variants.length})
|
||||
</StyledTypography>
|
||||
<StyledVariantBoxContainer>
|
||||
{variants.map((variant, index) => (
|
||||
<StyledVariantBox key={index} index={index}>
|
||||
<Box />
|
||||
<StyledTypography variant="body2">
|
||||
{variant.name}
|
||||
</StyledTypography>
|
||||
</StyledVariantBox>
|
||||
))}
|
||||
</StyledVariantBoxContainer>
|
||||
</StyledHeaderContainer>
|
||||
);
|
||||
};
|
||||
|
||||
interface ISplitPreviewTooltip {
|
||||
variant: IFeatureVariant;
|
||||
index: number;
|
||||
}
|
||||
|
||||
const StyledTooltipContainer = styled(Box)(() => ({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}));
|
||||
|
||||
const StyledVariantContainer = styled(Box)(() => ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
minWidth: '250px',
|
||||
}));
|
||||
|
||||
const StyledPayloadContainer = styled(Box)(({ theme }) => ({
|
||||
marginTop: theme.spacing(1),
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}));
|
||||
|
||||
const StyledPayloadLabel = styled(Typography)(({ theme }) => ({
|
||||
marginBottom: theme.spacing(1),
|
||||
}));
|
||||
|
||||
const SplitPreviewTooltip = ({ variant, index }: ISplitPreviewTooltip) => {
|
||||
return (
|
||||
<StyledTooltipContainer>
|
||||
<StyledVariantContainer>
|
||||
<StyledVariantBox index={index}>
|
||||
<Box />
|
||||
</StyledVariantBox>
|
||||
|
||||
<Typography variant="subtitle2">
|
||||
{variant.weight / 10}% - {variant.name}
|
||||
</Typography>
|
||||
</StyledVariantContainer>
|
||||
|
||||
{variant.payload ? (
|
||||
<StyledPayloadContainer>
|
||||
<StyledPayloadLabel variant="body2">
|
||||
Payload
|
||||
</StyledPayloadLabel>
|
||||
|
||||
<ConditionallyRender
|
||||
condition={variant.payload.type === 'json'}
|
||||
show={<code>{variant.payload.value}</code>}
|
||||
elseShow={
|
||||
<Typography variant="body2">
|
||||
{variant.payload.value}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
</StyledPayloadContainer>
|
||||
) : null}
|
||||
</StyledTooltipContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default SplitPreviewSlider;
|
||||
|
@ -157,9 +157,7 @@ export const StrategyVariants: FC<{
|
||||
>
|
||||
Add variant
|
||||
</PermissionButton>
|
||||
<SplitPreviewSlider
|
||||
values={variantsEdit.map(variant => variant.weight / 10)}
|
||||
/>
|
||||
<SplitPreviewSlider variants={variantsEdit} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user