From 3d9f5581d5c7c3a305516da2b1af750e23719e38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20G=C3=B3is?= Date: Wed, 24 Sep 2025 13:06:49 +0100 Subject: [PATCH] chore: limit total custom strategies displayed (#10688) https://linear.app/unleash/issue/2-3897/limit-custom-strategies-like-were-doing-with-release-templates Limits total custom strategies displayed, like we're doing for release templates, in the new "add strategy" modal. Added a more generic logic to `FeatureStrategyMenuCardsSection.tsx` so we can reuse it for both. We can also do it for other sections in the modal, but that feels like a premature optimization. These 2 categories are the ones that are user owned, and can have many items. --- .../FeatureStrategyMenuCards.tsx | 11 +++- ...atureStrategyMenuCardsReleaseTemplates.tsx | 37 ++++-------- .../FeatureStrategyMenuCardsSection.tsx | 57 ++++++++++++++----- 3 files changed, 63 insertions(+), 42 deletions(-) diff --git a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyMenu/FeatureStrategyMenuCards/FeatureStrategyMenuCards.tsx b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyMenu/FeatureStrategyMenuCards/FeatureStrategyMenuCards.tsx index ca7e54dc64..2847355dc7 100644 --- a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyMenu/FeatureStrategyMenuCards/FeatureStrategyMenuCards.tsx +++ b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyMenu/FeatureStrategyMenuCards/FeatureStrategyMenuCards.tsx @@ -38,6 +38,8 @@ const FILTERS = [ export type StrategyFilterValue = (typeof FILTERS)[number]['value']; +const CUSTOM_STRATEGY_DISPLAY_LIMIT = 5; + const StyledContainer = styled(Box)(() => ({ width: '100%', display: 'flex', @@ -118,6 +120,9 @@ export const FeatureStrategyMenuCards = ({ (strategy) => strategy.editable, ); + const customStrategyDisplayLimit = + filter === 'custom' ? 0 : CUSTOM_STRATEGY_DISPLAY_LIMIT; + const availableFilters = useMemo( () => FILTERS.filter(({ value }) => { @@ -281,7 +286,11 @@ export const FeatureStrategyMenuCards = ({ )} {shouldRender('custom') && customStrategies.length > 0 && ( - + setFilter('custom')} + > {customStrategies.map(renderStrategy)} )} diff --git a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyMenu/FeatureStrategyMenuCards/FeatureStrategyMenuCardsReleaseTemplates.tsx b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyMenu/FeatureStrategyMenuCards/FeatureStrategyMenuCardsReleaseTemplates.tsx index 375557ce97..d9b1371c55 100644 --- a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyMenu/FeatureStrategyMenuCards/FeatureStrategyMenuCardsReleaseTemplates.tsx +++ b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyMenu/FeatureStrategyMenuCards/FeatureStrategyMenuCardsReleaseTemplates.tsx @@ -2,7 +2,7 @@ import { useReleasePlanTemplates } from 'hooks/api/getters/useReleasePlanTemplat import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import { ReactComponent as ReleaseTemplateIcon } from 'assets/img/releaseTemplates.svg'; import type { IReleasePlanTemplate } from 'interfaces/releasePlans.ts'; -import { Box, Button, styled } from '@mui/material'; +import { Box, styled } from '@mui/material'; import type { StrategyFilterValue } from './FeatureStrategyMenuCards.tsx'; import type { Dispatch, SetStateAction } from 'react'; import { Link as RouterLink } from 'react-router-dom'; @@ -74,16 +74,6 @@ const StyledNoTemplatesDescription = styled('p')(({ theme }) => ({ color: theme.palette.text.secondary, })); -const StyledViewMoreButton = styled(Button)(({ theme }) => ({ - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - height: theme.spacing(10), - padding: theme.spacing(2), - border: `1px solid ${theme.palette.divider}`, - borderRadius: theme.spacing(1), -})); - const StyledLink = styled(RouterLink)({ textDecoration: 'none', '&:hover': { @@ -113,10 +103,9 @@ export const FeatureStrategyMenuCardsReleaseTemplates = ({ const isFiltered = filter === 'releaseTemplates'; const shouldShowHeader = !isFiltered || templates.length > 0; - - const slicedTemplates = isFiltered - ? templates - : templates.slice(0, RELEASE_TEMPLATE_DISPLAY_LIMIT); + const releaseTemplatesDisplayLimit = isFiltered + ? 0 + : RELEASE_TEMPLATE_DISPLAY_LIMIT; return ( @@ -153,8 +142,12 @@ export const FeatureStrategyMenuCardsReleaseTemplates = ({ ) : ( - - {slicedTemplates.map((template) => ( + setFilter('releaseTemplates')} + viewMoreLabel='View more templates' + > + {templates.map((template) => ( ))} - {slicedTemplates.length < templates.length && - templates.length > RELEASE_TEMPLATE_DISPLAY_LIMIT && ( - setFilter('releaseTemplates')} - > - View more templates - - )} )} diff --git a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyMenu/FeatureStrategyMenuCards/FeatureStrategyMenuCardsSection.tsx b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyMenu/FeatureStrategyMenuCards/FeatureStrategyMenuCardsSection.tsx index 654d10df50..771179cbf1 100644 --- a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyMenu/FeatureStrategyMenuCards/FeatureStrategyMenuCardsSection.tsx +++ b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyMenu/FeatureStrategyMenuCards/FeatureStrategyMenuCardsSection.tsx @@ -1,4 +1,4 @@ -import { Box, styled } from '@mui/material'; +import { Box, Button, styled } from '@mui/material'; import type { ReactNode } from 'react'; export const StyledStrategyModalSectionHeader = styled(Box)(({ theme }) => ({ @@ -17,23 +17,52 @@ const StyledStrategyModalSectionGrid = styled(Box)(({ theme }) => ({ width: '100%', })); +const StyledViewMoreButton = styled(Button)(({ theme }) => ({ + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + height: theme.spacing(10), + padding: theme.spacing(2), + border: `1px solid ${theme.palette.divider}`, + borderRadius: theme.spacing(1), +})); + interface IFeatureStrategyMenuCardsSectionProps { title?: string; - children: ReactNode; + limit?: number; + viewMore?: () => void; + viewMoreLabel?: string; + children: ReactNode[]; } export const FeatureStrategyMenuCardsSection = ({ title, + limit, + viewMore, + viewMoreLabel = 'View more', children, -}: IFeatureStrategyMenuCardsSectionProps) => ( - - {title && ( - - {title} - - )} - - {children} - - -); +}: IFeatureStrategyMenuCardsSectionProps) => { + const limitedChildren = limit ? children.slice(0, limit) : children; + + return ( + + {title && ( + + {title} + + )} + + {limitedChildren} + {viewMore && limitedChildren.length < children.length && ( + + {viewMoreLabel} + + )} + + + ); +};