From 1db97882c2c99ce092e948c7b1c6875a19f54fcc Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Fri, 21 Feb 2025 12:20:43 +0100 Subject: [PATCH] feat: make env selector filterable (#9340) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Makes the env selector on the flag page act the same way as the env selector on the new project page or any of the filterable buttons in the new project/flag dialogs. Also slightly changes the styles of the existing dropdown lists to bring them in line with the new env selector (more padding, full-width highlights). Selector: ![image](https://github.com/user-attachments/assets/83875aa3-f9d1-4763-b8eb-75f7dc493b13) Project/flag creation: Before: ![image](https://github.com/user-attachments/assets/97926ec8-64a0-4d08-900b-0acd5709ef92) After: ![image](https://github.com/user-attachments/assets/2616615f-3382-4183-a048-5ea4defc8fb2) ## Technical notes I was a little unsure how best to share the padding/spacing styles between the search field and popover at first (as was requested by UX). The easiest way (and most compliant with how we do it today) was to define the spacing in a variable and move the relevant components into the same file. However, I actually think that using a CSS variable (e.g. `--popover-spacing`) would be "better" here, but we don't really use them much, so I've left that out for now. That said, if you agree, I'd be more than happy to use that instead 🙋🏼 --- .../ConfigButtons/ConfigButton.styles.tsx | 16 +----- .../ConfigButtons/ConfigButton.tsx | 13 ++--- .../ConfigButtons/DropdownList.styles.tsx | 4 +- .../ConfigButtons/shared.styles.tsx | 20 ++++++- .../EnvironmentVisibilityMenu.tsx | 57 ++++++++++++++----- 5 files changed, 68 insertions(+), 42 deletions(-) diff --git a/frontend/src/component/common/DialogFormTemplate/ConfigButtons/ConfigButton.styles.tsx b/frontend/src/component/common/DialogFormTemplate/ConfigButtons/ConfigButton.styles.tsx index 8e5b7df8c7..218e24e606 100644 --- a/frontend/src/component/common/DialogFormTemplate/ConfigButtons/ConfigButton.styles.tsx +++ b/frontend/src/component/common/DialogFormTemplate/ConfigButtons/ConfigButton.styles.tsx @@ -1,18 +1,4 @@ -import { Popover, styled } from '@mui/material'; - -export const StyledDropdown = styled('div')(({ theme }) => ({ - padding: theme.spacing(2), - display: 'flex', - flexDirection: 'column', - gap: theme.spacing(1), - maxHeight: '70vh', -})); - -export const StyledPopover = styled(Popover)(({ theme }) => ({ - '& .MuiPaper-root': { - borderRadius: `${theme.shape.borderRadiusMedium}px`, - }, -})); +import { styled } from '@mui/material'; export const ButtonLabel = styled('span', { shouldForwardProp: (prop) => prop !== 'labelWidth', diff --git a/frontend/src/component/common/DialogFormTemplate/ConfigButtons/ConfigButton.tsx b/frontend/src/component/common/DialogFormTemplate/ConfigButtons/ConfigButton.tsx index bd0feafe6c..fdc803b729 100644 --- a/frontend/src/component/common/DialogFormTemplate/ConfigButtons/ConfigButton.tsx +++ b/frontend/src/component/common/DialogFormTemplate/ConfigButtons/ConfigButton.tsx @@ -1,14 +1,10 @@ import { v4 as uuidv4 } from 'uuid'; import { type FC, type ReactNode, useRef, type PropsWithChildren } from 'react'; import { Box, Button } from '@mui/material'; -import { - StyledDropdown, - StyledPopover, - ButtonLabel, - StyledTooltipContent, -} from './ConfigButton.styles'; +import { ButtonLabel, StyledTooltipContent } from './ConfigButton.styles'; import { TooltipResolver } from 'component/common/TooltipResolver/TooltipResolver'; import { ScreenReaderOnly } from 'component/common/ScreenReaderOnly/ScreenReaderOnly'; +import { StyledPopover } from './shared.styles'; export type ConfigButtonProps = { button: { @@ -94,13 +90,12 @@ export const ConfigButton: FC> = ({ vertical: 'top', horizontal: 'left', }} + aria-describedby={descriptionId} >

{description}

- - {children} - + {children} ); diff --git a/frontend/src/component/common/DialogFormTemplate/ConfigButtons/DropdownList.styles.tsx b/frontend/src/component/common/DialogFormTemplate/ConfigButtons/DropdownList.styles.tsx index ca73fd0151..fe6e95e0e0 100644 --- a/frontend/src/component/common/DialogFormTemplate/ConfigButtons/DropdownList.styles.tsx +++ b/frontend/src/component/common/DialogFormTemplate/ConfigButtons/DropdownList.styles.tsx @@ -1,8 +1,10 @@ import { Checkbox, ListItem, styled } from '@mui/material'; export const StyledListItem = styled(ListItem)(({ theme }) => ({ - paddingLeft: theme.spacing(1), + paddingLeft: theme.spacing(2), + paddingBlock: theme.spacing(1), cursor: 'pointer', + '&:hover, &:focus': { backgroundColor: theme.palette.action.hover, outline: 'none', diff --git a/frontend/src/component/common/DialogFormTemplate/ConfigButtons/shared.styles.tsx b/frontend/src/component/common/DialogFormTemplate/ConfigButtons/shared.styles.tsx index 9014ff2a49..9b28913c76 100644 --- a/frontend/src/component/common/DialogFormTemplate/ConfigButtons/shared.styles.tsx +++ b/frontend/src/component/common/DialogFormTemplate/ConfigButtons/shared.styles.tsx @@ -1,4 +1,4 @@ -import { TextField, styled } from '@mui/material'; +import { Popover, TextField, styled } from '@mui/material'; const visuallyHiddenStyles = { border: 0, @@ -12,11 +12,27 @@ const visuallyHiddenStyles = { whiteSpace: 'nowrap', }; +const dropdownPadding = 1.5; + +export const StyledPopover = styled(Popover)(({ theme }) => ({ + '& .MuiPaper-root': { + borderRadius: `${theme.shape.borderRadiusMedium}px`, + paddingInline: 0, + paddingTop: theme.spacing(dropdownPadding), + display: 'flex', + flexDirection: 'column', + + gap: theme.spacing(1), + maxHeight: '70vh', + }, +})); + export const StyledDropdownSearch = styled(TextField, { shouldForwardProp: (prop) => prop !== 'hideLabel', })<{ hideLabel?: boolean }>(({ theme, hideLabel }) => ({ + paddingInline: theme.spacing(dropdownPadding), '& .MuiInputBase-root': { - padding: theme.spacing(0, 1.5), + paddingInline: theme.spacing(1.5), borderRadius: `${theme.shape.borderRadiusMedium}px`, }, '& .MuiInputBase-input': { diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewMetaData/EnvironmentVisibilityMenu/EnvironmentVisibilityMenu.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewMetaData/EnvironmentVisibilityMenu/EnvironmentVisibilityMenu.tsx index 27f6a2d9bf..e166e330aa 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewMetaData/EnvironmentVisibilityMenu/EnvironmentVisibilityMenu.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewMetaData/EnvironmentVisibilityMenu/EnvironmentVisibilityMenu.tsx @@ -1,8 +1,10 @@ -import { Button, Checkbox, Menu, MenuItem, styled } from '@mui/material'; +import { Button, styled } from '@mui/material'; import { useState, type FC } from 'react'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import ExpandLessIcon from '@mui/icons-material/ExpandLess'; +import { DropdownList } from 'component/common/DialogFormTemplate/ConfigButtons/DropdownList'; +import { StyledPopover } from 'component/common/DialogFormTemplate/ConfigButtons/shared.styles'; type EnvironmentVisibilityMenuProps = { environments: Array<{ name: string }>; @@ -33,6 +35,18 @@ export const EnvironmentVisibilityMenu: FC = ({ setAnchorEl(null); }; + const allEnvironments = environments.map((environment) => environment.name); + + const selectedOptions = new Set( + allEnvironments.filter( + (environment) => !hiddenEnvironments.includes(environment), + ), + ); + + const handleToggle = (value: string) => { + onChange(value); + }; + return ( - - {environments.map(({ name }) => ( - onChange(name)}> - onChange(name)} - checked={!hiddenEnvironments?.includes(name)} - /> - {name} - - ))} - + ({ + label: env, + value: env, + }))} + search={{ + label: 'Filter environments', + placeholder: 'Filter environments', + }} + /> + ); };