Skip to content

Commit 064dbaa

Browse files
authored
Merge pull request #4 from stbenjam/component-query-param
Add query parameter filtering support to Regressed Tests modal DataGrid tables
2 parents 7b87643 + e6cc96b commit 064dbaa

12 files changed

+651
-35
lines changed

sippy-ng/src/component_readiness/ComponentReadiness.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,9 @@ export default function ComponentReadiness(props) {
394394
'regressedModalPage',
395395
'regressedModalTestRow',
396396
'regressedModalTestPage',
397+
'regressedModalFilters',
398+
'regressedModalTestFilters',
399+
'triageFilters',
397400
'searchComponent',
398401
'searchColumn',
399402
'searchRow',

sippy-ng/src/component_readiness/RegressedTestsModal.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { Box, Button, Grid, Tab, Tabs, Typography } from '@mui/material'
21
import {
32
ArrayParam,
43
NumberParam,
54
StringParam,
65
useQueryParam,
76
useQueryParams,
87
} from 'use-query-params'
8+
import { Box, Button, Grid, Tab, Tabs, Typography } from '@mui/material'
99
import Dialog from '@mui/material/Dialog'
1010
import PropTypes from 'prop-types'
1111
import React, { Fragment } from 'react'
@@ -69,13 +69,16 @@ export default function RegressedTestsModal({
6969
regressedModalPage: NumberParam,
7070
regressedModalTestRow: NumberParam,
7171
regressedModalTestPage: NumberParam,
72+
regressedModalFilters: StringParam,
73+
regressedModalTestFilters: StringParam,
74+
triageFilters: StringParam,
7275
},
7376
{ updateType: 'replaceIn' }
7477
)
7578

7679
const handleTabChange = (event, newValue) => {
7780
setActiveTab(newValue)
78-
// The active pages and rows in the DataGrid are most likely no longer relevant when switching tabs
81+
// Reset pagination and selection when switching tabs, but keep filters
7982
setQuery(
8083
{
8184
regressedModalRow: undefined,

sippy-ng/src/component_readiness/RegressedTestsPanel.js

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1+
import { applyFilterModel } from '../datagrid/filterUtils'
12
import { CapabilitiesContext } from '../App'
23
import { CompReadyVarsContext } from './CompReadyVars'
3-
import { DataGrid, GridToolbar } from '@mui/x-data-grid'
4+
import { DataGrid } from '@mui/x-data-grid'
45
import { FileCopy } from '@mui/icons-material'
56
import { formColumnName, generateTestDetailsReportLink } from './CompReadyUtils'
67
import { NumberParam, StringParam, useQueryParam } from 'use-query-params'
78
import { Popover, Snackbar, Tooltip } from '@mui/material'
8-
import { relativeTime } from '../helpers'
9+
import { relativeTime, SafeJSONParam } from '../helpers'
910
import Alert from '@mui/material/Alert'
1011
import Button from '@mui/material/Button'
1112
import CompSeverityIcon from './CompSeverityIcon'
13+
import GridToolbar from '../datagrid/GridToolbar'
1214
import IconButton from '@mui/material/IconButton'
1315
import PropTypes from 'prop-types'
1416
import React, { Fragment, useContext } from 'react'
@@ -25,12 +27,57 @@ export default function RegressedTestsPanel(props) {
2527
NumberParam,
2628
{ updateType: 'replaceIn' }
2729
)
30+
const [filterModel = { items: [] }, setFilterModel] = useQueryParam(
31+
'regressedModalFilters',
32+
SafeJSONParam,
33+
{ updateType: 'replaceIn' }
34+
)
2835
const { expandEnvironment, views, view } = useContext(CompReadyVarsContext)
2936
const { filterVals, regressedTests, setTriageActionTaken } = props
3037
const [sortModel, setSortModel] = React.useState([
3138
{ field: 'component', sort: 'asc' },
3239
])
3340

41+
const addFilters = (filter) => {
42+
const currentFilters = filterModel.items.filter((item) => item.value !== '')
43+
44+
filter.forEach((item) => {
45+
if (item.value && item.value !== '') {
46+
currentFilters.push(item)
47+
}
48+
})
49+
setFilterModel({
50+
items: currentFilters,
51+
linkOperator: filterModel.linkOperator || 'and',
52+
})
53+
}
54+
55+
// Quick search functionality - searches test_name field
56+
const requestSearch = (searchValue) => {
57+
const currentFilters = { ...filterModel }
58+
currentFilters.items = currentFilters.items.filter(
59+
(f) => f.columnField !== 'test_name'
60+
)
61+
if (searchValue && searchValue !== '') {
62+
currentFilters.items.push({
63+
id: 99,
64+
columnField: 'test_name',
65+
operatorValue: 'contains',
66+
value: searchValue,
67+
})
68+
}
69+
setFilterModel({
70+
items: currentFilters.items,
71+
linkOperator: currentFilters.linkOperator || 'and',
72+
})
73+
}
74+
75+
// Apply client-side filtering using shared utility
76+
const filteredTests = React.useMemo(
77+
() => applyFilterModel(regressedTests, filterModel),
78+
[regressedTests, filterModel]
79+
)
80+
3481
// Helpers for copying the test ID to clipboard
3582
const [copyPopoverEl, setCopyPopoverEl] = React.useState(null)
3683
const copyPopoverOpen = Boolean(copyPopoverEl)
@@ -86,6 +133,7 @@ export default function RegressedTestsPanel(props) {
86133
field: 'triage',
87134
headerName: 'Triage',
88135
flex: 4,
136+
filterable: false,
89137
valueGetter: (params) => {
90138
if (!params.row.regression?.opened) {
91139
// For a regression we haven't yet detected:
@@ -110,30 +158,35 @@ export default function RegressedTestsPanel(props) {
110158
field: 'component',
111159
headerName: 'Component',
112160
flex: 20,
161+
autocomplete: 'component',
113162
renderCell: (param) => <div className="test-name">{param.value}</div>,
114163
},
115164
{
116165
field: 'capability',
117166
headerName: 'Capability',
118167
flex: 12,
168+
autocomplete: 'capability',
119169
renderCell: (param) => <div className="test-name">{param.value}</div>,
120170
},
121171
{
122172
field: 'test_name',
123173
headerName: 'Test Name',
124174
flex: 40,
175+
autocomplete: 'test_name',
125176
renderCell: (param) => <div className="test-name">{param.value}</div>,
126177
},
127178
{
128179
field: 'test_suite',
129180
headerName: 'Test Suite',
130181
flex: 15,
182+
autocomplete: 'test_suite',
131183
renderCell: (param) => <div className="test-name">{param.value}</div>,
132184
},
133185
{
134186
field: 'variants',
135187
headerName: 'Variants',
136188
flex: 30,
189+
filterable: false,
137190
valueGetter: (params) => {
138191
return formColumnName({ variants: params.row.variants })
139192
},
@@ -143,6 +196,7 @@ export default function RegressedTestsPanel(props) {
143196
field: 'regression',
144197
headerName: 'Regressed Since',
145198
flex: 12,
199+
filterable: false,
146200
valueGetter: (params) => {
147201
if (!params.row.regression?.opened) {
148202
// For a regression we haven't yet detected:
@@ -172,6 +226,7 @@ export default function RegressedTestsPanel(props) {
172226
field: 'last_failure',
173227
headerName: 'Last Failure',
174228
flex: 12,
229+
filterable: false,
175230
valueGetter: (params) => {
176231
if (!params.row.last_failure) {
177232
return null
@@ -192,6 +247,7 @@ export default function RegressedTestsPanel(props) {
192247
field: 'test_id',
193248
flex: 5,
194249
headerName: 'ID',
250+
filterable: false,
195251
renderCell: (params) => {
196252
return (
197253
<IconButton
@@ -211,6 +267,7 @@ export default function RegressedTestsPanel(props) {
211267
{
212268
field: 'status',
213269
headerName: 'Status',
270+
filterable: false,
214271
renderCell: (params) => (
215272
<div
216273
style={{
@@ -258,7 +315,7 @@ export default function RegressedTestsPanel(props) {
258315
sortModel={sortModel}
259316
onSortModelChange={setSortModel}
260317
components={{ Toolbar: GridToolbar }}
261-
rows={regressedTests}
318+
rows={filteredTests}
262319
columns={columns}
263320
getRowId={(row) =>
264321
row.test_id +
@@ -285,7 +342,12 @@ export default function RegressedTestsPanel(props) {
285342
componentsProps={{
286343
toolbar: {
287344
columns: columns,
288-
showQuickFilter: true,
345+
addFilters: addFilters,
346+
filterModel: filterModel,
347+
setFilterModel: setFilterModel,
348+
clearSearch: () => requestSearch(''),
349+
doSearch: requestSearch,
350+
autocompleteData: regressedTests,
289351
},
290352
}}
291353
/>

sippy-ng/src/component_readiness/TriagedRegressionTestList.js

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
import { applyFilterModel } from '../datagrid/filterUtils'
12
import { CompReadyVarsContext } from './CompReadyVars'
2-
import { DataGrid, GridToolbar } from '@mui/x-data-grid'
3+
import { DataGrid } from '@mui/x-data-grid'
34
import { generateTestDetailsReportLink } from './CompReadyUtils'
45
import { NumberParam, useQueryParam } from 'use-query-params'
5-
import { relativeTime } from '../helpers'
6+
import { relativeTime, SafeJSONParam } from '../helpers'
67
import { Tooltip, Typography } from '@mui/material'
78
import CompSeverityIcon from './CompSeverityIcon'
9+
import GridToolbar from '../datagrid/GridToolbar'
810
import PropTypes from 'prop-types'
911
import React, { Fragment, useContext } from 'react'
1012

@@ -21,18 +23,63 @@ export default function TriagedRegressionTestList(props) {
2123
NumberParam,
2224
{ updateType: 'replaceIn' }
2325
)
26+
const [filterModel = { items: [] }, setFilterModel] = useQueryParam(
27+
'regressedModalTestFilters',
28+
SafeJSONParam,
29+
{ updateType: 'replaceIn' }
30+
)
2431

2532
const [sortModel, setSortModel] = React.useState([
2633
{ field: 'component', sort: 'asc' },
2734
])
2835

36+
const addFilters = (filter) => {
37+
const currentFilters = filterModel.items.filter((item) => item.value !== '')
38+
39+
filter.forEach((item) => {
40+
if (item.value && item.value !== '') {
41+
currentFilters.push(item)
42+
}
43+
})
44+
setFilterModel({
45+
items: currentFilters,
46+
linkOperator: filterModel.linkOperator || 'and',
47+
})
48+
}
49+
50+
// Quick search functionality - searches test_name field
51+
const requestSearch = (searchValue) => {
52+
const currentFilters = { ...filterModel }
53+
currentFilters.items = currentFilters.items.filter(
54+
(f) => f.columnField !== 'test_name'
55+
)
56+
if (searchValue && searchValue !== '') {
57+
currentFilters.items.push({
58+
id: 99,
59+
columnField: 'test_name',
60+
operatorValue: 'contains',
61+
value: searchValue,
62+
})
63+
}
64+
setFilterModel({
65+
items: currentFilters.items,
66+
linkOperator: currentFilters.linkOperator || 'and',
67+
})
68+
}
69+
2970
const [triagedRegressions, setTriagedRegressions] = React.useState(
3071
props.regressions !== undefined ? props.regressions : []
3172
)
3273
const [showView, setShowView] = React.useState(
3374
props.regressions !== undefined && props.regressions.length > 0
3475
)
3576

77+
// Apply client-side filtering using shared utility
78+
const filteredRegressions = React.useMemo(
79+
() => applyFilterModel(triagedRegressions, filterModel),
80+
[triagedRegressions, filterModel]
81+
)
82+
3683
const handleTriagedRegressionGroupSelectionChanged = (data) => {
3784
let displayView = false
3885
if (data) {
@@ -58,6 +105,7 @@ export default function TriagedRegressionTestList(props) {
58105
field: 'test_name',
59106
headerName: 'Test Name',
60107
flex: 50,
108+
autocomplete: 'test_name',
61109
valueGetter: (params) => {
62110
return params.row.test_name
63111
},
@@ -67,6 +115,7 @@ export default function TriagedRegressionTestList(props) {
67115
field: 'release',
68116
headerName: 'Release',
69117
flex: 7,
118+
autocomplete: 'release',
70119
valueGetter: (params) => {
71120
return params.row.release
72121
},
@@ -76,6 +125,7 @@ export default function TriagedRegressionTestList(props) {
76125
field: 'variants',
77126
headerName: 'Variants',
78127
flex: 20,
128+
filterable: false,
79129
renderCell: (params) => (
80130
<div className="variants-list">
81131
{params.value ? params.value.sort().join('\n') : ''}
@@ -86,6 +136,7 @@ export default function TriagedRegressionTestList(props) {
86136
field: 'opened',
87137
headerName: 'Regressed Since',
88138
flex: 12,
139+
filterable: false,
89140
valueGetter: (params) => {
90141
if (!params.row.opened) {
91142
// For a regression we haven't yet detected:
@@ -104,6 +155,7 @@ export default function TriagedRegressionTestList(props) {
104155
field: 'last_failure',
105156
headerName: 'Last Failure',
106157
flex: 12,
158+
filterable: false,
107159
valueGetter: (params) => {
108160
if (!params.row.last_failure.Valid) {
109161
return null
@@ -125,6 +177,7 @@ export default function TriagedRegressionTestList(props) {
125177
{
126178
field: 'status',
127179
headerName: 'Status',
180+
filterable: false,
128181
renderHeader: () => (
129182
<Tooltip title="Status information is only available for regressions that have not rolled off the reporting window">
130183
<span>Status</span>
@@ -184,7 +237,7 @@ export default function TriagedRegressionTestList(props) {
184237
sortModel={sortModel}
185238
onSortModelChange={setSortModel}
186239
components={{ Toolbar: GridToolbar }}
187-
rows={triagedRegressions}
240+
rows={filteredRegressions}
188241
columns={columns}
189242
getRowHeight={() => 'auto'}
190243
getRowId={(row) => row.id}
@@ -205,6 +258,12 @@ export default function TriagedRegressionTestList(props) {
205258
componentsProps={{
206259
toolbar: {
207260
columns: columns,
261+
addFilters: addFilters,
262+
filterModel: filterModel,
263+
setFilterModel: setFilterModel,
264+
clearSearch: () => requestSearch(''),
265+
doSearch: requestSearch,
266+
autocompleteData: triagedRegressions,
208267
},
209268
}}
210269
/>

0 commit comments

Comments
 (0)