@@ -15,12 +15,14 @@ import {
1515 GridRenderCellParams ,
1616 GridTreeNodeWithRender ,
1717} from "@mui/x-data-grid" ;
18+ import CopyLink from "components/common/CopyLink" ;
1819import LoadingPage from "components/common/LoadingPage" ;
1920import RegexButton from "components/common/RegexButton" ;
2021import { durationDisplay } from "components/common/TimeUtils" ;
2122import dayjs from "dayjs" ;
2223import isoWeek from "dayjs/plugin/isoWeek" ;
2324import ReactECharts from "echarts-for-react" ;
25+ import { encodeParams } from "lib/GeneralUtils" ;
2426import _ from "lodash" ;
2527import { useRouter } from "next/router" ;
2628import { useEffect , useRef , useState } from "react" ;
@@ -857,6 +859,7 @@ export default function Page() {
857859 const fileInputRef = useRef < HTMLInputElement > ( null ) ;
858860 const jobInputRef = useRef < HTMLInputElement > ( null ) ;
859861 const labelInputRef = useRef < HTMLInputElement > ( null ) ;
862+ const [ baseUrl , setBaseUrl ] = useState < string > ( "" ) ;
860863
861864 // Keep input fields in sync when filters are set programmatically
862865 useEffect ( ( ) => {
@@ -893,10 +896,24 @@ export default function Page() {
893896 } , [ commitMetadata , headShaIndex ] ) ;
894897
895898 useEffect ( ( ) => {
896- if ( router . query . label ) {
897- setLabelFilter ( router . query . label as string ) ;
898- }
899- } , [ router . query . label ] ) ;
899+ // Sync filters from the router query params in one effect to avoid
900+ // repeating similar hooks. Only update when the specific query keys
901+ // are present.
902+ const q = router . query ;
903+ if ( q . label ) setLabelFilter ( q . label as string ) ;
904+ if ( q . job ) setJobFilter ( q . job as string ) ;
905+ if ( q . file ) setFileFilter ( q . file as string ) ;
906+
907+ if ( q . labelRegex !== undefined ) setLabelRegex ( q . labelRegex === "true" ) ;
908+ if ( q . fileRegex !== undefined ) setFileRegex ( q . fileRegex === "true" ) ;
909+ if ( q . jobRegex !== undefined ) setJobRegex ( q . jobRegex === "true" ) ;
910+
911+ setBaseUrl (
912+ `${ window . location . protocol } //${
913+ window . location . host
914+ } ${ router . asPath . replace ( / \? .+ / , "" ) } `
915+ ) ;
916+ } , [ router . query ] ) ;
900917
901918 if ( ! router . isReady ) {
902919 return < LoadingPage /> ;
@@ -912,7 +929,21 @@ export default function Page() {
912929
913930 return (
914931 < Stack spacing = { 4 } >
915- < Typography variant = "h4" > Test Reports</ Typography >
932+ < Stack direction = "row" spacing = { 2 } >
933+ < Typography variant = "h4" > Test Reports</ Typography >
934+ { /* Permalink */ }
935+ < CopyLink
936+ textToCopy = { `${ baseUrl } ?${ encodeParams ( {
937+ file : fileFilter ,
938+ job : jobFilter ,
939+ label : labelFilter ,
940+ fileRegex : fileRegex ? "true" : "false" ,
941+ jobRegex : jobRegex ? "true" : "false" ,
942+ labelRegex : labelRegex ? "true" : "false" ,
943+ } ) } `}
944+ />
945+ </ Stack >
946+
916947 < Stack spacing = { 2 } >
917948 < Typography variant = "body1" >
918949 This provides insights into the test files executed over recent
0 commit comments