From 07046a52a8d6c2073a43dced8397a2d5b2b2ae43 Mon Sep 17 00:00:00 2001 From: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com> Date: Thu, 20 Mar 2025 13:26:32 +0100 Subject: [PATCH 1/5] refactor: variant colors --- frontend/src/themes/colors.ts | 37 +++++++++++++++++++++---------- frontend/src/themes/dark-theme.ts | 2 +- frontend/src/themes/theme.ts | 2 +- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/frontend/src/themes/colors.ts b/frontend/src/themes/colors.ts index 2b3b5302d5..2f439a8b1b 100644 --- a/frontend/src/themes/colors.ts +++ b/frontend/src/themes/colors.ts @@ -95,18 +95,31 @@ export const colors = { 600: '#1f3751', 500: '#0e2840', }, - variants: [ - '#BEBBF3', - '#FFC46F', - '#B0D182', - '#96D2FA', - '#F7E3AE', - '#7FBAA9', - '#D3B9DB', - '#FBC5A0', - '#DDE7B5', - '#9EC4E3', - '#F8B6CC', + lightVariants: [ + '#d2d1f5', + '#f8d18f', + '#c1d699', + '#b7dbf9', + '#f7ecc8', + '#9ac1b5', + '#dacbe2', + '#f6d6bb', + '#e7edcb', + '#b7cfe7', + '#f3d0dc', + ] as string[], + darkVariants: [ + '#3f3d89', + '#6f4f1d', + '#3a3f2f', + '#325e87', + '#8e7737', + '#2a2a2a', + '#585659', + '#8a552a', + '#686e4b', + '#3e4f60', + '#8e3a53', ] as string[], chartSeries: [ '#816DD3', diff --git a/frontend/src/themes/dark-theme.ts b/frontend/src/themes/dark-theme.ts index 4e2a1e2c20..2620388975 100644 --- a/frontend/src/themes/dark-theme.ts +++ b/frontend/src/themes/dark-theme.ts @@ -222,7 +222,7 @@ const theme = { // A400: '#A6000E', // A700: '#A6000E', }, - variants: colors.variants, + variants: colors.darkVariants, /** * Dashboard and charts diff --git a/frontend/src/themes/theme.ts b/frontend/src/themes/theme.ts index 4e22eac0b5..1e31aa06cd 100644 --- a/frontend/src/themes/theme.ts +++ b/frontend/src/themes/theme.ts @@ -281,7 +281,7 @@ const theme = { // A400: '#A6000E', // A700: '#A6000E', }, - variants: colors.variants, + variants: colors.lightVariants, /** * Dashboard and charts From 83a8cb816a6ffa0cc4302dc7b8a5e3ef30573ebd Mon Sep 17 00:00:00 2001 From: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com> Date: Thu, 20 Mar 2025 13:32:49 +0100 Subject: [PATCH 2/5] refactor: simplify new rollout variant --- .../RolloutVariants/RolloutVariants.tsx | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) 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 2f57913745..b4389b48de 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 @@ -6,22 +6,14 @@ import type { StrategyVariantSchema } from 'openapi'; import type { FC } from 'react'; const StyledVariantChip = styled(StrategyEvaluationChip)<{ order: number }>( - ({ theme, order }) => { - const variantColor = - theme.palette.variants[order % theme.palette.variants.length]; - - return { - borderRadius: theme.shape.borderRadiusExtraLarge, - border: 'none', - color: theme.palette.text.primary, - background: - // TODO: adjust theme.palette.variants - theme.mode === 'dark' - ? `hsl(from ${variantColor} h calc(s - 30) calc(l - 45))` - : `hsl(from ${variantColor} h s calc(l + 5))`, - fontWeight: theme.typography.fontWeightRegular, - }; - }, + ({ theme, order }) => ({ + borderRadius: theme.shape.borderRadiusExtraLarge, + border: 'none', + color: theme.palette.text.primary, + background: + theme.palette.variants[order % theme.palette.variants.length], + fontWeight: theme.typography.fontWeightRegular, + }), ); const StyledPayloadHeader = styled('div')(({ theme }) => ({ From 9b19d519ed93293b1939c3f110b765ffa5e77c91 Mon Sep 17 00:00:00 2001 From: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com> Date: Thu, 20 Mar 2025 14:09:19 +0100 Subject: [PATCH 3/5] adjust colors --- frontend/src/themes/colors.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/themes/colors.ts b/frontend/src/themes/colors.ts index 2f439a8b1b..898e8bb42c 100644 --- a/frontend/src/themes/colors.ts +++ b/frontend/src/themes/colors.ts @@ -113,13 +113,13 @@ export const colors = { '#6f4f1d', '#3a3f2f', '#325e87', - '#8e7737', - '#2a2a2a', + '#68620e', + '#8e3a53', '#585659', '#8a552a', '#686e4b', '#3e4f60', - '#8e3a53', + '#343444', ] as string[], chartSeries: [ '#816DD3', From 6129565828a7726340f03a4c957b34eb2657191b Mon Sep 17 00:00:00 2001 From: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com> Date: Thu, 20 Mar 2025 19:03:28 +0100 Subject: [PATCH 4/5] refactor constraint values --- .../ConstraintItemHeader.tsx | 70 +++++++++++++------ .../StrategyEvaluationItem.tsx | 45 +++--------- .../ConstraintsList/ValuesList/ValuesList.tsx | 65 +++++++++++++++++ .../common/SegmentItem/SegmentItem.tsx | 3 +- .../hooks/useCustomStrategyParameters.tsx | 6 +- .../hooks/useStrategyParameters.tsx | 3 +- frontend/src/utils/formatConstraintValue.ts | 4 +- 7 files changed, 131 insertions(+), 65 deletions(-) create mode 100644 frontend/src/component/common/ConstraintsList/ValuesList/ValuesList.tsx diff --git a/frontend/src/component/common/ConstraintsList/ConstraintItemHeader/ConstraintItemHeader.tsx b/frontend/src/component/common/ConstraintsList/ConstraintItemHeader/ConstraintItemHeader.tsx index bcaf83b751..6e31653f00 100644 --- a/frontend/src/component/common/ConstraintsList/ConstraintItemHeader/ConstraintItemHeader.tsx +++ b/frontend/src/component/common/ConstraintsList/ConstraintItemHeader/ConstraintItemHeader.tsx @@ -1,12 +1,14 @@ -import type { FC } from 'react'; -import { - StrategyEvaluationItem, - type StrategyEvaluationItemProps, -} from '../StrategyEvaluationItem/StrategyEvaluationItem'; +import { useMemo, type ComponentProps, type FC } from 'react'; +import { StrategyEvaluationItem } from '../StrategyEvaluationItem/StrategyEvaluationItem'; import type { ConstraintSchema } from 'openapi'; import { formatOperatorDescription } from 'component/common/ConstraintAccordion/ConstraintOperator/formatOperatorDescription'; import { StrategyEvaluationChip } from '../StrategyEvaluationChip/StrategyEvaluationChip'; import { styled, Tooltip } from '@mui/material'; +import { Truncator } from 'component/common/Truncator/Truncator'; +import { ValuesList } from '../ValuesList/ValuesList'; +import { useLocationSettings } from 'hooks/useLocationSettings'; +import { formatConstraintValue } from 'utils/formatConstraintValue'; +import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext'; const Inverted: FC = () => ( @@ -32,31 +34,55 @@ const StyledOperatorGroup = styled('div')(({ theme }) => ({ gap: theme.spacing(0.5), })); +const StyledConstraintName = styled('div')(({ theme }) => ({ + maxWidth: '150px', + paddingRight: theme.spacing(0.5), + overflow: 'hidden', +})); + export const ConstraintItemHeader: FC< - ConstraintSchema & Pick -> = ({ - caseInsensitive, - contextName, - inverted, - operator, - value, - values, - onSetTruncated, -}) => { - const items = value ? [value, ...(values || [])] : values || []; + ConstraintSchema & Pick, 'onSetTruncated'> +> = ({ onSetTruncated, ...constraint }) => { + const { caseInsensitive, contextName, inverted, operator, value, values } = + constraint; + const { context } = useUnleashContext(); + const { locationSettings } = useLocationSettings(); + const items = value + ? [ + formatConstraintValue(constraint, locationSettings) || '', + ...(values || []), + ] + : values || []; + + const tooltips = useMemo( + () => + // FIXME: tooltips + Object.fromEntries( + values?.map((value) => [ + value, + context.find(({ name }) => name === value)?.description, + ]) || [], + ), + [context, values], + ); return ( - - {contextName} + + + + {contextName} + + {inverted ? : null} {caseInsensitive ? : null} + ); }; diff --git a/frontend/src/component/common/ConstraintsList/StrategyEvaluationItem/StrategyEvaluationItem.tsx b/frontend/src/component/common/ConstraintsList/StrategyEvaluationItem/StrategyEvaluationItem.tsx index 239fe69968..2fc8948c9a 100644 --- a/frontend/src/component/common/ConstraintsList/StrategyEvaluationItem/StrategyEvaluationItem.tsx +++ b/frontend/src/component/common/ConstraintsList/StrategyEvaluationItem/StrategyEvaluationItem.tsx @@ -1,16 +1,11 @@ -import { styled } from '@mui/material'; -import { - Truncator, - type TruncatorProps, -} from 'component/common/Truncator/Truncator'; -import { disabledStrategyClassName } from 'component/common/StrategyItemContainer/disabled-strategy-utils'; import type { FC, ReactNode } from 'react'; +import { styled } from '@mui/material'; +import { disabledStrategyClassName } from 'component/common/StrategyItemContainer/disabled-strategy-utils'; export type StrategyEvaluationItemProps = { type?: ReactNode; children?: ReactNode; - values?: string[]; -} & Pick; +}; const StyledContainer = styled('div')(({ theme }) => ({ display: 'flex', @@ -38,35 +33,17 @@ const StyledType = styled('span')(({ theme }) => ({ color: theme.palette.text.secondary, width: theme.spacing(10), })); - /** * Abstract building block for a list of constraints, segments and other items inside a strategy */ export const StrategyEvaluationItem: FC = ({ type, children, - values, - onSetTruncated, -}) => ( - - {type} - - {children} - {values && values?.length === 1 ? ( - onSetTruncated?.(false)} - > - {values[0]} - - ) : null} - {values && values?.length > 1 ? ( - - {values.join(', ')} - - ) : null} - - -); +}) => { + return ( + + {type} + {children} + + ); +}; diff --git a/frontend/src/component/common/ConstraintsList/ValuesList/ValuesList.tsx b/frontend/src/component/common/ConstraintsList/ValuesList/ValuesList.tsx new file mode 100644 index 0000000000..d1053c8d88 --- /dev/null +++ b/frontend/src/component/common/ConstraintsList/ValuesList/ValuesList.tsx @@ -0,0 +1,65 @@ +import type { FC } from 'react'; +import { styled, Tooltip } from '@mui/material'; +import { + Truncator, + type TruncatorProps, +} from 'component/common/Truncator/Truncator'; + +export type ValuesListProps = { + values?: string[]; + tooltips?: Record; +} & Pick; + +const StyledValuesContainer = styled('div')({ + flex: '1 1 0', +}); + +const StyledValueItem = styled('span')(({ theme }) => ({ + padding: theme.spacing(0.25), + display: 'inline-block', + span: { + background: theme.palette.background.elevation2, + borderRadius: theme.shape.borderRadiusLarge, + display: 'inline-block', + padding: theme.spacing(0.25, 1), + }, +})); + +const StyledSingleValue = styled('div')(({ theme }) => ({ + padding: theme.spacing(0.25, 1), + background: theme.palette.background.elevation2, + borderRadius: theme.shape.borderRadiusLarge, +})); + +export const ValuesList: FC = ({ + values, + tooltips, + onSetTruncated, +}) => ( + + {values && values?.length === 1 ? ( + + onSetTruncated?.(false)} + > + {values[0]} + + + ) : null} + {values && values?.length > 1 ? ( + + {values.map((value) => ( + + + {value} + {tooltips?.[value]} + + + ))} + + ) : null} + +); diff --git a/frontend/src/component/common/SegmentItem/SegmentItem.tsx b/frontend/src/component/common/SegmentItem/SegmentItem.tsx index 610b422fb7..33f2c2666b 100644 --- a/frontend/src/component/common/SegmentItem/SegmentItem.tsx +++ b/frontend/src/component/common/SegmentItem/SegmentItem.tsx @@ -45,8 +45,7 @@ const StyledAccordionSummary = styled(AccordionSummary)(({ theme }) => ({ })); const StyledAccordionDetails = styled(AccordionDetails)(({ theme }) => ({ - borderTop: `1px dashed ${theme.palette.divider}`, - padding: theme.spacing(1.5, 3, 2.5), + padding: theme.spacing(0.5, 3, 2.5), })); const StyledLink = styled(Link)({ diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/hooks/useCustomStrategyParameters.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/hooks/useCustomStrategyParameters.tsx index 2d7fd503a2..7888ec9ca2 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/hooks/useCustomStrategyParameters.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/hooks/useCustomStrategyParameters.tsx @@ -51,7 +51,7 @@ export const useCustomStrategyParameters = ( {values.length === 1 ? 'has 1 item:' @@ -85,7 +85,7 @@ export const useCustomStrategyParameters = ( {value === '' ? 'is an empty string' : 'is set to'} @@ -98,7 +98,7 @@ export const useCustomStrategyParameters = ( is a number set to diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/hooks/useStrategyParameters.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/hooks/useStrategyParameters.tsx index f867c04a4f..9dd93f8a4a 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/hooks/useStrategyParameters.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/hooks/useStrategyParameters.tsx @@ -1,5 +1,4 @@ import { useMemo } from 'react'; -import { parseParameterStrings } from 'utils/parseParameter'; import { StrategyEvaluationItem } from 'component/common/ConstraintsList/StrategyEvaluationItem/StrategyEvaluationItem'; import type { FeatureStrategySchema } from 'openapi'; import { RolloutParameter } from '../RolloutParameter/RolloutParameter'; @@ -39,7 +38,7 @@ export const useStrategyParameters = ( ); } diff --git a/frontend/src/utils/formatConstraintValue.ts b/frontend/src/utils/formatConstraintValue.ts index b7a73748a7..c4a098716b 100644 --- a/frontend/src/utils/formatConstraintValue.ts +++ b/frontend/src/utils/formatConstraintValue.ts @@ -1,10 +1,10 @@ -import type { IConstraint } from 'interfaces/strategy'; import { formatDateYMDHMS } from 'utils/formatDate'; import type { ILocationSettings } from 'hooks/useLocationSettings'; import { CURRENT_TIME_CONTEXT_FIELD } from 'utils/operatorsForContext'; +import type { ConstraintSchema } from 'openapi'; export const formatConstraintValue = ( - constraint: IConstraint, + constraint: Pick, locationSettings: ILocationSettings, ): string | undefined => { if ( From 7c472536aa9a9f60b1b7410d13a54ecc0082ca42 Mon Sep 17 00:00:00 2001 From: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com> Date: Fri, 21 Mar 2025 12:58:35 +0100 Subject: [PATCH 5/5] constraint values with tooltips --- .../ConstraintItemHeader.tsx | 17 +--- .../hooks/useConstraintTooltips.test.ts | 99 +++++++++++++++++++ .../hooks/useConstraintTooltips.ts | 27 +++++ .../ConstraintsList/ValuesList/ValuesList.tsx | 7 +- .../hooks/useCustomStrategyParameters.tsx | 24 ++--- .../hooks/useStrategyParameters.tsx | 10 +- 6 files changed, 147 insertions(+), 37 deletions(-) create mode 100644 frontend/src/component/common/ConstraintsList/ConstraintItemHeader/hooks/useConstraintTooltips.test.ts create mode 100644 frontend/src/component/common/ConstraintsList/ConstraintItemHeader/hooks/useConstraintTooltips.ts diff --git a/frontend/src/component/common/ConstraintsList/ConstraintItemHeader/ConstraintItemHeader.tsx b/frontend/src/component/common/ConstraintsList/ConstraintItemHeader/ConstraintItemHeader.tsx index 6e31653f00..72afef6cae 100644 --- a/frontend/src/component/common/ConstraintsList/ConstraintItemHeader/ConstraintItemHeader.tsx +++ b/frontend/src/component/common/ConstraintsList/ConstraintItemHeader/ConstraintItemHeader.tsx @@ -1,4 +1,4 @@ -import { useMemo, type ComponentProps, type FC } from 'react'; +import type { ComponentProps, FC } from 'react'; import { StrategyEvaluationItem } from '../StrategyEvaluationItem/StrategyEvaluationItem'; import type { ConstraintSchema } from 'openapi'; import { formatOperatorDescription } from 'component/common/ConstraintAccordion/ConstraintOperator/formatOperatorDescription'; @@ -8,7 +8,7 @@ import { Truncator } from 'component/common/Truncator/Truncator'; import { ValuesList } from '../ValuesList/ValuesList'; import { useLocationSettings } from 'hooks/useLocationSettings'; import { formatConstraintValue } from 'utils/formatConstraintValue'; -import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext'; +import { useConstraintTooltips } from './hooks/useConstraintTooltips'; const Inverted: FC = () => ( @@ -45,7 +45,6 @@ export const ConstraintItemHeader: FC< > = ({ onSetTruncated, ...constraint }) => { const { caseInsensitive, contextName, inverted, operator, value, values } = constraint; - const { context } = useUnleashContext(); const { locationSettings } = useLocationSettings(); const items = value ? [ @@ -54,17 +53,7 @@ export const ConstraintItemHeader: FC< ] : values || []; - const tooltips = useMemo( - () => - // FIXME: tooltips - Object.fromEntries( - values?.map((value) => [ - value, - context.find(({ name }) => name === value)?.description, - ]) || [], - ), - [context, values], - ); + const tooltips = useConstraintTooltips(contextName, values || []); return ( diff --git a/frontend/src/component/common/ConstraintsList/ConstraintItemHeader/hooks/useConstraintTooltips.test.ts b/frontend/src/component/common/ConstraintsList/ConstraintItemHeader/hooks/useConstraintTooltips.test.ts new file mode 100644 index 0000000000..76fb8a6c69 --- /dev/null +++ b/frontend/src/component/common/ConstraintsList/ConstraintItemHeader/hooks/useConstraintTooltips.test.ts @@ -0,0 +1,99 @@ +import { vi } from 'vitest'; +import { renderHook } from '@testing-library/react'; +import { useConstraintTooltips } from './useConstraintTooltips'; +import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext'; + +vi.mock('hooks/api/getters/useUnleashContext/useUnleashContext', () => ({ + default: vi.fn(), +})); + +describe('useConstraintTooltips', () => { + beforeEach(() => { + vi.resetAllMocks(); + }); + + it('returns tooltip mapping for legal values with descriptions', () => { + ( + useUnleashContext as unknown as ReturnType + ).mockReturnValue({ + context: [ + { + name: 'contextA', + description: 'Test context A', + createdAt: '2021-01-01', + sortOrder: 1, + stickiness: false, + legalValues: [ + { value: 'value1', description: 'Tooltip 1' }, + { value: 'value2', description: 'Tooltip 2' }, + { value: 'value3' }, // No description provided + ], + }, + ], + }); + + const { result } = renderHook(() => + useConstraintTooltips('contextA', [ + 'value1', + 'value2', + 'value3', + 'nonExisting', + ]), + ); + + expect(result.current).toEqual({ + value1: 'Tooltip 1', + value2: 'Tooltip 2', + }); + }); + + it('returns an empty object when the context is not found', () => { + ( + useUnleashContext as unknown as ReturnType + ).mockReturnValue({ + context: [ + { + name: 'otherContext', + description: 'Other context', + createdAt: '2021-01-01', + sortOrder: 1, + stickiness: false, + legalValues: [ + { value: 'value1', description: 'Tooltip 1' }, + ], + }, + ], + }); + + const { result } = renderHook(() => + useConstraintTooltips('contextA', ['value1']), + ); + + expect(result.current).toEqual({}); + }); + + it('returns an empty object when no values are provided', () => { + ( + useUnleashContext as unknown as ReturnType + ).mockReturnValue({ + context: [ + { + name: 'contextA', + description: 'Test context A', + createdAt: '2021-01-01', + sortOrder: 1, + stickiness: false, + legalValues: [ + { value: 'value1', description: 'Tooltip 1' }, + ], + }, + ], + }); + + const { result } = renderHook(() => + useConstraintTooltips('contextA', []), + ); + + expect(result.current).toEqual({}); + }); +}); diff --git a/frontend/src/component/common/ConstraintsList/ConstraintItemHeader/hooks/useConstraintTooltips.ts b/frontend/src/component/common/ConstraintsList/ConstraintItemHeader/hooks/useConstraintTooltips.ts new file mode 100644 index 0000000000..1e0b7ca774 --- /dev/null +++ b/frontend/src/component/common/ConstraintsList/ConstraintItemHeader/hooks/useConstraintTooltips.ts @@ -0,0 +1,27 @@ +import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext'; +import { useMemo } from 'react'; + +export const useConstraintTooltips = ( + contextName: string, + values: string[], +) => { + const { context } = useUnleashContext(); + const contextDefinition = useMemo( + () => context.find(({ name }) => name === contextName), + [contextName, context], + ); + return useMemo>( + () => + Object.fromEntries( + values + ?.map((item) => [ + item, + contextDefinition?.legalValues?.find( + ({ value }) => value === item, + )?.description, + ]) + .filter(([_, tooltip]) => !!tooltip) || [], + ), + [context, values], + ); +}; diff --git a/frontend/src/component/common/ConstraintsList/ValuesList/ValuesList.tsx b/frontend/src/component/common/ConstraintsList/ValuesList/ValuesList.tsx index d1053c8d88..394cd1302d 100644 --- a/frontend/src/component/common/ConstraintsList/ValuesList/ValuesList.tsx +++ b/frontend/src/component/common/ConstraintsList/ValuesList/ValuesList.tsx @@ -45,17 +45,18 @@ export const ValuesList: FC = ({ lines={2} onSetTruncated={() => onSetTruncated?.(false)} > - {values[0]} + + {values[0]} + ) : null} {values && values?.length > 1 ? ( {values.map((value) => ( - + {value} - {tooltips?.[value]} ))} diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/hooks/useCustomStrategyParameters.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/hooks/useCustomStrategyParameters.tsx index 7888ec9ca2..ba5bd6de5c 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/hooks/useCustomStrategyParameters.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/hooks/useCustomStrategyParameters.tsx @@ -13,6 +13,7 @@ import type { StrategySchemaParametersItem, } from 'openapi'; import type { IFeatureStrategyPayload } from 'interfaces/strategy'; +import { ValuesList } from 'component/common/ConstraintsList/ValuesList/ValuesList'; export const useCustomStrategyParameters = ( strategy: Pick< @@ -48,14 +49,11 @@ export const useCustomStrategyParameters = ( } return ( - + {values.length === 1 ? 'has 1 item:' : `has ${values.length} items:`} + ); } @@ -82,12 +80,11 @@ export const useCustomStrategyParameters = ( const value = parseParameterString(parameters[name]); return ( - + {value === '' ? 'is an empty string' : 'is set to'} + ); } @@ -95,12 +92,9 @@ export const useCustomStrategyParameters = ( case 'number': { const value = parseParameterNumber(parameters[name]); return ( - + is a number set to + ); } diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/hooks/useStrategyParameters.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/hooks/useStrategyParameters.tsx index 9dd93f8a4a..ba081d8cd8 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/hooks/useStrategyParameters.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/hooks/useStrategyParameters.tsx @@ -2,6 +2,8 @@ import { useMemo } from 'react'; import { StrategyEvaluationItem } from 'component/common/ConstraintsList/StrategyEvaluationItem/StrategyEvaluationItem'; import type { FeatureStrategySchema } from 'openapi'; import { RolloutParameter } from '../RolloutParameter/RolloutParameter'; +import { ValuesList } from 'component/common/ConstraintsList/ValuesList/ValuesList'; +import { parseParameterStrings } from 'utils/parseParameter'; export const useStrategyParameters = ( strategy: Partial< @@ -35,11 +37,9 @@ export const useStrategyParameters = ( if (['userids', 'hostnames', 'ips'].includes(type)) { return ( - + + + ); }