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:
parent
b6f405d1af
commit
73b4ae18c1
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
@ -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={
|
||||
|
@ -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"
|
||||
/>
|
||||
|
Loading…
Reference in New Issue
Block a user