@parca/profile 0.19.140 → 0.19.142

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 (253) hide show
  1. package/CHANGELOG.md +5 -1
  2. package/dist/GraphTooltipArrow/Content.js +224 -30
  3. package/dist/GraphTooltipArrow/DockedGraphTooltip/index.js +192 -33
  4. package/dist/GraphTooltipArrow/ExpandOnHoverValue.js +53 -3
  5. package/dist/GraphTooltipArrow/index.d.ts.map +1 -1
  6. package/dist/GraphTooltipArrow/index.js +86 -56
  7. package/dist/GraphTooltipArrow/useGraphTooltip/index.js +37 -37
  8. package/dist/GraphTooltipArrow/useGraphTooltipMetaInfo/index.d.ts.map +1 -1
  9. package/dist/GraphTooltipArrow/useGraphTooltipMetaInfo/index.js +104 -72
  10. package/dist/MatchersInput/SuggestionItem.js +91 -12
  11. package/dist/MatchersInput/SuggestionsList.d.ts +2 -1
  12. package/dist/MatchersInput/SuggestionsList.d.ts.map +1 -1
  13. package/dist/MatchersInput/SuggestionsList.js +371 -157
  14. package/dist/MatchersInput/SuggestionsList.test.d.ts +2 -0
  15. package/dist/MatchersInput/SuggestionsList.test.d.ts.map +1 -0
  16. package/dist/MatchersInput/index.js +308 -115
  17. package/dist/MetricsCircle/index.js +39 -3
  18. package/dist/MetricsGraph/MetricsContextMenu/index.js +119 -19
  19. package/dist/MetricsGraph/MetricsInfoPanel/index.js +81 -20
  20. package/dist/MetricsGraph/MetricsTooltip/index.d.ts.map +1 -1
  21. package/dist/MetricsGraph/MetricsTooltip/index.js +107 -74
  22. package/dist/MetricsGraph/index.js +552 -203
  23. package/dist/MetricsGraph/useMetricsGraphDimensions.js +46 -25
  24. package/dist/MetricsGraph/utils/colorMapping.js +24 -17
  25. package/dist/MetricsSeries/index.js +70 -7
  26. package/dist/PreSelectedMatchers/index.d.ts.map +1 -1
  27. package/dist/PreSelectedMatchers/index.js +249 -102
  28. package/dist/ProfileExplorer/ProfileExplorerCompare.d.ts.map +1 -1
  29. package/dist/ProfileExplorer/ProfileExplorerCompare.js +241 -45
  30. package/dist/ProfileExplorer/ProfileExplorerSingle.js +98 -11
  31. package/dist/ProfileExplorer/index.js +183 -32
  32. package/dist/ProfileFlameChart/SamplesStrips/SamplesGraph/index.js +333 -148
  33. package/dist/ProfileFlameChart/SamplesStrips/SamplesStrips.stories.js +69 -35
  34. package/dist/ProfileFlameChart/SamplesStrips/index.d.ts +2 -2
  35. package/dist/ProfileFlameChart/SamplesStrips/index.d.ts.map +1 -1
  36. package/dist/ProfileFlameChart/SamplesStrips/index.js +645 -134
  37. package/dist/ProfileFlameChart/SamplesStrips/labelSetUtils.js +114 -55
  38. package/dist/ProfileFlameChart/index.d.ts.map +1 -1
  39. package/dist/ProfileFlameChart/index.js +267 -129
  40. package/dist/ProfileFlameGraph/FlameGraphArrow/ContextMenu.d.ts.map +1 -1
  41. package/dist/ProfileFlameGraph/FlameGraphArrow/ContextMenu.js +288 -89
  42. package/dist/ProfileFlameGraph/FlameGraphArrow/ContextMenuWrapper.js +56 -20
  43. package/dist/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.js +211 -140
  44. package/dist/ProfileFlameGraph/FlameGraphArrow/MemoizedTooltip.js +133 -38
  45. package/dist/ProfileFlameGraph/FlameGraphArrow/MiniMap.js +261 -216
  46. package/dist/ProfileFlameGraph/FlameGraphArrow/TextWithEllipsis.d.ts.map +1 -1
  47. package/dist/ProfileFlameGraph/FlameGraphArrow/TextWithEllipsis.js +72 -47
  48. package/dist/ProfileFlameGraph/FlameGraphArrow/TooltipContext.d.ts.map +1 -1
  49. package/dist/ProfileFlameGraph/FlameGraphArrow/TooltipContext.js +58 -28
  50. package/dist/ProfileFlameGraph/FlameGraphArrow/ZoomControls.d.ts.map +1 -1
  51. package/dist/ProfileFlameGraph/FlameGraphArrow/ZoomControls.js +59 -8
  52. package/dist/ProfileFlameGraph/FlameGraphArrow/index.js +396 -179
  53. package/dist/ProfileFlameGraph/FlameGraphArrow/useBatchedRendering.d.ts.map +1 -1
  54. package/dist/ProfileFlameGraph/FlameGraphArrow/useBatchedRendering.js +68 -50
  55. package/dist/ProfileFlameGraph/FlameGraphArrow/useMappingList.js +62 -38
  56. package/dist/ProfileFlameGraph/FlameGraphArrow/useNodeColor.js +14 -6
  57. package/dist/ProfileFlameGraph/FlameGraphArrow/useScrollViewport.js +124 -82
  58. package/dist/ProfileFlameGraph/FlameGraphArrow/useVisibleNodes.js +160 -98
  59. package/dist/ProfileFlameGraph/FlameGraphArrow/useZoom.js +232 -112
  60. package/dist/ProfileFlameGraph/FlameGraphArrow/utils.js +137 -114
  61. package/dist/ProfileFlameGraph/benchmarks/benchdata/populateData.js +85 -0
  62. package/dist/ProfileFlameGraph/index.d.ts.map +1 -1
  63. package/dist/ProfileFlameGraph/index.js +324 -150
  64. package/dist/ProfileMetricsGraph/hooks/useQueryRange.js +140 -32
  65. package/dist/ProfileMetricsGraph/index.d.ts.map +1 -1
  66. package/dist/ProfileMetricsGraph/index.js +519 -258
  67. package/dist/ProfileSelector/CompareButton.js +132 -12
  68. package/dist/ProfileSelector/MetricsGraphSection.d.ts.map +1 -1
  69. package/dist/ProfileSelector/MetricsGraphSection.js +236 -64
  70. package/dist/ProfileSelector/index.d.ts.map +1 -1
  71. package/dist/ProfileSelector/index.js +727 -141
  72. package/dist/ProfileSelector/useAutoQuerySelector.js +249 -130
  73. package/dist/ProfileSource.js +230 -163
  74. package/dist/ProfileTypeSelector/index.js +214 -125
  75. package/dist/ProfileView/components/ActionButtons/GroupByDropdown.js +50 -4
  76. package/dist/ProfileView/components/ActionButtons/SortByDropdown.d.ts.map +1 -1
  77. package/dist/ProfileView/components/ActionButtons/SortByDropdown.js +141 -35
  78. package/dist/ProfileView/components/ColorStackLegend.d.ts.map +1 -1
  79. package/dist/ProfileView/components/ColorStackLegend.js +185 -55
  80. package/dist/ProfileView/components/DashboardItems/index.js +87 -28
  81. package/dist/ProfileView/components/DashboardLayout/index.js +108 -16
  82. package/dist/ProfileView/components/DiffLegend.js +172 -29
  83. package/dist/ProfileView/components/GroupByLabelsDropdown/index.js +199 -55
  84. package/dist/ProfileView/components/InvertCallStack/index.d.ts.map +1 -1
  85. package/dist/ProfileView/components/InvertCallStack/index.js +100 -12
  86. package/dist/ProfileView/components/ProfileFilters/filterPresets.js +260 -315
  87. package/dist/ProfileView/components/ProfileFilters/index.js +518 -215
  88. package/dist/ProfileView/components/ProfileFilters/useProfileFilters.js +370 -306
  89. package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.d.ts +2 -1
  90. package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.d.ts.map +1 -1
  91. package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.js +188 -118
  92. package/dist/ProfileView/components/ProfileHeader/index.js +105 -11
  93. package/dist/ProfileView/components/ShareButton/ResultBox.js +119 -16
  94. package/dist/ProfileView/components/ShareButton/index.js +352 -62
  95. package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.d.ts.map +1 -1
  96. package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.js +678 -194
  97. package/dist/ProfileView/components/Toolbars/SwitchMenuItem.js +94 -7
  98. package/dist/ProfileView/components/Toolbars/TableColumnsDropdown.d.ts.map +1 -1
  99. package/dist/ProfileView/components/Toolbars/TableColumnsDropdown.js +199 -157
  100. package/dist/ProfileView/components/Toolbars/index.d.ts +2 -2
  101. package/dist/ProfileView/components/Toolbars/index.d.ts.map +1 -1
  102. package/dist/ProfileView/components/Toolbars/index.js +441 -21
  103. package/dist/ProfileView/components/ViewSelector/Dropdown.js +233 -22
  104. package/dist/ProfileView/components/ViewSelector/index.d.ts.map +1 -1
  105. package/dist/ProfileView/components/ViewSelector/index.js +212 -86
  106. package/dist/ProfileView/components/VisualizationContainer/index.d.ts.map +1 -1
  107. package/dist/ProfileView/components/VisualizationContainer/index.js +52 -7
  108. package/dist/ProfileView/components/VisualizationPanel.js +185 -8
  109. package/dist/ProfileView/context/DashboardContext.d.ts.map +1 -1
  110. package/dist/ProfileView/context/DashboardContext.js +85 -29
  111. package/dist/ProfileView/context/ProfileViewContext.js +56 -15
  112. package/dist/ProfileView/hooks/useAutoSelectDimension.js +71 -41
  113. package/dist/ProfileView/hooks/useProfileMetadata.js +50 -18
  114. package/dist/ProfileView/hooks/useResetFlameGraphState.d.ts.map +1 -1
  115. package/dist/ProfileView/hooks/useResetFlameGraphState.js +32 -12
  116. package/dist/ProfileView/hooks/useResetStateOnProfileTypeChange.d.ts.map +1 -1
  117. package/dist/ProfileView/hooks/useResetStateOnProfileTypeChange.js +71 -27
  118. package/dist/ProfileView/hooks/useResetStateOnSeriesChange.d.ts.map +1 -1
  119. package/dist/ProfileView/hooks/useResetStateOnSeriesChange.js +40 -19
  120. package/dist/ProfileView/hooks/useVisualizationState.d.ts +3 -3
  121. package/dist/ProfileView/hooks/useVisualizationState.d.ts.map +1 -1
  122. package/dist/ProfileView/hooks/useVisualizationState.js +258 -67
  123. package/dist/ProfileView/index.js +383 -45
  124. package/dist/ProfileView/types/visualization.js +1 -13
  125. package/dist/ProfileView/utils/colorUtils.js +8 -7
  126. package/dist/ProfileViewWithData.d.ts.map +1 -1
  127. package/dist/ProfileViewWithData.js +332 -228
  128. package/dist/QueryControls/index.js +418 -47
  129. package/dist/Sandwich/components/CalleesSection.js +54 -4
  130. package/dist/Sandwich/components/CallersSection.js +97 -27
  131. package/dist/Sandwich/components/TableSection.js +77 -4
  132. package/dist/Sandwich/index.d.ts.map +1 -1
  133. package/dist/Sandwich/index.js +126 -14
  134. package/dist/Sandwich/utils/processRowData.js +48 -39
  135. package/dist/SelectWithRefresh/index.js +102 -28
  136. package/dist/SimpleMatchers/Select.js +520 -187
  137. package/dist/SimpleMatchers/index.js +590 -288
  138. package/dist/SourceView/Highlighter.js +230 -70
  139. package/dist/SourceView/LineNo.js +72 -17
  140. package/dist/SourceView/index.d.ts.map +1 -1
  141. package/dist/SourceView/index.js +178 -104
  142. package/dist/SourceView/lang-detector/ext-to-lang.json +798 -798
  143. package/dist/SourceView/lang-detector/index.js +28 -14
  144. package/dist/SourceView/useSelectedLineRange.d.ts.map +1 -1
  145. package/dist/SourceView/useSelectedLineRange.js +99 -23
  146. package/dist/Table/ColorCell.js +42 -1
  147. package/dist/Table/ColumnsVisibility.js +114 -6
  148. package/dist/Table/MoreDropdown.d.ts.map +1 -1
  149. package/dist/Table/MoreDropdown.js +122 -25
  150. package/dist/Table/TableContextMenu.d.ts.map +1 -1
  151. package/dist/Table/TableContextMenu.js +151 -137
  152. package/dist/Table/TableContextMenuWrapper.js +59 -14
  153. package/dist/Table/hooks/useColorManagement.js +58 -16
  154. package/dist/Table/hooks/useTableConfiguration.d.ts.map +1 -1
  155. package/dist/Table/hooks/useTableConfiguration.js +333 -169
  156. package/dist/Table/index.d.ts.map +1 -1
  157. package/dist/Table/index.js +222 -128
  158. package/dist/Table/utils/functions.js +169 -144
  159. package/dist/Table/utils/topAndBottomExpandedRowModel.js +69 -52
  160. package/dist/TimelineGuide/index.js +209 -16
  161. package/dist/TopTable/benchmarks/benchdata/populateData.js +91 -0
  162. package/dist/TopTable/index.d.ts.map +1 -1
  163. package/dist/TopTable/index.js +342 -123
  164. package/dist/contexts/LabelsQueryProvider.js +94 -32
  165. package/dist/contexts/UnifiedLabelsContext.js +114 -49
  166. package/dist/contexts/utils.js +37 -15
  167. package/dist/hooks/useCompareModeMeta.d.ts.map +1 -1
  168. package/dist/hooks/useCompareModeMeta.js +158 -64
  169. package/dist/hooks/useLabels.js +295 -52
  170. package/dist/hooks/useQueryState.d.ts +3 -3
  171. package/dist/hooks/useQueryState.d.ts.map +1 -1
  172. package/dist/hooks/useQueryState.js +373 -332
  173. package/dist/index.d.ts +2 -3
  174. package/dist/index.d.ts.map +1 -1
  175. package/dist/index.js +22 -8
  176. package/dist/testdata/fg-diff.json +3750 -0
  177. package/dist/testdata/fg-simple.json +1879 -0
  178. package/dist/testdata/link_data.json +56 -0
  179. package/dist/testdata/tabular.json +30 -0
  180. package/dist/testdata/test_flamegraph.json +26846 -0
  181. package/dist/testdata/test_graph.json +53 -0
  182. package/dist/useDelayedLoader.js +32 -18
  183. package/dist/useGrpcQuery/index.js +71 -11
  184. package/dist/useHasProfileData.js +90 -12
  185. package/dist/useQuery.js +205 -64
  186. package/dist/useSumBy.d.ts +1 -1
  187. package/dist/useSumBy.d.ts.map +1 -1
  188. package/dist/useSumBy.js +294 -138
  189. package/dist/utils.js +62 -30
  190. package/package.json +9 -10
  191. package/src/GraphTooltipArrow/index.tsx +3 -0
  192. package/src/GraphTooltipArrow/useGraphTooltipMetaInfo/index.ts +13 -11
  193. package/src/MatchersInput/SuggestionsList.test.tsx +70 -0
  194. package/src/MatchersInput/SuggestionsList.tsx +11 -10
  195. package/src/MatchersInput/index.tsx +1 -1
  196. package/src/MetricsGraph/MetricsTooltip/index.tsx +22 -34
  197. package/src/PreSelectedMatchers/index.tsx +3 -0
  198. package/src/ProfileExplorer/ProfileExplorerCompare.tsx +9 -4
  199. package/src/ProfileFlameChart/SamplesStrips/index.tsx +2 -2
  200. package/src/ProfileFlameChart/index.tsx +28 -21
  201. package/src/ProfileFlameGraph/FlameGraphArrow/ContextMenu.tsx +9 -10
  202. package/src/ProfileFlameGraph/FlameGraphArrow/TextWithEllipsis.tsx +6 -5
  203. package/src/ProfileFlameGraph/FlameGraphArrow/TooltipContext.tsx +3 -0
  204. package/src/ProfileFlameGraph/FlameGraphArrow/ZoomControls.tsx +3 -0
  205. package/src/ProfileFlameGraph/FlameGraphArrow/useBatchedRendering.ts +3 -0
  206. package/src/ProfileFlameGraph/index.tsx +9 -6
  207. package/src/ProfileMetricsGraph/index.tsx +8 -6
  208. package/src/ProfileSelector/MetricsGraphSection.tsx +10 -5
  209. package/src/ProfileSelector/index.tsx +61 -39
  210. package/src/ProfileView/components/ActionButtons/SortByDropdown.tsx +6 -10
  211. package/src/ProfileView/components/ColorStackLegend.tsx +4 -2
  212. package/src/ProfileView/components/InvertCallStack/index.tsx +4 -5
  213. package/src/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.test.tsx +192 -94
  214. package/src/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.ts +21 -21
  215. package/src/ProfileView/components/Toolbars/MultiLevelDropdown.tsx +28 -24
  216. package/src/ProfileView/components/Toolbars/TableColumnsDropdown.tsx +5 -4
  217. package/src/ProfileView/components/Toolbars/index.tsx +3 -3
  218. package/src/ProfileView/components/ViewSelector/index.tsx +16 -9
  219. package/src/ProfileView/components/VisualizationContainer/index.tsx +3 -0
  220. package/src/ProfileView/context/DashboardContext.tsx +6 -6
  221. package/src/ProfileView/hooks/useResetFlameGraphState.ts +4 -6
  222. package/src/ProfileView/hooks/useResetStateOnProfileTypeChange.ts +26 -24
  223. package/src/ProfileView/hooks/useResetStateOnSeriesChange.ts +8 -16
  224. package/src/ProfileView/hooks/useVisualizationState.ts +69 -61
  225. package/src/ProfileViewWithData.tsx +35 -29
  226. package/src/Sandwich/index.tsx +3 -4
  227. package/src/SourceView/index.tsx +2 -4
  228. package/src/SourceView/useSelectedLineRange.ts +19 -34
  229. package/src/Table/MoreDropdown.tsx +11 -9
  230. package/src/Table/TableContextMenu.tsx +13 -10
  231. package/src/Table/hooks/useTableConfiguration.tsx +11 -16
  232. package/src/Table/index.tsx +21 -12
  233. package/src/TopTable/index.tsx +4 -3
  234. package/src/hooks/useCompareModeMeta.ts +91 -61
  235. package/src/hooks/useQueryState.test.tsx +345 -275
  236. package/src/hooks/useQueryState.ts +118 -136
  237. package/src/index.tsx +15 -16
  238. package/src/useDelayedLoader.ts +10 -10
  239. package/src/useSumBy.ts +15 -21
  240. package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.test.js +0 -455
  241. package/dist/hooks/urlParsers.d.ts +0 -18
  242. package/dist/hooks/urlParsers.d.ts.map +0 -1
  243. package/dist/hooks/urlParsers.js +0 -32
  244. package/dist/hooks/useColorBy.d.ts +0 -5
  245. package/dist/hooks/useColorBy.d.ts.map +0 -1
  246. package/dist/hooks/useColorBy.js +0 -26
  247. package/dist/hooks/useDashboardItems.d.ts +0 -5
  248. package/dist/hooks/useDashboardItems.d.ts.map +0 -1
  249. package/dist/hooks/useDashboardItems.js +0 -27
  250. package/dist/hooks/useQueryState.test.js +0 -868
  251. package/src/hooks/urlParsers.ts +0 -38
  252. package/src/hooks/useColorBy.ts +0 -42
  253. package/src/hooks/useDashboardItems.ts +0 -46
@@ -15,7 +15,6 @@ import {useEffect, useMemo, useState} from 'react';
15
15
 
16
16
  import {Icon} from '@iconify/react';
17
17
  import {AnimatePresence, motion} from 'framer-motion';
18
- import {useQueryState} from 'nuqs';
19
18
 
20
19
  import {
21
20
  Label,
@@ -26,8 +25,11 @@ import {
26
25
  import {
27
26
  DateTimeRange,
28
27
  MetricsGraphSkeleton,
28
+ NumberParser,
29
+ NumberSerializer,
29
30
  TextWithTooltip,
30
31
  useParcaContext,
32
+ useURLStateCustom,
31
33
  } from '@parca/components';
32
34
  import {Query} from '@parca/parser';
33
35
  import {TEST_IDS, testId} from '@parca/test-utils';
@@ -36,7 +38,6 @@ import {capitalizeOnlyFirstLetter, formatDate, timePattern, valueFormatter} from
36
38
  import {MergedProfileSelection, ProfileSelection} from '..';
37
39
  import MetricsGraph, {ContextMenuItemOrSubmenu, Series, SeriesPoint} from '../MetricsGraph';
38
40
  import {useMetricsGraphDimensions} from '../MetricsGraph/useMetricsGraphDimensions';
39
- import {intParam} from '../hooks/urlParsers';
40
41
  import {getStepCountFromScreenWidth, useQueryRange} from './hooks/useQueryRange';
41
42
 
42
43
  const createProfileContextMenuItems = (
@@ -199,10 +200,11 @@ const ProfileMetricsGraph = ({
199
200
  comparing = false,
200
201
  sumBy,
201
202
  }: ProfileMetricsGraphProps): JSX.Element => {
202
- const [rawStepCount] = useQueryState(
203
- 'step_count',
204
- intParam.withDefault(getStepCountFromScreenWidth(10))
205
- );
203
+ const [rawStepCount] = useURLStateCustom<number>('step_count', {
204
+ defaultValue: String(getStepCountFromScreenWidth(10)),
205
+ parse: NumberParser,
206
+ stringify: NumberSerializer,
207
+ });
206
208
  // Clamp step count so the step duration is at least 1 second as we don't have this enforced server-side anymore.
207
209
  const stepCount = useMemo(() => {
208
210
  const maxForOneSecond = Math.floor((to - from) / 1000);
@@ -14,7 +14,7 @@
14
14
  import cx from 'classnames';
15
15
 
16
16
  import {Label, QueryServiceClient} from '@parca/client';
17
- import {DateTimeRange, useParcaContext} from '@parca/components';
17
+ import {DateTimeRange, useParcaContext, useURLStateBatch} from '@parca/components';
18
18
  import {Query} from '@parca/parser';
19
19
 
20
20
  import {ProfileSelection} from '..';
@@ -67,6 +67,7 @@ export function MetricsGraphSection({
67
67
  hasNoProfileTypes = false,
68
68
  }: MetricsGraphSectionProps): JSX.Element {
69
69
  const resetStateOnSeriesChange = useResetStateOnSeriesChange();
70
+ const batchUpdates = useURLStateBatch();
70
71
  const {profileExplorer} = useParcaContext();
71
72
  const {heightStyle} = useMetricsGraphDimensions(comparing, profileExplorer?.metricsGraph.height);
72
73
  const handleTimeRangeChange = (range: DateTimeRange): void => {
@@ -116,8 +117,10 @@ export function MetricsGraphSection({
116
117
 
117
118
  if (hasChanged) {
118
119
  // Immediately apply the filter when adding label matchers from the graph
119
- setNewQueryExpression(newQuery.toString());
120
- commitDraft(undefined, newQuery.toString());
120
+ batchUpdates(() => {
121
+ setNewQueryExpression(newQuery.toString());
122
+ commitDraft(undefined, newQuery.toString());
123
+ });
121
124
  }
122
125
  };
123
126
 
@@ -138,8 +141,10 @@ export function MetricsGraphSection({
138
141
 
139
142
  const mergeFrom = timestamp;
140
143
  const mergeTo = query.profileType().delta ? mergeFrom + BigInt(duration) : mergeFrom;
141
- resetStateOnSeriesChange(); // reset some state when a new series is selected
142
- setProfileSelection(mergeFrom, mergeTo, query);
144
+ batchUpdates(() => {
145
+ resetStateOnSeriesChange(); // reset some state when a new series is selected
146
+ setProfileSelection(mergeFrom, mergeTo, query);
147
+ });
143
148
  };
144
149
 
145
150
  return (
@@ -11,13 +11,19 @@
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
13
 
14
- import {Dispatch, SetStateAction, useCallback, useEffect, useMemo, useRef, useState} from 'react';
14
+ import {Dispatch, SetStateAction, useCallback, useMemo, useRef, useState} from 'react';
15
15
 
16
16
  import {RpcError} from '@protobuf-ts/runtime-rpc';
17
- import {useQueryState as useNuqsQueryState} from 'nuqs';
18
17
 
19
18
  import {ProfileTypesRequest, ProfileTypesResponse, QueryServiceClient} from '@parca/client';
20
- import {DateTimeRange, IconButton, useGrpcMetadata, useParcaContext} from '@parca/components';
19
+ import {
20
+ DateTimeRange,
21
+ IconButton,
22
+ useGrpcMetadata,
23
+ useParcaContext,
24
+ useURLState,
25
+ useURLStateBatch,
26
+ } from '@parca/components';
21
27
  import {CloseIcon} from '@parca/icons';
22
28
  import {Query} from '@parca/parser';
23
29
  import {TEST_IDS, testId} from '@parca/test-utils';
@@ -30,7 +36,6 @@ import {
30
36
  import {QueryControls} from '../QueryControls';
31
37
  import {LabelsQueryProvider, useLabelsQueryProvider} from '../contexts/LabelsQueryProvider';
32
38
  import {UnifiedLabelsProvider} from '../contexts/UnifiedLabelsContext';
33
- import {stringParam} from '../hooks/urlParsers';
34
39
  import {useLabelNames} from '../hooks/useLabels';
35
40
  import {useQueryState} from '../hooks/useQueryState';
36
41
  import useGrpcQuery from '../useGrpcQuery';
@@ -113,16 +118,8 @@ const ProfileSelector = ({
113
118
  onSearchHook,
114
119
  }: ProfileSelectorProps): JSX.Element => {
115
120
  const {externalProfilerComponent, additionalMetricsGraph} = useParcaContext();
116
- const [queryBrowserMode, setRawQueryBrowserMode] = useNuqsQueryState(
117
- 'query_browser_mode',
118
- stringParam
119
- );
120
- const setQueryBrowserMode = useCallback(
121
- (mode: string | null) => {
122
- void setRawQueryBrowserMode(mode);
123
- },
124
- [setRawQueryBrowserMode]
125
- );
121
+ const [queryBrowserMode, setQueryBrowserMode] = useURLState('query_browser_mode');
122
+ const batchUpdates = useURLStateBatch();
126
123
 
127
124
  const profileFilterDefaults = externalProfilerComponent?.profileFilterDefaults as
128
125
  | ProfileFilter[]
@@ -157,7 +154,20 @@ const ProfileSelector = ({
157
154
  );
158
155
 
159
156
  // Sync local timeRangeSelection when URL state changes externally (e.g., "Switch to 1 minute" button)
160
- useEffect(() => {
157
+ const [prevQueryTimeSelection, setPrevQueryTimeSelection] = useState(
158
+ querySelection.timeSelection
159
+ );
160
+ const [prevQueryFrom, setPrevQueryFrom] = useState(querySelection.from);
161
+ const [prevQueryTo, setPrevQueryTo] = useState(querySelection.to);
162
+
163
+ if (
164
+ prevQueryTimeSelection !== querySelection.timeSelection ||
165
+ prevQueryFrom !== querySelection.from ||
166
+ prevQueryTo !== querySelection.to
167
+ ) {
168
+ setPrevQueryTimeSelection(querySelection.timeSelection);
169
+ setPrevQueryFrom(querySelection.from);
170
+ setPrevQueryTo(querySelection.to);
161
171
  setTimeRangeSelection(
162
172
  DateTimeRange.fromRangeKey(
163
173
  querySelection.timeSelection,
@@ -165,7 +175,7 @@ const ProfileSelector = ({
165
175
  querySelection.to
166
176
  )
167
177
  );
168
- }, [querySelection.timeSelection, querySelection.from, querySelection.to]);
178
+ }
169
179
 
170
180
  const [queryExpressionString, setQueryExpressionString] = useState(draftSelection.expression);
171
181
 
@@ -201,18 +211,28 @@ const ProfileSelector = ({
201
211
  return result.response?.labelNames === undefined ? [] : result.response.labelNames;
202
212
  }, [result]);
203
213
 
204
- useEffect(() => {
214
+ const [prevEnforcedProfileName, setPrevEnforcedProfileName] = useState(enforcedProfileName);
215
+ const [prevQueryExpression, setPrevQueryExpression] = useState(querySelection.expression);
216
+
217
+ if (
218
+ prevEnforcedProfileName !== enforcedProfileName ||
219
+ prevQueryExpression !== querySelection.expression
220
+ ) {
221
+ setPrevEnforcedProfileName(enforcedProfileName);
222
+ setPrevQueryExpression(querySelection.expression);
205
223
  if (enforcedProfileName !== '') {
206
224
  const [q, changed] = Query.parse(querySelection.expression).setProfileName(
207
225
  enforcedProfileName
208
226
  );
209
227
  if (changed) {
210
228
  setQueryExpressionString(q.toString());
211
- return;
229
+ } else {
230
+ setQueryExpressionString(querySelection.expression);
212
231
  }
232
+ } else {
233
+ setQueryExpressionString(querySelection.expression);
213
234
  }
214
- setQueryExpressionString(querySelection.expression);
215
- }, [enforcedProfileName, querySelection.expression]);
235
+ }
216
236
 
217
237
  const enforcedProfileNameQuery = (): Query => {
218
238
  const pq = Query.parse(queryExpressionString);
@@ -225,25 +245,27 @@ const ProfileSelector = ({
225
245
  const selectedProfileName = query.profileName();
226
246
 
227
247
  const setQueryExpression = (updateTs = false): void => {
228
- if (onSearchHook != null) {
229
- onSearchHook();
230
- }
231
- // When updateTs is true, re-evaluate the time range to current values
232
- if (updateTs) {
233
- // Force re-evaluation of time range (important for relative ranges like "last 15 minutes")
234
- const currentFrom = timeRangeSelection.getFromMs(true);
235
- const currentTo = timeRangeSelection.getToMs(true);
236
- const currentRangeKey = timeRangeSelection.getRangeKey();
237
- // Commit with refreshed time range
238
- commitDraft({
239
- from: currentFrom,
240
- to: currentTo,
241
- timeSelection: currentRangeKey,
242
- });
243
- } else {
244
- // Commit the draft with existing values
245
- commitDraft();
246
- }
248
+ batchUpdates(() => {
249
+ if (onSearchHook != null) {
250
+ onSearchHook();
251
+ }
252
+ // When updateTs is true, re-evaluate the time range to current values
253
+ if (updateTs) {
254
+ // Force re-evaluation of time range (important for relative ranges like "last 15 minutes")
255
+ const currentFrom = timeRangeSelection.getFromMs(true);
256
+ const currentTo = timeRangeSelection.getToMs(true);
257
+ const currentRangeKey = timeRangeSelection.getRangeKey();
258
+ // Commit with refreshed time range
259
+ commitDraft({
260
+ from: currentFrom,
261
+ to: currentTo,
262
+ timeSelection: currentRangeKey,
263
+ });
264
+ } else {
265
+ // Commit the draft with existing values
266
+ commitDraft();
267
+ }
268
+ });
247
269
  };
248
270
 
249
271
  const setMatchersString = (matchers: string): void => {
@@ -11,23 +11,19 @@
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
13
 
14
- import {useQueryState} from 'nuqs';
15
-
16
- import {Select} from '@parca/components';
14
+ import {Select, useURLState} from '@parca/components';
17
15
 
18
16
  import {
19
17
  FIELD_CUMULATIVE,
20
18
  FIELD_DIFF,
21
19
  FIELD_FUNCTION_NAME,
22
20
  } from '../../../ProfileFlameGraph/FlameGraphArrow';
23
- import {stringParam} from '../../../hooks/urlParsers';
24
21
  import {useProfileViewContext} from '../../context/ProfileViewContext';
25
22
 
26
23
  const SortByDropdown = (): React.JSX.Element => {
27
- const [storeSortBy, setStoreSortBy] = useQueryState(
28
- 'sort_by',
29
- stringParam.withDefault(FIELD_FUNCTION_NAME)
30
- );
24
+ const [storeSortBy, setStoreSortBy] = useURLState('sort_by', {
25
+ defaultValue: FIELD_FUNCTION_NAME,
26
+ });
31
27
 
32
28
  const {compareMode} = useProfileViewContext();
33
29
 
@@ -74,8 +70,8 @@ const SortByDropdown = (): React.JSX.Element => {
74
70
  },
75
71
  },
76
72
  ]}
77
- selectedKey={storeSortBy}
78
- onSelection={key => void setStoreSortBy(key)}
73
+ selectedKey={storeSortBy as string}
74
+ onSelection={key => setStoreSortBy(key)}
79
75
  placeholder={'Sort By'}
80
76
  primary={false}
81
77
  disabled={false}
@@ -16,12 +16,12 @@ import React, {useMemo} from 'react';
16
16
  import {Icon} from '@iconify/react';
17
17
  import cx from 'classnames';
18
18
 
19
+ import {useURLState} from '@parca/components';
19
20
  import {USER_PREFERENCES, useCurrentColorProfile, useUserPreference} from '@parca/hooks';
20
21
  import {EVERYTHING_ELSE, selectDarkMode, useAppSelector} from '@parca/store';
21
22
 
22
23
  import {getMappingColors} from '../../ProfileFlameGraph/FlameGraphArrow';
23
24
  import useMappingList from '../../ProfileFlameGraph/FlameGraphArrow/useMappingList';
24
- import {useColorBy} from '../../hooks/useColorBy';
25
25
  import {useProfileFilters} from './ProfileFilters/useProfileFilters';
26
26
 
27
27
  interface Props {
@@ -37,7 +37,9 @@ const ColorStackLegend = ({mappings, compareMode = false, loading}: Props): Reac
37
37
  USER_PREFERENCES.FLAMEGRAPH_COLOR_PROFILE.key
38
38
  );
39
39
 
40
- const {colorBy} = useColorBy();
40
+ const [colorByValue, _] = useURLState('color_by');
41
+
42
+ const colorBy = colorByValue === 'binary' || colorByValue === undefined ? 'binary' : 'filename';
41
43
 
42
44
  const {appliedFilters, removeExcludeBinary, excludeBinary} = useProfileFilters();
43
45
 
@@ -12,20 +12,19 @@
12
12
  // limitations under the License.
13
13
 
14
14
  import {Icon} from '@iconify/react';
15
- import {useQueryState} from 'nuqs';
16
15
 
17
- import {Button} from '@parca/components';
16
+ import {Button, useURLState} from '@parca/components';
18
17
  import {TEST_IDS, testId} from '@parca/test-utils';
19
18
 
20
- import {invertCallStackParser} from '../../../hooks/urlParsers';
21
19
  import {useResetFlameGraphState} from '../../hooks/useResetFlameGraphState';
22
20
 
23
21
  const InvertCallStack = (): JSX.Element => {
24
- const [isInvert, setInvertStack] = useQueryState('invert_call_stack', invertCallStackParser);
22
+ const [invertStack = '', setInvertStack] = useURLState('invert_call_stack');
23
+ const isInvert = invertStack === 'true';
25
24
  const resetFlameGraphState = useResetFlameGraphState();
26
25
 
27
26
  const handleSetInvert = (value: boolean): void => {
28
- void setInvertStack(value);
27
+ setInvertStack(value ? 'true' : '');
29
28
 
30
29
  resetFlameGraphState();
31
30
  };