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

Constraint values preview and filtering (#9603)

Restore constraint accordion to flag page.
This commit is contained in:
Tymoteusz Czech 2025-03-25 11:24:22 +01:00 committed by GitHub
parent c161291d09
commit d8c7e31b18
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 87 additions and 48 deletions

View File

@ -1,4 +1,4 @@
import type { ComponentProps, FC } from 'react';
import type { ComponentProps, FC, ReactNode } from 'react';
import { StrategyEvaluationItem } from '../StrategyEvaluationItem/StrategyEvaluationItem';
import type { ConstraintSchema } from 'openapi';
import { formatOperatorDescription } from 'component/common/ConstraintAccordion/ConstraintOperator/formatOperatorDescription';
@ -48,6 +48,13 @@ const CaseSensitive: FC = () => {
);
};
const StyledConstraintContainer = styled('div')(({ theme }) => ({
display: 'grid',
gridTemplateColumns: 'repeat(3, auto)',
gap: theme.spacing(2),
placeItems: 'center',
}));
const StyledOperatorGroup = styled('div')(({ theme }) => ({
display: 'flex',
alignItems: 'center',
@ -60,9 +67,15 @@ const StyledConstraintName = styled('div')(({ theme }) => ({
overflow: 'hidden',
}));
export const ConstraintItemHeader: FC<
ConstraintSchema & Pick<ComponentProps<typeof ValuesList>, 'onSetTruncated'>
> = ({ onSetTruncated, ...constraint }) => {
type ConstraintItemHeaderProps = ConstraintSchema & {
viewMore?: ReactNode;
} & Pick<ComponentProps<typeof ValuesList>, 'onSetTruncated'>;
export const ConstraintItemHeader: FC<ConstraintItemHeaderProps> = ({
onSetTruncated,
viewMore,
...constraint
}) => {
const { caseInsensitive, contextName, inverted, operator, value, values } =
constraint;
const { locationSettings } = useLocationSettings();
@ -77,22 +90,29 @@ export const ConstraintItemHeader: FC<
return (
<StrategyEvaluationItem type='Constraint'>
<StyledConstraintName>
<Truncator lines={2} title={contextName} arrow>
{contextName}
</Truncator>
</StyledConstraintName>
<StyledOperatorGroup>
<Operator label={operator} inverted={inverted} />
{isCaseSensitive(operator, caseInsensitive) ? (
<CaseSensitive />
) : null}
</StyledOperatorGroup>
<ValuesList
values={items}
onSetTruncated={onSetTruncated}
tooltips={tooltips}
/>
<StyledConstraintContainer>
<StyledConstraintName>
<Truncator title={contextName} arrow>
{contextName}
</Truncator>
</StyledConstraintName>
<StyledOperatorGroup>
<Operator label={operator} inverted={inverted} />
{isCaseSensitive(operator, caseInsensitive) ? (
<CaseSensitive />
) : null}
</StyledOperatorGroup>
<div>
<div>
<ValuesList
values={items}
onSetTruncated={onSetTruncated}
tooltips={tooltips}
/>
{viewMore}
</div>
</div>
</StyledConstraintContainer>
</StrategyEvaluationItem>
);
};

View File

@ -1,9 +1,10 @@
import type { FC } from 'react';
import { styled, Tooltip } from '@mui/material';
import { styled } from '@mui/material';
import {
Truncator,
type TruncatorProps,
} from 'component/common/Truncator/Truncator';
import { TooltipResolver } from 'component/common/TooltipResolver/TooltipResolver';
export type ValuesListProps = {
values?: string[];
@ -14,7 +15,12 @@ const StyledValuesContainer = styled('div')({
flex: '1 1 0',
});
const StyledValueItem = styled('span')(({ theme }) => ({
const StyledTruncator = styled(Truncator)({
padding: 0,
margin: 0,
});
const StyledValueItem = styled('li')(({ theme }) => ({
padding: theme.spacing(0.25),
display: 'inline-block',
span: {
@ -45,22 +51,30 @@ export const ValuesList: FC<ValuesListProps> = ({
lines={2}
onSetTruncated={() => onSetTruncated?.(false)}
>
<Tooltip title={tooltips?.[values[0]] || ''}>
<TooltipResolver title={tooltips?.[values[0]] || ''}>
<span>{values[0]}</span>
</Tooltip>
</TooltipResolver>
</Truncator>
</StyledSingleValue>
) : null}
{values && values?.length > 1 ? (
<Truncator title='' lines={2} onSetTruncated={onSetTruncated}>
<StyledTruncator
title=''
lines={2}
onSetTruncated={onSetTruncated}
component='ul'
>
{values.map((value) => (
<Tooltip title={tooltips?.[value] || ''} key={value}>
<TooltipResolver
title={tooltips?.[value] || ''}
key={value}
>
<StyledValueItem>
<span>{value}</span>
</StyledValueItem>
</Tooltip>
</TooltipResolver>
))}
</Truncator>
</StyledTruncator>
) : null}
</StyledValuesContainer>
);

View File

@ -30,7 +30,6 @@ interface IConstraintAccordionViewProps {
const StyledAccordion = styled(Accordion)(({ theme }) => ({
border: `1px solid ${theme.palette.divider}`,
borderRadius: theme.shape.borderRadiusMedium,
backgroundColor: 'transparent',
boxShadow: 'none',
margin: 0,
'&:before': {

View File

@ -10,7 +10,7 @@ interface IConstraintAccordionViewBodyProps {
}
const StyledValueContainer = styled('div')(({ theme }) => ({
padding: theme.spacing(2, 0),
padding: theme.spacing(1, 0),
maxHeight: '400px',
overflowY: 'auto',
}));

View File

@ -55,7 +55,6 @@ export const ConstraintAccordionViewHeader = ({
{flagOverviewRedesign ? (
<ConstraintAccordionViewHeaderInfo
constraint={constraint}
singleValue={singleValue}
allowExpand={allowExpand}
expanded={expanded}
disabled={disabled}

View File

@ -1,9 +1,7 @@
import { IconButton, styled } from '@mui/material';
import { styled } from '@mui/material';
import type { IConstraint } from 'interfaces/strategy';
import { ConstraintItemHeader } from 'component/common/ConstraintsList/ConstraintItemHeader/ConstraintItemHeader';
import { useState } from 'react';
import VisibilityIcon from '@mui/icons-material/Visibility';
import VisibilityOffIcon from '@mui/icons-material/VisibilityOff';
const StyledHeaderWrapper = styled('div')(({ theme }) => ({
display: 'flex',
@ -24,9 +22,14 @@ const StyledHeaderMetaInfo = styled('div')(({ theme }) => ({
},
}));
const StyledExpandItem = styled('div')(({ theme }) => ({
color: theme.palette.text.secondary,
margin: theme.spacing(0.25, 0, 0, 0.75),
fontSize: theme.fontSizes.smallerBody,
}));
interface ConstraintAccordionViewHeaderMetaInfoProps {
constraint: IConstraint;
singleValue: boolean;
expanded: boolean;
allowExpand: (shouldExpand: boolean) => void;
disabled?: boolean;
@ -49,12 +52,16 @@ export const ConstraintAccordionViewHeaderInfo = ({
setExpandable(state);
allowExpand(state);
}}
viewMore={
expandable ? (
<StyledExpandItem>
{expanded
? 'View less'
: `View all (${constraint.values?.length})`}
</StyledExpandItem>
) : null
}
/>
{expandable ? (
<IconButton type='button'>
{expanded ? <VisibilityOffIcon /> : <VisibilityIcon />}
</IconButton>
) : null}
</StyledHeaderMetaInfo>
</StyledHeaderWrapper>
);

View File

@ -20,10 +20,10 @@ export const ConstraintValueSearch = ({
value={filter}
onChange={(e) => setFilter(e.target.value)}
placeholder='Filter values'
style={{
sx={(theme) => ({
width: '100%',
margin: '1rem 0',
}}
margin: theme.spacing(1, 0, 2),
})}
variant='outlined'
size='small'
InputProps={{

View File

@ -3,7 +3,7 @@ import type { FeatureStrategySchema } from 'openapi';
import type { IFeatureStrategyPayload } from 'interfaces/strategy';
import { useUiFlag } from 'hooks/useUiFlag';
import { StrategyExecution as LegacyStrategyExecution } from './LegacyStrategyExecution';
import { ConstraintItemHeader } from 'component/common/ConstraintsList/ConstraintItemHeader/ConstraintItemHeader';
import { ConstraintAccordionView } from 'component/common/NewConstraintAccordion/ConstraintAccordionView/ConstraintAccordionView';
import { useStrategies } from 'hooks/api/getters/useStrategies/useStrategies';
import { objectId } from 'utils/objectId';
import { useCustomStrategyParameters } from './hooks/useCustomStrategyParameters';
@ -53,10 +53,10 @@ export const StrategyExecution: FC<StrategyExecutionProps> = ({
<SegmentItem segment={segment} key={segment.id} />
))}
{constraints?.map((constraint, index) => (
<ConstraintListItem key={`${objectId(constraint)}-${index}`}>
{/* FIXME: use constraint accordion */}
<ConstraintItemHeader {...constraint} />
</ConstraintListItem>
<ConstraintAccordionView
key={`${objectId(constraint)}-${index}`}
constraint={constraint}
/>
))}
{(isCustomStrategy ? customStrategyItems : strategyParameters).map(
(item, index) => (