@parca/profile 0.19.52 → 0.19.54

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 (56) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/MatchersInput/index.js +3 -3
  3. package/dist/MetricsGraph/MetricsContextMenu/index.js +2 -2
  4. package/dist/MetricsGraph/MetricsTooltip/index.js +2 -2
  5. package/dist/MetricsGraph/index.js +2 -2
  6. package/dist/ProfileExplorer/ProfileExplorerCompare.d.ts.map +1 -1
  7. package/dist/ProfileExplorer/ProfileExplorerCompare.js +2 -2
  8. package/dist/ProfileExplorer/index.js +3 -3
  9. package/dist/ProfileFlameGraph/index.js +2 -2
  10. package/dist/ProfileMetricsGraph/index.js +3 -3
  11. package/dist/ProfileSelector/QueryControls.js +6 -6
  12. package/dist/ProfileTypeSelector/index.js +2 -2
  13. package/dist/ProfileView/components/DashboardItems/index.d.ts +0 -2
  14. package/dist/ProfileView/components/DashboardItems/index.d.ts.map +1 -1
  15. package/dist/ProfileView/components/DiffLegend.js +2 -2
  16. package/dist/ProfileView/components/GroupByLabelsDropdown/index.js +3 -3
  17. package/dist/ProfileView/components/ProfileFilters/index.js +6 -6
  18. package/dist/ProfileView/components/ProfileFilters/useProfileFilters.d.ts.map +1 -1
  19. package/dist/ProfileView/components/ProfileFilters/useProfileFilters.js +10 -4
  20. package/dist/ProfileView/components/Toolbars/index.js +2 -2
  21. package/dist/ProfileView/hooks/useResetFlameGraphState.d.ts +2 -0
  22. package/dist/ProfileView/hooks/useResetFlameGraphState.d.ts.map +1 -0
  23. package/dist/ProfileView/hooks/{useResetStateOnNewSearch.js → useResetFlameGraphState.js} +1 -1
  24. package/dist/ProfileView/hooks/useVisualizationState.d.ts +0 -2
  25. package/dist/ProfileView/hooks/useVisualizationState.d.ts.map +1 -1
  26. package/dist/ProfileView/hooks/useVisualizationState.js +5 -5
  27. package/dist/ProfileView/index.d.ts.map +1 -1
  28. package/dist/ProfileView/index.js +1 -3
  29. package/dist/ProfileViewWithData.js +1 -1
  30. package/dist/SimpleMatchers/index.js +3 -3
  31. package/dist/ViewMatchers/index.js +2 -2
  32. package/package.json +4 -4
  33. package/src/MatchersInput/index.tsx +3 -3
  34. package/src/MetricsGraph/MetricsContextMenu/index.tsx +2 -2
  35. package/src/MetricsGraph/MetricsTooltip/index.tsx +2 -2
  36. package/src/MetricsGraph/index.tsx +2 -2
  37. package/src/ProfileExplorer/ProfileExplorerCompare.tsx +11 -5
  38. package/src/ProfileExplorer/index.tsx +3 -3
  39. package/src/ProfileFlameGraph/index.tsx +2 -2
  40. package/src/ProfileMetricsGraph/index.tsx +4 -4
  41. package/src/ProfileSelector/QueryControls.tsx +13 -13
  42. package/src/ProfileTypeSelector/index.tsx +2 -2
  43. package/src/ProfileView/components/DashboardItems/index.tsx +0 -2
  44. package/src/ProfileView/components/DiffLegend.tsx +2 -2
  45. package/src/ProfileView/components/GroupByLabelsDropdown/index.tsx +4 -4
  46. package/src/ProfileView/components/ProfileFilters/index.tsx +10 -10
  47. package/src/ProfileView/components/ProfileFilters/useProfileFilters.ts +10 -4
  48. package/src/ProfileView/components/Toolbars/index.tsx +2 -2
  49. package/src/ProfileView/hooks/{useResetStateOnNewSearch.ts → useResetFlameGraphState.ts} +1 -1
  50. package/src/ProfileView/hooks/useVisualizationState.ts +6 -7
  51. package/src/ProfileView/index.tsx +0 -4
  52. package/src/ProfileViewWithData.tsx +1 -1
  53. package/src/SimpleMatchers/index.tsx +9 -9
  54. package/src/ViewMatchers/index.tsx +2 -2
  55. package/dist/ProfileView/hooks/useResetStateOnNewSearch.d.ts +0 -2
  56. package/dist/ProfileView/hooks/useResetStateOnNewSearch.d.ts.map +0 -1
@@ -26,7 +26,7 @@ import { useVisualizationState } from './hooks/useVisualizationState';
26
26
  export const ProfileView = ({ total, filtered, flamegraphData, flamechartData, topTableData, sourceData, profileSource, queryClient, onDownloadPProf, pprofDownloading, compare, showVisualizationSelector, sandwichData, }) => {
27
27
  const { timezone, perf, profileViewExternalMainActions, preferencesModal, profileViewExternalSubActions, } = useParcaContext();
28
28
  const { ref, dimensions } = useContainerDimensions();
29
- const { curPath, setCurPath, curPathArrow, setCurPathArrow, colorStackLegend, colorBy, groupBy, toggleGroupBy, setGroupByLabels, sandwichFunctionName, resetSandwichFunctionName, } = useVisualizationState();
29
+ const { curPathArrow, setCurPathArrow, colorStackLegend, colorBy, groupBy, toggleGroupBy, setGroupByLabels, sandwichFunctionName, resetSandwichFunctionName, } = useVisualizationState();
30
30
  const { colorMappings } = useProfileMetadata({
31
31
  flamegraphArrow: flamegraphData.arrow,
32
32
  metadataMappingFiles: flamegraphData.metadataMappingFiles,
@@ -49,8 +49,6 @@ export const ProfileView = ({ total, filtered, flamegraphData, flamechartData, t
49
49
  profileSource,
50
50
  total,
51
51
  filtered,
52
- curPath,
53
- setNewCurPath: setCurPath,
54
52
  curPathArrow,
55
53
  setNewCurPathArrow: setCurPathArrow,
56
54
  perf,
@@ -39,7 +39,7 @@ export const ProfileViewWithData = ({ queryClient, profileSource, showVisualizat
39
39
  const { protoFilters } = useProfileFilters();
40
40
  useEffect(() => {
41
41
  // If profile type is not delta, remove flamechart from the dashboard items
42
- // and set it to flame if no other items are selected.
42
+ // and set it to flame graph if no other items are selected.
43
43
  if (profileSource == null) {
44
44
  return;
45
45
  }
@@ -16,7 +16,7 @@ import { Icon } from '@iconify/react';
16
16
  import { useQueryClient } from '@tanstack/react-query';
17
17
  import cx from 'classnames';
18
18
  import { useGrpcMetadata } from '@parca/components';
19
- import { testId } from '@parca/test-utils';
19
+ import { TEST_IDS, testId } from '@parca/test-utils';
20
20
  import { millisToProtoTimestamp, sanitizeLabelValue } from '@parca/utilities';
21
21
  import { LabelProvider, useLabels } from '../contexts/SimpleMatchersLabelContext';
22
22
  import { useUtilizationLabels } from '../contexts/UtilizationLabelsContext';
@@ -242,9 +242,9 @@ const SimpleMatchers = ({ queryClient, setMatchersString, currentQuery, profileT
242
242
  };
243
243
  }, [queryRows, fetchLabelValuesUnified]);
244
244
  const isRowRegex = (row) => row.operator === '=~' || row.operator === '!~';
245
- return (_jsxs("div", { className: `flex items-center gap-3 ${maxWidthInPixels} w-full flex-wrap`, id: "simple-matchers", ...testId('SIMPLE_MATCHERS_CONTAINER'), children: [visibleRows.map((row, index) => (_jsxs("div", { className: "flex items-center", ...testId('SIMPLE_MATCHER_ROW'), children: [_jsx(Select, { items: labelNameOptions, onSelection: value => handleUpdateRow(index, 'labelName', value), placeholder: "Select label name", selectedKey: row.labelName, className: "rounded-tr-none rounded-br-none ring-0 focus:ring-0 outline-none", loading: labelNamesLoading, searchable: true, ...testId('LABEL_NAME_SELECT') }), _jsx(Select, { items: operatorOptions, onSelection: value => handleUpdateRow(index, 'operator', value), selectedKey: row.operator, className: "rounded-none ring-0 focus:ring-0 outline-none", ...testId('OPERATOR_SELECT') }), _jsx(Select, { items: transformLabelsForSelect(row.labelValues), onSelection: value => handleUpdateRow(index, 'labelValue', value), placeholder: "Select label value", selectedKey: row.labelValue, className: "rounded-none ring-0 focus:ring-0 outline-none max-w-48", optionsClassname: cx('max-w-[300px]', {
245
+ return (_jsxs("div", { className: `flex items-center gap-3 ${maxWidthInPixels} w-full flex-wrap`, id: "simple-matchers", ...testId(TEST_IDS.SIMPLE_MATCHERS_CONTAINER), children: [visibleRows.map((row, index) => (_jsxs("div", { className: "flex items-center", ...testId(TEST_IDS.SIMPLE_MATCHER_ROW), children: [_jsx(Select, { items: labelNameOptions, onSelection: value => handleUpdateRow(index, 'labelName', value), placeholder: "Select label name", selectedKey: row.labelName, className: "rounded-tr-none rounded-br-none ring-0 focus:ring-0 outline-none", loading: labelNamesLoading, searchable: true, ...testId(TEST_IDS.LABEL_NAME_SELECT) }), _jsx(Select, { items: operatorOptions, onSelection: value => handleUpdateRow(index, 'operator', value), selectedKey: row.operator, className: "rounded-none ring-0 focus:ring-0 outline-none", ...testId(TEST_IDS.OPERATOR_SELECT) }), _jsx(Select, { items: transformLabelsForSelect(row.labelValues), onSelection: value => handleUpdateRow(index, 'labelValue', value), placeholder: "Select label value", selectedKey: row.labelValue, className: "rounded-none ring-0 focus:ring-0 outline-none max-w-48", optionsClassname: cx('max-w-[300px]', {
246
246
  'w-[300px]': isRowRegex(row),
247
- }), searchable: true, disabled: row.labelName === '', loading: row.isLoading, onButtonClick: () => handleLabelValueClick(index), editable: isRowRegex(row), ...testId('LABEL_VALUE_SELECT') }), _jsx("button", { onClick: () => removeRow(index), className: cx('p-2 border-gray-200 border rounded rounded-tl-none rounded-bl-none focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:border-gray-600 dark:bg-gray-900'), ...testId('REMOVE_MATCHER_BUTTON'), children: _jsx(Icon, { icon: "carbon:close", className: "h-5 w-5 text-gray-400", "aria-hidden": "true" }) })] }, index))), queryRows.length > 3 && (_jsx("button", { onClick: () => setShowAll(!showAll), className: "mr-2 px-3 py-1 text-sm font-medium text-gray-700 dark:text-gray-200 bg-gray-100 rounded-md hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:bg-gray-900", ...testId(showAll ? 'SHOW_LESS_BUTTON' : 'SHOW_MORE_BUTTON'), children: showAll ? 'Show less' : `Show ${hiddenRowsCount} more` })), _jsx("button", { onClick: addNewRow, className: "p-2 border-gray-200 dark:bg-gray-900 dark:border-gray-600 border rounded focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500", ...testId('ADD_MATCHER_BUTTON'), children: _jsx(Icon, { icon: "material-symbols:add", className: "h-5 w-5 text-gray-400", "aria-hidden": "true" }) })] }));
247
+ }), searchable: true, disabled: row.labelName === '', loading: row.isLoading, onButtonClick: () => handleLabelValueClick(index), editable: isRowRegex(row), ...testId(TEST_IDS.LABEL_VALUE_SELECT) }), _jsx("button", { onClick: () => removeRow(index), className: cx('p-2 border-gray-200 border rounded rounded-tl-none rounded-bl-none focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:border-gray-600 dark:bg-gray-900'), ...testId(TEST_IDS.REMOVE_MATCHER_BUTTON), children: _jsx(Icon, { icon: "carbon:close", className: "h-5 w-5 text-gray-400", "aria-hidden": "true" }) })] }, index))), queryRows.length > 3 && (_jsx("button", { onClick: () => setShowAll(!showAll), className: "mr-2 px-3 py-1 text-sm font-medium text-gray-700 dark:text-gray-200 bg-gray-100 rounded-md hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:bg-gray-900", ...testId(showAll ? TEST_IDS.SHOW_LESS_BUTTON : TEST_IDS.SHOW_MORE_BUTTON), children: showAll ? 'Show less' : `Show ${hiddenRowsCount} more` })), _jsx("button", { onClick: addNewRow, className: "p-2 border-gray-200 dark:bg-gray-900 dark:border-gray-600 border rounded focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500", ...testId(TEST_IDS.ADD_MATCHER_BUTTON), children: _jsx(Icon, { icon: "material-symbols:add", className: "h-5 w-5 text-gray-400", "aria-hidden": "true" }) })] }));
248
248
  };
249
249
  export default function SimpleMathersWithProvider(props) {
250
250
  const labelNameFromMatchers = useMemo(() => {
@@ -15,7 +15,7 @@ import { useCallback, useEffect, useRef, useState } from 'react';
15
15
  import { Icon } from '@iconify/react';
16
16
  import cx from 'classnames';
17
17
  import { useGrpcMetadata } from '@parca/components';
18
- import { testId } from '@parca/test-utils';
18
+ import { TEST_IDS, testId } from '@parca/test-utils';
19
19
  import { millisToProtoTimestamp, sanitizeLabelValue } from '@parca/utilities';
20
20
  import CustomSelect from '../SimpleMatchers/Select';
21
21
  const ViewMatchers = ({ labelNames, profileType, queryClient, runQuery, setMatchersString, start, end, currentQuery, }) => {
@@ -112,6 +112,6 @@ const ViewMatchers = ({ labelNames, profileType, queryClient, runQuery, setMatch
112
112
  element: { active: _jsx(_Fragment, { children: value }), expanded: _jsx(_Fragment, { children: value }) },
113
113
  }));
114
114
  }, []);
115
- return (_jsx("div", { className: "flex flex-wrap gap-2", ...testId('VIEW_MATCHERS_CONTAINER'), children: labelNames.map(labelName => (_jsxs("div", { className: "flex items-center", children: [_jsx("div", { className: "relative border shadow-sm px-4 py-2 text-left cursor-default focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 text-sm flex gap-2 items-center justify-between bg-gray-100 dark:bg-gray-700 rounded-l-md border-gray-300 dark:border-gray-600", children: labelName }), _jsx(CustomSelect, { searchable: true, placeholder: "Select value", items: transformValuesForSelect(labelValuesMap[labelName] ?? []), onSelection: (value) => handleSelection(labelName, value), selectedKey: selectionsRef.current[labelName] ?? undefined, className: cx('rounded-l-none border-l-0', selectionsRef.current[labelName] != null && 'border-r-0 rounded-r-none'), loading: isLoading[labelName] ?? false }), selectionsRef.current[labelName] != null && (_jsx("button", { onClick: () => handleReset(labelName), className: "p-2 border-gray-200 bg-white dark:bg-gray-900 dark:border-gray-600 border rounded-r-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500", "aria-label": `Reset ${labelName} selection`, children: _jsx(Icon, { icon: "mdi:close", className: "h-5 w-5 text-gray-400", "aria-hidden": "true" }) }))] }, labelName))) }));
115
+ return (_jsx("div", { className: "flex flex-wrap gap-2", ...testId(TEST_IDS.VIEW_MATCHERS_CONTAINER), children: labelNames.map(labelName => (_jsxs("div", { className: "flex items-center", children: [_jsx("div", { className: "relative border shadow-sm px-4 py-2 text-left cursor-default focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 text-sm flex gap-2 items-center justify-between bg-gray-100 dark:bg-gray-700 rounded-l-md border-gray-300 dark:border-gray-600", children: labelName }), _jsx(CustomSelect, { searchable: true, placeholder: "Select value", items: transformValuesForSelect(labelValuesMap[labelName] ?? []), onSelection: (value) => handleSelection(labelName, value), selectedKey: selectionsRef.current[labelName] ?? undefined, className: cx('rounded-l-none border-l-0', selectionsRef.current[labelName] != null && 'border-r-0 rounded-r-none'), loading: isLoading[labelName] ?? false }), selectionsRef.current[labelName] != null && (_jsx("button", { onClick: () => handleReset(labelName), className: "p-2 border-gray-200 bg-white dark:bg-gray-900 dark:border-gray-600 border rounded-r-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500", "aria-label": `Reset ${labelName} selection`, children: _jsx(Icon, { icon: "mdi:close", className: "h-5 w-5 text-gray-400", "aria-hidden": "true" }) }))] }, labelName))) }));
116
116
  };
117
117
  export default ViewMatchers;
package/package.json CHANGED
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "name": "@parca/profile",
3
- "version": "0.19.52",
3
+ "version": "0.19.54",
4
4
  "description": "Profile viewing libraries",
5
5
  "dependencies": {
6
6
  "@floating-ui/react": "^0.27.12",
7
7
  "@headlessui/react": "^1.7.19",
8
8
  "@iconify/react": "^4.0.0",
9
9
  "@parca/client": "0.17.5",
10
- "@parca/components": "0.16.370",
10
+ "@parca/components": "0.16.371",
11
11
  "@parca/dynamicsize": "0.16.67",
12
12
  "@parca/hooks": "0.0.102",
13
13
  "@parca/icons": "0.16.74",
14
14
  "@parca/parser": "0.16.81",
15
15
  "@parca/store": "0.16.186",
16
- "@parca/test-utils": "0.0.12",
16
+ "@parca/test-utils": "0.0.13",
17
17
  "@parca/utilities": "0.0.109",
18
18
  "@popperjs/core": "^2.11.8",
19
19
  "@protobuf-ts/runtime-rpc": "^2.5.0",
@@ -79,5 +79,5 @@
79
79
  "access": "public",
80
80
  "registry": "https://registry.npmjs.org/"
81
81
  },
82
- "gitHead": "df1f4ce1710f808dfc6af0a631b140cd346dfaab"
82
+ "gitHead": "842199b0933536a1d704de0fbcac61f8b365d41e"
83
83
  }
@@ -20,7 +20,7 @@ import TextareaAutosize from 'react-textarea-autosize';
20
20
  import {LabelsRequest, LabelsResponse, QueryServiceClient, ValuesRequest} from '@parca/client';
21
21
  import {useGrpcMetadata} from '@parca/components';
22
22
  import {Query} from '@parca/parser';
23
- import {testId} from '@parca/test-utils';
23
+ import {TEST_IDS, testId} from '@parca/test-utils';
24
24
  import {millisToProtoTimestamp, sanitizeLabelValue} from '@parca/utilities';
25
25
 
26
26
  import {UtilizationLabels} from '../ProfileSelector';
@@ -292,7 +292,7 @@ const MatchersInput = ({
292
292
  return (
293
293
  <div
294
294
  className="w-full min-w-[300px] flex-1 font-mono relative"
295
- {...testId('MATCHERS_INPUT_CONTAINER')}
295
+ {...testId(TEST_IDS.MATCHERS_INPUT_CONTAINER)}
296
296
  >
297
297
  <TextareaAutosize
298
298
  ref={inputRef}
@@ -308,7 +308,7 @@ const MatchersInput = ({
308
308
  onChange={onChange}
309
309
  value={value}
310
310
  onBlur={unfocus}
311
- {...testId('MATCHERS_TEXTAREA')}
311
+ {...testId(TEST_IDS.MATCHERS_TEXTAREA)}
312
312
  onFocus={focus}
313
313
  disabled={profileSelected} // Disable input if no profile has been selected
314
314
  title={
@@ -15,7 +15,7 @@ import {Icon} from '@iconify/react';
15
15
  import {Item, Menu, Submenu} from 'react-contexify';
16
16
 
17
17
  import {useParcaContext} from '@parca/components';
18
- import {testId} from '@parca/test-utils';
18
+ import {TEST_IDS, testId} from '@parca/test-utils';
19
19
 
20
20
  import {Series, SeriesPoint} from '../';
21
21
 
@@ -115,7 +115,7 @@ const MetricsContextMenu = ({
115
115
  id={menuId}
116
116
  onVisibilityChange={trackVisibility}
117
117
  theme={isDarkMode ? 'dark' : ''}
118
- {...testId('METRICS_GRAPH_CONTEXT_MENU')}
118
+ {...testId(TEST_IDS.METRICS_GRAPH_CONTEXT_MENU)}
119
119
  >
120
120
  {menuItems.map(renderMenuItem)}
121
121
  </Menu>
@@ -15,7 +15,7 @@ import {useEffect, useMemo, useState} from 'react';
15
15
 
16
16
  import {usePopper} from 'react-popper';
17
17
 
18
- import {testId} from '@parca/test-utils';
18
+ import {TEST_IDS, testId} from '@parca/test-utils';
19
19
 
20
20
  interface VirtualElement {
21
21
  getBoundingClientRect: () => DOMRect;
@@ -113,7 +113,7 @@ const MetricsTooltip = ({x, y, contextElement, content}: Props): JSX.Element =>
113
113
  ref={setPopperElement}
114
114
  style={styles.popper}
115
115
  {...attributes.popper}
116
- {...testId('METRICS_GRAPH_TOOLTIP')}
116
+ {...testId(TEST_IDS.METRICS_GRAPH_TOOLTIP)}
117
117
  className="z-50"
118
118
  >
119
119
  <div className="flex max-w-lg">
@@ -19,7 +19,7 @@ import throttle from 'lodash.throttle';
19
19
  import {useContextMenu} from 'react-contexify';
20
20
 
21
21
  import {DateTimeRange, useParcaContext} from '@parca/components';
22
- import {testId} from '@parca/test-utils';
22
+ import {TEST_IDS, testId} from '@parca/test-utils';
23
23
  import {formatDate, formatForTimespan, getPrecision, valueFormatter} from '@parca/utilities';
24
24
 
25
25
  import MetricsCircle from '../MetricsCircle';
@@ -84,7 +84,7 @@ const MetricsGraph = ({
84
84
  return (
85
85
  <div
86
86
  className="relative"
87
- {...testId('METRICS_GRAPH')}
87
+ {...testId(TEST_IDS.METRICS_GRAPH)}
88
88
  onClick={() => isInfoPanelOpen && setIsInfoPanelOpen(false)}
89
89
  >
90
90
  <div className="absolute right-0 top-0">
@@ -16,7 +16,7 @@ import {useState} from 'react';
16
16
  import {QueryServiceClient} from '@parca/client';
17
17
  import {useURLState} from '@parca/components';
18
18
  import {Query} from '@parca/parser';
19
- import {testId} from '@parca/test-utils';
19
+ import {TEST_IDS, testId} from '@parca/test-utils';
20
20
  import type {NavigateFunction} from '@parca/utilities';
21
21
 
22
22
  import {ProfileDiffSource, ProfileSelection, ProfileViewWithData} from '..';
@@ -64,9 +64,12 @@ const ProfileExplorerCompare = ({
64
64
  const [compareAbsolute] = useURLState('compare_absolute');
65
65
 
66
66
  return (
67
- <div {...testId('COMPARE_CONTAINER')}>
67
+ <div {...testId(TEST_IDS.COMPARE_CONTAINER)}>
68
68
  <div className="flex justify-between gap-2 relative mb-2">
69
- <div className="flex-column flex-1 p-2 shadow-md rounded-md" {...testId('COMPARE_SIDE_A')}>
69
+ <div
70
+ className="flex-column flex-1 p-2 shadow-md rounded-md"
71
+ {...testId(TEST_IDS.COMPARE_SIDE_A)}
72
+ >
70
73
  <ProfileSelector
71
74
  queryClient={queryClient}
72
75
  querySelection={queryA}
@@ -82,7 +85,10 @@ const ProfileExplorerCompare = ({
82
85
  setDisplayHideMetricsGraphButton={setShowMetricsGraph}
83
86
  />
84
87
  </div>
85
- <div className="flex-column flex-1 p-2 shadow-md rounded-md" {...testId('COMPARE_SIDE_B')}>
88
+ <div
89
+ className="flex-column flex-1 p-2 shadow-md rounded-md"
90
+ {...testId(TEST_IDS.COMPARE_SIDE_B)}
91
+ >
86
92
  <ProfileSelector
87
93
  queryClient={queryClient}
88
94
  querySelection={queryB}
@@ -101,7 +107,7 @@ const ProfileExplorerCompare = ({
101
107
  </div>
102
108
  <div className="grid grid-cols-1">
103
109
  {profileA != null && profileB != null ? (
104
- <div {...testId('COMPARE_PROFILE_VIEW')}>
110
+ <div {...testId(TEST_IDS.COMPARE_PROFILE_VIEW)}>
105
111
  <ProfileViewWithData
106
112
  queryClient={queryClient}
107
113
  profileSource={
@@ -23,7 +23,7 @@ import {capitalizeOnlyFirstLetter, safeDecode, type NavigateFunction} from '@par
23
23
 
24
24
  import {ProfileSelection, ProfileSelectionFromParams, SuffixParams} from '..';
25
25
  import {QuerySelection, useProfileTypes} from '../ProfileSelector';
26
- import {useResetStateOnNewSearch} from '../ProfileView/hooks/useResetStateOnNewSearch';
26
+ import {useResetFlameGraphState} from '../ProfileView/hooks/useResetFlameGraphState';
27
27
  import {useResetStateOnProfileTypeChange} from '../ProfileView/hooks/useResetStateOnProfileTypeChange';
28
28
  import {sumByToParam, useSumByFromParams} from '../useSumBy';
29
29
  import ProfileExplorerCompare from './ProfileExplorerCompare';
@@ -162,7 +162,7 @@ const ProfileExplorerApp = ({
162
162
  const [profileB, setProfileB] = useState<ProfileSelection | null>(null);
163
163
 
164
164
  const resetStateOnProfileTypeChange = useResetStateOnProfileTypeChange();
165
- const resetStateOnNewSearch = useResetStateOnNewSearch();
165
+ const resetFlameGraphState = useResetFlameGraphState();
166
166
 
167
167
  const sumByA = useSumByFromParams(sum_by_a);
168
168
  const sumByB = useSumByFromParams(sum_by_b);
@@ -250,7 +250,7 @@ const ProfileExplorerApp = ({
250
250
  resetStateOnProfileTypeChange();
251
251
  } else {
252
252
  // Reset the state when a new search is performed.
253
- resetStateOnNewSearch();
253
+ resetFlameGraphState();
254
254
  }
255
255
  }
256
256
 
@@ -25,7 +25,7 @@ import {
25
25
  useURLState,
26
26
  } from '@parca/components';
27
27
  import {ProfileType} from '@parca/parser';
28
- import {testId} from '@parca/test-utils';
28
+ import {TEST_IDS, testId} from '@parca/test-utils';
29
29
  import {capitalizeOnlyFirstLetter, divide} from '@parca/utilities';
30
30
 
31
31
  import {MergedProfileSource, ProfileSource} from '../ProfileSource';
@@ -396,7 +396,7 @@ const ProfileFlameGraph = function ProfileFlameGraphNonMemo({
396
396
  <div
397
397
  className={cx(!isInSandwichView ? 'min-h-48' : '')}
398
398
  id="h-flame-graph"
399
- {...testId('FLAMEGRAPH_CONTAINER')}
399
+ {...testId(TEST_IDS.FLAMEGRAPH_CONTAINER)}
400
400
  >
401
401
  <>{flameGraph}</>
402
402
  </div>
@@ -29,7 +29,7 @@ import {
29
29
  useParcaContext,
30
30
  } from '@parca/components';
31
31
  import {Query} from '@parca/parser';
32
- import {testId} from '@parca/test-utils';
32
+ import {TEST_IDS, testId} from '@parca/test-utils';
33
33
  import {capitalizeOnlyFirstLetter, formatDate, timePattern, valueFormatter} from '@parca/utilities';
34
34
 
35
35
  import {MergedProfileSelection, ProfileSelection} from '..';
@@ -491,7 +491,7 @@ const ProfileMetricsGraph = ({
491
491
  <div
492
492
  key={name}
493
493
  className="mr-3 inline-block rounded-lg bg-gray-200 px-2 py-1 text-xs font-bold text-gray-700 dark:bg-gray-700 dark:text-gray-400"
494
- {...testId('TOOLTIP_LABEL')}
494
+ {...testId(TEST_IDS.TOOLTIP_LABEL)}
495
495
  >
496
496
  <TextWithTooltip
497
497
  text={`${name.replace('attributes.', '')}="${
@@ -513,7 +513,7 @@ const ProfileMetricsGraph = ({
513
513
  <div
514
514
  key={name}
515
515
  className="mr-3 inline-block rounded-lg bg-gray-200 px-2 py-1 text-xs font-bold text-gray-700 dark:bg-gray-700 dark:text-gray-400"
516
- {...testId('TOOLTIP_LABEL')}
516
+ {...testId(TEST_IDS.TOOLTIP_LABEL)}
517
517
  >
518
518
  <TextWithTooltip
519
519
  text={`${name.replace('attributes.', '')}="${
@@ -534,7 +534,7 @@ const ProfileMetricsGraph = ({
534
534
  <div
535
535
  key={label.name}
536
536
  className="mr-3 inline-block rounded-lg bg-gray-200 px-2 py-1 text-xs font-bold text-gray-700 dark:bg-gray-700 dark:text-gray-400"
537
- {...testId('TOOLTIP_LABEL')}
537
+ {...testId(TEST_IDS.TOOLTIP_LABEL)}
538
538
  >
539
539
  <TextWithTooltip
540
540
  text={`${label.name}="${label.value}"`}
@@ -18,7 +18,7 @@ import Select, {type SelectInstance} from 'react-select';
18
18
  import {ProfileTypesResponse, QueryServiceClient} from '@parca/client';
19
19
  import {Button, DateTimeRange, DateTimeRangePicker, useParcaContext} from '@parca/components';
20
20
  import {ProfileType, Query} from '@parca/parser';
21
- import {testId} from '@parca/test-utils';
21
+ import {TEST_IDS, testId} from '@parca/test-utils';
22
22
 
23
23
  import MatchersInput from '../MatchersInput';
24
24
  import ProfileTypeSelector from '../ProfileTypeSelector';
@@ -97,11 +97,11 @@ export function QueryControls({
97
97
  return (
98
98
  <div
99
99
  className="flex w-full flex-wrap items-start gap-2"
100
- {...testId('QUERY_CONTROLS_CONTAINER')}
100
+ {...testId(TEST_IDS.QUERY_CONTROLS_CONTAINER)}
101
101
  >
102
102
  {showProfileTypeSelector && (
103
103
  <div>
104
- <label className="text-xs" {...testId('PROFILE_TYPE_LABEL')}>
104
+ <label className="text-xs" {...testId(TEST_IDS.PROFILE_TYPE_LABEL)}>
105
105
  Profile type
106
106
  </label>
107
107
  <ProfileTypeSelector
@@ -118,11 +118,11 @@ export function QueryControls({
118
118
  <div
119
119
  className="w-full flex-1 flex flex-col gap-1 mt-auto"
120
120
  ref={queryBrowserRef}
121
- {...testId('QUERY_BROWSER_CONTAINER')}
121
+ {...testId(TEST_IDS.QUERY_BROWSER_CONTAINER)}
122
122
  >
123
123
  <div className="flex items-center justify-between">
124
124
  <div className="flex items-center gap-3">
125
- <label className="text-xs" {...testId('QUERY_LABEL')}>
125
+ <label className="text-xs" {...testId(TEST_IDS.QUERY_LABEL)}>
126
126
  Query
127
127
  </label>
128
128
  {viewComponent?.disableExplorativeQuerying !== true && (
@@ -136,7 +136,7 @@ export function QueryControls({
136
136
  className={`${
137
137
  advancedModeForQueryBrowser ? 'bg-indigo-600' : 'bg-gray-400 dark:bg-gray-800'
138
138
  } relative inline-flex h-[20px] w-[44px] shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus-visible:ring-2 focus-visible:ring-white/75`}
139
- {...testId('ADVANCED_MODE_SWITCH')}
139
+ {...testId(TEST_IDS.ADVANCED_MODE_SWITCH)}
140
140
  >
141
141
  <span className="sr-only">Use setting</span>
142
142
  <span
@@ -146,7 +146,7 @@ export function QueryControls({
146
146
  } pointer-events-none inline-block h-[16px] w-[16px] transform rounded-full bg-white shadow-lg ring-0 transition duration-200 ease-in-out`}
147
147
  />
148
148
  </Switch>
149
- <label className="text-xs" {...testId('QUERY_MODE_LABEL')}>
149
+ <label className="text-xs" {...testId(TEST_IDS.QUERY_MODE_LABEL)}>
150
150
  Advanced Mode
151
151
  </label>
152
152
  </>
@@ -194,15 +194,15 @@ export function QueryControls({
194
194
  </div>
195
195
 
196
196
  {showSumBySelector && (
197
- <div {...testId('SUM_BY_CONTAINER')}>
197
+ <div {...testId(TEST_IDS.SUM_BY_CONTAINER)}>
198
198
  <div className="mb-0.5 mt-1.5 flex items-center justify-between">
199
- <label className="text-xs" {...testId('SUM_BY_LABEL')}>
199
+ <label className="text-xs" {...testId(TEST_IDS.SUM_BY_LABEL)}>
200
200
  Sum by
201
201
  </label>
202
202
  </div>
203
203
  <Select<SelectOption, true>
204
204
  id="h-sum-by-selector"
205
- data-testid={testId('SUM_BY_SELECT')['data-testid']}
205
+ data-testid={testId(TEST_IDS.SUM_BY_SELECT)['data-testid']}
206
206
  defaultValue={[]}
207
207
  isMulti
208
208
  isClearable={false}
@@ -250,11 +250,11 @@ export function QueryControls({
250
250
  onRangeSelection={setTimeRangeSelection}
251
251
  range={timeRangeSelection}
252
252
  timezone={timezone}
253
- {...testId('DATE_TIME_RANGE_PICKER')}
253
+ {...testId(TEST_IDS.DATE_TIME_RANGE_PICKER)}
254
254
  />
255
255
 
256
256
  <div>
257
- <label className="text-xs" {...testId('SEARCH_BUTTON_LABEL')}>
257
+ <label className="text-xs" {...testId(TEST_IDS.SEARCH_BUTTON_LABEL)}>
258
258
  &nbsp;
259
259
  </label>
260
260
  <Button
@@ -264,7 +264,7 @@ export function QueryControls({
264
264
  setQueryExpression(true);
265
265
  }}
266
266
  id="h-matcher-search-button"
267
- {...testId('SEARCH_BUTTON')}
267
+ {...testId(TEST_IDS.SEARCH_BUTTON)}
268
268
  >
269
269
  Search
270
270
  </Button>
@@ -17,7 +17,7 @@ import {RpcError} from '@protobuf-ts/runtime-rpc';
17
17
 
18
18
  import {ProfileType, ProfileTypesResponse} from '@parca/client';
19
19
  import {Select, type SelectElement} from '@parca/components';
20
- import {testId} from '@parca/test-utils';
20
+ import {TEST_IDS, testId} from '@parca/test-utils';
21
21
 
22
22
  interface WellKnownProfile {
23
23
  name: string;
@@ -198,7 +198,7 @@ const ProfileTypeSelector = ({
198
198
  loading={loading}
199
199
  className="bg-white h-profile-type-dropdown"
200
200
  disabled={disabled}
201
- {...testId('PROFILE_TYPE_SELECTOR')}
201
+ {...testId(TEST_IDS.PROFILE_TYPE_SELECTOR)}
202
202
  />
203
203
  );
204
204
  };
@@ -42,8 +42,6 @@ interface GetDashboardItemProps {
42
42
  profileSource: ProfileSource;
43
43
  total: bigint;
44
44
  filtered: bigint;
45
- curPath: string[];
46
- setNewCurPath: (path: string[]) => void;
47
45
  curPathArrow: CurrentPathFrame[];
48
46
  setNewCurPathArrow: (path: CurrentPathFrame[]) => void;
49
47
  perf?: {
@@ -17,7 +17,7 @@ import {Popover, Transition} from '@headlessui/react';
17
17
  import {usePopper} from 'react-popper';
18
18
 
19
19
  import {selectDarkMode, useAppSelector} from '@parca/store';
20
- import {testId} from '@parca/test-utils';
20
+ import {TEST_IDS, testId} from '@parca/test-utils';
21
21
  import {getIncreasedSpanColor, getNewSpanColor, getReducedSpanColor} from '@parca/utilities';
22
22
 
23
23
  const transparencyValues = [-100, -80, -60, -40, -20, 0, 20, 40, 60, 80, 100];
@@ -75,7 +75,7 @@ const DiffLegend = (): JSX.Element => {
75
75
  };
76
76
 
77
77
  return (
78
- <div className="mt-1 mb-2 hidden md:block" id="h-diff-legend" {...testId('DIFF_LEGEND')}>
78
+ <div className="mt-1 mb-2 hidden md:block" id="h-diff-legend" {...testId(TEST_IDS.DIFF_LEGEND)}>
79
79
  <div ref={setReferenceElement} className="flex items-center justify-center">
80
80
  <span>Better</span>
81
81
  <DiffLegendBar onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} />
@@ -13,7 +13,7 @@
13
13
 
14
14
  import Select from 'react-select';
15
15
 
16
- import {testId} from '@parca/test-utils';
16
+ import {TEST_IDS, testId} from '@parca/test-utils';
17
17
 
18
18
  import {FIELD_LABELS} from '../../../ProfileFlameGraph/FlameGraphArrow';
19
19
 
@@ -30,9 +30,9 @@ interface Props {
30
30
 
31
31
  const GroupByLabelsDropdown = ({labels, groupBy, setGroupByLabels}: Props): JSX.Element => {
32
32
  return (
33
- <div className="flex flex-col relative" {...testId('GROUP_BY_CONTAINER')}>
33
+ <div className="flex flex-col relative" {...testId(TEST_IDS.GROUP_BY_CONTAINER)}>
34
34
  <div className="flex items-center justify-between">
35
- <label className="text-sm" {...testId('GROUP_BY_LABEL')}>
35
+ <label className="text-sm" {...testId(TEST_IDS.GROUP_BY_LABEL)}>
36
36
  Group by
37
37
  </label>
38
38
  </div>
@@ -50,7 +50,7 @@ const GroupByLabelsDropdown = ({labels, groupBy, setGroupByLabels}: Props): JSX.
50
50
  MenuList: ({children, innerProps}) => (
51
51
  <div
52
52
  className="overflow-y-auto"
53
- {...testId('GROUP_BY_SELECT_FLYOUT')}
53
+ {...testId(TEST_IDS.GROUP_BY_SELECT_FLYOUT)}
54
54
  {...innerProps}
55
55
  // eslint-disable-next-line react/prop-types
56
56
  style={{...innerProps.style, height: '332px', maxHeight: '332px', fontSize: '14px'}}
@@ -17,7 +17,7 @@ import {Icon} from '@iconify/react';
17
17
  import cx from 'classnames';
18
18
 
19
19
  import {Button, Input, Select, type SelectItem} from '@parca/components';
20
- import {testId} from '@parca/test-utils';
20
+ import {TEST_IDS, testId} from '@parca/test-utils';
21
21
 
22
22
  import {useProfileViewContext} from '../../context/ProfileViewContext';
23
23
  import {getPresetByKey, getPresetsForProfileType, isPresetKey} from './filterPresets';
@@ -205,7 +205,7 @@ const ProfileFilters = ({readOnly = false}: ProfileFiltersProps = {}): JSX.Eleme
205
205
  const filtersToRender = localFilters.length > 0 ? localFilters : appliedFilters ?? [];
206
206
 
207
207
  return (
208
- <div className="flex gap-2 w-full items-start" {...testId('PROFILE_FILTERS_CONTAINER')}>
208
+ <div className="flex gap-2 w-full items-start" {...testId(TEST_IDS.PROFILE_FILTERS_CONTAINER)}>
209
209
  <div className="flex-1 flex flex-wrap gap-2">
210
210
  {filtersToRender.map(filter => {
211
211
  const isNumberField = filter.field === 'address' || filter.field === 'line_number';
@@ -219,7 +219,7 @@ const ProfileFilters = ({readOnly = false}: ProfileFiltersProps = {}): JSX.Eleme
219
219
  selectedKey={filter.type}
220
220
  placeholder="Select Filter"
221
221
  disabled={readOnly}
222
- {...testId('FILTER_TYPE_SELECT')}
222
+ {...testId(TEST_IDS.FILTER_TYPE_SELECT)}
223
223
  flyoutTestId="filter-type-select-flyout"
224
224
  onSelection={key => {
225
225
  // Check if this is a preset selection
@@ -269,7 +269,7 @@ const ProfileFilters = ({readOnly = false}: ProfileFiltersProps = {}): JSX.Eleme
269
269
  items={fieldItems}
270
270
  selectedKey={filter.field ?? ''}
271
271
  disabled={readOnly}
272
- {...testId('FILTER_FIELD_SELECT')}
272
+ {...testId(TEST_IDS.FILTER_FIELD_SELECT)}
273
273
  flyoutTestId="filter-field-select-flyout"
274
274
  onSelection={key => {
275
275
  const newField = key as ProfileFilter['field'];
@@ -297,7 +297,7 @@ const ProfileFilters = ({readOnly = false}: ProfileFiltersProps = {}): JSX.Eleme
297
297
  items={matchTypeItems}
298
298
  selectedKey={filter.matchType ?? ''}
299
299
  disabled={readOnly}
300
- {...testId('FILTER_MATCH_TYPE_SELECT')}
300
+ {...testId(TEST_IDS.FILTER_MATCH_TYPE_SELECT)}
301
301
  flyoutTestId="filter-match-type-select-flyout"
302
302
  onSelection={key =>
303
303
  updateFilter(filter.id, {matchType: key as ProfileFilter['matchType']})
@@ -316,7 +316,7 @@ const ProfileFilters = ({readOnly = false}: ProfileFiltersProps = {}): JSX.Eleme
316
316
  onChange={e => updateFilter(filter.id, {value: e.target.value})}
317
317
  onKeyDown={handleKeyDown}
318
318
  className="rounded-none w-36 text-sm focus:outline-1"
319
- {...testId('FILTER_VALUE_INPUT')}
319
+ {...testId(TEST_IDS.FILTER_VALUE_INPUT)}
320
320
  />
321
321
  </>
322
322
  )}
@@ -324,7 +324,7 @@ const ProfileFilters = ({readOnly = false}: ProfileFiltersProps = {}): JSX.Eleme
324
324
  {!readOnly && (
325
325
  <Button
326
326
  variant="neutral"
327
- {...testId('FILTER_REMOVE_BUTTON')}
327
+ {...testId(TEST_IDS.FILTER_REMOVE_BUTTON)}
328
328
  onClick={() => {
329
329
  // If we're displaying local filters and this is the last one, reset everything
330
330
  if (localFilters.length > 0 && localFilters.length === 1) {
@@ -358,7 +358,7 @@ const ProfileFilters = ({readOnly = false}: ProfileFiltersProps = {}): JSX.Eleme
358
358
  variant="neutral"
359
359
  onClick={addFilter}
360
360
  className="p-3 h-[38px]"
361
- {...testId('ADD_FILTER_BUTTON')}
361
+ {...testId(TEST_IDS.ADD_FILTER_BUTTON)}
362
362
  >
363
363
  <Icon icon="mdi:filter-plus-outline" className="h-4 w-4" />
364
364
  </Button>
@@ -369,7 +369,7 @@ const ProfileFilters = ({readOnly = false}: ProfileFiltersProps = {}): JSX.Eleme
369
369
  variant="neutral"
370
370
  onClick={addFilter}
371
371
  className="flex items-center gap-2"
372
- {...testId('ADD_FILTER_BUTTON')}
372
+ {...testId(TEST_IDS.ADD_FILTER_BUTTON)}
373
373
  >
374
374
  <Icon icon="mdi:filter-outline" className="h-4 w-4" />
375
375
  <span>Filter</span>
@@ -383,7 +383,7 @@ const ProfileFilters = ({readOnly = false}: ProfileFiltersProps = {}): JSX.Eleme
383
383
  onClick={onApplyFilters}
384
384
  disabled={!hasUnsavedChanges || !localFilters.some(isFilterComplete)}
385
385
  className={cx('flex items-center gap-2 sticky top-0')}
386
- {...testId('APPLY_FILTERS_BUTTON')}
386
+ {...testId(TEST_IDS.APPLY_FILTERS_BUTTON)}
387
387
  >
388
388
  <span>Apply</span>
389
389
  </Button>