1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-08-27 13:49:10 +02:00

improved constraints list

This commit is contained in:
Tymoteusz Czech 2025-03-20 10:41:00 +01:00
parent bb779828d3
commit d14ae2d8ed
No known key found for this signature in database
GPG Key ID: 133555230D88D75F
9 changed files with 90 additions and 68 deletions

View File

@ -32,7 +32,7 @@ const StyledOperatorGroup = styled('div')(({ theme }) => ({
gap: theme.spacing(0.5), gap: theme.spacing(0.5),
})); }));
export const ConstraintItem: FC< export const ConstraintItemHeader: FC<
ConstraintSchema & Pick<StrategyEvaluationItemProps, 'onSetTruncated'> ConstraintSchema & Pick<StrategyEvaluationItemProps, 'onSetTruncated'>
> = ({ > = ({
caseInsensitive, caseInsensitive,

View File

@ -10,17 +10,21 @@ const StyledList = styled('ul')(({ theme }) => ({
gap: theme.spacing(1), gap: theme.spacing(1),
})); }));
const StyledListItem = styled('li')(({ theme }) => ({ export const ConstraintListItem = styled('div')(({ theme }) => ({
position: 'relative', position: 'relative',
border: `1px solid ${theme.palette.divider}`, border: `1px solid ${theme.palette.divider}`,
borderRadius: theme.shape.borderRadiusMedium, borderRadius: theme.shape.borderRadiusMedium,
background: theme.palette.background.default, background: theme.palette.background.default,
padding: theme.spacing(2, 3), padding: theme.spacing(1.5, 3),
display: 'flex', display: 'flex',
flexFlow: 'column', flexFlow: 'column',
gap: theme.spacing(2), gap: theme.spacing(2),
})); }));
const StyledListItem = styled('li')({
position: 'relative',
});
const StyledAnd = styled('div')(({ theme }) => ({ const StyledAnd = styled('div')(({ theme }) => ({
position: 'absolute', position: 'absolute',
top: theme.spacing(-0.5), top: theme.spacing(-0.5),

View File

@ -16,6 +16,7 @@ const StyledContainer = styled('div')(({ theme }) => ({
gap: theme.spacing(1), gap: theme.spacing(1),
alignItems: 'center', alignItems: 'center',
fontSize: theme.typography.body2.fontSize, fontSize: theme.typography.body2.fontSize,
minHeight: theme.spacing(4),
})); }));
const StyledContent = styled('div')(({ theme }) => ({ const StyledContent = styled('div')(({ theme }) => ({

View File

@ -1,6 +1,6 @@
import { IconButton, styled } from '@mui/material'; import { IconButton, styled } from '@mui/material';
import type { IConstraint } from 'interfaces/strategy'; import type { IConstraint } from 'interfaces/strategy';
import { ConstraintItem } from 'component/common/ConstraintsList/ConstraintItem/ConstraintItem'; import { ConstraintItemHeader } from 'component/common/ConstraintsList/ConstraintItemHeader/ConstraintItemHeader';
import { useState } from 'react'; import { useState } from 'react';
import VisibilityIcon from '@mui/icons-material/Visibility'; import VisibilityIcon from '@mui/icons-material/Visibility';
import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'; import VisibilityOffIcon from '@mui/icons-material/VisibilityOff';
@ -43,7 +43,7 @@ export const ConstraintAccordionViewHeaderInfo = ({
return ( return (
<StyledHeaderWrapper> <StyledHeaderWrapper>
<StyledHeaderMetaInfo> <StyledHeaderMetaInfo>
<ConstraintItem <ConstraintItemHeader
{...constraint} {...constraint}
onSetTruncated={(state: boolean) => { onSetTruncated={(state: boolean) => {
setExpandable(state); setExpandable(state);

View File

@ -7,6 +7,9 @@ interface IConstraintIconProps {
disabled?: boolean; disabled?: boolean;
} }
/**
* @deprecated remove with `flagOverviewRedesign`
*/
export const ConstraintIcon: VFC<IConstraintIconProps> = ({ export const ConstraintIcon: VFC<IConstraintIconProps> = ({
compact, compact,
disabled, disabled,

View File

@ -1,5 +1,4 @@
import type { IConstraint } from 'interfaces/strategy'; import type { IConstraint } from 'interfaces/strategy';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { ConstraintAccordionEdit } from './ConstraintAccordionEdit/ConstraintAccordionEdit'; import { ConstraintAccordionEdit } from './ConstraintAccordionEdit/ConstraintAccordionEdit';
import { ConstraintAccordionView } from './ConstraintAccordionView/ConstraintAccordionView'; import { ConstraintAccordionView } from './ConstraintAccordionView/ConstraintAccordionView';
@ -27,26 +26,24 @@ export const NewConstraintAccordion = ({
}: IConstraintAccordionProps) => { }: IConstraintAccordionProps) => {
if (!constraint) return null; if (!constraint) return null;
if (editing && onSave) {
return (
<ConstraintAccordionEdit
constraint={constraint}
onCancel={onCancel}
onSave={onSave!}
onDelete={onDelete}
onAutoSave={onAutoSave!}
compact={compact}
/>
);
}
return ( return (
<ConditionallyRender <ConstraintAccordionView
condition={Boolean(editing && onSave)} constraint={constraint}
show={ onEdit={onEdit}
<ConstraintAccordionEdit onDelete={onDelete}
constraint={constraint}
onCancel={onCancel}
onSave={onSave!}
onDelete={onDelete}
onAutoSave={onAutoSave!}
compact={compact}
/>
}
elseShow={
<ConstraintAccordionView
constraint={constraint}
onEdit={onEdit}
onDelete={onDelete}
/>
}
/> />
); );
}; };

View File

@ -9,9 +9,12 @@ import {
styled, styled,
} from '@mui/material'; } from '@mui/material';
import { StrategyEvaluationItem } from 'component/common/ConstraintsList/StrategyEvaluationItem/StrategyEvaluationItem'; import { StrategyEvaluationItem } from 'component/common/ConstraintsList/StrategyEvaluationItem/StrategyEvaluationItem';
import { ConstraintItem } from 'component/common/ConstraintsList/ConstraintItem/ConstraintItem'; import { ConstraintItemHeader } from 'component/common/ConstraintsList/ConstraintItemHeader/ConstraintItemHeader';
import { objectId } from 'utils/objectId'; import { objectId } from 'utils/objectId';
import { ConstraintsList } from 'component/common/ConstraintsList/ConstraintsList'; import {
ConstraintListItem,
ConstraintsList,
} from 'component/common/ConstraintsList/ConstraintsList';
type SegmentItemProps = { type SegmentItemProps = {
segment: Partial<ISegment>; segment: Partial<ISegment>;
@ -21,7 +24,11 @@ type SegmentItemProps = {
headerContent?: JSX.Element; headerContent?: JSX.Element;
}; };
const StyledAccordion = styled(Accordion)(({ theme }) => ({ const StyledConstraintListItem = styled(ConstraintListItem)(() => ({
padding: 0,
}));
const StyledAccordion = styled(Accordion)(() => ({
boxShadow: 'none', boxShadow: 'none',
margin: 0, margin: 0,
padding: 0, padding: 0,
@ -32,16 +39,14 @@ const StyledAccordion = styled(Accordion)(({ theme }) => ({
})); }));
const StyledAccordionSummary = styled(AccordionSummary)(({ theme }) => ({ const StyledAccordionSummary = styled(AccordionSummary)(({ theme }) => ({
padding: 0, padding: theme.spacing(0, 3),
fontSize: theme.typography.body2.fontSize, fontSize: theme.typography.body2.fontSize,
minHeight: 'unset', minHeight: 'unset',
'.MuiAccordionSummary-content, .MuiAccordionSummary-content.Mui-expanded': {
margin: 0,
},
})); }));
const StyledAccordionDetails = styled(AccordionDetails)(({ theme }) => ({ const StyledAccordionDetails = styled(AccordionDetails)(({ theme }) => ({
padding: theme.spacing(2, 0, 1), borderTop: `1px dashed ${theme.palette.divider}`,
padding: theme.spacing(1.5, 3, 2.5),
})); }));
const StyledLink = styled(Link)({ const StyledLink = styled(Link)({
@ -55,8 +60,6 @@ const StyledActionsContainer = styled('div')(({ theme }) => ({
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
marginLeft: 'auto', marginLeft: 'auto',
marginTop: theme.spacing(-0.5),
marginBottom: theme.spacing(-0.5),
})); }));
const StyledButton = styled(Button)(({ theme }) => ({ const StyledButton = styled(Button)(({ theme }) => ({
@ -85,10 +88,12 @@ export const SegmentItem: FC<SegmentItemProps> = ({
return ( return (
<ConstraintsList> <ConstraintsList>
{segment.constraints.map((constraint, index) => ( {segment.constraints.map((constraint, index) => (
<ConstraintItem <ConstraintListItem
key={`${objectId(constraint)}-${index}`} key={`${objectId(constraint)}-${index}`}
{...constraint} >
/> {/* FIXME: use accordion */}
<ConstraintItemHeader {...constraint} />
</ConstraintListItem>
))} ))}
</ConstraintsList> </ConstraintsList>
); );
@ -102,27 +107,29 @@ export const SegmentItem: FC<SegmentItemProps> = ({
}, [constraintList, segment.constraints]); }, [constraintList, segment.constraints]);
return ( return (
<StyledAccordion expanded={isOpen} disableGutters> <StyledConstraintListItem>
<StyledAccordionSummary id={`segment-accordion-${segment.id}`}> <StyledAccordion expanded={isOpen} disableGutters>
<StrategyEvaluationItem type='Segment'> <StyledAccordionSummary id={`segment-accordion-${segment.id}`}>
<StyledLink to={`/segments/edit/${segment.id}`}> <StrategyEvaluationItem type='Segment'>
{segment.name} <StyledLink to={`/segments/edit/${segment.id}`}>
</StyledLink> {segment.name}
</StrategyEvaluationItem> </StyledLink>
{headerContent ? headerContent : null} </StrategyEvaluationItem>
{!isExpanded ? ( {headerContent ? headerContent : null}
<StyledActionsContainer> {!isExpanded ? (
<StyledButton <StyledActionsContainer>
size='small' <StyledButton
variant='outlined' size='small'
onClick={() => setIsOpen((value) => !value)} variant='outlined'
> onClick={() => setIsOpen((value) => !value)}
{isOpen ? 'Close preview' : 'Preview'} >
</StyledButton> {isOpen ? 'Close preview' : 'Preview'}
</StyledActionsContainer> </StyledButton>
) : null} </StyledActionsContainer>
</StyledAccordionSummary> ) : null}
<StyledAccordionDetails>{constraints}</StyledAccordionDetails> </StyledAccordionSummary>
</StyledAccordion> <StyledAccordionDetails>{constraints}</StyledAccordionDetails>
</StyledAccordion>
</StyledConstraintListItem>
); );
}; };

View File

@ -4,14 +4,17 @@ import type { FeatureStrategySchema } from 'openapi';
import type { IFeatureStrategyPayload } from 'interfaces/strategy'; import type { IFeatureStrategyPayload } from 'interfaces/strategy';
import { useUiFlag } from 'hooks/useUiFlag'; import { useUiFlag } from 'hooks/useUiFlag';
import { StrategyExecution as LegacyStrategyExecution } from './LegacyStrategyExecution'; import { StrategyExecution as LegacyStrategyExecution } from './LegacyStrategyExecution';
import { ConstraintItem } from 'component/common/ConstraintsList/ConstraintItem/ConstraintItem'; import { ConstraintItemHeader } from 'component/common/ConstraintsList/ConstraintItemHeader/ConstraintItemHeader';
import { useStrategies } from 'hooks/api/getters/useStrategies/useStrategies'; import { useStrategies } from 'hooks/api/getters/useStrategies/useStrategies';
import { objectId } from 'utils/objectId'; import { objectId } from 'utils/objectId';
import { useCustomStrategyParameters } from './hooks/useCustomStrategyParameters'; import { useCustomStrategyParameters } from './hooks/useCustomStrategyParameters';
import { useStrategyParameters } from './hooks/useStrategyParameters'; import { useStrategyParameters } from './hooks/useStrategyParameters';
import { useSegments } from 'hooks/api/getters/useSegments/useSegments'; import { useSegments } from 'hooks/api/getters/useSegments/useSegments';
import { SegmentItem } from 'component/common/SegmentItem/SegmentItem'; import { SegmentItem } from 'component/common/SegmentItem/SegmentItem';
import { ConstraintsList } from 'component/common/ConstraintsList/ConstraintsList'; import {
ConstraintListItem,
ConstraintsList,
} from 'component/common/ConstraintsList/ConstraintsList';
const FilterContainer = styled('div', { const FilterContainer = styled('div', {
shouldForwardProp: (prop) => prop !== 'grayscale', shouldForwardProp: (prop) => prop !== 'grayscale',
@ -58,12 +61,19 @@ export const StrategyExecution: FC<StrategyExecutionProps> = ({
<SegmentItem segment={segment} key={segment.id} /> <SegmentItem segment={segment} key={segment.id} />
))} ))}
{constraints?.map((constraint, index) => ( {constraints?.map((constraint, index) => (
<ConstraintItem <ConstraintListItem
key={`${objectId(constraint)}-${index}`} key={`${objectId(constraint)}-${index}`}
{...constraint} >
/> {/* FIXME: use constraint accordion */}
<ConstraintItemHeader {...constraint} />
</ConstraintListItem>
))}
{(isCustomStrategy
? customStrategyItems
: strategyParameters
).map((item, index) => (
<ConstraintListItem key={index}>{item}</ConstraintListItem>
))} ))}
{isCustomStrategy ? customStrategyItems : strategyParameters}
</ConstraintsList> </ConstraintsList>
</FilterContainer> </FilterContainer>
); );

View File

@ -3,7 +3,7 @@ import type {
PlaygroundConstraintSchema, PlaygroundConstraintSchema,
PlaygroundRequestSchema, PlaygroundRequestSchema,
} from 'openapi'; } from 'openapi';
import { ConstraintItem } from 'component/common/ConstraintsList/ConstraintItem/ConstraintItem'; import { ConstraintItemHeader } from 'component/common/ConstraintsList/ConstraintItemHeader/ConstraintItemHeader';
import CheckCircle from '@mui/icons-material/CheckCircle'; import CheckCircle from '@mui/icons-material/CheckCircle';
import { styled } from '@mui/material'; import { styled } from '@mui/material';
import Cancel from '@mui/icons-material/Cancel'; import Cancel from '@mui/icons-material/Cancel';
@ -68,7 +68,7 @@ export const ConstraintExecution: FC<IConstraintExecutionProps> = ({
return ( return (
<> <>
<ConstraintItem {...constraint} /> <ConstraintItemHeader {...constraint} />
{constraint.result ? ( {constraint.result ? (
<ConstraintOk /> <ConstraintOk />
) : ( ) : (