@parca/profile 0.19.10 → 0.19.12

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 (40) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/ProfileSelector/QueryControls.d.ts.map +1 -1
  3. package/dist/ProfileSelector/QueryControls.js +1 -1
  4. package/dist/ProfileView/components/ActionButtons/GroupByDropdown.d.ts +0 -1
  5. package/dist/ProfileView/components/ActionButtons/GroupByDropdown.d.ts.map +1 -1
  6. package/dist/ProfileView/components/ActionButtons/GroupByDropdown.js +4 -141
  7. package/dist/ProfileView/components/GroupByLabelsDropdown/index.d.ts +8 -0
  8. package/dist/ProfileView/components/GroupByLabelsDropdown/index.d.ts.map +1 -0
  9. package/dist/ProfileView/components/GroupByLabelsDropdown/index.js +57 -0
  10. package/dist/ProfileView/components/InvertCallStack/index.d.ts +3 -0
  11. package/dist/ProfileView/components/InvertCallStack/index.d.ts.map +1 -0
  12. package/dist/ProfileView/components/InvertCallStack/index.js +21 -0
  13. package/dist/ProfileView/components/ShareButton/index.d.ts.map +1 -1
  14. package/dist/ProfileView/components/ShareButton/index.js +1 -1
  15. package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.d.ts +3 -0
  16. package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.d.ts.map +1 -1
  17. package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.js +78 -20
  18. package/dist/ProfileView/components/Toolbars/SwitchMenuItem.d.ts +9 -0
  19. package/dist/ProfileView/components/Toolbars/SwitchMenuItem.d.ts.map +1 -0
  20. package/dist/ProfileView/components/Toolbars/SwitchMenuItem.js +22 -0
  21. package/dist/ProfileView/components/Toolbars/index.d.ts.map +1 -1
  22. package/dist/ProfileView/components/Toolbars/index.js +4 -1
  23. package/dist/ProfileView/components/ViewSelector/Dropdown.js +1 -1
  24. package/dist/ProfileView/components/ViewSelector/index.d.ts.map +1 -1
  25. package/dist/ProfileView/components/ViewSelector/index.js +9 -12
  26. package/dist/ProfileView/hooks/useVisualizationState.d.ts.map +1 -1
  27. package/dist/ProfileView/hooks/useVisualizationState.js +16 -6
  28. package/dist/styles.css +1 -1
  29. package/package.json +2 -2
  30. package/src/ProfileSelector/QueryControls.tsx +1 -0
  31. package/src/ProfileView/components/ActionButtons/GroupByDropdown.tsx +7 -323
  32. package/src/ProfileView/components/GroupByLabelsDropdown/index.tsx +92 -0
  33. package/src/ProfileView/components/InvertCallStack/index.tsx +34 -0
  34. package/src/ProfileView/components/ShareButton/index.tsx +8 -4
  35. package/src/ProfileView/components/Toolbars/MultiLevelDropdown.tsx +134 -22
  36. package/src/ProfileView/components/Toolbars/SwitchMenuItem.tsx +50 -0
  37. package/src/ProfileView/components/Toolbars/index.tsx +25 -9
  38. package/src/ProfileView/components/ViewSelector/Dropdown.tsx +1 -1
  39. package/src/ProfileView/components/ViewSelector/index.tsx +15 -19
  40. package/src/ProfileView/hooks/useVisualizationState.ts +25 -6
package/CHANGELOG.md CHANGED
@@ -3,6 +3,14 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## 0.19.12 (2025-07-02)
7
+
8
+ **Note:** Version bump only for package @parca/profile
9
+
10
+ ## [0.19.11](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.10...@parca/profile@0.19.11) (2025-06-26)
11
+
12
+ **Note:** Version bump only for package @parca/profile
13
+
6
14
  ## [0.19.10](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.9...@parca/profile@0.19.10) (2025-06-25)
7
15
 
8
16
  **Note:** Version bump only for package @parca/profile
@@ -1 +1 @@
1
- {"version":3,"file":"QueryControls.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/QueryControls.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAClD,OAAe,EAAC,KAAK,cAAc,EAAC,MAAM,cAAc,CAAC;AAEzD,OAAO,EAAC,oBAAoB,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AACvE,OAAO,EAAS,aAAa,EAAsB,MAAM,mBAAmB,CAAC;AAC7E,OAAO,EAAC,WAAW,EAAE,KAAK,EAAC,MAAM,eAAe,CAAC;AAYjD,UAAU,kBAAkB;IAC1B,uBAAuB,EAAE,OAAO,CAAC;IACjC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,0BAA0B,EAAE,OAAO,CAAC;IACpC,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;IACxC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IACnD,iBAAiB,CAAC,EAAE,QAAQ,CAAC;IAC7B,aAAa,CAAC,EAAE;QACd,2BAA2B,CAAC,EAAE,OAAO,CAAC;QACtC,0BAA0B,CAAC,EAAE,OAAO,CAAC;QACrC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,mBAAmB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;KACvC,CAAC;IACF,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,2BAA2B,EAAE,OAAO,CAAC;IACrC,8BAA8B,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACxD,iBAAiB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,kBAAkB,EAAE,CAAC,QAAQ,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD,KAAK,EAAE,KAAK,CAAC;IACb,eAAe,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IACjD,kBAAkB,EAAE,aAAa,CAAC;IAClC,qBAAqB,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACtD,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,EAAE,kBAAkB,CAAC;IAChC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,qBAAqB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACjD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IAC1C,WAAW,EAAE,WAAW,CAAC;CAC1B;AAED,wBAAgB,aAAa,CAAC,EAC5B,uBAAuB,EACvB,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,2BAA2B,EAC3B,8BAA8B,EAC9B,iBAAiB,EACjB,kBAAkB,EAClB,KAAK,EACL,eAAe,EACf,kBAAkB,EAClB,qBAAqB,EACrB,cAAc,EACd,WAAW,EACX,MAAM,EACN,cAAc,EACd,qBAAqB,EACrB,qBAAqB,EACrB,QAAQ,EACR,WAAW,EACX,iBAAiB,EACjB,iBAAiB,GAClB,EAAE,kBAAkB,GAAG,GAAG,CAAC,OAAO,CAkJlC"}
1
+ {"version":3,"file":"QueryControls.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/QueryControls.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAClD,OAAe,EAAC,KAAK,cAAc,EAAC,MAAM,cAAc,CAAC;AAEzD,OAAO,EAAC,oBAAoB,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AACvE,OAAO,EAAS,aAAa,EAAsB,MAAM,mBAAmB,CAAC;AAC7E,OAAO,EAAC,WAAW,EAAE,KAAK,EAAC,MAAM,eAAe,CAAC;AAYjD,UAAU,kBAAkB;IAC1B,uBAAuB,EAAE,OAAO,CAAC;IACjC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,0BAA0B,EAAE,OAAO,CAAC;IACpC,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;IACxC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IACnD,iBAAiB,CAAC,EAAE,QAAQ,CAAC;IAC7B,aAAa,CAAC,EAAE;QACd,2BAA2B,CAAC,EAAE,OAAO,CAAC;QACtC,0BAA0B,CAAC,EAAE,OAAO,CAAC;QACrC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,mBAAmB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;KACvC,CAAC;IACF,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,2BAA2B,EAAE,OAAO,CAAC;IACrC,8BAA8B,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACxD,iBAAiB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,kBAAkB,EAAE,CAAC,QAAQ,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD,KAAK,EAAE,KAAK,CAAC;IACb,eAAe,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IACjD,kBAAkB,EAAE,aAAa,CAAC;IAClC,qBAAqB,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACtD,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,EAAE,kBAAkB,CAAC;IAChC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,qBAAqB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACjD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IAC1C,WAAW,EAAE,WAAW,CAAC;CAC1B;AAED,wBAAgB,aAAa,CAAC,EAC5B,uBAAuB,EACvB,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,2BAA2B,EAC3B,8BAA8B,EAC9B,iBAAiB,EACjB,kBAAkB,EAClB,KAAK,EACL,eAAe,EACf,kBAAkB,EAClB,qBAAqB,EACrB,cAAc,EACd,WAAW,EACX,MAAM,EACN,cAAc,EACd,qBAAqB,EACrB,qBAAqB,EACrB,QAAQ,EACR,WAAW,EACX,iBAAiB,EACjB,iBAAiB,GAClB,EAAE,kBAAkB,GAAG,GAAG,CAAC,OAAO,CAmJlC"}
@@ -24,7 +24,7 @@ export function QueryControls({ showProfileTypeSelector, profileTypesData, profi
24
24
  setQueryBrowserMode(advancedModeForQueryBrowser ? 'simple' : 'advanced');
25
25
  }, className: `${advancedModeForQueryBrowser ? 'bg-indigo-600' : 'bg-gray-400 dark:bg-gray-800'} 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`, children: [_jsx("span", { className: "sr-only", children: "Use setting" }), _jsx("span", { "aria-hidden": "true", className: `${advancedModeForQueryBrowser ? 'translate-x-6' : 'translate-x-0'} pointer-events-none inline-block h-[16px] w-[16px] transform rounded-full bg-white shadow-lg ring-0 transition duration-200 ease-in-out` })] }), _jsx("label", { className: "text-xs", children: "Advanced Mode" })] }))] }), viewComponent?.createViewComponent] }), viewComponent?.disableExplorativeQuerying === true &&
26
26
  viewComponent?.labelnames !== undefined &&
27
- viewComponent?.labelnames.length >= 1 ? (_jsx(ViewMatchers, { labelNames: viewComponent.labelnames, setMatchersString: setMatchersString, profileType: selectedProfileName, runQuery: setQueryExpression, currentQuery: query, queryClient: queryClient })) : advancedModeForQueryBrowser ? (_jsx(MatchersInput, { setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query, profileType: selectedProfileName, queryClient: queryClient })) : (_jsx(SimpleMatchers, { setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query, profileType: selectedProfileName, queryBrowserRef: queryBrowserRef, queryClient: queryClient }, query.toString()))] }), showSumBySelector && (_jsxs("div", { children: [_jsx("div", { className: "mb-0.5 mt-1.5 flex items-center justify-between", children: _jsx("label", { className: "text-xs", children: "Sum by" }) }), _jsx(Select, { id: "h-sum-by-selector", defaultValue: [], isMulti: true, name: "colors", options: labels.map(label => ({ label, value: label })), className: "parca-select-container text-sm w-full max-w-80", classNamePrefix: "parca-select", value: (sumBySelection ?? []).map(sumBy => ({ label: sumBy, value: sumBy })), onChange: newValue => {
27
+ viewComponent?.labelnames.length >= 1 ? (_jsx(ViewMatchers, { labelNames: viewComponent.labelnames, setMatchersString: setMatchersString, profileType: selectedProfileName, runQuery: setQueryExpression, currentQuery: query, queryClient: queryClient })) : advancedModeForQueryBrowser ? (_jsx(MatchersInput, { setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query, profileType: selectedProfileName, queryClient: queryClient })) : (_jsx(SimpleMatchers, { setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query, profileType: selectedProfileName, queryBrowserRef: queryBrowserRef, queryClient: queryClient }, query.toString()))] }), showSumBySelector && (_jsxs("div", { children: [_jsx("div", { className: "mb-0.5 mt-1.5 flex items-center justify-between", children: _jsx("label", { className: "text-xs", children: "Sum by" }) }), _jsx(Select, { id: "h-sum-by-selector", defaultValue: [], isMulti: true, isClearable: false, name: "colors", options: labels.map(label => ({ label, value: label })), className: "parca-select-container text-sm w-full max-w-80", classNamePrefix: "parca-select", value: (sumBySelection ?? []).map(sumBy => ({ label: sumBy, value: sumBy })), onChange: newValue => {
28
28
  setUserSumBySelection(newValue.map(option => option.value));
29
29
  }, placeholder: "Labels...", styles: {
30
30
  indicatorSeparator: () => ({ display: 'none' }),
@@ -2,7 +2,6 @@ import React from 'react';
2
2
  interface GroupByControlsProps {
3
3
  groupBy: string[];
4
4
  labels: string[];
5
- toggleGroupBy: (key: string) => void;
6
5
  setGroupByLabels: (labels: string[]) => void;
7
6
  }
8
7
  declare const GroupByControls: React.FC<GroupByControlsProps>;
@@ -1 +1 @@
1
- {"version":3,"file":"GroupByDropdown.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ActionButtons/GroupByDropdown.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAoC,MAAM,OAAO,CAAC;AAuRzD,UAAU,oBAAoB;IAC5B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CAC9C;AAED,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAoDnD,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"GroupByDropdown.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ActionButtons/GroupByDropdown.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,UAAU,oBAAoB;IAC5B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CAC9C;AAED,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAYnD,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -1,143 +1,6 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- // Copyright 2022 The Parca Authors
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
14
- import { useEffect, useRef, useState } from 'react';
15
- import { Transition } from '@headlessui/react';
16
- import { Icon } from '@iconify/react';
17
- import Select from 'react-select';
18
- import { Button } from '@parca/components';
19
- import { FIELD_FUNCTION_FILE_NAME, FIELD_FUNCTION_NAME, FIELD_LABELS, FIELD_LOCATION_ADDRESS, FIELD_MAPPING_FILE, } from '../../../ProfileIcicleGraph/IcicleGraphArrow';
20
- const groupByOptions = [
21
- {
22
- value: FIELD_FUNCTION_NAME,
23
- label: 'Function Name',
24
- description: 'Stacktraces are grouped by function names.',
25
- disabled: true,
26
- },
27
- {
28
- value: FIELD_FUNCTION_FILE_NAME,
29
- label: 'Filename',
30
- description: 'Stacktraces are grouped by filenames.',
31
- disabled: false,
32
- },
33
- {
34
- value: FIELD_LOCATION_ADDRESS,
35
- label: 'Address',
36
- description: 'Stacktraces are grouped by addresses.',
37
- disabled: false,
38
- },
39
- {
40
- value: FIELD_MAPPING_FILE,
41
- label: 'Binary',
42
- description: 'Stacktraces are grouped by binaries.',
43
- disabled: false,
44
- },
45
- ];
46
- const LabelSelector = ({ labels, groupBy, setGroupByLabels, isOpen, labelsButtonRef, setIsLabelSelectorOpen, }) => {
47
- const [position, setPosition] = useState({ top: 0, left: 0 });
48
- useEffect(() => {
49
- if (isOpen && labelsButtonRef.current !== null) {
50
- const rect = labelsButtonRef.current.getBoundingClientRect();
51
- const parentRect = labelsButtonRef.current.offsetParent?.getBoundingClientRect() ?? {
52
- top: 0,
53
- left: 0,
54
- };
55
- setPosition({
56
- top: rect.bottom - parentRect.top,
57
- left: rect.right - parentRect.left + 4,
58
- });
59
- }
60
- }, [isOpen, labelsButtonRef]);
61
- if (!isOpen)
62
- return null;
63
- return (_jsx("div", { className: "absolute w-64 ml-4 z-20", style: {
64
- top: `${position.top}px`,
65
- left: `${position.left}px`,
66
- }, children: _jsx(Select, { isMulti: true, name: "labels", options: labels.map(label => ({ label, value: `${FIELD_LABELS}.${label}` })), className: "parca-select-container text-sm w-full border-gray-300 border rounded-md", classNamePrefix: "parca-select", value: groupBy
67
- .filter(l => l.startsWith(FIELD_LABELS))
68
- .map(l => ({ value: l, label: l.slice(FIELD_LABELS.length + 1) })), onChange: newValue => {
69
- setGroupByLabels(newValue.map(option => option.value));
70
- setIsLabelSelectorOpen(false);
71
- }, placeholder: "Select labels...", styles: {
72
- menu: provided => ({
73
- ...provided,
74
- position: 'relative',
75
- marginBottom: 0,
76
- boxShadow: 'none',
77
- marginTop: 0,
78
- }),
79
- control: provided => ({
80
- ...provided,
81
- boxShadow: 'none',
82
- borderBottom: '1px solid #e2e8f0',
83
- borderRight: 0,
84
- borderLeft: 0,
85
- borderTop: 0,
86
- borderBottomLeftRadius: 0,
87
- borderBottomRightRadius: 0,
88
- ':hover': {
89
- borderColor: '#e2e8f0',
90
- borderBottomLeftRadius: 0,
91
- borderBottomRightRadius: 0,
92
- },
93
- }),
94
- }, menuIsOpen: true }) }));
95
- };
96
- const GroupByDropdown = ({ groupBy, toggleGroupBy, onLabelClick, labelsButtonRef, }) => {
97
- const [isDropdownOpen, setIsDropdownOpen] = useState(false);
98
- const dropdownRef = useRef(null);
99
- useEffect(() => {
100
- const handleClickOutside = (event) => {
101
- if (isDropdownOpen &&
102
- dropdownRef.current != null &&
103
- !dropdownRef.current.contains(event.target)) {
104
- setIsDropdownOpen(false);
105
- }
106
- };
107
- document.addEventListener('mousedown', handleClickOutside);
108
- return () => {
109
- document.removeEventListener('mousedown', handleClickOutside);
110
- };
111
- }, [isDropdownOpen]);
112
- const label = groupBy.length === 0
113
- ? 'Nothing'
114
- : groupBy.length === 1
115
- ? groupByOptions.find(option => option.value === groupBy[0])?.label
116
- : 'Multiple';
117
- const selectedLabels = groupBy
118
- .filter(l => l.startsWith(FIELD_LABELS))
119
- .map(l => l.slice(FIELD_LABELS.length + 1));
120
- return (_jsxs("div", { className: "relative", ref: dropdownRef, children: [_jsx("label", { className: "text-sm", children: "Group by" }), _jsxs("div", { className: "relative text-left", id: "h-group-by-filter", children: [_jsxs(Button, { variant: "neutral", onClick: () => setIsDropdownOpen(!isDropdownOpen), className: "relative w-max cursor-default rounded-md border bg-white py-2 pl-3 pr-[1.7rem] text-left text-sm shadow-sm dark:border-gray-600 dark:bg-gray-900 sm:text-sm", children: [_jsx("span", { className: "block overflow-x-hidden text-ellipsis", children: label }), _jsx("span", { className: "pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2 text-gray-400", children: _jsx(Icon, { icon: "heroicons:chevron-down-20-solid", "aria-hidden": "true" }) })] }), _jsx(Transition, { as: "div", leave: "transition ease-in duration-100", leaveFrom: "opacity-100", leaveTo: "opacity-0", show: isDropdownOpen, children: _jsx("div", { className: "absolute left-0 z-10 mt-1 min-w-[400px] overflow-auto rounded-md bg-gray-50 py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:ring-white dark:ring-opacity-20 sm:text-sm", children: _jsx("div", { className: "p-4", children: _jsx("fieldset", { children: _jsxs("div", { className: "space-y-5", children: [groupByOptions.map(({ value, label, description, disabled }) => (_jsxs("div", { className: "relative flex items-start", children: [_jsx("div", { className: "flex h-6 items-center", children: _jsx("input", { id: value, name: value, type: "checkbox", disabled: disabled, className: "h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-600", checked: groupBy.includes(value), onChange: () => toggleGroupBy(value) }) }), _jsxs("div", { className: "ml-3 text-sm leading-6", children: [_jsx("label", { htmlFor: value, className: "font-medium text-gray-900 dark:text-gray-200", children: label }), _jsx("p", { className: "text-gray-500 dark:text-gray-400", children: description })] })] }, value))), _jsxs("div", { className: "ml-7 flex flex-col items-start text-sm leading-6 cursor-pointer", onClick: onLabelClick, ref: labelsButtonRef, children: [_jsxs("div", { className: "flex justify-between w-full items-center", children: [_jsxs("div", { children: [_jsx("span", { className: "font-medium text-gray-900 dark:text-gray-200", children: "Labels" }), _jsx("p", { className: "text-gray-500 dark:text-gray-400", children: "Stacktraces are grouped by labels." })] }), _jsx(Icon, { icon: "flowbite:caret-right-solid", className: "h-[14px] w-[14px]" })] }), selectedLabels.length > 0 && (_jsxs("div", { className: "flex gap-2 flex-wrap", children: [_jsx("span", { className: "text-gray-500 dark:text-gray-200", children: "Selected labels:" }), _jsx("div", { className: "flex flex-wrap gap-3", children: selectedLabels.map(label => (_jsx("span", { className: "mr-2 px-3 py-1 text-xs text-gray-700 dark:text-gray-200 bg-gray-200 rounded-md dark:bg-gray-800", children: label }, label))) })] }))] })] }) }) }) }) })] })] }));
121
- };
122
- const GroupByControls = ({ groupBy, labels, toggleGroupBy, setGroupByLabels, }) => {
123
- const [isLabelSelectorOpen, setIsLabelSelectorOpen] = useState(false);
124
- const labelsButton = useRef(null);
125
- const labelSelectorRef = useRef(null);
126
- useEffect(() => {
127
- const handleClickOutside = (event) => {
128
- if (isLabelSelectorOpen &&
129
- labelSelectorRef.current !== null &&
130
- !labelSelectorRef.current.contains(event.target) &&
131
- labelsButton.current !== null &&
132
- !labelsButton.current.contains(event.target)) {
133
- setIsLabelSelectorOpen(false);
134
- }
135
- };
136
- document.addEventListener('mousedown', handleClickOutside);
137
- return () => {
138
- document.removeEventListener('mousedown', handleClickOutside);
139
- };
140
- }, [isLabelSelectorOpen]);
141
- return (_jsx("div", { className: "inline-flex items-start", children: _jsxs("div", { className: "relative flex items-start", children: [_jsx(GroupByDropdown, { groupBy: groupBy, toggleGroupBy: toggleGroupBy, onLabelClick: () => setIsLabelSelectorOpen(!isLabelSelectorOpen), labelsButtonRef: labelsButton }), _jsx("div", { ref: labelSelectorRef, children: _jsx(LabelSelector, { labels: labels, groupBy: groupBy, setGroupByLabels: setGroupByLabels, isOpen: isLabelSelectorOpen, labelsButtonRef: labelsButton, setIsLabelSelectorOpen: setIsLabelSelectorOpen }) })] }) }));
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import GroupByLabelsDropdown from '../GroupByLabelsDropdown';
3
+ const GroupByControls = ({ groupBy, labels, setGroupByLabels }) => {
4
+ return (_jsx("div", { className: "inline-flex items-start", children: _jsx("div", { className: "relative flex gap-3 items-start", children: _jsx(GroupByLabelsDropdown, { labels: labels, groupBy: groupBy, setGroupByLabels: setGroupByLabels }) }) }));
142
5
  };
143
6
  export default GroupByControls;
@@ -0,0 +1,8 @@
1
+ interface Props {
2
+ labels: string[];
3
+ groupBy: string[];
4
+ setGroupByLabels: (labels: string[]) => void;
5
+ }
6
+ declare const GroupByLabelsDropdown: ({ labels, groupBy, setGroupByLabels }: Props) => JSX.Element;
7
+ export default GroupByLabelsDropdown;
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/GroupByLabelsDropdown/index.tsx"],"names":[],"mappings":"AAsBA,UAAU,KAAK;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CAC9C;AAED,QAAA,MAAM,qBAAqB,0CAAyC,KAAK,KAAG,GAAG,CAAC,OA6D/E,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
@@ -0,0 +1,57 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // Copyright 2022 The Parca Authors
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ import Select from 'react-select';
15
+ import { FIELD_LABELS } from '../../../ProfileIcicleGraph/IcicleGraphArrow';
16
+ const GroupByLabelsDropdown = ({ labels, groupBy, setGroupByLabels }) => {
17
+ return (_jsxs("div", { children: [_jsx("div", { className: "flex items-center justify-between", children: _jsx("label", { className: "text-sm", children: "Group by" }) }), _jsx(Select, { id: "h-group-by-labels-selector", isMulti: true, defaultMenuIsOpen: false, defaultValue: undefined, name: "labels", options: labels.map(label => ({ label, value: `${FIELD_LABELS}.${label}` })), className: "parca-select-container text-sm w-full rounded-md bg-white", classNamePrefix: "parca-select", value: groupBy
18
+ .filter(l => l.startsWith(FIELD_LABELS))
19
+ .map(l => ({ value: l, label: l.slice(FIELD_LABELS.length + 1) })), onChange: newValue => {
20
+ setGroupByLabels(newValue.map(option => option.value));
21
+ }, placeholder: "Select labels...", styles: {
22
+ menu: provided => ({
23
+ ...provided,
24
+ marginBottom: 0,
25
+ boxShadow: 'none',
26
+ marginTop: 0,
27
+ zIndex: 1000,
28
+ minWidth: '320px',
29
+ }),
30
+ control: provided => ({
31
+ ...provided,
32
+ position: 'relative',
33
+ boxShadow: 'none',
34
+ borderBottom: '1px solid #e2e8f0',
35
+ borderRight: '1px solid #e2e8f0',
36
+ borderLeft: '1px solid #e2e8f0',
37
+ borderTop: '1px solid #e2e8f0',
38
+ ':hover': {
39
+ borderColor: '#e2e8f0',
40
+ borderBottomLeftRadius: 0,
41
+ borderBottomRightRadius: 0,
42
+ },
43
+ }),
44
+ option: provided => ({
45
+ ...provided,
46
+ ':hover': {
47
+ backgroundColor: '#4f46e5',
48
+ color: '#ffffff',
49
+ },
50
+ ':focus': {
51
+ backgroundColor: '#4f46e5',
52
+ color: '#ffffff',
53
+ },
54
+ }),
55
+ } })] }));
56
+ };
57
+ export default GroupByLabelsDropdown;
@@ -0,0 +1,3 @@
1
+ declare const InvertCallStack: () => JSX.Element;
2
+ export default InvertCallStack;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/InvertCallStack/index.tsx"],"names":[],"mappings":"AAiBA,QAAA,MAAM,eAAe,QAAO,GAAG,CAAC,OAc/B,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // Copyright 2022 The Parca Authors
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ import { Icon } from '@iconify/react';
15
+ import { Button, useURLState } from '@parca/components';
16
+ const InvertCallStack = () => {
17
+ const [invertStack = '', setInvertStack] = useURLState('invert_call_stack');
18
+ const isInvert = invertStack === 'true';
19
+ return (_jsxs(Button, { variant: "neutral", className: "flex items-center gap-2", onClick: () => setInvertStack(isInvert ? '' : 'true'), children: [_jsx(Icon, { icon: isInvert ? 'ph:sort-ascending' : 'ph:sort-descending', className: "h-4 w-4" }), isInvert ? 'Original' : 'Invert', " Call Stack"] }));
20
+ };
21
+ export default InvertCallStack;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ShareButton/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAiB,MAAM,OAAO,CAAC;AAItC,OAAO,EAAC,YAAY,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAG/D,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAGrD,UAAU,KAAK;IACb,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,6BAA6B,EAAE,KAAK,CAAC,SAAS,CAAC;CAChD;AAmGD,QAAA,MAAM,WAAW,oHAOd,KAAK,KAAG,GAAG,CAAC,OA4Ed,CAAC;AAEF,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ShareButton/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAiB,MAAM,OAAO,CAAC;AAItC,OAAO,EAAC,YAAY,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAG/D,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAGrD,UAAU,KAAK;IACb,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,6BAA6B,EAAE,KAAK,CAAC,SAAS,CAAC;CAChD;AAmGD,QAAA,MAAM,WAAW,oHAOd,KAAK,KAAG,GAAG,CAAC,OAgFd,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -77,7 +77,7 @@ const ShareButton = ({ queryRequest, queryClient, profileSource, onDownloadPProf
77
77
  return (_jsx(_Fragment, { children: profileViewExternalSubActions != null ? (_jsx(_Fragment, { children: _jsxs(Button, { className: "gap-2", variant: "neutral", onClick: e => {
78
78
  e.preventDefault();
79
79
  onDownloadPProf();
80
- }, disabled: pprofdownloading, id: "h-download-pprof", children: [pprofdownloading != null && pprofdownloading ? 'Downloading...' : 'Download pprof', _jsx(Icon, { icon: "material-symbols:download", width: 20 })] }) })) : (_jsxs(_Fragment, { children: [_jsxs(Dropdown, { dropdownWidth: "w-48", element: _jsxs(Button, { variant: "neutral", children: ["Share", _jsx(Icon, { icon: "material-symbols:share", className: "h-5 w-5 ml-2" })] }), children: [_jsx("span", { className: "text-xs text-gray-400 capitalize px-2", children: "actions" }), actions.map(item => (_jsx(Dropdown.Item, { onSelect: item.onSelect, children: _jsxs("div", { id: item.id, className: "flex items-center", children: [_jsx("span", { children: item.label }), _jsx(Icon, { icon: item.icon, className: "ml-2 h-4 w-4" })] }) }, item.key)))] }), profileSource !== undefined &&
80
+ }, disabled: pprofdownloading, id: "h-download-pprof", children: [pprofdownloading != null && pprofdownloading ? 'Downloading...' : 'Download pprof', _jsx(Icon, { icon: "material-symbols:download", width: 20 })] }) })) : (_jsxs(_Fragment, { children: [_jsxs(Dropdown, { dropdownWidth: "w-48", element: _jsxs(Button, { variant: "neutral", className: "flex items-center gap-2", id: "h-share-dropdown-button", children: [_jsx(Icon, { icon: "material-symbols:share", className: "h-4 w-4" }), "Share"] }), children: [_jsx("span", { className: "text-xs text-gray-400 capitalize px-2", children: "actions" }), actions.map(item => (_jsx(Dropdown.Item, { onSelect: item.onSelect, children: _jsxs("div", { id: item.id, className: "flex items-center gap-2", children: [_jsx(Icon, { icon: item.icon, className: "h-4 w-4" }), _jsx("span", { children: item.label })] }) }, item.key)))] }), profileSource !== undefined &&
81
81
  queryClient !== undefined &&
82
82
  queryRequest !== undefined && (_jsx(ProfileShareModal, { isOpen: showProfileShareModal, closeModal: () => setShowProfileShareModal(false), queryRequest: queryRequest, queryClient: queryClient }))] })) }));
83
83
  };
@@ -3,6 +3,9 @@ import { ProfileType } from '@parca/parser';
3
3
  interface MultiLevelDropdownProps {
4
4
  onSelect: (path: string[]) => void;
5
5
  profileType?: ProfileType;
6
+ groupBy: string[];
7
+ toggleGroupBy: (key: string) => void;
8
+ isTableVizOnly: boolean;
6
9
  }
7
10
  declare const MultiLevelDropdown: React.FC<MultiLevelDropdownProps>;
8
11
  export default MultiLevelDropdown;
@@ -1 +1 @@
1
- {"version":3,"file":"MultiLevelDropdown.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/Toolbars/MultiLevelDropdown.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAOzC,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AA6H1C,UAAU,uBAAuB;IAC/B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,QAAA,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAkKzD,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
1
+ {"version":3,"file":"MultiLevelDropdown.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/Toolbars/MultiLevelDropdown.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAQtE,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAkK1C,UAAU,uBAAuB;IAC/B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,QAAA,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAyOzD,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
@@ -11,14 +11,29 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
11
11
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
- import { useCallback } from 'react';
14
+ import { useCallback, useEffect, useRef, useState } from 'react';
15
15
  import { Menu } from '@headlessui/react';
16
16
  import { Icon } from '@iconify/react';
17
+ import cx from 'classnames';
17
18
  import { useURLState } from '@parca/components';
18
19
  import { USER_PREFERENCES, useUserPreference } from '@parca/hooks';
19
- import { FIELD_FUNCTION_NAME } from '../../../ProfileIcicleGraph/IcicleGraphArrow';
20
+ import { FIELD_FUNCTION_FILE_NAME, FIELD_FUNCTION_NAME, FIELD_LOCATION_ADDRESS, FIELD_MAPPING_FILE, } from '../../../ProfileIcicleGraph/IcicleGraphArrow';
20
21
  import { useProfileViewContext } from '../../context/ProfileViewContext';
21
- const MenuItem = ({ label, items, onclick, onSelect, path = [], id, closeDropdown, isNested = false, activeValueForSortBy, activeValueForColorBy, value, disabled = false, icon, customSubmenu, }) => {
22
+ import SwitchMenuItem from './SwitchMenuItem';
23
+ const MenuItem = ({ label, items, onclick, onSelect, path = [], id, closeDropdown, isNested = false, activeValueForSortBy, activeValueForColorBy, activeValuesForLevel, value, disabled = false, icon, customSubmenu, renderAsDiv = false, }) => {
24
+ const menuRef = useRef(null);
25
+ const [shouldOpenLeft, setShouldOpenLeft] = useState(false);
26
+ useEffect(() => {
27
+ if (items !== undefined && menuRef.current !== null) {
28
+ const rect = menuRef.current.getBoundingClientRect();
29
+ const viewportWidth = window.innerWidth;
30
+ const menuWidth = 224; // w-56 = 14rem = 224px
31
+ const spaceOnRight = viewportWidth - rect.right;
32
+ const spaceOnLeft = rect.left;
33
+ // Open to the left if there's not enough space on the right but enough on the left
34
+ setShouldOpenLeft(spaceOnRight < menuWidth && spaceOnLeft >= menuWidth);
35
+ }
36
+ }, [items]);
22
37
  let isActive = false;
23
38
  if (isNested) {
24
39
  if (activeValueForSortBy !== undefined && value === activeValueForSortBy) {
@@ -27,6 +42,9 @@ const MenuItem = ({ label, items, onclick, onSelect, path = [], id, closeDropdow
27
42
  if (activeValueForColorBy !== undefined && value === activeValueForColorBy) {
28
43
  isActive = true;
29
44
  }
45
+ if (activeValuesForLevel?.includes(value ?? '') ?? false) {
46
+ isActive = true;
47
+ }
30
48
  }
31
49
  const handleSelect = () => {
32
50
  if (items === undefined) {
@@ -40,17 +58,19 @@ const MenuItem = ({ label, items, onclick, onSelect, path = [], id, closeDropdow
40
58
  }
41
59
  }
42
60
  };
43
- return (_jsx("div", { className: "relative", children: _jsx(Menu, { children: ({ close }) => (_jsxs(_Fragment, { children: [_jsxs(Menu.Button, { className: `w-full text-left px-4 py-2 text-sm ${disabled
61
+ return (_jsx("div", { className: "relative", ref: menuRef, children: _jsx(Menu, { children: ({ close }) => (_jsxs(_Fragment, { children: [_jsxs(Menu.Button, { as: renderAsDiv ? 'div' : 'button', className: `w-full text-left px-4 py-2 text-sm ${disabled
44
62
  ? 'text-gray-400'
45
63
  : isActive
46
64
  ? 'text-white bg-indigo-400 hover:text-white'
47
- : 'text-white-600 hover:bg-indigo-600 hover:text-white'} flex justify-between items-center`, onClick: handleSelect, id: id, disabled: disabled, children: [customSubmenu !== undefined ? (customSubmenu) : (_jsxs("span", { className: "flex items-center", children: [_jsxs("div", { className: "flex items-center", children: [_jsx("span", { children: label }), icon !== undefined && _jsx(Icon, { icon: icon, className: "ml-2 h-4 w-4" })] }), isActive && _jsx(Icon, { icon: "heroicons-solid:check", className: "ml-2 h-4 w-4" })] })), items !== undefined && (_jsx(Icon, { icon: "flowbite:caret-right-solid", className: "h-[14px] w-[14px]" }))] }), items !== undefined && (_jsx(Menu.Items, { className: "absolute left-full top-0 w-56 mt-0 origin-top-right bg-white border border-gray-200 rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:bg-gray-900 ml-1 dark:border-gray-600", children: items?.map((item, index) => (_jsx(MenuItem, { ...item, onSelect: selectedPath => {
65
+ : 'text-white-600 hover:bg-indigo-600 hover:text-white'} flex justify-between items-center`, onClick: handleSelect, id: id, disabled: disabled, children: [customSubmenu !== undefined ? (customSubmenu) : (_jsxs("span", { className: "flex items-center", children: [_jsxs("div", { className: "flex items-center gap-2", children: [icon !== undefined && _jsx(Icon, { icon: icon, className: "h-4 w-4" }), _jsx("span", { children: label })] }), isActive && _jsx(Icon, { icon: "heroicons-solid:check", className: "ml-2 h-4 w-4" })] })), items !== undefined && (_jsx(Icon, { icon: "flowbite:caret-right-solid", className: "h-[14px] w-[14px]" }))] }), items !== undefined && (_jsx(Menu.Items, { className: `absolute top-0 w-56 mt-0 bg-white border border-gray-200 rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:bg-gray-900 dark:border-gray-600 ${shouldOpenLeft
66
+ ? 'right-full mr-1 origin-top-left'
67
+ : 'left-full ml-1 origin-top-right'}`, children: items?.map((item, index) => (_jsx(MenuItem, { ...item, onSelect: selectedPath => {
48
68
  onSelect([...path, ...selectedPath]);
49
69
  close();
50
70
  closeDropdown();
51
- }, path: [...path, label], closeDropdown: closeDropdown, isNested: true, activeValueForSortBy: activeValueForSortBy, activeValueForColorBy: activeValueForColorBy }, index))) }))] })) }) }));
71
+ }, path: [...path, label], closeDropdown: closeDropdown, isNested: true, activeValueForSortBy: activeValueForSortBy, activeValueForColorBy: activeValueForColorBy, activeValuesForLevel: activeValuesForLevel }, index))) }))] })) }) }));
52
72
  };
53
- const MultiLevelDropdown = ({ onSelect, profileType }) => {
73
+ const MultiLevelDropdown = ({ onSelect, profileType, groupBy, toggleGroupBy, isTableVizOnly, }) => {
54
74
  const [storeSortBy] = useURLState('sort_by', {
55
75
  defaultValue: FIELD_FUNCTION_NAME,
56
76
  });
@@ -63,8 +83,6 @@ const MultiLevelDropdown = ({ onSelect, profileType }) => {
63
83
  });
64
84
  const { compareMode } = useProfileViewContext();
65
85
  const [colorProfileName] = useUserPreference(USER_PREFERENCES.FLAMEGRAPH_COLOR_PROFILE.key);
66
- const [invertStack = '', setInvertStack] = useURLState('invert_call_stack');
67
- const isInvert = invertStack === 'true';
68
86
  const isColorStackLegendEnabled = colorStackLegend === 'true';
69
87
  const [alignFunctionName, setAlignFunctionName] = useURLState('align_function_name');
70
88
  const isLeftAligned = alignFunctionName === 'left' || alignFunctionName === undefined;
@@ -85,9 +103,37 @@ const MultiLevelDropdown = ({ onSelect, profileType }) => {
85
103
  setBinaryFrameFilter([]);
86
104
  };
87
105
  const menuItems = [
106
+ {
107
+ label: 'Levels',
108
+ id: 'h-levels-filter',
109
+ items: [
110
+ {
111
+ label: 'Function',
112
+ onclick: () => toggleGroupBy(FIELD_FUNCTION_NAME),
113
+ value: FIELD_FUNCTION_NAME,
114
+ },
115
+ {
116
+ label: 'Binary',
117
+ onclick: () => toggleGroupBy(FIELD_MAPPING_FILE),
118
+ value: FIELD_MAPPING_FILE,
119
+ },
120
+ {
121
+ label: 'Code',
122
+ onclick: () => toggleGroupBy(FIELD_FUNCTION_FILE_NAME),
123
+ value: FIELD_FUNCTION_FILE_NAME,
124
+ },
125
+ {
126
+ label: 'Address',
127
+ onclick: () => toggleGroupBy(FIELD_LOCATION_ADDRESS),
128
+ value: FIELD_LOCATION_ADDRESS,
129
+ },
130
+ ],
131
+ hide: !!isTableVizOnly,
132
+ icon: 'heroicons-solid:bars-3',
133
+ },
88
134
  {
89
135
  label: 'Color by',
90
- id: 'h-solor-by-filter',
136
+ id: 'h-color-by-filter',
91
137
  items: [
92
138
  {
93
139
  label: 'Binary',
@@ -110,17 +156,11 @@ const MultiLevelDropdown = ({ onSelect, profileType }) => {
110
156
  id: 'h-show-legend-button',
111
157
  icon: isColorStackLegendEnabled ? 'ph:eye-closed' : 'ph:eye',
112
158
  },
113
- {
114
- label: isInvert ? 'Original Call Stack' : 'Invert Call Stack',
115
- onclick: () => setInvertStack(isInvert ? '' : 'true'),
116
- hide: false,
117
- icon: isInvert ? 'ph:sort-ascending' : 'ph:sort-descending',
118
- },
119
159
  {
120
160
  label: isLeftAligned ? 'Right-align function names' : 'Left-align function names',
121
161
  onclick: () => setAlignFunctionName(isLeftAligned ? 'right' : 'left'),
122
162
  id: 'h-align-function-names',
123
- hide: false,
163
+ hide: !!isTableVizOnly,
124
164
  icon: isLeftAligned
125
165
  ? 'ic:outline-align-horizontal-right'
126
166
  : 'ic:outline-align-horizontal-left',
@@ -131,6 +171,24 @@ const MultiLevelDropdown = ({ onSelect, profileType }) => {
131
171
  hide: !compareMode,
132
172
  icon: isCompareAbsolute ? 'fluent-mdl2:compare' : 'fluent-mdl2:compare-uneven',
133
173
  },
174
+ {
175
+ label: 'Highlight matching nodes after filtering',
176
+ hide: !!isTableVizOnly,
177
+ customSubmenu: (_jsx(SwitchMenuItem, { label: "Highlight matching nodes after filtering", id: "h-highlight-after-filtering", userPreferenceDetails: USER_PREFERENCES.HIGHTLIGHT_AFTER_FILTERING })),
178
+ renderAsDiv: true,
179
+ },
180
+ {
181
+ label: 'Dock Graph MetaInfo',
182
+ hide: !!isTableVizOnly,
183
+ customSubmenu: (_jsx(SwitchMenuItem, { label: "Dock graph tooltip", id: "h-dock-graph-meta-info", userPreferenceDetails: USER_PREFERENCES.GRAPH_METAINFO_DOCKED })),
184
+ renderAsDiv: true,
185
+ },
186
+ {
187
+ label: 'Highlight similar stacks when hovering over a node',
188
+ hide: !!isTableVizOnly,
189
+ customSubmenu: (_jsx(SwitchMenuItem, { label: "Highlight similar stacks when hovering over a node", id: "h-highlight-similar-stacks", userPreferenceDetails: USER_PREFERENCES.HIGHLIGHT_SIMILAR_STACKS })),
190
+ renderAsDiv: true,
191
+ },
134
192
  {
135
193
  label: 'Reset Legend',
136
194
  hide: binaryFrameFilter === undefined || binaryFrameFilter.length === 0,
@@ -149,8 +207,8 @@ const MultiLevelDropdown = ({ onSelect, profileType }) => {
149
207
  icon: 'ph:eye-closed',
150
208
  },
151
209
  ];
152
- return (_jsx("div", { className: "relative inline-block text-left", id: "h-visualisation-toolbar-actions", children: _jsx(Menu, { children: ({ open, close }) => (_jsxs(_Fragment, { children: [_jsxs(Menu.Button, { className: "inline-flex dark:bg-gray-900 dark:border-gray-600 justify-center w-full px-4 py-2 text-sm font-normal text-gray-600 dark:text-gray-200 bg-white rounded-md focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 border border-gray-200 pr-[1.7rem]", children: [_jsx("span", { children: "More" }), _jsx("span", { className: "pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2 text-gray-400", children: _jsx(Icon, { icon: "heroicons:chevron-down-20-solid", "aria-hidden": "true" }) })] }), open && (_jsxs(Menu.Items, { className: "absolute z-30 left-0 w-64 mt-2 py-2 origin-top-right bg-white rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none border dark:bg-gray-900 dark:border-gray-600", children: [_jsx("span", { className: "text-xs text-gray-400 capitalize px-4 py-3", children: "actions" }), menuItems
153
- .filter(item => item.hide !== undefined && !item.hide)
154
- .map((item, index) => (_jsx(MenuItem, { ...item, onSelect: onSelect, closeDropdown: close, activeValueForSortBy: storeSortBy, activeValueForColorBy: colorBy === undefined || colorBy === '' ? 'binary' : colorBy }, index)))] }))] })) }) }));
210
+ return (_jsx("div", { className: "relative inline-block text-left", id: "h-visualisation-toolbar-actions", children: _jsx(Menu, { children: ({ open, close }) => (_jsxs(_Fragment, { children: [_jsxs(Menu.Button, { className: "flex dark:bg-gray-900 dark:border-gray-600 justify-center w-full px-4 py-2 text-sm font-normal text-gray-600 dark:text-gray-200 bg-white rounded-md focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 border border-gray-200 pr-[1.7rem]", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Icon, { icon: "pajamas:preferences", className: "w-4 h-4" }), _jsx("span", { children: "Preferences" })] }), _jsx("span", { className: "pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2 text-gray-400", children: _jsx(Icon, { icon: "heroicons:chevron-down-20-solid", "aria-hidden": "true" }) })] }), open && (_jsx(Menu.Items, { className: cx(isTableVizOnly ? 'w-64' : 'w-80', 'absolute z-30 left-0 mt-2 py-2 origin-top-right bg-white rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none border dark:bg-gray-900 dark:border-gray-600'), children: menuItems
211
+ .filter(item => item.hide !== undefined && !item.hide)
212
+ .map((item, index) => (_jsx(MenuItem, { ...item, onSelect: onSelect, closeDropdown: close, activeValueForSortBy: storeSortBy, activeValueForColorBy: colorBy === undefined || colorBy === '' ? 'binary' : colorBy, activeValuesForLevel: groupBy, renderAsDiv: item.renderAsDiv }, index))) }))] })) }) }));
155
213
  };
156
214
  export default MultiLevelDropdown;
@@ -0,0 +1,9 @@
1
+ import { type UserPreferenceDetails } from '@parca/hooks';
2
+ interface SwitchMenuItemProps {
3
+ label: string;
4
+ id: string;
5
+ userPreferenceDetails: UserPreferenceDetails;
6
+ }
7
+ declare function SwitchMenuItem<T>({ label, id, userPreferenceDetails }: SwitchMenuItemProps): JSX.Element;
8
+ export default SwitchMenuItem;
9
+ //# sourceMappingURL=SwitchMenuItem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SwitchMenuItem.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/Toolbars/SwitchMenuItem.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAoB,KAAK,qBAAqB,EAAC,MAAM,cAAc,CAAC;AAE3E,UAAU,mBAAmB;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,qBAAqB,EAAE,qBAAqB,CAAC;CAC9C;AAED,iBAAS,cAAc,CAAC,CAAC,EAAE,EAAC,KAAK,EAAE,EAAE,EAAE,qBAAqB,EAAC,EAAE,mBAAmB,GAAG,GAAG,CAAC,OAAO,CAwB/F;AAED,eAAe,cAAc,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // Copyright 2022 The Parca Authors
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ import { Switch } from '@headlessui/react';
15
+ import { useUserPreference } from '@parca/hooks';
16
+ function SwitchMenuItem({ label, id, userPreferenceDetails }) {
17
+ const [enabledPreference, setEnabledPreference] = useUserPreference(userPreferenceDetails.key);
18
+ return (_jsxs("div", { className: "flex items-center justify-between w-full", children: [_jsx("span", { children: label }), _jsxs(Switch, { id: id, checked: enabledPreference, onChange: (checked) => setEnabledPreference(checked), className: `${enabledPreference ? 'bg-indigo-600' : 'bg-gray-400 dark:bg-gray-800'}
19
+ relative inline-flex h-[24px] 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`, children: [_jsx("span", { className: "sr-only", children: "Use setting" }), _jsx("span", { "aria-hidden": "true", className: `${enabledPreference ? 'translate-x-5' : 'translate-x-0'}
20
+ pointer-events-none inline-block h-[20px] w-[20px] transform rounded-full bg-white shadow-lg ring-0 transition duration-200 ease-in-out` })] })] }));
21
+ }
22
+ export default SwitchMenuItem;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/Toolbars/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,EAAE,EAAC,MAAM,OAAO,CAAC;AAIzB,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAC,gBAAgB,EAAC,MAAM,oDAAoD,CAAC;AACpF,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AASrD,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAClD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,6BAA6B,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAChD,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,uBAAuB,EAAE,CAAC,oBAAoB,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IAC5E,yBAAyB,EAAE,MAAM,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;CACnD;AAED,MAAM,WAAW,+BAA+B;IAC9C,yBAAyB,EAAE,MAAM,IAAI,CAAC;IACtC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CAwB9C,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,EAAE,CAAC,uBAAuB,CAiB1D,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,EAAE,CAAC,+BAA+B,CAmB1E,CAAC;AAMF,eAAO,MAAM,oBAAoB,EAAE,EAAE,CAAC,yBAAyB,CA8F9D,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/Toolbars/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,EAAE,EAAC,MAAM,OAAO,CAAC;AAIzB,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAC,gBAAgB,EAAC,MAAM,oDAAoD,CAAC;AACpF,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAUrD,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAClD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,6BAA6B,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAChD,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,uBAAuB,EAAE,CAAC,oBAAoB,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IAC5E,yBAAyB,EAAE,MAAM,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;CACnD;AAED,MAAM,WAAW,+BAA+B;IAC9C,yBAAyB,EAAE,MAAM,IAAI,CAAC;IACtC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CAwB9C,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,EAAE,CAAC,uBAAuB,CAiB1D,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,EAAE,CAAC,+BAA+B,CAmB1E,CAAC;AAMF,eAAO,MAAM,oBAAoB,EAAE,EAAE,CAAC,yBAAyB,CA6G9D,CAAC"}
@@ -4,6 +4,7 @@ import { Button, UserPreferencesModal } from '@parca/components';
4
4
  import { useDashboard } from '../../context/DashboardContext';
5
5
  import GroupByDropdown from '../ActionButtons/GroupByDropdown';
6
6
  import FilterByFunctionButton from '../FilterByFunctionButton';
7
+ import InvertCallStack from '../InvertCallStack';
7
8
  import ShareButton from '../ShareButton';
8
9
  import ViewSelector from '../ViewSelector';
9
10
  import MultiLevelDropdown from './MultiLevelDropdown';
@@ -21,13 +22,15 @@ const Divider = () => (_jsx("div", { className: "border-t mt-4 border-gray-200 d
21
22
  export const VisualisationToolbar = ({ groupBy, toggleGroupBy, groupByLabels, setGroupByLabels, profileType, preferencesModal, profileSource, queryClient, onDownloadPProf, pprofdownloading, profileViewExternalSubActions, curPath, setNewCurPath, total, filtered, currentSearchString, clearSelection, showVisualizationSelector = true, resetSandwichFunctionName, sandwichFunctionName, }) => {
22
23
  const { dashboardItems } = useDashboard();
23
24
  const isTableViz = dashboardItems?.includes('table');
25
+ const isTableVizOnly = dashboardItems?.length === 1 && isTableViz;
24
26
  const isGraphViz = dashboardItems?.includes('icicle');
25
27
  const isSandwichIcicleGraphViz = dashboardItems?.includes('sandwich');
28
+ const isTableView = isTableVizOnly || isSandwichIcicleGraphViz;
26
29
  const req = profileSource?.QueryRequest();
27
30
  if (req !== null && req !== undefined) {
28
31
  req.groupBy = {
29
32
  fields: groupBy ?? [],
30
33
  };
31
34
  }
32
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex w-full justify-between items-end", children: [_jsxs("div", { className: "flex gap-3 items-end", children: [_jsxs(_Fragment, { children: [_jsx(GroupByDropdown, { groupBy: groupBy, toggleGroupBy: toggleGroupBy, labels: groupByLabels, setGroupByLabels: setGroupByLabels }), _jsx(MultiLevelDropdown, { profileType: profileType, onSelect: () => { } })] }), _jsx(FilterByFunctionButton, {}), profileViewExternalSubActions != null ? profileViewExternalSubActions : null] }), _jsxs("div", { className: "flex gap-3", children: [preferencesModal === true && _jsx(UserPreferencesModal, {}), _jsx(ShareButton, { profileSource: profileSource, queryClient: queryClient, queryRequest: req, onDownloadPProf: onDownloadPProf, pprofdownloading: pprofdownloading ?? false, profileViewExternalSubActions: profileViewExternalSubActions }), showVisualizationSelector ? _jsx(ViewSelector, { profileSource: profileSource }) : null] })] }), isGraphViz && !isTableViz && (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(IcicleGraphToolbar, { curPath: curPath, setNewCurPath: setNewCurPath })] })), isTableViz && !isGraphViz && (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(TableToolbar, { profileType: profileType, total: total, filtered: filtered, clearSelection: clearSelection, currentSearchString: currentSearchString })] })), isSandwichIcicleGraphViz && (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(SandwichIcicleGraphToolbar, { resetSandwichFunctionName: resetSandwichFunctionName, sandwichFunctionName: sandwichFunctionName })] }))] }));
35
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex w-full justify-between items-end", children: [_jsxs("div", { className: "flex gap-3 items-end", children: [!isTableView && (_jsxs(_Fragment, { children: [_jsx(GroupByDropdown, { groupBy: groupBy, labels: groupByLabels, setGroupByLabels: setGroupByLabels }), _jsx(InvertCallStack, {})] })), _jsx(FilterByFunctionButton, {}), profileViewExternalSubActions != null ? profileViewExternalSubActions : null] }), _jsxs("div", { className: "flex gap-3", children: [preferencesModal === true && _jsx(UserPreferencesModal, {}), _jsx(MultiLevelDropdown, { groupBy: groupBy, toggleGroupBy: toggleGroupBy, profileType: profileType, onSelect: () => { }, isTableVizOnly: isTableView }), _jsx(ShareButton, { profileSource: profileSource, queryClient: queryClient, queryRequest: req, onDownloadPProf: onDownloadPProf, pprofdownloading: pprofdownloading ?? false, profileViewExternalSubActions: profileViewExternalSubActions }), showVisualizationSelector ? _jsx(ViewSelector, { profileSource: profileSource }) : null] })] }), isGraphViz && !isTableViz && (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(IcicleGraphToolbar, { curPath: curPath, setNewCurPath: setNewCurPath })] })), isTableViz && !isGraphViz && (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(TableToolbar, { profileType: profileType, total: total, filtered: filtered, clearSelection: clearSelection, currentSearchString: currentSearchString })] })), isSandwichIcicleGraphViz && (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(SandwichIcicleGraphToolbar, { resetSandwichFunctionName: resetSandwichFunctionName, sandwichFunctionName: sandwichFunctionName })] }))] }));
33
36
  };