From 6025ad0f0d54af25a36c5e59113c265d0678afe4 Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Mon, 25 Mar 2024 10:23:22 +0100 Subject: [PATCH] fix: add forwardRef to ProjectSelect component (#6674) Make the tooltip for project selection in the playground work properly again. Right now, it doesn't work due to an error in react refs. Because we wrap this in a tooltip in the Playground, we need to forward the ref to the underlying component. This follows the steps outlined in https://mui.com/material-ui/guides/composition/#caveat-with-refs --- .../common/ProjectSelect/ProjectSelect.tsx | 152 +++++++++--------- 1 file changed, 80 insertions(+), 72 deletions(-) diff --git a/frontend/src/component/common/ProjectSelect/ProjectSelect.tsx b/frontend/src/component/common/ProjectSelect/ProjectSelect.tsx index ecd3806df1b..9cba5b67620 100644 --- a/frontend/src/component/common/ProjectSelect/ProjectSelect.tsx +++ b/frontend/src/component/common/ProjectSelect/ProjectSelect.tsx @@ -1,4 +1,10 @@ -import type { ComponentProps, Dispatch, SetStateAction, VFC } from 'react'; +import { + forwardRef, + type ComponentProps, + type Dispatch, + type SetStateAction, + type VFC, +} from 'react'; import { Autocomplete, type SxProps, TextField } from '@mui/material'; import { renderOption } from 'component/playground/Playground/PlaygroundForm/renderOption'; import useProjects from 'hooks/api/getters/useProjects/useProjects'; @@ -30,85 +36,87 @@ function findAllIndexes(arr: string[], name: string): number[] { return indexes; } -export const ProjectSelect: VFC = ({ - selectedProjects, - onChange, - dataTestId, - sx, - disabled, -}) => { - const { projects: availableProjects } = useProjects(); +export const ProjectSelect: VFC = forwardRef( + ( + { selectedProjects, onChange, dataTestId, sx, disabled, ...props }, + ref, + ) => { + const { projects: availableProjects } = useProjects(); - const projectNames = availableProjects.map(({ name }) => name); + const projectNames = availableProjects.map(({ name }) => name); - const projectsOptions = [ - allOption, - ...availableProjects.map(({ name, id }) => { - const indexes = findAllIndexes(projectNames, name); - const isDuplicate = indexes.length > 1; + const projectsOptions = [ + allOption, + ...availableProjects.map(({ name, id }) => { + const indexes = findAllIndexes(projectNames, name); + const isDuplicate = indexes.length > 1; - return { - label: isDuplicate ? `${name} - (${id})` : name, - id, - }; - }), - ]; + return { + label: isDuplicate ? `${name} - (${id})` : name, + id, + }; + }), + ]; - const isAllProjects = - selectedProjects && - (selectedProjects.length === 0 || - (selectedProjects.length === 1 && selectedProjects[0] === '*')); + const isAllProjects = + selectedProjects && + (selectedProjects.length === 0 || + (selectedProjects.length === 1 && selectedProjects[0] === '*')); - const onProjectsChange: ComponentProps['onChange'] = ( - event, - value, - reason, - ) => { - const newProjects = value as IOption | IOption[]; - if (reason === 'clear' || newProjects === null) { - return onChange([allOption.id]); - } - if (Array.isArray(newProjects)) { - if (newProjects.length === 0) { + const onProjectsChange: ComponentProps< + typeof Autocomplete + >['onChange'] = (event, value, reason) => { + const newProjects = value as IOption | IOption[]; + if (reason === 'clear' || newProjects === null) { return onChange([allOption.id]); } - if ( - newProjects.find(({ id }) => id === allOption.id) !== undefined - ) { + if (Array.isArray(newProjects)) { + if (newProjects.length === 0) { + return onChange([allOption.id]); + } + if ( + newProjects.find(({ id }) => id === allOption.id) !== + undefined + ) { + return onChange([allOption.id]); + } + return onChange(newProjects.map(({ id }) => id)); + } + if (newProjects.id === allOption.id) { return onChange([allOption.id]); } - return onChange(newProjects.map(({ id }) => id)); - } - if (newProjects.id === allOption.id) { - return onChange([allOption.id]); - } - return onChange([newProjects.id]); - }; + return onChange([newProjects.id]); + }; - return ( - } - renderOption={renderOption} - getOptionLabel={({ label }) => label} - disableCloseOnSelect - size='small' - disabled={disabled} - value={ - isAllProjects - ? allOption - : projectsOptions.filter(({ id }) => - selectedProjects.includes(id), - ) - } - onChange={onProjectsChange} - data-testid={dataTestId ? dataTestId : 'PROJECT_SELECT'} - /> - ); -}; + return ( + ( + + )} + renderOption={renderOption} + getOptionLabel={({ label }) => label} + disableCloseOnSelect + size='small' + disabled={disabled} + value={ + isAllProjects + ? allOption + : projectsOptions.filter(({ id }) => + selectedProjects.includes(id), + ) + } + onChange={onProjectsChange} + data-testid={dataTestId ? dataTestId : 'PROJECT_SELECT'} + /> + ); + }, +);