From f5e42ab1b6b62b7f1de54ec9c1e8387afc5e22d2 Mon Sep 17 00:00:00 2001 From: Rohit Rai Date: Tue, 12 May 2020 23:49:48 +0530 Subject: [PATCH] Remove topology text filter from redux and rely on URL search params --- .../src/components/topology/Topology.tsx | 27 ++++++++++- .../src/components/topology/TopologyPage.tsx | 14 +----- .../topology/components/GraphComponent.tsx | 20 +++------ .../__tests__/topology-model.spec.ts | 15 +------ .../topology/filters/TopologyFilterBar.tsx | 45 ++++++++++++------- .../filters/__tests__/useSearchFilter.spec.ts | 19 +++----- .../topology/filters/filter-utils.ts | 9 ++-- .../topology/filters/useSearchFilter.ts | 9 +--- .../src/components/topology/redux/const.ts | 2 - .../src/components/topology/redux/reducer.ts | 8 +--- .../topology/__tests__/topology-model.spec.ts | 15 +------ .../__tests__/kubevirt-topology-model.spec.ts | 15 +------ 12 files changed, 80 insertions(+), 118 deletions(-) diff --git a/frontend/packages/dev-console/src/components/topology/Topology.tsx b/frontend/packages/dev-console/src/components/topology/Topology.tsx index 482571cc0c5..791178e0f5c 100644 --- a/frontend/packages/dev-console/src/components/topology/Topology.tsx +++ b/frontend/packages/dev-console/src/components/topology/Topology.tsx @@ -51,7 +51,13 @@ import { topologyModelFromDataModel } from './data-transforms/topology-model'; import { layoutFactory, COLA_LAYOUT, COLA_FORCE_LAYOUT } from './layouts/layoutFactory'; import { TYPE_APPLICATION_GROUP, ComponentFactory } from './components'; import TopologyFilterBar from './filters/TopologyFilterBar'; -import { getTopologyFilters, TopologyFilters } from './filters/filter-utils'; +import { + getTopologyFilters, + getTopologySearchQuery, + TopologyFilters, + TOPOLOGY_SEARCH_FILTER_KEY, + FILTER_ACTIVE_CLASS, +} from './filters/filter-utils'; import TopologyHelmReleasePanel from './helm/TopologyHelmReleasePanel'; import { TYPE_HELM_RELEASE } from './helm/components/const'; import { HelmComponentFactory } from './helm/components/helmComponentFactory'; @@ -227,6 +233,21 @@ const Topology: React.FC = ({ })(); }, [layout]); + const onSearchChange = (searchQuery) => { + if (searchQuery.length > 0) { + setQueryArgument(TOPOLOGY_SEARCH_FILTER_KEY, searchQuery); + document.body.classList.add(FILTER_ACTIVE_CLASS); + } else { + removeQueryArgument(TOPOLOGY_SEARCH_FILTER_KEY); + document.body.classList.remove(FILTER_ACTIVE_CLASS); + } + }; + + React.useEffect(() => { + const searchQuery = getTopologySearchQuery(); + searchQuery && onSearchChange(searchQuery); + }, []); + const onSidebarClose = () => { setSelectedIds([]); removeQueryArgument('selectId'); @@ -346,7 +367,9 @@ const Topology: React.FC = ({ return ( } + viewToolbar={ + + } controlBar={renderControlBar()} sideBar={sideBar} sideBarOpen={!!sideBar} diff --git a/frontend/packages/dev-console/src/components/topology/TopologyPage.tsx b/frontend/packages/dev-console/src/components/topology/TopologyPage.tsx index 1b7ff0d03d1..f4d16050b73 100644 --- a/frontend/packages/dev-console/src/components/topology/TopologyPage.tsx +++ b/frontend/packages/dev-console/src/components/topology/TopologyPage.tsx @@ -11,13 +11,6 @@ import { removeQueryArgument, } from '@console/internal/components/utils'; -// FIXME upgrading redux types is causing many errors at this time -// eslint-disable-next-line @typescript-eslint/ban-ts-ignore -// @ts-ignore -import { useSelector, useDispatch } from 'react-redux'; -import { RootState } from '@console/internal/redux'; -import { getTopologyFilters } from './filters/filter-utils'; - import EmptyState from '../EmptyState'; import NamespacedPage, { NamespacedPageVariants } from '../NamespacedPage'; import ProjectsExistWrapper from '../ProjectsExistWrapper'; @@ -28,8 +21,7 @@ import TopologyShortcuts from './TopologyShortcuts'; import { LAST_TOPOLOGY_VIEW_LOCAL_STORAGE_KEY } from './components/const'; import './TopologyPage.scss'; -import { TOPOLOGY_SEARCH_FILTER_KEY } from './redux/const'; -import { setTopologyFilters } from './redux/action'; +import { TOPOLOGY_SEARCH_FILTER_KEY } from './filters'; export interface TopologyPageProps { match: RMatch<{ @@ -86,13 +78,9 @@ export const TopologyPage: React.FC = ({ match }) => { exact: true, }); - const dispatch = useDispatch(); - const displayFilters = useSelector((state: RootState) => getTopologyFilters(state).display); - const handleNamespaceChange = (ns: string) => { if (ns !== namespace) { removeQueryArgument(TOPOLOGY_SEARCH_FILTER_KEY); - dispatch(setTopologyFilters({ display: displayFilters, searchQuery: '' })); } }; diff --git a/frontend/packages/dev-console/src/components/topology/components/GraphComponent.tsx b/frontend/packages/dev-console/src/components/topology/components/GraphComponent.tsx index 53d173f3184..6ff129b2963 100644 --- a/frontend/packages/dev-console/src/components/topology/components/GraphComponent.tsx +++ b/frontend/packages/dev-console/src/components/topology/components/GraphComponent.tsx @@ -1,30 +1,24 @@ import * as React from 'react'; import * as classNames from 'classnames'; -import { connect } from 'react-redux'; -import { RootState } from '@console/internal/redux'; import { GraphComponent as BaseGraphComponent, WithContextMenuProps } from '@console/topology'; -import { TopologyFilters, getTopologyFilters } from '../filters/filter-utils'; type GraphComponentProps = React.ComponentProps & { dragEditInProgress?: boolean; hasDropTarget?: boolean; dragCreate?: boolean; - filters: TopologyFilters; } & WithContextMenuProps; const DRAG_ACTIVE_CLASS = 'odc-m-drag-active'; -const FILTER_ACTIVE_CLASS = 'odc-m-filter-active'; const VALID_DROP_CLASS = 'odc-m-valid-drop-target'; const GraphComponent: React.FC = (props) => { - const { dragEditInProgress, hasDropTarget, dragCreate, filters } = props; + const { dragEditInProgress, hasDropTarget, dragCreate } = props; const graphClasses = classNames('odc-graph', { 'odc-m-drag-create': dragCreate }); + React.useEffect(() => { const addClassList = []; const removeClassList = []; - filters.searchQuery.trim() !== '' - ? addClassList.push(FILTER_ACTIVE_CLASS) - : removeClassList.push(FILTER_ACTIVE_CLASS); + dragEditInProgress ? addClassList.push(DRAG_ACTIVE_CLASS) : removeClassList.push(DRAG_ACTIVE_CLASS); @@ -36,7 +30,7 @@ const GraphComponent: React.FC = (props) => { if (removeClassList.length) { removeClassList.forEach((className) => document.body.classList.remove(className)); } - }, [dragEditInProgress, filters.searchQuery, hasDropTarget]); + }, [dragEditInProgress, hasDropTarget]); return ( @@ -44,8 +38,4 @@ const GraphComponent: React.FC = (props) => { ); }; -const GraphComponentState = (state: RootState) => { - const filters = getTopologyFilters(state); - return { filters }; -}; -export default connect(GraphComponentState)(GraphComponent); +export default GraphComponent; diff --git a/frontend/packages/dev-console/src/components/topology/data-transforms/__tests__/topology-model.spec.ts b/frontend/packages/dev-console/src/components/topology/data-transforms/__tests__/topology-model.spec.ts index 061c52d5b03..76781a50ca6 100644 --- a/frontend/packages/dev-console/src/components/topology/data-transforms/__tests__/topology-model.spec.ts +++ b/frontend/packages/dev-console/src/components/topology/data-transforms/__tests__/topology-model.spec.ts @@ -10,24 +10,13 @@ import { topologyModelFromDataModel } from '../topology-model'; import { transformTopologyData } from '../data-transformer'; import { TopologyFilters } from '../../filters/filter-utils'; import { allowedResources } from '../../topology-utils'; +import { DEFAULT_TOPOLOGY_FILTERS } from '../../redux/const'; describe('topology model ', () => { let filters: TopologyFilters; beforeEach(() => { - filters = { - display: { - podCount: true, - eventSources: true, - virtualMachines: true, - showLabels: true, - knativeServices: true, - appGrouping: true, - operatorGrouping: true, - helmGrouping: true, - }, - searchQuery: '', - }; + filters = _.cloneDeep(DEFAULT_TOPOLOGY_FILTERS); }); it('should return topology model data', () => { diff --git a/frontend/packages/dev-console/src/components/topology/filters/TopologyFilterBar.tsx b/frontend/packages/dev-console/src/components/topology/filters/TopologyFilterBar.tsx index a69f6632c22..16d4e7e14c7 100644 --- a/frontend/packages/dev-console/src/components/topology/filters/TopologyFilterBar.tsx +++ b/frontend/packages/dev-console/src/components/topology/filters/TopologyFilterBar.tsx @@ -6,10 +6,14 @@ import { RootState } from '@console/internal/redux'; import { TextFilter } from '@console/internal/components/factory'; import { InfoCircleIcon } from '@patternfly/react-icons'; import { Visualization } from '@console/topology'; -import { setQueryArgument, removeQueryArgument } from '@console/internal/components/utils'; import { setTopologyFilters } from '../redux/action'; -import { TOPOLOGY_SEARCH_FILTER_KEY } from '../redux/const'; -import { TopologyFilters, DisplayFilters, getTopologyFilters } from './filter-utils'; +import { + TopologyFilters, + DisplayFilters, + getTopologyFilters, + getTopologySearchQuery, +} from './filter-utils'; + import FilterDropdown from './FilterDropdown'; import './TopologyFilterBar.scss'; @@ -23,22 +27,38 @@ type DispatchProps = { type OwnProps = { visualization: Visualization; + onSearchChange: (searchQuery: string) => void; }; type MergeProps = { onDisplayFiltersChange: (display: DisplayFilters) => void; - onSearchQueryChange: (searchQuery: string) => void; } & StateProps & OwnProps; type TopologyFilterBarProps = MergeProps; const TopologyFilterBar: React.FC = ({ - filters: { display, searchQuery }, + filters: { display }, onDisplayFiltersChange, - onSearchQueryChange, + onSearchChange, visualization, }) => { + const [searchQuery, setSearchQuery] = React.useState(''); + + React.useEffect(() => { + const query = getTopologySearchQuery(); + setSearchQuery(query); + }, []); + + const onTextFilterChange = React.useCallback( + (text) => { + const query = text?.trim(); + setSearchQuery(query); + onSearchChange(query); + }, + [onSearchChange], + ); + return ( @@ -52,7 +72,7 @@ const TopologyFilterBar: React.FC = ({ placeholder="Find by name..." value={searchQuery} autoFocus - onChange={onSearchQueryChange} + onChange={onTextFilterChange} /> @@ -92,20 +112,13 @@ const dispatchToProps = (dispatch: Dispatch): DispatchProps => ({ const mergeProps = ( { filters }: StateProps, { onFiltersChange }: DispatchProps, - { visualization }: OwnProps, + { visualization, onSearchChange }: OwnProps, ): MergeProps => ({ filters, onDisplayFiltersChange: (display: DisplayFilters) => { onFiltersChange({ ...filters, display }); }, - onSearchQueryChange: (searchQuery) => { - onFiltersChange({ ...filters, searchQuery }); - if (searchQuery.length > 0) { - setQueryArgument(TOPOLOGY_SEARCH_FILTER_KEY, searchQuery); - } else { - removeQueryArgument(TOPOLOGY_SEARCH_FILTER_KEY); - } - }, + onSearchChange, visualization, }); diff --git a/frontend/packages/dev-console/src/components/topology/filters/__tests__/useSearchFilter.spec.ts b/frontend/packages/dev-console/src/components/topology/filters/__tests__/useSearchFilter.spec.ts index 23eb94f3c71..695a50a19ab 100644 --- a/frontend/packages/dev-console/src/components/topology/filters/__tests__/useSearchFilter.spec.ts +++ b/frontend/packages/dev-console/src/components/topology/filters/__tests__/useSearchFilter.spec.ts @@ -1,26 +1,17 @@ -// FIXME upgrading redux types is causing many errors at this time -// eslint-disable-next-line @typescript-eslint/ban-ts-ignore -// @ts-ignore -import { useSelector } from 'react-redux'; -import { RootState } from '@console/internal/redux'; import { testHook } from '../../../../test/test-utils'; import { useSearchFilter } from '../useSearchFilter'; +import { getTopologySearchQuery } from '../filter-utils'; -jest.mock('react-redux', () => ({ - useSelector: jest.fn(), +jest.mock('../filter-utils', () => ({ + getTopologySearchQuery: jest.fn(), })); const testUseSearchFilter = ( text: string | null | undefined, searchQuery: string | undefined, ): ReturnType => { - (useSelector as jest.Mock).mockImplementation((fn: (state: Partial) => any) => { - return fn({ - plugins: { - devconsole: { topology: new Map(Object.entries({ filters: { searchQuery } })) }, - }, - }); - }); + (getTopologySearchQuery as jest.Mock).mockImplementation(() => searchQuery); + // eslint-disable-next-line react-hooks/rules-of-hooks return useSearchFilter(text); }; diff --git a/frontend/packages/dev-console/src/components/topology/filters/filter-utils.ts b/frontend/packages/dev-console/src/components/topology/filters/filter-utils.ts index 70a0df2b1cc..7ff81868800 100644 --- a/frontend/packages/dev-console/src/components/topology/filters/filter-utils.ts +++ b/frontend/packages/dev-console/src/components/topology/filters/filter-utils.ts @@ -1,4 +1,8 @@ import { RootState } from '@console/internal/redux'; +import { getQueryArgument } from '@console/internal/components/utils'; + +export const TOPOLOGY_SEARCH_FILTER_KEY = 'searchQuery'; +export const FILTER_ACTIVE_CLASS = 'odc-m-filter-active'; export enum ShowFiltersKeyValue { podCount = 'Pod Count', @@ -20,13 +24,12 @@ export const getTopologyFilters = ({ }, }: RootState): TopologyFilters => topology.get('filters'); +export const getTopologySearchQuery = () => getQueryArgument(TOPOLOGY_SEARCH_FILTER_KEY) ?? ''; + export type TopologyFilters = { display: DisplayFilters; - searchQuery: SearchQuery; }; -export type SearchQuery = string; - export type DisplayFilters = { podCount: boolean; eventSources: boolean; diff --git a/frontend/packages/dev-console/src/components/topology/filters/useSearchFilter.ts b/frontend/packages/dev-console/src/components/topology/filters/useSearchFilter.ts index 5db8db751a8..bca5d50814e 100644 --- a/frontend/packages/dev-console/src/components/topology/filters/useSearchFilter.ts +++ b/frontend/packages/dev-console/src/components/topology/filters/useSearchFilter.ts @@ -1,17 +1,12 @@ import * as React from 'react'; import * as fuzzy from 'fuzzysearch'; import { toLower } from 'lodash'; -// FIXME upgrading redux types is causing many errors at this time -// eslint-disable-next-line @typescript-eslint/ban-ts-ignore -// @ts-ignore -import { useSelector } from 'react-redux'; -import { RootState } from '@console/internal/redux'; -import { getTopologyFilters } from './filter-utils'; +import { getTopologySearchQuery } from './filter-utils'; const fuzzyCaseInsensitive = (a: string, b: string): boolean => fuzzy(toLower(a), toLower(b)); const useSearchFilter = (text: string): [boolean, string] => { - const searchQuery = useSelector((state: RootState) => getTopologyFilters(state).searchQuery); + const searchQuery = getTopologySearchQuery(); const filtered = React.useMemo(() => fuzzyCaseInsensitive(searchQuery, text), [ searchQuery, text, diff --git a/frontend/packages/dev-console/src/components/topology/redux/const.ts b/frontend/packages/dev-console/src/components/topology/redux/const.ts index 56a08cd1181..da0cb5d4c27 100644 --- a/frontend/packages/dev-console/src/components/topology/redux/const.ts +++ b/frontend/packages/dev-console/src/components/topology/redux/const.ts @@ -1,5 +1,4 @@ export const TOPOLOGY_DISPLAY_FILTERS_LOCAL_STORAGE_KEY = `bridge/topology-display-filters`; -export const TOPOLOGY_SEARCH_FILTER_KEY = 'searchQuery'; export const DEFAULT_TOPOLOGY_FILTERS = { display: { podCount: false, @@ -11,5 +10,4 @@ export const DEFAULT_TOPOLOGY_FILTERS = { operatorGrouping: true, helmGrouping: true, }, - searchQuery: '', }; diff --git a/frontend/packages/dev-console/src/components/topology/redux/reducer.ts b/frontend/packages/dev-console/src/components/topology/redux/reducer.ts index 0921e43086e..8e0e6318b25 100644 --- a/frontend/packages/dev-console/src/components/topology/redux/reducer.ts +++ b/frontend/packages/dev-console/src/components/topology/redux/reducer.ts @@ -1,17 +1,12 @@ import { Map } from 'immutable'; import { merge } from 'lodash'; import { TopologyAction, Actions } from './action'; -import { - TOPOLOGY_DISPLAY_FILTERS_LOCAL_STORAGE_KEY, - DEFAULT_TOPOLOGY_FILTERS, - TOPOLOGY_SEARCH_FILTER_KEY, -} from './const'; +import { TOPOLOGY_DISPLAY_FILTERS_LOCAL_STORAGE_KEY, DEFAULT_TOPOLOGY_FILTERS } from './const'; export type State = Map; export const getDefaultTopologyFilters = () => { const displayFilters = localStorage.getItem(TOPOLOGY_DISPLAY_FILTERS_LOCAL_STORAGE_KEY); - const searchQuery = new URLSearchParams(window.location.search).get(TOPOLOGY_SEARCH_FILTER_KEY); if (!displayFilters) { localStorage.setItem( @@ -22,7 +17,6 @@ export const getDefaultTopologyFilters = () => { const filters = merge({}, DEFAULT_TOPOLOGY_FILTERS, { display: JSON.parse(displayFilters) ?? {}, - searchQuery: searchQuery ?? '', }); return filters; diff --git a/frontend/packages/knative-plugin/src/topology/__tests__/topology-model.spec.ts b/frontend/packages/knative-plugin/src/topology/__tests__/topology-model.spec.ts index e4ed8a10c26..b12c640ffc3 100644 --- a/frontend/packages/knative-plugin/src/topology/__tests__/topology-model.spec.ts +++ b/frontend/packages/knative-plugin/src/topology/__tests__/topology-model.spec.ts @@ -1,5 +1,6 @@ import * as _ from 'lodash'; import { ALL_APPLICATIONS_KEY } from '@console/shared/src'; +import { DEFAULT_TOPOLOGY_FILTERS } from '@console/dev-console/src/components/topology/redux/const'; import { TopologyFilters } from '@console/dev-console/src/components/topology/filters/filter-utils'; import { transformTopologyData, @@ -12,19 +13,7 @@ describe('topology model ', () => { let filters: TopologyFilters; beforeEach(() => { - filters = { - display: { - podCount: true, - eventSources: true, - virtualMachines: true, - showLabels: true, - knativeServices: true, - appGrouping: true, - operatorGrouping: true, - helmGrouping: true, - }, - searchQuery: '', - }; + filters = _.cloneDeep(DEFAULT_TOPOLOGY_FILTERS); }); it('should flag knative groups as collapsed when display filter is set', () => { diff --git a/frontend/packages/kubevirt-plugin/src/topology/__tests__/kubevirt-topology-model.spec.ts b/frontend/packages/kubevirt-plugin/src/topology/__tests__/kubevirt-topology-model.spec.ts index 121674e2767..c92b8b435eb 100644 --- a/frontend/packages/kubevirt-plugin/src/topology/__tests__/kubevirt-topology-model.spec.ts +++ b/frontend/packages/kubevirt-plugin/src/topology/__tests__/kubevirt-topology-model.spec.ts @@ -1,5 +1,6 @@ import * as _ from 'lodash'; import { ALL_APPLICATIONS_KEY } from '@console/shared/src'; +import { DEFAULT_TOPOLOGY_FILTERS } from '@console/dev-console/src/components/topology/redux/const'; import { TopologyFilters } from '@console/dev-console/src/components/topology/filters/filter-utils'; import { transformTopologyData, @@ -14,19 +15,7 @@ describe('topology model ', () => { beforeEach(() => { mockResources = _.cloneDeep(kubevirtResources as any); - filters = { - display: { - podCount: true, - eventSources: true, - virtualMachines: true, - showLabels: true, - knativeServices: true, - appGrouping: true, - operatorGrouping: true, - helmGrouping: true, - }, - searchQuery: '', - }; + filters = _.cloneDeep(DEFAULT_TOPOLOGY_FILTERS); }); it('should create nodes and edges for Virtual Machines', () => {