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 81c9e4ab71..605bf1c81b 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 1d8eea3cb8..337218a8b1 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 878b959e65..f192b15666 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 5095857009..d3470faab6 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 34b264d491..5b7ef0ac01 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 86123b7d52..1aaf8fb287 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 60794905b2..220799434d 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 a9412f6ad6..46eb540c3c 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 c25ba537b8..9d57eceaf7 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 31ac07999c..cce14f9c84 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 68fd3701ce..734ef93492 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 0252365448..105bc4f744 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 5b047b74bc..ff763650bc 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 cc8c28a423..41fbeacc54 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 602a3f640d..4b7652a875 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 363faa9f68..42bef2e807 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 605bf1c81b..2fc6a3a813 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 337218a8b1..972595dea7 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 f192b15666..96ab7f02e3 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 d3470faab6..a4cb9a581f 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 5b7ef0ac01..4773972e12 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 1aaf8fb287..047eb4d4ac 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 220799434d..a304adf452 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 46eb540c3c..4920d9f6ae 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 9d57eceaf7..8851d3ccc3 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 cce14f9c84..d268aeb9e3 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 734ef93492..8e4c4eed46 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 4b7652a875..46c18c5fff 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 46c18c5fff..f96889333f 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])