@parca/profile 0.16.425 → 0.16.427

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 (79) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.js +1 -1
  3. package/dist/ProfileIcicleGraph/index.d.ts +1 -1
  4. package/dist/ProfileIcicleGraph/index.d.ts.map +1 -1
  5. package/dist/ProfileIcicleGraph/index.js +4 -59
  6. package/dist/ProfileSelector/index.d.ts.map +1 -1
  7. package/dist/ProfileSelector/index.js +11 -6
  8. package/dist/ProfileView/VisualizationPanel.d.ts.map +1 -1
  9. package/dist/ProfileView/VisualizationPanel.js +2 -3
  10. package/dist/ProfileView/index.d.ts.map +1 -1
  11. package/dist/ProfileView/index.js +21 -14
  12. package/dist/Table/ColumnsVisibility.js +1 -1
  13. package/dist/Table/index.d.ts +6 -0
  14. package/dist/Table/index.d.ts.map +1 -1
  15. package/dist/Table/index.js +45 -21
  16. package/dist/ViewMatchers/index.d.ts +14 -0
  17. package/dist/ViewMatchers/index.d.ts.map +1 -0
  18. package/dist/ViewMatchers/index.js +103 -0
  19. package/dist/components/ActionButtons/GroupByDropdown.d.ts.map +1 -0
  20. package/dist/{ProfileIcicleGraph → components}/ActionButtons/GroupByDropdown.js +1 -1
  21. package/dist/components/FilterByFunctionButton.d.ts.map +1 -0
  22. package/dist/components/ShareButton/ResultBox.d.ts.map +1 -0
  23. package/dist/components/ShareButton/index.d.ts +14 -0
  24. package/dist/components/ShareButton/index.d.ts.map +1 -0
  25. package/dist/components/{ProfileShareButton → ShareButton}/index.js +28 -5
  26. package/dist/components/ViewSelector/Dropdown.d.ts +30 -0
  27. package/dist/components/ViewSelector/Dropdown.d.ts.map +1 -0
  28. package/dist/components/ViewSelector/Dropdown.js +41 -0
  29. package/dist/components/ViewSelector/index.d.ts +3 -0
  30. package/dist/components/ViewSelector/index.d.ts.map +1 -0
  31. package/dist/{ProfileView/ViewSelector.js → components/ViewSelector/index.js} +25 -12
  32. package/dist/components/VisualisationToolbar/MultiLevelDropdown.d.ts +9 -0
  33. package/dist/components/VisualisationToolbar/MultiLevelDropdown.d.ts.map +1 -0
  34. package/dist/components/VisualisationToolbar/MultiLevelDropdown.js +123 -0
  35. package/dist/components/VisualisationToolbar/TableColumnsDropdown.d.ts +9 -0
  36. package/dist/components/VisualisationToolbar/TableColumnsDropdown.d.ts.map +1 -0
  37. package/dist/components/VisualisationToolbar/TableColumnsDropdown.js +189 -0
  38. package/dist/components/VisualisationToolbar/index.d.ts +25 -0
  39. package/dist/components/VisualisationToolbar/index.d.ts.map +1 -0
  40. package/dist/components/VisualisationToolbar/index.js +55 -0
  41. package/dist/index.d.ts +3 -1
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +3 -1
  44. package/dist/styles.css +1 -1
  45. package/package.json +4 -4
  46. package/src/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.tsx +1 -1
  47. package/src/ProfileIcicleGraph/index.tsx +3 -206
  48. package/src/ProfileSelector/index.tsx +59 -33
  49. package/src/ProfileView/VisualizationPanel.tsx +1 -6
  50. package/src/ProfileView/index.tsx +46 -56
  51. package/src/Table/ColumnsVisibility.tsx +1 -1
  52. package/src/Table/index.tsx +64 -42
  53. package/src/ViewMatchers/index.tsx +190 -0
  54. package/src/{ProfileIcicleGraph → components}/ActionButtons/GroupByDropdown.tsx +1 -1
  55. package/src/components/{ProfileShareButton → ShareButton}/index.tsx +88 -24
  56. package/src/components/ViewSelector/Dropdown.tsx +181 -0
  57. package/src/{ProfileView/ViewSelector.tsx → components/ViewSelector/index.tsx} +32 -39
  58. package/src/components/VisualisationToolbar/MultiLevelDropdown.tsx +258 -0
  59. package/src/components/VisualisationToolbar/TableColumnsDropdown.tsx +222 -0
  60. package/src/components/VisualisationToolbar/index.tsx +171 -0
  61. package/src/index.tsx +3 -1
  62. package/dist/ProfileIcicleGraph/ActionButtons/GroupByDropdown.d.ts.map +0 -1
  63. package/dist/ProfileIcicleGraph/ActionButtons/SortBySelect.d.ts +0 -7
  64. package/dist/ProfileIcicleGraph/ActionButtons/SortBySelect.d.ts.map +0 -1
  65. package/dist/ProfileIcicleGraph/ActionButtons/SortBySelect.js +0 -44
  66. package/dist/ProfileView/FilterByFunctionButton.d.ts.map +0 -1
  67. package/dist/ProfileView/ViewSelector.d.ts +0 -13
  68. package/dist/ProfileView/ViewSelector.d.ts.map +0 -1
  69. package/dist/components/ProfileShareButton/ResultBox.d.ts.map +0 -1
  70. package/dist/components/ProfileShareButton/index.d.ts +0 -9
  71. package/dist/components/ProfileShareButton/index.d.ts.map +0 -1
  72. package/src/ProfileIcicleGraph/ActionButtons/SortBySelect.tsx +0 -81
  73. /package/dist/{ProfileIcicleGraph → components}/ActionButtons/GroupByDropdown.d.ts +0 -0
  74. /package/dist/{ProfileView → components}/FilterByFunctionButton.d.ts +0 -0
  75. /package/dist/{ProfileView → components}/FilterByFunctionButton.js +0 -0
  76. /package/dist/components/{ProfileShareButton → ShareButton}/ResultBox.d.ts +0 -0
  77. /package/dist/components/{ProfileShareButton → ShareButton}/ResultBox.js +0 -0
  78. /package/src/{ProfileView → components}/FilterByFunctionButton.tsx +0 -0
  79. /package/src/components/{ProfileShareButton → ShareButton}/ResultBox.tsx +0 -0
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.16.427](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.426...@parca/profile@0.16.427) (2024-08-19)
7
+
8
+ **Note:** Version bump only for package @parca/profile
9
+
10
+ ## [0.16.426](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.425...@parca/profile@0.16.426) (2024-08-19)
11
+
12
+ **Note:** Version bump only for package @parca/profile
13
+
6
14
  ## 0.16.425 (2024-08-12)
7
15
 
8
16
  **Note:** Version bump only for package @parca/profile
@@ -78,6 +78,6 @@ const ContextMenu = ({ menuId, table, total, totalUnfiltered, row, level, compar
78
78
  { id: 'Build Id', value: buildIdText },
79
79
  ];
80
80
  const nonEmptyValuesToCopy = valuesToCopy.filter(({ value }) => value !== '');
81
- return (_jsxs(Menu, { id: menuId, onVisibilityChange: trackVisibility, theme: isDarkMode ? 'dark' : '', children: [_jsxs(Item, { id: "view-source-file", onClick: handleViewSourceFile, disabled: enableSourcesView === false || !isSourceAvailable, children: [_jsx("div", { "data-tooltip-id": "view-source-file-help", "data-tooltip-content": "There is no source code uploaded for this build", children: _jsxs("div", { className: "flex w-full items-center gap-2", children: [_jsx(Icon, { icon: "wpf:view-file" }), _jsx("div", { children: "View source file" })] }) }), !isSourceAvailable ? _jsx(Tooltip, { id: "view-source-file-help" }) : null] }), _jsx(Item, { id: "reset-view", onClick: handleResetView, disabled: curPath.length === 0, children: _jsxs("div", { className: "flex w-full items-center gap-2", children: [_jsx(Icon, { icon: "system-uicons:reset" }), _jsx("div", { children: "Reset view" })] }) }), _jsxs(Item, { id: "hide-binary", onClick: () => hideBinary(getLastItem(mappingFile)), disabled: mappingFile === null || mappingFile === '', children: [_jsx("div", { "data-tooltip-id": "hide-binary-help", "data-tooltip-content": "Hide all frames for this binary", children: _jsxs("div", { className: "flex w-full items-center gap-2", children: [_jsx(Icon, { icon: "bx:bxs-hide" }), _jsxs("div", { children: ["Hide Binary ", mappingFile !== null && `(${getLastItem(mappingFile)})`] })] }) }), _jsx(Tooltip, { place: "left", id: "hide-binary-help" })] }), _jsx(Submenu, { label: _jsxs("div", { className: "flex w-full items-center gap-2", children: [_jsx(Icon, { icon: "ph:copy" }), _jsx("div", { children: "Copy" })] }), children: _jsx("div", { className: "max-h-[300px] overflow-scroll", children: nonEmptyValuesToCopy.map(({ id, value }) => (_jsx(Item, { id: id, onClick: () => handleCopyItem(value), className: "dark:bg-gray-800", children: _jsxs("div", { className: "flex flex-col dark:text-gray-300 hover:dark:text-gray-100", children: [_jsx("div", { className: "text-sm", children: id }), _jsx("div", { className: "text-xs", children: truncateString(value, 30) })] }) }, id))) }) }), _jsx(Separator, {}), _jsx(Item, { id: "dock-tooltip", onClick: handleDockTooltip, children: _jsxs("div", { className: "flex w-full items-center gap-2", children: [_jsx(Icon, { icon: "bx:dock-bottom" }), isGraphTooltipDocked ? 'Undock tooltip' : 'Dock tooltip'] }) })] }));
81
+ return (_jsxs(Menu, { id: menuId, onVisibilityChange: trackVisibility, theme: isDarkMode ? 'dark' : '', children: [_jsxs(Item, { id: "view-source-file", onClick: handleViewSourceFile, disabled: enableSourcesView === false || !isSourceAvailable, children: [_jsx("div", { "data-tooltip-id": "view-source-file-help", "data-tooltip-content": "There is no source code uploaded for this build", children: _jsxs("div", { className: "flex w-full items-center gap-2", children: [_jsx(Icon, { icon: "wpf:view-file" }), _jsx("div", { children: "View source file" })] }) }), !isSourceAvailable ? _jsx(Tooltip, { id: "view-source-file-help" }) : null] }), _jsx(Item, { id: "reset-view", onClick: handleResetView, disabled: curPath.length === 0, children: _jsxs("div", { className: "flex w-full items-center gap-2", children: [_jsx(Icon, { icon: "system-uicons:reset" }), _jsx("div", { children: "Reset graph" })] }) }), _jsxs(Item, { id: "hide-binary", onClick: () => hideBinary(getLastItem(mappingFile)), disabled: mappingFile === null || mappingFile === '', children: [_jsx("div", { "data-tooltip-id": "hide-binary-help", "data-tooltip-content": "Hide all frames for this binary", children: _jsxs("div", { className: "flex w-full items-center gap-2", children: [_jsx(Icon, { icon: "bx:bxs-hide" }), _jsxs("div", { children: ["Hide Binary ", mappingFile !== null && `(${getLastItem(mappingFile)})`] })] }) }), _jsx(Tooltip, { place: "left", id: "hide-binary-help" })] }), _jsx(Submenu, { label: _jsxs("div", { className: "flex w-full items-center gap-2", children: [_jsx(Icon, { icon: "ph:copy" }), _jsx("div", { children: "Copy" })] }), children: _jsx("div", { className: "max-h-[300px] overflow-scroll", children: nonEmptyValuesToCopy.map(({ id, value }) => (_jsx(Item, { id: id, onClick: () => handleCopyItem(value), className: "dark:bg-gray-800", children: _jsxs("div", { className: "flex flex-col dark:text-gray-300 hover:dark:text-gray-100", children: [_jsx("div", { className: "text-sm", children: id }), _jsx("div", { className: "text-xs", children: truncateString(value, 30) })] }) }, id))) }) }), _jsx(Separator, {}), _jsx(Item, { id: "dock-tooltip", onClick: handleDockTooltip, children: _jsxs("div", { className: "flex w-full items-center gap-2", children: [_jsx(Icon, { icon: "bx:dock-bottom" }), isGraphTooltipDocked ? 'Undock tooltip' : 'Dock tooltip'] }) })] }));
82
82
  };
83
83
  export default ContextMenu;
@@ -18,6 +18,6 @@ interface ProfileIcicleGraphProps {
18
18
  mappings?: string[];
19
19
  mappingsLoading?: boolean;
20
20
  }
21
- declare const ProfileIcicleGraph: ({ graph, arrow, total, filtered, curPath, setNewCurPath, profileType, loading, setActionButtons, error, width, isHalfScreen, mappings, }: ProfileIcicleGraphProps) => JSX.Element;
21
+ declare const ProfileIcicleGraph: ({ graph, arrow, total, filtered, curPath, setNewCurPath, profileType, loading, error, width, isHalfScreen, mappings, }: ProfileIcicleGraphProps) => JSX.Element;
22
22
  export default ProfileIcicleGraph;
23
23
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileIcicleGraph/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAkD,MAAM,OAAO,CAAC;AAKvE,OAAO,EAAC,UAAU,EAAE,eAAe,EAAC,MAAM,eAAe,CAAC;AAS1D,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAc1C,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;AAEpE,UAAU,uBAAuB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IACvB,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC;IACxD,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAyHD,QAAA,MAAM,kBAAkB,6IAcrB,uBAAuB,KAAG,GAAG,CAAC,OAkPhC,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileIcicleGraph/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAqC,MAAM,OAAO,CAAC;AAI1D,OAAO,EAAC,UAAU,EAAE,eAAe,EAAC,MAAM,eAAe,CAAC;AAE1D,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAY1C,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;AAEpE,UAAU,uBAAuB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IACvB,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC;IACxD,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAMD,QAAA,MAAM,kBAAkB,2HAarB,uBAAuB,KAAG,GAAG,CAAC,OAqKhC,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
@@ -11,16 +11,12 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } 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, useEffect, useMemo, useState } from 'react';
15
- import { Icon } from '@iconify/react';
14
+ import { useEffect, useMemo, useState } from 'react';
16
15
  import { AnimatePresence, motion } from 'framer-motion';
17
- import { Button, IcicleGraphSkeleton, IconButton, useParcaContext, useURLState, } from '@parca/components';
18
- import { USER_PREFERENCES, useUserPreference } from '@parca/hooks';
16
+ import { IcicleGraphSkeleton, useParcaContext, useURLState } from '@parca/components';
19
17
  import { capitalizeOnlyFirstLetter, divide, selectQueryParam } from '@parca/utilities';
20
18
  import { useProfileViewContext } from '../ProfileView/ProfileViewContext';
21
19
  import DiffLegend from '../components/DiffLegend';
22
- import GroupByDropdown from './ActionButtons/GroupByDropdown';
23
- import SortBySelect from './ActionButtons/SortBySelect';
24
20
  import { IcicleGraph } from './IcicleGraph';
25
21
  import { FIELD_FUNCTION_NAME, IcicleGraphArrow } from './IcicleGraphArrow';
26
22
  import ColorStackLegend from './IcicleGraphArrow/ColorStackLegend';
@@ -29,52 +25,17 @@ const numberFormatter = new Intl.NumberFormat('en-US');
29
25
  const ErrorContent = ({ errorMessage }) => {
30
26
  return _jsx("div", { className: "flex justify-center p-10", children: errorMessage });
31
27
  };
32
- const ShowHideLegendButton = ({ isHalfScreen }) => {
33
- const [colorStackLegend, setStoreColorStackLegend] = useURLState('color_stack_legend');
34
- const [binaryFrameFilter, setBinaryFrameFilter] = useURLState('binary_frame_filter');
35
- const { compareMode } = useProfileViewContext();
36
- const isColorStackLegendEnabled = colorStackLegend === 'true';
37
- const [colorProfileName] = useUserPreference(USER_PREFERENCES.FLAMEGRAPH_COLOR_PROFILE.key);
38
- const setColorStackLegend = useCallback((value) => {
39
- setStoreColorStackLegend(value);
40
- }, [setStoreColorStackLegend]);
41
- const resetLegend = () => {
42
- setBinaryFrameFilter([]);
43
- };
44
- return (_jsx(_Fragment, { children: colorProfileName === 'default' || compareMode ? null : (_jsx(_Fragment, { children: isHalfScreen ? (_jsxs(_Fragment, { children: [_jsx(IconButton, { className: "rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 items-center flex border border-gray-200 dark:border-gray-600 dark:text-white justify-center !py-2 !px-3 cursor-pointer min-h-[38px]", icon: isColorStackLegendEnabled ? 'ph:eye-closed' : 'ph:eye', toolTipText: isColorStackLegendEnabled ? 'Hide legend' : 'Show legend', onClick: () => setColorStackLegend(isColorStackLegendEnabled ? 'false' : 'true'), id: "h-show-legend-button" }), binaryFrameFilter !== undefined && binaryFrameFilter.length > 0 && (_jsx(IconButton, { className: "rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 items-center flex border border-gray-200 dark:border-gray-600 dark:text-white justify-center !py-2 !px-3 cursor-pointer min-h-[38px]", icon: "system-uicons:reset", toolTipText: "Reset the legend selection", onClick: () => resetLegend(), id: "h-reset-legend-button" }))] })) : (_jsxs(_Fragment, { children: [_jsxs(Button, { className: "gap-2 w-max", variant: "neutral", onClick: () => setColorStackLegend(isColorStackLegendEnabled ? 'false' : 'true'), id: "h-show-legend-button", children: [isColorStackLegendEnabled ? 'Hide legend' : 'Show legend', _jsx(Icon, { icon: isColorStackLegendEnabled ? 'ph:eye-closed' : 'ph:eye', width: 20 })] }), binaryFrameFilter !== undefined && binaryFrameFilter.length > 0 && (_jsxs(Button, { className: "gap-2 w-max", variant: "neutral", onClick: () => resetLegend(), id: "h-reset-legend-button", children: ["Reset Legend", _jsx(Icon, { icon: "system-uicons:reset", width: 20 })] }))] })) })) }));
45
- };
46
- const GroupAndSortActionButtons = () => {
47
- const [storeSortBy, setStoreSortBy] = useURLState('sort_by', {
48
- defaultValue: FIELD_FUNCTION_NAME,
49
- });
50
- const { compareMode } = useProfileViewContext();
51
- const [groupBy, setStoreGroupBy] = useURLState('group_by', {
52
- defaultValue: [FIELD_FUNCTION_NAME],
53
- alwaysReturnArray: true,
54
- });
55
- const setGroupBy = useCallback((keys) => {
56
- setStoreGroupBy(keys);
57
- }, [setStoreGroupBy]);
58
- const toggleGroupBy = useCallback((key) => {
59
- groupBy.includes(key)
60
- ? setGroupBy(groupBy.filter(v => v !== key)) // remove
61
- : setGroupBy([...groupBy, key]); // add
62
- }, [groupBy, setGroupBy]);
63
- return (_jsxs(_Fragment, { children: [_jsx(GroupByDropdown, { groupBy: groupBy, toggleGroupBy: toggleGroupBy }), _jsx(SortBySelect, { compareMode: compareMode, sortBy: storeSortBy, setSortBy: setStoreSortBy })] }));
64
- };
65
- const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ graph, arrow, total, filtered, curPath, setNewCurPath, profileType, loading, setActionButtons, error, width, isHalfScreen, mappings, }) {
28
+ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ graph, arrow, total, filtered, curPath, setNewCurPath, profileType, loading, error, width, isHalfScreen, mappings, }) {
66
29
  const { onError, authenticationErrorMessage, isDarkMode } = useParcaContext();
67
30
  const { compareMode } = useProfileViewContext();
68
31
  const [isLoading, setIsLoading] = useState(true);
69
32
  const isColorStackLegendEnabled = selectQueryParam('color_stack_legend') === 'true';
70
33
  const mappingsList = useMappingList(mappings);
71
34
  const [storeSortBy = FIELD_FUNCTION_NAME] = useURLState('sort_by');
72
- const [invertStack = '', setInvertStack] = useURLState('invert_call_stack');
73
- const isInvert = invertStack === 'true';
74
35
  // By default, we want delta profiles (CPU) to be relatively compared.
75
36
  // For non-delta profiles, like goroutines or memory, we want the profiles to be compared absolutely.
76
37
  const compareAbsoluteDefault = profileType?.delta === false ? 'true' : 'false';
77
- const [compareAbsolute = compareAbsoluteDefault, setCompareAbsolute] = useURLState('compare_absolute');
38
+ const [compareAbsolute = compareAbsoluteDefault] = useURLState('compare_absolute');
78
39
  const isCompareAbsolute = compareAbsolute === 'true';
79
40
  const [totalFormatted, totalUnfilteredFormatted, isTrimmed, trimmedFormatted, trimmedPercentage, isFiltered, filteredPercentage,] = useMemo(() => {
80
41
  if (graph === undefined && arrow === undefined) {
@@ -94,22 +55,6 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ graph, arrow, to
94
55
  numberFormatter.format(divide(total * 100n, totalUnfilteredDivisor)),
95
56
  ];
96
57
  }, [graph, arrow, filtered, total]);
97
- useEffect(() => {
98
- setActionButtons?.(_jsx("div", { className: "flex w-full justify-end gap-2 pb-2", children: _jsxs("div", { className: "ml-2 flex w-full flex-col items-start justify-between gap-2 md:flex-row md:items-end", children: [_jsx(GroupAndSortActionButtons, {}), isHalfScreen ? (_jsx(IconButton, { icon: isInvert ? 'ph:sort-ascending' : 'ph:sort-descending', toolTipText: isInvert ? 'Original Call Stack' : 'Invert Call Stack', onClick: () => setInvertStack(isInvert ? '' : 'true'), className: "rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 items-center flex border border-gray-200 dark:border-gray-600 dark:text-white justify-center py-2 px-3 cursor-pointer min-h-[38px]" })) : (_jsxs(Button, { variant: "neutral", className: "gap-2 w-max", onClick: () => setInvertStack(isInvert ? '' : 'true'), children: [isInvert ? 'Original Call Stack' : 'Invert Call Stack', _jsx(Icon, { icon: isInvert ? 'ph:sort-ascending' : 'ph:sort-descending', width: 20 })] })), _jsx(ShowHideLegendButton, { isHalfScreen: isHalfScreen }), compareMode && (_jsxs(Button, { variant: "neutral", className: "gap-2 w-max", onClick: () => setCompareAbsolute(isCompareAbsolute ? '' : 'true'), children: [isCompareAbsolute ? 'Compare Relative' : 'Compare Absolute', _jsx(Icon, { icon: isCompareAbsolute ? 'fluent-mdl2:compare' : 'fluent-mdl2:compare-uneven', width: 20 })] })), isHalfScreen ? (_jsx(IconButton, { icon: "system-uicons:reset", disabled: curPath.length === 0, toolTipText: "Reset View", onClick: () => setNewCurPath([]), className: "rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 items-center flex border border-gray-200 dark:border-gray-600 dark:text-white justify-center py-2 px-3 cursor-pointer min-h-[38px]" })) : (_jsxs(Button, { variant: "neutral", className: "gap-2 w-max", onClick: () => setNewCurPath([]), disabled: curPath.length === 0, children: ["Reset View", _jsx(Icon, { icon: "system-uicons:reset", width: 20 })] }))] }) }));
99
- }, [
100
- isInvert,
101
- setInvertStack,
102
- arrow,
103
- curPath,
104
- setNewCurPath,
105
- setActionButtons,
106
- loading,
107
- isHalfScreen,
108
- isLoading,
109
- compareMode,
110
- isCompareAbsolute,
111
- setCompareAbsolute,
112
- ]);
113
58
  const loadingState = !loading && (arrow !== undefined || graph !== undefined) && mappings !== undefined;
114
59
  useEffect(() => {
115
60
  if (loadingState) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/index.tsx"],"names":[],"mappings":"AAgBA,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAGlD,OAAO,EAAQ,oBAAoB,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAa9E,OAAO,EAAC,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAyB,gBAAgB,EAAC,MAAM,IAAI,CAAC;AAS5D,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,oBAAoB;IAC5B,WAAW,EAAE,kBAAkB,CAAC;IAChC,cAAc,EAAE,cAAc,CAAC;IAC/B,aAAa,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClD,WAAW,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC7C,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,KAAK,CAAC,EAAE,QAAQ,CAAC;CAClB;AAED,eAAO,MAAM,eAAe,WAAY,kBAAkB,KAAG,mBAkB5D,CAAC;AAEF,QAAA,MAAM,eAAe,6IAUlB,oBAAoB,KAAG,GAAG,CAAC,OAoX7B,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/index.tsx"],"names":[],"mappings":"AAgBA,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAGlD,OAAO,EAAQ,oBAAoB,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAa9E,OAAO,EAAC,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAyB,gBAAgB,EAAC,MAAM,IAAI,CAAC;AAU5D,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,oBAAoB;IAC5B,WAAW,EAAE,kBAAkB,CAAC;IAChC,cAAc,EAAE,cAAc,CAAC;IAC/B,aAAa,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClD,WAAW,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC7C,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,KAAK,CAAC,EAAE,QAAQ,CAAC;CAClB;AAED,eAAO,MAAM,eAAe,WAAY,kBAAkB,KAAG,mBAkB5D,CAAC;AAEF,QAAA,MAAM,eAAe,6IAUlB,oBAAoB,KAAG,GAAG,CAAC,OA6Y7B,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -23,6 +23,7 @@ import { useMetricsGraphDimensions } from '../MetricsGraph/useMetricsGraphDimens
23
23
  import ProfileMetricsGraph, { ProfileMetricsEmptyState } from '../ProfileMetricsGraph';
24
24
  import ProfileTypeSelector from '../ProfileTypeSelector/index';
25
25
  import SimpleMatchers from '../SimpleMatchers';
26
+ import ViewMatchers from '../ViewMatchers';
26
27
  import { useDefaultSumBy, useSumBySelection } from '../useSumBy';
27
28
  import { useAutoQuerySelector } from './useAutoQuerySelector';
28
29
  export const useProfileTypes = (client) => {
@@ -172,13 +173,17 @@ const ProfileSelector = ({ queryClient, querySelection, selectProfile, selectQue
172
173
  queryExpressionString === '' ||
173
174
  queryExpressionString === '{}';
174
175
  const queryBrowserRef = useRef(null);
175
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "mb-2 flex gap-2", children: [_jsxs("div", { className: "flex w-full flex-wrap content-start items-center gap-2", children: [_jsxs("div", { className: "pb-6", children: [_jsx("label", { className: "text-xs", children: "Profile type" }), _jsx(ProfileTypeSelector, { profileTypesData: profileTypesData, loading: profileTypesLoading, selectedKey: selectedProfileName, onSelection: setProfileName, error: error, disabled: viewComponent?.disableProfileTypesDropdown })] }), _jsxs("div", { className: "w-full flex-1 flex flex-col pb-6 gap-1", ref: queryBrowserRef, children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("label", { className: "text-xs", children: "Query" }), _jsxs(Switch, { checked: advancedModeForQueryBrowser, onChange: () => {
176
- setAdvancedModeForQueryBrowser(!advancedModeForQueryBrowser);
177
- setQueryBrowserMode(advancedModeForQueryBrowser ? 'simple' : 'advanced');
178
- }, className: `${advancedModeForQueryBrowser ? 'bg-indigo-600' : 'bg-gray-400 dark:bg-gray-900'}
176
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "mb-2 flex gap-2", children: [_jsxs("div", { className: "flex w-full flex-wrap content-start items-center gap-2", children: [_jsxs("div", { className: "pb-6", children: [_jsx("label", { className: "text-xs", children: "Profile type" }), _jsx(ProfileTypeSelector, { profileTypesData: profileTypesData, loading: profileTypesLoading, selectedKey: selectedProfileName, onSelection: setProfileName, error: error, disabled: viewComponent?.disableProfileTypesDropdown })] }), _jsxs("div", { className: "w-full flex-1 flex flex-col pb-6 gap-1", ref: queryBrowserRef, children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("label", { className: "text-xs", children: "Query" }), viewComponent?.disableExplorativeQuerying === true ? null : (_jsxs(_Fragment, { children: [_jsxs(Switch, { checked: advancedModeForQueryBrowser, onChange: () => {
177
+ setAdvancedModeForQueryBrowser(!advancedModeForQueryBrowser);
178
+ setQueryBrowserMode(advancedModeForQueryBrowser ? 'simple' : 'advanced');
179
+ }, className: `${advancedModeForQueryBrowser
180
+ ? 'bg-indigo-600'
181
+ : 'bg-gray-400 dark:bg-gray-900'}
179
182
  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'}
180
- 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" })] }), (query.matchers.length > 0 || query.inputMatcherString.length > 0) &&
181
- viewComponent !== undefined && _jsx("div", { children: viewComponent?.createViewComponent })] }), advancedModeForQueryBrowser ? (_jsx(MatchersInput, { queryClient: queryClient, setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query, profileType: selectedProfileName })) : (_jsx(SimpleMatchers, { queryClient: queryClient, setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query, profileType: selectedProfileName, queryBrowserRef: queryBrowserRef }))] }), _jsxs("div", { className: "pb-6", 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, { 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: selectedOptions => {
183
+ 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" })] }))] }), (query.matchers.length > 0 || query.inputMatcherString.length > 0) &&
184
+ viewComponent !== undefined && _jsx("div", { children: viewComponent?.createViewComponent })] }), viewComponent?.disableExplorativeQuerying === true &&
185
+ viewComponent?.labelnames !== undefined &&
186
+ viewComponent?.labelnames.length >= 1 ? (_jsx(_Fragment, { children: _jsx(ViewMatchers, { labelNames: viewComponent.labelnames, setMatchersString: setMatchersString, profileType: selectedProfileName, runQuery: setQueryExpression, currentQuery: query, queryClient: queryClient }) })) : (_jsx(_Fragment, { children: advancedModeForQueryBrowser ? (_jsx(MatchersInput, { queryClient: queryClient, setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query, profileType: selectedProfileName })) : (_jsx(SimpleMatchers, { queryClient: queryClient, setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query, profileType: selectedProfileName, queryBrowserRef: queryBrowserRef })) }))] }), _jsxs("div", { className: "pb-6", 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, { 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: selectedOptions => {
182
187
  setUserSumBySelection(selectedOptions.map(option => option.value));
183
188
  }, placeholder: "Labels...", styles: {
184
189
  indicatorSeparator: () => ({ display: 'none' }),
@@ -1 +1 @@
1
- {"version":3,"file":"VisualizationPanel.d.ts","sourceRoot":"","sources":["../../src/ProfileView/VisualizationPanel.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAiB,MAAM,OAAO,CAAC;AAItC,OAAO,KAAK,EAAC,gCAAgC,EAAC,MAAM,qBAAqB,CAAC;AAO1E,UAAU,KAAK;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gBAAgB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,eAAe,EAAE,gCAAgC,GAAG,IAAI,GAAG,SAAS,CAAC;IACrE,sBAAsB,EAAE,CAAC,KAAK,EAAE;QAC9B,IAAI,EAAE,MAAM,CAAC;QACb,YAAY,EAAE,OAAO,CAAC;QACtB,gBAAgB,EAAE,CAAC,aAAa,EAAE,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC;KACxD,KAAK,GAAG,CAAC,OAAO,CAAC;CACnB;AAED,eAAO,MAAM,kBAAkB,mCAyD7B,CAAC"}
1
+ {"version":3,"file":"VisualizationPanel.d.ts","sourceRoot":"","sources":["../../src/ProfileView/VisualizationPanel.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAiB,MAAM,OAAO,CAAC;AAItC,OAAO,KAAK,EAAC,gCAAgC,EAAC,MAAM,qBAAqB,CAAC;AAK1E,UAAU,KAAK;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gBAAgB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,eAAe,EAAE,gCAAgC,GAAG,IAAI,GAAG,SAAS,CAAC;IACrE,sBAAsB,EAAE,CAAC,KAAK,EAAE;QAC9B,IAAI,EAAE,MAAM,CAAC;QACb,YAAY,EAAE,OAAO,CAAC;QACtB,gBAAgB,EAAE,CAAC,aAAa,EAAE,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC;KACxD,KAAK,GAAG,CAAC,OAAO,CAAC;CACnB;AAED,eAAO,MAAM,kBAAkB,mCAsD7B,CAAC"}
@@ -16,11 +16,10 @@ import { Icon } from '@iconify/react';
16
16
  import cx from 'classnames';
17
17
  import { IconButton, useParcaContext } from '@parca/components';
18
18
  import { CloseIcon } from '@parca/icons';
19
- import ViewSelector from './ViewSelector';
20
- export const VisualizationPanel = React.memo(function VisualizationPanel({ dashboardItem, index, isMultiPanelView, handleClosePanel, dragHandleProps, getDashboardItemByType, }) {
19
+ export const VisualizationPanel = React.memo(function VisualizationPanel({ dashboardItem, isMultiPanelView, handleClosePanel, dragHandleProps, getDashboardItemByType, }) {
21
20
  const [actionButtons, setActionButtons] = useState(_jsx(_Fragment, {}));
22
21
  const { flamegraphHint } = useParcaContext();
23
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex w-full items-center justify-end gap-2 pb-2 min-h-[78px]", children: [_jsxs("div", { className: cx('flex w-full justify-between flex-col-reverse md:flex-row', isMultiPanelView && dashboardItem === 'icicle' ? 'items-end gap-x-2' : 'items-end'), children: [_jsxs("div", { className: "flex items-center", children: [_jsx("div", { className: cx(isMultiPanelView ? '' : 'hidden', 'flex items-center'), ...dragHandleProps, children: _jsx(Icon, { className: "text-xl", icon: "material-symbols:drag-indicator" }) }), _jsx("div", { className: "flex gap-2", children: actionButtons })] }), _jsxs("div", { className: cx('flex flex-row items-center gap-4', isMultiPanelView && dashboardItem === 'icicle' && 'pb-[10px]'), children: [_jsx(ViewSelector, { id: "h-switch-viz", defaultValue: dashboardItem, position: index }), dashboardItem === 'icicle' && flamegraphHint != null ? (_jsx("div", { className: "px-2", children: flamegraphHint })) : null] })] }), isMultiPanelView && (_jsx(IconButton, { className: "py-0", onClick: () => handleClosePanel(dashboardItem), icon: _jsx(CloseIcon, {}) }))] }), getDashboardItemByType({
22
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex w-full items-center justify-end gap-2 pb-2", children: [_jsxs("div", { className: cx('flex w-full justify-between flex-col-reverse md:flex-row', isMultiPanelView && dashboardItem === 'icicle' ? 'items-end gap-x-2' : 'items-end'), children: [_jsxs("div", { className: "flex items-center", children: [_jsx("div", { className: cx(isMultiPanelView ? '' : 'hidden', 'flex items-center'), ...dragHandleProps, children: _jsx(Icon, { className: "text-xl", icon: "material-symbols:drag-indicator" }) }), _jsx("div", { className: "flex gap-2", children: actionButtons })] }), _jsx("div", { className: cx('flex flex-row items-center gap-4', isMultiPanelView && dashboardItem === 'icicle' && 'pb-[10px]'), children: dashboardItem === 'icicle' && flamegraphHint != null ? (_jsx("div", { className: "px-2", children: flamegraphHint })) : null })] }), isMultiPanelView && (_jsx(IconButton, { className: "py-0", onClick: () => handleClosePanel(dashboardItem), icon: _jsx(CloseIcon, {}) }))] }), getDashboardItemByType({
24
23
  type: dashboardItem,
25
24
  isHalfScreen: isMultiPanelView,
26
25
  setActionButtons,
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileView/index.tsx"],"names":[],"mappings":"AA2BA,OAAO,EACL,SAAS,IAAI,aAAa,EAC1B,UAAU,EACV,eAAe,EACf,kBAAkB,EAClB,MAAM,EACN,UAAU,EACV,GAAG,EACJ,MAAM,eAAe,CAAC;AAgBvB,OAAO,EAAC,aAAa,EAAC,MAAM,kBAAkB,CAAC;AAS/C,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,UAAU,aAAa;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,GAAG,CAAC;CACb;AAED,UAAU,UAAU;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,GAAG,CAAC;CACb;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,cAAc,CAAC;IAC/B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAWD,eAAO,MAAM,WAAW,0JAYrB,gBAAgB,KAAG,GAAG,CAAC,OAoUzB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileView/index.tsx"],"names":[],"mappings":"AA0BA,OAAO,EACL,SAAS,IAAI,aAAa,EAC1B,UAAU,EACV,eAAe,EACf,kBAAkB,EAClB,MAAM,EACN,UAAU,EACV,GAAG,EACJ,MAAM,eAAe,CAAC;AAUvB,OAAO,EAAC,aAAa,EAAC,MAAM,kBAAkB,CAAC;AAO/C,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,UAAU,aAAa;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,GAAG,CAAC;CACb;AAED,UAAU,UAAU;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,GAAG,CAAC;CACb;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,cAAc,CAAC;IAC/B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAWD,eAAO,MAAM,WAAW,0JAYrB,gBAAgB,KAAG,GAAG,CAAC,OAmUzB,CAAC"}
@@ -12,25 +12,23 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
12
12
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
  // See the License for the specific language governing permissions and
14
14
  // limitations under the License.
15
- import { Profiler, useEffect, useState } from 'react';
16
- import { Icon } from '@iconify/react';
15
+ import { Profiler, useCallback, useEffect, useState } from 'react';
17
16
  import cx from 'classnames';
18
17
  import { scaleLinear } from 'd3';
19
18
  import graphviz from 'graphviz-wasm';
20
19
  import { DragDropContext, Draggable, Droppable, } from 'react-beautiful-dnd';
21
- import { Button, ConditionalWrapper, KeyDownProvider, UserPreferences, useParcaContext, useURLState, } from '@parca/components';
20
+ import { ConditionalWrapper, KeyDownProvider, useParcaContext, useURLState } from '@parca/components';
22
21
  import { useContainerDimensions } from '@parca/hooks';
23
22
  import { selectDarkMode, useAppSelector } from '@parca/store';
24
23
  import { getNewSpanColor, selectQueryParam } from '@parca/utilities';
25
24
  import { Callgraph } from '../';
26
25
  import { jsonToDot } from '../Callgraph/utils';
27
26
  import ProfileIcicleGraph from '../ProfileIcicleGraph';
27
+ import { FIELD_FUNCTION_NAME } from '../ProfileIcicleGraph/IcicleGraphArrow';
28
28
  import { SourceView } from '../SourceView';
29
29
  import { Table } from '../Table';
30
- import ProfileShareButton from '../components/ProfileShareButton';
31
- import FilterByFunctionButton from './FilterByFunctionButton';
30
+ import VisualisationToolbar from '../components/VisualisationToolbar';
32
31
  import { ProfileViewContextProvider } from './ProfileViewContext';
33
- import ViewSelector from './ViewSelector';
34
32
  import { VisualizationPanel } from './VisualizationPanel';
35
33
  function arrayEquals(a, b) {
36
34
  return (Array.isArray(a) &&
@@ -50,7 +48,7 @@ export const ProfileView = ({ total, filtered, flamegraphData, topTableData, cal
50
48
  const [currentSearchString, setSearchString] = useURLState('search_string');
51
49
  const isDarkMode = useAppSelector(selectDarkMode);
52
50
  const isMultiPanelView = dashboardItems.length > 1;
53
- const { perf, profileViewExternalMainActions, profileViewExternalSubActions } = useParcaContext();
51
+ const { perf, profileViewExternalMainActions } = useParcaContext();
54
52
  useEffect(() => {
55
53
  // Reset the current path when the profile source changes
56
54
  setCurPath([]);
@@ -143,17 +141,26 @@ export const ProfileView = ({ total, filtered, flamegraphData, topTableData, cal
143
141
  const headerParts = profileSourceString?.split('"') ?? [];
144
142
  const compareMode = compare === true ||
145
143
  (selectQueryParam('compare_a') === 'true' && selectQueryParam('compare_b') === 'true');
146
- return (_jsx(KeyDownProvider, { children: _jsxs(ProfileViewContextProvider, { value: { profileSource, compareMode }, children: [_jsxs("div", { className: cx('mb-4 flex w-full', hasProfileSource || profileViewExternalMainActions != null
144
+ const [groupBy, setStoreGroupBy] = useURLState('group_by', {
145
+ defaultValue: [FIELD_FUNCTION_NAME],
146
+ alwaysReturnArray: true,
147
+ });
148
+ const setGroupBy = useCallback((keys) => {
149
+ setStoreGroupBy(keys);
150
+ }, [setStoreGroupBy]);
151
+ const toggleGroupBy = useCallback((key) => {
152
+ groupBy.includes(key)
153
+ ? setGroupBy(groupBy.filter(v => v !== key)) // remove
154
+ : setGroupBy([...groupBy, key]); // add
155
+ }, [groupBy, setGroupBy]);
156
+ return (_jsx(KeyDownProvider, { children: _jsxs(ProfileViewContextProvider, { value: { profileSource, compareMode }, children: [_jsx("div", { className: cx('mb-4 flex w-full', hasProfileSource || profileViewExternalMainActions != null
147
157
  ? 'justify-between'
148
158
  : 'justify-end', {
149
159
  'items-end': !hasProfileSource && profileViewExternalMainActions != null,
150
160
  'items-center': hasProfileSource,
151
- }), children: [_jsxs("div", { children: [hasProfileSource && (_jsxs("div", { className: "max-w-[300px]", children: [_jsx("div", { className: "text-sm font-medium capitalize", children: headerParts.length > 0 ? headerParts[0].replace(/"/g, '') : '' }), _jsx("div", { className: "text-xs", children: headerParts.length > 1
152
- ? headerParts[headerParts.length - 1].replace(/"/g, '')
153
- : '' })] })), profileViewExternalMainActions != null ? profileViewExternalMainActions : null] }), _jsxs("div", { className: "lg:flex flex-wrap items-center gap-2 md:justify-end hidden", children: [_jsx(FilterByFunctionButton, {}), profileViewExternalSubActions != null ? profileViewExternalSubActions : null, _jsx(UserPreferences, { customButton: _jsxs(Button, { className: "gap-2", variant: "neutral", id: "h-viz-preferences", children: ["Preferences", _jsx(Icon, { icon: "pajamas:preferences", width: 20 })] }) }), profileSource !== undefined && queryClient !== undefined ? (_jsx(ProfileShareButton, { queryRequest: profileSource.QueryRequest(), queryClient: queryClient })) : null, _jsxs(Button, { className: "gap-2", variant: "neutral", onClick: e => {
154
- e.preventDefault();
155
- onDownloadPProf();
156
- }, disabled: pprofDownloading, id: "h-download-pprof", children: [pprofDownloading != null && pprofDownloading ? 'Downloading...' : 'Download pprof', _jsx(Icon, { icon: "material-symbols:download", width: 20 })] }), _jsx(ViewSelector, { defaultValue: "", position: -1, placeholderText: "Add panel", icon: _jsx(Icon, { icon: "material-symbols:add", width: 20 }), addView: true, disabled: isMultiPanelView || dashboardItems.length < 1, id: "h-add-panel" })] })] }), _jsx("div", { className: "w-full", ref: ref, children: _jsx(DragDropContext, { onDragEnd: onDragEnd, children: _jsx(Droppable, { droppableId: "droppable", direction: "horizontal", children: provided => (_jsx("div", { ref: provided.innerRef, className: cx('grid w-full gap-2', isMultiPanelView ? 'grid-cols-2' : 'grid-cols-1'), ...provided.droppableProps, children: dashboardItems.map((dashboardItem, index) => {
161
+ }), children: _jsxs("div", { children: [hasProfileSource && (_jsxs("div", { className: "flex items-center gap-1", children: [_jsx("div", { className: "text-sm font-medium capitalize", children: headerParts.length > 0 ? headerParts[0].replace(/"/g, '') : '' }), _jsx("div", { className: "text-xs", children: headerParts.length > 1
162
+ ? headerParts[headerParts.length - 1].replace(/"/g, '')
163
+ : '' })] })), profileViewExternalMainActions != null ? profileViewExternalMainActions : null] }) }), _jsx(VisualisationToolbar, { groupBy: groupBy, toggleGroupBy: toggleGroupBy, hasProfileSource: hasProfileSource, pprofdownloading: pprofDownloading, profileSource: profileSource, queryClient: queryClient, onDownloadPProf: onDownloadPProf, isMultiPanelView: isMultiPanelView, dashboardItems: dashboardItems, curPath: curPath, setNewCurPath: setNewCurPath, profileType: profileSource?.ProfileType(), total: total, filtered: filtered, currentSearchString: currentSearchString, setSearchString: setSearchString }), _jsx("div", { className: "w-full", ref: ref, children: _jsx(DragDropContext, { onDragEnd: onDragEnd, children: _jsx(Droppable, { droppableId: "droppable", direction: "horizontal", children: provided => (_jsx("div", { ref: provided.innerRef, className: cx('grid w-full gap-2', isMultiPanelView ? 'grid-cols-2' : 'grid-cols-1'), ...provided.droppableProps, children: dashboardItems.map((dashboardItem, index) => {
157
164
  return (_jsx(Draggable, { draggableId: dashboardItem, index: index, isDragDisabled: !isMultiPanelView, children: (provided, snapshot) => (_createElement("div", { ref: provided.innerRef, ...provided.draggableProps, key: dashboardItem, className: cx('w-full rounded p-2 shadow dark:border dark:border-gray-700 dark:bg-gray-700 min-h-96', snapshot.isDragging
158
165
  ? 'bg-gray-200 dark:bg-gray-500'
159
166
  : 'bg-white dark:bg-gray-700') },
@@ -15,7 +15,7 @@ import { Fragment } from 'react';
15
15
  import { Menu, Transition } from '@headlessui/react';
16
16
  import { Icon } from '@iconify/react';
17
17
  const ColumnsVisibility = ({ columns, visibility, setVisibility, }) => {
18
- return (_jsx("div", { children: _jsxs(Menu, { as: "div", className: "relative text-left", children: [_jsx("div", { children: _jsxs(Menu.Button, { className: "relative w-full cursor-default rounded-md border bg-white py-2 pl-3 pr-10 text-left text-sm shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 dark:border-gray-600 dark:bg-gray-900 sm:text-sm", children: [_jsx("span", { className: "block overflow-x-hidden text-ellipsis", children: "Columns" }), _jsx("span", { className: "pointer-events-none absolute inset-y-0 right-0 ml-3 flex items-center pr-2 text-gray-400", children: _jsx(Icon, { icon: "heroicons:chevron-down-20-solid", "aria-hidden": "true" }) })] }) }), _jsx(Transition, { as: Fragment, leave: "transition ease-in duration-100", leaveFrom: "opacity-100", leaveTo: "opacity-0", children: _jsx(Menu.Items, { 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: _jsx("div", { className: "space-y-5", children: columns.map(col => (_jsxs("div", { className: "relative flex items-start", children: [_jsx("div", { className: "flex h-6 items-center", children: _jsx("input", { id: col.id, name: col.id, type: "checkbox", className: "h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-600", checked: visibility[col.id ?? ''] ?? false, onChange: () => {
18
+ return (_jsx("div", { children: _jsxs(Menu, { as: "div", className: "relative text-left", children: [_jsx("div", { children: _jsxs(Menu.Button, { className: "relative w-full cursor-default rounded-md border bg-white py-2 pl-3 pr-10 text-left text-sm shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 dark:border-gray-600 dark:bg-gray-900 sm:text-sm", children: [_jsx("span", { className: "block overflow-x-hidden text-ellipsis", children: "Multiple" }), _jsx("span", { className: "pointer-events-none absolute inset-y-0 right-0 ml-3 flex items-center pr-2 text-gray-400", children: _jsx(Icon, { icon: "heroicons:chevron-down-20-solid", "aria-hidden": "true" }) })] }) }), _jsx(Transition, { as: Fragment, leave: "transition ease-in duration-100", leaveFrom: "opacity-100", leaveTo: "opacity-0", children: _jsx(Menu.Items, { 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: _jsx("div", { className: "space-y-5", children: columns.map(col => (_jsxs("div", { className: "relative flex items-start", children: [_jsx("div", { className: "flex h-6 items-center", children: _jsx("input", { id: col.id, name: col.id, type: "checkbox", className: "h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-600", checked: visibility[col.id ?? ''] ?? false, onChange: () => {
19
19
  setVisibility(col.id ?? '', !visibility[col.id ?? '']);
20
20
  } }) }), _jsx("div", { className: "ml-3 text-sm leading-6", children: _jsx("label", { htmlFor: col.id, className: "font-medium text-gray-900 dark:text-gray-200", children: col.header }) })] }, col.id))) }) }) }) }) })] }) }));
21
21
  };
@@ -24,6 +24,7 @@ interface DummyRow {
24
24
  isBottomSubRow?: boolean;
25
25
  }
26
26
  export type Row = DataRow | DummyRow;
27
+ export declare const isDummyRow: (row: Row) => row is DummyRow;
27
28
  interface TableProps {
28
29
  data?: Uint8Array;
29
30
  total: bigint;
@@ -36,7 +37,12 @@ interface TableProps {
36
37
  isHalfScreen: boolean;
37
38
  unit?: string;
38
39
  }
40
+ export type ColumnName = 'flat' | 'flatPercentage' | 'flatDiff' | 'flatDiffPercentage' | 'cumulative' | 'cumulativePercentage' | 'cumulativeDiff' | 'cumulativeDiffPercentage' | 'name' | 'functionSystemName' | 'functionFileName' | 'mappingFile';
41
+ export declare const getPercentageString: (value: bigint | number, total: bigint | number) => string;
42
+ export declare const getRatioString: (value: bigint | number, total: bigint, filtered: bigint) => string;
43
+ export declare const possibleColumns: string[];
39
44
  export declare const Table: React.NamedExoticComponent<TableProps>;
45
+ export declare const addPlusSign: (num: string) => string;
40
46
  export declare const RowName: (mappingFileColumn: Vector | null, locationAddressColumn: Vector | null, functionNameColumn: Vector | null, row: number) => string;
41
47
  export default Table;
42
48
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Table/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAA0D,MAAM,OAAO,CAAC;AAU/E,OAAO,EAAQ,MAAM,EAAgC,MAAM,cAAc,CAAC;AAY1E,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAoB1C,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,UAAU,QAAQ;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,MAAM,GAAG,GAAG,OAAO,GAAG,QAAQ,CAAC;AAQrC,UAAU,UAAU;IAClB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,eAAe,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC;IACxD,YAAY,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AA4LD,eAAO,MAAM,KAAK,wCA0ahB,CAAC;AAUH,eAAO,MAAM,OAAO,sBACC,MAAM,GAAG,IAAI,yBACT,MAAM,GAAG,IAAI,sBAChB,MAAM,GAAG,IAAI,OAC5B,MAAM,KACV,MAoBF,CAAC;AAgDF,eAAe,KAAK,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Table/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAA0D,MAAM,OAAO,CAAC;AAU/E,OAAO,EAAQ,MAAM,EAAgC,MAAM,cAAc,CAAC;AAW1E,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAmB1C,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,UAAU,QAAQ;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,MAAM,GAAG,GAAG,OAAO,GAAG,QAAQ,CAAC;AAErC,eAAO,MAAM,UAAU,QAAS,GAAG,KAAG,GAAG,IAAI,QAE5C,CAAC;AAIF,UAAU,UAAU;IAClB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,eAAe,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC;IACxD,YAAY,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,UAAU,GAClB,MAAM,GACN,gBAAgB,GAChB,UAAU,GACV,oBAAoB,GACpB,YAAY,GACZ,sBAAsB,GACtB,gBAAgB,GAChB,0BAA0B,GAC1B,MAAM,GACN,oBAAoB,GACpB,kBAAkB,GAClB,aAAa,CAAC;AA4LlB,eAAO,MAAM,mBAAmB,UAAW,MAAM,GAAG,MAAM,SAAS,MAAM,GAAG,MAAM,KAAG,MAOpF,CAAC;AAEF,eAAO,MAAM,cAAc,UAAW,MAAM,GAAG,MAAM,SAAS,MAAM,YAAY,MAAM,KAAG,MAMxF,CAAC;AAEF,eAAO,MAAM,eAAe,UAa3B,CAAC;AAEF,eAAO,MAAM,KAAK,wCAoZhB,CAAC;AAEH,eAAO,MAAM,WAAW,QAAS,MAAM,KAAG,MAMzC,CAAC;AAEF,eAAO,MAAM,OAAO,sBACC,MAAM,GAAG,IAAI,yBACT,MAAM,GAAG,IAAI,sBAChB,MAAM,GAAG,IAAI,OAC5B,MAAM,KACV,MAoBF,CAAC;AAgDF,eAAe,KAAK,CAAC"}
@@ -17,11 +17,10 @@ import { createColumnHelper, } from '@tanstack/table-core';
17
17
  import { tableFromIPC, vectorFromArray } from 'apache-arrow';
18
18
  import cx from 'classnames';
19
19
  import { AnimatePresence, motion } from 'framer-motion';
20
- import { Button, Table as TableComponent, TableSkeleton, useParcaContext, useURLState, } from '@parca/components';
20
+ import { Table as TableComponent, TableSkeleton, useParcaContext, useURLState, } from '@parca/components';
21
21
  import { getLastItem, isSearchMatch, valueFormatter } from '@parca/utilities';
22
22
  import { useProfileViewContext } from '../ProfileView/ProfileViewContext';
23
23
  import { hexifyAddress } from '../utils';
24
- import ColumnsVisibility from './ColumnsVisibility';
25
24
  import { getTopAndBottomExpandedRowModel } from './utils/topAndBottomExpandedRowModel';
26
25
  const FIELD_MAPPING_FILE = 'mapping_file';
27
26
  const FIELD_LOCATION_ADDRESS = 'location_address';
@@ -34,7 +33,7 @@ const FIELD_CUMULATIVE = 'cumulative';
34
33
  const FIELD_CUMULATIVE_DIFF = 'cumulative_diff';
35
34
  const FIELD_CALLERS = 'callers';
36
35
  const FIELD_CALLEES = 'callees';
37
- const isDummyRow = (row) => {
36
+ export const isDummyRow = (row) => {
38
37
  return 'size' in row;
39
38
  };
40
39
  let doubleClickTimer = null;
@@ -146,10 +145,40 @@ const getCalleeRows = (callees) => {
146
145
  }
147
146
  return [{ size: 3 - rows.length, message: '', isBottomSubRow: true }, ...rows];
148
147
  };
149
- export const Table = React.memo(function Table({ data, total, filtered, profileType, loading, currentSearchString, setSearchString = () => { }, setActionButtons, isHalfScreen, unit, }) {
148
+ export const getPercentageString = (value, total) => {
149
+ if (total === 0n) {
150
+ return '0%';
151
+ }
152
+ const percentage = (Number(value) / Number(total)) * 100;
153
+ return `${percentage.toFixed(2)}%`;
154
+ };
155
+ export const getRatioString = (value, total, filtered) => {
156
+ if (filtered === 0n) {
157
+ return ` ${getPercentageString(value, total)}`;
158
+ }
159
+ return `${getPercentageString(value, total)} / ${getPercentageString(value, filtered)}`;
160
+ };
161
+ export const possibleColumns = [
162
+ 'flat',
163
+ 'flatPercentage',
164
+ 'flatDiff',
165
+ 'flatDiffPercentage',
166
+ 'cumulative',
167
+ 'cumulativePercentage',
168
+ 'cumulativeDiff',
169
+ 'cumulativeDiffPercentage',
170
+ 'name',
171
+ 'functionSystemName',
172
+ 'functionFileName',
173
+ 'mappingFile',
174
+ ];
175
+ export const Table = React.memo(function Table({ data, total, filtered, profileType, loading, currentSearchString, setSearchString = () => { }, isHalfScreen, unit, }) {
150
176
  const [dashboardItems] = useURLState('dashboard_items', {
151
177
  alwaysReturnArray: true,
152
178
  });
179
+ const [tableColumns] = useURLState('table_columns', {
180
+ alwaysReturnArray: true,
181
+ });
153
182
  const { isDarkMode } = useParcaContext();
154
183
  const [expanded, setExpanded] = useState({});
155
184
  const [scrollToIndex, setScrollToIndex] = useState(undefined);
@@ -310,6 +339,17 @@ export const Table = React.memo(function Table({ data, total, filtered, profileT
310
339
  mappingFile: false,
311
340
  };
312
341
  });
342
+ useEffect(() => {
343
+ if (Array.isArray(tableColumns)) {
344
+ setColumnVisibility(prevState => {
345
+ const newState = { ...prevState };
346
+ Object.keys(newState).forEach(column => {
347
+ newState[column] = tableColumns.includes(column);
348
+ });
349
+ return newState;
350
+ });
351
+ }
352
+ }, [tableColumns]);
313
353
  const selectSpan = useCallback((span) => {
314
354
  setSearchString(span.trim());
315
355
  }, [setSearchString]);
@@ -359,22 +399,6 @@ export const Table = React.memo(function Table({ data, total, filtered, profileT
359
399
  const enableHighlighting = useMemo(() => {
360
400
  return currentSearchString != null && currentSearchString?.length > 0;
361
401
  }, [currentSearchString]);
362
- const clearSelection = useCallback(() => {
363
- setSearchString('');
364
- }, [setSearchString]);
365
- useEffect(() => {
366
- setActionButtons?.(_jsxs(_Fragment, { children: [_jsx(ColumnsVisibility, { columns: columns, visibility: columnVisibility, setVisibility: (id, visible) => {
367
- setColumnVisibility({ ...columnVisibility, [id]: visible });
368
- } }), dashboardItems.length > 1 && (_jsx(Button, { color: "neutral", onClick: clearSelection, className: "w-auto", variant: "neutral", disabled: currentSearchString === undefined || currentSearchString.length === 0, children: "Clear selection" }))] }));
369
- }, [
370
- dashboardItems,
371
- clearSelection,
372
- currentSearchString,
373
- setActionButtons,
374
- columns,
375
- columnVisibility,
376
- loading,
377
- ]);
378
402
  const initialSorting = useMemo(() => {
379
403
  return [
380
404
  {
@@ -458,7 +482,7 @@ export const Table = React.memo(function Table({ data, total, filtered, profileT
458
482
  setExpanded(newState);
459
483
  }, CustomRowRenderer: CustomRowRenderer, scrollToIndex: scrollToIndex, estimatedRowHeight: ROW_HEIGHT }) }) }) }, "table-loaded") }));
460
484
  });
461
- const addPlusSign = (num) => {
485
+ export const addPlusSign = (num) => {
462
486
  if (num.charAt(0) === '0' || num.charAt(0) === '-') {
463
487
  return num;
464
488
  }
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import { QueryServiceClient } from '@parca/client';
3
+ import { Query } from '@parca/parser';
4
+ interface Props {
5
+ labelNames: string[];
6
+ profileType: string;
7
+ runQuery: () => void;
8
+ currentQuery: Query;
9
+ queryClient: QueryServiceClient;
10
+ setMatchersString: (arg: string) => void;
11
+ }
12
+ declare const ViewMatchers: React.FC<Props>;
13
+ export default ViewMatchers;
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ViewMatchers/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAKtE,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAKpC,UAAU,KAAK;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,EAAE,KAAK,CAAC;IACpB,WAAW,EAAE,kBAAkB,CAAC;IAChC,iBAAiB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1C;AAED,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAyJjC,CAAC;AAEF,eAAe,YAAY,CAAC"}