@parca/profile 0.19.138 → 0.19.140

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 (138) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/GraphTooltipArrow/useGraphTooltipMetaInfo/index.d.ts.map +1 -1
  3. package/dist/GraphTooltipArrow/useGraphTooltipMetaInfo/index.js +11 -13
  4. package/dist/ProfileExplorer/ProfileExplorerCompare.d.ts.map +1 -1
  5. package/dist/ProfileExplorer/ProfileExplorerCompare.js +4 -9
  6. package/dist/ProfileFlameChart/SamplesStrips/index.d.ts +2 -2
  7. package/dist/ProfileFlameChart/SamplesStrips/index.d.ts.map +1 -1
  8. package/dist/ProfileFlameChart/index.d.ts.map +1 -1
  9. package/dist/ProfileFlameChart/index.js +13 -19
  10. package/dist/ProfileFlameGraph/FlameGraphArrow/ContextMenu.d.ts.map +1 -1
  11. package/dist/ProfileFlameGraph/FlameGraphArrow/ContextMenu.js +8 -8
  12. package/dist/ProfileFlameGraph/FlameGraphArrow/TextWithEllipsis.d.ts.map +1 -1
  13. package/dist/ProfileFlameGraph/FlameGraphArrow/TextWithEllipsis.js +4 -3
  14. package/dist/ProfileFlameGraph/index.d.ts.map +1 -1
  15. package/dist/ProfileFlameGraph/index.js +6 -4
  16. package/dist/ProfileMetricsGraph/index.d.ts.map +1 -1
  17. package/dist/ProfileMetricsGraph/index.js +4 -6
  18. package/dist/ProfileSelector/MetricsGraphSection.d.ts.map +1 -1
  19. package/dist/ProfileSelector/MetricsGraphSection.js +5 -10
  20. package/dist/ProfileSelector/index.d.ts.map +1 -1
  21. package/dist/ProfileSelector/index.js +27 -25
  22. package/dist/ProfileSelector/useAutoQuerySelector.d.ts.map +1 -1
  23. package/dist/ProfileSelector/useAutoQuerySelector.js +3 -0
  24. package/dist/ProfileTypeSelector/index.d.ts.map +1 -1
  25. package/dist/ProfileTypeSelector/index.js +4 -0
  26. package/dist/ProfileView/components/ActionButtons/SortByDropdown.d.ts.map +1 -1
  27. package/dist/ProfileView/components/ActionButtons/SortByDropdown.js +5 -5
  28. package/dist/ProfileView/components/ColorStackLegend.d.ts.map +1 -1
  29. package/dist/ProfileView/components/ColorStackLegend.js +2 -3
  30. package/dist/ProfileView/components/InvertCallStack/index.d.ts.map +1 -1
  31. package/dist/ProfileView/components/InvertCallStack/index.js +5 -4
  32. package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.d.ts +1 -2
  33. package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.d.ts.map +1 -1
  34. package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.js +14 -16
  35. package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.test.js +84 -170
  36. package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.d.ts.map +1 -1
  37. package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.js +16 -20
  38. package/dist/ProfileView/components/Toolbars/TableColumnsDropdown.d.ts.map +1 -1
  39. package/dist/ProfileView/components/Toolbars/TableColumnsDropdown.js +4 -5
  40. package/dist/ProfileView/components/Toolbars/index.d.ts +2 -2
  41. package/dist/ProfileView/components/Toolbars/index.d.ts.map +1 -1
  42. package/dist/ProfileView/components/Toolbars/index.js +1 -1
  43. package/dist/ProfileView/components/ViewSelector/index.d.ts.map +1 -1
  44. package/dist/ProfileView/components/ViewSelector/index.js +8 -14
  45. package/dist/ProfileView/context/DashboardContext.d.ts.map +1 -1
  46. package/dist/ProfileView/context/DashboardContext.js +6 -6
  47. package/dist/ProfileView/hooks/useResetFlameGraphState.d.ts.map +1 -1
  48. package/dist/ProfileView/hooks/useResetFlameGraphState.js +5 -4
  49. package/dist/ProfileView/hooks/useResetStateOnProfileTypeChange.d.ts.map +1 -1
  50. package/dist/ProfileView/hooks/useResetStateOnProfileTypeChange.js +25 -26
  51. package/dist/ProfileView/hooks/useResetStateOnSeriesChange.d.ts.map +1 -1
  52. package/dist/ProfileView/hooks/useResetStateOnSeriesChange.js +13 -8
  53. package/dist/ProfileView/hooks/useVisualizationState.d.ts +3 -3
  54. package/dist/ProfileView/hooks/useVisualizationState.d.ts.map +1 -1
  55. package/dist/ProfileView/hooks/useVisualizationState.js +35 -51
  56. package/dist/ProfileViewWithData.d.ts.map +1 -1
  57. package/dist/ProfileViewWithData.js +19 -28
  58. package/dist/Sandwich/index.d.ts.map +1 -1
  59. package/dist/Sandwich/index.js +4 -3
  60. package/dist/SourceView/index.d.ts.map +1 -1
  61. package/dist/SourceView/index.js +4 -2
  62. package/dist/SourceView/useSelectedLineRange.d.ts.map +1 -1
  63. package/dist/SourceView/useSelectedLineRange.js +21 -16
  64. package/dist/Table/MoreDropdown.d.ts.map +1 -1
  65. package/dist/Table/MoreDropdown.js +8 -11
  66. package/dist/Table/TableContextMenu.d.ts.map +1 -1
  67. package/dist/Table/TableContextMenu.js +10 -13
  68. package/dist/Table/hooks/useTableConfiguration.d.ts.map +1 -1
  69. package/dist/Table/hooks/useTableConfiguration.js +3 -4
  70. package/dist/Table/index.d.ts.map +1 -1
  71. package/dist/Table/index.js +11 -9
  72. package/dist/TopTable/index.d.ts.map +1 -1
  73. package/dist/TopTable/index.js +3 -4
  74. package/dist/hooks/urlParsers.d.ts +18 -0
  75. package/dist/hooks/urlParsers.d.ts.map +1 -0
  76. package/dist/hooks/urlParsers.js +32 -0
  77. package/dist/hooks/useColorBy.d.ts +5 -0
  78. package/dist/hooks/useColorBy.d.ts.map +1 -0
  79. package/dist/hooks/useColorBy.js +26 -0
  80. package/dist/hooks/useCompareModeMeta.d.ts.map +1 -1
  81. package/dist/hooks/useCompareModeMeta.js +55 -86
  82. package/dist/hooks/useDashboardItems.d.ts +5 -0
  83. package/dist/hooks/useDashboardItems.d.ts.map +1 -0
  84. package/dist/hooks/useDashboardItems.js +27 -0
  85. package/dist/hooks/useQueryState.d.ts +3 -3
  86. package/dist/hooks/useQueryState.d.ts.map +1 -1
  87. package/dist/hooks/useQueryState.js +105 -105
  88. package/dist/hooks/useQueryState.test.js +186 -302
  89. package/dist/index.d.ts +3 -2
  90. package/dist/index.d.ts.map +1 -1
  91. package/dist/index.js +3 -12
  92. package/dist/useSumBy.d.ts +1 -1
  93. package/dist/useSumBy.d.ts.map +1 -1
  94. package/dist/useSumBy.js +2 -2
  95. package/package.json +12 -11
  96. package/src/GraphTooltipArrow/useGraphTooltipMetaInfo/index.ts +11 -13
  97. package/src/ProfileExplorer/ProfileExplorerCompare.tsx +4 -9
  98. package/src/ProfileFlameChart/SamplesStrips/index.tsx +2 -2
  99. package/src/ProfileFlameChart/index.tsx +21 -28
  100. package/src/ProfileFlameGraph/FlameGraphArrow/ContextMenu.tsx +10 -9
  101. package/src/ProfileFlameGraph/FlameGraphArrow/TextWithEllipsis.tsx +5 -3
  102. package/src/ProfileFlameGraph/index.tsx +6 -9
  103. package/src/ProfileMetricsGraph/index.tsx +6 -8
  104. package/src/ProfileSelector/MetricsGraphSection.tsx +5 -10
  105. package/src/ProfileSelector/index.tsx +32 -31
  106. package/src/ProfileSelector/useAutoQuerySelector.ts +5 -0
  107. package/src/ProfileTypeSelector/index.tsx +4 -0
  108. package/src/ProfileView/components/ActionButtons/SortByDropdown.tsx +10 -6
  109. package/src/ProfileView/components/ColorStackLegend.tsx +2 -4
  110. package/src/ProfileView/components/InvertCallStack/index.tsx +5 -4
  111. package/src/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.test.tsx +94 -192
  112. package/src/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.ts +21 -21
  113. package/src/ProfileView/components/Toolbars/MultiLevelDropdown.tsx +24 -25
  114. package/src/ProfileView/components/Toolbars/TableColumnsDropdown.tsx +4 -5
  115. package/src/ProfileView/components/Toolbars/index.tsx +3 -3
  116. package/src/ProfileView/components/ViewSelector/index.tsx +9 -16
  117. package/src/ProfileView/context/DashboardContext.tsx +6 -6
  118. package/src/ProfileView/hooks/useResetFlameGraphState.ts +6 -4
  119. package/src/ProfileView/hooks/useResetStateOnProfileTypeChange.ts +24 -26
  120. package/src/ProfileView/hooks/useResetStateOnSeriesChange.ts +16 -8
  121. package/src/ProfileView/hooks/useVisualizationState.ts +61 -69
  122. package/src/ProfileViewWithData.tsx +29 -35
  123. package/src/Sandwich/index.tsx +4 -3
  124. package/src/SourceView/index.tsx +4 -2
  125. package/src/SourceView/useSelectedLineRange.ts +34 -19
  126. package/src/Table/MoreDropdown.tsx +9 -11
  127. package/src/Table/TableContextMenu.tsx +10 -13
  128. package/src/Table/hooks/useTableConfiguration.tsx +3 -4
  129. package/src/Table/index.tsx +12 -21
  130. package/src/TopTable/index.tsx +3 -4
  131. package/src/hooks/urlParsers.ts +38 -0
  132. package/src/hooks/useColorBy.ts +42 -0
  133. package/src/hooks/useCompareModeMeta.ts +61 -91
  134. package/src/hooks/useDashboardItems.ts +46 -0
  135. package/src/hooks/useQueryState.test.tsx +275 -345
  136. package/src/hooks/useQueryState.ts +136 -118
  137. package/src/index.tsx +16 -15
  138. package/src/useSumBy.ts +3 -3
@@ -15,9 +15,10 @@ import { useCallback, useEffect, useRef, useState } from 'react';
15
15
  import { Menu } from '@headlessui/react';
16
16
  import { Icon } from '@iconify/react';
17
17
  import cx from 'classnames';
18
- import { useURLState } from '@parca/components';
18
+ import { useQueryState } from 'nuqs';
19
19
  import { USER_PREFERENCES, useUserPreference } from '@parca/hooks';
20
20
  import { FIELD_FUNCTION_FILE_NAME, FIELD_FUNCTION_NAME, FIELD_LOCATION_ADDRESS, FIELD_MAPPING_FILE, } from '../../../ProfileFlameGraph/FlameGraphArrow';
21
+ import { boolParam, hiddenBinariesParser, stringParam } from '../../../hooks/urlParsers';
21
22
  import { useProfileViewContext } from '../../context/ProfileViewContext';
22
23
  import SwitchMenuItem from './SwitchMenuItem';
23
24
  const MenuItem = ({ label, items, onclick, onSelect, path = [], id, closeDropdown, isNested = false, activeValueForSortBy, activeValueForColorBy, activeValuesForLevel, value, disabled = false, icon, customSubmenu, renderAsDiv = false, }) => {
@@ -73,23 +74,18 @@ const MenuItem = ({ label, items, onclick, onSelect, path = [], id, closeDropdow
73
74
  const MultiLevelDropdown = ({ onSelect, profileType, groupBy, toggleGroupBy, isTableVizOnly, alignFunctionName, setAlignFunctionName, colorBy, setColorBy, }) => {
74
75
  const dropdownRef = useRef(null);
75
76
  const [shouldOpenLeft, setShouldOpenLeft] = useState(false);
76
- const [storeSortBy] = useURLState('sort_by', {
77
- defaultValue: FIELD_FUNCTION_NAME,
78
- });
79
- const [colorStackLegend, setStoreColorStackLegend] = useURLState('color_stack_legend');
80
- const [hiddenBinaries, setHiddenBinaries] = useURLState('hidden_binaries', {
81
- defaultValue: [],
82
- alwaysReturnArray: true,
83
- });
77
+ const [storeSortBy] = useQueryState('sort_by', stringParam.withDefault(FIELD_FUNCTION_NAME));
78
+ const [colorStackLegend, setStoreColorStackLegend] = useQueryState('color_stack_legend', stringParam);
79
+ const [hiddenBinaries, setHiddenBinaries] = useQueryState('hidden_binaries', hiddenBinariesParser);
84
80
  const { compareMode } = useProfileViewContext();
85
81
  const [colorProfileName] = useUserPreference(USER_PREFERENCES.FLAMEGRAPH_COLOR_PROFILE.key);
86
82
  const isColorStackLegendEnabled = colorStackLegend === 'true';
87
83
  const isLeftAligned = alignFunctionName === 'left';
88
84
  // By default, we want delta profiles (CPU) to be relatively compared.
89
85
  // For non-delta profiles, like goroutines or memory, we want the profiles to be compared absolutely.
90
- const compareAbsoluteDefault = profileType?.delta === false ? 'true' : 'false';
91
- const [compareAbsolute = compareAbsoluteDefault, setCompareAbsolute] = useURLState('compare_absolute');
92
- const isCompareAbsolute = compareAbsolute === 'true';
86
+ const compareAbsoluteDefault = profileType?.delta === false;
87
+ const [compareAbsolute, setCompareAbsolute] = useQueryState('compare_absolute', boolParam);
88
+ const isCompareAbsolute = compareAbsolute ?? compareAbsoluteDefault;
93
89
  useEffect(() => {
94
90
  const checkOverflow = () => {
95
91
  if (dropdownRef.current !== null) {
@@ -108,13 +104,13 @@ const MultiLevelDropdown = ({ onSelect, profileType, groupBy, toggleGroupBy, isT
108
104
  const handleBinaryToggle = (index) => {
109
105
  const updatedBinaries = [...hiddenBinaries];
110
106
  updatedBinaries.splice(index, 1);
111
- setHiddenBinaries(updatedBinaries);
107
+ void setHiddenBinaries(updatedBinaries);
112
108
  };
113
109
  const setColorStackLegend = useCallback((value) => {
114
- setStoreColorStackLegend(value);
110
+ void setStoreColorStackLegend(value);
115
111
  }, [setStoreColorStackLegend]);
116
112
  const resetLegend = () => {
117
- setHiddenBinaries([]);
113
+ void setHiddenBinaries([]);
118
114
  };
119
115
  const menuItems = [
120
116
  {
@@ -181,7 +177,7 @@ const MultiLevelDropdown = ({ onSelect, profileType, groupBy, toggleGroupBy, isT
181
177
  },
182
178
  {
183
179
  label: isCompareAbsolute ? 'Compare Relative' : 'Compare Absolute',
184
- onclick: () => setCompareAbsolute(isCompareAbsolute ? 'false' : 'true'),
180
+ onclick: () => void setCompareAbsolute(!isCompareAbsolute),
185
181
  hide: !compareMode,
186
182
  icon: isCompareAbsolute ? 'fluent-mdl2:compare' : 'fluent-mdl2:compare-uneven',
187
183
  },
@@ -199,7 +195,7 @@ const MultiLevelDropdown = ({ onSelect, profileType, groupBy, toggleGroupBy, isT
199
195
  },
200
196
  {
201
197
  label: 'Reset Legend',
202
- hide: hiddenBinaries === undefined || hiddenBinaries.length === 0,
198
+ hide: hiddenBinaries.length === 0,
203
199
  onclick: () => resetLegend(),
204
200
  id: 'h-reset-legend-button',
205
201
  icon: 'system-uicons:reset',
@@ -207,16 +203,16 @@ const MultiLevelDropdown = ({ onSelect, profileType, groupBy, toggleGroupBy, isT
207
203
  {
208
204
  label: 'Hidden Binaries',
209
205
  id: 'h-hidden-binaries',
210
- items: hiddenBinaries?.map((binary, index) => ({
206
+ items: hiddenBinaries.map((binary, index) => ({
211
207
  label: binary,
212
208
  customSubmenu: (_jsxs("div", { className: "flex items-center gap-2 w-full", children: [_jsx("input", { id: binary, name: binary, type: "checkbox", className: "h-4 w-4 rounded-md border-2 border-gray-300 text-indigo-600 focus:ring-indigo-600 focus:ring-offset-0 checked:bg-indigo-600 checked:border-indigo-600", checked: hiddenBinaries?.includes(binary), onChange: () => handleBinaryToggle(index) }), _jsx("span", { children: binary })] })),
213
209
  })),
214
- hide: hiddenBinaries === undefined || hiddenBinaries.length === 0,
210
+ hide: hiddenBinaries.length === 0,
215
211
  icon: 'ph:eye-closed',
216
212
  },
217
213
  ];
218
214
  return (_jsx("div", { className: "relative inline-block text-left", id: "h-visualisation-toolbar-actions", ref: dropdownRef, children: _jsx(Menu, { children: ({ open, close }) => (_jsxs(_Fragment, { children: [_jsxs(Menu.Button, { className: "flex dark:bg-gray-900 dark:border-gray-600 justify-center w-full px-4 py-2 text-sm font-normal text-gray-600 dark:text-gray-200 bg-white rounded-md focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 border border-gray-200 pr-[1.7rem]", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Icon, { icon: "pajamas:preferences", className: "w-4 h-4" }), _jsx("span", { children: "Preferences" })] }), _jsx("span", { className: "pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2 text-gray-400", children: _jsx(Icon, { icon: "heroicons:chevron-down-20-solid", "aria-hidden": "true" }) })] }), open && (_jsx(Menu.Items, { className: cx(isTableVizOnly ? 'w-64' : 'w-80', 'absolute z-50 mt-2 py-2 bg-white rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none border dark:bg-gray-900 dark:border-gray-600', shouldOpenLeft ? 'right-0 origin-top-right' : 'left-0 origin-top-left'), children: menuItems
219
215
  .filter(item => item.hide !== undefined && !item.hide)
220
- .map((item, index) => (_jsx(MenuItem, { ...item, onSelect: onSelect, closeDropdown: close, activeValueForSortBy: storeSortBy, activeValueForColorBy: colorBy === undefined || colorBy === '' ? 'binary' : colorBy, activeValuesForLevel: groupBy, renderAsDiv: item.renderAsDiv }, index))) }))] })) }) }));
216
+ .map((item, index) => (_jsx(MenuItem, { ...item, onSelect: onSelect, closeDropdown: close, activeValueForSortBy: storeSortBy, activeValueForColorBy: colorBy, activeValuesForLevel: groupBy, renderAsDiv: item.renderAsDiv }, index))) }))] })) }) }));
221
217
  };
222
218
  export default MultiLevelDropdown;
@@ -1 +1 @@
1
- {"version":3,"file":"TableColumnsDropdown.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/Toolbars/TableColumnsDropdown.tsx"],"names":[],"mappings":"AAkBA,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAQ1C,UAAU,KAAK;IACb,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,QAAA,MAAM,oBAAoB,GAAI,kCAAgC,KAAK,KAAG,GAAG,CAAC,OA+KzE,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"TableColumnsDropdown.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/Toolbars/TableColumnsDropdown.tsx"],"names":[],"mappings":"AAkBA,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAS1C,UAAU,KAAK;IACb,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,QAAA,MAAM,oBAAoB,GAAI,kCAAgC,KAAK,KAAG,GAAG,CAAC,OA6KzE,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
@@ -13,16 +13,15 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
13
  // limitations under the License.
14
14
  import { useEffect, useMemo, useState } from 'react';
15
15
  import { createColumnHelper } from '@tanstack/table-core';
16
- import { useURLState } from '@parca/components';
16
+ import { useQueryState } from 'nuqs';
17
17
  import { valueFormatter } from '@parca/utilities';
18
18
  import ColumnsVisibility from '../../../Table/ColumnsVisibility';
19
19
  import { addPlusSign, getRatioString } from '../../../Table/utils/functions';
20
+ import { tableColumnsParser } from '../../../hooks/urlParsers';
20
21
  import { useProfileViewContext } from '../../context/ProfileViewContext';
21
22
  const TableColumnsDropdown = ({ profileType, total, filtered }) => {
22
23
  const { compareMode } = useProfileViewContext();
23
- const [tableColumns, setTableColumns] = useURLState('table_columns', {
24
- alwaysReturnArray: true,
25
- });
24
+ const [tableColumns, setTableColumns] = useQueryState('table_columns', tableColumnsParser);
26
25
  const columnHelper = createColumnHelper();
27
26
  const unit = useMemo(() => profileType?.sampleUnit ?? '', [profileType?.sampleUnit]);
28
27
  const columns = useMemo(() => {
@@ -169,7 +168,7 @@ const TableColumnsDropdown = ({ profileType, total, filtered }) => {
169
168
  const updateColumnVisibility = (column, isVisible) => {
170
169
  const updatedColumns = { ...columnVisibility, [column]: isVisible };
171
170
  const newTableColumns = Object.keys(updatedColumns).filter(col => updatedColumns[col]);
172
- setTableColumns(newTableColumns);
171
+ void setTableColumns(newTableColumns);
173
172
  };
174
173
  return (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("label", { className: "text-sm", children: "Table Columns" }), _jsx(ColumnsVisibility, { columns: columns, visibility: columnVisibility, setVisibility: (id, visible) => {
175
174
  updateColumnVisibility(id, visible);
@@ -22,7 +22,7 @@ export interface VisualisationToolbarProps {
22
22
  flamechartDimension: string[];
23
23
  setFlamechartDimension: (labels: string[]) => void;
24
24
  showVisualizationSelector?: boolean;
25
- sandwichFunctionName?: string;
25
+ sandwichFunctionName: string | null;
26
26
  alignFunctionName: string;
27
27
  setAlignFunctionName: (align: string) => void;
28
28
  colorBy: string;
@@ -44,7 +44,7 @@ export interface FlameGraphToolbarProps {
44
44
  }
45
45
  export interface SandwichFlameGraphToolbarProps {
46
46
  resetSandwichFunctionName: () => void;
47
- sandwichFunctionName?: string;
47
+ sandwichFunctionName: string | null;
48
48
  }
49
49
  export declare const TableToolbar: FC<TableToolbarProps>;
50
50
  export declare const FlameGraphToolbar: FC<FlameGraphToolbarProps>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/Toolbars/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,EAAE,EAAC,MAAM,OAAO,CAAC;AAIzB,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAG1C,OAAO,EAAC,gBAAgB,EAAC,MAAM,kDAAkD,CAAC;AAClF,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAUrD,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAClD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,6BAA6B,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAChD,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,sBAAsB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACnD,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,QAAQ,EAAE;QACR,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9B,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;CACnD;AAED,MAAM,WAAW,8BAA8B;IAC7C,yBAAyB,EAAE,MAAM,IAAI,CAAC;IACtC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CAQ9C,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,sBAAsB,CAkBxD,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,EAAE,CAAC,8BAA8B,CAmBxE,CAAC;AAMF,eAAO,MAAM,oBAAoB,EAAE,EAAE,CAAC,yBAAyB,CAoH9D,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/Toolbars/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,EAAE,EAAC,MAAM,OAAO,CAAC;AAIzB,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAG1C,OAAO,EAAC,gBAAgB,EAAC,MAAM,kDAAkD,CAAC;AAClF,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAUrD,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAClD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,6BAA6B,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAChD,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,sBAAsB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACnD,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,QAAQ,EAAE;QACR,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9B,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;CACnD;AAED,MAAM,WAAW,8BAA8B;IAC7C,yBAAyB,EAAE,MAAM,IAAI,CAAC;IACtC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CAQ9C,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,sBAAsB,CAkBxD,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,EAAE,CAAC,8BAA8B,CAmBxE,CAAC;AAMF,eAAO,MAAM,oBAAoB,EAAE,EAAE,CAAC,yBAAyB,CAoH9D,CAAC"}
@@ -17,7 +17,7 @@ export const FlameGraphToolbar = ({ curPath, setNewCurPath }) => {
17
17
  return (_jsx(_Fragment, { children: _jsx("div", { className: "flex w-full gap-2 items-end", children: _jsxs(Button, { variant: "neutral", className: "gap-2 w-max h-fit", onClick: () => setNewCurPath([]), disabled: curPath.length === 0, id: "h-reset-graph", ...testId(TEST_IDS.FLAMEGRAPH_RESET_BUTTON), children: ["Reset graph", _jsx(Icon, { icon: "system-uicons:reset", width: 20 })] }) }) }));
18
18
  };
19
19
  export const SandwichFlameGraphToolbar = ({ resetSandwichFunctionName, sandwichFunctionName, }) => {
20
- return (_jsx(_Fragment, { children: _jsx("div", { className: "flex w-full gap-2 items-end justify-between", children: _jsx(Button, { color: "neutral", onClick: () => resetSandwichFunctionName(), className: "w-auto", variant: "neutral", disabled: sandwichFunctionName === undefined || sandwichFunctionName.length === 0, children: "Reset view" }) }) }));
20
+ return (_jsx(_Fragment, { children: _jsx("div", { className: "flex w-full gap-2 items-end justify-between", children: _jsx(Button, { color: "neutral", onClick: () => resetSandwichFunctionName(), className: "w-auto", variant: "neutral", disabled: sandwichFunctionName == null || sandwichFunctionName.length === 0, children: "Reset view" }) }) }));
21
21
  };
22
22
  const Divider = () => (_jsx("div", { className: "border-t mt-4 border-gray-200 dark:border-gray-700 h-[1px] w-full pb-4" }));
23
23
  export const VisualisationToolbar = ({ groupBy, toggleGroupBy, setGroupByLabels, flamechartDimension, setFlamechartDimension, profileType, profileSource, queryClient, onDownloadPProf, pprofdownloading, profileViewExternalSubActions, curPath, setNewCurPath, total, filtered, showVisualizationSelector = true, alignFunctionName, setAlignFunctionName, colorBy, setColorBy, metadata: { labels: groupByLabels, refetch: metadataRefetch, loading: metadataLoading }, }) => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ViewSelector/index.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAGrD,UAAU,KAAK;IACb,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,QAAA,MAAM,YAAY,GAAI,mBAAiB,KAAK,KAAG,GAAG,CAAC,OA+JlD,CAAC;AAEF,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ViewSelector/index.tsx"],"names":[],"mappings":"AAmBA,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAKrD,UAAU,KAAK;IACb,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,QAAA,MAAM,YAAY,GAAI,mBAAiB,KAAK,KAAG,GAAG,CAAC,OAoJlD,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -1,13 +1,13 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useParcaContext, useURLState, useURLStateBatch } from '@parca/components';
2
+ import { useQueryState } from 'nuqs';
3
+ import { useParcaContext } from '@parca/components';
4
+ import { stringParam } from '../../../hooks/urlParsers';
5
+ import { useDashboardItems } from '../../../hooks/useDashboardItems';
3
6
  import Dropdown from './Dropdown';
4
7
  const ViewSelector = ({ profileSource }) => {
5
- const [dashboardItems = ['flamegraph'], setDashboardItems] = useURLState('dashboard_items', {
6
- alwaysReturnArray: true,
7
- });
8
- const [, setSandwichFunctionName] = useURLState('sandwich_function_name');
8
+ const { dashboardItems, setDashboardItems } = useDashboardItems();
9
+ const [, setSandwichFunctionName] = useQueryState('sandwich_function_name', stringParam);
9
10
  const { enableSourcesView, enableSandwichView } = useParcaContext();
10
- const batchUpdates = useURLStateBatch();
11
11
  const allItems = [
12
12
  {
13
13
  key: 'flamegraph',
@@ -61,15 +61,9 @@ const ViewSelector = ({ profileSource }) => {
61
61
  }
62
62
  else {
63
63
  const newDashboardItems = dashboardItems.filter(v => v !== item.key);
64
- // Batch updates when removing sandwich panel to combine both URL changes
64
+ setDashboardItems(newDashboardItems);
65
65
  if (item.key === 'sandwich') {
66
- batchUpdates(() => {
67
- setDashboardItems(newDashboardItems);
68
- setSandwichFunctionName(undefined);
69
- });
70
- }
71
- else {
72
- setDashboardItems(newDashboardItems);
66
+ void setSandwichFunctionName(null);
73
67
  }
74
68
  }
75
69
  },
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardContext.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/context/DashboardContext.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,EAAE,EAAE,iBAAiB,EAA4B,MAAM,OAAO,CAAC;AAIvE,OAAO,EAAC,iBAAiB,EAAC,MAAM,wBAAwB,CAAC;AAEzD,UAAU,oBAAoB;IAC5B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,gBAAgB,EAAE,CAAC,iBAAiB,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACjE,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAID,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,iBAAiB,CA8BnD,CAAC;AAEF,eAAO,MAAM,YAAY,QAAO,oBAM/B,CAAC"}
1
+ {"version":3,"file":"DashboardContext.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/context/DashboardContext.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,EAAE,EAAE,iBAAiB,EAA4B,MAAM,OAAO,CAAC;AAMvE,OAAO,EAAC,iBAAiB,EAAC,MAAM,wBAAwB,CAAC;AAEzD,UAAU,oBAAoB;IAC5B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,gBAAgB,EAAE,CAAC,iBAAiB,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACjE,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAID,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,iBAAiB,CA4BnD,CAAC;AAEF,eAAO,MAAM,YAAY,QAAO,oBAM/B,CAAC"}
@@ -12,19 +12,19 @@ import { jsx as _jsx } from "react/jsx-runtime";
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
14
  import { createContext, useContext } from 'react';
15
- import { useURLState } from '@parca/components';
15
+ import { useQueryState } from 'nuqs';
16
+ import { stringParam } from '../../hooks/urlParsers';
17
+ import { useDashboardItems } from '../../hooks/useDashboardItems';
16
18
  const DashboardContext = createContext(undefined);
17
19
  export const DashboardProvider = ({ children }) => {
18
- const [dashboardItems, setDashboardItems] = useURLState('dashboard_items', {
19
- alwaysReturnArray: true,
20
- });
21
- const [, setSandwichFunctionName] = useURLState('sandwich_function_name');
20
+ const { dashboardItems, setDashboardItems } = useDashboardItems();
21
+ const [, setSandwichFunctionName] = useQueryState('sandwich_function_name', stringParam);
22
22
  const handleClosePanel = (visualizationType) => {
23
23
  const newDashboardItems = dashboardItems.filter(item => item !== visualizationType);
24
24
  setDashboardItems(newDashboardItems);
25
25
  // Reset sandwich function name when closing sandwich panel
26
26
  if (visualizationType === 'sandwich') {
27
- setSandwichFunctionName(undefined);
27
+ void setSandwichFunctionName(null);
28
28
  }
29
29
  };
30
30
  const isMultiPanelView = dashboardItems.length > 1;
@@ -1 +1 @@
1
- {"version":3,"file":"useResetFlameGraphState.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useResetFlameGraphState.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,uBAAuB,QAAO,CAAC,MAAM,IAAI,CAWrD,CAAC"}
1
+ {"version":3,"file":"useResetFlameGraphState.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useResetFlameGraphState.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,uBAAuB,QAAO,CAAC,MAAM,IAAI,CAWrD,CAAC"}
@@ -10,15 +10,16 @@
10
10
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
- import { useURLState } from '@parca/components';
13
+ import { useQueryState } from 'nuqs';
14
+ import { stringParam } from '../../hooks/urlParsers';
14
15
  export const useResetFlameGraphState = () => {
15
- const [val, setCurPath] = useURLState('cur_path');
16
+ const [val, setCurPath] = useQueryState('cur_path', stringParam);
16
17
  return () => {
17
18
  setTimeout(() => {
18
- if (val === undefined) {
19
+ if (val === null) {
19
20
  return;
20
21
  }
21
- setCurPath(undefined);
22
+ void setCurPath(null);
22
23
  });
23
24
  };
24
25
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useResetStateOnProfileTypeChange.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useResetStateOnProfileTypeChange.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,gCAAgC,QAAO,CAAC,MAAM,IAAI,CA+B9D,CAAC"}
1
+ {"version":3,"file":"useResetStateOnProfileTypeChange.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useResetStateOnProfileTypeChange.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,gCAAgC,QAAO,CAAC,MAAM,IAAI,CA4B9D,CAAC"}
@@ -10,35 +10,34 @@
10
10
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
- import { useURLState, useURLStateBatch } from '@parca/components';
13
+ import { useQueryStates } from 'nuqs';
14
+ import { stringParam } from '../../hooks/urlParsers';
14
15
  import { useProfileFilters } from '../components/ProfileFilters/useProfileFilters';
15
16
  export const useResetStateOnProfileTypeChange = () => {
16
- const [groupBy, setGroupBy] = useURLState('group_by');
17
- const [curPath, setCurPath] = useURLState('cur_path');
18
- const [sumByA, setSumByA] = useURLState('sum_by_a');
19
- const [sumByB, setSumByB] = useURLState('sum_by_b');
17
+ const [state, setState] = useQueryStates({
18
+ group_by: stringParam,
19
+ cur_path: stringParam,
20
+ sum_by_a: stringParam,
21
+ sum_by_b: stringParam,
22
+ sandwich_function_name: stringParam,
23
+ }, { history: 'replace' });
20
24
  const { resetFilters } = useProfileFilters();
21
- const [sandwichFunctionName, setSandwichFunctionName] = useURLState('sandwich_function_name');
22
- const batchUpdates = useURLStateBatch();
23
25
  return () => {
24
- // Batch all URL state resets into a single navigation
25
- batchUpdates(() => {
26
- if (groupBy !== undefined) {
27
- setGroupBy(undefined);
28
- }
29
- if (curPath !== undefined) {
30
- setCurPath(undefined);
31
- }
32
- if (sandwichFunctionName !== undefined) {
33
- setSandwichFunctionName(undefined);
34
- }
35
- if (sumByA !== undefined) {
36
- setSumByA(undefined);
37
- }
38
- if (sumByB !== undefined) {
39
- setSumByB(undefined);
40
- }
41
- resetFilters();
42
- });
26
+ // Atomic reset: clear all params in single URL update
27
+ const updates = {};
28
+ if (state.group_by !== null)
29
+ updates.group_by = null;
30
+ if (state.cur_path !== null)
31
+ updates.cur_path = null;
32
+ if (state.sandwich_function_name !== null)
33
+ updates.sandwich_function_name = null;
34
+ if (state.sum_by_a !== null)
35
+ updates.sum_by_a = null;
36
+ if (state.sum_by_b !== null)
37
+ updates.sum_by_b = null;
38
+ if (Object.keys(updates).length > 0) {
39
+ void setState(updates);
40
+ }
41
+ resetFilters();
43
42
  };
44
43
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useResetStateOnSeriesChange.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useResetStateOnSeriesChange.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,2BAA2B,QAAO,CAAC,MAAM,IAAI,CAczD,CAAC"}
1
+ {"version":3,"file":"useResetStateOnSeriesChange.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useResetStateOnSeriesChange.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,2BAA2B,QAAO,CAAC,MAAM,IAAI,CAoBzD,CAAC"}
@@ -10,17 +10,22 @@
10
10
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
- import { useURLState } from '@parca/components';
13
+ import { useQueryStates } from 'nuqs';
14
+ import { stringParam } from '../../hooks/urlParsers';
14
15
  export const useResetStateOnSeriesChange = () => {
15
- const [curPath, setCurPath] = useURLState('cur_path');
16
- const [sandwichFunctionName, setSandwichFunctionName] = useURLState('sandwich_function_name');
16
+ const [state, setState] = useQueryStates({
17
+ cur_path: stringParam,
18
+ sandwich_function_name: stringParam,
19
+ }, { history: 'replace' });
17
20
  return () => {
18
21
  setTimeout(() => {
19
- if (curPath !== undefined) {
20
- setCurPath(undefined);
21
- }
22
- if (sandwichFunctionName !== undefined) {
23
- setSandwichFunctionName(undefined);
22
+ const updates = {};
23
+ if (state.cur_path !== null)
24
+ updates.cur_path = null;
25
+ if (state.sandwich_function_name !== null)
26
+ updates.sandwich_function_name = null;
27
+ if (Object.keys(updates).length > 0) {
28
+ void setState(updates);
24
29
  }
25
30
  });
26
31
  };
@@ -2,7 +2,7 @@ import { CurrentPathFrame } from '../../ProfileFlameGraph/FlameGraphArrow/utils'
2
2
  export declare const useVisualizationState: () => {
3
3
  curPathArrow: CurrentPathFrame[];
4
4
  setCurPathArrow: (path: CurrentPathFrame[]) => void;
5
- colorStackLegend: string | undefined;
5
+ colorStackLegend: string | null;
6
6
  colorBy: string;
7
7
  setColorBy: (colorBy: string) => void;
8
8
  groupBy: string[];
@@ -11,8 +11,8 @@ export declare const useVisualizationState: () => {
11
11
  setGroupByLabels: (labels: string[]) => void;
12
12
  flamechartDimension: string[];
13
13
  setFlamechartDimension: (labels: string[]) => void;
14
- sandwichFunctionName: string | undefined;
15
- setSandwichFunctionName: (sandwichFunctionName: string | undefined) => void;
14
+ sandwichFunctionName: string | null;
15
+ setSandwichFunctionName: (sandwichFunctionName: string | null) => void;
16
16
  resetSandwichFunctionName: () => void;
17
17
  alignFunctionName: string;
18
18
  setAlignFunctionName: (align: string) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"useVisualizationState.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useVisualizationState.ts"],"names":[],"mappings":"AA+BA,OAAO,EAAC,gBAAgB,EAAC,MAAM,+CAA+C,CAAC;AAG/E,eAAO,MAAM,qBAAqB,QAAO;IACvC,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,eAAe,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IACpD,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACrC,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,sBAAsB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACnD,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,uBAAuB,EAAE,CAAC,oBAAoB,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IAC5E,yBAAyB,EAAE,MAAM,IAAI,CAAC;IACtC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAgI/C,CAAC"}
1
+ {"version":3,"file":"useVisualizationState.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useVisualizationState.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAC,gBAAgB,EAAC,MAAM,+CAA+C,CAAC;AAU/E,eAAO,MAAM,qBAAqB,QAAO;IACvC,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,eAAe,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IACpD,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACrC,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,sBAAsB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACnD,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,uBAAuB,EAAE,CAAC,oBAAoB,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACvE,yBAAyB,EAAE,MAAM,IAAI,CAAC;IACtC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAsH/C,CAAC"}
@@ -11,35 +11,29 @@
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
13
  import { useCallback, useMemo } from 'react';
14
- import { JSONParser, JSONSerializer, useURLState, useURLStateBatch, useURLStateCustom, } from '@parca/components';
14
+ import { useQueryState } from 'nuqs';
15
15
  import { USER_PREFERENCES, useUserPreference } from '@parca/hooks';
16
16
  import { FIELD_FUNCTION_FILE_NAME, FIELD_FUNCTION_NAME, FIELD_LABELS, FIELD_LOCATION_ADDRESS, FIELD_MAPPING_FILE, } from '../../ProfileFlameGraph/FlameGraphArrow';
17
+ import { flamechartDimensionParser, groupByParser, jsonParser, stringParam, } from '../../hooks/urlParsers';
18
+ import { useColorBy } from '../../hooks/useColorBy';
17
19
  import { useResetFlameGraphState } from './useResetFlameGraphState';
18
20
  export const useVisualizationState = () => {
19
- const [colorByPreference, setColorByPreference] = useUserPreference(USER_PREFERENCES.COLOR_BY.key);
20
21
  const [alignFunctionNamePreference, setAlignFunctionNamePreference] = useUserPreference(USER_PREFERENCES.ALIGN_FUNCTION_NAME.key);
21
- const [curPathArrow, setCurPathArrow] = useURLStateCustom('cur_path', {
22
- parse: (JSONParser),
23
- stringify: JSONSerializer,
24
- defaultValue: '[]',
25
- });
26
- const [colorStackLegend] = useURLState('color_stack_legend');
27
- const [colorBy, setStoreColorBy] = useURLState('color_by', {
28
- defaultValue: colorByPreference,
29
- });
30
- const [alignFunctionName, setStoreAlignFunctionName] = useURLState('align_function_name', {
31
- defaultValue: alignFunctionNamePreference,
32
- });
33
- const [groupBy, setStoreGroupBy] = useURLState('group_by', {
34
- defaultValue: [FIELD_FUNCTION_NAME],
35
- alwaysReturnArray: true,
36
- });
37
- const [sandwichFunctionName, setSandwichFunctionName] = useURLState('sandwich_function_name');
38
- const [flamechartDimension, setStoreFlamechartDimension] = useURLState('flamechart_dimension', {
39
- alwaysReturnArray: true,
40
- });
22
+ const [curPathArrow, setRawCurPathArrow] = useQueryState('cur_path', jsonParser().withDefault([]));
23
+ const setCurPathArrow = useCallback((path) => {
24
+ void setRawCurPathArrow(path);
25
+ }, [setRawCurPathArrow]);
26
+ const [colorStackLegend] = useQueryState('color_stack_legend', stringParam);
27
+ const { colorBy, setColorBy } = useColorBy();
28
+ const [alignFunctionNameRaw, setStoreAlignFunctionName] = useQueryState('align_function_name', stringParam);
29
+ const alignFunctionName = alignFunctionNameRaw ?? alignFunctionNamePreference ?? 'left';
30
+ const [groupBy, setStoreGroupBy] = useQueryState('group_by', groupByParser.withDefault([FIELD_FUNCTION_NAME]));
31
+ const [sandwichFunctionName, setRawSandwichFunctionName] = useQueryState('sandwich_function_name', stringParam);
32
+ const setSandwichFunctionName = useCallback((name) => {
33
+ void setRawSandwichFunctionName(name);
34
+ }, [setRawSandwichFunctionName]);
35
+ const [flamechartDimension, setStoreFlamechartDimension] = useQueryState('flamechart_dimension', flamechartDimensionParser.withDefault([]));
41
36
  const resetFlameGraphState = useResetFlameGraphState();
42
- const batchUpdates = useURLStateBatch();
43
37
  const levelsOfProfiling = useMemo(() => [
44
38
  FIELD_FUNCTION_NAME,
45
39
  FIELD_FUNCTION_FILE_NAME,
@@ -47,47 +41,37 @@ export const useVisualizationState = () => {
47
41
  FIELD_MAPPING_FILE,
48
42
  ], []);
49
43
  const setGroupBy = useCallback((keys) => {
50
- setStoreGroupBy(keys);
44
+ void setStoreGroupBy(keys);
51
45
  }, [setStoreGroupBy]);
52
46
  const toggleGroupBy = useCallback((key) => {
53
- // Batch updates to combine setGroupBy + resetFlameGraphState into single URL navigation
54
- batchUpdates(() => {
55
- if (groupBy.includes(key)) {
56
- setGroupBy(groupBy.filter(v => v !== key)); // remove
57
- }
58
- else {
59
- const filteredGroupBy = groupBy.filter(item => !levelsOfProfiling.includes(item));
60
- setGroupBy([...filteredGroupBy, key]); // add
61
- }
62
- resetFlameGraphState();
63
- });
64
- }, [groupBy, setGroupBy, levelsOfProfiling, resetFlameGraphState, batchUpdates]);
47
+ if (groupBy.includes(key)) {
48
+ setGroupBy(groupBy.filter(v => v !== key));
49
+ }
50
+ else {
51
+ const filteredGroupBy = groupBy.filter(item => !levelsOfProfiling.includes(item));
52
+ setGroupBy([...filteredGroupBy, key]);
53
+ }
54
+ resetFlameGraphState();
55
+ }, [groupBy, setGroupBy, levelsOfProfiling, resetFlameGraphState]);
65
56
  const setGroupByLabels = useCallback((labels) => {
66
- // Batch updates to combine setGroupBy + resetFlameGraphState into single URL navigation
67
- batchUpdates(() => {
68
- setGroupBy(groupBy.filter(l => !l.startsWith(`${FIELD_LABELS}.`)).concat(labels));
69
- resetFlameGraphState();
70
- });
71
- }, [groupBy, setGroupBy, resetFlameGraphState, batchUpdates]);
57
+ setGroupBy(groupBy.filter(l => !l.startsWith(`${FIELD_LABELS}.`)).concat(labels));
58
+ resetFlameGraphState();
59
+ }, [groupBy, setGroupBy, resetFlameGraphState]);
72
60
  const setFlamechartDimension = useCallback((labels) => {
73
- setStoreFlamechartDimension(labels.filter(l => l.startsWith(`${FIELD_LABELS}.`)));
61
+ void setStoreFlamechartDimension(labels.filter(l => l.startsWith(`${FIELD_LABELS}.`)));
74
62
  }, [setStoreFlamechartDimension]);
75
63
  const resetSandwichFunctionName = useCallback(() => {
76
- setSandwichFunctionName(undefined);
64
+ setSandwichFunctionName(null);
77
65
  }, [setSandwichFunctionName]);
78
- const setColorBy = useCallback((value) => {
79
- setStoreColorBy(value);
80
- setColorByPreference(value);
81
- }, [setStoreColorBy, setColorByPreference]);
82
66
  const setAlignFunctionName = useCallback((value) => {
83
- setStoreAlignFunctionName(value);
67
+ void setStoreAlignFunctionName(value);
84
68
  setAlignFunctionNamePreference(value);
85
69
  }, [setStoreAlignFunctionName, setAlignFunctionNamePreference]);
86
70
  return {
87
71
  curPathArrow,
88
72
  setCurPathArrow,
89
73
  colorStackLegend,
90
- colorBy: colorBy ?? '',
74
+ colorBy,
91
75
  setColorBy,
92
76
  groupBy,
93
77
  setGroupBy,
@@ -98,7 +82,7 @@ export const useVisualizationState = () => {
98
82
  sandwichFunctionName,
99
83
  setSandwichFunctionName,
100
84
  resetSandwichFunctionName,
101
- alignFunctionName: alignFunctionName ?? 'left',
85
+ alignFunctionName,
102
86
  setAlignFunctionName,
103
87
  };
104
88
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ProfileViewWithData.d.ts","sourceRoot":"","sources":["../src/ProfileViewWithData.tsx"],"names":[],"mappings":"AAeA,OAAO,EAA0B,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAkB1E,OAAO,EAAsB,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAOnE,UAAU,wBAAwB;IAChC,WAAW,EAAE,kBAAkB,CAAC;IAChC,aAAa,EAAE,aAAa,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,wBAAwB,CAAC,EAAE,MAAM,IAAI,CAAC;CACvC;AAED,eAAO,MAAM,mBAAmB,GAAI,sFAKjC,wBAAwB,KAAG,GAAG,CAAC,OA4UjC,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"ProfileViewWithData.d.ts","sourceRoot":"","sources":["../src/ProfileViewWithData.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAA0B,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAW1E,OAAO,EAAsB,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAenE,UAAU,wBAAwB;IAChC,WAAW,EAAE,kBAAkB,CAAC;IAChC,aAAa,EAAE,aAAa,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,wBAAwB,CAAC,EAAE,MAAM,IAAI,CAAC;CACvC;AAED,eAAO,MAAM,mBAAmB,GAAI,sFAKjC,wBAAwB,KAAG,GAAG,CAAC,OAmUjC,CAAC;AAEF,eAAe,mBAAmB,CAAC"}