From 11693aa9be4cea3cb436f4783b2c299cd54eb905 Mon Sep 17 00:00:00 2001 From: Olivier Giorgis Date: Tue, 10 Jun 2025 09:40:50 +0200 Subject: [PATCH 1/3] feat: add materialUI lib --- package.json | 6 ++- yarn.lock | 130 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 130 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index f1d5ede0870..3652a6e3952 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,8 @@ "@fortawesome/free-regular-svg-icons": "6.7.2", "@fortawesome/free-solid-svg-icons": "6.7.2", "@fortawesome/react-fontawesome": "0.2.2", + "@mui/material": "7.1.1", + "@mui/styled-engine-sc": "npm:@mui/styled-engine-sc@latest", "@types/react": "*", "@types/react-dom": "*", "ajv": "8.17.1", @@ -70,7 +72,6 @@ }, "devDependencies": { "@babel/core": "7.26.10", - "@babel/eslint-parser": "7.25.9", "@babel/eslint-parser": "7.26.10", "@babel/plugin-proposal-class-properties": "7.18.6", "@babel/plugin-syntax-dynamic-import": "7.8.3", @@ -135,6 +136,7 @@ "test:watch": "node ./node_modules/jest/bin/jest --watch" }, "resolutions": { - "cacache": "19.0.1" + "cacache": "19.0.1", + "@mui/styled-engine": "npm:@mui/styled-engine-sc@latest" } } diff --git a/yarn.lock b/yarn.lock index b56ad159c7e..401e1c48ade 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1015,6 +1015,11 @@ dependencies: regenerator-runtime "^0.14.0" +"@babel/runtime@^7.27.1", "@babel/runtime@^7.5.5": + version "7.27.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.27.6.tgz#ec4070a04d76bae8ddbb10770ba55714a417b7c6" + integrity sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q== + "@babel/template@^7.25.9", "@babel/template@^7.26.9", "@babel/template@^7.27.0", "@babel/template@^7.3.3": version "7.27.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.0.tgz#b253e5406cc1df1c57dcd18f11760c2dbf40c0b4" @@ -1583,6 +1588,93 @@ dependencies: "@types/whatwg-streams" "^0.0.7" +"@mui/core-downloads-tracker@^7.1.1": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-7.1.1.tgz#43532ccf57be19055eb20e7802508520293cf286" + integrity sha512-yBckQs4aQ8mqukLnPC6ivIRv6guhaXi8snVl00VtyojBbm+l6VbVhyTSZ68Abcx7Ah8B+GZhrB7BOli+e+9LkQ== + +"@mui/material@7.1.1": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-7.1.1.tgz#5f75b25936925be14cb34abe0489cda82a6f8413" + integrity sha512-mTpdmdZCaHCGOH3SrYM41+XKvNL0iQfM9KlYgpSjgadXx/fEKhhvOktxm8++Xw6FFeOHoOiV+lzOI8X1rsv71A== + dependencies: + "@babel/runtime" "^7.27.1" + "@mui/core-downloads-tracker" "^7.1.1" + "@mui/system" "^7.1.1" + "@mui/types" "^7.4.3" + "@mui/utils" "^7.1.1" + "@popperjs/core" "^2.11.8" + "@types/react-transition-group" "^4.4.12" + clsx "^2.1.1" + csstype "^3.1.3" + prop-types "^15.8.1" + react-is "^19.1.0" + react-transition-group "^4.4.5" + +"@mui/private-theming@^7.1.1": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-7.1.1.tgz#c2ecc57a9b97fbfdd850430de500c42a0f2571fe" + integrity sha512-M8NbLUx+armk2ZuaxBkkMk11ultnWmrPlN0Xe3jUEaBChg/mcxa5HWIWS1EE4DF36WRACaAHVAvyekWlDQf0PQ== + dependencies: + "@babel/runtime" "^7.27.1" + "@mui/utils" "^7.1.1" + prop-types "^15.8.1" + +"@mui/styled-engine-sc@npm:@mui/styled-engine-sc@latest": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@mui/styled-engine-sc/-/styled-engine-sc-7.1.1.tgz#44fb74e14f36a091a37b64da0cab5f2678dd1367" + integrity sha512-wUh1/aUMLQ1JAD33oL+ZFdx97JB8On1XLFtpsllJR5lNNMAkeLKj+ZDRB4Bm2VqPgGMuv3aVYFYtlJR2FFg73A== + dependencies: + "@babel/runtime" "^7.27.1" + "@types/hoist-non-react-statics" "^3.3.6" + csstype "^3.1.3" + hoist-non-react-statics "^3.3.2" + prop-types "^15.8.1" + +"@mui/styled-engine@^7.1.1", "@mui/styled-engine@npm:@mui/styled-engine-sc@latest": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@mui/styled-engine-sc/-/styled-engine-sc-7.1.1.tgz#44fb74e14f36a091a37b64da0cab5f2678dd1367" + integrity sha512-wUh1/aUMLQ1JAD33oL+ZFdx97JB8On1XLFtpsllJR5lNNMAkeLKj+ZDRB4Bm2VqPgGMuv3aVYFYtlJR2FFg73A== + dependencies: + "@babel/runtime" "^7.27.1" + "@types/hoist-non-react-statics" "^3.3.6" + csstype "^3.1.3" + hoist-non-react-statics "^3.3.2" + prop-types "^15.8.1" + +"@mui/system@^7.1.1": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-7.1.1.tgz#eff52e597b0bfed8ecf2e973f4575ef737430727" + integrity sha512-Kj1uhiqnj4Zo7PDjAOghtXJtNABunWvhcRU0O7RQJ7WOxeynoH6wXPcilphV8QTFtkKaip8EiNJRiCD+B3eROA== + dependencies: + "@babel/runtime" "^7.27.1" + "@mui/private-theming" "^7.1.1" + "@mui/styled-engine" "^7.1.1" + "@mui/types" "^7.4.3" + "@mui/utils" "^7.1.1" + clsx "^2.1.1" + csstype "^3.1.3" + prop-types "^15.8.1" + +"@mui/types@^7.4.3": + version "7.4.3" + resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.4.3.tgz#b205ee3404db0478cd93227fc21967e2cb8630fe" + integrity sha512-2UCEiK29vtiZTeLdS2d4GndBKacVyxGvReznGXGr+CzW/YhjIX+OHUdCIczZjzcRAgKBGmE9zCIgoV9FleuyRQ== + dependencies: + "@babel/runtime" "^7.27.1" + +"@mui/utils@^7.1.1": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-7.1.1.tgz#de315ec45ac9e16c637dcc2b32cd7912edb4e234" + integrity sha512-BkOt2q7MBYl7pweY2JWwfrlahhp+uGLR8S+EhiyRaofeRYUWL2YKbSGQvN4hgSN1i8poN0PaUiii1kEMrchvzg== + dependencies: + "@babel/runtime" "^7.27.1" + "@mui/types" "^7.4.3" + "@types/prop-types" "^15.7.14" + clsx "^2.1.1" + prop-types "^15.8.1" + react-is "^19.1.0" + "@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": version "5.1.1-v1" resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129" @@ -1715,6 +1807,11 @@ qs "^6.10.1" url-parse "^1.5.3" +"@popperjs/core@^2.11.8": + version "2.11.8" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" + integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== + "@puppeteer/browsers@2.7.1": version "2.7.1" resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-2.7.1.tgz#6df07e95d8e22239b77599f3ceaef4041b933e62" @@ -2042,7 +2139,7 @@ dependencies: "@types/node" "*" -"@types/hoist-non-react-statics@^3.3.1": +"@types/hoist-non-react-statics@^3.3.1", "@types/hoist-non-react-statics@^3.3.6": version "3.3.6" resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.6.tgz#6bba74383cdab98e8db4e20ce5b4a6b98caed010" integrity sha512-lPByRJUer/iN/xa4qpyL0qmL11DqNW81iU/IG1S3uvRUq4oKagz8VCxZjiWkumgt66YT3vOdDgZ0o32sGKtCEw== @@ -2129,6 +2226,11 @@ dependencies: undici-types "~6.20.0" +"@types/prop-types@^15.7.14": + version "15.7.15" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.15.tgz#e6e5a86d602beaca71ce5163fadf5f95d70931c7" + integrity sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw== + "@types/qs@*": version "6.9.18" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.18.tgz#877292caa91f7c1b213032b34626505b746624c2" @@ -2144,6 +2246,11 @@ resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.0.4.tgz#bedba97f9346bd4c0fe5d39e689713804ec9ac89" integrity sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg== +"@types/react-transition-group@^4.4.12": + version "4.4.12" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.12.tgz#b5d76568485b02a307238270bfe96cb51ee2a044" + integrity sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w== + "@types/react@*": version "19.0.12" resolved "https://registry.yarnpkg.com/@types/react/-/react-19.0.12.tgz#338b3f7854adbb784be454b3a83053127af96bd3" @@ -3400,7 +3507,7 @@ clsx@^1.0.4: resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== -clsx@^2.0.0: +clsx@^2.0.0, clsx@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== @@ -3772,7 +3879,7 @@ cssstyle@^2.3.0: dependencies: cssom "~0.3.6" -csstype@3.1.3, csstype@^3.0.2: +csstype@3.1.3, csstype@^3.0.2, csstype@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== @@ -4170,7 +4277,7 @@ dom-helpers@^3.4.0: dependencies: "@babel/runtime" "^7.1.2" -dom-helpers@^5.1.3: +dom-helpers@^5.0.1, dom-helpers@^5.1.3: version "5.2.1" resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== @@ -8564,6 +8671,11 @@ react-is@^18.0.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== +react-is@^19.1.0: + version "19.1.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-19.1.0.tgz#805bce321546b7e14c084989c77022351bbdd11b" + integrity sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg== + react-lazylog@4.5.3: version "4.5.3" resolved "https://registry.yarnpkg.com/react-lazylog/-/react-lazylog-4.5.3.tgz#289e24995b5599e75943556ac63f5e2c04d0001e" @@ -8725,6 +8837,16 @@ react-transition-group@^3.0.0: prop-types "^15.6.2" react-lifecycles-compat "^3.0.4" +react-transition-group@^4.4.5: + version "4.4.5" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" + integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g== + dependencies: + "@babel/runtime" "^7.5.5" + dom-helpers "^5.0.1" + loose-envify "^1.4.0" + prop-types "^15.6.2" + react-virtualized@^9.21.0: version "9.22.6" resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-9.22.6.tgz#3ae2aa69eca61cf3af332e2f9d6b4aa5638786d5" From 2c770ec50b3ea3cd800a3d86ca1f8b3173c04093 Mon Sep 17 00:00:00 2001 From: Olivier Giorgis Date: Tue, 10 Jun 2025 13:42:08 +0200 Subject: [PATCH 2/3] feat: add mui autocomplete checkboxes for product filters --- ui/css/react-table.css | 5 +++ ui/intermittent-failures/MainView.jsx | 54 ++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/ui/css/react-table.css b/ui/css/react-table.css index d417fa8f8b0..805f2103380 100644 --- a/ui/css/react-table.css +++ b/ui/css/react-table.css @@ -504,3 +504,8 @@ -ms-user-select: none; user-select: none; } + +.ReactTable .MuiAutocomplete-inputRoot .MuiOutlinedInput-input { + border: none; + height: 1em; +} diff --git a/ui/intermittent-failures/MainView.jsx b/ui/intermittent-failures/MainView.jsx index 2dad5b5fe3c..6a73edf7ff2 100644 --- a/ui/intermittent-failures/MainView.jsx +++ b/ui/intermittent-failures/MainView.jsx @@ -3,6 +3,9 @@ import { Row, Col, Breadcrumb, BreadcrumbItem } from 'reactstrap'; import PropTypes from 'prop-types'; import moment from 'moment'; import ReactTable from 'react-table-6'; +import Checkbox from '@mui/material/Checkbox'; +import TextField from '@mui/material/TextField'; +import Autocomplete from '@mui/material/Autocomplete'; import { bugsEndpoint } from '../helpers/url'; import { setUrlParam, getUrlParam } from '../helpers/location'; @@ -32,6 +35,7 @@ const MainView = (props) => { updateAppState, } = props; + const [selectedProduct, setSelectedProduct] = React.useState([]); const textFilter = (filter, row) => { if (getUrlParam(filter.id) !== filter.value) { setUrlParam(filter.id, filter.value); @@ -75,7 +79,46 @@ const MainView = (props) => { Header: 'Product', accessor: 'product', maxWidth: 100, - filterMethod: (filter, row) => textFilter(filter, row), + filterMethod: (filter, row) => { + const regex = RegExp(filter.value.join('|'), 'i'); + if (regex.test(row.product)) { + return row; + } + }, + Filter: ({ onChange }) => { + return ( + d.product))]} + onChange={(_event, values) => { + setUrlParam('product', values); + onChange(values); + }} + limitTags={2} + disableCloseOnSelect + defaultValue={selectedProduct} + style={{ + width: '20em', + }} + renderOption={(props, option, { selected }) => { + const { key, ...optionProps } = props; + return ( +
  • + + {option} +
  • + ); + }} + renderInput={(params) => ( + + )} + /> + ); + }, }, { Header: 'Component', @@ -128,7 +171,14 @@ const MainView = (props) => { for (const header of ['product', 'component', 'summary', 'whiteboard']) { const param = getUrlParam(header); if (param) { - filters.push({ id: header, value: getUrlParam(header) }); + if (header === 'product') { + filters.push({ id: header, value: param.split(',') }); + if (selectedProduct.length === 0) { + setSelectedProduct(param.split(',')); + } + } else { + filters.push({ id: header, value: param }); + } } } return filters; From 01fcbe0e26006d493d8cbf46e5cf1a5838520922 Mon Sep 17 00:00:00 2001 From: Olivier Giorgis Date: Thu, 12 Jun 2025 16:23:00 +0200 Subject: [PATCH 3/3] feat: add mui autocomplete checkboxes for component filter --- ui/css/react-table.css | 4 + ui/intermittent-failures/MainView.jsx | 124 +++++++++++++++++--------- 2 files changed, 87 insertions(+), 41 deletions(-) diff --git a/ui/css/react-table.css b/ui/css/react-table.css index 805f2103380..3ecc6beb997 100644 --- a/ui/css/react-table.css +++ b/ui/css/react-table.css @@ -505,6 +505,10 @@ user-select: none; } +.ReactTable .MuiAutocomplete-inputRoot { + max-height: 2em; +} + .ReactTable .MuiAutocomplete-inputRoot .MuiOutlinedInput-input { border: none; height: 1em; diff --git a/ui/intermittent-failures/MainView.jsx b/ui/intermittent-failures/MainView.jsx index 6a73edf7ff2..6de670a8b21 100644 --- a/ui/intermittent-failures/MainView.jsx +++ b/ui/intermittent-failures/MainView.jsx @@ -6,6 +6,7 @@ import ReactTable from 'react-table-6'; import Checkbox from '@mui/material/Checkbox'; import TextField from '@mui/material/TextField'; import Autocomplete from '@mui/material/Autocomplete'; +import Popper from '@mui/material/Popper'; import { bugsEndpoint } from '../helpers/url'; import { setUrlParam, getUrlParam } from '../helpers/location'; @@ -21,6 +22,16 @@ import withView from './View'; import Layout from './Layout'; import DateRangePicker from './DateRangePicker'; +const CustomPopper = (props) => { + return ( + + ); +}; + const MainView = (props) => { const { graphData, @@ -35,7 +46,10 @@ const MainView = (props) => { updateAppState, } = props; - const [selectedProduct, setSelectedProduct] = React.useState([]); + const [selectedFilter, setSelectedFilter] = React.useState({ + product: [], + component: [], + }); const textFilter = (filter, row) => { if (getUrlParam(filter.id) !== filter.value) { setUrlParam(filter.id, filter.value); @@ -47,6 +61,49 @@ const MainView = (props) => { } }; + const autoCompleteFilter = ({ column, onChange }) => { + const options = [...new Set(tableData.map((d) => d[column.id]))]; + options.sort(); + return ( + { + setUrlParam(column.id, values); + onChange(values); + setSelectedFilter({ ...selectedFilter, [column.id]: values }); + }} + disableCloseOnSelect + defaultValue={selectedFilter[column.id]} + fullWidth + renderOption={(props, option, { selected }) => { + const { key, ...optionProps } = props; + return ( +
  • + + {option} +
  • + ); + }} + renderInput={(params) => ( + + )} + /> + ); + }; + const columns = [ { Header: 'Bug', @@ -80,51 +137,28 @@ const MainView = (props) => { accessor: 'product', maxWidth: 100, filterMethod: (filter, row) => { - const regex = RegExp(filter.value.join('|'), 'i'); - if (regex.test(row.product)) { - return row; + if (filter.value) { + const regex = RegExp(filter.value.join('|'), 'i'); + if (regex.test(row.product)) { + return row; + } } }, - Filter: ({ onChange }) => { - return ( - d.product))]} - onChange={(_event, values) => { - setUrlParam('product', values); - onChange(values); - }} - limitTags={2} - disableCloseOnSelect - defaultValue={selectedProduct} - style={{ - width: '20em', - }} - renderOption={(props, option, { selected }) => { - const { key, ...optionProps } = props; - return ( -
  • - - {option} -
  • - ); - }} - renderInput={(params) => ( - - )} - /> - ); - }, + Filter: autoCompleteFilter, }, { Header: 'Component', accessor: 'component', maxWidth: 100, - filterMethod: (filter, row) => textFilter(filter, row), + filterMethod: (filter, row) => { + if (filter.value) { + const regex = RegExp(filter.value.join('|'), 'i'); + if (regex.test(row.component)) { + return row; + } + } + }, + Filter: autoCompleteFilter, }, { Header: 'Summary', @@ -173,8 +207,16 @@ const MainView = (props) => { if (param) { if (header === 'product') { filters.push({ id: header, value: param.split(',') }); - if (selectedProduct.length === 0) { - setSelectedProduct(param.split(',')); + if (selectedFilter.product.length === 0) { + setSelectedFilter({ ...selectedFilter, product: param.split(',') }); + } + } else if (header === 'component') { + filters.push({ id: header, value: param.split(',') }); + if (selectedFilter.component.length === 0) { + setSelectedFilter({ + ...selectedFilter, + component: param.split(','), + }); } } else { filters.push({ id: header, value: param });