@parca/profile 0.16.22 → 0.16.49
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.
- package/CHANGELOG.md +44 -45
- package/dist/Callgraph/Edge/index.d.ts +1 -0
- package/dist/Callgraph/Node/index.d.ts +2 -1
- package/dist/Callgraph/index.d.ts +1 -0
- package/dist/GraphTooltip/index.d.ts +1 -0
- package/dist/GraphTooltip/index.js +51 -15
- package/dist/IcicleGraph.d.ts +1 -0
- package/dist/IcicleGraph.js +23 -4
- package/dist/MatchersInput/index.d.ts +1 -0
- package/dist/MetricsCircle/index.d.ts +1 -0
- package/dist/MetricsGraph/index.d.ts +1 -0
- package/dist/MetricsGraph/index.js +5 -27
- package/dist/MetricsSeries/index.d.ts +1 -0
- package/dist/ProfileExplorer/ProfileExplorerCompare.d.ts +1 -0
- package/dist/ProfileExplorer/ProfileExplorerSingle.d.ts +1 -0
- package/dist/ProfileExplorer/index.d.ts +1 -0
- package/dist/ProfileIcicleGraph.d.ts +1 -0
- package/dist/ProfileMetricsGraph/index.d.ts +1 -0
- package/dist/ProfileSelector/CompareButton.d.ts +1 -0
- package/dist/ProfileSelector/MergeButton.d.ts +1 -0
- package/dist/ProfileSelector/index.d.ts +1 -0
- package/dist/ProfileSource.d.ts +1 -0
- package/dist/ProfileTypeSelector/index.d.ts +1 -0
- package/dist/ProfileView.d.ts +1 -0
- package/dist/ProfileViewWithData.d.ts +1 -0
- package/dist/TopTable.d.ts +2 -1
- package/dist/components/DiffLegend.d.ts +1 -0
- package/dist/components/ProfileShareButton/ResultBox.d.ts +1 -0
- package/dist/components/ProfileShareButton/index.d.ts +1 -0
- package/dist/styles.css +1 -1
- package/package.json +10 -9
- package/src/GraphTooltip/index.tsx +116 -21
- package/src/IcicleGraph.tsx +25 -5
- package/src/MetricsGraph/index.tsx +6 -31
package/CHANGELOG.md
CHANGED
|
@@ -3,137 +3,136 @@
|
|
|
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.
|
|
6
|
+
## [0.16.49](https://github.com/parca-dev/parca/compare/ui-v0.16.48...ui-v0.16.49) (2022-10-17)
|
|
7
7
|
|
|
8
8
|
**Note:** Version bump only for package @parca/profile
|
|
9
9
|
|
|
10
|
+
## [0.16.48](https://github.com/parca-dev/parca/compare/ui-v0.16.47...ui-v0.16.48) (2022-10-17)
|
|
10
11
|
|
|
12
|
+
**Note:** Version bump only for package @parca/profile
|
|
11
13
|
|
|
14
|
+
## [0.16.44](https://github.com/parca-dev/parca/compare/ui-v0.16.43...ui-v0.16.44) (2022-10-13)
|
|
12
15
|
|
|
16
|
+
**Note:** Version bump only for package @parca/profile
|
|
13
17
|
|
|
14
|
-
## [0.16.
|
|
18
|
+
## [0.16.43](https://github.com/parca-dev/parca/compare/ui-v0.16.42...ui-v0.16.43) (2022-10-13)
|
|
15
19
|
|
|
16
20
|
**Note:** Version bump only for package @parca/profile
|
|
17
21
|
|
|
22
|
+
## [0.16.42](https://github.com/parca-dev/parca/compare/ui-v0.16.41...ui-v0.16.42) (2022-10-13)
|
|
18
23
|
|
|
24
|
+
**Note:** Version bump only for package @parca/profile
|
|
19
25
|
|
|
26
|
+
## [0.16.40](https://github.com/parca-dev/parca/compare/ui-v0.16.39...ui-v0.16.40) (2022-10-10)
|
|
20
27
|
|
|
28
|
+
**Note:** Version bump only for package @parca/profile
|
|
21
29
|
|
|
22
|
-
## [0.16.
|
|
30
|
+
## [0.16.39](https://github.com/parca-dev/parca/compare/ui-v0.16.38...ui-v0.16.39) (2022-10-10)
|
|
23
31
|
|
|
24
32
|
**Note:** Version bump only for package @parca/profile
|
|
25
33
|
|
|
34
|
+
## [0.16.38](https://github.com/parca-dev/parca/compare/ui-v0.16.37...ui-v0.16.38) (2022-10-10)
|
|
26
35
|
|
|
36
|
+
## [0.16.32](https://github.com/parca-dev/parca/compare/ui-v0.16.30...ui-v0.16.32) (2022-10-06)
|
|
27
37
|
|
|
38
|
+
## [0.16.30](https://github.com/parca-dev/parca/compare/ui-v0.16.27...ui-v0.16.30) (2022-10-01)
|
|
28
39
|
|
|
29
|
-
|
|
30
|
-
## [0.16.19](https://github.com/parca-dev/parca/compare/ui-v0.16.18...ui-v0.16.19) (2022-09-26)
|
|
40
|
+
## 0.16.27 (2022-09-29)
|
|
31
41
|
|
|
32
42
|
**Note:** Version bump only for package @parca/profile
|
|
33
43
|
|
|
44
|
+
## [0.16.32](https://github.com/parca-dev/parca/compare/ui-v0.16.31...ui-v0.16.32) (2022-10-06)
|
|
34
45
|
|
|
46
|
+
**Note:** Version bump only for package @parca/profile
|
|
35
47
|
|
|
48
|
+
## [0.16.28](https://github.com/parca-dev/parca/compare/ui-v0.16.27...ui-v0.16.28) (2022-09-30)
|
|
36
49
|
|
|
50
|
+
**Note:** Version bump only for package @parca/profile
|
|
37
51
|
|
|
38
|
-
## [0.16.
|
|
52
|
+
## [0.16.24](https://github.com/parca-dev/parca/compare/ui-v0.16.23...ui-v0.16.24) (2022-09-27)
|
|
39
53
|
|
|
40
|
-
|
|
54
|
+
## [0.16.20](https://github.com/parca-dev/parca/compare/ui-v0.16.19...ui-v0.16.20) (2022-09-27)
|
|
41
55
|
|
|
56
|
+
## [0.16.19](https://github.com/parca-dev/parca/compare/ui-v0.16.18...ui-v0.16.19) (2022-09-26)
|
|
42
57
|
|
|
58
|
+
## [0.16.18](https://github.com/parca-dev/parca/compare/ui-v0.16.17...ui-v0.16.18) (2022-09-26)
|
|
43
59
|
|
|
60
|
+
## [0.16.2](https://github.com/parca-dev/parca/compare/ui-v0.13.4...ui-v0.16.2) (2022-09-14)
|
|
44
61
|
|
|
62
|
+
## [0.13.4](https://github.com/parca-dev/parca/compare/ui-v0.13.3...ui-v0.13.4) (2022-06-07)
|
|
45
63
|
|
|
46
|
-
|
|
64
|
+
**Note:** Version bump only for package @parca/profile
|
|
65
|
+
|
|
66
|
+
## [0.16.23](https://github.com/parca-dev/parca/compare/ui-v0.16.20...ui-v0.16.23) (2022-09-27)
|
|
47
67
|
|
|
48
68
|
**Note:** Version bump only for package @parca/profile
|
|
49
69
|
|
|
70
|
+
## [0.16.22](https://github.com/parca-dev/parca/compare/ui-v0.16.20...ui-v0.16.22) (2022-09-27)
|
|
50
71
|
|
|
72
|
+
**Note:** Version bump only for package @parca/profile
|
|
51
73
|
|
|
74
|
+
## [0.16.21](https://github.com/parca-dev/parca/compare/ui-v0.16.20...ui-v0.16.21) (2022-09-27)
|
|
52
75
|
|
|
76
|
+
**Note:** Version bump only for package @parca/profile
|
|
53
77
|
|
|
54
|
-
## [0.
|
|
78
|
+
## [0.16.20](https://github.com/parca-dev/parca/compare/ui-v0.16.19...ui-v0.16.20) (2022-09-27)
|
|
55
79
|
|
|
56
80
|
**Note:** Version bump only for package @parca/profile
|
|
57
81
|
|
|
82
|
+
## [0.16.19](https://github.com/parca-dev/parca/compare/ui-v0.16.18...ui-v0.16.19) (2022-09-26)
|
|
58
83
|
|
|
84
|
+
**Note:** Version bump only for package @parca/profile
|
|
59
85
|
|
|
86
|
+
## [0.16.16](https://github.com/parca-dev/parca/compare/ui-v0.16.15...ui-v0.16.16) (2022-09-26)
|
|
60
87
|
|
|
88
|
+
**Note:** Version bump only for package @parca/profile
|
|
61
89
|
|
|
62
|
-
|
|
90
|
+
# [0.16.0](https://github.com/parca-dev/parca/compare/ui-v0.15.26...ui-v0.16.0) (2022-09-13)
|
|
63
91
|
|
|
92
|
+
**Note:** Version bump only for package @parca/profile
|
|
64
93
|
|
|
94
|
+
## [0.15.25](https://github.com/parca-dev/parca/compare/ui-v0.15.24...ui-v0.15.25) (2022-09-13)
|
|
65
95
|
|
|
66
|
-
|
|
96
|
+
**Note:** Version bump only for package @parca/profile
|
|
67
97
|
|
|
98
|
+
## [0.15.24](https://github.com/parca-dev/parca/compare/ui-v0.15.23...ui-v0.15.24) (2022-09-13)
|
|
68
99
|
|
|
100
|
+
## [0.15.19](https://github.com/parca-dev/parca/compare/ui-v0.15.17...ui-v0.15.19) (2022-09-08)
|
|
69
101
|
|
|
70
102
|
## [0.15.17](https://github.com/parca-dev/parca/compare/ui-v0.15.10...ui-v0.15.17) (2022-09-07)
|
|
71
103
|
|
|
72
|
-
|
|
73
104
|
### Bug Fixes
|
|
74
105
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
106
|
+
- **ui:** type all the things (string mode) ([e91ac9d](https://github.com/parca-dev/parca/commit/e91ac9deb8a200ed3c9a9c5d81ae71e13d49466e))
|
|
78
107
|
|
|
79
108
|
## 0.15.10 (2022-08-30)
|
|
80
109
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
110
|
## [0.15.19](https://github.com/parca-dev/parca/compare/ui-v0.15.18...ui-v0.15.19) (2022-09-08)
|
|
86
111
|
|
|
87
|
-
|
|
88
|
-
|
|
89
112
|
## [0.15.17](https://github.com/parca-dev/parca/compare/ui-v0.15.10...ui-v0.15.17) (2022-09-07)
|
|
90
113
|
|
|
91
|
-
|
|
92
|
-
|
|
93
114
|
## [0.15.10](https://github.com/parca-dev/parca/compare/ui-v0.15.8...ui-v0.15.10) (2022-08-30)
|
|
94
115
|
|
|
95
116
|
**Note:** Version bump only for package @parca/profile
|
|
96
117
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
118
|
## [0.15.18](https://github.com/parca-dev/parca/compare/ui-v0.15.17...ui-v0.15.18) (2022-09-08)
|
|
102
119
|
|
|
103
|
-
|
|
104
|
-
|
|
105
120
|
## [0.15.10](https://github.com/parca-dev/parca/compare/ui-v0.15.8...ui-v0.15.10) (2022-08-30)
|
|
106
121
|
|
|
107
122
|
**Note:** Version bump only for package @parca/profile
|
|
108
123
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
124
|
## [0.15.17](https://github.com/parca-dev/parca/compare/ui-v0.15.16...ui-v0.15.17) (2022-09-07)
|
|
114
125
|
|
|
115
|
-
|
|
116
|
-
|
|
117
126
|
## [0.15.11](https://github.com/parca-dev/parca/compare/ui-v0.15.10...ui-v0.15.11) (2022-09-01)
|
|
118
127
|
|
|
119
|
-
|
|
120
|
-
|
|
121
128
|
## [0.15.10](https://github.com/parca-dev/parca/compare/ui-v0.15.2...ui-v0.15.10) (2022-08-30)
|
|
122
129
|
|
|
123
|
-
|
|
124
|
-
|
|
125
130
|
## [0.15.2](https://github.com/parca-dev/parca/compare/ui-v0.15.1...ui-v0.15.2) (2022-08-25)
|
|
126
131
|
|
|
127
|
-
|
|
128
|
-
|
|
129
132
|
## 0.15.1 (2022-08-25)
|
|
130
133
|
|
|
131
134
|
**Note:** Version bump only for package @parca/profile
|
|
132
135
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
136
|
## [0.15.11](https://github.com/parca-dev/parca/compare/ui-v0.15.10...ui-v0.15.11) (2022-09-01)
|
|
138
137
|
|
|
139
138
|
**Note:** Version bump only for package @parca/profile
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
1
2
|
export interface INode {
|
|
2
3
|
id: number;
|
|
3
4
|
x: number;
|
|
@@ -15,5 +16,5 @@ interface Props {
|
|
|
15
16
|
setHoveredNode: (node: INode | null) => void;
|
|
16
17
|
nodeRadius: number;
|
|
17
18
|
}
|
|
18
|
-
declare const Node: ({ node, hoveredNode, setHoveredNode, nodeRadius, }: Props) => JSX.Element;
|
|
19
|
+
declare const Node: ({ node, hoveredNode, setHoveredNode, nodeRadius: defaultRadius, }: Props) => JSX.Element;
|
|
19
20
|
export default Node;
|
|
@@ -21,10 +21,24 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
21
21
|
return t;
|
|
22
22
|
};
|
|
23
23
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
// Copyright 2022 The Parca Authors
|
|
25
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
26
|
+
// you may not use this file except in compliance with the License.
|
|
27
|
+
// You may obtain a copy of the License at
|
|
28
|
+
//
|
|
29
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
30
|
+
//
|
|
31
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
32
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
33
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
34
|
+
// See the License for the specific language governing permissions and
|
|
35
|
+
// limitations under the License.
|
|
36
|
+
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
|
26
37
|
import { useState, useEffect } from 'react';
|
|
27
38
|
import { usePopper } from 'react-popper';
|
|
39
|
+
import { getLastItem, valueFormatter } from '@parca/functions';
|
|
40
|
+
import useIsShiftDown from '@parca/components/src/hooks/useIsShiftDown';
|
|
41
|
+
import { hexifyAddress } from '../';
|
|
28
42
|
var virtualElement = {
|
|
29
43
|
getBoundingClientRect: function () {
|
|
30
44
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
@@ -55,21 +69,37 @@ function generateGetBoundingClientRect(contextElement, x, y) {
|
|
|
55
69
|
};
|
|
56
70
|
}
|
|
57
71
|
var TooltipMetaInfo = function (_a) {
|
|
58
|
-
var _b, _c, _d, _e
|
|
59
|
-
var hoveringNode = _a.hoveringNode;
|
|
72
|
+
var _b, _c, _d, _e;
|
|
73
|
+
var hoveringNode = _a.hoveringNode, onCopy = _a.onCopy;
|
|
60
74
|
if (hoveringNode.meta === undefined)
|
|
61
75
|
return _jsx(_Fragment, {});
|
|
76
|
+
var getTextForFile = function (hoveringNode) {
|
|
77
|
+
var _a, _b, _c, _d;
|
|
78
|
+
if (hoveringNode.meta === undefined)
|
|
79
|
+
return '<unknown>';
|
|
80
|
+
// @ts-expect-error
|
|
81
|
+
return "".concat(hoveringNode.meta.function.filename, " ").concat(((_a = hoveringNode.meta.line) === null || _a === void 0 ? void 0 : _a.line) !== undefined && ((_b = hoveringNode.meta.line) === null || _b === void 0 ? void 0 : _b.line) !== '0'
|
|
82
|
+
? " +".concat(hoveringNode.meta.line.line.toString())
|
|
83
|
+
: "".concat(((_c = hoveringNode.meta.function) === null || _c === void 0 ? void 0 : _c.startLine) !== undefined &&
|
|
84
|
+
((_d = hoveringNode.meta.function) === null || _d === void 0 ? void 0 : _d.startLine) !== '0'
|
|
85
|
+
? " +".concat(hoveringNode.meta.function.startLine)
|
|
86
|
+
: ''));
|
|
87
|
+
};
|
|
62
88
|
return (_jsxs(_Fragment, { children: [((_b = hoveringNode.meta.function) === null || _b === void 0 ? void 0 : _b.filename) !== undefined &&
|
|
63
|
-
((_c = hoveringNode.meta.function) === null || _c === void 0 ? void 0 : _c.filename) !== '' && (_jsxs("tr", { children: [_jsx("td", __assign({ className: "w-1/5" }, { children: "File" })),
|
|
64
|
-
|
|
65
|
-
: "".concat(((_f = hoveringNode.meta.function) === null || _f === void 0 ? void 0 : _f.startLine) !== undefined &&
|
|
66
|
-
((_g = hoveringNode.meta.function) === null || _g === void 0 ? void 0 : _g.startLine) !== '0'
|
|
67
|
-
? " +".concat(hoveringNode.meta.function.startLine)
|
|
68
|
-
: '')] }))] })), ((_h = hoveringNode.meta.location) === null || _h === void 0 ? void 0 : _h.address) !== undefined &&
|
|
69
|
-
((_j = hoveringNode.meta.location) === null || _j === void 0 ? void 0 : _j.address) !== '0' && (_jsxs("tr", { children: [_jsx("td", __assign({ className: "w-1/5" }, { children: "Address" })), _jsx("td", __assign({ className: "w-4/5 break-all" }, { children: ' 0x' + hoveringNode.meta.location.address.toString() }))] })), hoveringNode.meta.mapping !== undefined && hoveringNode.meta.mapping.file !== '' && (_jsxs("tr", { children: [_jsx("td", __assign({ className: "w-1/5" }, { children: "Binary" })), _jsx("td", __assign({ className: "w-4/5 break-all" }, { children: getLastItem(hoveringNode.meta.mapping.file) }))] }))] }));
|
|
89
|
+
((_c = hoveringNode.meta.function) === null || _c === void 0 ? void 0 : _c.filename) !== '' && (_jsxs("tr", { children: [_jsx("td", __assign({ className: "w-1/5" }, { children: "File" })), _jsx("td", __assign({ className: "w-4/5 break-all" }, { children: _jsx(CopyToClipboard, __assign({ onCopy: onCopy, text: getTextForFile(hoveringNode) }, { children: _jsx("button", __assign({ className: "cursor-pointer text-left" }, { children: getTextForFile(hoveringNode) })) })) }))] })), ((_d = hoveringNode.meta.location) === null || _d === void 0 ? void 0 : _d.address) !== undefined &&
|
|
90
|
+
((_e = hoveringNode.meta.location) === null || _e === void 0 ? void 0 : _e.address) !== '0' && (_jsxs("tr", { children: [_jsx("td", __assign({ className: "w-1/5" }, { children: "Address" })), _jsx("td", __assign({ className: "w-4/5 break-all" }, { children: _jsx(CopyToClipboard, __assign({ onCopy: onCopy, text: ' 0x' + hoveringNode.meta.location.address.toString() }, { children: _jsx("button", __assign({ className: "cursor-pointer" }, { children: ' 0x' + hoveringNode.meta.location.address.toString() })) })) }))] })), hoveringNode.meta.mapping !== undefined && hoveringNode.meta.mapping.file !== '' && (_jsxs("tr", { children: [_jsx("td", __assign({ className: "w-1/5" }, { children: "Binary" })), _jsx("td", __assign({ className: "w-4/5 break-all" }, { children: _jsx(CopyToClipboard, __assign({ onCopy: onCopy, text: hoveringNode.meta.mapping.file }, { children: _jsx("button", __assign({ className: "cursor-pointer" }, { children: getLastItem(hoveringNode.meta.mapping.file) })) })) }))] })), hoveringNode.meta.mapping !== undefined && hoveringNode.meta.mapping.buildId !== '' && (_jsxs("tr", { children: [_jsx("td", __assign({ className: "w-1/5" }, { children: "Build Id" })), _jsx("td", __assign({ className: "w-4/5 break-all" }, { children: _jsx(CopyToClipboard, __assign({ onCopy: onCopy, text: hoveringNode.meta.mapping.buildId }, { children: _jsx("button", __assign({ className: "cursor-pointer" }, { children: getLastItem(hoveringNode.meta.mapping.buildId) })) })) }))] }))] }));
|
|
70
91
|
};
|
|
92
|
+
var timeoutHandle = null;
|
|
71
93
|
var GraphTooltipContent = function (_a) {
|
|
72
94
|
var hoveringNode = _a.hoveringNode, unit = _a.unit, total = _a.total, isFixed = _a.isFixed;
|
|
95
|
+
var _b = useState(false), isCopied = _b[0], setIsCopied = _b[1];
|
|
96
|
+
var onCopy = function () {
|
|
97
|
+
setIsCopied(true);
|
|
98
|
+
if (timeoutHandle !== null) {
|
|
99
|
+
clearTimeout(timeoutHandle);
|
|
100
|
+
}
|
|
101
|
+
timeoutHandle = setTimeout(function () { return setIsCopied(false); }, 3000);
|
|
102
|
+
};
|
|
73
103
|
var hoveringNodeCumulative = parseFloat(hoveringNode.cumulative);
|
|
74
104
|
var diff = hoveringNode.diff === undefined ? 0 : parseFloat(hoveringNode.diff);
|
|
75
105
|
var prevValue = hoveringNodeCumulative - diff;
|
|
@@ -78,10 +108,13 @@ var GraphTooltipContent = function (_a) {
|
|
|
78
108
|
var diffValueText = diffSign + valueFormatter(diff, unit, 1);
|
|
79
109
|
var diffPercentageText = diffSign + (diffRatio * 100).toFixed(2) + '%';
|
|
80
110
|
var diffText = "".concat(diffValueText, " (").concat(diffPercentageText, ")");
|
|
81
|
-
var metaRows = hoveringNode.meta === undefined ? _jsx(_Fragment, {}) : _jsx(TooltipMetaInfo, { hoveringNode: hoveringNode });
|
|
111
|
+
var metaRows = hoveringNode.meta === undefined ? (_jsx(_Fragment, {})) : (_jsx(TooltipMetaInfo, { onCopy: onCopy, hoveringNode: hoveringNode }));
|
|
112
|
+
var getTextForCumulative = function (hoveringNodeCumulative) {
|
|
113
|
+
return "".concat(valueFormatter(hoveringNodeCumulative, unit, 2), " (\n ").concat(((hoveringNodeCumulative * 100) / total).toFixed(2), "%)");
|
|
114
|
+
};
|
|
82
115
|
return (_jsx("div", __assign({ className: "flex ".concat(isFixed ? 'w-full h-36' : '') }, { children: _jsx("div", __assign({ className: "m-auto w-full ".concat(isFixed ? 'w-full h-36' : '') }, { children: _jsx("div", __assign({ className: "border-gray-300 dark:border-gray-500 bg-gray-50 dark:bg-gray-900 rounded-lg p-3 shadow-lg opacity-90", style: { borderWidth: 1 } }, { children: _jsx("div", __assign({ className: "flex flex-row" }, { children: _jsxs("div", __assign({ className: "ml-2 mr-6" }, { children: [_jsx("span", __assign({ className: "font-semibold break-all" }, { children: hoveringNode.meta === undefined ? (_jsx("p", { children: "root" })) : (_jsx(_Fragment, { children: hoveringNode.meta.function !== undefined &&
|
|
83
|
-
hoveringNode.meta.function.name !== '' ? (_jsx("
|
|
84
|
-
parseInt(hoveringNode.meta.location.address, 10) !== 0 ? (_jsx("
|
|
116
|
+
hoveringNode.meta.function.name !== '' ? (_jsx(CopyToClipboard, __assign({ onCopy: onCopy, text: hoveringNode.meta.function.name }, { children: _jsx("button", __assign({ className: "cursor-pointer text-left" }, { children: hoveringNode.meta.function.name })) }))) : (_jsx(_Fragment, { children: hoveringNode.meta.location !== undefined &&
|
|
117
|
+
parseInt(hoveringNode.meta.location.address, 10) !== 0 ? (_jsx(CopyToClipboard, __assign({ onCopy: onCopy, text: hexifyAddress(hoveringNode.meta.location.address) }, { children: _jsx("button", __assign({ className: "cursor-pointer text-left" }, { children: hexifyAddress(hoveringNode.meta.location.address) })) }))) : (_jsx("p", { children: "unknown" })) })) })) })), _jsx("span", __assign({ className: "text-gray-700 dark:text-gray-300 my-2" }, { children: _jsx("table", __assign({ className: "table-fixed" }, { children: _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", __assign({ className: "w-1/5" }, { children: "Cumulative" })), _jsx("td", __assign({ className: "w-4/5" }, { children: _jsx(CopyToClipboard, __assign({ onCopy: onCopy, text: getTextForCumulative(hoveringNodeCumulative) }, { children: _jsx("button", __assign({ className: "cursor-pointer" }, { children: getTextForCumulative(hoveringNodeCumulative) })) })) }))] }), hoveringNode.diff !== undefined && diff !== 0 && (_jsxs("tr", { children: [_jsx("td", __assign({ className: "w-1/5" }, { children: "Diff" })), _jsx("td", __assign({ className: "w-4/5" }, { children: _jsx(CopyToClipboard, __assign({ onCopy: onCopy, text: diffText }, { children: _jsx("button", __assign({ className: "cursor-pointer" }, { children: diffText })) })) }))] })), metaRows] }) })) })), _jsx("span", __assign({ className: "block text-gray-500 text-xs mt-2" }, { children: isCopied ? 'Copied!' : 'Hold shift and click on a value to copy.' }))] })) })) })) })) })));
|
|
85
118
|
};
|
|
86
119
|
var GraphTooltip = function (_a) {
|
|
87
120
|
var x = _a.x, y = _a.y, unit = _a.unit, total = _a.total, hoveringNode = _a.hoveringNode, contextElement = _a.contextElement, _b = _a.isFixed, isFixed = _b === void 0 ? false : _b, _c = _a.virtualContextElement, virtualContextElement = _c === void 0 ? true : _c;
|
|
@@ -106,12 +139,15 @@ var GraphTooltip = function (_a) {
|
|
|
106
139
|
],
|
|
107
140
|
}), styles = _e.styles, attributes = _e.attributes, popperProps = __rest(_e, ["styles", "attributes"]);
|
|
108
141
|
var update = popperProps.update;
|
|
142
|
+
var isShiftDown = useIsShiftDown();
|
|
109
143
|
useEffect(function () {
|
|
110
144
|
if (contextElement != null) {
|
|
145
|
+
if (isShiftDown)
|
|
146
|
+
return;
|
|
111
147
|
virtualElement.getBoundingClientRect = generateGetBoundingClientRect(contextElement, x, y);
|
|
112
148
|
void (update === null || update === void 0 ? void 0 : update());
|
|
113
149
|
}
|
|
114
|
-
}, [x, y, contextElement, update]);
|
|
150
|
+
}, [x, y, contextElement, update, isShiftDown]);
|
|
115
151
|
if (hoveringNode === undefined || hoveringNode == null)
|
|
116
152
|
return _jsx(_Fragment, {});
|
|
117
153
|
return isFixed ? (_jsx(GraphTooltipContent, { hoveringNode: hoveringNode, unit: unit, total: total, isFixed: isFixed })) : (_jsx("div", __assign({ ref: setPopperElement, style: styles.popper }, attributes.popper, { children: _jsx(GraphTooltipContent, { hoveringNode: hoveringNode, unit: unit, total: total, isFixed: isFixed }) })));
|
package/dist/IcicleGraph.d.ts
CHANGED
package/dist/IcicleGraph.js
CHANGED
|
@@ -29,6 +29,7 @@ import { scaleLinear } from 'd3-scale';
|
|
|
29
29
|
import GraphTooltip from './GraphTooltip';
|
|
30
30
|
import { getLastItem, diffColor, isSearchMatch } from '@parca/functions';
|
|
31
31
|
import { useAppSelector, selectDarkMode, selectSearchNodeString } from '@parca/store';
|
|
32
|
+
import useIsShiftDown from '@parca/components/src/hooks/useIsShiftDown';
|
|
32
33
|
import { hexifyAddress } from './utils';
|
|
33
34
|
var RowHeight = 26;
|
|
34
35
|
var icicleRectStyles = {
|
|
@@ -70,6 +71,7 @@ export function nodeLabel(node) {
|
|
|
70
71
|
export function IcicleGraphNodes(_a) {
|
|
71
72
|
var data = _a.data, x = _a.x, y = _a.y, xScale = _a.xScale, total = _a.total, totalWidth = _a.totalWidth, level = _a.level, setHoveringNode = _a.setHoveringNode, path = _a.path, setCurPath = _a.setCurPath, curPath = _a.curPath;
|
|
72
73
|
var isDarkMode = useAppSelector(selectDarkMode);
|
|
74
|
+
var isShiftDown = useIsShiftDown();
|
|
73
75
|
var nodes = curPath.length === 0 ? data : data.filter(function (d) { return d != null && curPath[0] === nodeLabel(d); });
|
|
74
76
|
var nextLevel = level + 1;
|
|
75
77
|
return (_jsx("g", __assign({ transform: "translate(".concat(x, ", ").concat(y, ")") }, { children: nodes.map(function (d, i) {
|
|
@@ -94,8 +96,16 @@ export function IcicleGraphNodes(_a) {
|
|
|
94
96
|
var newXScale = nextCurPath.length === 0 && curPath.length === 1
|
|
95
97
|
? scaleLinear().domain([0, cumulative]).range([0, totalWidth])
|
|
96
98
|
: xScale;
|
|
97
|
-
var onMouseEnter = function () {
|
|
98
|
-
|
|
99
|
+
var onMouseEnter = function () {
|
|
100
|
+
if (isShiftDown)
|
|
101
|
+
return;
|
|
102
|
+
setHoveringNode(d);
|
|
103
|
+
};
|
|
104
|
+
var onMouseLeave = function () {
|
|
105
|
+
if (isShiftDown)
|
|
106
|
+
return;
|
|
107
|
+
setHoveringNode(undefined);
|
|
108
|
+
};
|
|
99
109
|
return (_jsxs(React.Fragment, { children: [_jsx(IcicleRect, { x: xStart, y: 0, width: width, height: RowHeight, name: name, color: color, onClick: onClick, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, curPath: curPath }, "rect-".concat(key)), data !== undefined && data.length > 0 && (_jsx(IcicleGraphNodes, { data: d.children, x: xStart, y: RowHeight, xScale: newXScale, total: total, totalWidth: totalWidth, level: nextLevel, setHoveringNode: setHoveringNode, path: nextPath, curPath: nextCurPath, setCurPath: setCurPath }, "node-".concat(key)))] }, "node-".concat(key)));
|
|
100
110
|
}) })));
|
|
101
111
|
}
|
|
@@ -103,12 +113,21 @@ var MemoizedIcicleGraphNodes = React.memo(IcicleGraphNodes);
|
|
|
103
113
|
export function IcicleGraphRootNode(_a) {
|
|
104
114
|
var node = _a.node, xScale = _a.xScale, total = _a.total, totalWidth = _a.totalWidth, setHoveringNode = _a.setHoveringNode, setCurPath = _a.setCurPath, curPath = _a.curPath;
|
|
105
115
|
var isDarkMode = useAppSelector(selectDarkMode);
|
|
116
|
+
var isShiftDown = useIsShiftDown();
|
|
106
117
|
var cumulative = parseFloat(node.cumulative);
|
|
107
118
|
var diff = parseFloat(node.diff);
|
|
108
119
|
var color = diffColor(diff, cumulative, isDarkMode);
|
|
109
120
|
var onClick = function () { return setCurPath([]); };
|
|
110
|
-
var onMouseEnter = function () {
|
|
111
|
-
|
|
121
|
+
var onMouseEnter = function () {
|
|
122
|
+
if (isShiftDown)
|
|
123
|
+
return;
|
|
124
|
+
setHoveringNode(node);
|
|
125
|
+
};
|
|
126
|
+
var onMouseLeave = function () {
|
|
127
|
+
if (isShiftDown)
|
|
128
|
+
return;
|
|
129
|
+
setHoveringNode(undefined);
|
|
130
|
+
};
|
|
112
131
|
var path = [];
|
|
113
132
|
return (_jsxs("g", __assign({ transform: 'translate(0, 0)' }, { children: [_jsx(IcicleRect, { x: 0, y: 0, width: totalWidth, height: RowHeight, name: 'root', color: color, onClick: onClick, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, curPath: curPath }), _jsx(MemoizedIcicleGraphNodes, { data: node.children, x: 0, y: RowHeight, xScale: xScale, total: total, totalWidth: totalWidth, level: 0, setHoveringNode: setHoveringNode, path: path, curPath: curPath, setCurPath: setCurPath })] })));
|
|
114
133
|
}
|
|
@@ -35,8 +35,6 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
35
35
|
// limitations under the License.
|
|
36
36
|
import { useEffect, useRef, useState } from 'react';
|
|
37
37
|
import * as d3 from 'd3';
|
|
38
|
-
import MetricsSeries from '../MetricsSeries';
|
|
39
|
-
import MetricsCircle from '../MetricsCircle';
|
|
40
38
|
import { pointer } from 'd3-selection';
|
|
41
39
|
import { formatForTimespan } from '@parca/functions/time';
|
|
42
40
|
import { timeFormat } from '..';
|
|
@@ -46,6 +44,9 @@ import { usePopper } from 'react-popper';
|
|
|
46
44
|
import { valueFormatter, formatDate } from '@parca/functions';
|
|
47
45
|
import { DateTimeRange } from '@parca/components';
|
|
48
46
|
import { useContainerDimensions } from '@parca/dynamicsize';
|
|
47
|
+
import useIsShiftDown from '@parca/components/src/hooks/useIsShiftDown';
|
|
48
|
+
import MetricsSeries from '../MetricsSeries';
|
|
49
|
+
import MetricsCircle from '../MetricsCircle';
|
|
49
50
|
var MetricsGraph = function (_a) {
|
|
50
51
|
var data = _a.data, from = _a.from, to = _a.to, profile = _a.profile, onSampleClick = _a.onSampleClick, onLabelClick = _a.onLabelClick, setTimeRange = _a.setTimeRange, sampleUnit = _a.sampleUnit;
|
|
51
52
|
var _b = useContainerDimensions(), ref = _b.ref, dimensions = _b.dimensions;
|
|
@@ -133,30 +134,8 @@ export var RawMetricsGraph = function (_a) {
|
|
|
133
134
|
var _c = useState(false), hovering = _c[0], setHovering = _c[1];
|
|
134
135
|
var _d = useState(-1), relPos = _d[0], setRelPos = _d[1];
|
|
135
136
|
var _e = useState([0, 0]), pos = _e[0], setPos = _e[1];
|
|
136
|
-
var _f = useState(false), freezeTooltip = _f[0], setFreezeTooltip = _f[1];
|
|
137
137
|
var metricPointRef = useRef(null);
|
|
138
|
-
|
|
139
|
-
var handleShiftDown = function (event) {
|
|
140
|
-
if (event.keyCode === 16) {
|
|
141
|
-
setFreezeTooltip(true);
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
window.addEventListener('keydown', handleShiftDown);
|
|
145
|
-
return function () {
|
|
146
|
-
window.removeEventListener('keydown', handleShiftDown);
|
|
147
|
-
};
|
|
148
|
-
}, []);
|
|
149
|
-
useEffect(function () {
|
|
150
|
-
var handleShiftUp = function (event) {
|
|
151
|
-
if (event.keyCode === 16) {
|
|
152
|
-
setFreezeTooltip(false);
|
|
153
|
-
}
|
|
154
|
-
};
|
|
155
|
-
window.addEventListener('keyup', handleShiftUp);
|
|
156
|
-
return function () {
|
|
157
|
-
window.removeEventListener('keyup', handleShiftUp);
|
|
158
|
-
};
|
|
159
|
-
}, []);
|
|
138
|
+
var isShiftDown = useIsShiftDown();
|
|
160
139
|
var time = parseFloat(profile === null || profile === void 0 ? void 0 : profile.HistoryParams().time);
|
|
161
140
|
if (width === undefined || width == null) {
|
|
162
141
|
width = 0;
|
|
@@ -283,7 +262,7 @@ export var RawMetricsGraph = function (_a) {
|
|
|
283
262
|
var xCoordinateWithoutMargin = xCoordinate - margin;
|
|
284
263
|
var yCoordinate = rel[1];
|
|
285
264
|
var yCoordinateWithoutMargin = yCoordinate - margin;
|
|
286
|
-
if (!
|
|
265
|
+
if (!isShiftDown) {
|
|
287
266
|
throttledSetPos([xCoordinateWithoutMargin, yCoordinateWithoutMargin]);
|
|
288
267
|
}
|
|
289
268
|
};
|
|
@@ -336,7 +315,6 @@ export var RawMetricsGraph = function (_a) {
|
|
|
336
315
|
var selected = findSelectedProfile();
|
|
337
316
|
return (_jsxs(_Fragment, { children: [highlighted != null && hovering && !dragging && pos[0] !== 0 && pos[1] !== 0 && (_jsx("div", __assign({ onMouseMove: onMouseMove, onMouseEnter: function () { return setHovering(true); }, onMouseLeave: function () { return setHovering(false); } }, { children: _jsx(MetricsTooltip, { x: pos[0] + margin, y: pos[1] + margin, highlighted: highlighted, onLabelClick: onLabelClick, contextElement: graph.current, sampleUnit: sampleUnit }) }))), _jsx("div", __assign({ ref: graph, onMouseEnter: function () {
|
|
338
317
|
setHovering(true);
|
|
339
|
-
setFreezeTooltip(false);
|
|
340
318
|
}, onMouseLeave: function () { return setHovering(false); } }, { children: _jsxs("svg", __assign({ width: "".concat(width, "px"), height: "".concat(height + margin, "px"), onMouseDown: onMouseDown, onMouseUp: onMouseUp, onMouseMove: onMouseMove }, { children: [_jsx("g", __assign({ transform: "translate(".concat(margin, ", 0)") }, { children: dragging && (_jsx("g", __assign({ className: "zoom-time-rect" }, { children: _jsx("rect", { className: "bar", x: pos[0] - relPos < 0 ? pos[0] : relPos, y: 0, height: height, width: Math.abs(pos[0] - relPos), fill: 'rgba(0, 0, 0, 0.125)' }) }))) })), _jsxs("g", __assign({ transform: "translate(".concat(margin, ", ").concat(margin, ")") }, { children: [_jsx("g", __assign({ className: "lines fill-transparent" }, { children: series.map(function (s, i) { return (_jsx("g", __assign({ className: "line" }, { children: _jsx(MetricsSeries, { data: s, line: l, color: color(i.toString()), strokeWidth: hovering && highlighted != null && i === highlighted.seriesIndex
|
|
341
319
|
? lineStrokeHover
|
|
342
320
|
: lineStroke, xScale: xScale, yScale: yScale }) }), i)); }) })), hovering && highlighted != null && (_jsx("g", __assign({ className: "circle-group", ref: metricPointRef, style: { fill: color(highlighted.seriesIndex.toString()) } }, { children: _jsx(MetricsCircle, { cx: highlighted.x, cy: highlighted.y }) }))), selected != null && (_jsx("g", __assign({ className: "circle-group", style: (selected === null || selected === void 0 ? void 0 : selected.seriesIndex) != null
|
package/dist/ProfileSource.d.ts
CHANGED
package/dist/ProfileView.d.ts
CHANGED
package/dist/TopTable.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
1
2
|
import { TopNodeMeta, Top } from '@parca/client';
|
|
2
3
|
import './TopTable.styles.css';
|
|
3
4
|
interface TopTableProps {
|
|
@@ -5,5 +6,5 @@ interface TopTableProps {
|
|
|
5
6
|
sampleUnit: string;
|
|
6
7
|
}
|
|
7
8
|
export declare const RowLabel: (meta: TopNodeMeta | undefined) => string;
|
|
8
|
-
export declare const TopTable: ({ data, sampleUnit }: TopTableProps) => JSX.Element;
|
|
9
|
+
export declare const TopTable: ({ data: top, sampleUnit }: TopTableProps) => JSX.Element;
|
|
9
10
|
export default TopTable;
|
package/dist/styles.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
/*! tailwindcss v3.1.8 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::-webkit-backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.absolute{position:absolute}.relative{position:relative}.left-0{left:0}.right-0{right:0}.z-50{z-index:50}.z-10{z-index:10}.m-auto{margin:auto}.m-0{margin:0}.m-2{margin:.5rem}.my-2{margin-bottom:.5rem;margin-top:.5rem}.my-20{margin-bottom:5rem;margin-top:5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mr-3{margin-right:.75rem}.ml-auto{margin-left:auto}.ml-2{margin-left:.5rem}.mr-6{margin-right:1.5rem}.mt-1{margin-top:.25rem}.mb-2{margin-bottom:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-8{margin-top:2rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.table{display:table}.grid{display:grid}.h-36{height:9rem}.h-1{height:.25rem}.h-4{height:1rem}.max-h-\[400px\]{max-height:400px}.w-full{width:100%}.w-2\/5{width:40%}.w-auto{width:auto}.w-1\/2{width:50%}.w-\[150px\]{width:150px}.w-1\/5{width:20%}.w-4\/5{width:80%}.w-fit{width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.w-1\/4{width:25%}.w-3\/4{width:75%}.w-40{width:10rem}.w-8{width:2rem}.w-16{width:4rem}.w-\[420px\]{width:420px}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.flex-grow{flex-grow:1}.table-auto{table-layout:auto}.table-fixed{table-layout:fixed}.translate-y-1{--tw-translate-y:0.25rem}.translate-y-0,.translate-y-1{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-0{--tw-translate-y:0px}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-pointer{cursor:pointer}.cursor-not-allowed{cursor:not-allowed}.cursor-default{cursor:default}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-row{flex-direction:row}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(1rem*var(--tw-space-x-reverse))}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.25rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.25rem*var(--tw-space-x-reverse))}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.5rem*var(--tw-space-x-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-bottom-width:calc(1px*var(--tw-divide-y-reverse));border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)))}.divide-gray-200>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(229 231 235/var(--tw-divide-opacity))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-scroll{overflow-x:scroll}.text-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.break-all{word-break:break-all}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded{border-radius:.25rem}.rounded-none{border-radius:0}.rounded-l{border-bottom-left-radius:.25rem;border-top-left-radius:.25rem}.rounded-r{border-bottom-right-radius:.25rem;border-top-right-radius:.25rem}.rounded-tr-none{border-top-right-radius:0}.rounded-br-none{border-bottom-right-radius:0}.rounded-tl-none{border-top-left-radius:0}.rounded-bl-none{border-bottom-left-radius:0}.border{border-width:1px}.border-l-0{border-left-width:0}.border-r-0{border-right-width:0}.border-b{border-bottom-width:1px}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.border-red-400{--tw-border-opacity:1;border-color:rgb(248 113 113/var(--tw-border-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-indigo-600{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity))}.bg-transparent{background-color:transparent}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(254 226 226/var(--tw-bg-opacity))}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}.bg-inherit{background-color:inherit}.fill-\[\#161616\]{fill:#161616}.fill-transparent{fill:transparent}.fill-current{fill:currentColor}.p-10{padding:2.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.px-2{padding-left:.5rem;padding-right:.5rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.px-8{padding-left:2rem;padding-right:2rem}.py-1\.5{padding-bottom:.375rem;padding-top:.375rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.py-20{padding-bottom:5rem;padding-top:5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-1{padding-left:.25rem;padding-right:.25rem}.pt-2{padding-top:.5rem}.pb-2{padding-bottom:.5rem}.pl-2{padding-left:.5rem}.pr-2{padding-right:.5rem}.pb-4{padding-bottom:1rem}.pl-3{padding-left:.75rem}.pr-9{padding-right:2.25rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-middle{vertical-align:middle}.text-xs{font-size:.75rem;line-height:1rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-base{font-size:1rem;line-height:1.5rem}.font-bold{font-weight:700}.font-semibold{font-weight:600}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-100{--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity))}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity))}.\!text-indigo-600{--tw-text-opacity:1!important;color:rgb(79 70 229/var(--tw-text-opacity))!important}.opacity-90{opacity:.9}.opacity-100{opacity:1}.opacity-0{opacity:0}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-black{--tw-ring-opacity:1;--tw-ring-color:rgb(0 0 0/var(--tw-ring-opacity))}.ring-opacity-5{--tw-ring-opacity:0.05}.blur{--tw-blur:blur(8px)}.blur,.invert{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.invert{--tw-invert:invert(100%)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-100{transition-duration:.1s}.duration-200{transition-duration:.2s}.duration-150{transition-duration:.15s}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.hover\:bg-\[\#62626212\]:hover{background-color:#62626212}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-indigo-800:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(55 48 163/var(--tw-ring-opacity))}.dark .dark\:divide-gray-700>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(55 65 81/var(--tw-divide-opacity))}.dark .dark\:border-gray-500{--tw-border-opacity:1;border-color:rgb(107 114 128/var(--tw-border-opacity))}.dark .dark\:border-gray-600{--tw-border-opacity:1;border-color:rgb(75 85 99/var(--tw-border-opacity))}.dark .dark\:bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.dark .dark\:bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.dark .dark\:bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}.dark .dark\:fill-\[\#ffffff\]{fill:#fff}.dark .dark\:text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.dark .dark\:text-gray-300{--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}.dark .dark\:text-gray-50{--tw-text-opacity:1;color:rgb(249 250 251/var(--tw-text-opacity))}.dark .dark\:\!text-indigo-400{--tw-text-opacity:1!important;color:rgb(129 140 248/var(--tw-text-opacity))!important}.dark .dark\:hover\:bg-\[\#ffffff12\]:hover{background-color:#ffffff12}@media (min-width:640px){.sm\:inline{display:inline}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}
|
|
1
|
+
/*! tailwindcss v3.1.8 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.absolute{position:absolute}.relative{position:relative}.left-0{left:0}.right-0{right:0}.z-50{z-index:50}.z-10{z-index:10}.m-auto{margin:auto}.m-0{margin:0}.m-2{margin:.5rem}.my-2{margin-bottom:.5rem;margin-top:.5rem}.my-20{margin-bottom:5rem;margin-top:5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mr-3{margin-right:.75rem}.ml-auto{margin-left:auto}.ml-2{margin-left:.5rem}.mr-6{margin-right:1.5rem}.mt-2{margin-top:.5rem}.mt-1{margin-top:.25rem}.mb-2{margin-bottom:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-8{margin-top:2rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.table{display:table}.grid{display:grid}.h-36{height:9rem}.h-1{height:.25rem}.h-4{height:1rem}.max-h-\[400px\]{max-height:400px}.w-full{width:100%}.w-2\/5{width:40%}.w-auto{width:auto}.w-1\/2{width:50%}.w-\[150px\]{width:150px}.w-1\/5{width:20%}.w-4\/5{width:80%}.w-fit{width:-moz-fit-content;width:fit-content}.w-1\/4{width:25%}.w-3\/4{width:75%}.w-40{width:10rem}.w-8{width:2rem}.w-16{width:4rem}.w-\[420px\]{width:420px}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.flex-grow{flex-grow:1}.table-auto{table-layout:auto}.table-fixed{table-layout:fixed}.translate-y-1{--tw-translate-y:0.25rem}.translate-y-0,.translate-y-1{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-0{--tw-translate-y:0px}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-pointer{cursor:pointer}.cursor-not-allowed{cursor:not-allowed}.cursor-default{cursor:default}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-row{flex-direction:row}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(1rem*var(--tw-space-x-reverse))}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.25rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.25rem*var(--tw-space-x-reverse))}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.5rem*var(--tw-space-x-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-bottom-width:calc(1px*var(--tw-divide-y-reverse));border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)))}.divide-gray-200>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(229 231 235/var(--tw-divide-opacity))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-scroll{overflow-x:scroll}.text-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.break-all{word-break:break-all}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded{border-radius:.25rem}.rounded-none{border-radius:0}.rounded-l{border-bottom-left-radius:.25rem;border-top-left-radius:.25rem}.rounded-r{border-bottom-right-radius:.25rem;border-top-right-radius:.25rem}.rounded-tr-none{border-top-right-radius:0}.rounded-br-none{border-bottom-right-radius:0}.rounded-tl-none{border-top-left-radius:0}.rounded-bl-none{border-bottom-left-radius:0}.border{border-width:1px}.border-l-0{border-left-width:0}.border-r-0{border-right-width:0}.border-b{border-bottom-width:1px}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.border-red-400{--tw-border-opacity:1;border-color:rgb(248 113 113/var(--tw-border-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-indigo-600{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity))}.bg-transparent{background-color:transparent}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(254 226 226/var(--tw-bg-opacity))}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}.bg-inherit{background-color:inherit}.fill-\[\#161616\]{fill:#161616}.fill-transparent{fill:transparent}.fill-current{fill:currentColor}.p-10{padding:2.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.px-2{padding-left:.5rem;padding-right:.5rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.px-8{padding-left:2rem;padding-right:2rem}.py-1\.5{padding-bottom:.375rem;padding-top:.375rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.py-20{padding-bottom:5rem;padding-top:5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-1{padding-left:.25rem;padding-right:.25rem}.pt-2{padding-top:.5rem}.pb-2{padding-bottom:.5rem}.pl-2{padding-left:.5rem}.pr-2{padding-right:.5rem}.pb-4{padding-bottom:1rem}.pl-3{padding-left:.75rem}.pr-9{padding-right:2.25rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-middle{vertical-align:middle}.text-xs{font-size:.75rem;line-height:1rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-base{font-size:1rem;line-height:1.5rem}.font-bold{font-weight:700}.font-semibold{font-weight:600}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-gray-100{--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity))}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity))}.\!text-indigo-600{--tw-text-opacity:1!important;color:rgb(79 70 229/var(--tw-text-opacity))!important}.opacity-90{opacity:.9}.opacity-100{opacity:1}.opacity-0{opacity:0}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-black{--tw-ring-opacity:1;--tw-ring-color:rgb(0 0 0/var(--tw-ring-opacity))}.ring-opacity-5{--tw-ring-opacity:0.05}.blur{--tw-blur:blur(8px)}.blur,.invert{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.invert{--tw-invert:invert(100%)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-100{transition-duration:.1s}.duration-200{transition-duration:.2s}.duration-150{transition-duration:.15s}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.hover\:bg-\[\#62626212\]:hover{background-color:#62626212}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-indigo-800:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(55 48 163/var(--tw-ring-opacity))}.dark .dark\:divide-gray-700>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(55 65 81/var(--tw-divide-opacity))}.dark .dark\:border-gray-500{--tw-border-opacity:1;border-color:rgb(107 114 128/var(--tw-border-opacity))}.dark .dark\:border-gray-600{--tw-border-opacity:1;border-color:rgb(75 85 99/var(--tw-border-opacity))}.dark .dark\:bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.dark .dark\:bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.dark .dark\:bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}.dark .dark\:fill-\[\#ffffff\]{fill:#fff}.dark .dark\:text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.dark .dark\:text-gray-300{--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}.dark .dark\:text-gray-50{--tw-text-opacity:1;color:rgb(249 250 251/var(--tw-text-opacity))}.dark .dark\:\!text-indigo-400{--tw-text-opacity:1!important;color:rgb(129 140 248/var(--tw-text-opacity))!important}.dark .dark\:hover\:bg-\[\#ffffff12\]:hover{background-color:#ffffff12}@media (min-width:640px){.sm\:inline{display:inline}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parca/profile",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.49",
|
|
4
4
|
"description": "Profile viewing libraries",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@iconify/react": "^3.2.2",
|
|
7
|
-
"@parca/client": "^0.16.
|
|
8
|
-
"@parca/components": "^0.16.
|
|
9
|
-
"@parca/dynamicsize": "^0.16.
|
|
10
|
-
"@parca/functions": "^0.16.
|
|
11
|
-
"@parca/parser": "^0.16.
|
|
12
|
-
"@parca/store": "^0.16.
|
|
7
|
+
"@parca/client": "^0.16.49",
|
|
8
|
+
"@parca/components": "^0.16.49",
|
|
9
|
+
"@parca/dynamicsize": "^0.16.49",
|
|
10
|
+
"@parca/functions": "^0.16.49",
|
|
11
|
+
"@parca/parser": "^0.16.49",
|
|
12
|
+
"@parca/store": "^0.16.49",
|
|
13
13
|
"d3-scale": "^4.0.2",
|
|
14
14
|
"d3-selection": "3.0.0",
|
|
15
15
|
"react-copy-to-clipboard": "^5.1.0"
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"scripts": {
|
|
22
22
|
"test": "jest --coverage --config ../../../jest.config.js ./src/*",
|
|
23
23
|
"prepublish": "yarn build",
|
|
24
|
-
"build": "tsc && tailwindcss -o dist/styles.css --minify && cp src/*.css ./dist/"
|
|
24
|
+
"build": "tsc && tailwindcss -o dist/styles.css --minify && cp src/*.css ./dist/",
|
|
25
|
+
"watch": "tsc-watch --onSuccess 'tailwindcss -o dist/styles.css --minify'"
|
|
25
26
|
},
|
|
26
27
|
"keywords": [],
|
|
27
28
|
"author": "",
|
|
@@ -30,5 +31,5 @@
|
|
|
30
31
|
"access": "public",
|
|
31
32
|
"registry": "https://registry.npmjs.org/"
|
|
32
33
|
},
|
|
33
|
-
"gitHead": "
|
|
34
|
+
"gitHead": "2d1d93e9e75a15dfe18875acc6924f8f2e16206f"
|
|
34
35
|
}
|
|
@@ -11,11 +11,14 @@
|
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
|
|
14
|
+
import {CopyToClipboard} from 'react-copy-to-clipboard';
|
|
15
|
+
import {useState, useEffect} from 'react';
|
|
16
|
+
import {usePopper} from 'react-popper';
|
|
17
|
+
|
|
14
18
|
import {CallgraphNode, FlamegraphNode, FlamegraphRootNode} from '@parca/client';
|
|
15
19
|
import {getLastItem, valueFormatter} from '@parca/functions';
|
|
20
|
+
import useIsShiftDown from '@parca/components/src/hooks/useIsShiftDown';
|
|
16
21
|
import {hexifyAddress} from '../';
|
|
17
|
-
import {useState, useEffect} from 'react';
|
|
18
|
-
import {usePopper} from 'react-popper';
|
|
19
22
|
|
|
20
23
|
interface GraphTooltipProps {
|
|
21
24
|
x: number;
|
|
@@ -55,9 +58,31 @@ function generateGetBoundingClientRect(contextElement: Element, x = 0, y = 0): (
|
|
|
55
58
|
} as DOMRect);
|
|
56
59
|
}
|
|
57
60
|
|
|
58
|
-
const TooltipMetaInfo = ({
|
|
61
|
+
const TooltipMetaInfo = ({
|
|
62
|
+
hoveringNode,
|
|
63
|
+
onCopy,
|
|
64
|
+
}: {
|
|
65
|
+
hoveringNode: FlamegraphNode;
|
|
66
|
+
onCopy: () => void;
|
|
67
|
+
}): JSX.Element => {
|
|
59
68
|
if (hoveringNode.meta === undefined) return <></>;
|
|
60
69
|
|
|
70
|
+
const getTextForFile = (hoveringNode: FlamegraphNode): string => {
|
|
71
|
+
if (hoveringNode.meta === undefined) return '<unknown>';
|
|
72
|
+
|
|
73
|
+
// @ts-expect-error
|
|
74
|
+
return `${hoveringNode.meta.function.filename} ${
|
|
75
|
+
hoveringNode.meta.line?.line !== undefined && hoveringNode.meta.line?.line !== '0'
|
|
76
|
+
? ` +${hoveringNode.meta.line.line.toString()}`
|
|
77
|
+
: `${
|
|
78
|
+
hoveringNode.meta.function?.startLine !== undefined &&
|
|
79
|
+
hoveringNode.meta.function?.startLine !== '0'
|
|
80
|
+
? ` +${hoveringNode.meta.function.startLine}`
|
|
81
|
+
: ''
|
|
82
|
+
}`
|
|
83
|
+
}`;
|
|
84
|
+
};
|
|
85
|
+
|
|
61
86
|
return (
|
|
62
87
|
<>
|
|
63
88
|
{hoveringNode.meta.function?.filename !== undefined &&
|
|
@@ -65,15 +90,9 @@ const TooltipMetaInfo = ({hoveringNode}: {hoveringNode: FlamegraphNode}): JSX.El
|
|
|
65
90
|
<tr>
|
|
66
91
|
<td className="w-1/5">File</td>
|
|
67
92
|
<td className="w-4/5 break-all">
|
|
68
|
-
{hoveringNode
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
: `${
|
|
72
|
-
hoveringNode.meta.function?.startLine !== undefined &&
|
|
73
|
-
hoveringNode.meta.function?.startLine !== '0'
|
|
74
|
-
? ` +${hoveringNode.meta.function.startLine}`
|
|
75
|
-
: ''
|
|
76
|
-
}`}
|
|
93
|
+
<CopyToClipboard onCopy={onCopy} text={getTextForFile(hoveringNode)}>
|
|
94
|
+
<button className="cursor-pointer text-left">{getTextForFile(hoveringNode)}</button>
|
|
95
|
+
</CopyToClipboard>
|
|
77
96
|
</td>
|
|
78
97
|
</tr>
|
|
79
98
|
)}
|
|
@@ -82,14 +101,39 @@ const TooltipMetaInfo = ({hoveringNode}: {hoveringNode: FlamegraphNode}): JSX.El
|
|
|
82
101
|
<tr>
|
|
83
102
|
<td className="w-1/5">Address</td>
|
|
84
103
|
<td className="w-4/5 break-all">
|
|
85
|
-
|
|
104
|
+
<CopyToClipboard
|
|
105
|
+
onCopy={onCopy}
|
|
106
|
+
text={' 0x' + hoveringNode.meta.location.address.toString()}
|
|
107
|
+
>
|
|
108
|
+
<button className="cursor-pointer">
|
|
109
|
+
{' 0x' + hoveringNode.meta.location.address.toString()}
|
|
110
|
+
</button>
|
|
111
|
+
</CopyToClipboard>
|
|
86
112
|
</td>
|
|
87
113
|
</tr>
|
|
88
114
|
)}
|
|
89
115
|
{hoveringNode.meta.mapping !== undefined && hoveringNode.meta.mapping.file !== '' && (
|
|
90
116
|
<tr>
|
|
91
117
|
<td className="w-1/5">Binary</td>
|
|
92
|
-
<td className="w-4/5 break-all">
|
|
118
|
+
<td className="w-4/5 break-all">
|
|
119
|
+
<CopyToClipboard onCopy={onCopy} text={hoveringNode.meta.mapping.file}>
|
|
120
|
+
<button className="cursor-pointer">
|
|
121
|
+
{getLastItem(hoveringNode.meta.mapping.file)}
|
|
122
|
+
</button>
|
|
123
|
+
</CopyToClipboard>
|
|
124
|
+
</td>
|
|
125
|
+
</tr>
|
|
126
|
+
)}
|
|
127
|
+
{hoveringNode.meta.mapping !== undefined && hoveringNode.meta.mapping.buildId !== '' && (
|
|
128
|
+
<tr>
|
|
129
|
+
<td className="w-1/5">Build Id</td>
|
|
130
|
+
<td className="w-4/5 break-all">
|
|
131
|
+
<CopyToClipboard onCopy={onCopy} text={hoveringNode.meta.mapping.buildId}>
|
|
132
|
+
<button className="cursor-pointer">
|
|
133
|
+
{getLastItem(hoveringNode.meta.mapping.buildId)}
|
|
134
|
+
</button>
|
|
135
|
+
</CopyToClipboard>
|
|
136
|
+
</td>
|
|
93
137
|
</tr>
|
|
94
138
|
)}
|
|
95
139
|
</>
|
|
@@ -101,6 +145,8 @@ export interface HoveringNode extends CallgraphNode, FlamegraphRootNode {
|
|
|
101
145
|
meta?: {[key: string]: any};
|
|
102
146
|
}
|
|
103
147
|
|
|
148
|
+
let timeoutHandle: ReturnType<typeof setTimeout> | null = null;
|
|
149
|
+
|
|
104
150
|
const GraphTooltipContent = ({
|
|
105
151
|
hoveringNode,
|
|
106
152
|
unit,
|
|
@@ -112,6 +158,17 @@ const GraphTooltipContent = ({
|
|
|
112
158
|
total: number;
|
|
113
159
|
isFixed: boolean;
|
|
114
160
|
}): JSX.Element => {
|
|
161
|
+
const [isCopied, setIsCopied] = useState<boolean>(false);
|
|
162
|
+
|
|
163
|
+
const onCopy = (): void => {
|
|
164
|
+
setIsCopied(true);
|
|
165
|
+
|
|
166
|
+
if (timeoutHandle !== null) {
|
|
167
|
+
clearTimeout(timeoutHandle);
|
|
168
|
+
}
|
|
169
|
+
timeoutHandle = setTimeout(() => setIsCopied(false), 3000);
|
|
170
|
+
};
|
|
171
|
+
|
|
115
172
|
const hoveringNodeCumulative = parseFloat(hoveringNode.cumulative);
|
|
116
173
|
const diff = hoveringNode.diff === undefined ? 0 : parseFloat(hoveringNode.diff);
|
|
117
174
|
const prevValue = hoveringNodeCumulative - diff;
|
|
@@ -121,7 +178,16 @@ const GraphTooltipContent = ({
|
|
|
121
178
|
const diffPercentageText = diffSign + (diffRatio * 100).toFixed(2) + '%';
|
|
122
179
|
const diffText = `${diffValueText} (${diffPercentageText})`;
|
|
123
180
|
const metaRows =
|
|
124
|
-
hoveringNode.meta === undefined ?
|
|
181
|
+
hoveringNode.meta === undefined ? (
|
|
182
|
+
<></>
|
|
183
|
+
) : (
|
|
184
|
+
<TooltipMetaInfo onCopy={onCopy} hoveringNode={hoveringNode} />
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
const getTextForCumulative = (hoveringNodeCumulative: number): string => {
|
|
188
|
+
return `${valueFormatter(hoveringNodeCumulative, unit, 2)} (
|
|
189
|
+
${((hoveringNodeCumulative * 100) / total).toFixed(2)}%)`;
|
|
190
|
+
};
|
|
125
191
|
|
|
126
192
|
return (
|
|
127
193
|
<div className={`flex ${isFixed ? 'w-full h-36' : ''}`}>
|
|
@@ -139,12 +205,23 @@ const GraphTooltipContent = ({
|
|
|
139
205
|
<>
|
|
140
206
|
{hoveringNode.meta.function !== undefined &&
|
|
141
207
|
hoveringNode.meta.function.name !== '' ? (
|
|
142
|
-
<
|
|
208
|
+
<CopyToClipboard onCopy={onCopy} text={hoveringNode.meta.function.name}>
|
|
209
|
+
<button className="cursor-pointer text-left">
|
|
210
|
+
{hoveringNode.meta.function.name}
|
|
211
|
+
</button>
|
|
212
|
+
</CopyToClipboard>
|
|
143
213
|
) : (
|
|
144
214
|
<>
|
|
145
215
|
{hoveringNode.meta.location !== undefined &&
|
|
146
216
|
parseInt(hoveringNode.meta.location.address, 10) !== 0 ? (
|
|
147
|
-
<
|
|
217
|
+
<CopyToClipboard
|
|
218
|
+
onCopy={onCopy}
|
|
219
|
+
text={hexifyAddress(hoveringNode.meta.location.address)}
|
|
220
|
+
>
|
|
221
|
+
<button className="cursor-pointer text-left">
|
|
222
|
+
{hexifyAddress(hoveringNode.meta.location.address)}
|
|
223
|
+
</button>
|
|
224
|
+
</CopyToClipboard>
|
|
148
225
|
) : (
|
|
149
226
|
<p>unknown</p>
|
|
150
227
|
)}
|
|
@@ -158,21 +235,36 @@ const GraphTooltipContent = ({
|
|
|
158
235
|
<tbody>
|
|
159
236
|
<tr>
|
|
160
237
|
<td className="w-1/5">Cumulative</td>
|
|
238
|
+
|
|
161
239
|
<td className="w-4/5">
|
|
162
|
-
|
|
163
|
-
|
|
240
|
+
<CopyToClipboard
|
|
241
|
+
onCopy={onCopy}
|
|
242
|
+
text={getTextForCumulative(hoveringNodeCumulative)}
|
|
243
|
+
>
|
|
244
|
+
<button className="cursor-pointer">
|
|
245
|
+
{getTextForCumulative(hoveringNodeCumulative)}
|
|
246
|
+
</button>
|
|
247
|
+
</CopyToClipboard>
|
|
164
248
|
</td>
|
|
165
249
|
</tr>
|
|
166
250
|
{hoveringNode.diff !== undefined && diff !== 0 && (
|
|
167
251
|
<tr>
|
|
168
252
|
<td className="w-1/5">Diff</td>
|
|
169
|
-
<td className="w-4/5">
|
|
253
|
+
<td className="w-4/5">
|
|
254
|
+
<CopyToClipboard onCopy={onCopy} text={diffText}>
|
|
255
|
+
<button className="cursor-pointer">{diffText}</button>
|
|
256
|
+
</CopyToClipboard>
|
|
257
|
+
</td>
|
|
170
258
|
</tr>
|
|
171
259
|
)}
|
|
172
260
|
{metaRows}
|
|
173
261
|
</tbody>
|
|
174
262
|
</table>
|
|
175
263
|
</span>
|
|
264
|
+
|
|
265
|
+
<span className="block text-gray-500 text-xs mt-2">
|
|
266
|
+
{isCopied ? 'Copied!' : 'Hold shift and click on a value to copy.'}
|
|
267
|
+
</span>
|
|
176
268
|
</div>
|
|
177
269
|
</div>
|
|
178
270
|
</div>
|
|
@@ -218,13 +310,16 @@ const GraphTooltip = ({
|
|
|
218
310
|
);
|
|
219
311
|
|
|
220
312
|
const update = popperProps.update;
|
|
313
|
+
const isShiftDown = useIsShiftDown();
|
|
221
314
|
|
|
222
315
|
useEffect(() => {
|
|
223
316
|
if (contextElement != null) {
|
|
317
|
+
if (isShiftDown) return;
|
|
318
|
+
|
|
224
319
|
virtualElement.getBoundingClientRect = generateGetBoundingClientRect(contextElement, x, y);
|
|
225
320
|
void update?.();
|
|
226
321
|
}
|
|
227
|
-
}, [x, y, contextElement, update]);
|
|
322
|
+
}, [x, y, contextElement, update, isShiftDown]);
|
|
228
323
|
|
|
229
324
|
if (hoveringNode === undefined || hoveringNode == null) return <></>;
|
|
230
325
|
|
package/src/IcicleGraph.tsx
CHANGED
|
@@ -16,11 +16,12 @@ import React, {MouseEvent, useEffect, useRef, useState} from 'react';
|
|
|
16
16
|
import {throttle} from 'lodash';
|
|
17
17
|
import {pointer} from 'd3-selection';
|
|
18
18
|
import {scaleLinear} from 'd3-scale';
|
|
19
|
+
|
|
19
20
|
import {Flamegraph, FlamegraphNode, FlamegraphRootNode} from '@parca/client';
|
|
20
21
|
import GraphTooltip from './GraphTooltip';
|
|
21
22
|
import {getLastItem, diffColor, isSearchMatch} from '@parca/functions';
|
|
22
23
|
import {useAppSelector, selectDarkMode, selectSearchNodeString} from '@parca/store';
|
|
23
|
-
|
|
24
|
+
import useIsShiftDown from '@parca/components/src/hooks/useIsShiftDown';
|
|
24
25
|
import {hexifyAddress} from './utils';
|
|
25
26
|
import type {HoveringNode} from './GraphTooltip';
|
|
26
27
|
|
|
@@ -161,6 +162,7 @@ export function IcicleGraphNodes({
|
|
|
161
162
|
curPath,
|
|
162
163
|
}: IcicleGraphNodesProps): JSX.Element {
|
|
163
164
|
const isDarkMode = useAppSelector(selectDarkMode);
|
|
165
|
+
const isShiftDown = useIsShiftDown();
|
|
164
166
|
|
|
165
167
|
const nodes =
|
|
166
168
|
curPath.length === 0 ? data : data.filter(d => d != null && curPath[0] === nodeLabel(d));
|
|
@@ -200,8 +202,16 @@ export function IcicleGraphNodes({
|
|
|
200
202
|
? scaleLinear().domain([0, cumulative]).range([0, totalWidth])
|
|
201
203
|
: xScale;
|
|
202
204
|
|
|
203
|
-
const onMouseEnter = (): void =>
|
|
204
|
-
|
|
205
|
+
const onMouseEnter = (): void => {
|
|
206
|
+
if (isShiftDown) return;
|
|
207
|
+
|
|
208
|
+
setHoveringNode(d);
|
|
209
|
+
};
|
|
210
|
+
const onMouseLeave = (): void => {
|
|
211
|
+
if (isShiftDown) return;
|
|
212
|
+
|
|
213
|
+
setHoveringNode(undefined);
|
|
214
|
+
};
|
|
205
215
|
|
|
206
216
|
return (
|
|
207
217
|
<React.Fragment key={`node-${key}`}>
|
|
@@ -253,14 +263,24 @@ export function IcicleGraphRootNode({
|
|
|
253
263
|
curPath,
|
|
254
264
|
}: IcicleGraphRootNodeProps): JSX.Element {
|
|
255
265
|
const isDarkMode = useAppSelector(selectDarkMode);
|
|
266
|
+
const isShiftDown = useIsShiftDown();
|
|
256
267
|
|
|
257
268
|
const cumulative = parseFloat(node.cumulative);
|
|
258
269
|
const diff = parseFloat(node.diff);
|
|
259
270
|
const color = diffColor(diff, cumulative, isDarkMode);
|
|
260
271
|
|
|
261
272
|
const onClick = (): void => setCurPath([]);
|
|
262
|
-
const onMouseEnter = (): void =>
|
|
263
|
-
|
|
273
|
+
const onMouseEnter = (): void => {
|
|
274
|
+
if (isShiftDown) return;
|
|
275
|
+
|
|
276
|
+
setHoveringNode(node);
|
|
277
|
+
};
|
|
278
|
+
const onMouseLeave = (): void => {
|
|
279
|
+
if (isShiftDown) return;
|
|
280
|
+
|
|
281
|
+
setHoveringNode(undefined);
|
|
282
|
+
};
|
|
283
|
+
|
|
264
284
|
const path: string[] = [];
|
|
265
285
|
|
|
266
286
|
return (
|
|
@@ -13,8 +13,6 @@
|
|
|
13
13
|
|
|
14
14
|
import React, {useEffect, useRef, useState} from 'react';
|
|
15
15
|
import * as d3 from 'd3';
|
|
16
|
-
import MetricsSeries from '../MetricsSeries';
|
|
17
|
-
import MetricsCircle from '../MetricsCircle';
|
|
18
16
|
import {pointer} from 'd3-selection';
|
|
19
17
|
import {formatForTimespan} from '@parca/functions/time';
|
|
20
18
|
import {SingleProfileSelection, timeFormat} from '..';
|
|
@@ -26,6 +24,10 @@ import type {VirtualElement} from '@popperjs/core';
|
|
|
26
24
|
import {valueFormatter, formatDate} from '@parca/functions';
|
|
27
25
|
import {DateTimeRange} from '@parca/components';
|
|
28
26
|
import {useContainerDimensions} from '@parca/dynamicsize';
|
|
27
|
+
import useIsShiftDown from '@parca/components/src/hooks/useIsShiftDown';
|
|
28
|
+
|
|
29
|
+
import MetricsSeries from '../MetricsSeries';
|
|
30
|
+
import MetricsCircle from '../MetricsCircle';
|
|
29
31
|
|
|
30
32
|
interface RawMetricsGraphProps {
|
|
31
33
|
data: MetricsSeriesPb[];
|
|
@@ -244,34 +246,8 @@ export const RawMetricsGraph = ({
|
|
|
244
246
|
const [hovering, setHovering] = useState(false);
|
|
245
247
|
const [relPos, setRelPos] = useState(-1);
|
|
246
248
|
const [pos, setPos] = useState([0, 0]);
|
|
247
|
-
const [freezeTooltip, setFreezeTooltip] = useState(false);
|
|
248
249
|
const metricPointRef = useRef(null);
|
|
249
|
-
|
|
250
|
-
useEffect(() => {
|
|
251
|
-
const handleShiftDown = (event: {keyCode: number}): void => {
|
|
252
|
-
if (event.keyCode === 16) {
|
|
253
|
-
setFreezeTooltip(true);
|
|
254
|
-
}
|
|
255
|
-
};
|
|
256
|
-
window.addEventListener('keydown', handleShiftDown);
|
|
257
|
-
|
|
258
|
-
return () => {
|
|
259
|
-
window.removeEventListener('keydown', handleShiftDown);
|
|
260
|
-
};
|
|
261
|
-
}, []);
|
|
262
|
-
|
|
263
|
-
useEffect(() => {
|
|
264
|
-
const handleShiftUp = (event: {keyCode: number}): void => {
|
|
265
|
-
if (event.keyCode === 16) {
|
|
266
|
-
setFreezeTooltip(false);
|
|
267
|
-
}
|
|
268
|
-
};
|
|
269
|
-
window.addEventListener('keyup', handleShiftUp);
|
|
270
|
-
|
|
271
|
-
return () => {
|
|
272
|
-
window.removeEventListener('keyup', handleShiftUp);
|
|
273
|
-
};
|
|
274
|
-
}, []);
|
|
250
|
+
const isShiftDown = useIsShiftDown();
|
|
275
251
|
|
|
276
252
|
const time: number = parseFloat(profile?.HistoryParams().time);
|
|
277
253
|
|
|
@@ -431,7 +407,7 @@ export const RawMetricsGraph = ({
|
|
|
431
407
|
const yCoordinate = rel[1];
|
|
432
408
|
const yCoordinateWithoutMargin = yCoordinate - margin;
|
|
433
409
|
|
|
434
|
-
if (!
|
|
410
|
+
if (!isShiftDown) {
|
|
435
411
|
throttledSetPos([xCoordinateWithoutMargin, yCoordinateWithoutMargin]);
|
|
436
412
|
}
|
|
437
413
|
};
|
|
@@ -505,7 +481,6 @@ export const RawMetricsGraph = ({
|
|
|
505
481
|
ref={graph}
|
|
506
482
|
onMouseEnter={function () {
|
|
507
483
|
setHovering(true);
|
|
508
|
-
setFreezeTooltip(false);
|
|
509
484
|
}}
|
|
510
485
|
onMouseLeave={() => setHovering(false)}
|
|
511
486
|
>
|