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

Segment view for strategy evaluation (#9399)

Refactored "segments" part of strategy evaluation. This shows a lot of places, that use "Legacy" component.
This commit is contained in:
Tymoteusz Czech 2025-02-28 15:15:25 +01:00 committed by GitHub
parent 8d0820fc8b
commit 1b67b288ee
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 275 additions and 165 deletions

View File

@ -0,0 +1,52 @@
import { Children, isValidElement, type FC, type ReactNode } from 'react';
import { styled } from '@mui/material';
const StyledList = styled('ul')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
listStyle: 'none',
padding: 0,
margin: 0,
gap: theme.spacing(1),
}));
const StyledListItem = styled('li')(({ theme }) => ({
position: 'relative',
border: `1px solid ${theme.palette.divider}`,
borderRadius: theme.shape.borderRadiusMedium,
background: theme.palette.background.default,
}));
const StyledAnd = styled('div')(({ theme }) => ({
position: 'absolute',
top: theme.spacing(-0.5),
left: theme.spacing(2),
transform: 'translateY(-50%)',
padding: theme.spacing(0.75, 1),
lineHeight: 1,
fontSize: theme.fontSizes.smallerBody,
color: theme.palette.text.primary,
background: theme.palette.background.application,
borderRadius: theme.shape.borderRadiusLarge,
zIndex: theme.zIndex.fab,
}));
export const ConstraintsList: FC<{ children: ReactNode }> = ({ children }) => {
const result: ReactNode[] = [];
Children.forEach(children, (child, index) => {
if (isValidElement(child)) {
result.push(
<StyledListItem key={index}>
{index > 0 ? (
<StyledAnd role='separator' key={`${index}-divider`}>
AND
</StyledAnd>
) : null}
{child}
</StyledListItem>,
);
}
});
return <StyledList>{result}</StyledList>;
};

View File

@ -12,6 +12,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,
padding: theme.spacing(2, 3),
})); }));
const StyledType = styled('span')(({ theme }) => ({ const StyledType = styled('span')(({ theme }) => ({

View File

@ -0,0 +1,141 @@
import { useState, type VFC } from 'react';
import { Link } from 'react-router-dom';
import DonutLarge from '@mui/icons-material/DonutLarge';
import type { ISegment } from 'interfaces/segment';
import {
Accordion,
AccordionDetails,
AccordionSummary,
Button,
styled,
Typography,
} from '@mui/material';
import { ConstraintAccordionList } from 'component/common/ConstraintAccordion/ConstraintAccordionList/ConstraintAccordionList';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
interface ISegmentItemProps {
segment: Partial<ISegment>;
isExpanded?: boolean;
disabled?: boolean | null;
constraintList?: JSX.Element;
headerContent?: JSX.Element;
}
const StyledAccordion = styled(Accordion, {
shouldForwardProp: (prop) => prop !== 'isDisabled',
})<{ isDisabled: boolean | null }>(({ theme, isDisabled }) => ({
border: `1px solid ${theme.palette.divider}`,
'&.segment-accordion': {
borderRadius: theme.shape.borderRadiusMedium,
},
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 }) => ({
margin: theme.spacing(0, 0.5),
fontSize: theme.typography.body2.fontSize,
'.MuiAccordionSummary-content': {
display: 'flex',
alignItems: 'center',
},
}));
const StyledLink = styled(Link)(({ theme }) => ({
textDecoration: 'none',
marginLeft: theme.spacing(1),
'&:hover': {
textDecoration: 'underline',
},
}));
const StyledText = styled('span', {
shouldForwardProp: (prop) => prop !== 'disabled',
})<{ disabled: boolean | null }>(({ theme, disabled }) => ({
color: disabled ? theme.palette.text.secondary : 'inherit',
}));
export const SegmentItem: VFC<ISegmentItemProps> = ({
segment,
isExpanded,
headerContent,
constraintList,
disabled = false,
}) => {
const [isOpen, setIsOpen] = useState(isExpanded || false);
return (
<StyledAccordion
className='segment-accordion'
isDisabled={disabled}
expanded={isOpen}
>
<StyledAccordionSummary id={`segment-accordion-${segment.id}`}>
<DonutLarge
sx={(theme) => ({
mr: 1,
color: disabled
? theme.palette.neutral.border
: theme.palette.secondary.main,
})}
/>
<StyledText disabled={disabled}>Segment:</StyledText>
<StyledLink to={`/segments/edit/${segment.id}`}>
{segment.name}
</StyledLink>
<ConditionallyRender
condition={Boolean(headerContent)}
show={headerContent}
/>
<ConditionallyRender
condition={!isExpanded}
show={
<Button
size='small'
variant='outlined'
onClick={() => setIsOpen((value) => !value)}
sx={{
my: 0,
ml: 'auto',
fontSize: (theme) =>
theme.typography.body2.fontSize,
}}
>
{isOpen ? 'Close preview' : 'Preview'}
</Button>
}
/>
</StyledAccordionSummary>
<AccordionDetails sx={{ pt: 0 }}>
<ConditionallyRender
condition={Boolean(constraintList)}
show={constraintList}
elseShow={
<ConditionallyRender
condition={(segment?.constraints?.length || 0) > 0}
show={
<ConstraintAccordionList
constraints={segment!.constraints!}
showLabel={false}
/>
}
elseShow={
<Typography>
This segment has no constraints.
</Typography>
}
/>
}
/>
</AccordionDetails>
</StyledAccordion>
);
};

View File

@ -1,6 +1,5 @@
import { useState, type VFC } from 'react'; import { useMemo, useState, type FC } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import DonutLarge from '@mui/icons-material/DonutLarge';
import type { ISegment } from 'interfaces/segment'; import type { ISegment } from 'interfaces/segment';
import { import {
Accordion, Accordion,
@ -10,132 +9,106 @@ import {
styled, styled,
Typography, Typography,
} from '@mui/material'; } from '@mui/material';
import { ConstraintAccordionList } from 'component/common/ConstraintAccordion/ConstraintAccordionList/ConstraintAccordionList'; import { StrategyEvaluationItem } from 'component/common/ConstraintsList/StrategyEvaluationItem/StrategyEvaluationItem';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConstraintItem } from 'component/common/ConstraintsList/ConstraintItem/ConstraintItem';
import { objectId } from 'utils/objectId';
import { ConstraintsList } from 'component/common/ConstraintsList/ConstraintsList';
interface ISegmentItemProps { type SegmentItemProps = {
segment: Partial<ISegment>; segment: Partial<ISegment>;
isExpanded?: boolean; isExpanded?: boolean;
disabled?: boolean | null; disabled?: boolean | null;
constraintList?: JSX.Element; constraintList?: JSX.Element;
headerContent?: JSX.Element; headerContent?: JSX.Element;
} };
const StyledAccordion = styled(Accordion, { const StyledAccordion = styled(Accordion)(({ theme }) => ({
shouldForwardProp: (prop) => prop !== 'isDisabled',
})<{ isDisabled: boolean | null }>(({ theme, isDisabled }) => ({
border: `1px solid ${theme.palette.divider}`,
'&.segment-accordion': {
borderRadius: theme.shape.borderRadiusMedium,
},
boxShadow: 'none', boxShadow: 'none',
margin: 0, margin: 0,
transition: 'all 0.1s ease', padding: 0,
'&: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 }) => ({ const StyledAccordionSummary = styled(AccordionSummary)(({ theme }) => ({
margin: theme.spacing(0, 0.5), padding: 0,
fontSize: theme.typography.body2.fontSize, fontSize: theme.typography.body2.fontSize,
'.MuiAccordionSummary-content': { '.MuiAccordionSummary-content, .Mui-expanded.MuiAccordionSummary-content': {
display: 'flex', margin: 0,
alignItems: 'center',
}, },
})); }));
const StyledLink = styled(Link)(({ theme }) => ({ const StyledAccordionDetails = styled(AccordionDetails)(({ theme }) => ({
padding: theme.spacing(0, 2, 3),
}));
const StyledLink = styled(Link)({
textDecoration: 'none', textDecoration: 'none',
marginLeft: theme.spacing(1),
'&:hover': { '&:hover': {
textDecoration: 'underline', textDecoration: 'underline',
}, },
});
const StyledActionsContainer = styled('div')(({ theme }) => ({
display: 'flex',
alignItems: 'center',
marginLeft: 'auto',
marginRight: theme.spacing(2),
})); }));
const StyledText = styled('span', { const StyledButton = styled(Button)(({ theme }) => ({
shouldForwardProp: (prop) => prop !== 'disabled', fontSize: theme.typography.body2.fontSize,
})<{ disabled: boolean | null }>(({ theme, disabled }) => ({
color: disabled ? theme.palette.text.secondary : 'inherit',
})); }));
export const SegmentItem: VFC<ISegmentItemProps> = ({ export const SegmentItem: FC<SegmentItemProps> = ({
segment, segment,
isExpanded, isExpanded,
headerContent, headerContent,
constraintList, constraintList,
disabled = false,
}) => { }) => {
const [isOpen, setIsOpen] = useState(isExpanded || false); const [isOpen, setIsOpen] = useState(isExpanded || false);
const constraints = useMemo(() => {
if (constraintList) {
return constraintList;
}
if (segment.constraints?.length) {
return (
<ConstraintsList>
{segment.constraints.map((constraint, index) => (
<ConstraintItem
key={`${objectId(constraint)}-${index}`}
{...constraint}
/>
))}
</ConstraintsList>
);
}
return <Typography>This segment has no constraints.</Typography>;
}, [constraintList, segment.constraints]);
return ( return (
<StyledAccordion <StyledAccordion expanded={isOpen}>
className='segment-accordion'
isDisabled={disabled}
expanded={isOpen}
>
<StyledAccordionSummary id={`segment-accordion-${segment.id}`}> <StyledAccordionSummary id={`segment-accordion-${segment.id}`}>
<DonutLarge <StrategyEvaluationItem type='Segment'>
sx={(theme) => ({ <StyledLink to={`/segments/edit/${segment.id}`}>
mr: 1, {segment.name}
color: disabled </StyledLink>
? theme.palette.neutral.border </StrategyEvaluationItem>
: theme.palette.secondary.main, {headerContent ? headerContent : null}
})} {!isExpanded ? (
/> <StyledActionsContainer>
<StyledText disabled={disabled}>Segment:</StyledText> <StyledButton
<StyledLink to={`/segments/edit/${segment.id}`}>
{segment.name}
</StyledLink>
<ConditionallyRender
condition={Boolean(headerContent)}
show={headerContent}
/>
<ConditionallyRender
condition={!isExpanded}
show={
<Button
size='small' size='small'
variant='outlined' variant='outlined'
onClick={() => setIsOpen((value) => !value)} onClick={() => setIsOpen((value) => !value)}
sx={{
my: 0,
ml: 'auto',
fontSize: (theme) =>
theme.typography.body2.fontSize,
}}
> >
{isOpen ? 'Close preview' : 'Preview'} {isOpen ? 'Close preview' : 'Preview'}
</Button> </StyledButton>
} </StyledActionsContainer>
/> ) : null}
</StyledAccordionSummary> </StyledAccordionSummary>
<AccordionDetails sx={{ pt: 0 }}> <StyledAccordionDetails>{constraints}</StyledAccordionDetails>
<ConditionallyRender
condition={Boolean(constraintList)}
show={constraintList}
elseShow={
<ConditionallyRender
condition={(segment?.constraints?.length || 0) > 0}
show={
<ConstraintAccordionList
constraints={segment!.constraints!}
showLabel={false}
/>
}
elseShow={
<Typography>
This segment has no constraints.
</Typography>
}
/>
}
/>
</AccordionDetails>
</StyledAccordion> </StyledAccordion>
); );
}; };

View File

@ -3,7 +3,7 @@ import { Fragment, useState } from 'react';
import type { ISegment } from 'interfaces/segment'; import type { ISegment } from 'interfaces/segment';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { FeatureStrategySegmentChip } from 'component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegmentChip'; import { FeatureStrategySegmentChip } from 'component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegmentChip';
import { SegmentItem } from 'component/common/SegmentItem/SegmentItem'; import { SegmentItem } from 'component/common/SegmentItem/LegacySegmentItem';
import { styled } from '@mui/material'; import { styled } from '@mui/material';
interface IFeatureStrategySegmentListProps { interface IFeatureStrategySegmentListProps {

View File

@ -1,18 +0,0 @@
import { styled } from '@mui/material';
const StyledAnd = styled('div')(({ theme }) => ({
position: 'absolute',
top: theme.spacing(-0.5),
left: theme.spacing(2),
transform: 'translateY(-50%)',
padding: theme.spacing(0.75, 1),
lineHeight: 1,
fontSize: theme.fontSizes.smallerBody,
color: theme.palette.text.primary,
background: theme.palette.background.application,
borderRadius: theme.shape.borderRadiusLarge,
}));
export const StrategyEvaluationSeparator = () => (
<StyledAnd role='separator'>AND</StyledAnd>
);

View File

@ -1,17 +1,17 @@
import { Children, isValidElement, type FC, type ReactNode } from 'react'; import type { FC } from 'react';
import { styled } from '@mui/material'; import { styled } from '@mui/material';
import type { CreateFeatureStrategySchema } from 'openapi'; import type { CreateFeatureStrategySchema } 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 './ConstraintItem/ConstraintItem'; import { ConstraintItem } from 'component/common/ConstraintsList/ConstraintItem/ConstraintItem';
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 { StrategyEvaluationSeparator } from './StrategyEvaluationSeparator/StrategyEvaluationSeparator';
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';
const FilterContainer = styled('div', { const FilterContainer = styled('div', {
shouldForwardProp: (prop) => prop !== 'grayscale', shouldForwardProp: (prop) => prop !== 'grayscale',
@ -19,49 +19,6 @@ const FilterContainer = styled('div', {
grayscale ? { filter: 'grayscale(1)', opacity: 0.67 } : {}, grayscale ? { filter: 'grayscale(1)', opacity: 0.67 } : {},
); );
const StyledList = styled('ul')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
listStyle: 'none',
padding: 0,
margin: 0,
'&.disabled-strategy': {
filter: 'grayscale(1)',
opacity: 0.67,
},
gap: theme.spacing(1),
}));
const StyledListItem = styled('li')(({ theme }) => ({
position: 'relative',
padding: theme.spacing(2, 3),
border: `1px solid ${theme.palette.divider}`,
borderRadius: theme.shape.borderRadiusMedium,
background: theme.palette.background.default,
}));
const List: FC<{ children: ReactNode }> = ({ children }) => {
const result: ReactNode[] = [];
Children.forEach(children, (child, index) => {
if (isValidElement(child)) {
result.push(
<ListItem key={index}>
{index > 0 ? (
<StrategyEvaluationSeparator key={`${index}-divider`} />
) : null}
{child}
</ListItem>,
);
}
});
return <StyledList>{result}</StyledList>;
};
const ListItem: FC<{ children: ReactNode }> = ({ children }) => (
<StyledListItem>{children}</StyledListItem>
);
type StrategyExecutionProps = { type StrategyExecutionProps = {
strategy: IFeatureStrategyPayload | CreateFeatureStrategySchema; strategy: IFeatureStrategyPayload | CreateFeatureStrategySchema;
displayGroupId?: boolean; displayGroupId?: boolean;
@ -93,7 +50,7 @@ export const StrategyExecution: FC<StrategyExecutionProps> = ({
return ( return (
<FilterContainer grayscale={strategy.disabled === true}> <FilterContainer grayscale={strategy.disabled === true}>
<List> <ConstraintsList>
{strategySegments?.map((segment) => ( {strategySegments?.map((segment) => (
<SegmentItem segment={segment} /> <SegmentItem segment={segment} />
))} ))}
@ -104,7 +61,7 @@ export const StrategyExecution: FC<StrategyExecutionProps> = ({
/> />
))} ))}
{isCustomStrategy ? customStrategyItems : strategyParameters} {isCustomStrategy ? customStrategyItems : strategyParameters}
</List> </ConstraintsList>
</FilterContainer> </FilterContainer>
); );
}; };

View File

@ -5,8 +5,8 @@ import {
parseParameterString, parseParameterString,
parseParameterStrings, parseParameterStrings,
} from 'utils/parseParameter'; } from 'utils/parseParameter';
import { StrategyEvaluationItem } from '../StrategyEvaluationItem/StrategyEvaluationItem'; import { StrategyEvaluationItem } from 'component/common/ConstraintsList/StrategyEvaluationItem/StrategyEvaluationItem';
import { StrategyEvaluationChip } from '../StrategyEvaluationChip/StrategyEvaluationChip'; import { StrategyEvaluationChip } from 'component/common/ConstraintsList/StrategyEvaluationChip/StrategyEvaluationChip';
import type { import type {
CreateFeatureStrategySchema, CreateFeatureStrategySchema,
StrategySchema, StrategySchema,

View File

@ -1,10 +1,10 @@
import { type FC, useMemo } from 'react'; import { type FC, useMemo } from 'react';
import { StrategyEvaluationChip } from '../StrategyEvaluationChip/StrategyEvaluationChip'; import { StrategyEvaluationChip } from 'component/common/ConstraintsList/StrategyEvaluationChip/StrategyEvaluationChip';
import { import {
parseParameterNumber, parseParameterNumber,
parseParameterStrings, parseParameterStrings,
} from 'utils/parseParameter'; } from 'utils/parseParameter';
import { StrategyEvaluationItem } from '../StrategyEvaluationItem/StrategyEvaluationItem'; import { StrategyEvaluationItem } from 'component/common/ConstraintsList/StrategyEvaluationItem/StrategyEvaluationItem';
import type { IFeatureStrategyPayload } from 'interfaces/strategy'; import type { IFeatureStrategyPayload } from 'interfaces/strategy';
import type { CreateFeatureStrategySchema } from 'openapi'; import type { CreateFeatureStrategySchema } from 'openapi';
@ -38,7 +38,11 @@ const RolloutParameter: FC<{
{hasConstraints ? 'who match constraints ' : ' '} {hasConstraints ? 'who match constraints ' : ' '}
is included. is included.
</span> </span>
{/* TODO: displayGroupId */} {displayGroupId && parameters?.groupId ? (
<StrategyEvaluationChip
label={`groupId: ${parameters?.groupId}`}
/>
) : null}
</StrategyEvaluationItem> </StrategyEvaluationItem>
); );
}; };

View File

@ -1,7 +1,7 @@
import { Fragment } from 'react'; import { Fragment } from 'react';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { StrategySeparator } from 'component/common/StrategySeparator/LegacyStrategySeparator'; import { StrategySeparator } from 'component/common/StrategySeparator/LegacyStrategySeparator';
import { SegmentItem } from '../../../../common/SegmentItem/SegmentItem'; import { SegmentItem } from 'component/common/SegmentItem/LegacySegmentItem';
import type { ISegment } from 'interfaces/segment'; import type { ISegment } from 'interfaces/segment';
interface IFeatureOverviewSegmentProps { interface IFeatureOverviewSegmentProps {

View File

@ -5,7 +5,7 @@ import CancelOutlined from '@mui/icons-material/CancelOutlined';
import { StrategySeparator } from 'component/common/StrategySeparator/LegacyStrategySeparator'; import { StrategySeparator } from 'component/common/StrategySeparator/LegacyStrategySeparator';
import { styled, Typography } from '@mui/material'; import { styled, Typography } from '@mui/material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { SegmentItem } from 'component/common/SegmentItem/SegmentItem'; import { SegmentItem } from 'component/common/SegmentItem/LegacySegmentItem';
interface ISegmentExecutionProps { interface ISegmentExecutionProps {
segments?: PlaygroundSegmentSchema[]; segments?: PlaygroundSegmentSchema[];

View File

@ -2,7 +2,7 @@ import { Fragment, type VFC } from 'react';
import type { PlaygroundSegmentSchema } from 'openapi'; import type { PlaygroundSegmentSchema } from 'openapi';
import { StrategySeparator } from 'component/common/StrategySeparator/LegacyStrategySeparator'; import { StrategySeparator } from 'component/common/StrategySeparator/LegacyStrategySeparator';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { SegmentItem } from 'component/common/SegmentItem/SegmentItem'; import { SegmentItem } from 'component/common/SegmentItem/LegacySegmentItem';
import { ConstraintExecutionWithoutResults } from '../ConstraintExecution/ConstraintExecutionWithoutResults'; import { ConstraintExecutionWithoutResults } from '../ConstraintExecution/ConstraintExecutionWithoutResults';
interface ISegmentExecutionWithoutResultProps { interface ISegmentExecutionWithoutResultProps {

View File

@ -2,7 +2,7 @@ import { Fragment, useState } from 'react';
import type { ISegment } from 'interfaces/segment'; import type { ISegment } from 'interfaces/segment';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { FeatureStrategySegmentChip } from 'component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegmentChip'; import { FeatureStrategySegmentChip } from 'component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegmentChip';
import { SegmentItem } from 'component/common/SegmentItem/SegmentItem'; import { SegmentItem } from 'component/common/SegmentItem/LegacySegmentItem';
import { styled } from '@mui/material'; import { styled } from '@mui/material';
const StyledList = styled('div')(({ theme }) => ({ const StyledList = styled('div')(({ theme }) => ({