From 859774c52ace7254cc50d4b0f843bd8b17e40db7 Mon Sep 17 00:00:00 2001 From: LE SAULNIER Kevin Date: Wed, 24 Jun 2026 10:37:24 +0200 Subject: [PATCH 1/7] move dispatch calls out of global filter component + move inner state into the component Signed-off-by: LE SAULNIER Kevin --- .../global-filter-autocomplete.tsx | 115 ++++++++++++------ .../global-filter/global-filter-context.ts | 44 ------- .../global-filter/global-filter-paper.tsx | 80 ++++++------ .../global-filter/global-filter-provider.tsx | 97 ++++++++------- .../global-filter/global-filter-selector.tsx | 5 +- .../global-filter/selected-global-filters.tsx | 15 ++- 6 files changed, 189 insertions(+), 167 deletions(-) delete mode 100644 src/components/results/common/global-filter/global-filter-context.ts diff --git a/src/components/results/common/global-filter/global-filter-autocomplete.tsx b/src/components/results/common/global-filter/global-filter-autocomplete.tsx index b909a79365..ecdbf0f4f4 100644 --- a/src/components/results/common/global-filter/global-filter-autocomplete.tsx +++ b/src/components/results/common/global-filter/global-filter-autocomplete.tsx @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import React, { useCallback, useContext, useMemo, useRef } from 'react'; +import React, { useCallback, useMemo, useRef, useState } from 'react'; import { Autocomplete, AutocompleteChangeDetails, @@ -27,22 +27,13 @@ import { import { Delete as DeleteIcon, FilterAlt, WarningAmberRounded } from '@mui/icons-material'; import { useIntl } from 'react-intl'; import { useLocalizedCountries } from 'components/utils/localized-countries-hook'; -import { useDispatch } from 'react-redux'; import { FilterType } from '../utils'; import { EquipmentType, OverflowableChip, OverflowableText } from '@gridsuite/commons-ui'; -import { GlobalFilter } from './global-filter-types'; +import { GlobalFilter, RecentGlobalFilter } from './global-filter-types'; import { getResultsGlobalFiltersChipStyle, resultsGlobalFilterStyles } from './global-filter-styles'; import GlobalFilterPaper from './global-filter-paper'; import IconButton from '@mui/material/IconButton'; import { getOptionLabel, RECENT_FILTER } from './global-filter-utils'; -import { GlobalFilterContext } from './global-filter-context'; -import { - addToSelectedGlobalFilters, - clearSelectedGlobalFilters, - removeFromGlobalFilterOptions, - removeFromSelectedGlobalFilters, -} from '../../../../redux/actions'; -import { AppDispatch } from '../../../../redux/store'; const TAG_LIMIT_NUMBER: number = 4; @@ -92,14 +83,15 @@ function RenderOption({ props, option, state, + removeGlobalFilterOption, }: { props: Omit, 'key'>; option: GlobalFilter; state: { selected: boolean }; + removeGlobalFilterOption: (id: string) => void; }) { const { children, ...otherProps } = props; const intl = useIntl(); - const dispatch = useDispatch(); const { translate } = useLocalizedCountries(); const label = getOptionLabel(option, translate, intl) ?? ''; @@ -127,7 +119,7 @@ function RenderOption({ }} onClick={(e) => { e.stopPropagation(); - dispatch(removeFromGlobalFilterOptions(option.id)); + removeGlobalFilterOption(option.id); }} > @@ -147,6 +139,20 @@ function RenderOption({ ); } +export type GlobalFilterAutocompleteProps = { + globalFilterOptions: GlobalFilter[]; + selectedGlobalFilters: GlobalFilter[]; + recentGlobalFilters: RecentGlobalFilter[]; + filterCategories: string[]; + genericFiltersStrictMode: boolean; + filterableEquipmentTypes: string[]; + selectGlobalFilter: (id: string) => void; + unselectGlobalFilters: (ids: string[]) => void; + clearSelectedGlobalFilters: () => void; + addGlobalFilterOptions: (newFilters: GlobalFilter[]) => void; + removeGlobalFilterOption: (id: string) => void; +}; + interface WarningTooltipProps { warningEquipmentTypeMessage: string; } @@ -175,24 +181,25 @@ function WarningTooltip({ warningEquipmentTypeMessage }: Readonly) { const intl = useIntl(); const { translate } = useLocalizedCountries(); - const dispatch = useDispatch(); const autocompleteRef = useRef(null); + const [openedDropdown, setOpenedDropdown] = useState(false); + const [directoryItemSelectorOpen, setDirectoryItemSelectorOpen] = useState(false); + const [filterGroupSelected, setFilterGroupSelected] = useState(FilterType.VOLTAGE_LEVEL); // checks the generic filter to see if they are applicable to the current tab const warningEquipmentTypeMessage: string = useMemo(() => { @@ -321,8 +328,38 @@ function GlobalFilterAutocomplete() { const isOptionEqualToValue = useCallback((option: GlobalFilter, value: GlobalFilter) => option.id === value.id, []); const PaperComponentMemo = useCallback( - (props: PaperProps) => , - [autocompleteRef] + (props: PaperProps) => ( + + ), + [ + autocompleteRef, + directoryItemSelectorOpen, + filterGroupSelected, + selectedGlobalFilters, + filterCategories, + genericFiltersStrictMode, + filterableEquipmentTypes, + selectGlobalFilter, + unselectGlobalFilters, + clearSelectedGlobalFilters, + addGlobalFilterOptions, + ] ); const handleOnChange = useCallback( @@ -334,19 +371,19 @@ function GlobalFilterAutocomplete() { ) => { switch (reason) { case 'selectOption': - dispatch(addToSelectedGlobalFilters(tableType, tableUuid, [details!.option.id])); + selectGlobalFilter(details!.option.id); break; case 'removeOption': - dispatch(removeFromSelectedGlobalFilters(tableType, tableUuid, [details!.option.id])); + unselectGlobalFilters([details!.option.id]); break; case 'clear': - dispatch(clearSelectedGlobalFilters(tableType, tableUuid)); + clearSelectedGlobalFilters(); break; default: break; } }, - [dispatch, tableType, tableUuid] + [clearSelectedGlobalFilters, selectGlobalFilter, unselectGlobalFilters] ); return ( @@ -391,7 +428,15 @@ function GlobalFilterAutocomplete() { // renderOption : the checkboxes visible when we focus on the AutoComplete renderOption={(props, option, state) => { const { key, ...otherProps } = props; - return ; + return ( + + ); }} // Allows to find the corresponding chips without taking into account the recent status isOptionEqualToValue={isOptionEqualToValue} diff --git a/src/components/results/common/global-filter/global-filter-context.ts b/src/components/results/common/global-filter/global-filter-context.ts deleted file mode 100644 index 00c76facb2..0000000000 --- a/src/components/results/common/global-filter/global-filter-context.ts +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright (c) 2025, RTE (http://www.rte-france.com) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -import { createContext } from 'react'; -import { GlobalFilter } from './global-filter-types'; -import { TableType } from '../../../../types/custom-aggrid-types'; -import type { RecentGlobalFilter } from './global-filter-types'; - -export const GlobalFilterContext = createContext<{ - // manage internal states - openedDropdown: boolean; - setOpenedDropdown: (open: boolean) => void; - directoryItemSelectorOpen: boolean; - setDirectoryItemSelectorOpen: (open: boolean) => void; - filterGroupSelected?: string; - setFilterGroupSelected: (selectedFilterGroup: string) => void; - globalFilterOptions: GlobalFilter[]; - selectedGlobalFilters: GlobalFilter[]; - recentGlobalFilters: RecentGlobalFilter[]; - filterCategories: string[]; - genericFiltersStrictMode: boolean; - filterableEquipmentTypes: string[]; - tableType: TableType; - tableUuid: string; -}>({ - openedDropdown: false, - setOpenedDropdown: () => {}, - directoryItemSelectorOpen: false, - setDirectoryItemSelectorOpen: () => {}, - filterGroupSelected: undefined, - setFilterGroupSelected: () => {}, - globalFilterOptions: [], - selectedGlobalFilters: [], - recentGlobalFilters: [], - filterCategories: [], - genericFiltersStrictMode: false, - filterableEquipmentTypes: [], - tableType: TableType.Loadflow, - tableUuid: TableType.Loadflow, -}); diff --git a/src/components/results/common/global-filter/global-filter-paper.tsx b/src/components/results/common/global-filter/global-filter-paper.tsx index cee978bd3c..cfb91fb873 100644 --- a/src/components/results/common/global-filter/global-filter-paper.tsx +++ b/src/components/results/common/global-filter/global-filter-paper.tsx @@ -9,7 +9,7 @@ import { Box, Button, Grid, ListItemButton, Paper, Typography } from '@mui/mater import { GLOBAL_FILTERS_CELL_HEIGHT, IMPORT_FILTER_HEIGHT, resultsGlobalFilterStyles } from './global-filter-styles'; import { FormattedMessage, useIntl } from 'react-intl'; import FileUploadIcon from '@mui/icons-material/FileUpload'; -import { PropsWithChildren, RefObject, useCallback, useContext, useEffect, useMemo, useState } from 'react'; +import { PropsWithChildren, RefObject, useCallback, useEffect, useMemo, useState } from 'react'; import ListItemText from '@mui/material/ListItemText'; import List from '@mui/material/List'; import { FilterType, isCriteriaFilterType } from '../utils'; @@ -25,16 +25,8 @@ import { mergeSx, TreeViewFinderNodeProps, } from '@gridsuite/commons-ui'; -import { GlobalFilterContext } from './global-filter-context'; import SelectedGlobalFilters from './selected-global-filters'; import { TextWithInfoIcon } from './text-with-info-icon'; -import { - addToSelectedGlobalFilters, - addToGlobalFilterOptions, - clearSelectedGlobalFilters, -} from '../../../../redux/actions'; -import { useDispatch } from 'react-redux'; -import { AppDispatch } from '../../../../redux/store'; const XS_COLUMN1: number = 3; const XS_COLUMN2: number = 4; @@ -42,24 +34,39 @@ const XS_COLUMN3: number = 5; type GlobalFilterPaperProps = PropsWithChildren<{ autocompleteRef?: RefObject; + setOpenedDropdown: (open: boolean) => void; + directoryItemSelectorOpen: boolean; + setDirectoryItemSelectorOpen: (open: boolean) => void; + filterGroupSelected: string; + setFilterGroupSelected: (selectedFilterGroup: string) => void; + selectedGlobalFilters: GlobalFilter[]; + filterCategories: string[]; + genericFiltersStrictMode: boolean; + filterableEquipmentTypes: string[]; + selectGlobalFilter: (id: string) => void; + unselectGlobalFilters: (ids: string[]) => void; + clearSelectedGlobalFilters: () => void; + addGlobalFilterOptions: (newFilters: GlobalFilter[]) => void; }>; -function GlobalFilterPaper({ children, autocompleteRef }: Readonly) { - const { - setOpenedDropdown, - directoryItemSelectorOpen, - setDirectoryItemSelectorOpen, - filterGroupSelected, - setFilterGroupSelected, - selectedGlobalFilters, - filterCategories, - genericFiltersStrictMode, - filterableEquipmentTypes, - tableType, - tableUuid, - } = useContext(GlobalFilterContext); +function GlobalFilterPaper({ + children, + autocompleteRef, + setOpenedDropdown, + directoryItemSelectorOpen, + setDirectoryItemSelectorOpen, + filterGroupSelected, + setFilterGroupSelected, + selectedGlobalFilters, + filterCategories, + genericFiltersStrictMode, + filterableEquipmentTypes, + selectGlobalFilter, + unselectGlobalFilters, + clearSelectedGlobalFilters, + addGlobalFilterOptions, +}: Readonly) { const intl = useIntl(); - const dispatch = useDispatch(); const [substationPropertiesFilters, setSubstationPropertiesFilters] = useState>(); // fetches substation properties global filters from local config @@ -161,17 +168,17 @@ function GlobalFilterPaper({ children, autocompleteRef }: Readonly f.id) - ) - ); + addGlobalFilterOptions(newlySelectedFilters); + newlySelectedFilters.forEach((filter) => selectGlobalFilter(filter.id)); setDirectoryItemSelectorOpen(false); }, - [selectedGlobalFilters, setDirectoryItemSelectorOpen, setOpenedDropdown, dispatch, tableType, tableUuid] + [ + selectedGlobalFilters, + setDirectoryItemSelectorOpen, + setOpenedDropdown, + addGlobalFilterOptions, + selectGlobalFilter, + ] ); /** @@ -219,7 +226,7 @@ function GlobalFilterPaper({ children, autocompleteRef }: Readonly{filtersMsg}