From 061b4cb0c6d19148f6bf68f301c466019de23d26 Mon Sep 17 00:00:00 2001 From: openshift-trt Date: Tue, 30 Jun 2026 16:43:03 +0000 Subject: [PATCH 1/4] TRT-2764: Fix search bar not completing search until page refresh The requestSearch function in 11 table components mutated the filterModel object returned by useStableJSONQueryParam in place. This corrupted the hook's internal ref state: the intermediate re-render from setSearching(true) would detect the mutation via the defaultValue fallback, update the serialized cache, and then when the URL update arrived with the same content, the comparison found no change, so the useEffect never fired and fetchData was never called. Fix by creating a new object with spread syntax instead of mutating the existing filterModel. This ensures useStableJSONQueryParam sees a genuinely new reference on re-render, triggering the useEffect and completing the search. Co-Authored-By: Claude Opus 4.6 --- sippy-ng/src/jobs/JobRunsTable.js | 12 ++++++------ sippy-ng/src/jobs/JobTable.js | 12 ++++++------ sippy-ng/src/releases/PayloadStreamTestFailures.js | 12 ++++++------ sippy-ng/src/releases/PayloadStreamsTable.js | 10 ++++++---- sippy-ng/src/releases/PayloadTestFailures.js | 12 ++++++------ sippy-ng/src/releases/ReleasePayloadJobRuns.js | 10 ++++++---- sippy-ng/src/releases/ReleasePayloadPullRequests.js | 10 ++++++---- sippy-ng/src/releases/ReleasePayloadTable.js | 10 ++++++---- sippy-ng/src/repositories/RepositoriesTable.js | 12 ++++++------ sippy-ng/src/tests/FeatureGates.js | 10 ++++++---- sippy-ng/src/tests/TestTable.js | 12 ++++++------ 11 files changed, 66 insertions(+), 56 deletions(-) diff --git a/sippy-ng/src/jobs/JobRunsTable.js b/sippy-ng/src/jobs/JobRunsTable.js index 81c9e4ab7..605bf1c81 100644 --- a/sippy-ng/src/jobs/JobRunsTable.js +++ b/sippy-ng/src/jobs/JobRunsTable.js @@ -468,17 +468,17 @@ export default function JobRunsTable(props) { } const requestSearch = (searchValue) => { - const currentFilters = filterModel - currentFilters.items = currentFilters.items.filter( - (f) => f.columnField !== 'job' - ) - currentFilters.items.push({ + const newItems = filterModel.items.filter((f) => f.columnField !== 'job') + newItems.push({ id: 99, columnField: 'job', operatorValue: 'contains', value: searchValue, }) - setFilterModel(currentFilters) + setFilterModel({ + ...filterModel, + items: newItems, + }) } useEffect(() => { diff --git a/sippy-ng/src/jobs/JobTable.js b/sippy-ng/src/jobs/JobTable.js index 1d8eea3cb..337218a8b 100644 --- a/sippy-ng/src/jobs/JobTable.js +++ b/sippy-ng/src/jobs/JobTable.js @@ -533,17 +533,17 @@ function JobTable(props) { } const requestSearch = (searchValue) => { - const currentFilters = filterModel - currentFilters.items = currentFilters.items.filter( - (f) => f.columnField !== 'name' - ) - currentFilters.items.push({ + const newItems = filterModel.items.filter((f) => f.columnField !== 'name') + newItems.push({ id: 99, columnField: 'name', operatorValue: 'contains', value: searchValue, }) - setFilterModel(currentFilters) + setFilterModel({ + ...filterModel, + items: newItems, + }) } useEffect(() => { diff --git a/sippy-ng/src/releases/PayloadStreamTestFailures.js b/sippy-ng/src/releases/PayloadStreamTestFailures.js index 878b959e6..f192b1566 100644 --- a/sippy-ng/src/releases/PayloadStreamTestFailures.js +++ b/sippy-ng/src/releases/PayloadStreamTestFailures.js @@ -116,17 +116,17 @@ function PayloadStreamTestFailures(props) { ) const requestSearch = (searchValue) => { - const currentFilters = filterModel - currentFilters.items = currentFilters.items.filter( - (f) => f.columnField !== 'name' - ) - currentFilters.items.push({ + const newItems = filterModel.items.filter((f) => f.columnField !== 'name') + newItems.push({ id: 99, columnField: 'name', operatorValue: 'contains', value: searchValue, }) - setFilterModel(currentFilters) + setFilterModel({ + ...filterModel, + items: newItems, + }) } const addFilters = (filter) => { diff --git a/sippy-ng/src/releases/PayloadStreamsTable.js b/sippy-ng/src/releases/PayloadStreamsTable.js index 509585700..d3470faab 100644 --- a/sippy-ng/src/releases/PayloadStreamsTable.js +++ b/sippy-ng/src/releases/PayloadStreamsTable.js @@ -127,17 +127,19 @@ function PayloadStreamsTable(props) { ) const requestSearch = (searchValue) => { - const currentFilters = filterModel - currentFilters.items = currentFilters.items.filter( + const newItems = filterModel.items.filter( (f) => f.columnField !== 'release_tag' ) - currentFilters.items.push({ + newItems.push({ id: 99, columnField: 'release_tag', operatorValue: 'contains', value: searchValue, }) - setFilterModel(currentFilters) + setFilterModel({ + ...filterModel, + items: newItems, + }) } const addFilters = (filter) => { diff --git a/sippy-ng/src/releases/PayloadTestFailures.js b/sippy-ng/src/releases/PayloadTestFailures.js index 34b264d49..5b7ef0ac0 100644 --- a/sippy-ng/src/releases/PayloadTestFailures.js +++ b/sippy-ng/src/releases/PayloadTestFailures.js @@ -95,17 +95,17 @@ function PayloadTestFailures(props) { ) const requestSearch = (searchValue) => { - const currentFilters = filterModel - currentFilters.items = currentFilters.items.filter( - (f) => f.columnField !== 'name' - ) - currentFilters.items.push({ + const newItems = filterModel.items.filter((f) => f.columnField !== 'name') + newItems.push({ id: 99, columnField: 'name', operatorValue: 'contains', value: searchValue, }) - setFilterModel(currentFilters) + setFilterModel({ + ...filterModel, + items: newItems, + }) } const addFilters = (filter) => { diff --git a/sippy-ng/src/releases/ReleasePayloadJobRuns.js b/sippy-ng/src/releases/ReleasePayloadJobRuns.js index 86123b7d5..1aaf8fb28 100644 --- a/sippy-ng/src/releases/ReleasePayloadJobRuns.js +++ b/sippy-ng/src/releases/ReleasePayloadJobRuns.js @@ -155,17 +155,19 @@ function ReleasePayloadJobRuns(props) { ) const requestSearch = (searchValue) => { - const currentFilters = filterModel - currentFilters.items = currentFilters.items.filter( + const newItems = filterModel.items.filter( (f) => f.columnField !== 'release_tag' ) - currentFilters.items.push({ + newItems.push({ id: 99, columnField: 'releaseTag', operatorValue: 'contains', value: searchValue, }) - setFilterModel(currentFilters) + setFilterModel({ + ...filterModel, + items: newItems, + }) } const addFilters = (filter) => { diff --git a/sippy-ng/src/releases/ReleasePayloadPullRequests.js b/sippy-ng/src/releases/ReleasePayloadPullRequests.js index 60794905b..220799434 100644 --- a/sippy-ng/src/releases/ReleasePayloadPullRequests.js +++ b/sippy-ng/src/releases/ReleasePayloadPullRequests.js @@ -77,17 +77,19 @@ function ReleasePayloadPullRequests(props) { ) const requestSearch = (searchValue) => { - const currentFilters = filterModel - currentFilters.items = currentFilters.items.filter( + const newItems = filterModel.items.filter( (f) => f.columnField !== 'release_tag' ) - currentFilters.items.push({ + newItems.push({ id: 99, columnField: 'release_tag', operatorValue: 'contains', value: searchValue, }) - setFilterModel(currentFilters) + setFilterModel({ + ...filterModel, + items: newItems, + }) } const addFilters = (filter) => { diff --git a/sippy-ng/src/releases/ReleasePayloadTable.js b/sippy-ng/src/releases/ReleasePayloadTable.js index a9412f6ad..46eb540c3 100644 --- a/sippy-ng/src/releases/ReleasePayloadTable.js +++ b/sippy-ng/src/releases/ReleasePayloadTable.js @@ -320,17 +320,19 @@ function ReleasePayloadTable(props) { } const requestSearch = (searchValue) => { - const currentFilters = filterModel - currentFilters.items = currentFilters.items.filter( + const newItems = filterModel.items.filter( (f) => f.columnField !== 'release_tag' ) - currentFilters.items.push({ + newItems.push({ id: 99, columnField: 'release_tag', operatorValue: 'contains', value: searchValue, }) - setFilterModelWithConversion(currentFilters) + setFilterModelWithConversion({ + ...filterModel, + items: newItems, + }) } const addFilters = (filter) => { diff --git a/sippy-ng/src/repositories/RepositoriesTable.js b/sippy-ng/src/repositories/RepositoriesTable.js index c25ba537b..9d57eceaf 100644 --- a/sippy-ng/src/repositories/RepositoriesTable.js +++ b/sippy-ng/src/repositories/RepositoriesTable.js @@ -278,17 +278,17 @@ function RepositoriesTable(props) { } const requestSearch = (searchValue) => { - const currentFilters = filterModel - currentFilters.items = currentFilters.items.filter( - (f) => f.columnField !== 'repo' - ) - currentFilters.items.push({ + const newItems = filterModel.items.filter((f) => f.columnField !== 'repo') + newItems.push({ id: 99, columnField: 'repo', operatorValue: 'contains', value: searchValue, }) - setFilterModel(currentFilters) + setFilterModel({ + ...filterModel, + items: newItems, + }) } return ( diff --git a/sippy-ng/src/tests/FeatureGates.js b/sippy-ng/src/tests/FeatureGates.js index 31ac07999..cce14f9c8 100644 --- a/sippy-ng/src/tests/FeatureGates.js +++ b/sippy-ng/src/tests/FeatureGates.js @@ -211,17 +211,19 @@ export default function FeatureGates(props) { } const requestSearch = (searchValue) => { - const currentFilters = filterModel - currentFilters.items = currentFilters.items.filter( + const newItems = filterModel.items.filter( (f) => f.columnField !== 'feature_gate' ) - currentFilters.items.push({ + newItems.push({ id: 99, columnField: 'feature_gate', operatorValue: 'contains', value: searchValue, }) - setFilterModel(currentFilters) + setFilterModel({ + ...filterModel, + items: newItems, + }) } const addFilters = (filter) => { diff --git a/sippy-ng/src/tests/TestTable.js b/sippy-ng/src/tests/TestTable.js index 68fd3701c..734ef9349 100644 --- a/sippy-ng/src/tests/TestTable.js +++ b/sippy-ng/src/tests/TestTable.js @@ -1004,17 +1004,17 @@ function TestTable(props) { const requestSearch = (searchValue) => { setSearching(true) - const currentFilters = filterModel - currentFilters.items = currentFilters.items.filter( - (f) => f.columnField !== 'name' - ) - currentFilters.items.push({ + const newItems = filterModel.items.filter((f) => f.columnField !== 'name') + newItems.push({ id: 99, columnField: 'name', operatorValue: 'contains', value: searchValue, }) - setFilterModel(currentFilters) + setFilterModel({ + ...filterModel, + items: newItems, + }) } if (fetchError !== '') { From 45601e8e60044e39c4d4c26d8a77b6d8a7e640da Mon Sep 17 00:00:00 2001 From: openshift-trt Date: Wed, 1 Jul 2026 14:07:31 +0000 Subject: [PATCH 2/4] TRT-2764: Fix double-search stuck loading and repopulate search bar on refresh Fix two issues with the quick search bar: 1. Pressing Enter or clicking the search icon when the same search term is already active no longer gets stuck in loading state. The requestSearch function in TestTable now checks if the filter would actually change before setting the searching state. 2. When refreshing the page, the quick search bar is now repopulated from the filterModel URL query parameter. GridToolbar accepts a new searchField prop that identifies which filter column corresponds to the search bar, and initializes the search text on mount. Co-Authored-By: Claude Opus 4.6 --- .../RegressedTestsPanel.js | 1 + .../TriagedRegressionTestList.js | 1 + .../component_readiness/TriagedRegressions.js | 1 + sippy-ng/src/datagrid/GridToolbar.js | 23 ++++++++++++++++++- sippy-ng/src/jobs/JobAnalysis.js | 1 + sippy-ng/src/jobs/JobRunsTable.js | 1 + sippy-ng/src/jobs/JobTable.js | 1 + .../src/releases/PayloadStreamTestFailures.js | 1 + sippy-ng/src/releases/PayloadStreamsTable.js | 1 + sippy-ng/src/releases/PayloadTestFailures.js | 1 + .../src/releases/ReleasePayloadJobRuns.js | 1 + .../releases/ReleasePayloadPullRequests.js | 1 + sippy-ng/src/releases/ReleasePayloadTable.js | 1 + .../src/repositories/RepositoriesTable.js | 1 + sippy-ng/src/tests/FeatureGates.js | 1 + sippy-ng/src/tests/TestTable.js | 7 ++++++ 16 files changed, 43 insertions(+), 1 deletion(-) diff --git a/sippy-ng/src/component_readiness/RegressedTestsPanel.js b/sippy-ng/src/component_readiness/RegressedTestsPanel.js index 025236544..105bc4f74 100644 --- a/sippy-ng/src/component_readiness/RegressedTestsPanel.js +++ b/sippy-ng/src/component_readiness/RegressedTestsPanel.js @@ -373,6 +373,7 @@ export default function RegressedTestsPanel(props) { setFilterModel: setFilterModel, clearSearch: () => requestSearch(''), doSearch: requestSearch, + searchField: 'test_name', autocompleteData: regressedTests, downloadDataFunc: () => { return filteredTests diff --git a/sippy-ng/src/component_readiness/TriagedRegressionTestList.js b/sippy-ng/src/component_readiness/TriagedRegressionTestList.js index 5b047b74b..ff763650b 100644 --- a/sippy-ng/src/component_readiness/TriagedRegressionTestList.js +++ b/sippy-ng/src/component_readiness/TriagedRegressionTestList.js @@ -352,6 +352,7 @@ export default function TriagedRegressionTestList(props) { setFilterModel: setFilterModel, clearSearch: () => requestSearch(''), doSearch: requestSearch, + searchField: 'test_name', autocompleteData: triagedRegressions, downloadDataFunc: () => { return filteredRegressions diff --git a/sippy-ng/src/component_readiness/TriagedRegressions.js b/sippy-ng/src/component_readiness/TriagedRegressions.js index cc8c28a42..41fbeacc5 100644 --- a/sippy-ng/src/component_readiness/TriagedRegressions.js +++ b/sippy-ng/src/component_readiness/TriagedRegressions.js @@ -407,6 +407,7 @@ export default function TriagedRegressions({ setFilterModel: setFilterModel, clearSearch: () => requestSearch(''), doSearch: requestSearch, + searchField: 'description', autocompleteData: triageEntries, downloadDataFunc: () => { return filteredTriageEntries diff --git a/sippy-ng/src/datagrid/GridToolbar.js b/sippy-ng/src/datagrid/GridToolbar.js index 602a3f640..4b7652a87 100644 --- a/sippy-ng/src/datagrid/GridToolbar.js +++ b/sippy-ng/src/datagrid/GridToolbar.js @@ -8,7 +8,7 @@ import GridToolbarPeriodSelector from '../datagrid/GridToolbarPeriodSelector' import GridToolbarViewSelector from './GridToolbarViewSelector' import IconButton from '@mui/material/IconButton' import PropTypes from 'prop-types' -import React, { Fragment } from 'react' +import React, { Fragment, useEffect, useRef } from 'react' import SearchIcon from '@mui/icons-material/Search' import TextField from '@mui/material/TextField' @@ -39,6 +39,26 @@ export default function GridToolbar(props) { const classes = useStyles(theme) const [search, setSearch] = React.useState('') + const initializedFromFilter = useRef(false) + + useEffect(() => { + if ( + initializedFromFilter.current || + !props.searchField || + !props.filterModel || + !props.filterModel.items + ) { + return + } + const searchFilter = props.filterModel.items.find( + (f) => + f.columnField === props.searchField && f.operatorValue === 'contains' + ) + if (searchFilter && searchFilter.value) { + setSearch(searchFilter.value) + } + initializedFromFilter.current = true + }, [props.searchField, props.filterModel]) return (
@@ -145,4 +165,5 @@ GridToolbar.propTypes = { downloadDataFunc: PropTypes.func, downloadFilePrefix: PropTypes.string, autocompleteData: PropTypes.array, + searchField: PropTypes.string, } diff --git a/sippy-ng/src/jobs/JobAnalysis.js b/sippy-ng/src/jobs/JobAnalysis.js index 363faa9f6..42bef2e80 100644 --- a/sippy-ng/src/jobs/JobAnalysis.js +++ b/sippy-ng/src/jobs/JobAnalysis.js @@ -602,6 +602,7 @@ export function JobAnalysis(props) { setFilterModel: setTestFilter, clearSearch: () => requestSearch(''), doSearch: requestSearch, + searchField: 'name', }, }} /> diff --git a/sippy-ng/src/jobs/JobRunsTable.js b/sippy-ng/src/jobs/JobRunsTable.js index 605bf1c81..2fc6a3a81 100644 --- a/sippy-ng/src/jobs/JobRunsTable.js +++ b/sippy-ng/src/jobs/JobRunsTable.js @@ -655,6 +655,7 @@ export default function JobRunsTable(props) { columns: columns, clearSearch: () => requestSearch(''), doSearch: requestSearch, + searchField: 'job', filterModel: filterModel, setFilterModel: setFilterModel, addFilters: (m) => addFilters(m), diff --git a/sippy-ng/src/jobs/JobTable.js b/sippy-ng/src/jobs/JobTable.js index 337218a8b..972595dea 100644 --- a/sippy-ng/src/jobs/JobTable.js +++ b/sippy-ng/src/jobs/JobTable.js @@ -708,6 +708,7 @@ function JobTable(props) { columns: gridView.filterColumns, clearSearch: () => requestSearch(''), doSearch: requestSearch, + searchField: 'name', period: period, selectPeriod: setPeriod, addFilters: (m) => addFilters(m), diff --git a/sippy-ng/src/releases/PayloadStreamTestFailures.js b/sippy-ng/src/releases/PayloadStreamTestFailures.js index f192b1566..96ab7f02e 100644 --- a/sippy-ng/src/releases/PayloadStreamTestFailures.js +++ b/sippy-ng/src/releases/PayloadStreamTestFailures.js @@ -257,6 +257,7 @@ function PayloadStreamTestFailures(props) { columns: columns, clearSearch: () => requestSearch(''), doSearch: requestSearch, + searchField: 'name', addFilters: addFilters, filterModel: filterModel, setFilterModel: setFilterModel, diff --git a/sippy-ng/src/releases/PayloadStreamsTable.js b/sippy-ng/src/releases/PayloadStreamsTable.js index d3470faab..a4cb9a581 100644 --- a/sippy-ng/src/releases/PayloadStreamsTable.js +++ b/sippy-ng/src/releases/PayloadStreamsTable.js @@ -248,6 +248,7 @@ function PayloadStreamsTable(props) { columns: columns, clearSearch: () => requestSearch(''), doSearch: requestSearch, + searchField: 'release_tag', addFilters: addFilters, filterModel: filterModel, setFilterModel: setFilterModel, diff --git a/sippy-ng/src/releases/PayloadTestFailures.js b/sippy-ng/src/releases/PayloadTestFailures.js index 5b7ef0ac0..4773972e1 100644 --- a/sippy-ng/src/releases/PayloadTestFailures.js +++ b/sippy-ng/src/releases/PayloadTestFailures.js @@ -231,6 +231,7 @@ function PayloadTestFailures(props) { columns: columns, clearSearch: () => requestSearch(''), doSearch: requestSearch, + searchField: 'name', addFilters: addFilters, filterModel: filterModel, setFilterModel: setFilterModel, diff --git a/sippy-ng/src/releases/ReleasePayloadJobRuns.js b/sippy-ng/src/releases/ReleasePayloadJobRuns.js index 1aaf8fb28..047eb4d4a 100644 --- a/sippy-ng/src/releases/ReleasePayloadJobRuns.js +++ b/sippy-ng/src/releases/ReleasePayloadJobRuns.js @@ -343,6 +343,7 @@ function ReleasePayloadJobRuns(props) { columns: columns, clearSearch: () => requestSearch(''), doSearch: requestSearch, + searchField: 'release_tag', addFilters: addFilters, filterModel: filterModel, setFilterModel: setFilterModel, diff --git a/sippy-ng/src/releases/ReleasePayloadPullRequests.js b/sippy-ng/src/releases/ReleasePayloadPullRequests.js index 220799434..a304adf45 100644 --- a/sippy-ng/src/releases/ReleasePayloadPullRequests.js +++ b/sippy-ng/src/releases/ReleasePayloadPullRequests.js @@ -197,6 +197,7 @@ function ReleasePayloadPullRequests(props) { columns: columns, clearSearch: () => requestSearch(''), doSearch: requestSearch, + searchField: 'release_tag', addFilters: addFilters, filterModel: filterModel, setFilterModel: setFilterModel, diff --git a/sippy-ng/src/releases/ReleasePayloadTable.js b/sippy-ng/src/releases/ReleasePayloadTable.js index 46eb540c3..4920d9f6a 100644 --- a/sippy-ng/src/releases/ReleasePayloadTable.js +++ b/sippy-ng/src/releases/ReleasePayloadTable.js @@ -445,6 +445,7 @@ function ReleasePayloadTable(props) { columns: columns, clearSearch: () => requestSearch(''), doSearch: requestSearch, + searchField: 'release_tag', addFilters: addFilters, filterModel: filterModel, setFilterModel: setFilterModelWithConversion, diff --git a/sippy-ng/src/repositories/RepositoriesTable.js b/sippy-ng/src/repositories/RepositoriesTable.js index 9d57eceaf..8851d3ccc 100644 --- a/sippy-ng/src/repositories/RepositoriesTable.js +++ b/sippy-ng/src/repositories/RepositoriesTable.js @@ -328,6 +328,7 @@ function RepositoriesTable(props) { componentsProps={{ toolbar: { doSearch: requestSearch, + searchField: 'repo', clearSearch: () => requestSearch(''), views: gridView.views, view: view, diff --git a/sippy-ng/src/tests/FeatureGates.js b/sippy-ng/src/tests/FeatureGates.js index cce14f9c8..d268aeb9e 100644 --- a/sippy-ng/src/tests/FeatureGates.js +++ b/sippy-ng/src/tests/FeatureGates.js @@ -403,6 +403,7 @@ export default function FeatureGates(props) { columns: columns, clearSearch: () => requestSearch(''), doSearch: requestSearch, + searchField: 'feature_gate', addFilters: (m) => addFilters(m), filterModel: filterModel, setFilterModel: setFilterModel, diff --git a/sippy-ng/src/tests/TestTable.js b/sippy-ng/src/tests/TestTable.js index 734ef9349..8e4c4eed4 100644 --- a/sippy-ng/src/tests/TestTable.js +++ b/sippy-ng/src/tests/TestTable.js @@ -1003,6 +1003,12 @@ function TestTable(props) { ]) const requestSearch = (searchValue) => { + const existingFilter = filterModel.items.find( + (f) => f.columnField === 'name' && f.operatorValue === 'contains' + ) + if (existingFilter && existingFilter.value === searchValue) { + return + } setSearching(true) const newItems = filterModel.items.filter((f) => f.columnField !== 'name') newItems.push({ @@ -1123,6 +1129,7 @@ function TestTable(props) { columns: gridView.filterColumns, clearSearch: () => requestSearch(''), doSearch: requestSearch, + searchField: 'name', period: period, selectPeriod: setPeriod, addFilters: addFilters, From 9ca19ddfa0571fedd2dcbfba949ebab5f9277385 Mon Sep 17 00:00:00 2001 From: openshift-trt Date: Wed, 1 Jul 2026 15:39:17 +0000 Subject: [PATCH 3/4] TRT-2764: Fix double-search stuck loading and search bar repopulation Two fixes in GridToolbar: 1. Remove onBlur handler from search TextField to prevent double-trigger when clicking the search icon (onBlur fires before onClick, causing two requestSearch calls that can race with state updates and leave isSearching stuck as true). 2. Only set initializedFromFilter ref when a search filter is actually found, so the search bar gets repopulated from URL params on page refresh even if the filterModel is initially empty on first render. Co-Authored-By: Claude Opus 4.6 --- sippy-ng/src/datagrid/GridToolbar.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sippy-ng/src/datagrid/GridToolbar.js b/sippy-ng/src/datagrid/GridToolbar.js index 4b7652a87..46c18c5ff 100644 --- a/sippy-ng/src/datagrid/GridToolbar.js +++ b/sippy-ng/src/datagrid/GridToolbar.js @@ -56,8 +56,8 @@ export default function GridToolbar(props) { ) if (searchFilter && searchFilter.value) { setSearch(searchFilter.value) + initializedFromFilter.current = true } - initializedFromFilter.current = true }, [props.searchField, props.filterModel]) return ( @@ -112,7 +112,6 @@ export default function GridToolbar(props) { value={search} onChange={(e) => setSearch(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && props.doSearch(search)} - onBlur={() => props.doSearch(search)} placeholder="Search…" InputProps={{ endAdornment: ( From db0562a518d3d3ae3260a27428789fef015f87e2 Mon Sep 17 00:00:00 2001 From: openshift-trt Date: Thu, 2 Jul 2026 01:31:15 +0000 Subject: [PATCH 4/4] TRT-2764: Only populate quick search from single positive filter Only initialize the search bar from the URL filterModel when there is exactly one filter on the search field and it uses a positive 'contains' operator. This avoids misleadingly populating the search bar for NOT matchers or when multiple filters exist on the same column. Co-Authored-By: Claude Opus 4.6 --- sippy-ng/src/datagrid/GridToolbar.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/sippy-ng/src/datagrid/GridToolbar.js b/sippy-ng/src/datagrid/GridToolbar.js index 46c18c5ff..f96889333 100644 --- a/sippy-ng/src/datagrid/GridToolbar.js +++ b/sippy-ng/src/datagrid/GridToolbar.js @@ -50,12 +50,15 @@ export default function GridToolbar(props) { ) { return } - const searchFilter = props.filterModel.items.find( - (f) => - f.columnField === props.searchField && f.operatorValue === 'contains' + const filtersForField = props.filterModel.items.filter( + (f) => f.columnField === props.searchField ) - if (searchFilter && searchFilter.value) { - setSearch(searchFilter.value) + if (filtersForField.length !== 1) { + return + } + const filter = filtersForField[0] + if (filter.operatorValue === 'contains' && filter.value) { + setSearch(filter.value) initializedFromFilter.current = true } }, [props.searchField, props.filterModel])