@parca/profile 0.16.415 → 0.16.417

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 (88) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/Callgraph/index.js +3 -2
  3. package/dist/GraphTooltipArrow/Content.d.ts +1 -3
  4. package/dist/GraphTooltipArrow/Content.d.ts.map +1 -1
  5. package/dist/GraphTooltipArrow/Content.js +4 -4
  6. package/dist/GraphTooltipArrow/DockedGraphTooltip/index.js +2 -2
  7. package/dist/GraphTooltipArrow/useGraphTooltipMetaInfo/index.d.ts +1 -3
  8. package/dist/GraphTooltipArrow/useGraphTooltipMetaInfo/index.d.ts.map +1 -1
  9. package/dist/GraphTooltipArrow/useGraphTooltipMetaInfo/index.js +6 -16
  10. package/dist/ProfileExplorer/ProfileExplorerCompare.d.ts.map +1 -1
  11. package/dist/ProfileExplorer/ProfileExplorerCompare.js +3 -3
  12. package/dist/ProfileExplorer/ProfileExplorerSingle.d.ts.map +1 -1
  13. package/dist/ProfileExplorer/ProfileExplorerSingle.js +1 -1
  14. package/dist/ProfileExplorer/index.d.ts.map +1 -1
  15. package/dist/ProfileExplorer/index.js +1 -7
  16. package/dist/ProfileIcicleGraph/IcicleGraph/ColorStackLegend.d.ts +1 -3
  17. package/dist/ProfileIcicleGraph/IcicleGraph/ColorStackLegend.d.ts.map +1 -1
  18. package/dist/ProfileIcicleGraph/IcicleGraph/ColorStackLegend.js +2 -2
  19. package/dist/ProfileIcicleGraph/IcicleGraph/index.d.ts +0 -2
  20. package/dist/ProfileIcicleGraph/IcicleGraph/index.d.ts.map +1 -1
  21. package/dist/ProfileIcicleGraph/IcicleGraph/index.js +4 -3
  22. package/dist/ProfileIcicleGraph/IcicleGraphArrow/ColorStackLegend.d.ts +1 -3
  23. package/dist/ProfileIcicleGraph/IcicleGraphArrow/ColorStackLegend.d.ts.map +1 -1
  24. package/dist/ProfileIcicleGraph/IcicleGraphArrow/ColorStackLegend.js +8 -20
  25. package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.d.ts +1 -3
  26. package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.d.ts.map +1 -1
  27. package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.js +2 -2
  28. package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.d.ts +1 -2
  29. package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.d.ts.map +1 -1
  30. package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.js +6 -9
  31. package/dist/ProfileIcicleGraph/index.d.ts +1 -3
  32. package/dist/ProfileIcicleGraph/index.d.ts.map +1 -1
  33. package/dist/ProfileIcicleGraph/index.js +20 -48
  34. package/dist/ProfileMetricsGraph/index.js +1 -2
  35. package/dist/ProfileSelector/index.d.ts.map +1 -1
  36. package/dist/ProfileSelector/index.js +19 -2
  37. package/dist/ProfileView/FilterByFunctionButton.d.ts +1 -4
  38. package/dist/ProfileView/FilterByFunctionButton.d.ts.map +1 -1
  39. package/dist/ProfileView/FilterByFunctionButton.js +12 -3
  40. package/dist/ProfileView/ViewSelector.d.ts +1 -3
  41. package/dist/ProfileView/ViewSelector.d.ts.map +1 -1
  42. package/dist/ProfileView/ViewSelector.js +3 -4
  43. package/dist/ProfileView/VisualizationPanel.d.ts +0 -2
  44. package/dist/ProfileView/VisualizationPanel.d.ts.map +1 -1
  45. package/dist/ProfileView/VisualizationPanel.js +2 -2
  46. package/dist/ProfileView/index.d.ts +1 -5
  47. package/dist/ProfileView/index.d.ts.map +1 -1
  48. package/dist/ProfileView/index.js +11 -18
  49. package/dist/ProfileViewWithData.d.ts +1 -3
  50. package/dist/ProfileViewWithData.d.ts.map +1 -1
  51. package/dist/ProfileViewWithData.js +15 -12
  52. package/dist/SourceView/index.js +1 -1
  53. package/dist/SourceView/useSelectedLineRange.js +1 -1
  54. package/dist/Table/index.d.ts +1 -2
  55. package/dist/Table/index.d.ts.map +1 -1
  56. package/dist/Table/index.js +9 -25
  57. package/dist/TopTable/index.d.ts.map +1 -1
  58. package/dist/TopTable/index.js +3 -7
  59. package/dist/index.d.ts +3 -0
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +3 -0
  62. package/dist/styles.css +1 -1
  63. package/package.json +7 -7
  64. package/src/Callgraph/index.tsx +3 -3
  65. package/src/GraphTooltipArrow/Content.tsx +4 -14
  66. package/src/GraphTooltipArrow/DockedGraphTooltip/index.tsx +2 -2
  67. package/src/GraphTooltipArrow/useGraphTooltipMetaInfo/index.ts +6 -22
  68. package/src/ProfileExplorer/ProfileExplorerCompare.tsx +2 -3
  69. package/src/ProfileExplorer/ProfileExplorerSingle.tsx +1 -5
  70. package/src/ProfileExplorer/index.tsx +0 -8
  71. package/src/ProfileIcicleGraph/IcicleGraph/ColorStackLegend.tsx +2 -4
  72. package/src/ProfileIcicleGraph/IcicleGraph/index.tsx +5 -8
  73. package/src/ProfileIcicleGraph/IcicleGraphArrow/ColorStackLegend.tsx +8 -27
  74. package/src/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.tsx +2 -4
  75. package/src/ProfileIcicleGraph/IcicleGraphArrow/index.tsx +4 -17
  76. package/src/ProfileIcicleGraph/index.tsx +19 -67
  77. package/src/ProfileMetricsGraph/index.tsx +2 -2
  78. package/src/ProfileSelector/index.tsx +23 -2
  79. package/src/ProfileView/FilterByFunctionButton.tsx +15 -9
  80. package/src/ProfileView/ViewSelector.tsx +6 -7
  81. package/src/ProfileView/VisualizationPanel.tsx +1 -9
  82. package/src/ProfileView/index.tsx +8 -23
  83. package/src/ProfileViewWithData.tsx +15 -18
  84. package/src/SourceView/index.tsx +1 -1
  85. package/src/SourceView/useSelectedLineRange.ts +2 -2
  86. package/src/Table/index.tsx +10 -41
  87. package/src/TopTable/index.tsx +3 -8
  88. package/src/index.tsx +4 -0
@@ -19,7 +19,6 @@ import cx from 'classnames';
19
19
  import {useURLState} from '@parca/components';
20
20
  import {USER_PREFERENCES, useCurrentColorProfile, useUserPreference} from '@parca/hooks';
21
21
  import {EVERYTHING_ELSE, selectDarkMode, useAppSelector} from '@parca/store';
22
- import {type NavigateFunction} from '@parca/utilities';
23
22
 
24
23
  import {getMappingColors} from '.';
25
24
  import useMappingList from './useMappingList';
@@ -27,24 +26,18 @@ import useMappingList from './useMappingList';
27
26
  interface Props {
28
27
  mappings?: string[];
29
28
  loading?: boolean;
30
- navigateTo?: NavigateFunction;
31
29
  compareMode?: boolean;
32
30
  }
33
31
 
34
- const ColorStackLegend = ({
35
- mappings,
36
- navigateTo,
37
- compareMode = false,
38
- loading,
39
- }: Props): React.JSX.Element => {
32
+ const ColorStackLegend = ({mappings, compareMode = false, loading}: Props): React.JSX.Element => {
40
33
  const isDarkMode = useAppSelector(selectDarkMode);
41
34
  const currentColorProfile = useCurrentColorProfile();
42
35
  const [colorProfileName] = useUserPreference<string>(
43
36
  USER_PREFERENCES.FLAMEGRAPH_COLOR_PROFILE.key
44
37
  );
45
- const [currentSearchString, setSearchString] = useURLState({
46
- param: 'binary_frame_filter',
47
- navigateTo,
38
+ const [currentSearchString, setSearchString] = useURLState<string[]>('binary_frame_filter', {
39
+ alwaysReturnArray: true,
40
+ defaultValue: [],
48
41
  });
49
42
 
50
43
  const mappingsList = useMappingList(mappings);
@@ -79,7 +72,7 @@ const ColorStackLegend = ({
79
72
  }
80
73
 
81
74
  return (
82
- <div className="my-4 flex w-full flex-wrap justify-start">
75
+ <div className="my-4 flex w-full flex-wrap justify-start column-gap-2">
83
76
  {stackColorArray.map(([feature, color]) => {
84
77
  const filteringAllowed = feature !== EVERYTHING_ELSE;
85
78
  const isHighlighted =
@@ -88,7 +81,7 @@ const ColorStackLegend = ({
88
81
  <div
89
82
  key={feature}
90
83
  className={cx(
91
- 'flex-no-wrap mb-1 flex w-1/5 items-center justify-between text-ellipsis p-1',
84
+ 'flex-no-wrap mb-1 flex w-[19.25%] items-center justify-between text-ellipsis p-1',
92
85
  {
93
86
  'cursor-pointer': filteringAllowed,
94
87
  'bg-gray-200 dark:bg-gray-800': isHighlighted,
@@ -100,12 +93,7 @@ const ColorStackLegend = ({
100
93
  }
101
94
 
102
95
  // Check if the current search string is defined and an array
103
- const updatedSearchString = Array.isArray(currentSearchString)
104
- ? [...currentSearchString, feature] // If array, append the feature
105
- : // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
106
- currentSearchString // If not array, preserve current value
107
- ? currentSearchString.split(',') // If string, split by commas
108
- : [feature]; // If undefined, initialize array with feature
96
+ const updatedSearchString = [...currentSearchString, feature]; // If array, append the feature
109
97
 
110
98
  setSearchString(updatedSearchString);
111
99
  }}
@@ -123,15 +111,8 @@ const ColorStackLegend = ({
123
111
  <Icon
124
112
  icon="radix-icons:cross-circled"
125
113
  onClick={e => {
126
- let searchString: string[] = [];
127
- if (typeof currentSearchString === 'string') {
128
- searchString.push(currentSearchString);
129
- } else {
130
- searchString = currentSearchString;
131
- }
132
-
133
114
  // remove the current feature from the search string array of strings
134
- setSearchString(searchString.filter((f: string) => f !== feature));
115
+ setSearchString(currentSearchString.filter((f: string) => f !== feature));
135
116
  e.stopPropagation();
136
117
  }}
137
118
  />
@@ -19,7 +19,7 @@ import {Tooltip} from 'react-tooltip';
19
19
  import {useParcaContext} from '@parca/components';
20
20
  import {USER_PREFERENCES, useUserPreference} from '@parca/hooks';
21
21
  import {ProfileType} from '@parca/parser';
22
- import {getLastItem, type NavigateFunction} from '@parca/utilities';
22
+ import {getLastItem} from '@parca/utilities';
23
23
 
24
24
  import {useGraphTooltip} from '../../GraphTooltipArrow/useGraphTooltip';
25
25
  import {useGraphTooltipMetaInfo} from '../../GraphTooltipArrow/useGraphTooltipMetaInfo';
@@ -34,7 +34,6 @@ interface ContextMenuProps {
34
34
  totalUnfiltered: bigint;
35
35
  row: number;
36
36
  level: number;
37
- navigateTo: NavigateFunction;
38
37
  trackVisibility: (isVisible: boolean) => void;
39
38
  curPath: string[];
40
39
  setCurPath: (path: string[]) => void;
@@ -49,7 +48,6 @@ const ContextMenu = ({
49
48
  totalUnfiltered,
50
49
  row,
51
50
  level,
52
- navigateTo,
53
51
  trackVisibility,
54
52
  curPath,
55
53
  setCurPath,
@@ -83,7 +81,7 @@ const ContextMenu = ({
83
81
  mappingFile,
84
82
  mappingBuildID,
85
83
  inlined,
86
- } = useGraphTooltipMetaInfo({table, row, navigateTo});
84
+ } = useGraphTooltipMetaInfo({table, row});
87
85
 
88
86
  if (contextMenuData === null) {
89
87
  return <></>;
@@ -27,13 +27,7 @@ import {
27
27
  useAppDispatch,
28
28
  useAppSelector,
29
29
  } from '@parca/store';
30
- import {
31
- getLastItem,
32
- scaleLinear,
33
- selectQueryParam,
34
- type ColorConfig,
35
- type NavigateFunction,
36
- } from '@parca/utilities';
30
+ import {getLastItem, scaleLinear, type ColorConfig} from '@parca/utilities';
37
31
 
38
32
  import GraphTooltipArrow from '../../GraphTooltipArrow';
39
33
  import GraphTooltipArrowContent from '../../GraphTooltipArrow/Content';
@@ -70,7 +64,6 @@ interface IcicleGraphArrowProps {
70
64
  width?: number;
71
65
  curPath: string[];
72
66
  setCurPath: (path: string[]) => void;
73
- navigateTo?: NavigateFunction;
74
67
  sortBy: string;
75
68
  flamegraphLoading: boolean;
76
69
  isHalfScreen: boolean;
@@ -101,7 +94,6 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
101
94
  setCurPath,
102
95
  curPath,
103
96
  profileType,
104
- navigateTo,
105
97
  sortBy,
106
98
  flamegraphLoading,
107
99
  mappingsListFromMetadata,
@@ -125,12 +117,9 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
125
117
  const svg = useRef(null);
126
118
  const ref = useRef<SVGGElement>(null);
127
119
 
128
- const [binaryFrameFilter, setBinaryFrameFilter] = useURLState({
129
- param: 'binary_frame_filter',
130
- navigateTo,
131
- });
120
+ const [binaryFrameFilter, setBinaryFrameFilter] = useURLState('binary_frame_filter');
132
121
 
133
- const currentSearchString = (selectQueryParam('search_string') as string) ?? '';
122
+ const [currentSearchString] = useURLState('search_string');
134
123
  const {compareMode} = useProfileViewContext();
135
124
  const currentColorProfile = useCurrentColorProfile();
136
125
  const colorForSimilarNodes = currentColorProfile.colorForSimilarNodes;
@@ -258,7 +247,7 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
258
247
  path={path}
259
248
  level={0}
260
249
  isRoot={true}
261
- searchString={currentSearchString}
250
+ searchString={(currentSearchString as string) ?? ''}
262
251
  setHoveringRow={setHoveringRow}
263
252
  setHoveringLevel={highlightSimilarStacksSetLevel}
264
253
  sortBy={sortBy}
@@ -312,7 +301,6 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
312
301
  total={total}
313
302
  totalUnfiltered={total + filtered}
314
303
  profileType={profileType}
315
- navigateTo={navigateTo as NavigateFunction}
316
304
  trackVisibility={trackVisibility}
317
305
  curPath={curPath}
318
306
  setCurPath={setCurPath}
@@ -341,7 +329,6 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
341
329
  total={total}
342
330
  totalUnfiltered={total + filtered}
343
331
  profileType={profileType}
344
- navigateTo={navigateTo as NavigateFunction}
345
332
  unit={arrow.unit}
346
333
  />
347
334
  </GraphTooltipArrow>
@@ -26,19 +26,14 @@ import {
26
26
  } from '@parca/components';
27
27
  import {USER_PREFERENCES, useUserPreference} from '@parca/hooks';
28
28
  import {ProfileType} from '@parca/parser';
29
- import {
30
- capitalizeOnlyFirstLetter,
31
- divide,
32
- selectQueryParam,
33
- type NavigateFunction,
34
- } from '@parca/utilities';
29
+ import {capitalizeOnlyFirstLetter, divide, selectQueryParam} from '@parca/utilities';
35
30
 
36
31
  import {useProfileViewContext} from '../ProfileView/ProfileViewContext';
37
32
  import DiffLegend from '../components/DiffLegend';
38
33
  import GroupByDropdown from './ActionButtons/GroupByDropdown';
39
34
  import SortBySelect from './ActionButtons/SortBySelect';
40
- import IcicleGraph from './IcicleGraph';
41
- import IcicleGraphArrow, {FIELD_FUNCTION_NAME} from './IcicleGraphArrow';
35
+ import {IcicleGraph} from './IcicleGraph';
36
+ import {FIELD_FUNCTION_NAME, IcicleGraphArrow} from './IcicleGraphArrow';
42
37
  import ColorStackLegend from './IcicleGraphArrow/ColorStackLegend';
43
38
  import useMappingList from './IcicleGraphArrow/useMappingList';
44
39
 
@@ -55,7 +50,6 @@ interface ProfileIcicleGraphProps {
55
50
  profileType?: ProfileType;
56
51
  curPath: string[] | [];
57
52
  setNewCurPath: (path: string[]) => void;
58
- navigateTo?: NavigateFunction;
59
53
  loading: boolean;
60
54
  setActionButtons?: (buttons: React.JSX.Element) => void;
61
55
  error?: any;
@@ -68,21 +62,9 @@ const ErrorContent = ({errorMessage}: {errorMessage: string}): JSX.Element => {
68
62
  return <div className="flex justify-center p-10">{errorMessage}</div>;
69
63
  };
70
64
 
71
- const ShowHideLegendButton = ({
72
- navigateTo,
73
- isHalfScreen,
74
- }: {
75
- navigateTo?: NavigateFunction;
76
- isHalfScreen: boolean;
77
- }): JSX.Element => {
78
- const [colorStackLegend, setStoreColorStackLegend] = useURLState({
79
- param: 'color_stack_legend',
80
- navigateTo,
81
- });
82
- const [binaryFrameFilter, setBinaryFrameFilter] = useURLState({
83
- param: 'binary_frame_filter',
84
- navigateTo,
85
- });
65
+ const ShowHideLegendButton = ({isHalfScreen}: {isHalfScreen: boolean}): JSX.Element => {
66
+ const [colorStackLegend, setStoreColorStackLegend] = useURLState('color_stack_legend');
67
+ const [binaryFrameFilter, setBinaryFrameFilter] = useURLState('binary_frame_filter');
86
68
 
87
69
  const {compareMode} = useProfileViewContext();
88
70
 
@@ -156,16 +138,15 @@ const ShowHideLegendButton = ({
156
138
  );
157
139
  };
158
140
 
159
- const GroupAndSortActionButtons = ({navigateTo}: {navigateTo?: NavigateFunction}): JSX.Element => {
160
- const [storeSortBy = FIELD_FUNCTION_NAME, setStoreSortBy] = useURLState({
161
- param: 'sort_by',
162
- navigateTo,
141
+ const GroupAndSortActionButtons = (): JSX.Element => {
142
+ const [storeSortBy, setStoreSortBy] = useURLState('sort_by', {
143
+ defaultValue: FIELD_FUNCTION_NAME,
163
144
  });
164
145
  const {compareMode} = useProfileViewContext();
165
146
 
166
- const [storeGroupBy = [FIELD_FUNCTION_NAME], setStoreGroupBy] = useURLState({
167
- param: 'group_by',
168
- navigateTo,
147
+ const [groupBy, setStoreGroupBy] = useURLState<string[]>('group_by', {
148
+ defaultValue: [FIELD_FUNCTION_NAME],
149
+ alwaysReturnArray: true,
169
150
  });
170
151
 
171
152
  const setGroupBy = useCallback(
@@ -175,16 +156,6 @@ const GroupAndSortActionButtons = ({navigateTo}: {navigateTo?: NavigateFunction}
175
156
  [setStoreGroupBy]
176
157
  );
177
158
 
178
- const groupBy = useMemo(() => {
179
- if (storeGroupBy !== undefined) {
180
- if (typeof storeGroupBy === 'string') {
181
- return [storeGroupBy];
182
- }
183
- return storeGroupBy;
184
- }
185
- return [FIELD_FUNCTION_NAME];
186
- }, [storeGroupBy]);
187
-
188
159
  const toggleGroupBy = useCallback(
189
160
  (key: string): void => {
190
161
  groupBy.includes(key)
@@ -214,7 +185,6 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
214
185
  curPath,
215
186
  setNewCurPath,
216
187
  profileType,
217
- navigateTo,
218
188
  loading,
219
189
  setActionButtons,
220
190
  error,
@@ -229,26 +199,17 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
229
199
 
230
200
  const mappingsList = useMappingList(mappings);
231
201
 
232
- const [storeSortBy = FIELD_FUNCTION_NAME] = useURLState({
233
- param: 'sort_by',
234
- navigateTo,
235
- });
202
+ const [storeSortBy = FIELD_FUNCTION_NAME] = useURLState('sort_by');
236
203
 
237
- const [invertStack = '', setInvertStack] = useURLState({
238
- param: 'invert_call_stack',
239
- navigateTo,
240
- });
204
+ const [invertStack = '', setInvertStack] = useURLState('invert_call_stack');
241
205
  const isInvert = invertStack === 'true';
242
206
 
243
207
  // By default, we want delta profiles (CPU) to be relatively compared.
244
208
  // For non-delta profiles, like goroutines or memory, we want the profiles to be compared absolutely.
245
209
  const compareAbsoluteDefault = profileType?.delta === false ? 'true' : 'false';
246
210
 
247
- const [compareAbsolute = compareAbsoluteDefault, setCompareAbsolute] = useURLState({
248
- param: 'compare_absolute',
249
- navigateTo,
250
- withURLUpdate: true,
251
- });
211
+ const [compareAbsolute = compareAbsoluteDefault, setCompareAbsolute] =
212
+ useURLState('compare_absolute');
252
213
  const isCompareAbsolute = compareAbsolute === 'true';
253
214
 
254
215
  const [
@@ -285,7 +246,7 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
285
246
  setActionButtons?.(
286
247
  <div className="flex w-full justify-end gap-2 pb-2">
287
248
  <div className="ml-2 flex w-full flex-col items-start justify-between gap-2 md:flex-row md:items-end">
288
- {<GroupAndSortActionButtons navigateTo={navigateTo} />}
249
+ {<GroupAndSortActionButtons />}
289
250
  {isHalfScreen ? (
290
251
  <IconButton
291
252
  icon={isInvert ? 'ph:sort-ascending' : 'ph:sort-descending'}
@@ -303,7 +264,7 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
303
264
  <Icon icon={isInvert ? 'ph:sort-ascending' : 'ph:sort-descending'} width={20} />
304
265
  </Button>
305
266
  )}
306
- <ShowHideLegendButton isHalfScreen={isHalfScreen} navigateTo={navigateTo} />
267
+ <ShowHideLegendButton isHalfScreen={isHalfScreen} />
307
268
  {compareMode && (
308
269
  <Button
309
270
  variant="neutral"
@@ -340,7 +301,6 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
340
301
  </div>
341
302
  );
342
303
  }, [
343
- navigateTo,
344
304
  isInvert,
345
305
  setInvertStack,
346
306
  arrow,
@@ -391,7 +351,6 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
391
351
  curPath={curPath}
392
352
  setCurPath={setNewCurPath}
393
353
  profileType={profileType}
394
- navigateTo={navigateTo}
395
354
  />
396
355
  );
397
356
 
@@ -405,7 +364,6 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
405
364
  curPath={curPath}
406
365
  setCurPath={setNewCurPath}
407
366
  profileType={profileType}
408
- navigateTo={navigateTo}
409
367
  sortBy={storeSortBy as string}
410
368
  flamegraphLoading={isLoading}
411
369
  isHalfScreen={isHalfScreen}
@@ -423,7 +381,6 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
423
381
  curPath,
424
382
  setNewCurPath,
425
383
  profileType,
426
- navigateTo,
427
384
  storeSortBy,
428
385
  isHalfScreen,
429
386
  isDarkMode,
@@ -455,12 +412,7 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
455
412
  >
456
413
  {compareMode ? <DiffLegend /> : null}
457
414
  {isColorStackLegendEnabled && (
458
- <ColorStackLegend
459
- navigateTo={navigateTo}
460
- compareMode={compareMode}
461
- mappings={mappings}
462
- loading={isLoading}
463
- />
415
+ <ColorStackLegend compareMode={compareMode} mappings={mappings} loading={isLoading} />
464
416
  )}
465
417
  <div className="min-h-48" id="h-icicle-graph">
466
418
  <>{icicleGraph}</>
@@ -101,8 +101,8 @@ export const useQueryRange = (
101
101
  skip = false
102
102
  ): IQueryRangeState => {
103
103
  const metadata = useGrpcMetadata();
104
- const {navigateTo} = useParcaContext();
105
- const [stepCountStr, setStepCount] = useURLState({param: 'step_count', navigateTo});
104
+ const [stepCountStr, setStepCount] = useURLState('step_count');
105
+
106
106
  const defaultStepCount = useMemo(() => {
107
107
  return getStepCountFromScreenWidth(10);
108
108
  }, []);
@@ -11,10 +11,10 @@
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
13
 
14
- import React, {useEffect, useMemo, useState} from 'react';
14
+ import React, {useEffect, useMemo, useRef, useState} from 'react';
15
15
 
16
16
  import {RpcError} from '@protobuf-ts/runtime-rpc';
17
- import Select from 'react-select';
17
+ import Select, {type SelectInstance} from 'react-select';
18
18
 
19
19
  import {Label, ProfileTypesResponse, QueryServiceClient} from '@parca/client';
20
20
  import {
@@ -105,6 +105,7 @@ const ProfileSelector = ({
105
105
  } = useProfileTypes(queryClient);
106
106
  const {heightStyle} = useMetricsGraphDimensions(comparing);
107
107
  const {viewComponent} = useParcaContext();
108
+ const sumByRef = useRef(null);
108
109
 
109
110
  const [timeRangeSelection, setTimeRangeSelection] = useState(
110
111
  DateTimeRange.fromRangeKey(querySelection.timeSelection, querySelection.from, querySelection.to)
@@ -316,6 +317,26 @@ const ProfileSelector = ({
316
317
  indicatorSeparator: () => ({display: 'none'}),
317
318
  }}
318
319
  isDisabled={!profileType.delta}
320
+ ref={sumByRef}
321
+ onKeyDown={e => {
322
+ const currentRef = sumByRef.current as unknown as SelectInstance | null;
323
+ if (currentRef == null) {
324
+ return;
325
+ }
326
+ const inputRef = currentRef.inputRef;
327
+ if (inputRef == null) {
328
+ return;
329
+ }
330
+
331
+ if (
332
+ e.key === 'Enter' &&
333
+ inputRef.value === '' &&
334
+ currentRef.state.focusedOptionId === null // menu is not open
335
+ ) {
336
+ setQueryExpression(true);
337
+ currentRef.blur();
338
+ }
339
+ }}
319
340
  />
320
341
  </div>
321
342
  <DateTimeRangePicker
@@ -16,14 +16,14 @@ import {useCallback, useMemo, useState} from 'react';
16
16
  import {Icon} from '@iconify/react';
17
17
 
18
18
  import {Input, useURLState} from '@parca/components';
19
- import type {NavigateFunction} from '@parca/utilities';
20
-
21
- const FilterByFunctionButton = ({
22
- navigateTo,
23
- }: {
24
- navigateTo: NavigateFunction | undefined;
25
- }): JSX.Element => {
26
- const [storeValue, setStoreValue] = useURLState({param: 'filter_by_function', navigateTo});
19
+ import {USER_PREFERENCES, useUserPreference} from '@parca/hooks';
20
+
21
+ const FilterByFunctionButton = (): JSX.Element => {
22
+ const [highlightAfterFilteringEnabled] = useUserPreference<boolean>(
23
+ USER_PREFERENCES.HIGHTLIGHT_AFTER_FILTERING.key
24
+ );
25
+ const [storeValue, setStoreValue] = useURLState('filter_by_function');
26
+ const [_, setSearchString] = useURLState('search_string');
27
27
  const [localValue, setLocalValue] = useState(storeValue as string);
28
28
 
29
29
  const isClearAction = useMemo(() => {
@@ -34,10 +34,16 @@ const FilterByFunctionButton = ({
34
34
  if (isClearAction) {
35
35
  setLocalValue('');
36
36
  setStoreValue('');
37
+ if (highlightAfterFilteringEnabled) {
38
+ setSearchString('');
39
+ }
37
40
  } else {
38
41
  setStoreValue(localValue);
42
+ if (highlightAfterFilteringEnabled) {
43
+ setSearchString(localValue);
44
+ }
39
45
  }
40
- }, [localValue, isClearAction, setStoreValue]);
46
+ }, [localValue, isClearAction, setStoreValue, highlightAfterFilteringEnabled, setSearchString]);
41
47
 
42
48
  return (
43
49
  <Input
@@ -13,12 +13,10 @@
13
13
 
14
14
  import {Select, useParcaContext, useURLState, type SelectElement} from '@parca/components';
15
15
  import {useUIFeatureFlag} from '@parca/hooks';
16
- import type {NavigateFunction} from '@parca/utilities';
17
16
 
18
17
  interface Props {
19
18
  position: number;
20
19
  defaultValue: string;
21
- navigateTo?: NavigateFunction;
22
20
  placeholderText?: string;
23
21
  primary?: boolean;
24
22
  addView?: boolean;
@@ -29,7 +27,6 @@ interface Props {
29
27
 
30
28
  const ViewSelector = ({
31
29
  defaultValue,
32
- navigateTo,
33
30
  position,
34
31
  placeholderText,
35
32
  primary = false,
@@ -39,10 +36,12 @@ const ViewSelector = ({
39
36
  id,
40
37
  }: Props): JSX.Element => {
41
38
  const [callgraphEnabled] = useUIFeatureFlag('callgraph');
42
- const [dashboardItems = ['icicle'], setDashboardItems] = useURLState({
43
- param: 'dashboard_items',
44
- navigateTo,
45
- });
39
+ const [dashboardItems = ['icicle'], setDashboardItems] = useURLState<string[]>(
40
+ 'dashboard_items',
41
+ {
42
+ alwaysReturnArray: true,
43
+ }
44
+ );
46
45
  const {enableSourcesView} = useParcaContext();
47
46
 
48
47
  const allItems: Array<{key: string; canBeSelected: boolean; supportingText?: string}> = [
@@ -19,7 +19,6 @@ import type {DraggableProvidedDragHandleProps} from 'react-beautiful-dnd';
19
19
 
20
20
  import {IconButton, useParcaContext} from '@parca/components';
21
21
  import {CloseIcon} from '@parca/icons';
22
- import type {NavigateFunction} from '@parca/utilities';
23
22
 
24
23
  import ViewSelector from './ViewSelector';
25
24
 
@@ -28,7 +27,6 @@ interface Props {
28
27
  index: number;
29
28
  isMultiPanelView: boolean;
30
29
  handleClosePanel: (dashboardItem: string) => void;
31
- navigateTo: NavigateFunction | undefined;
32
30
  dragHandleProps: DraggableProvidedDragHandleProps | null | undefined;
33
31
  getDashboardItemByType: (props: {
34
32
  type: string;
@@ -42,7 +40,6 @@ export const VisualizationPanel = React.memo(function VisualizationPanel({
42
40
  index,
43
41
  isMultiPanelView,
44
42
  handleClosePanel,
45
- navigateTo,
46
43
  dragHandleProps,
47
44
  getDashboardItemByType,
48
45
  }: Props): JSX.Element {
@@ -73,12 +70,7 @@ export const VisualizationPanel = React.memo(function VisualizationPanel({
73
70
  isMultiPanelView && dashboardItem === 'icicle' && 'pb-[10px]'
74
71
  )}
75
72
  >
76
- <ViewSelector
77
- id="h-switch-viz"
78
- defaultValue={dashboardItem}
79
- navigateTo={navigateTo}
80
- position={index}
81
- />
73
+ <ViewSelector id="h-switch-viz" defaultValue={dashboardItem} position={index} />
82
74
 
83
75
  {dashboardItem === 'icicle' && flamegraphHint != null ? (
84
76
  <div className="px-2">{flamegraphHint}</div>
@@ -11,7 +11,7 @@
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
13
 
14
- import {Profiler, ProfilerProps, useEffect, useMemo, useState} from 'react';
14
+ import {Profiler, ProfilerProps, useEffect, useState} from 'react';
15
15
 
16
16
  import {Icon} from '@iconify/react';
17
17
  import cx from 'classnames';
@@ -51,15 +51,13 @@ import {jsonToDot} from '../Callgraph/utils';
51
51
  import ProfileIcicleGraph from '../ProfileIcicleGraph';
52
52
  import {ProfileSource} from '../ProfileSource';
53
53
  import {SourceView} from '../SourceView';
54
- import Table from '../Table';
54
+ import {Table} from '../Table';
55
55
  import ProfileShareButton from '../components/ProfileShareButton';
56
56
  import FilterByFunctionButton from './FilterByFunctionButton';
57
57
  import {ProfileViewContextProvider} from './ProfileViewContext';
58
58
  import ViewSelector from './ViewSelector';
59
59
  import {VisualizationPanel} from './VisualizationPanel';
60
60
 
61
- type NavigateFunction = (path: string, queryParams: any, options?: {replace?: boolean}) => void;
62
-
63
61
  export interface FlamegraphData {
64
62
  loading: boolean;
65
63
  data?: Flamegraph;
@@ -104,7 +102,6 @@ export interface ProfileViewProps {
104
102
  sourceData?: SourceData;
105
103
  profileSource?: ProfileSource;
106
104
  queryClient?: QueryServiceClient;
107
- navigateTo?: NavigateFunction;
108
105
  compare?: boolean;
109
106
  onDownloadPProf: () => void;
110
107
  pprofDownloading?: boolean;
@@ -128,7 +125,6 @@ export const ProfileView = ({
128
125
  sourceData,
129
126
  profileSource,
130
127
  queryClient,
131
- navigateTo,
132
128
  onDownloadPProf,
133
129
  pprofDownloading,
134
130
  compare,
@@ -136,20 +132,12 @@ export const ProfileView = ({
136
132
  const {timezone} = useParcaContext();
137
133
  const {ref, dimensions} = useContainerDimensions();
138
134
  const [curPath, setCurPath] = useState<string[]>([]);
139
- const [rawDashboardItems = ['icicle'], setDashboardItems] = useURLState({
140
- param: 'dashboard_items',
141
- navigateTo,
135
+ const [dashboardItems, setDashboardItems] = useURLState<string[]>('dashboard_items', {
136
+ alwaysReturnArray: true,
142
137
  });
143
138
  const [graphvizLoaded, setGraphvizLoaded] = useState(false);
144
139
  const [callgraphSVG, setCallgraphSVG] = useState<string | undefined>(undefined);
145
- const [currentSearchString] = useURLState({param: 'search_string'});
146
-
147
- const dashboardItems = useMemo(() => {
148
- if (rawDashboardItems !== undefined) {
149
- return rawDashboardItems as string[];
150
- }
151
- return ['icicle'];
152
- }, [rawDashboardItems]);
140
+ const [currentSearchString, setSearchString] = useURLState<string | undefined>('search_string');
153
141
 
154
142
  const isDarkMode = useAppSelector(selectDarkMode);
155
143
  const isMultiPanelView = dashboardItems.length > 1;
@@ -240,7 +228,6 @@ export const ProfileView = ({
240
228
  total={total}
241
229
  filtered={filtered}
242
230
  profileType={profileSource?.ProfileType()}
243
- navigateTo={navigateTo}
244
231
  loading={flamegraphData.loading}
245
232
  setActionButtons={setActionButtons}
246
233
  error={flamegraphData.error}
@@ -281,9 +268,9 @@ export const ProfileView = ({
281
268
  data={topTableData.arrow?.record}
282
269
  unit={topTableData.unit}
283
270
  profileType={profileSource?.ProfileType()}
284
- navigateTo={navigateTo}
285
271
  setActionButtons={setActionButtons}
286
- currentSearchString={currentSearchString as string}
272
+ currentSearchString={currentSearchString}
273
+ setSearchString={setSearchString}
287
274
  isHalfScreen={isHalfScreen}
288
275
  />
289
276
  ) : (
@@ -371,7 +358,7 @@ export const ProfileView = ({
371
358
  </div>
372
359
 
373
360
  <div className="lg:flex flex-wrap items-center gap-2 md:justify-end hidden">
374
- <FilterByFunctionButton navigateTo={navigateTo} />
361
+ <FilterByFunctionButton />
375
362
  {profileViewExternalSubActions != null ? profileViewExternalSubActions : null}
376
363
  <UserPreferences
377
364
  customButton={
@@ -402,7 +389,6 @@ export const ProfileView = ({
402
389
  </Button>
403
390
  <ViewSelector
404
391
  defaultValue=""
405
- navigateTo={navigateTo}
406
392
  position={-1}
407
393
  placeholderText="Add panel"
408
394
  icon={<Icon icon="material-symbols:add" width={20} />}
@@ -451,7 +437,6 @@ export const ProfileView = ({
451
437
  dashboardItem={dashboardItem}
452
438
  getDashboardItemByType={getDashboardItemByType}
453
439
  dragHandleProps={provided.dragHandleProps}
454
- navigateTo={navigateTo}
455
440
  index={index}
456
441
  />
457
442
  </div>