Skip to content

Commit

Permalink
Feat/disabled strategies (#5930)
Browse files Browse the repository at this point in the history
This PR makes disabled strategies more prominent in the UI:

<img width="1031" alt="Skjermbilde 2024-01-17 kl 11 26 11"
src="https://github.com/Unleash/unleash/assets/16081982/4a07c0aa-8f86-4854-829e-1088abecfb4e">
  • Loading branch information
FredrikOseberg authored Jan 17, 2024
1 parent ee08bd8 commit 1deee10
Show file tree
Hide file tree
Showing 10 changed files with 75 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const ConstraintIcon: VFC<IConstraintIconProps> = ({
disabled,
}) => (
<Box
className='constraint-icon-container'
sx={(theme) => ({
backgroundColor: disabled
? theme.palette.neutral.border
Expand All @@ -24,6 +25,7 @@ export const ConstraintIcon: VFC<IConstraintIconProps> = ({
})}
>
<TrackChanges
className='constraint-icon'
sx={(theme) => ({
fill: theme.palette.common.white,
display: 'block',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ const StyledContainer = styled('div')(({ theme }) => ({
lineHeight: 1.25,
}));

const StyledName = styled('div', {
const StyledName = styled('p', {
shouldForwardProp: (prop) => prop !== 'disabled',
})<{ disabled: boolean }>(({ theme, disabled }) => ({
fontSize: theme.fontSizes.smallBody,
lineHeight: 17 / 14,
color: disabled ? theme.palette.text.secondary : theme.palette.text.primary,
}));

const StyledText = styled('div', {
const StyledText = styled('p', {
shouldForwardProp: (prop) => prop !== 'disabled',
})<{ disabled: boolean }>(({ theme, disabled }) => ({
fontSize: theme.fontSizes.smallerBody,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ const StyledContainer = styled('div')(({ theme }) => ({
lineHeight: 1.25,
}));

const StyledName = styled('div', {
const StyledName = styled('p', {
shouldForwardProp: (prop) => prop !== 'disabled',
})<{ disabled: boolean }>(({ theme, disabled }) => ({
fontSize: theme.fontSizes.smallBody,
lineHeight: 17 / 14,
color: disabled ? theme.palette.text.secondary : theme.palette.text.primary,
}));

const StyledText = styled('div', {
const StyledText = styled('p', {
shouldForwardProp: (prop) => prop !== 'disabled',
})<{ disabled: boolean }>(({ theme, disabled }) => ({
fontSize: theme.fontSizes.smallerBody,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import { CSSProperties } from 'react';
interface IPercentageCircleProps {
percentage: number;
size?: `${number}rem`;
disabled?: boolean | null;
}

const PercentageCircle = ({
percentage,
size = '4rem',
disabled = false,
}: IPercentageCircleProps) => {
const theme = useTheme();

Expand All @@ -27,6 +29,10 @@ const PercentageCircle = ({
const r = 100 / (2 * Math.PI);
const d = 2 * r;

const color = disabled
? theme.palette.neutral.border
: theme.palette.primary.light;

return (
<svg viewBox={`0 0 ${d} ${d}`} style={style} aria-hidden>
<title>A circle progress bar with {percentage}% completion.</title>
Expand All @@ -35,7 +41,7 @@ const PercentageCircle = ({
cx={r}
cy={r}
fill='none'
stroke={theme.palette.primary.light}
stroke={color}
strokeWidth={d}
strokeDasharray={`${percentage} 100`}
/>
Expand Down
14 changes: 9 additions & 5 deletions frontend/src/component/common/SegmentItem/SegmentItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,26 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit
interface ISegmentItemProps {
segment: Partial<ISegment>;
isExpanded?: boolean;
disabled?: boolean;
disabled?: boolean | null;
constraintList?: JSX.Element;
headerContent?: JSX.Element;
}

const StyledAccordion = styled(Accordion)(({ theme }) => ({
const StyledAccordion = styled(Accordion, {
shouldForwardProp: (prop) => prop !== 'isDisabled',
})<{ isDisabled: boolean | null }>(({ theme, isDisabled }) => ({
border: `1px solid ${theme.palette.divider}`,
borderRadius: theme.shape.borderRadiusMedium,
backgroundColor: theme.palette.background.paper,
boxShadow: 'none',
margin: 0,
transition: 'all 0.1s ease',
'&:before': {
opacity: '0 !important',
},
'&.Mui-expanded': { backgroundColor: theme.palette.neutral.light },
backgroundColor: isDisabled
? theme.palette.envAccordion.disabled
: theme.palette.background.paper,
}));

const StyledAccordionSummary = styled(AccordionSummary)(({ theme }) => ({
Expand All @@ -52,7 +56,7 @@ const StyledLink = styled(Link)(({ theme }) => ({
}));
const StyledText = styled('span', {
shouldForwardProp: (prop) => prop !== 'disabled',
})<{ disabled: boolean }>(({ theme, disabled }) => ({
})<{ disabled: boolean | null }>(({ theme, disabled }) => ({
color: disabled ? theme.palette.text.secondary : 'inherit',
}));

Expand All @@ -66,7 +70,7 @@ export const SegmentItem: VFC<ISegmentItemProps> = ({
const [isOpen, setIsOpen] = useState(isExpanded || false);

return (
<StyledAccordion expanded={isOpen}>
<StyledAccordion isDisabled={disabled}>
<StyledAccordionSummary id={`segment-accordion-${segment.id}`}>
<DonutLarge
sx={(theme) => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { StrategySeparator } from 'component/common/StrategySeparator/StrategySe
import { ConstraintItem } from './ConstraintItem/ConstraintItem';
import { useStrategies } from 'hooks/api/getters/useStrategies/useStrategies';
import { useSegments } from 'hooks/api/getters/useSegments/useSegments';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { FeatureOverviewSegment } from 'component/feature/FeatureView/FeatureOverview/FeatureOverviewSegment/FeatureOverviewSegment';
import { ConstraintAccordionList } from 'component/common/ConstraintAccordion/ConstraintAccordionList/ConstraintAccordionList';
import {
Expand All @@ -23,6 +22,25 @@ interface IStrategyExecutionProps {
strategy: IFeatureStrategyPayload | CreateFeatureStrategySchema;
}

const StyledContainer = styled(Box, {
shouldForwardProp: (prop) => prop !== 'disabled',
})<{ disabled?: boolean | null }>(({ theme, disabled }) => ({
'& p, & span, & h1, & h2, & h3, & h4, & h5, & h6': {
color: disabled ? theme.palette.neutral.main : 'inherit',
},
'.constraint-icon-container': {
backgroundColor: disabled
? theme.palette.neutral.border
: theme.palette.primary.light,
borderRadius: '50%',
},
'.constraint-icon': {
fill: disabled
? theme.palette.neutral.light
: theme.palette.common.white,
},
}));

const NoItems: VFC = () => (
<Box sx={{ px: 3, color: 'text.disabled' }}>
This strategy does not have constraints or parameters.
Expand All @@ -44,7 +62,6 @@ export const StrategyExecution: VFC<IStrategyExecutionProps> = ({
}) => {
const { parameters, constraints = [] } = strategy;
const { strategies } = useStrategies();
const { uiConfig } = useUiConfig();
const { segments } = useSegments();
const strategySegments = segments?.filter((segment) => {
return strategy.segments?.includes(segment.id);
Expand All @@ -63,6 +80,8 @@ export const StrategyExecution: VFC<IStrategyExecutionProps> = ({
case 'Rollout': {
const percentage = parseParameterNumber(parameters[key]);

const badgeType = strategy.disabled ? 'neutral' : 'success';

return (
<StyledValueContainer
sx={{ display: 'flex', alignItems: 'center' }}
Expand All @@ -71,15 +90,18 @@ export const StrategyExecution: VFC<IStrategyExecutionProps> = ({
<PercentageCircle
percentage={percentage}
size='2rem'
disabled={strategy.disabled}
/>
</Box>
<div>
<Badge color='success'>{percentage}%</Badge> of
your base{' '}
{constraints.length > 0
? 'who match constraints'
: ''}{' '}
is included.
<Badge color={badgeType}>{percentage}%</Badge>{' '}
<span>of your base</span>{' '}
<span>
{constraints.length > 0
? 'who match constraints'
: ''}{' '}
is included.
</span>
</div>
</StyledValueContainer>
);
Expand Down Expand Up @@ -109,7 +131,7 @@ export const StrategyExecution: VFC<IStrategyExecutionProps> = ({
return null;
}
});
}, [parameters, definition, constraints]);
}, [parameters, definition, constraints, strategy.disabled]);

const customStrategyList = useMemo(() => {
if (!parameters || !definition?.editable) return null;
Expand Down Expand Up @@ -252,7 +274,10 @@ export const StrategyExecution: VFC<IStrategyExecutionProps> = ({

const listItems = [
strategySegments && strategySegments.length > 0 && (
<FeatureOverviewSegment segments={strategySegments} />
<FeatureOverviewSegment
segments={strategySegments}
disabled={strategy.disabled}
/>
),
constraints.length > 0 && (
<ConstraintAccordionList
Expand All @@ -276,7 +301,7 @@ export const StrategyExecution: VFC<IStrategyExecutionProps> = ({
<ConditionallyRender
condition={listItems.length > 0}
show={
<>
<StyledContainer disabled={Boolean(strategy.disabled)}>
{listItems.map((item, index) => (
// biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
<Fragment key={index}>
Expand All @@ -287,7 +312,7 @@ export const StrategyExecution: VFC<IStrategyExecutionProps> = ({
{item}
</Fragment>
))}
</>
</StyledContainer>
}
elseShow={<NoItems />}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { CopyStrategyIconMenu } from './CopyStrategyIconMenu/CopyStrategyIconMen
import { StrategyItemContainer } from 'component/common/StrategyItemContainer/StrategyItemContainer';
import MenuStrategyRemove from './MenuStrategyRemove/MenuStrategyRemove';
import SplitPreviewSlider from 'component/feature/StrategyTypes/SplitPreviewSlider/SplitPreviewSlider';

import { Box } from '@mui/material';
interface IStrategyItemProps {
environmentId: string;
strategy: IFeatureStrategy;
Expand Down Expand Up @@ -87,9 +87,16 @@ export const StrategyItem: FC<IStrategyItemProps> = ({
}
>
<StrategyExecution strategy={strategy} />
{strategy.variants ? (
<SplitPreviewSlider variants={strategy.variants} />
) : null}

{strategy.variants &&
strategy.variants.length > 0 &&
(strategy.disabled ? (
<Box sx={{ opacity: '0.5' }}>
<SplitPreviewSlider variants={strategy.variants} />
</Box>
) : (
<SplitPreviewSlider variants={strategy.variants} />
))}
</StrategyItemContainer>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import { ISegment } from 'interfaces/segment';

interface IFeatureOverviewSegmentProps {
segments?: ISegment[];
disabled?: boolean | null;
}

export const FeatureOverviewSegment = ({
segments,
disabled = false,
}: IFeatureOverviewSegmentProps) => {
if (!segments || segments.length === 0) {
return null;
Expand All @@ -23,7 +25,7 @@ export const FeatureOverviewSegment = ({
condition={index > 0}
show={<StrategySeparator text='AND' />}
/>
<SegmentItem segment={segment} />
<SegmentItem segment={segment} disabled={disabled} />
</Fragment>
))}
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ exports[`renders an empty list correctly 1`] = `
className="css-non55o"
>
<div
className="css-16ldy6v"
className="css-1om4ep4"
>
<svg
aria-hidden={true}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/themes/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export const theme = {
main: colors.grey[700],
light: colors.grey[100],
dark: colors.grey[800],
border: colors.grey[400],
border: colors.grey[500],
contrastText: colors.grey[800], // Color used for text inside badge
},

Expand Down

0 comments on commit 1deee10

Please sign in to comment.