1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-09 00:18:00 +01:00

feat: responsive strategy icons (#4121)

https://linear.app/unleash/issue/2-1167/multiple-strategies-breaking-the-environment-card

https://linear.app/unleash/issue/2-1179/buttons-have-an-extra-space-if-the-icon-its-not-visible

This fixes the broken UI when we have too many strategies.

Before:
<img width="1500" alt="image"
src="https://github.com/Unleash/unleash/assets/14320932/ddf2f636-965c-4527-b879-dba5c16d9630">

After:
<img width="1303" alt="image"
src="https://github.com/Unleash/unleash/assets/14320932/852c20c9-c5f4-4aa5-b8c0-e5bc5286c572">

We also added the new strategy type to the tooltips:
<img width="519" alt="image"
src="https://github.com/Unleash/unleash/assets/14320932/117ee00f-f2a7-4ecb-8596-44486a2870a2">

<img width="422" alt="image"
src="https://github.com/Unleash/unleash/assets/14320932/4281a48c-4b6e-4100-86e2-29dfe9ce4cec">

This also fixes an extra margin we caught on our `PermissionButton` when
it had no endIcon set.

Co-authored by: @daveleek

---------

Co-authored-by: David Leek <david@getunleash.io>
This commit is contained in:
Nuno Góis 2023-06-29 18:01:27 +01:00 committed by GitHub
parent b6f405d1af
commit 73b4ae18c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 102 additions and 44 deletions

View File

@ -1,7 +1,6 @@
import { Button, ButtonProps } from '@mui/material';
import { Lock } from '@mui/icons-material';
import React from 'react';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import {
TooltipResolver,
ITooltipResolverProps,
@ -32,6 +31,22 @@ export interface IProjectPermissionButtonProps extends IPermissionButtonProps {
environmentId: string;
}
const getEndIcon = (
access: boolean,
fallBackIcon?: React.ReactNode,
hideLockIcon?: boolean
): React.ReactNode => {
if (!access && !hideLockIcon) {
return <Lock titleAccess="Locked" />;
}
if (fallBackIcon) {
return fallBackIcon;
}
return null;
};
const ProjectEnvironmentPermissionButton: React.FC<IProjectPermissionButtonProps> =
React.forwardRef((props, ref) => {
const access = useHasProjectEnvironmentAccess(
@ -75,6 +90,7 @@ const BasePermissionButton: React.FC<IPermissionBaseButtonProps> =
ref
) => {
const id = useId();
const endIcon = getEndIcon(access, rest.endIcon, hideLockIcon);
return (
<TooltipResolver
@ -91,18 +107,7 @@ const BasePermissionButton: React.FC<IPermissionBaseButtonProps> =
variant={variant}
color={color}
{...rest}
endIcon={
<>
<ConditionallyRender
condition={!access && !hideLockIcon}
show={<Lock titleAccess="Locked" />}
elseShow={
Boolean(rest.endIcon) &&
rest.endIcon
}
/>
</>
}
endIcon={endIcon}
>
{children}
</Button>

View File

@ -3,18 +3,25 @@ import {
formatStrategyName,
} from 'utils/strategyNames';
import { styled, Tooltip } from '@mui/material';
import { IFeatureStrategy } from 'interfaces/strategy';
interface IFeatureStrategyIconProps {
strategyName: string;
strategy: IFeatureStrategy;
}
export const FeatureStrategyIcon = ({
strategyName,
strategy,
}: IFeatureStrategyIconProps) => {
const Icon = getFeatureStrategyIcon(strategyName);
const Icon = getFeatureStrategyIcon(strategy.name);
return (
<Tooltip title={formatStrategyName(strategyName)} arrow>
<Tooltip
title={
formatStrategyName(strategy.name) +
(strategy.title ? ` - ${strategy.title}` : '')
}
arrow
>
<StyledIcon>
<Icon />
</StyledIcon>

View File

@ -1,28 +1,8 @@
import { IFeatureStrategy } from 'interfaces/strategy';
import { FeatureStrategyIcon } from 'component/feature/FeatureStrategy/FeatureStrategyIcon/FeatureStrategyIcon';
import { styled } from '@mui/material';
interface IFeatureStrategyIconsProps {
strategies: IFeatureStrategy[] | undefined;
}
export const FeatureStrategyIcons = ({
strategies,
}: IFeatureStrategyIconsProps) => {
if (!strategies?.length) {
return null;
}
return (
<StyledList aria-label="Feature strategies">
{strategies.map(strategy => (
<StyledListItem key={strategy.id}>
<FeatureStrategyIcon strategyName={strategy.name} />
</StyledListItem>
))}
</StyledList>
);
};
import { TooltipLink } from 'component/common/TooltipLink/TooltipLink';
import { formatStrategyName } from 'utils/strategyNames';
const StyledList = styled('ul')(() => ({
all: 'unset',
@ -36,3 +16,61 @@ const StyledListItem = styled('li')(() => ({
minWidth: 30,
textAlign: 'center',
}));
const StyledItem = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
gap: theme.spacing(1),
}));
const THRESHOLD = 5;
interface IFeatureStrategyIconsProps {
strategies: IFeatureStrategy[] | undefined;
}
export const FeatureStrategyIcons = ({
strategies,
}: IFeatureStrategyIconsProps) => {
if (!strategies?.length) {
return null;
}
if (strategies.length > THRESHOLD + 1) {
return (
<StyledList aria-label="Feature strategies">
{strategies.slice(0, THRESHOLD).map(strategy => (
<StyledListItem key={strategy.id}>
<FeatureStrategyIcon strategy={strategy} />
</StyledListItem>
))}
<TooltipLink
tooltip={strategies.slice(THRESHOLD).map(strategy => (
<StyledListItem key={strategy.id}>
<StyledItem>
<FeatureStrategyIcon strategy={strategy} />{' '}
{formatStrategyName(strategy.name) +
(strategy.title
? ` - ${strategy.title}`
: '')}
</StyledItem>
</StyledListItem>
))}
>
(+{strategies.length - THRESHOLD})
</TooltipLink>
</StyledList>
);
}
return (
<StyledList aria-label="Feature strategies">
{strategies.map(strategy => (
<StyledListItem key={strategy.id}>
<FeatureStrategyIcon strategy={strategy} />
</StyledListItem>
))}
</StyledList>
);
};

View File

@ -20,6 +20,10 @@ interface IFeatureStrategyMenuProps {
size?: IPermissionButtonProps['size'];
}
const StyledStrategyMenu = styled('div')({
flexShrink: 0,
});
const StyledAdditionalMenuButton = styled(PermissionButton)(({ theme }) => ({
minWidth: 0,
width: theme.spacing(4.5),
@ -71,7 +75,7 @@ export const FeatureStrategyMenu = ({
);
return (
<div onClick={event => event.stopPropagation()}>
<StyledStrategyMenu onClick={event => event.stopPropagation()}>
<PermissionButton
permission={CREATE_FEATURE_STRATEGY}
projectId={projectId}
@ -118,6 +122,6 @@ export const FeatureStrategyMenu = ({
environmentId={environmentId}
/>
</Popover>
</div>
</StyledStrategyMenu>
);
};

View File

@ -123,6 +123,8 @@ const StyledButtonContainer = styled('div')(({ theme }) => ({
display: 'flex',
alignItems: 'center',
marginTop: theme.spacing(2),
gap: theme.spacing(2),
flexWrap: 'wrap',
[theme.breakpoints.down(560)]: {
flexDirection: 'column',
},
@ -199,6 +201,11 @@ const FeatureOverviewEnvironment = ({
variant="outlined"
size="small"
/>
<FeatureStrategyIcons
strategies={
featureEnvironment?.strategies
}
/>
</StyledButtonContainer>
}
elseShow={

View File

@ -97,9 +97,6 @@ exports[`renders an empty list correctly 1`] = `
type="button"
>
New tag type
<span
className="MuiButton-endIcon MuiButton-iconSizeMedium css-9tj150-MuiButton-endIcon"
/>
<span
className="MuiTouchRipple-root css-8je8zh-MuiTouchRipple-root"
/>