diff --git a/frontend/src/component/common/ConstraintsList/ConstraintItem/ConstraintItem.tsx b/frontend/src/component/common/ConstraintsList/ConstraintItem/ConstraintItem.tsx index 2a038b3315..222b8f9674 100644 --- a/frontend/src/component/common/ConstraintsList/ConstraintItem/ConstraintItem.tsx +++ b/frontend/src/component/common/ConstraintsList/ConstraintItem/ConstraintItem.tsx @@ -1,5 +1,8 @@ import type { FC } from 'react'; -import { StrategyEvaluationItem } from '../StrategyEvaluationItem/StrategyEvaluationItem'; +import { + StrategyEvaluationItem, + type StrategyEvaluationItemProps, +} from '../StrategyEvaluationItem/StrategyEvaluationItem'; import type { ConstraintSchema } from 'openapi'; import { formatOperatorDescription } from 'component/common/ConstraintAccordion/ConstraintOperator/formatOperatorDescription'; import { StrategyEvaluationChip } from '../StrategyEvaluationChip/StrategyEvaluationChip'; @@ -29,18 +32,25 @@ const StyledOperatorGroup = styled('div')(({ theme }) => ({ gap: theme.spacing(0.5), })); -export const ConstraintItem: FC = ({ +export const ConstraintItem: FC< + ConstraintSchema & Pick +> = ({ caseInsensitive, contextName, inverted, operator, value, values, + onSetTruncated, }) => { const items = value ? [value, ...(values || [])] : values || []; return ( - + {contextName} {inverted ? : null} diff --git a/frontend/src/component/common/ConstraintsList/StrategyEvaluationItem/StrategyEvaluationItem.tsx b/frontend/src/component/common/ConstraintsList/StrategyEvaluationItem/StrategyEvaluationItem.tsx index 5f26e7e4a6..9bf97c46ab 100644 --- a/frontend/src/component/common/ConstraintsList/StrategyEvaluationItem/StrategyEvaluationItem.tsx +++ b/frontend/src/component/common/ConstraintsList/StrategyEvaluationItem/StrategyEvaluationItem.tsx @@ -1,11 +1,15 @@ -import { Chip, type ChipProps, styled } from '@mui/material'; +import { styled } from '@mui/material'; +import { + Truncator, + type TruncatorProps, +} from 'component/common/Truncator/Truncator'; import type { FC, ReactNode } from 'react'; -type StrategyItemProps = { +export type StrategyEvaluationItemProps = { type?: ReactNode; children?: ReactNode; values?: string[]; -}; +} & Pick; const StyledContainer = styled('div')(({ theme }) => ({ display: 'flex', @@ -17,7 +21,6 @@ const StyledContainer = styled('div')(({ theme }) => ({ const StyledContent = styled('div')(({ theme }) => ({ display: 'flex', gap: theme.spacing(1), - flexWrap: 'wrap', alignItems: 'center', })); @@ -30,37 +33,33 @@ const StyledType = styled('span')(({ theme }) => ({ width: theme.spacing(10), })); -const StyledValuesGroup = styled('div')(({ theme }) => ({ - display: 'flex', - alignItems: 'center', - gap: theme.spacing(0.5), -})); - -const StyledValue = styled(({ ...props }: ChipProps) => ( - -))(({ theme }) => ({ - padding: theme.spacing(0.5), - background: theme.palette.background.elevation1, -})); - /** * Abstract building block for a list of constraints, segments and other items inside a strategy */ -export const StrategyEvaluationItem: FC = ({ +export const StrategyEvaluationItem: FC = ({ type, children, values, + onSetTruncated, }) => ( {type} {children} - {values && values?.length > 0 ? ( - - {values?.map((value, index) => ( - - ))} - + {values && values?.length === 1 ? ( + onSetTruncated?.(false)} + > + {values[0]} + + ) : null} + {values && values?.length > 1 ? ( + + {values.join(', ')} + ) : null} diff --git a/frontend/src/component/common/NewConstraintAccordion/ConstraintAccordionView/ConstraintAccordionViewHeader/ConstraintAccordionViewHeader.tsx b/frontend/src/component/common/NewConstraintAccordion/ConstraintAccordionView/ConstraintAccordionViewHeader/ConstraintAccordionViewHeader.tsx index 633aa3dd19..e7a80d8e87 100644 --- a/frontend/src/component/common/NewConstraintAccordion/ConstraintAccordionView/ConstraintAccordionViewHeader/ConstraintAccordionViewHeader.tsx +++ b/frontend/src/component/common/NewConstraintAccordion/ConstraintAccordionView/ConstraintAccordionViewHeader/ConstraintAccordionViewHeader.tsx @@ -4,6 +4,7 @@ import { ConstraintAccordionViewHeaderInfo } from './ConstraintAccordionViewHead import { ConstraintAccordionHeaderActions } from '../../ConstraintAccordionHeaderActions/ConstraintAccordionHeaderActions'; import { styled } from '@mui/system'; import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext'; +import { useUiFlag } from 'hooks/useUiFlag'; interface IConstraintAccordionViewHeaderProps { constraint: IConstraint; @@ -38,6 +39,7 @@ export const ConstraintAccordionViewHeader = ({ disabled, }: IConstraintAccordionViewHeaderProps) => { const { context } = useUnleashContext(); + const flagOverviewRedesign = useUiFlag('flagOverviewRedesign'); const { contextName } = constraint; const disableEdit = !context @@ -46,7 +48,9 @@ export const ConstraintAccordionViewHeader = ({ return ( - + {!flagOverviewRedesign ? ( + + ) : null} ({ - display: '-webkit-box', - WebkitLineClamp: 3, - WebkitBoxOrient: 'vertical', - overflow: 'hidden', - maxWidth: '100px', - minWidth: '100px', - marginRight: '10px', - marginTop: 'auto', - marginBottom: 'auto', - wordBreak: 'break-word', - fontSize: theme.fontSizes.smallBody, - [theme.breakpoints.down(710)]: { - textAlign: 'center', - padding: theme.spacing(1, 0), - marginRight: 'inherit', - maxWidth: 'inherit', - }, -})); +import { ConstraintItem } from 'component/common/ConstraintsList/ConstraintItem/ConstraintItem'; +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', @@ -55,49 +35,26 @@ interface ConstraintAccordionViewHeaderMetaInfoProps { export const ConstraintAccordionViewHeaderInfo = ({ constraint, - singleValue, allowExpand, expanded, - disabled = false, - maxLength = 112, //The max number of characters in the values text for NOT allowing expansion }: ConstraintAccordionViewHeaderMetaInfoProps) => { + const [expandable, setExpandable] = useState(false); + return ( - - ({ - color: disabled - ? theme.palette.text.secondary - : 'inherit', - })} - > - {constraint.contextName} - - - - - } - elseShow={ - - } + { + setExpandable(state); + allowExpand(state); + }} /> + {expandable ? ( + + {expanded ? : } + + ) : null} ); diff --git a/frontend/src/component/common/Truncator/Truncator.tsx b/frontend/src/component/common/Truncator/Truncator.tsx index 8302845f12..77d69b76f7 100644 --- a/frontend/src/component/common/Truncator/Truncator.tsx +++ b/frontend/src/component/common/Truncator/Truncator.tsx @@ -25,13 +25,14 @@ const StyledTruncatorContainer = styled(Box, { type OverridableTooltipProps = Omit; -interface ITruncatorProps extends BoxProps { +export type TruncatorProps = { lines?: number; title?: string; arrow?: boolean; tooltipProps?: OverridableTooltipProps; children: React.ReactNode; -} + onSetTruncated?: (isTruncated: boolean) => void; +} & BoxProps; export const Truncator = ({ lines = 1, @@ -40,8 +41,9 @@ export const Truncator = ({ tooltipProps, children, component = 'span', + onSetTruncated, ...props -}: ITruncatorProps) => { +}: TruncatorProps) => { const [isTruncated, setIsTruncated] = useState(false); const ref = useRef(null); @@ -50,7 +52,6 @@ export const Truncator = ({ setIsTruncated(ref.current.scrollHeight > ref.current.offsetHeight); } }; - useEffect(() => { const resizeObserver = new ResizeObserver(checkTruncation); if (ref.current) { @@ -59,6 +60,10 @@ export const Truncator = ({ return () => resizeObserver.disconnect(); }, [title, children]); + useEffect(() => { + onSetTruncated?.(isTruncated); + }, [isTruncated]); + const overridableTooltipProps: OverridableTooltipProps = { title, arrow, diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/RolloutParameter/RolloutVariants/RolloutVariants.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/RolloutParameter/RolloutVariants/RolloutVariants.tsx index d8b560b251..2f57913745 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/RolloutParameter/RolloutVariants/RolloutVariants.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/RolloutParameter/RolloutVariants/RolloutVariants.tsx @@ -29,6 +29,12 @@ const StyledPayloadHeader = styled('div')(({ theme }) => ({ marginBottom: theme.spacing(1), })); +const StyledValuesContainer = styled('div')(({ theme }) => ({ + display: 'flex', + gap: theme.spacing(0.75, 0.5), + flexWrap: 'wrap', +})); + export const RolloutVariants: FC<{ variants?: StrategyVariantSchema[]; }> = ({ variants }) => { @@ -38,34 +44,36 @@ export const RolloutVariants: FC<{ return ( - {variants.map((variant, i) => ( - - - Payload: - - {variant.payload?.value} - - ) : null - } - key={variant.name} - > - - - {variant.weight / 10}% – {variant.name} - - + + {variants.map((variant, i) => ( + + + Payload: + + {variant.payload?.value} + + ) : null } - /> - - ))} + key={variant.name} + > + + + {variant.weight / 10}% – {variant.name} + + + } + /> + + ))} + ); };