1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-08-18 13:48:58 +02:00

Feat: update variants placement (#9832)

This commit is contained in:
Tymoteusz Czech 2025-04-24 16:01:35 +02:00 committed by GitHub
parent 81c1fb9143
commit 0e2f7374e5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
36 changed files with 367 additions and 340 deletions

View File

@ -5,6 +5,7 @@ import { disabledStrategyClassName } from 'component/common/StrategyItemContaine
export type StrategyEvaluationItemProps = {
type?: ReactNode;
children?: ReactNode;
alignType?: 'center' | 'top';
};
const StyledContainer = styled('div')(({ theme }) => ({
@ -22,6 +23,8 @@ const StyledContent = styled('div')(({ theme }) => ({
display: 'flex',
gap: theme.spacing(1),
alignItems: 'center',
flexGrow: 1,
position: 'relative',
[`.${disabledStrategyClassName} &`]: {
filter: 'grayscale(1)',
color: theme.palette.text.secondary,
@ -31,7 +34,9 @@ const StyledContent = styled('div')(({ theme }) => ({
},
}));
const StyledType = styled('span')(({ theme }) => ({
const StyledType = styled('span')<{
align?: 'top' | 'center';
}>(({ theme, align }) => ({
display: 'block',
flexShrink: 0,
fontSize: theme.fontSizes.smallerBody,
@ -41,6 +46,9 @@ const StyledType = styled('span')(({ theme }) => ({
[theme.breakpoints.down('sm')]: {
width: '100%',
},
...(align === 'top' && {
alignSelf: 'flex-start',
}),
}));
/**
@ -49,10 +57,11 @@ const StyledType = styled('span')(({ theme }) => ({
export const StrategyEvaluationItem: FC<StrategyEvaluationItemProps> = ({
type,
children,
alignType,
}) => {
return (
<StyledContainer>
<StyledType>{type}</StyledType>
<StyledType align={alignType}>{type}</StyledType>
<StyledContent>{children}</StyledContent>
</StyledContainer>
);

View File

@ -0,0 +1,97 @@
import { Box, styled, Typography } from '@mui/material';
import type { StrategyVariantSchema } from 'openapi';
const StyledTooltipContainer = styled(Box)(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
}));
const StyledVariantContainer = styled(Box)(({ theme }) => ({
display: 'flex',
alignItems: 'center',
minWidth: '250px',
gap: theme.spacing(1),
}));
const StyledPayloadContainer = styled(Box)(({ theme }) => ({
padding: theme.spacing(1, 0, 0.75, 0),
flexDirection: 'column',
}));
const StyledPayloadLabel = styled('span')(({ theme }) => ({
marginBottom: theme.spacing(1),
fontSize: theme.typography.body2.fontSize,
}));
const StyledVariantBox = styled(Box, {
shouldForwardProp: (prop) => prop !== 'index',
})<{ index: number }>(({ theme, index }) => ({
display: 'flex',
alignItems: 'center',
figure: {
margin: 0,
padding: 0,
width: theme.spacing(1.6),
height: theme.spacing(1.6),
borderRadius: '50%',
background:
theme.palette.variants[index % theme.palette.variants.length],
},
}));
const StyledVariantType = styled('span')(({ theme }) => ({
display: 'inline-block',
background: theme.palette.background.elevation2,
borderRadius: theme.shape.borderRadiusLarge,
padding: theme.spacing(0.25, 1),
align: 'center',
fontSize: theme.fontSizes.smallBody,
}));
const StyledVariantPayload = styled('code')(({ theme }) => ({
display: 'inline-block',
background: theme.palette.background.elevation2,
borderRadius: theme.shape.borderRadiusLarge,
padding: theme.spacing(0.25, 1),
fontSize: theme.fontSizes.smallerBody,
}));
type SplitPreviewTooltipProps = {
variant: StrategyVariantSchema;
index: number;
selected?: boolean;
};
export const SplitPreviewTooltip = ({
variant: { name, weight, payload },
index,
selected,
}: SplitPreviewTooltipProps) => (
<StyledTooltipContainer>
<StyledVariantContainer>
<StyledVariantBox index={index}>
<figure />
</StyledVariantBox>
<Typography variant='subtitle2'>
{weight / 10}% - {name}
</Typography>
</StyledVariantContainer>
{payload ? (
<StyledPayloadContainer
sx={{
display: ['json', 'csv'].includes(payload.type)
? 'flex'
: 'block',
}}
>
<StyledPayloadLabel>
<StyledVariantType>{payload.type}</StyledVariantType>
{' payload: '}
</StyledPayloadLabel>
<StyledVariantPayload>{payload.value}</StyledVariantPayload>
</StyledPayloadContainer>
) : null}
</StyledTooltipContainer>
);

View File

@ -0,0 +1,145 @@
import { Box, Typography, styled } from '@mui/material';
import { TooltipResolver } from 'component/common/TooltipResolver/TooltipResolver';
import { Truncator } from 'component/common/Truncator/Truncator';
import type { StrategyVariantSchema } from 'openapi';
import { SplitPreviewTooltip } from './SplitPreviewTooltip/SplitPreviewTooltip';
const StyledContainer = styled(Box)(() => ({
display: 'flex',
width: '100%',
position: 'relative',
}));
const StyledVariantItem = styled(Box)<{ selected?: boolean }>(
({ theme, selected }) => ({
position: 'relative',
fontSize: theme.fontSizes.smallerBody,
...(selected
? {
fontWeight: theme.typography.fontWeightBold,
}
: {}),
}),
);
const StyledVariantItemTrack = styled(Box)<{
index: number;
hasError?: boolean;
isFirst?: boolean;
isLast?: boolean;
}>(({ theme, index, hasError, isFirst, isLast }) => ({
height: theme.spacing(2),
width: '100%',
position: 'relative',
color: hasError ? theme.palette.error.main : 'inherit',
background: theme.palette.variants[index % theme.palette.variants.length],
...(isFirst
? {
borderTopLeftRadius: theme.shape.borderRadius,
borderBottomLeftRadius: theme.shape.borderRadius,
}
: {}),
...(isLast
? {
borderTopRightRadius: theme.shape.borderRadius,
borderBottomRightRadius: theme.shape.borderRadius,
}
: {}),
}));
const StyledTrackPercentage = styled(Box)(({ theme }) => ({
padding: theme.spacing(0.25, 0.25),
lineHeight: 1,
}));
const StyledVariantItemInfo = styled(Box)(({ theme }) => ({
padding: theme.spacing(0.125, 0.25, 0),
overflow: 'hidden',
color: theme.palette.text.secondary,
}));
const StyledHeaderContainer = styled(Box)(({ theme }) => ({
display: 'flex',
alignItems: 'center',
marginBottom: theme.spacing(1),
}));
const StyledTypography = styled(Typography)(({ theme }) => ({
marginY: theme.spacing(1),
}));
type VariantsSplitPreviewProps = {
variants: StrategyVariantSchema[];
weightsError?: boolean;
header?: boolean;
selected?: string;
};
export const VariantsSplitPreview = ({
variants,
weightsError,
header = true,
selected,
}: VariantsSplitPreviewProps) => {
if (variants.length < 1) {
return null;
}
return (
<Box sx={(theme) => ({ marginTop: theme.spacing(header ? 2 : 0) })}>
{header ? (
<StyledHeaderContainer>
<StyledTypography variant='body2'>
Flag variants ({variants.length})
</StyledTypography>
</StyledHeaderContainer>
) : null}
<StyledContainer>
{variants.map((variant, index) => {
const value = variant.weight / 10;
if (value === 0) {
return null;
}
return (
<TooltipResolver
variant='custom'
key={index}
arrow
onClick={(e) => e.preventDefault()}
titleComponent={
<SplitPreviewTooltip
variant={variant}
index={index}
selected={selected === variant.name}
/>
}
>
<StyledVariantItem
sx={{ width: `${value}%` }}
selected={selected === variant.name}
>
<StyledVariantItemTrack
index={index}
isFirst={index === 0}
isLast={index === variants.length - 1}
hasError={weightsError}
>
<StyledTrackPercentage>
<Truncator lines={1}>
{`${value}%`}
</Truncator>
</StyledTrackPercentage>
</StyledVariantItemTrack>
<StyledVariantItemInfo>
<Truncator lines={1}>
{variant.name}
</Truncator>
</StyledVariantItemInfo>
</StyledVariantItem>
</TooltipResolver>
);
})}
</StyledContainer>
</Box>
);
};

View File

@ -13,7 +13,7 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit
import { CopyStrategyIconMenu } from './CopyStrategyIconMenu/CopyStrategyIconMenu';
import { StrategyItemContainer } from 'component/common/StrategyItemContainer/LegacyStrategyItemContainer';
import MenuStrategyRemove from './MenuStrategyRemove/MenuStrategyRemove';
import SplitPreviewSlider from 'component/feature/StrategyTypes/SplitPreviewSlider/SplitPreviewSlider';
import { VariantsSplitPreview } from 'component/common/VariantsSplitPreview/VariantsSplitPreview';
import { Box } from '@mui/material';
interface IStrategyItemProps {
environmentId: string;
@ -93,10 +93,10 @@ export const StrategyItem: FC<IStrategyItemProps> = ({
strategy.variants.length > 0 &&
(strategy.disabled ? (
<Box sx={{ opacity: '0.5' }}>
<SplitPreviewSlider variants={strategy.variants} />
<VariantsSplitPreview variants={strategy.variants} />
</Box>
) : (
<SplitPreviewSlider variants={strategy.variants} />
<VariantsSplitPreview variants={strategy.variants} />
))}
</StrategyItemContainer>
);

View File

@ -1,17 +1,15 @@
import type { FC } from 'react';
import { StrategyEvaluationChip } from 'component/common/ConstraintsList/StrategyEvaluationChip/StrategyEvaluationChip';
import { StrategyEvaluationItem } from 'component/common/ConstraintsList/StrategyEvaluationItem/StrategyEvaluationItem';
import type { ParametersSchema, StrategyVariantSchema } from 'openapi';
import type { FC } from 'react';
import type { ParametersSchema } from 'openapi';
import { parseParameterNumber } from 'utils/parseParameter';
import { RolloutVariants } from './RolloutVariants/RolloutVariants';
export const RolloutParameter: FC<{
value: string;
parameters?: ParametersSchema;
hasConstraints?: boolean;
variants?: StrategyVariantSchema[];
displayGroupId?: boolean;
}> = ({ value, parameters, hasConstraints, variants, displayGroupId }) => {
}> = ({ value, parameters, hasConstraints, displayGroupId }) => {
const percentage = parseParameterNumber(value);
const explainStickiness =
@ -43,7 +41,6 @@ export const RolloutParameter: FC<{
) : null}
</p>
</StrategyEvaluationItem>
<RolloutVariants variants={variants} />
</>
);
};

View File

@ -1,71 +0,0 @@
import { styled } from '@mui/material';
import { StrategyEvaluationChip } from 'component/common/ConstraintsList/StrategyEvaluationChip/StrategyEvaluationChip';
import { StrategyEvaluationItem } from 'component/common/ConstraintsList/StrategyEvaluationItem/StrategyEvaluationItem';
import { HtmlTooltip } from 'component/common/HtmlTooltip/HtmlTooltip';
import type { StrategyVariantSchema } from 'openapi';
import type { FC } from 'react';
const StyledVariantChip = styled(StrategyEvaluationChip)<{ order: number }>(
({ theme, order }) => ({
borderRadius: theme.shape.borderRadiusExtraLarge,
border: 'none',
color: theme.palette.text.primary,
background:
theme.palette.variants[order % theme.palette.variants.length],
fontWeight: theme.typography.fontWeightRegular,
}),
);
const StyledPayloadHeader = styled('div')(({ theme }) => ({
fontSize: theme.typography.body2.fontSize,
marginBottom: theme.spacing(1),
}));
const StyledValuesContainer = styled('div')(({ theme }) => ({
display: 'flex',
gap: theme.spacing(0.75, 0.5),
flexWrap: 'wrap',
}));
export const RolloutVariants: FC<{
variants?: StrategyVariantSchema[];
}> = ({ variants }) => {
if (!variants?.length) {
return null;
}
return (
<StrategyEvaluationItem type={`Variants (${variants.length})`}>
<StyledValuesContainer>
{variants.map((variant, i) => (
<HtmlTooltip
arrow
title={
variant.payload?.value ? (
<div>
<StyledPayloadHeader>
Payload:
</StyledPayloadHeader>
<code>{variant.payload?.value}</code>
</div>
) : null
}
key={variant.name}
>
<StyledVariantChip
key={variant.name}
order={i}
label={
<>
<span>
{variant.weight / 10}% {variant.name}
</span>
</>
}
/>
</HtmlTooltip>
))}
</StyledValuesContainer>
</StrategyEvaluationItem>
);
};

View File

@ -0,0 +1,40 @@
import { styled } from '@mui/material';
import { StrategyEvaluationItem } from 'component/common/ConstraintsList/StrategyEvaluationItem/StrategyEvaluationItem';
import { VariantsSplitPreview } from 'component/common/VariantsSplitPreview/VariantsSplitPreview';
import type { StrategyVariantSchema } from 'openapi';
import type { FC } from 'react';
const StyledContainer = styled('div')(({ theme }) => ({
padding: theme.spacing(3.5, 2, 0.5),
}));
const StyledTrack = styled('div')(() => ({
width: '100%',
position: 'relative',
}));
export const RolloutVariants: FC<{
variants?: StrategyVariantSchema[];
selected?: StrategyVariantSchema['name'];
}> = ({ variants, selected }) => {
if (!variants?.length) {
return null;
}
return (
<StyledContainer>
<StrategyEvaluationItem
type={`Variants (${variants.length})`}
alignType='top'
>
<StyledTrack>
<VariantsSplitPreview
variants={variants}
header={false}
selected={selected}
/>
</StyledTrack>
</StrategyEvaluationItem>
</StyledContainer>
);
};

View File

@ -14,6 +14,7 @@ import {
ConstraintListItem,
ConstraintsList,
} from 'component/common/ConstraintsList/ConstraintsList';
import { RolloutVariants } from './RolloutVariants/RolloutVariants';
type StrategyExecutionProps = {
strategy: IFeatureStrategyPayload | FeatureStrategySchema;
@ -48,21 +49,25 @@ export const StrategyExecution: FC<StrategyExecutionProps> = ({
}
return (
<ConstraintsList>
{strategySegments?.map((segment) => (
<SegmentItem segment={segment} key={segment.id} />
))}
{constraints?.map((constraint, index) => (
<ConstraintAccordionView
key={`${objectId(constraint)}-${index}`}
constraint={constraint}
/>
))}
{(isCustomStrategy ? customStrategyItems : strategyParameters).map(
(item, index) => (
<>
<ConstraintsList>
{strategySegments?.map((segment) => (
<SegmentItem segment={segment} key={segment.id} />
))}
{constraints?.map((constraint, index) => (
<ConstraintAccordionView
key={`${objectId(constraint)}-${index}`}
constraint={constraint}
/>
))}
{(isCustomStrategy
? customStrategyItems
: strategyParameters
).map((item, index) => (
<ConstraintListItem key={index}>{item}</ConstraintListItem>
),
)}
</ConstraintsList>
))}
</ConstraintsList>
<RolloutVariants variants={strategy.variants} />
</>
);
};

View File

@ -30,7 +30,6 @@ export const useStrategyParameters = (
parameters={parameters}
hasConstraints={hasConstraints}
displayGroupId={displayGroupId}
variants={variants}
/>
);
}

View File

@ -1,7 +1,7 @@
// deprecated; remove with `flagOverviewRedesign` flag
import { Box, styled } from '@mui/material';
import { StrategyExecution } from '../../FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/StrategyExecution';
import SplitPreviewSlider from 'component/feature/StrategyTypes/SplitPreviewSlider/SplitPreviewSlider';
import { VariantsSplitPreview } from 'component/common/VariantsSplitPreview/VariantsSplitPreview';
import {
formatStrategyName,
getFeatureStrategyIcon,
@ -46,10 +46,10 @@ export const ReleasePlanMilestoneStrategy = ({
strategy.variants.length > 0 &&
(strategy.disabled ? (
<Box sx={{ opacity: '0.5' }}>
<SplitPreviewSlider variants={strategy.variants} />
<VariantsSplitPreview variants={strategy.variants} />
</Box>
) : (
<SplitPreviewSlider variants={strategy.variants} />
<VariantsSplitPreview variants={strategy.variants} />
))}
</StyledStrategy>
);

View File

@ -1,17 +1,17 @@
import { VariantForm } from '../FeatureView/FeatureVariants/FeatureEnvironmentVariants/EnvironmentVariantsModal/VariantForm/VariantForm';
import { updateWeightEdit } from '../../common/util';
import { updateWeightEdit } from 'component/common/util';
import type React from 'react';
import { type FC, useEffect, useState } from 'react';
import type { IFeatureVariantEdit } from '../FeatureView/FeatureVariants/FeatureEnvironmentVariants/EnvironmentVariantsModal/EnvironmentVariantsModal';
import PermissionButton from '../../common/PermissionButton/PermissionButton';
import PermissionButton from 'component/common/PermissionButton/PermissionButton';
import { UPDATE_FEATURE_ENVIRONMENT_VARIANTS } from '../../providers/AccessProvider/permissions';
import { v4 as uuidv4 } from 'uuid';
import { WeightType } from '../../../constants/variantTypes';
import { Box, styled, Typography, useTheme } from '@mui/material';
import type { IFeatureStrategy } from 'interfaces/strategy';
import SplitPreviewSlider from './SplitPreviewSlider/SplitPreviewSlider';
import { HelpIcon } from '../../common/HelpIcon/HelpIcon';
import { StrategyVariantsUpgradeAlert } from '../../common/StrategyVariantsUpgradeAlert/StrategyVariantsUpgradeAlert';
import { VariantsSplitPreview } from 'component/common/VariantsSplitPreview/VariantsSplitPreview';
import { HelpIcon } from 'component/common/HelpIcon/HelpIcon';
import { StrategyVariantsUpgradeAlert } from 'component/common/StrategyVariantsUpgradeAlert/StrategyVariantsUpgradeAlert';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
import Add from '@mui/icons-material/Add';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
@ -199,7 +199,7 @@ export const NewStrategyVariants: FC<{
>
Add variant
</PermissionButton>
<SplitPreviewSlider
<VariantsSplitPreview
variants={variantsEdit}
weightsError={variantWeightsError}
/>

View File

@ -1,214 +0,0 @@
import { Box, Typography, styled } from '@mui/material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { TooltipResolver } from 'component/common/TooltipResolver/TooltipResolver';
import type { IFeatureVariant } from 'interfaces/featureToggle';
const StyledContainer = styled(Box)(() => ({
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)(() => ({
height: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
width: '100%',
}));
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 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',
flexWrap: 'wrap',
}));
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[];
weightsError?: boolean;
}
const SplitPreviewSlider = ({
variants,
weightsError,
}: ISplitPreviewSliderProps) => {
if (variants.length < 1) {
return null;
}
return (
<Box sx={(theme) => ({ marginTop: theme.spacing(2) })}>
<SplitPreviewHeader variants={variants} />
<StyledContainer>
<StyledTrack />
{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}
/>
}
>
<Box
style={{
width: `${value}%`,
}}
>
{' '}
<StyledSegment>
<StyledSegmentTrack index={index} />
<StyledTypographySubtitle
variant='subtitle2'
color={
weightsError ? 'error' : 'inherit'
}
>
{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;

View File

@ -1,17 +1,17 @@
import { VariantForm } from '../FeatureView/FeatureVariants/FeatureEnvironmentVariants/EnvironmentVariantsModal/VariantForm/VariantForm';
import { updateWeightEdit } from '../../common/util';
import { updateWeightEdit } from 'component/common/util';
import type React from 'react';
import { type FC, useEffect, useState } from 'react';
import type { IFeatureVariantEdit } from '../FeatureView/FeatureVariants/FeatureEnvironmentVariants/EnvironmentVariantsModal/EnvironmentVariantsModal';
import PermissionButton from '../../common/PermissionButton/PermissionButton';
import PermissionButton from 'component/common/PermissionButton/PermissionButton';
import { UPDATE_FEATURE_ENVIRONMENT_VARIANTS } from '../../providers/AccessProvider/permissions';
import { v4 as uuidv4 } from 'uuid';
import { WeightType } from '../../../constants/variantTypes';
import { Link, styled, Typography, useTheme } from '@mui/material';
import type { IFeatureStrategy } from 'interfaces/strategy';
import SplitPreviewSlider from './SplitPreviewSlider/SplitPreviewSlider';
import { HelpIcon } from '../../common/HelpIcon/HelpIcon';
import { StrategyVariantsUpgradeAlert } from '../../common/StrategyVariantsUpgradeAlert/StrategyVariantsUpgradeAlert';
import { VariantsSplitPreview } from 'component/common/VariantsSplitPreview/VariantsSplitPreview';
import { HelpIcon } from 'component/common/HelpIcon/HelpIcon';
import { StrategyVariantsUpgradeAlert } from 'component/common/StrategyVariantsUpgradeAlert/StrategyVariantsUpgradeAlert';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
const StyledVariantForms = styled('div')({
@ -168,7 +168,7 @@ export const StrategyVariants: FC<{
>
Add variant
</PermissionButton>
<SplitPreviewSlider variants={variantsEdit} />
<VariantsSplitPreview variants={variantsEdit} />
</>
);
};

View File

@ -5,7 +5,7 @@ import type {
} from 'openapi';
import { objectId } from 'utils/objectId';
import { StrategyItemContainer } from 'component/common/StrategyItemContainer/StrategyItemContainer';
import { StrategyExecution } from './StrategyExecution/StrategyExecution';
import { PlaygroundStrategyExecution } from './PlaygroundStrategyExecution/PlaygroundStrategyExecution';
interface IFeatureStrategyItemProps {
strategy: PlaygroundStrategySchema;
@ -42,7 +42,10 @@ export const FeatureStrategyItem = ({
)
}
>
<StrategyExecution strategyResult={strategy} input={input} />
<PlaygroundStrategyExecution
strategyResult={strategy}
input={input}
/>
</StrategyItemContainer>
);
};

View File

@ -4,10 +4,10 @@ import type {
PlaygroundStrategySchema,
PlaygroundRequestSchema,
} from 'openapi';
import { StrategyExecution } from './StrategyExecution/LegacyStrategyExecution';
import { StrategyExecution } from './PlaygroundStrategyExecution/LegacyStrategyExecution';
import { objectId } from 'utils/objectId';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { DisabledStrategyExecution } from './StrategyExecution/DisabledStrategyExecution';
import { DisabledStrategyExecution } from './PlaygroundStrategyExecution/DisabledStrategyExecution';
import { StrategyItemContainer } from 'component/common/StrategyItemContainer/LegacyStrategyItemContainer';
interface IFeatureStrategyItemProps {

View File

@ -1,6 +1,8 @@
import type {
PlaygroundFeatureSchemaVariant,
PlaygroundRequestSchema,
PlaygroundStrategySchema,
StrategyVariantSchema,
} from 'openapi';
import { ConstraintExecution } from './ConstraintExecution/ConstraintExecution';
import { formattedStrategyNames } from 'utils/strategyNames';
@ -16,6 +18,7 @@ import { SegmentExecution } from './SegmentExecution/SegmentExecution';
import { useStrategyParameters } from 'component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/hooks/useStrategyParameters';
import { useStrategies } from 'hooks/api/getters/useStrategies/useStrategies';
import { useCustomStrategyParameters } from 'component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/hooks/useCustomStrategyParameters';
import { RolloutVariants } from 'component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/RolloutVariants/RolloutVariants';
type StrategyExecutionProps = {
strategyResult: PlaygroundStrategySchema;
@ -23,7 +26,7 @@ type StrategyExecutionProps = {
input?: PlaygroundRequestSchema;
};
export const StrategyExecution: FC<StrategyExecutionProps> = ({
export const PlaygroundStrategyExecution: FC<StrategyExecutionProps> = ({
strategyResult,
input,
}) => {
@ -79,5 +82,17 @@ export const StrategyExecution: FC<StrategyExecutionProps> = ({
),
].filter(Boolean);
return <ConstraintsList>{items}</ConstraintsList>;
const { variant, variants } = strategyResult.result as unknown as Partial<{
variant: PlaygroundFeatureSchemaVariant;
variants: StrategyVariantSchema[];
}>;
return (
<>
<ConstraintsList>{items}</ConstraintsList>
{variants?.length ? (
<RolloutVariants variants={variants} selected={variant?.name} />
) : null}
</>
);
};

View File

@ -10,7 +10,7 @@ import {
PROJECT_DEFAULT_STRATEGY_WRITE,
UPDATE_PROJECT,
} from '@server/types/permissions';
import SplitPreviewSlider from 'component/feature/StrategyTypes/SplitPreviewSlider/SplitPreviewSlider';
import { VariantsSplitPreview } from 'component/common/VariantsSplitPreview/VariantsSplitPreview';
import { StrategyItemContainer } from 'component/common/StrategyItemContainer/LegacyStrategyItemContainer';
interface ProjectEnvironmentDefaultStrategyProps {
@ -84,7 +84,7 @@ const ProjectEnvironmentDefaultStrategy = ({
<StrategyExecution strategy={strategy} />
{strategy.variants && strategy.variants.length > 0 ? (
<SplitPreviewSlider variants={strategy.variants} />
<VariantsSplitPreview variants={strategy.variants} />
) : null}
</StrategyItemContainer>
</>

View File

@ -1,5 +1,5 @@
import { Box, IconButton, styled } from '@mui/material';
import SplitPreviewSlider from 'component/feature/StrategyTypes/SplitPreviewSlider/SplitPreviewSlider';
import { VariantsSplitPreview } from 'component/common/VariantsSplitPreview/VariantsSplitPreview';
import {
formatStrategyName,
getFeatureStrategyIcon,
@ -88,10 +88,12 @@ export const MilestoneStrategyItem = ({
strategy.variants.length > 0 &&
(strategy.disabled ? (
<Box sx={{ opacity: '0.5' }}>
<SplitPreviewSlider variants={strategy.variants} />
<VariantsSplitPreview
variants={strategy.variants}
/>
</Box>
) : (
<SplitPreviewSlider variants={strategy.variants} />
<VariantsSplitPreview variants={strategy.variants} />
))}
</StyledStrategyExecution>
</StyledStrategy>

View File

@ -10,7 +10,7 @@ import { updateWeightEdit } from 'component/common/util';
import { WeightType } from 'constants/variantTypes';
import { useTheme } from '@mui/material';
import Add from '@mui/icons-material/Add';
import SplitPreviewSlider from 'component/feature/StrategyTypes/SplitPreviewSlider/SplitPreviewSlider';
import { VariantsSplitPreview } from 'component/common/VariantsSplitPreview/VariantsSplitPreview';
const StyledVariantForms = styled('div')({
display: 'flex',
@ -180,7 +180,7 @@ export const MilestoneStrategyVariants = ({
<Button onClick={addVariant} variant='outlined' startIcon={<Add />}>
Add variant
</Button>
<SplitPreviewSlider
<VariantsSplitPreview
variants={variantsEdit}
weightsError={variantWeightsError}
/>