@parca/profile 0.16.0 → 0.16.22

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 (93) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/Callgraph/Edge/index.d.ts +22 -0
  3. package/dist/Callgraph/Edge/index.js +30 -0
  4. package/dist/Callgraph/Node/index.d.ts +19 -0
  5. package/dist/Callgraph/Node/index.js +37 -0
  6. package/dist/Callgraph/index.d.ts +8 -0
  7. package/dist/Callgraph/index.js +137 -0
  8. package/dist/Callgraph/mockData/index.d.ts +148 -0
  9. package/dist/Callgraph/mockData/index.js +577 -0
  10. package/dist/Callgraph/utils.d.ts +19 -0
  11. package/dist/Callgraph/utils.js +82 -0
  12. package/dist/GraphTooltip/index.d.ts +19 -0
  13. package/dist/GraphTooltip/index.js +119 -0
  14. package/dist/IcicleGraph.d.ts +35 -0
  15. package/dist/IcicleGraph.js +139 -0
  16. package/dist/MatchersInput/index.d.ts +23 -0
  17. package/dist/MatchersInput/index.js +479 -0
  18. package/dist/MetricsCircle/index.d.ts +7 -0
  19. package/dist/MetricsCircle/index.js +18 -0
  20. package/dist/MetricsGraph/index.d.ts +35 -0
  21. package/dist/MetricsGraph/index.js +349 -0
  22. package/dist/MetricsSeries/index.d.ts +11 -0
  23. package/dist/MetricsSeries/index.js +21 -0
  24. package/dist/ProfileExplorer/ProfileExplorerCompare.d.ts +19 -0
  25. package/dist/ProfileExplorer/ProfileExplorerCompare.js +38 -0
  26. package/dist/ProfileExplorer/ProfileExplorerSingle.d.ts +15 -0
  27. package/dist/ProfileExplorer/ProfileExplorerSingle.js +19 -0
  28. package/dist/ProfileExplorer/index.d.ts +9 -0
  29. package/dist/ProfileExplorer/index.js +203 -0
  30. package/dist/ProfileIcicleGraph.d.ts +10 -0
  31. package/dist/ProfileIcicleGraph.js +28 -0
  32. package/dist/ProfileMetricsGraph/index.d.ts +22 -0
  33. package/dist/ProfileMetricsGraph/index.js +127 -0
  34. package/dist/ProfileSVG.module.css +3 -0
  35. package/dist/ProfileSelector/CompareButton.d.ts +5 -0
  36. package/dist/ProfileSelector/CompareButton.js +41 -0
  37. package/dist/ProfileSelector/MergeButton.d.ts +5 -0
  38. package/dist/ProfileSelector/MergeButton.js +41 -0
  39. package/dist/ProfileSelector/index.d.ts +29 -0
  40. package/dist/ProfileSelector/index.js +133 -0
  41. package/dist/ProfileSource.d.ts +88 -0
  42. package/dist/ProfileSource.js +239 -0
  43. package/dist/ProfileTypeSelector/index.d.ts +20 -0
  44. package/dist/ProfileTypeSelector/index.js +138 -0
  45. package/dist/ProfileView.d.ts +39 -0
  46. package/dist/ProfileView.js +111 -0
  47. package/dist/ProfileView.styles.css +3 -0
  48. package/dist/ProfileViewWithData.d.ts +11 -0
  49. package/dist/ProfileViewWithData.js +116 -0
  50. package/dist/TopTable.d.ts +9 -0
  51. package/dist/TopTable.js +140 -0
  52. package/dist/TopTable.styles.css +7 -0
  53. package/dist/components/DiffLegend.d.ts +2 -0
  54. package/dist/components/DiffLegend.js +62 -0
  55. package/dist/components/ProfileShareButton/ResultBox.d.ts +6 -0
  56. package/dist/components/ProfileShareButton/ResultBox.js +46 -0
  57. package/dist/components/ProfileShareButton/index.d.ts +7 -0
  58. package/dist/components/ProfileShareButton/index.js +119 -0
  59. package/dist/index.d.ts +13 -0
  60. package/dist/index.js +64 -0
  61. package/dist/styles.css +1 -0
  62. package/dist/useDelayedLoader.d.ts +5 -0
  63. package/dist/useDelayedLoader.js +33 -0
  64. package/dist/useQuery.d.ts +13 -0
  65. package/dist/useQuery.js +41 -0
  66. package/dist/utils.d.ts +4 -0
  67. package/dist/utils.js +83 -0
  68. package/package.json +12 -8
  69. package/src/Callgraph/Edge/index.tsx +59 -0
  70. package/src/Callgraph/Node/index.tsx +66 -0
  71. package/src/Callgraph/index.tsx +169 -0
  72. package/src/Callgraph/mockData/index.ts +605 -0
  73. package/src/Callgraph/utils.ts +116 -0
  74. package/src/GraphTooltip/index.tsx +245 -0
  75. package/src/IcicleGraph.tsx +3 -3
  76. package/src/MatchersInput/index.tsx +698 -0
  77. package/src/MetricsCircle/index.tsx +28 -0
  78. package/src/MetricsGraph/index.tsx +614 -0
  79. package/src/MetricsSeries/index.tsx +38 -0
  80. package/src/ProfileExplorer/ProfileExplorerCompare.tsx +109 -0
  81. package/src/ProfileExplorer/ProfileExplorerSingle.tsx +72 -0
  82. package/src/ProfileExplorer/index.tsx +377 -0
  83. package/src/ProfileMetricsGraph/index.tsx +143 -0
  84. package/src/ProfileSelector/CompareButton.tsx +72 -0
  85. package/src/ProfileSelector/MergeButton.tsx +72 -0
  86. package/src/ProfileSelector/index.tsx +270 -0
  87. package/src/ProfileTypeSelector/index.tsx +180 -0
  88. package/src/ProfileView.tsx +2 -7
  89. package/src/index.tsx +11 -0
  90. package/src/useQuery.tsx +1 -0
  91. package/tailwind.config.js +8 -0
  92. package/tsconfig.json +7 -3
  93. package/typings.d.ts +14 -0
@@ -0,0 +1,111 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
+ // Copyright 2022 The Parca Authors
14
+ // Licensed under the Apache License, Version 2.0 (the "License");
15
+ // you may not use this file except in compliance with the License.
16
+ // You may obtain a copy of the License at
17
+ //
18
+ // http://www.apache.org/licenses/LICENSE-2.0
19
+ //
20
+ // Unless required by applicable law or agreed to in writing, software
21
+ // distributed under the License is distributed on an "AS IS" BASIS,
22
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23
+ // See the License for the specific language governing permissions and
24
+ // limitations under the License.
25
+ import { useEffect, useMemo, useState } from 'react';
26
+ import { parseParams } from '@parca/functions';
27
+ import useUIFeatureFlag from '@parca/functions/useUIFeatureFlag';
28
+ import { Button, Card, SearchNodes, useParcaTheme } from '@parca/components';
29
+ import { Callgraph as CallgraphComponent } from './';
30
+ import { useContainerDimensions } from '@parca/dynamicsize';
31
+ import ProfileShareButton from './components/ProfileShareButton';
32
+ import ProfileIcicleGraph from './ProfileIcicleGraph';
33
+ import TopTable from './TopTable';
34
+ import useDelayedLoader from './useDelayedLoader';
35
+ import './ProfileView.styles.css';
36
+ function arrayEquals(a, b) {
37
+ return (Array.isArray(a) &&
38
+ Array.isArray(b) &&
39
+ a.length === b.length &&
40
+ a.every(function (val, index) { return val === b[index]; }));
41
+ }
42
+ export var useProfileVisState = function () {
43
+ var _a = useState(function () {
44
+ if (typeof window === 'undefined') {
45
+ return 'icicle';
46
+ }
47
+ var router = parseParams(window.location.search);
48
+ var currentViewFromURL = router.currentProfileView;
49
+ if (currentViewFromURL != null) {
50
+ return currentViewFromURL;
51
+ }
52
+ return 'icicle';
53
+ }), currentView = _a[0], setCurrentView = _a[1];
54
+ return { currentView: currentView, setCurrentView: setCurrentView };
55
+ };
56
+ export var ProfileView = function (_a) {
57
+ var flamegraphData = _a.flamegraphData, topTableData = _a.topTableData, callgraphData = _a.callgraphData, sampleUnit = _a.sampleUnit, profileSource = _a.profileSource, queryClient = _a.queryClient, navigateTo = _a.navigateTo, profileVisState = _a.profileVisState, onDownloadPProf = _a.onDownloadPProf;
58
+ var _b = useContainerDimensions(), ref = _b.ref, dimensions = _b.dimensions;
59
+ var _c = useState([]), curPath = _c[0], setCurPath = _c[1];
60
+ var currentView = profileVisState.currentView, setCurrentView = profileVisState.setCurrentView;
61
+ var callgraphEnabled = useUIFeatureFlag('callgraph')[0];
62
+ var loader = useParcaTheme().loader;
63
+ useEffect(function () {
64
+ // Reset the current path when the profile source changes
65
+ setCurPath([]);
66
+ }, [profileSource]);
67
+ var isLoading = useMemo(function () {
68
+ if (currentView === 'icicle') {
69
+ return Boolean(flamegraphData === null || flamegraphData === void 0 ? void 0 : flamegraphData.loading);
70
+ }
71
+ if (currentView === 'callgraph') {
72
+ return Boolean(callgraphData === null || callgraphData === void 0 ? void 0 : callgraphData.loading);
73
+ }
74
+ if (currentView === 'table') {
75
+ return Boolean(topTableData === null || topTableData === void 0 ? void 0 : topTableData.loading);
76
+ }
77
+ if (currentView === 'both') {
78
+ return Boolean(flamegraphData === null || flamegraphData === void 0 ? void 0 : flamegraphData.loading) || Boolean(topTableData === null || topTableData === void 0 ? void 0 : topTableData.loading);
79
+ }
80
+ return false;
81
+ }, [currentView, callgraphData === null || callgraphData === void 0 ? void 0 : callgraphData.loading, flamegraphData === null || flamegraphData === void 0 ? void 0 : flamegraphData.loading, topTableData === null || topTableData === void 0 ? void 0 : topTableData.loading]);
82
+ var isLoaderVisible = useDelayedLoader(isLoading);
83
+ if (isLoaderVisible) {
84
+ return _jsx(_Fragment, { children: loader });
85
+ }
86
+ if ((flamegraphData === null || flamegraphData === void 0 ? void 0 : flamegraphData.error) != null) {
87
+ console.error('Error: ', flamegraphData === null || flamegraphData === void 0 ? void 0 : flamegraphData.error);
88
+ return (_jsxs("div", __assign({ className: "p-10 flex justify-center" }, { children: ["An error occurred: ", flamegraphData === null || flamegraphData === void 0 ? void 0 : flamegraphData.error.message] })));
89
+ }
90
+ var resetIcicleGraph = function () { return setCurPath([]); };
91
+ var setNewCurPath = function (path) {
92
+ if (!arrayEquals(curPath, path)) {
93
+ setCurPath(path);
94
+ }
95
+ };
96
+ var switchProfileView = function (view) {
97
+ if (view == null) {
98
+ return;
99
+ }
100
+ setCurrentView(view);
101
+ if (navigateTo === undefined) {
102
+ return;
103
+ }
104
+ var router = parseParams(window.location.search);
105
+ navigateTo('/', __assign(__assign({}, router), { currentProfileView: view }));
106
+ };
107
+ return (_jsx(_Fragment, { children: _jsx("div", __assign({ className: "py-3" }, { children: _jsx(Card, { children: _jsxs(Card.Body, { children: [_jsxs("div", __assign({ className: "flex py-3 w-full" }, { children: [_jsxs("div", __assign({ className: "w-2/5 flex space-x-4" }, { children: [_jsxs("div", __assign({ className: "flex space-x-1" }, { children: [profileSource != null && queryClient != null ? (_jsx(ProfileShareButton, { queryRequest: profileSource.QueryRequest(), queryClient: queryClient })) : null, _jsx(Button, __assign({ color: "neutral", onClick: function (e) {
108
+ e.preventDefault();
109
+ onDownloadPProf();
110
+ } }, { children: "Download pprof" }))] })), _jsx(SearchNodes, {})] })), _jsxs("div", __assign({ className: "flex ml-auto" }, { children: [_jsx("div", __assign({ className: "mr-3" }, { children: _jsx(Button, __assign({ color: "neutral", onClick: resetIcicleGraph, disabled: curPath.length === 0, className: "whitespace-nowrap text-ellipsis" }, { children: "Reset View" })) })), callgraphEnabled ? (_jsx("div", __assign({ className: "mr-3" }, { children: _jsx(Button, __assign({ variant: "".concat(currentView === 'callgraph' ? 'primary' : 'neutral'), onClick: function () { return switchProfileView('callgraph'); }, className: "whitespace-nowrap text-ellipsis" }, { children: "Call Graph" })) }))) : null, _jsx(Button, __assign({ variant: "".concat(currentView === 'table' ? 'primary' : 'neutral'), className: "items-center rounded-tr-none rounded-br-none w-auto px-8 whitespace-nowrap text-ellipsis no-outline-on-buttons", onClick: function () { return switchProfileView('table'); } }, { children: "Table" })), _jsx(Button, __assign({ variant: "".concat(currentView === 'both' ? 'primary' : 'neutral'), className: "items-center rounded-tl-none rounded-tr-none rounded-bl-none rounded-br-none border-l-0 border-r-0 w-auto px-8 whitespace-nowrap no-outline-on-buttons text-ellipsis", onClick: function () { return switchProfileView('both'); } }, { children: "Both" })), _jsx(Button, __assign({ variant: "".concat(currentView === 'icicle' ? 'primary' : 'neutral'), className: "items-center rounded-tl-none rounded-bl-none w-auto px-8 whitespace-nowrap text-ellipsis no-outline-on-buttons", onClick: function () { return switchProfileView('icicle'); } }, { children: "Icicle Graph" }))] }))] })), _jsxs("div", __assign({ ref: ref, className: "flex space-x-4 justify-between w-full" }, { children: [currentView === 'icicle' && (flamegraphData === null || flamegraphData === void 0 ? void 0 : flamegraphData.data) != null && (_jsx("div", __assign({ className: "w-full" }, { children: _jsx(ProfileIcicleGraph, { curPath: curPath, setNewCurPath: setNewCurPath, graph: flamegraphData.data, sampleUnit: sampleUnit }) }))), currentView === 'callgraph' && (callgraphData === null || callgraphData === void 0 ? void 0 : callgraphData.data) != null && (_jsx("div", __assign({ className: "w-full" }, { children: (dimensions === null || dimensions === void 0 ? void 0 : dimensions.width) !== undefined && (_jsx(CallgraphComponent, { graph: callgraphData.data, sampleUnit: sampleUnit, width: dimensions === null || dimensions === void 0 ? void 0 : dimensions.width })) }))), currentView === 'table' && topTableData != null && (_jsx("div", __assign({ className: "w-full" }, { children: _jsx(TopTable, { data: topTableData.data, sampleUnit: sampleUnit }) }))), currentView === 'both' && (_jsxs(_Fragment, { children: [_jsx("div", __assign({ className: "w-1/2" }, { children: _jsx(TopTable, { data: topTableData === null || topTableData === void 0 ? void 0 : topTableData.data, sampleUnit: sampleUnit }) })), _jsx("div", __assign({ className: "w-1/2" }, { children: flamegraphData != null && (_jsx(ProfileIcicleGraph, { curPath: curPath, setNewCurPath: setNewCurPath, graph: flamegraphData.data, sampleUnit: sampleUnit })) }))] }))] }))] }) }) })) }));
111
+ };
@@ -0,0 +1,3 @@
1
+ .no-outline-on-buttons {
2
+ box-shadow: none !important;
3
+ }
@@ -0,0 +1,11 @@
1
+ import { QueryServiceClient } from '@parca/client';
2
+ import { ProfileSource } from './ProfileSource';
3
+ declare type NavigateFunction = (path: string, queryParams: any) => void;
4
+ interface ProfileViewWithDataProps {
5
+ queryClient: QueryServiceClient;
6
+ profileSource: ProfileSource;
7
+ navigateTo?: NavigateFunction;
8
+ compare?: boolean;
9
+ }
10
+ export declare const ProfileViewWithData: ({ queryClient, profileSource, navigateTo, }: ProfileViewWithDataProps) => JSX.Element;
11
+ export default ProfileViewWithData;
@@ -0,0 +1,116 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ var __generator = (this && this.__generator) || function (thisArg, body) {
11
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
12
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
+ function verb(n) { return function (v) { return step([n, v]); }; }
14
+ function step(op) {
15
+ if (f) throw new TypeError("Generator is already executing.");
16
+ while (_) try {
17
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18
+ if (y = 0, t) op = [op[0] & 2, t.value];
19
+ switch (op[0]) {
20
+ case 0: case 1: t = op; break;
21
+ case 4: _.label++; return { value: op[1], done: false };
22
+ case 5: _.label++; y = op[1]; op = [0]; continue;
23
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
24
+ default:
25
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29
+ if (t[2]) _.ops.pop();
30
+ _.trys.pop(); continue;
31
+ }
32
+ op = body.call(thisArg, _);
33
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
+ }
36
+ };
37
+ import { jsx as _jsx } from "react/jsx-runtime";
38
+ // Copyright 2022 The Parca Authors
39
+ // Licensed under the Apache License, Version 2.0 (the "License");
40
+ // you may not use this file except in compliance with the License.
41
+ // You may obtain a copy of the License at
42
+ //
43
+ // http://www.apache.org/licenses/LICENSE-2.0
44
+ //
45
+ // Unless required by applicable law or agreed to in writing, software
46
+ // distributed under the License is distributed on an "AS IS" BASIS,
47
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
48
+ // See the License for the specific language governing permissions and
49
+ // limitations under the License.
50
+ import { QueryRequest_ReportType } from '@parca/client';
51
+ import { useQuery } from './useQuery';
52
+ import { ProfileView, useProfileVisState } from './ProfileView';
53
+ import { downloadPprof } from './utils';
54
+ import { useGrpcMetadata } from '@parca/components';
55
+ export var ProfileViewWithData = function (_a) {
56
+ var _b, _c;
57
+ var queryClient = _a.queryClient, profileSource = _a.profileSource, navigateTo = _a.navigateTo;
58
+ var profileVisState = useProfileVisState();
59
+ var metadata = useGrpcMetadata();
60
+ var currentView = profileVisState.currentView;
61
+ var _d = useQuery(queryClient, profileSource, QueryRequest_ReportType.FLAMEGRAPH_UNSPECIFIED, {
62
+ skip: currentView !== 'icicle' && currentView !== 'both',
63
+ }), flamegraphLoading = _d.isLoading, flamegraphResponse = _d.response, flamegraphError = _d.error;
64
+ var _e = useQuery(queryClient, profileSource, QueryRequest_ReportType.TOP, {
65
+ skip: currentView !== 'table' && currentView !== 'both',
66
+ }), topTableLoading = _e.isLoading, topTableResponse = _e.response, topTableError = _e.error;
67
+ var _f = useQuery(queryClient, profileSource, QueryRequest_ReportType.CALLGRAPH, {
68
+ skip: currentView !== 'callgraph',
69
+ }), callgraphLoading = _f.isLoading, callgraphResponse = _f.response, callgraphError = _f.error;
70
+ var sampleUnit = profileSource.ProfileType().sampleUnit;
71
+ var downloadPProfClick = function () { return __awaiter(void 0, void 0, void 0, function () {
72
+ var blob, link, error_1;
73
+ return __generator(this, function (_a) {
74
+ switch (_a.label) {
75
+ case 0:
76
+ if (profileSource == null || queryClient == null) {
77
+ return [2 /*return*/];
78
+ }
79
+ _a.label = 1;
80
+ case 1:
81
+ _a.trys.push([1, 3, , 4]);
82
+ return [4 /*yield*/, downloadPprof(profileSource.QueryRequest(), queryClient, metadata)];
83
+ case 2:
84
+ blob = _a.sent();
85
+ link = document.createElement('a');
86
+ link.href = window.URL.createObjectURL(blob);
87
+ link.download = 'profile.pb.gz';
88
+ link.click();
89
+ return [3 /*break*/, 4];
90
+ case 3:
91
+ error_1 = _a.sent();
92
+ console.error('Error while querying', error_1);
93
+ return [3 /*break*/, 4];
94
+ case 4: return [2 /*return*/];
95
+ }
96
+ });
97
+ }); };
98
+ return (_jsx(ProfileView, { flamegraphData: {
99
+ loading: flamegraphLoading,
100
+ data: (flamegraphResponse === null || flamegraphResponse === void 0 ? void 0 : flamegraphResponse.report.oneofKind) === 'flamegraph'
101
+ ? (_b = flamegraphResponse === null || flamegraphResponse === void 0 ? void 0 : flamegraphResponse.report) === null || _b === void 0 ? void 0 : _b.flamegraph
102
+ : undefined,
103
+ error: flamegraphError,
104
+ }, topTableData: {
105
+ loading: topTableLoading,
106
+ data: (topTableResponse === null || topTableResponse === void 0 ? void 0 : topTableResponse.report.oneofKind) === 'top' ? topTableResponse.report.top : undefined,
107
+ error: topTableError,
108
+ }, callgraphData: {
109
+ loading: callgraphLoading,
110
+ data: (callgraphResponse === null || callgraphResponse === void 0 ? void 0 : callgraphResponse.report.oneofKind) === 'callgraph'
111
+ ? (_c = callgraphResponse === null || callgraphResponse === void 0 ? void 0 : callgraphResponse.report) === null || _c === void 0 ? void 0 : _c.callgraph
112
+ : undefined,
113
+ error: callgraphError,
114
+ }, profileVisState: profileVisState, sampleUnit: sampleUnit, profileSource: profileSource, queryClient: queryClient, navigateTo: navigateTo, onDownloadPProf: function () { return void downloadPProfClick(); } }));
115
+ };
116
+ export default ProfileViewWithData;
@@ -0,0 +1,9 @@
1
+ import { TopNodeMeta, Top } from '@parca/client';
2
+ import './TopTable.styles.css';
3
+ interface TopTableProps {
4
+ data?: Top;
5
+ sampleUnit: string;
6
+ }
7
+ export declare const RowLabel: (meta: TopNodeMeta | undefined) => string;
8
+ export declare const TopTable: ({ data, sampleUnit }: TopTableProps) => JSX.Element;
9
+ export default TopTable;
@@ -0,0 +1,140 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
13
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
14
+ if (ar || !(i in from)) {
15
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
16
+ ar[i] = from[i];
17
+ }
18
+ }
19
+ return to.concat(ar || Array.prototype.slice.call(from));
20
+ };
21
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
22
+ // Copyright 2022 The Parca Authors
23
+ // Licensed under the Apache License, Version 2.0 (the "License");
24
+ // you may not use this file except in compliance with the License.
25
+ // You may obtain a copy of the License at
26
+ //
27
+ // http://www.apache.org/licenses/LICENSE-2.0
28
+ //
29
+ // Unless required by applicable law or agreed to in writing, software
30
+ // distributed under the License is distributed on an "AS IS" BASIS,
31
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32
+ // See the License for the specific language governing permissions and
33
+ // limitations under the License.
34
+ import React from 'react';
35
+ import { getLastItem, valueFormatter, isSearchMatch } from '@parca/functions';
36
+ import { useAppSelector, selectCompareMode, selectSearchNodeString } from '@parca/store';
37
+ import { hexifyAddress } from './utils';
38
+ import './TopTable.styles.css';
39
+ var Arrow = function (_a) {
40
+ var direction = _a.direction;
41
+ return (_jsx("svg", __assign({ className: "".concat(direction !== undefined ? 'fill-[#161616] dark:fill-[#ffffff]' : ''), fill: "#777d87", height: "10", viewBox: "0 0 11 10", width: "11", xmlns: "http://www.w3.org/2000/svg" }, { children: _jsx("path", { clipRule: "evenodd", d: "m.573997 0 5.000003 10 5-10h-9.999847z", fillRule: "evenodd" }) })));
42
+ };
43
+ var useSortableData = function (top, config) {
44
+ if (config === void 0) { config = {
45
+ key: 'cumulative',
46
+ direction: 'desc',
47
+ }; }
48
+ var _a = React.useState(config), sortConfig = _a[0], setSortConfig = _a[1];
49
+ var rawTableReport = top != null ? top.list : [];
50
+ var items = rawTableReport.map(function (node) {
51
+ var _a, _b;
52
+ return (__assign(__assign({}, node), {
53
+ // Warning: string to number can overflow
54
+ // https://github.com/timostamm/protobuf-ts/blob/master/MANUAL.md#bigint-support
55
+ diff: Number(node.diff), cumulative: Number(node.cumulative), flat: Number(node.flat), name: (_b = (_a = node.meta) === null || _a === void 0 ? void 0 : _a.function) === null || _b === void 0 ? void 0 : _b.name }));
56
+ });
57
+ var sortedItems = React.useMemo(function () {
58
+ if (items.length === 0)
59
+ return;
60
+ var sortableItems = __spreadArray([], items, true);
61
+ if (sortConfig !== null) {
62
+ sortableItems.sort(function (a, b) {
63
+ var itemA = a[sortConfig.key];
64
+ var itemB = b[sortConfig.key];
65
+ if (itemA === undefined && itemB === undefined) {
66
+ return 0;
67
+ }
68
+ if (itemA === undefined) {
69
+ return sortConfig.direction === 'asc' ? -1 : 1;
70
+ }
71
+ if (itemB === undefined) {
72
+ return sortConfig.direction === 'asc' ? 1 : -1;
73
+ }
74
+ if (itemA < itemB) {
75
+ return sortConfig.direction === 'asc' ? -1 : 1;
76
+ }
77
+ if (itemA > itemB) {
78
+ return sortConfig.direction === 'asc' ? 1 : -1;
79
+ }
80
+ return 0;
81
+ });
82
+ }
83
+ return sortableItems;
84
+ }, [items, sortConfig]);
85
+ var requestSort = function (key) {
86
+ var direction = 'desc';
87
+ if (sortConfig != null && sortConfig.key === key && sortConfig.direction === 'desc') {
88
+ direction = 'asc';
89
+ }
90
+ setSortConfig({ key: key, direction: direction });
91
+ };
92
+ return { items: sortedItems, requestSort: requestSort, sortConfig: sortConfig };
93
+ };
94
+ export var RowLabel = function (meta) {
95
+ var _a, _b, _c, _d, _e, _f;
96
+ if (meta === undefined)
97
+ return '<unknown>';
98
+ var mapping = "".concat(((_a = meta === null || meta === void 0 ? void 0 : meta.mapping) === null || _a === void 0 ? void 0 : _a.file) !== undefined && ((_b = meta === null || meta === void 0 ? void 0 : meta.mapping) === null || _b === void 0 ? void 0 : _b.file) !== ''
99
+ ? "[".concat((_c = getLastItem(meta.mapping.file)) !== null && _c !== void 0 ? _c : '', "]")
100
+ : '');
101
+ if (((_d = meta.function) === null || _d === void 0 ? void 0 : _d.name) !== undefined && ((_e = meta.function) === null || _e === void 0 ? void 0 : _e.name) !== '')
102
+ return "".concat(mapping, " ").concat(meta.function.name);
103
+ var address = hexifyAddress((_f = meta.location) === null || _f === void 0 ? void 0 : _f.address);
104
+ var fallback = "".concat(mapping, " ").concat(address);
105
+ return fallback === '' ? '<unknown>' : fallback;
106
+ };
107
+ export var TopTable = function (_a) {
108
+ var _b, _c, _d, _e;
109
+ var top = _a.data, sampleUnit = _a.sampleUnit;
110
+ var _f = useSortableData(top), items = _f.items, requestSort = _f.requestSort, sortConfig = _f.sortConfig;
111
+ var currentSearchString = useAppSelector(selectSearchNodeString);
112
+ var compareMode = useAppSelector(selectCompareMode);
113
+ var unit = sampleUnit;
114
+ var total = top != null ? top.list.length : 0;
115
+ if (total === 0)
116
+ return _jsx(_Fragment, { children: "Profile has no samples" });
117
+ var getClassNamesFor = function (name) {
118
+ if (sortConfig == null) {
119
+ return;
120
+ }
121
+ return sortConfig.key === name ? sortConfig.direction : undefined;
122
+ };
123
+ var addPlusSign = function (num) {
124
+ if (num.charAt(0) === '0' || num.charAt(0) === '-') {
125
+ return num;
126
+ }
127
+ return "+".concat(num);
128
+ };
129
+ return (_jsx(_Fragment, { children: _jsx("div", __assign({ className: "w-full font-robotoMono" }, { children: _jsxs("table", __assign({ className: "iciclegraph-table table-fixed text-left w-full divide-y divide-gray-200 dark:divide-gray-700" }, { children: [_jsx("thead", __assign({ className: "bg-gray-50 dark:bg-gray-800" }, { children: _jsxs("tr", { children: [_jsxs("th", __assign({ className: "text-sm cursor-pointer pt-2 pb-2 pl-2", onClick: function () { return requestSort('name'); } }, { children: ["Name", _jsx("span", __assign({ className: "inline-block align-middle ml-2 ".concat((_b = getClassNamesFor('name')) !== null && _b !== void 0 ? _b : '') }, { children: _jsx(Arrow, { direction: getClassNamesFor('name') }) }))] })), _jsxs("th", __assign({ className: "text-right text-sm cursor-pointer pt-2 pb-2 w-[150px]", onClick: function () { return requestSort('flat'); } }, { children: ["Flat", _jsx("span", __assign({ className: "inline-block align-middle ml-2 ".concat((_c = getClassNamesFor('flat')) !== null && _c !== void 0 ? _c : '') }, { children: _jsx(Arrow, { direction: getClassNamesFor('flat') }) }))] })), _jsxs("th", __assign({ className: "text-right text-sm cursor-pointer pt-2 pb-2 pr-2 w-[150px]", onClick: function () { return requestSort('cumulative'); } }, { children: ["Cumulative", _jsx("span", __assign({ className: "inline-block align-middle ml-2 ".concat((_d = getClassNamesFor('cumulative')) !== null && _d !== void 0 ? _d : '') }, { children: _jsx(Arrow, { direction: getClassNamesFor('cumulative') }) }))] })), compareMode && (_jsxs("th", __assign({ className: "text-right text-sm cursor-pointer pt-2 pb-2 pr-2 w-[150px]", onClick: function () { return requestSort('diff'); } }, { children: ["Diff", _jsx("span", __assign({ className: "inline-block align-middle ml-2 ".concat((_e = getClassNamesFor('diff')) !== null && _e !== void 0 ? _e : '') }, { children: _jsx(Arrow, { direction: getClassNamesFor('diff') }) }))] })))] }) })), _jsx("tbody", __assign({ className: "bg-white divide-y divide-gray-200 dark:bg-gray-900 dark:divide-gray-700" }, { children: items === null || items === void 0 ? void 0 : items.map(function (report, index) {
130
+ var name = RowLabel(report.meta);
131
+ return (_jsxs("tr", __assign({ className: "hover:bg-[#62626212] dark:hover:bg-[#ffffff12]", style: {
132
+ opacity: currentSearchString !== undefined &&
133
+ currentSearchString !== '' &&
134
+ !isSearchMatch(currentSearchString, name)
135
+ ? 0.5
136
+ : 1,
137
+ } }, { children: [_jsx("td", __assign({ className: "text-xs py-1.5 pl-2" }, { children: name })), _jsx("td", __assign({ className: "text-xs py-1.5 text-right" }, { children: valueFormatter(report.flat, unit, 2) })), _jsx("td", __assign({ className: "text-xs py-1.5 text-right pr-2" }, { children: valueFormatter(report.cumulative, unit, 2) })), compareMode && (_jsx("td", __assign({ className: "text-xs py-1.5 text-right pr-2" }, { children: addPlusSign(valueFormatter(report.diff, unit, 2)) })))] }), index));
138
+ }) }))] })) })) }));
139
+ };
140
+ export default TopTable;
@@ -0,0 +1,7 @@
1
+ .iciclegraph-table .desc {
2
+ transform: rotate(0);
3
+ }
4
+
5
+ .iciclegraph-table .asc {
6
+ transform: rotate(180deg);
7
+ }
@@ -0,0 +1,2 @@
1
+ declare const DiffLegend: () => JSX.Element;
2
+ export default DiffLegend;
@@ -0,0 +1,62 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
+ // Copyright 2022 The Parca Authors
14
+ // Licensed under the Apache License, Version 2.0 (the "License");
15
+ // you may not use this file except in compliance with the License.
16
+ // You may obtain a copy of the License at
17
+ //
18
+ // http://www.apache.org/licenses/LICENSE-2.0
19
+ //
20
+ // Unless required by applicable law or agreed to in writing, software
21
+ // distributed under the License is distributed on an "AS IS" BASIS,
22
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23
+ // See the License for the specific language governing permissions and
24
+ // limitations under the License.
25
+ import { Fragment, useState } from 'react';
26
+ import { Popover, Transition } from '@headlessui/react';
27
+ import { useAppSelector, selectDarkMode } from '@parca/store';
28
+ import { getNewSpanColor, getIncreasedSpanColor, getReducedSpanColor } from '@parca/functions';
29
+ import { usePopper } from 'react-popper';
30
+ var transparencyValues = [-100, -80, -60, -40, -20, 0, 20, 40, 60, 80, 100];
31
+ var DiffLegendBar = function (_a) {
32
+ var onMouseEnter = _a.onMouseEnter, onMouseLeave = _a.onMouseLeave;
33
+ var isDarkMode = useAppSelector(selectDarkMode);
34
+ return (_jsx("div", __assign({ className: "flex items-center m-2" }, { children: transparencyValues.map(function (value) {
35
+ var valueAsPercentage = value / 100;
36
+ var absoluteValue = Math.abs(valueAsPercentage);
37
+ return (_jsx("div", { onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, className: "w-8 h-4", style: {
38
+ backgroundColor: absoluteValue === 0
39
+ ? getNewSpanColor(isDarkMode)
40
+ : valueAsPercentage > 0
41
+ ? getIncreasedSpanColor(absoluteValue, isDarkMode)
42
+ : getReducedSpanColor(absoluteValue, isDarkMode),
43
+ } }, valueAsPercentage));
44
+ }) })));
45
+ };
46
+ var DiffLegend = function () {
47
+ var _a = useState(false), showLegendTooltip = _a[0], setShowLegendTooltip = _a[1];
48
+ var _b = useState(null), popperElement = _b[0], setPopperElement = _b[1];
49
+ var _c = useState(null), referenceElement = _c[0], setReferenceElement = _c[1];
50
+ var _d = usePopper(referenceElement, popperElement, {
51
+ placement: 'auto-start',
52
+ strategy: 'absolute',
53
+ }), styles = _d.styles, attributes = _d.attributes;
54
+ var handleMouseEnter = function () {
55
+ setShowLegendTooltip(true);
56
+ };
57
+ var handleMouseLeave = function () {
58
+ setShowLegendTooltip(false);
59
+ };
60
+ return (_jsxs("div", __assign({ className: "mt-1 mb-2" }, { children: [_jsxs("div", __assign({ ref: setReferenceElement, className: "flex items-center justify-center" }, { children: [_jsx("span", { children: "Better" }), _jsx(DiffLegendBar, { onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave }), _jsx("span", { children: "Worse" })] })), _jsx(Popover, __assign({ className: "relative" }, { children: function () { return (_jsx(Transition, __assign({ show: showLegendTooltip, as: Fragment, enter: "transition ease-out duration-200", enterFrom: "opacity-0 translate-y-1", enterTo: "opacity-100 translate-y-0", leave: "transition ease-in duration-150", leaveFrom: "opacity-100 translate-y-0", leaveTo: "opacity-0 translate-y-1" }, { children: _jsx(Popover.Panel, __assign({ ref: setPopperElement, style: styles.popper }, attributes.popper, { children: _jsx("div", __assign({ className: "overflow-hidden rounded-lg shadow-lg ring-1 ring-black ring-opacity-5" }, { children: _jsxs("div", __assign({ className: "p-4 bg-gray-50 dark:bg-gray-800" }, { children: [_jsx("div", { className: "flex items-center justify-center" }), _jsx("span", __assign({ className: "block text-sm text-gray-500 dark:text-gray-50" }, { children: "This is a differential icicle graph, where a purple-colored node means unchanged, and the darker the red, the worse the node got, and the darker the green, the better the node got." }))] })) })) })) }))); } }))] })));
61
+ };
62
+ export default DiffLegend;
@@ -0,0 +1,6 @@
1
+ interface Props {
2
+ value: string;
3
+ className?: string;
4
+ }
5
+ declare const ResultBox: ({ value, className }: Props) => JSX.Element;
6
+ export default ResultBox;
@@ -0,0 +1,46 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
+ // Copyright 2022 The Parca Authors
14
+ // Licensed under the Apache License, Version 2.0 (the "License");
15
+ // you may not use this file except in compliance with the License.
16
+ // You may obtain a copy of the License at
17
+ //
18
+ // http://www.apache.org/licenses/LICENSE-2.0
19
+ //
20
+ // Unless required by applicable law or agreed to in writing, software
21
+ // distributed under the License is distributed on an "AS IS" BASIS,
22
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23
+ // See the License for the specific language governing permissions and
24
+ // limitations under the License.
25
+ import { useState } from 'react';
26
+ import cx from 'classnames';
27
+ import { Icon } from '@iconify/react';
28
+ import { Button } from '@parca/components';
29
+ import { CopyToClipboard } from 'react-copy-to-clipboard';
30
+ var timeoutHandle = null;
31
+ var ResultBox = function (_a) {
32
+ var _b;
33
+ var value = _a.value, _c = _a.className, className = _c === void 0 ? '' : _c;
34
+ var _d = useState(false), isCopied = _d[0], setIsCopied = _d[1];
35
+ var onCopy = function () {
36
+ var _a, _b;
37
+ setIsCopied(true);
38
+ (_b = (_a = window.document) === null || _a === void 0 ? void 0 : _a.activeElement) === null || _b === void 0 ? void 0 : _b.blur();
39
+ if (timeoutHandle != null) {
40
+ clearTimeout(timeoutHandle);
41
+ }
42
+ timeoutHandle = setTimeout(function () { return setIsCopied(false); }, 3000);
43
+ };
44
+ return (_jsxs("div", __assign({ className: cx('flex flex-row w-full', (_b = {}, _b[className] = (className === null || className === void 0 ? void 0 : className.length) > 0, _b)) }, { children: [_jsx("span", __assign({ className: "flex justify-center items-center border border-r-0 w-16 rounded-l" }, { children: _jsx(Icon, { icon: "ant-design:link-outlined" }) })), _jsx("input", { type: "text", className: "border text-sm bg-inherit w-full px-1 py-2 flex-grow", value: value, readOnly: true }), _jsx(CopyToClipboard, __assign({ text: value, onCopy: onCopy }, { children: _jsx(Button, __assign({ variant: "link", className: "border border-l-0 w-fit whitespace-nowrap p-4 items-center !text-indigo-600 dark:!text-indigo-400 rounded-none rounded-r" }, { children: isCopied ? 'Copied!' : 'Copy Link' })) }))] })));
45
+ };
46
+ export default ResultBox;
@@ -0,0 +1,7 @@
1
+ import { QueryRequest, QueryServiceClient } from '@parca/client';
2
+ interface Props {
3
+ queryRequest: QueryRequest;
4
+ queryClient: QueryServiceClient;
5
+ }
6
+ declare const ProfileShareButton: ({ queryRequest, queryClient }: Props) => JSX.Element;
7
+ export default ProfileShareButton;