@parca/profile 0.19.156 → 0.19.157

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/GraphTooltipArrow/useGraphTooltipMetaInfo/index.d.ts.map +1 -1
  3. package/dist/GraphTooltipArrow/useGraphTooltipMetaInfo/index.js +9 -3
  4. package/dist/ProfileFlameGraph/FlameGraphArrow/ContextMenu.js +3 -1
  5. package/dist/ProfileSelector/index.js +274 -265
  6. package/dist/ProfileView/components/ActionButtons/SortByDropdown.js +3 -1
  7. package/dist/ProfileView/components/InvertCallStack/index.d.ts.map +1 -1
  8. package/dist/ProfileView/components/InvertCallStack/index.js +55 -46
  9. package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.d.ts.map +1 -1
  10. package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.js +282 -255
  11. package/dist/ProfileView/components/Toolbars/TableColumnsDropdown.d.ts.map +1 -1
  12. package/dist/ProfileView/components/Toolbars/TableColumnsDropdown.js +141 -132
  13. package/dist/ProfileView/components/ViewSelector/index.d.ts.map +1 -1
  14. package/dist/ProfileView/components/ViewSelector/index.js +49 -40
  15. package/dist/ProfileView/context/DashboardContext.d.ts.map +1 -1
  16. package/dist/ProfileView/context/DashboardContext.js +37 -28
  17. package/dist/ProfileView/hooks/useResetFlameGraphState.d.ts.map +1 -1
  18. package/dist/ProfileView/hooks/useResetFlameGraphState.js +19 -10
  19. package/dist/ProfileView/hooks/useVisualizationState.d.ts.map +1 -1
  20. package/dist/ProfileView/hooks/useVisualizationState.js +122 -98
  21. package/dist/SourceView/useSelectedLineRange.js +2 -0
  22. package/dist/Table/MoreDropdown.d.ts.map +1 -1
  23. package/dist/Table/MoreDropdown.js +40 -31
  24. package/dist/Table/TableContextMenu.d.ts.map +1 -1
  25. package/dist/Table/TableContextMenu.js +3 -1
  26. package/dist/Table/index.d.ts.map +1 -1
  27. package/dist/Table/index.js +3 -1
  28. package/dist/hooks/useColorBy.d.ts.map +1 -1
  29. package/dist/hooks/useColorBy.js +27 -18
  30. package/dist/hooks/useQueryState.d.ts.map +1 -1
  31. package/dist/hooks/useQueryState.js +11 -3
  32. package/package.json +2 -2
  33. package/src/GraphTooltipArrow/useGraphTooltipMetaInfo/index.ts +12 -3
  34. package/src/ProfileFlameGraph/FlameGraphArrow/ContextMenu.tsx +1 -1
  35. package/src/ProfileSelector/index.tsx +1 -1
  36. package/src/ProfileView/components/ActionButtons/SortByDropdown.tsx +1 -1
  37. package/src/ProfileView/components/InvertCallStack/index.tsx +4 -1
  38. package/src/ProfileView/components/Toolbars/MultiLevelDropdown.tsx +6 -3
  39. package/src/ProfileView/components/Toolbars/TableColumnsDropdown.tsx +4 -1
  40. package/src/ProfileView/components/ViewSelector/index.tsx +4 -1
  41. package/src/ProfileView/context/DashboardContext.tsx +4 -1
  42. package/src/ProfileView/hooks/useResetFlameGraphState.ts +4 -1
  43. package/src/ProfileView/hooks/useVisualizationState.ts +7 -5
  44. package/src/SourceView/useSelectedLineRange.ts +1 -1
  45. package/src/Table/MoreDropdown.tsx +4 -1
  46. package/src/Table/TableContextMenu.tsx +4 -1
  47. package/src/Table/index.tsx +4 -1
  48. package/src/hooks/useColorBy.ts +4 -1
  49. package/src/hooks/useQueryState.ts +29 -18
@@ -24,40 +24,49 @@ import { USER_PREFERENCES, useUserPreference } from '@parca/hooks';
24
24
  import { stringParam } from './urlParsers';
25
25
  export var useColorBy = function useColorBy() {
26
26
  var _ref;
27
- var $ = _c(6);
27
+ var $ = _c(7);
28
28
  var _useUserPreference = useUserPreference(USER_PREFERENCES.COLOR_BY.key),
29
29
  _useUserPreference2 = _slicedToArray(_useUserPreference, 2),
30
30
  colorByPreference = _useUserPreference2[0],
31
31
  setColorByPreference = _useUserPreference2[1];
32
- var _useQueryState = useQueryState("color_by", stringParam),
32
+ var t0;
33
+ if ($[0] === Symbol["for"]("react.memo_cache_sentinel")) {
34
+ t0 = stringParam.withOptions({
35
+ history: "push"
36
+ });
37
+ $[0] = t0;
38
+ } else {
39
+ t0 = $[0];
40
+ }
41
+ var _useQueryState = useQueryState("color_by", t0),
33
42
  _useQueryState2 = _slicedToArray(_useQueryState, 2),
34
43
  colorByRaw = _useQueryState2[0],
35
44
  setRawColorBy = _useQueryState2[1];
36
45
  var colorBy = (_ref = colorByRaw !== null && colorByRaw !== void 0 ? colorByRaw : colorByPreference) !== null && _ref !== void 0 ? _ref : "binary";
37
- var t0;
38
- if ($[0] !== setColorByPreference || $[1] !== setRawColorBy) {
39
- t0 = function t0(value) {
46
+ var t1;
47
+ if ($[1] !== setColorByPreference || $[2] !== setRawColorBy) {
48
+ t1 = function t1(value) {
40
49
  setRawColorBy(value);
41
50
  setColorByPreference(value);
42
51
  };
43
- $[0] = setColorByPreference;
44
- $[1] = setRawColorBy;
45
- $[2] = t0;
52
+ $[1] = setColorByPreference;
53
+ $[2] = setRawColorBy;
54
+ $[3] = t1;
46
55
  } else {
47
- t0 = $[2];
56
+ t1 = $[3];
48
57
  }
49
- var setColorBy = t0;
50
- var t1;
51
- if ($[3] !== colorBy || $[4] !== setColorBy) {
52
- t1 = {
58
+ var setColorBy = t1;
59
+ var t2;
60
+ if ($[4] !== colorBy || $[5] !== setColorBy) {
61
+ t2 = {
53
62
  colorBy: colorBy,
54
63
  setColorBy: setColorBy
55
64
  };
56
- $[3] = colorBy;
57
- $[4] = setColorBy;
58
- $[5] = t1;
65
+ $[4] = colorBy;
66
+ $[5] = setColorBy;
67
+ $[6] = t2;
59
68
  } else {
60
- t1 = $[5];
69
+ t2 = $[6];
61
70
  }
62
- return t1;
71
+ return t2;
63
72
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useQueryState.d.ts","sourceRoot":"","sources":["../../src/hooks/useQueryState.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAEpC,OAAO,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAC,gBAAgB,EAA8B,aAAa,EAAC,MAAM,kBAAkB,CAAC;AAM7F,UAAU,oBAAoB;IAC5B,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;CAClC;AAED,UAAU,mBAAmB;IAE3B,cAAc,EAAE,cAAc,CAAC;IAG/B,cAAc,EAAE,cAAc,CAAC;IAG/B,kBAAkB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7E,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,KAAK,IAAI,CAAC;IACrD,mBAAmB,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,gBAAgB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAG7C,WAAW,EAAE,CACX,kBAAkB,CAAC,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAC,EACtE,UAAU,CAAC,EAAE,MAAM,KAChB,IAAI,CAAC;IAGV,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAG1C,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;IAGpC,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAGhF,YAAY,EAAE,OAAO,CAAC;IAGtB,gBAAgB,EAAE,KAAK,GAAG,IAAI,CAAC;IAG/B,WAAW,EAAE,KAAK,GAAG,IAAI,CAAC;IAE1B,kBAAkB,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACnD,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC9C,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,KAAK,IAAI,CAAC;CACnD;AAED,eAAO,MAAM,aAAa,GAAI,UAAS,oBAAyB,KAAG,mBAsclE,CAAC"}
1
+ {"version":3,"file":"useQueryState.d.ts","sourceRoot":"","sources":["../../src/hooks/useQueryState.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAEpC,OAAO,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAC,gBAAgB,EAA8B,aAAa,EAAC,MAAM,kBAAkB,CAAC;AAM7F,UAAU,oBAAoB;IAC5B,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;CAClC;AAED,UAAU,mBAAmB;IAE3B,cAAc,EAAE,cAAc,CAAC;IAG/B,cAAc,EAAE,cAAc,CAAC;IAG/B,kBAAkB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7E,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,KAAK,IAAI,CAAC;IACrD,mBAAmB,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,gBAAgB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAG7C,WAAW,EAAE,CACX,kBAAkB,CAAC,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAC,EACtE,UAAU,CAAC,EAAE,MAAM,KAChB,IAAI,CAAC;IAGV,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAG1C,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;IAGpC,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAGhF,YAAY,EAAE,OAAO,CAAC;IAGtB,gBAAgB,EAAE,KAAK,GAAG,IAAI,CAAC;IAG/B,WAAW,EAAE,KAAK,GAAG,IAAI,CAAC;IAE1B,kBAAkB,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACnD,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC9C,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,KAAK,IAAI,CAAC;CACnD;AAED,eAAO,MAAM,aAAa,GAAI,UAAS,oBAAyB,KAAG,mBAidlE,CAAC"}
@@ -97,7 +97,9 @@ export var useQueryState = function useQueryState() {
97
97
  sum_by: val_0
98
98
  });
99
99
  }, [setQueryParams]);
100
- var _useNuqsQueryState = useNuqsQueryState('group_by', commaArrayParam),
100
+ var _useNuqsQueryState = useNuqsQueryState('group_by', commaArrayParam.withOptions({
101
+ history: 'replace'
102
+ })),
101
103
  _useNuqsQueryState2 = _slicedToArray(_useNuqsQueryState, 2),
102
104
  setRawGroupByParam = _useNuqsQueryState2[1];
103
105
  var setGroupByParam = useCallback(function (val_1) {
@@ -296,7 +298,8 @@ export var useQueryState = function useQueryState() {
296
298
  }
297
299
  }
298
300
 
299
- // Atomic URL update with all params at once
301
+ // Atomic URL update with all params at once. Push a history entry so the
302
+ // back button steps through profile/time selections (default is 'replace').
300
303
  void setQueryParams({
301
304
  expression: finalExpression,
302
305
  from: finalFrom,
@@ -306,6 +309,8 @@ export var useQueryState = function useQueryState() {
306
309
  merge_from: mergeFromValue,
307
310
  merge_to: mergeToValue,
308
311
  selection: selectionValue
312
+ }, {
313
+ history: 'push'
309
314
  });
310
315
  resetFlameGraphState();
311
316
  if (draftProfileType.toString() !== Query.parse(querySelection.expression).profileType().toString()) {
@@ -337,12 +342,15 @@ export var useQueryState = function useQueryState() {
337
342
  setDraftExpression(newExpression);
338
343
  }, [draftProfileName]);
339
344
 
340
- // Set ProfileSelection (auto-commits to URL immediately)
345
+ // Set ProfileSelection (auto-commits to URL immediately). Push a history
346
+ // entry so selecting a sample is a back-navigable step (default is 'replace').
341
347
  var setProfileSelection = useCallback(function (mergeFrom_0, mergeTo_0, query_0) {
342
348
  void setQueryParams({
343
349
  selection: query_0.toString(),
344
350
  merge_from: mergeFrom_0.toString(),
345
351
  merge_to: mergeTo_0.toString()
352
+ }, {
353
+ history: 'push'
346
354
  });
347
355
  }, [setQueryParams]);
348
356
  var draftParsedQuery = useMemo(function () {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parca/profile",
3
- "version": "0.19.156",
3
+ "version": "0.19.157",
4
4
  "description": "Profile viewing libraries",
5
5
  "dependencies": {
6
6
  "@floating-ui/react": "^0.27.12",
@@ -89,5 +89,5 @@
89
89
  "access": "public",
90
90
  "registry": "https://registry.npmjs.org/"
91
91
  },
92
- "gitHead": "a46796c75671cdd66351103a30b0321f8213debc"
92
+ "gitHead": "e84502e97f82660256ff814e12867002751930c6"
93
93
  }
@@ -105,11 +105,20 @@ export const useGraphTooltipMetaInfo = ({table, row}: Props): GraphTooltipMetaIn
105
105
 
106
106
  const {dashboardItems, setDashboardItems} = useDashboardItems();
107
107
 
108
- const [_unusedBuildId, setSourceBuildId] = useQueryState('source_buildid', stringParam);
108
+ const [_unusedBuildId, setSourceBuildId] = useQueryState(
109
+ 'source_buildid',
110
+ stringParam.withOptions({history: 'push'})
111
+ );
109
112
 
110
- const [_unusedFilename, setSourceFilename] = useQueryState('source_filename', stringParam);
113
+ const [_unusedFilename, setSourceFilename] = useQueryState(
114
+ 'source_filename',
115
+ stringParam.withOptions({history: 'push'})
116
+ );
111
117
 
112
- const [_unusedLine, setSourceLine] = useQueryState('source_line', stringParam);
118
+ const [_unusedLine, setSourceLine] = useQueryState(
119
+ 'source_line',
120
+ stringParam.withOptions({history: 'push'})
121
+ );
113
122
 
114
123
  const openFile = (): void => {
115
124
  setDashboardItems([dashboardItems[0], 'source']);
@@ -89,7 +89,7 @@ const ContextMenu = ({
89
89
  const {dashboardItems, setDashboardItems} = useDashboardItems();
90
90
  const [_sandwichFunctionName, setSandwichFunctionName] = useQueryState(
91
91
  'sandwich_function_name',
92
- stringParam
92
+ stringParam.withOptions({history: 'push'})
93
93
  );
94
94
 
95
95
  if (contextMenuData === null) {
@@ -113,7 +113,7 @@ const ProfileSelector = ({
113
113
  const {externalProfilerComponent, additionalMetricsGraph} = useParcaContext();
114
114
  const [queryBrowserMode, setRawQueryBrowserMode] = useNuqsQueryState(
115
115
  'query_browser_mode',
116
- stringParam
116
+ stringParam.withOptions({history: 'replace'})
117
117
  );
118
118
  const setQueryBrowserMode = useCallback(
119
119
  (mode: string | null) => {
@@ -26,7 +26,7 @@ import {useProfileViewContext} from '../../context/ProfileViewContext';
26
26
  const SortByDropdown = (): React.JSX.Element => {
27
27
  const [storeSortBy, setStoreSortBy] = useQueryState(
28
28
  'sort_by',
29
- stringParam.withDefault(FIELD_FUNCTION_NAME)
29
+ stringParam.withDefault(FIELD_FUNCTION_NAME).withOptions({history: 'push'})
30
30
  );
31
31
 
32
32
  const {compareMode} = useProfileViewContext();
@@ -21,7 +21,10 @@ import {invertCallStackParser} from '../../../hooks/urlParsers';
21
21
  import {useResetFlameGraphState} from '../../hooks/useResetFlameGraphState';
22
22
 
23
23
  const InvertCallStack = (): JSX.Element => {
24
- const [isInvert, setInvertStack] = useQueryState('invert_call_stack', invertCallStackParser);
24
+ const [isInvert, setInvertStack] = useQueryState(
25
+ 'invert_call_stack',
26
+ invertCallStackParser.withOptions({history: 'push'})
27
+ );
25
28
  const resetFlameGraphState = useResetFlameGraphState();
26
29
 
27
30
  const handleSetInvert = (value: boolean): void => {
@@ -213,11 +213,11 @@ const MultiLevelDropdown: React.FC<MultiLevelDropdownProps> = ({
213
213
  const [storeSortBy] = useQueryState('sort_by', stringParam.withDefault(FIELD_FUNCTION_NAME));
214
214
  const [colorStackLegend, setStoreColorStackLegend] = useQueryState(
215
215
  'color_stack_legend',
216
- stringParam
216
+ stringParam.withOptions({history: 'push'})
217
217
  );
218
218
  const [hiddenBinaries, setHiddenBinaries] = useQueryState(
219
219
  'hidden_binaries',
220
- hiddenBinariesParser
220
+ hiddenBinariesParser.withOptions({history: 'push'})
221
221
  );
222
222
  const {compareMode} = useProfileViewContext();
223
223
  const [colorProfileName] = useUserPreference<string>(
@@ -230,7 +230,10 @@ const MultiLevelDropdown: React.FC<MultiLevelDropdownProps> = ({
230
230
  // For non-delta profiles, like goroutines or memory, we want the profiles to be compared absolutely.
231
231
  const compareAbsoluteDefault = profileType?.delta === false;
232
232
 
233
- const [compareAbsolute, setCompareAbsolute] = useQueryState('compare_absolute', boolParam);
233
+ const [compareAbsolute, setCompareAbsolute] = useQueryState(
234
+ 'compare_absolute',
235
+ boolParam.withOptions({history: 'push'})
236
+ );
234
237
  const isCompareAbsolute = compareAbsolute ?? compareAbsoluteDefault;
235
238
 
236
239
  useEffect(() => {
@@ -33,7 +33,10 @@ interface Props {
33
33
 
34
34
  const TableColumnsDropdown = ({profileType, total, filtered}: Props): JSX.Element => {
35
35
  const {compareMode} = useProfileViewContext();
36
- const [tableColumns, setTableColumns] = useQueryState('table_columns', tableColumnsParser);
36
+ const [tableColumns, setTableColumns] = useQueryState(
37
+ 'table_columns',
38
+ tableColumnsParser.withOptions({history: 'push'})
39
+ );
37
40
 
38
41
  const columnHelper = createColumnHelper<Row>();
39
42
 
@@ -28,7 +28,10 @@ interface Props {
28
28
 
29
29
  const ViewSelector = ({profileSource}: Props): JSX.Element => {
30
30
  const {dashboardItems, setDashboardItems} = useDashboardItems();
31
- const [, setSandwichFunctionName] = useQueryState('sandwich_function_name', stringParam);
31
+ const [, setSandwichFunctionName] = useQueryState(
32
+ 'sandwich_function_name',
33
+ stringParam.withOptions({history: 'replace'})
34
+ );
32
35
  const {enableSourcesView, enableSandwichView} = useParcaContext();
33
36
 
34
37
  const allItems: Array<{
@@ -30,7 +30,10 @@ const DashboardContext = createContext<DashboardContextType | undefined>(undefin
30
30
 
31
31
  export const DashboardProvider: FC<PropsWithChildren> = ({children}) => {
32
32
  const {dashboardItems, setDashboardItems} = useDashboardItems();
33
- const [, setSandwichFunctionName] = useQueryState('sandwich_function_name', stringParam);
33
+ const [, setSandwichFunctionName] = useQueryState(
34
+ 'sandwich_function_name',
35
+ stringParam.withOptions({history: 'replace'})
36
+ );
34
37
 
35
38
  const handleClosePanel = (visualizationType: VisualizationType): void => {
36
39
  const newDashboardItems = dashboardItems.filter(item => item !== visualizationType);
@@ -16,7 +16,10 @@ import {useQueryState} from 'nuqs';
16
16
  import {stringParam} from '../../hooks/urlParsers';
17
17
 
18
18
  export const useResetFlameGraphState = (): (() => void) => {
19
- const [val, setCurPath] = useQueryState('cur_path', stringParam);
19
+ const [val, setCurPath] = useQueryState(
20
+ 'cur_path',
21
+ stringParam.withOptions({history: 'replace'})
22
+ );
20
23
 
21
24
  return () => {
22
25
  setTimeout(() => {
@@ -58,7 +58,7 @@ export const useVisualizationState = (): {
58
58
 
59
59
  const [curPathArrow, setRawCurPathArrow] = useQueryState(
60
60
  'cur_path',
61
- jsonParser<CurrentPathFrame[]>().withDefault([])
61
+ jsonParser<CurrentPathFrame[]>().withDefault([]).withOptions({history: 'push'})
62
62
  );
63
63
  const setCurPathArrow = useCallback(
64
64
  (path: CurrentPathFrame[]) => {
@@ -70,16 +70,18 @@ export const useVisualizationState = (): {
70
70
  const {colorBy, setColorBy} = useColorBy();
71
71
  const [alignFunctionNameRaw, setStoreAlignFunctionName] = useQueryState(
72
72
  'align_function_name',
73
- stringParam
73
+ stringParam.withOptions({history: 'push'})
74
74
  );
75
75
  const alignFunctionName = alignFunctionNameRaw ?? alignFunctionNamePreference ?? 'left';
76
76
  const [groupBy, setStoreGroupBy] = useQueryState(
77
77
  'group_by',
78
- groupByParser.withDefault([FIELD_FUNCTION_NAME])
78
+ groupByParser.withDefault([FIELD_FUNCTION_NAME]).withOptions({history: 'push'})
79
79
  );
80
+ // Shared with resetSandwichFunctionName below, so keep the default 'replace';
81
+ // user "show in sandwich" actions push from the Table/flamegraph menus.
80
82
  const [sandwichFunctionName, setRawSandwichFunctionName] = useQueryState(
81
83
  'sandwich_function_name',
82
- stringParam
84
+ stringParam.withOptions({history: 'replace'})
83
85
  );
84
86
  const setSandwichFunctionName = useCallback(
85
87
  (name: string | null) => {
@@ -89,7 +91,7 @@ export const useVisualizationState = (): {
89
91
  );
90
92
  const [flamechartDimension, setStoreFlamechartDimension] = useQueryState(
91
93
  'flamechart_dimension',
92
- flamechartDimensionParser.withDefault([])
94
+ flamechartDimensionParser.withDefault([]).withOptions({history: 'push'})
93
95
  );
94
96
  const resetFlameGraphState = useResetFlameGraphState();
95
97
 
@@ -40,7 +40,7 @@ interface LineRange {
40
40
  const useLineRange = (): LineRange => {
41
41
  const [lineRange, setRawLineRange] = useQueryState(
42
42
  'source_line',
43
- lineRangeParser.withDefault({start: -1, end: -1})
43
+ lineRangeParser.withDefault({start: -1, end: -1}).withOptions({history: 'push'})
44
44
  );
45
45
 
46
46
  const setLineRange = useCallback(
@@ -21,7 +21,10 @@ import {stringParam} from '../hooks/urlParsers';
21
21
  import {useDashboardItems} from '../hooks/useDashboardItems';
22
22
 
23
23
  const MoreDropdown = ({functionName}: {functionName: string}): React.JSX.Element | null => {
24
- const [_, setSandwichFunctionName] = useQueryState('sandwich_function_name', stringParam);
24
+ const [_, setSandwichFunctionName] = useQueryState(
25
+ 'sandwich_function_name',
26
+ stringParam.withOptions({history: 'push'})
27
+ );
25
28
  const {dashboardItems, setDashboardItems} = useDashboardItems();
26
29
  const {enableSandwichView} = useParcaContext();
27
30
 
@@ -45,7 +45,10 @@ const TableContextMenu = ({
45
45
  totalUnfiltered,
46
46
  columnVisibility,
47
47
  }: TableContextMenuProps): React.JSX.Element => {
48
- const [_, setSandwichFunctionName] = useQueryState('sandwich_function_name', stringParam);
48
+ const [_, setSandwichFunctionName] = useQueryState(
49
+ 'sandwich_function_name',
50
+ stringParam.withOptions({history: 'push'})
51
+ );
49
52
  const {dashboardItems, setDashboardItems} = useDashboardItems();
50
53
  const {enableSandwichView, isDarkMode} = useParcaContext();
51
54
 
@@ -76,7 +76,10 @@ export const Table = React.memo(function Table({
76
76
  }: TableProps): React.JSX.Element {
77
77
  const currentColorProfile = useCurrentColorProfile();
78
78
  const {dashboardItems} = useDashboardItems();
79
- const [_, setSandwichFunctionName] = useQueryState('sandwich_function_name', stringParam);
79
+ const [_, setSandwichFunctionName] = useQueryState(
80
+ 'sandwich_function_name',
81
+ stringParam.withOptions({history: 'push'})
82
+ );
80
83
  const {colorBy, setColorBy} = useColorBy();
81
84
  const {isDarkMode} = useParcaContext();
82
85
  const {compareMode} = useProfileViewContext();
@@ -26,7 +26,10 @@ export const useColorBy = (): {
26
26
  const [colorByPreference, setColorByPreference] = useUserPreference<string>(
27
27
  USER_PREFERENCES.COLOR_BY.key
28
28
  );
29
- const [colorByRaw, setRawColorBy] = useQueryState('color_by', stringParam);
29
+ const [colorByRaw, setRawColorBy] = useQueryState(
30
+ 'color_by',
31
+ stringParam.withOptions({history: 'push'})
32
+ );
30
33
 
31
34
  const colorBy = colorByRaw ?? colorByPreference ?? 'binary';
32
35
 
@@ -139,7 +139,10 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
139
139
  [setQueryParams]
140
140
  );
141
141
 
142
- const [, setRawGroupByParam] = useNuqsQueryState('group_by', commaArrayParam);
142
+ const [, setRawGroupByParam] = useNuqsQueryState(
143
+ 'group_by',
144
+ commaArrayParam.withOptions({history: 'replace'})
145
+ );
143
146
  const setGroupByParam = useCallback(
144
147
  (val: string[] | null) => {
145
148
  void setRawGroupByParam(val);
@@ -388,17 +391,21 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
388
391
  }
389
392
  }
390
393
 
391
- // Atomic URL update with all params at once
392
- void setQueryParams({
393
- expression: finalExpression,
394
- from: finalFrom,
395
- to: finalTo,
396
- time_selection: finalTimeSelection,
397
- sum_by: sumByValue,
398
- merge_from: mergeFromValue,
399
- merge_to: mergeToValue,
400
- selection: selectionValue,
401
- });
394
+ // Atomic URL update with all params at once. Push a history entry so the
395
+ // back button steps through profile/time selections (default is 'replace').
396
+ void setQueryParams(
397
+ {
398
+ expression: finalExpression,
399
+ from: finalFrom,
400
+ to: finalTo,
401
+ time_selection: finalTimeSelection,
402
+ sum_by: sumByValue,
403
+ merge_from: mergeFromValue,
404
+ merge_to: mergeToValue,
405
+ selection: selectionValue,
406
+ },
407
+ {history: 'push'}
408
+ );
402
409
 
403
410
  resetFlameGraphState();
404
411
  if (
@@ -464,14 +471,18 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
464
471
  [draftProfileName]
465
472
  );
466
473
 
467
- // Set ProfileSelection (auto-commits to URL immediately)
474
+ // Set ProfileSelection (auto-commits to URL immediately). Push a history
475
+ // entry so selecting a sample is a back-navigable step (default is 'replace').
468
476
  const setProfileSelection = useCallback(
469
477
  (mergeFrom: bigint, mergeTo: bigint, query: Query) => {
470
- void setQueryParams({
471
- selection: query.toString(),
472
- merge_from: mergeFrom.toString(),
473
- merge_to: mergeTo.toString(),
474
- });
478
+ void setQueryParams(
479
+ {
480
+ selection: query.toString(),
481
+ merge_from: mergeFrom.toString(),
482
+ merge_to: mergeTo.toString(),
483
+ },
484
+ {history: 'push'}
485
+ );
475
486
  },
476
487
  [setQueryParams]
477
488
  );