1313
1414import { useEffect , useRef } from 'react' ;
1515
16+ import { useQueryStates } from 'nuqs' ;
17+
1618import { ProfileTypesResponse } from '@parca/client' ;
1719import { selectAutoQuery , setAutoQuery , useAppDispatch , useAppSelector } from '@parca/store' ;
18- import { type NavigateFunction } from '@parca/utilities' ;
1920
20- import { ProfileSelectionFromParams , SuffixParams } from '..' ;
21+ import { ProfileSelectionFromParams } from '..' ;
2122import { QuerySelection } from '../ProfileSelector' ;
2223import { constructProfileName } from '../ProfileTypeSelector' ;
24+ import { boolParam , stringParam } from '../hooks/urlParsers' ;
25+ import { useDashboardItems } from '../hooks/useDashboardItems' ;
2326
2427interface Props {
2528 selectedProfileName : string ;
2629 profileTypesData : ProfileTypesResponse | undefined ;
2730 setProfileName : ( name : string ) => void ;
2831 setQueryExpression : ( ) => void ;
2932 querySelection : QuerySelection ;
30- navigateTo : NavigateFunction ;
3133 loading : boolean ;
3234 defaultProfileType ?: string ;
3335}
@@ -38,18 +40,40 @@ export const useAutoQuerySelector = ({
3840 setProfileName,
3941 setQueryExpression,
4042 querySelection,
41- navigateTo,
4243 loading,
4344 defaultProfileType,
4445} : Props ) : void => {
4546 const autoQuery = useAppSelector ( selectAutoQuery ) ;
4647 const dispatch = useAppDispatch ( ) ;
47- const queryParams = new URLSearchParams ( location . search ) ;
48- const compareA = queryParams . get ( 'compare_a' ) ;
49- const compareB = queryParams . get ( 'compare_b' ) ;
50- const comparing = compareA === 'true' || compareB === 'true' ;
51- const expressionA = queryParams . get ( 'expression_a' ) ;
52- const expressionB = queryParams . get ( 'expression_b' ) ;
48+
49+ const { setDashboardItems} = useDashboardItems ( ) ;
50+
51+ const [ compareState , setCompareParams ] = useQueryStates (
52+ {
53+ compare_a : boolParam ,
54+ compare_b : boolParam ,
55+ expression_a : stringParam ,
56+ from_a : stringParam ,
57+ to_a : stringParam ,
58+ time_selection_a : stringParam ,
59+ sum_by_a : stringParam ,
60+ merge_from_a : stringParam ,
61+ merge_to_a : stringParam ,
62+ selection_a : stringParam ,
63+ expression_b : stringParam ,
64+ from_b : stringParam ,
65+ to_b : stringParam ,
66+ time_selection_b : stringParam ,
67+ sum_by_b : stringParam ,
68+ search_string : stringParam ,
69+ } ,
70+ { history : 'replace' }
71+ ) ;
72+
73+ // Read compare params through nuqs (not location.search) to stay in sync
74+ const comparing = compareState . compare_a === true || compareState . compare_b === true ;
75+ const expressionA = compareState . expression_a ;
76+ const expressionB = compareState . expression_b ;
5377
5478 // Track if we've already set up compare mode to prevent infinite loops
5579 const hasSetupCompareMode = useRef ( false ) ;
@@ -64,13 +88,7 @@ export const useAutoQuerySelector = ({
6488 // 2. expressionA exists
6589 // 3. expressionB doesn't exist yet (meaning we need to set it up)
6690 // 4. We haven't already set it up in this session
67- if (
68- comparing &&
69- expressionA !== null &&
70- expressionA !== undefined &&
71- expressionB === null &&
72- ! hasSetupCompareMode . current
73- ) {
91+ if ( comparing && expressionA !== null && expressionB === null && ! hasSetupCompareMode . current ) {
7492 if ( querySelection . expression === undefined ) {
7593 return ;
7694 }
@@ -87,42 +105,46 @@ export const useAutoQuerySelector = ({
87105 sumBy : querySelection . sumBy ,
88106 } ;
89107
90- const sumBy = queryA . sumBy ?. join ( ',' ) ;
108+ const sumBy = queryA . sumBy ?. join ( ',' ) ?? null ;
109+
110+ const mergeFromA = profileA != null ? profileA . HistoryParams ( ) . merge_from ?. toString ( ) : null ;
111+ const mergeToA = profileA != null ? profileA . HistoryParams ( ) . merge_to ?. toString ( ) : null ;
112+ const selectionA = profileA != null ? profileA . HistoryParams ( ) . selection ?. toString ( ) : null ;
113+
114+ hasSetupCompareMode . current = true ;
91115
92- let compareQuery : Record < string , string > = {
93- compare_a : 'true' ,
116+ // Set all compare params atomically via nuqs
117+ void setCompareParams ( {
118+ compare_a : true ,
119+ compare_b : true ,
94120 expression_a : queryA . expression ,
95121 from_a : queryA . from . toString ( ) ,
96122 to_a : queryA . to . toString ( ) ,
97123 time_selection_a : queryA . timeSelection ,
98-
99- compare_b : 'true' ,
124+ sum_by_a : sumBy ,
125+ merge_from_a : mergeFromA ,
126+ merge_to_a : mergeToA ,
127+ selection_a : selectionA ,
100128 expression_b : queryA . expression ,
101129 from_b : queryA . from . toString ( ) ,
102130 to_b : queryA . to . toString ( ) ,
103131 time_selection_b : queryA . timeSelection ,
104- } ;
105-
106- if ( sumBy != null ) {
107- compareQuery . sum_by_a = sumBy ;
108- compareQuery . sum_by_b = sumBy ;
109- }
110-
111- if ( profileA != null ) {
112- compareQuery = {
113- ...SuffixParams ( profileA . HistoryParams ( ) , '_a' ) ,
114- ...compareQuery ,
115- } ;
116- }
117-
118- hasSetupCompareMode . current = true ;
119- void navigateTo ( '/' , {
120- ...compareQuery ,
121- search_string : '' ,
122- dashboard_items : [ 'flamegraph' ] ,
132+ sum_by_b : sumBy ,
133+ search_string : null ,
123134 } ) ;
135+
136+ setDashboardItems ( [ 'flamegraph' ] ) ;
124137 }
125- } , [ comparing , querySelection , navigateTo , expressionA , expressionB , dispatch , loading ] ) ;
138+ } , [
139+ comparing ,
140+ querySelection ,
141+ expressionA ,
142+ expressionB ,
143+ dispatch ,
144+ loading ,
145+ setCompareParams ,
146+ setDashboardItems ,
147+ ] ) ;
126148
127149 // Effect to load some initial data on load when is no selection
128150 useEffect ( ( ) => {
0 commit comments