@parca/profile 0.16.110 → 0.16.112
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 +8 -0
- package/dist/Callgraph/index.js +5 -2
- package/dist/ProfileIcicleGraph/IcicleGraph/IcicleGraphNodes.js +12 -3
- package/dist/ProfileIcicleGraph/IcicleGraph/index.js +13 -5
- package/dist/ProfileIcicleGraph/IcicleGraph/useColoredGraph.js +5 -4
- package/dist/ProfileIcicleGraph/IcicleGraph/utils.d.ts +3 -2
- package/dist/ProfileIcicleGraph/IcicleGraph/utils.js +13 -9
- package/dist/TopTable/index.js +19 -7
- package/dist/styles.css +1 -1
- package/package.json +4 -4
- package/src/Callgraph/index.tsx +15 -4
- package/src/ProfileIcicleGraph/IcicleGraph/IcicleGraphNodes.tsx +11 -4
- package/src/ProfileIcicleGraph/IcicleGraph/index.tsx +20 -8
- package/src/ProfileIcicleGraph/IcicleGraph/useColoredGraph.ts +9 -7
- package/src/ProfileIcicleGraph/IcicleGraph/utils.ts +15 -10
- package/src/TopTable/index.tsx +47 -15
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [0.16.112](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.111...@parca/profile@0.16.112) (2023-02-09)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @parca/profile
|
|
9
|
+
|
|
10
|
+
## [0.16.111](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.109...@parca/profile@0.16.111) (2023-02-09)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @parca/profile
|
|
13
|
+
|
|
6
14
|
## [0.16.110](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.109...@parca/profile@0.16.110) (2023-02-08)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @parca/profile
|
package/dist/Callgraph/index.js
CHANGED
|
@@ -59,10 +59,11 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
59
59
|
// See the License for the specific language governing permissions and
|
|
60
60
|
// limitations under the License.
|
|
61
61
|
import { useState, useEffect, useRef } from 'react';
|
|
62
|
+
import cx from 'classnames';
|
|
62
63
|
import graphviz from 'graphviz-wasm';
|
|
63
64
|
import * as d3 from 'd3';
|
|
64
65
|
import { Stage, Layer, Rect, Arrow, Text, Label } from 'react-konva';
|
|
65
|
-
import { Button } from '@parca/components';
|
|
66
|
+
import { Button, useURLState } from '@parca/components';
|
|
66
67
|
import { jsonToDot, getCurvePoints } from './utils';
|
|
67
68
|
import { isSearchMatch, selectQueryParam } from '@parca/functions';
|
|
68
69
|
import Tooltip from '../GraphTooltip';
|
|
@@ -109,6 +110,8 @@ var Callgraph = function (_a) {
|
|
|
109
110
|
var rawNodes = graph.nodes, total = graph.cumulative;
|
|
110
111
|
var currentSearchString = (_b = selectQueryParam('search_string')) !== null && _b !== void 0 ? _b : '';
|
|
111
112
|
var isSearchEmpty = currentSearchString === undefined || currentSearchString === '';
|
|
113
|
+
var rawDashboardItems = useURLState({ param: 'dashboard_items' })[0];
|
|
114
|
+
var dashboardItems = rawDashboardItems;
|
|
112
115
|
useEffect(function () {
|
|
113
116
|
var getDataWithPositions = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
114
117
|
var dataAsDot, jsonGraph;
|
|
@@ -218,6 +221,6 @@ var Callgraph = function (_a) {
|
|
|
218
221
|
? true
|
|
219
222
|
: isSearchMatch(currentSearchString, node.functionName);
|
|
220
223
|
return (_jsx(Node, { node: node, hoveredNode: hoveredNode, setHoveredNode: setHoveredNode, isCurrentSearchMatch: isCurrentSearchMatch }, "node-".concat(node._gvid)));
|
|
221
|
-
})] })) })), _jsx(Tooltip, { hoveringNode: rawNodes.find(function (n) { return n.id === (hoveredNode === null || hoveredNode === void 0 ? void 0 : hoveredNode.data.id); }), unit: sampleUnit, total: +total, isFixed: false, x: (_c = hoveredNode === null || hoveredNode === void 0 ? void 0 : hoveredNode.mouseX) !== null && _c !== void 0 ? _c : 0, y: (_d = hoveredNode === null || hoveredNode === void 0 ? void 0 : hoveredNode.mouseY) !== null && _d !== void 0 ? _d : 0, contextElement: containerRef.current }), stage.scale.x !== 1 && (_jsx(
|
|
224
|
+
})] })) })), _jsx(Tooltip, { hoveringNode: rawNodes.find(function (n) { return n.id === (hoveredNode === null || hoveredNode === void 0 ? void 0 : hoveredNode.data.id); }), unit: sampleUnit, total: +total, isFixed: false, x: (_c = hoveredNode === null || hoveredNode === void 0 ? void 0 : hoveredNode.mouseX) !== null && _c !== void 0 ? _c : 0, y: (_d = hoveredNode === null || hoveredNode === void 0 ? void 0 : hoveredNode.mouseY) !== null && _d !== void 0 ? _d : 0, contextElement: containerRef.current }), stage.scale.x !== 1 && (_jsx("div", __assign({ className: cx(dashboardItems.length > 1 ? 'left-[25px]' : 'left-0', 'w-auto absolute top-[-46px]') }, { children: _jsx(Button, __assign({ variant: "neutral", onClick: resetZoom }, { children: "Reset Zoom" })) })))] })) })));
|
|
222
225
|
};
|
|
223
226
|
export default Callgraph;
|
|
@@ -26,15 +26,21 @@ import React, { useMemo } from 'react';
|
|
|
26
26
|
import cx from 'classnames';
|
|
27
27
|
import { scaleLinear } from 'd3-scale';
|
|
28
28
|
import { isSearchMatch } from '@parca/functions';
|
|
29
|
+
import { useAppSelector, selectBinaries } from '@parca/store';
|
|
29
30
|
import { nodeLabel } from './utils';
|
|
30
31
|
import useNodeColor from './useNodeColor';
|
|
31
32
|
import { useKeyDown } from '@parca/components';
|
|
32
33
|
export var RowHeight = 26;
|
|
33
34
|
export var IcicleGraphNodes = React.memo(function IcicleGraphNodes(_a) {
|
|
34
35
|
var data = _a.data, strings = _a.strings, mappings = _a.mappings, locations = _a.locations, functions = _a.functions, 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, searchString = _a.searchString, compareMode = _a.compareMode;
|
|
36
|
+
var binaries = useAppSelector(selectBinaries);
|
|
35
37
|
var nodes = curPath.length === 0
|
|
36
38
|
? data
|
|
37
|
-
: data.filter(function (d) {
|
|
39
|
+
: data.filter(function (d) {
|
|
40
|
+
return d != null &&
|
|
41
|
+
curPath[0] ===
|
|
42
|
+
nodeLabel(d, strings, mappings, locations, functions, binaries.length > 1);
|
|
43
|
+
});
|
|
38
44
|
return (_jsx("g", __assign({ transform: "translate(".concat(x, ", ").concat(y, ")") }, { children: nodes.map(function (d, i) {
|
|
39
45
|
var start = nodes.slice(0, i).reduce(function (sum, d) { return sum + parseFloat(d.cumulative); }, 0);
|
|
40
46
|
var xStart = xScale(start);
|
|
@@ -52,11 +58,14 @@ var fadedIcicleRectStyles = {
|
|
|
52
58
|
};
|
|
53
59
|
export var IcicleNode = React.memo(function IcicleNode(_a) {
|
|
54
60
|
var x = _a.x, y = _a.y, height = _a.height, setCurPath = _a.setCurPath, setHoveringNode = _a.setHoveringNode, curPath = _a.curPath, level = _a.level, path = _a.path, data = _a.data, strings = _a.strings, mappings = _a.mappings, locations = _a.locations, functions = _a.functions, total = _a.total, totalWidth = _a.totalWidth, xScale = _a.xScale, _b = _a.isRoot, isRoot = _b === void 0 ? false : _b, searchString = _a.searchString, compareMode = _a.compareMode;
|
|
61
|
+
var binaries = useAppSelector(selectBinaries);
|
|
55
62
|
var isShiftDown = useKeyDown().isShiftDown;
|
|
56
63
|
var colorResult = useNodeColor({ data: data, compareMode: compareMode });
|
|
57
64
|
var name = useMemo(function () {
|
|
58
|
-
return isRoot
|
|
59
|
-
|
|
65
|
+
return isRoot
|
|
66
|
+
? 'root'
|
|
67
|
+
: nodeLabel(data, strings, mappings, locations, functions, binaries.length > 1);
|
|
68
|
+
}, [data, strings, mappings, locations, functions, isRoot, binaries]);
|
|
60
69
|
var nextPath = path.concat([name]);
|
|
61
70
|
var isFaded = curPath.length > 0 && name !== curPath[curPath.length - 1];
|
|
62
71
|
var styles = isFaded ? fadedIcicleRectStyles : icicleRectStyles;
|
|
@@ -33,6 +33,7 @@ import { IcicleNode, RowHeight } from './IcicleGraphNodes';
|
|
|
33
33
|
import useColoredGraph from './useColoredGraph';
|
|
34
34
|
import { selectQueryParam } from '@parca/functions';
|
|
35
35
|
import ColorStackLegend from './ColorStackLegend';
|
|
36
|
+
import useUserPreference, { USER_PREFERENCES } from '@parca/functions/useUserPreference';
|
|
36
37
|
export var IcicleGraph = memo(function IcicleGraph(_a) {
|
|
37
38
|
var _b;
|
|
38
39
|
var graph = _a.graph, width = _a.width, setCurPath = _a.setCurPath, curPath = _a.curPath, sampleUnit = _a.sampleUnit, navigateTo = _a.navigateTo, _c = _a.isTrimmed, isTrimmed = _c === void 0 ? false : _c;
|
|
@@ -48,6 +49,7 @@ export var IcicleGraph = memo(function IcicleGraph(_a) {
|
|
|
48
49
|
var coloredGraph = useColoredGraph(graph);
|
|
49
50
|
var currentSearchString = (_b = selectQueryParam('search_string')) !== null && _b !== void 0 ? _b : '';
|
|
50
51
|
var compareMode = selectQueryParam('compare_a') === 'true' && selectQueryParam('compare_b') === 'true';
|
|
52
|
+
var colorProfileName = useUserPreference(USER_PREFERENCES.FLAMEGRAPH_COLOR_PROFILE.key)[0];
|
|
51
53
|
useEffect(function () {
|
|
52
54
|
if (ref.current != null) {
|
|
53
55
|
setHeight(ref === null || ref === void 0 ? void 0 : ref.current.getBoundingClientRect().height);
|
|
@@ -69,10 +71,16 @@ export var IcicleGraph = memo(function IcicleGraph(_a) {
|
|
|
69
71
|
var rel = pointer(e);
|
|
70
72
|
throttledSetPos([rel[0], rel[1]]);
|
|
71
73
|
};
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
: isTrimmed
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
var isColorStackLegendVisible = colorProfileName !== 'default';
|
|
75
|
+
return (_jsxs("div", __assign({ onMouseLeave: function () { return setHoveringNode(undefined); } }, { children: [_jsx(ColorStackLegend, { navigateTo: navigateTo, compareMode: compareMode }), _jsx(GraphTooltip, { unit: sampleUnit, total: total, x: pos[0], y: pos[1], hoveringNode: hoveringNode, contextElement: svg.current, strings: coloredGraph.stringTable, mappings: coloredGraph.mapping, locations: coloredGraph.locations, functions: coloredGraph.function }), _jsx("div", __assign({ className: cx('flex justify-start absolute', {
|
|
76
|
+
'top-[-48px]': dashboardItems.length <= 1 && !isTrimmed && !isColorStackLegendVisible,
|
|
77
|
+
'top-[-69px]': dashboardItems.length <= 1 && !isTrimmed,
|
|
78
|
+
'top-[-54px]': dashboardItems.length <= 1 && isTrimmed && isColorStackLegendVisible,
|
|
79
|
+
'top-[-54px] ': dashboardItems.length <= 1 && isTrimmed && !isColorStackLegendVisible,
|
|
80
|
+
'top-[-54px] left-[25px]': dashboardItems.length > 1 && isTrimmed && isColorStackLegendVisible,
|
|
81
|
+
'top-[-54px] left-[25px] ': dashboardItems.length > 1 && isTrimmed && !isColorStackLegendVisible,
|
|
82
|
+
'top-[-70px] left-[25px]': dashboardItems.length > 1 && !isTrimmed && isColorStackLegendVisible,
|
|
83
|
+
'top-[-46px] left-[25px]': dashboardItems.length > 1 && !isTrimmed && !isColorStackLegendVisible,
|
|
84
|
+
}) }, { children: _jsx(Button, __assign({ color: "neutral", onClick: function () { return setCurPath([]); }, disabled: curPath.length === 0, className: "w-auto", variant: "neutral" }, { children: "Reset View" })) })), _jsx("svg", __assign({ className: "font-robotoMono", width: width, height: height, onMouseMove: onMouseMove, preserveAspectRatio: "xMinYMid", ref: svg }, { children: _jsx("g", __assign({ ref: ref }, { children: _jsx("g", __assign({ transform: 'translate(0, 0)' }, { children: _jsx(IcicleNode, { x: 0, y: 0, totalWidth: width, height: RowHeight, setCurPath: setCurPath, setHoveringNode: setHoveringNode, curPath: curPath, data: coloredGraph.root, strings: coloredGraph.stringTable, mappings: coloredGraph.mapping, locations: coloredGraph.locations, functions: coloredGraph.function, total: total, xScale: xScale, path: [], level: 0, isRoot: true, searchString: currentSearchString, compareMode: compareMode }) })) })) }))] })));
|
|
77
85
|
});
|
|
78
86
|
export default IcicleGraph;
|
|
@@ -34,8 +34,9 @@ var colorNodes = function (nodes, strings, mappings, locations, functions, featu
|
|
|
34
34
|
if (node.children != null) {
|
|
35
35
|
coloredNode.children = colorNodes(node.children, strings, mappings, locations, functions, features);
|
|
36
36
|
}
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
var feature = extractFeature(node, mappings, locations, strings, functions);
|
|
38
|
+
coloredNode.feature = feature.name;
|
|
39
|
+
features[feature.name] = feature.type;
|
|
39
40
|
return coloredNode;
|
|
40
41
|
});
|
|
41
42
|
};
|
|
@@ -46,11 +47,11 @@ var useColoredGraph = function (graph) {
|
|
|
46
47
|
var _a = useMemo(function () {
|
|
47
48
|
var _a;
|
|
48
49
|
if (graph.root == null) {
|
|
49
|
-
return [graph,
|
|
50
|
+
return [graph, {}];
|
|
50
51
|
}
|
|
51
52
|
var features = {};
|
|
52
53
|
var coloredGraph = __assign(__assign({}, graph), { root: __assign(__assign({}, graph.root), { children: colorNodes((_a = graph.root.children) !== null && _a !== void 0 ? _a : [], graph.stringTable, graph.mapping, graph.locations, graph.function, features) }) });
|
|
53
|
-
return [coloredGraph,
|
|
54
|
+
return [coloredGraph, features];
|
|
54
55
|
}, [graph]), coloredGraph = _a[0], features = _a[1];
|
|
55
56
|
useEffect(function () {
|
|
56
57
|
dispatch(setFeatures({ features: features, colorProfileName: colorProfile, isDarkMode: isDarkMode }));
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { FlamegraphNode } from '@parca/client';
|
|
2
2
|
import { Mapping, Function as ParcaFunction, Location } from '@parca/client/dist/parca/metastore/v1alpha1/metastore';
|
|
3
|
+
import type { Feature } from '@parca/store';
|
|
3
4
|
export declare const getBinaryName: (node: FlamegraphNode, mappings: Mapping[], locations: Location[], strings: string[]) => string | undefined;
|
|
4
|
-
export declare function nodeLabel(node: FlamegraphNode, strings: string[], mappings: Mapping[], locations: Location[], functions: ParcaFunction[]): string;
|
|
5
|
-
export declare const extractFeature: (data: FlamegraphNode, mappings: Mapping[], locations: Location[], strings: string[], functions: ParcaFunction[]) =>
|
|
5
|
+
export declare function nodeLabel(node: FlamegraphNode, strings: string[], mappings: Mapping[], locations: Location[], functions: ParcaFunction[], showBinaryName: boolean): string;
|
|
6
|
+
export declare const extractFeature: (data: FlamegraphNode, mappings: Mapping[], locations: Location[], strings: string[], functions: ParcaFunction[]) => Feature;
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
import { getLastItem } from '@parca/functions';
|
|
14
14
|
import { hexifyAddress } from '../../utils';
|
|
15
|
-
import { EVERYTHING_ELSE } from '@parca/store';
|
|
15
|
+
import { EVERYTHING_ELSE, FEATURE_TYPES } from '@parca/store';
|
|
16
16
|
export var getBinaryName = function (node, mappings, locations, strings) {
|
|
17
17
|
var _a, _b;
|
|
18
18
|
if (((_a = node.meta) === null || _a === void 0 ? void 0 : _a.locationIndex) === undefined || ((_b = node.meta) === null || _b === void 0 ? void 0 : _b.locationIndex) === 0) {
|
|
@@ -29,31 +29,35 @@ export var getBinaryName = function (node, mappings, locations, strings) {
|
|
|
29
29
|
var mappingFile = strings[mapping.fileStringIndex];
|
|
30
30
|
return getLastItem(mappingFile);
|
|
31
31
|
};
|
|
32
|
-
export function nodeLabel(node, strings, mappings, locations, functions) {
|
|
32
|
+
export function nodeLabel(node, strings, mappings, locations, functions, showBinaryName) {
|
|
33
33
|
var _a, _b;
|
|
34
34
|
if (((_a = node.meta) === null || _a === void 0 ? void 0 : _a.locationIndex) === undefined)
|
|
35
35
|
return '<unknown>';
|
|
36
36
|
if (((_b = node.meta) === null || _b === void 0 ? void 0 : _b.locationIndex) === 0)
|
|
37
37
|
return '<unknown>';
|
|
38
38
|
var location = locations[node.meta.locationIndex - 1];
|
|
39
|
-
var
|
|
40
|
-
|
|
39
|
+
var mappingString = '';
|
|
40
|
+
if (showBinaryName) {
|
|
41
|
+
var binary = getBinaryName(node, mappings, locations, strings);
|
|
42
|
+
if (binary != null)
|
|
43
|
+
mappingString = "[".concat(binary, "]");
|
|
44
|
+
}
|
|
41
45
|
if (location.lines.length > 0) {
|
|
42
46
|
var funcName = strings[functions[location.lines[node.meta.lineIndex].functionIndex - 1].nameStringIndex];
|
|
43
|
-
return "".concat(mappingString, " ").concat(funcName);
|
|
47
|
+
return "".concat(mappingString.length > 0 ? "".concat(mappingString, " ") : '').concat(funcName);
|
|
44
48
|
}
|
|
45
49
|
var address = hexifyAddress(location.address);
|
|
46
50
|
var fallback = "".concat(mappingString).concat(address);
|
|
47
51
|
return fallback === '' ? '<unknown>' : fallback;
|
|
48
52
|
}
|
|
49
53
|
export var extractFeature = function (data, mappings, locations, strings, functions) {
|
|
50
|
-
var name = nodeLabel(data, strings, mappings, locations, functions).trim();
|
|
54
|
+
var name = nodeLabel(data, strings, mappings, locations, functions, false).trim();
|
|
51
55
|
if (name.startsWith('runtime') || name === 'root') {
|
|
52
|
-
return 'runtime';
|
|
56
|
+
return { name: 'runtime', type: FEATURE_TYPES.Runtime };
|
|
53
57
|
}
|
|
54
58
|
var binaryName = getBinaryName(data, mappings, locations, strings);
|
|
55
59
|
if (binaryName != null) {
|
|
56
|
-
return binaryName;
|
|
60
|
+
return { name: binaryName, type: FEATURE_TYPES.Binary };
|
|
57
61
|
}
|
|
58
|
-
return EVERYTHING_ELSE;
|
|
62
|
+
return { name: EVERYTHING_ELSE, type: FEATURE_TYPES.Misc };
|
|
59
63
|
};
|
package/dist/TopTable/index.js
CHANGED
|
@@ -9,7 +9,7 @@ var __assign = (this && this.__assign) || function () {
|
|
|
9
9
|
};
|
|
10
10
|
return __assign.apply(this, arguments);
|
|
11
11
|
};
|
|
12
|
-
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
12
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
13
|
// Copyright 2022 The Parca Authors
|
|
14
14
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
15
15
|
// you may not use this file except in compliance with the License.
|
|
@@ -23,8 +23,8 @@ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
|
23
23
|
// See the License for the specific language governing permissions and
|
|
24
24
|
// limitations under the License.
|
|
25
25
|
import { useCallback, useMemo } from 'react';
|
|
26
|
-
import { getLastItem, valueFormatter, isSearchMatch, parseParams
|
|
27
|
-
import { Table } from '@parca/components';
|
|
26
|
+
import { getLastItem, valueFormatter, isSearchMatch, parseParams } from '@parca/functions';
|
|
27
|
+
import { Button, Table, useURLState } from '@parca/components';
|
|
28
28
|
import { createColumnHelper } from '@tanstack/react-table';
|
|
29
29
|
import { hexifyAddress } from '../utils';
|
|
30
30
|
import '../TopTable.styles.css';
|
|
@@ -52,8 +52,11 @@ export var TopTable = function (_a) {
|
|
|
52
52
|
var _b;
|
|
53
53
|
var top = _a.data, unit = _a.sampleUnit, navigateTo = _a.navigateTo, loading = _a.loading;
|
|
54
54
|
var router = parseParams(window.location.search);
|
|
55
|
-
var
|
|
56
|
-
var
|
|
55
|
+
var rawDashboardItems = useURLState({ param: 'dashboard_items' })[0];
|
|
56
|
+
var currentSearchString = useURLState({ param: 'search_string' })[0];
|
|
57
|
+
var rawcompareMode = useURLState({ param: 'compare_a' })[0];
|
|
58
|
+
var compareMode = rawcompareMode === undefined ? false : rawcompareMode === 'true';
|
|
59
|
+
var dashboardItems = rawDashboardItems;
|
|
57
60
|
var columns = useMemo(function () {
|
|
58
61
|
var cols = [
|
|
59
62
|
columnHelper.accessor('meta', {
|
|
@@ -107,13 +110,17 @@ export var TopTable = function (_a) {
|
|
|
107
110
|
}
|
|
108
111
|
}, [navigateTo, router]);
|
|
109
112
|
var onRowClick = useCallback(function (row) {
|
|
113
|
+
// If there is only one dashboard item, we don't want to select a span
|
|
114
|
+
if (dashboardItems.length <= 1) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
110
117
|
var meta = row.meta;
|
|
111
118
|
if (meta === undefined) {
|
|
112
119
|
return;
|
|
113
120
|
}
|
|
114
121
|
var name = RowLabel(meta);
|
|
115
122
|
selectSpan(name);
|
|
116
|
-
}, [selectSpan]);
|
|
123
|
+
}, [selectSpan, dashboardItems.length]);
|
|
117
124
|
var shouldHighlightRow = useCallback(function (row) {
|
|
118
125
|
var meta = row.meta;
|
|
119
126
|
if (meta === undefined)
|
|
@@ -124,12 +131,17 @@ export var TopTable = function (_a) {
|
|
|
124
131
|
var enableHighlighting = useMemo(function () {
|
|
125
132
|
return currentSearchString != null && (currentSearchString === null || currentSearchString === void 0 ? void 0 : currentSearchString.length) > 0;
|
|
126
133
|
}, [currentSearchString]);
|
|
134
|
+
var clearSelection = useCallback(function () {
|
|
135
|
+
if (navigateTo != null) {
|
|
136
|
+
navigateTo('/', __assign(__assign({}, router), { search_string: '' }), { replace: true });
|
|
137
|
+
}
|
|
138
|
+
}, [navigateTo, router]);
|
|
127
139
|
var initialSorting = useMemo(function () {
|
|
128
140
|
return [{ id: compareMode ? 'diff' : 'cumulative', desc: true }];
|
|
129
141
|
}, [compareMode]);
|
|
130
142
|
var total = top != null ? top.list.length : 0;
|
|
131
143
|
if (total === 0 && !loading)
|
|
132
144
|
return _jsx(_Fragment, { children: "Profile has no samples" });
|
|
133
|
-
return (_jsx(
|
|
145
|
+
return (_jsxs("div", __assign({ className: "relative" }, { children: [dashboardItems.length > 1 && (_jsx("div", __assign({ className: "left-[25px] top-[-45px] absolute" }, { children: _jsx(Button, __assign({ color: "neutral", onClick: clearSelection, className: "w-auto", variant: "neutral", disabled: currentSearchString === undefined || currentSearchString.length === 0 }, { children: "Clear selection" })) }))), _jsx("div", __assign({ className: "w-full font-robotoMono h-[80vh] overflow-scroll" }, { children: _jsx(Table, { data: (_b = top === null || top === void 0 ? void 0 : top.list) !== null && _b !== void 0 ? _b : [], columns: columns, initialSorting: initialSorting, onRowClick: onRowClick, enableHighlighting: enableHighlighting, shouldHighlightRow: shouldHighlightRow, usePointerCursor: dashboardItems.length > 1 }) }))] })));
|
|
134
146
|
};
|
|
135
147
|
export default TopTable;
|
package/dist/styles.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
/*! tailwindcss v3.2.4 | 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-feature-settings:normal;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%}[hidden]{display:none}*,: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}}.visible{visibility:visible}.invisible{visibility:hidden}.\!absolute{position:absolute!important}.absolute{position:absolute}.relative{position:relative}.top-0{top:0}.left-0{left:0}.right-0{right:0}.top-\[-54px\]{top:-54px}.top-\[-70px\]{top:-70px}.left-\[25px\]{left:25px}.top-\[-69px\]{top:-69px}.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}.my-6{margin-bottom:1.5rem;margin-top:1.5rem}.mr-3{margin-right:.75rem}.ml-2{margin-left:.5rem}.mr-6{margin-right:1.5rem}.mt-2{margin-top:.5rem}.mt-1{margin-top:.25rem}.ml-auto{margin-left:auto}.mb-2{margin-bottom:.5rem}.mr-1{margin-right:.25rem}.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-\[80vh\]{height:80vh}.h-4{height:1rem}.max-h-\[400px\]{max-height:400px}.w-auto{width:auto}.w-1\/5{width:20%}.w-4\/5{width:80%}.w-full{width:100%}.w-1\/4{width:25%}.w-3\/4{width:75%}.w-40{width:10rem}.w-2\/5{width:40%}.w-1\/2{width:50%}.w-8{width:2rem}.w-4{width:1rem}.w-16{width:4rem}.w-fit{width:-moz-fit-content;width:fit-content}.w-\[420px\]{width:420px}.min-w-\[300px\]{min-width:300px}.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-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.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}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-2{gap:.5rem}.gap-1{gap:.25rem}.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))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.25rem*var(--tw-space-y-reverse));margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)))}.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))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-scroll{overflow:scroll}.text-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.break-all{word-break:break-all}.rounded-lg{border-radius:.5rem}.rounded{border-radius:.25rem}.rounded-md{border-radius:.375rem}.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}.border{border-width:1px}.border-r-0{border-right-width:0}.border-l-0{border-left-width:0}.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-indigo-600{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity))}.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-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.bg-inherit{background-color:inherit}.fill-transparent{fill:transparent}.fill-current{fill:currentColor}.p-3{padding:.75rem}.p-10{padding:2.5rem}.p-4{padding:1rem}.p-1{padding:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.py-20{padding-bottom:5rem;padding-top:5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-1{padding-left:.25rem;padding-right:.25rem}.pl-3{padding-left:.75rem}.pr-9{padding-right:2.25rem}.pt-2{padding-top:.5rem}.pb-4{padding-bottom:1rem}.pr-2{padding-right:.5rem}.pl-2{padding-left:.5rem}.pb-2{padding-bottom:.5rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-xs{font-size:.75rem;line-height:1rem}.text-base{font-size:1rem;line-height:1.5rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.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-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}.opacity-50{opacity:.5}.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)}.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))}[class~=theme-dark] .dark\:border-gray-500{--tw-border-opacity:1;border-color:rgb(107 114 128/var(--tw-border-opacity))}[class~=theme-dark] .dark\:bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-gray-300{--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-gray-50{--tw-text-opacity:1;color:rgb(249 250 251/var(--tw-text-opacity))}[class~=theme-dark] .dark\:\!text-indigo-400{--tw-text-opacity:1!important;color:rgb(129 140 248/var(--tw-text-opacity))!important}@media (min-width:640px){.sm\:inline{display:inline}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}
|
|
1
|
+
/*! tailwindcss v3.2.4 | 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-feature-settings:normal;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%}[hidden]{display:none}*,: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}}.visible{visibility:visible}.invisible{visibility:hidden}.absolute{position:absolute}.relative{position:relative}.left-\[25px\]{left:25px}.left-0{left:0}.top-\[-46px\]{top:-46px}.right-0{right:0}.top-\[-45px\]{top:-45px}.top-\[-48px\]{top:-48px}.top-\[-69px\]{top:-69px}.top-\[-54px\]{top:-54px}.top-\[-70px\]{top:-70px}.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}.my-6{margin-bottom:1.5rem;margin-top:1.5rem}.mr-3{margin-right:.75rem}.ml-2{margin-left:.5rem}.mr-6{margin-right:1.5rem}.mt-2{margin-top:.5rem}.mt-1{margin-top:.25rem}.ml-auto{margin-left:auto}.mb-2{margin-bottom:.5rem}.mr-1{margin-right:.25rem}.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-\[80vh\]{height:80vh}.h-4{height:1rem}.max-h-\[400px\]{max-height:400px}.w-auto{width:auto}.w-1\/5{width:20%}.w-4\/5{width:80%}.w-full{width:100%}.w-1\/4{width:25%}.w-3\/4{width:75%}.w-40{width:10rem}.w-2\/5{width:40%}.w-1\/2{width:50%}.w-8{width:2rem}.w-4{width:1rem}.w-16{width:4rem}.w-fit{width:-moz-fit-content;width:fit-content}.w-\[420px\]{width:420px}.min-w-\[300px\]{min-width:300px}.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-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.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}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-2{gap:.5rem}.gap-1{gap:.25rem}.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))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.25rem*var(--tw-space-y-reverse));margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)))}.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))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-scroll{overflow:scroll}.text-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.break-all{word-break:break-all}.rounded-lg{border-radius:.5rem}.rounded{border-radius:.25rem}.rounded-md{border-radius:.375rem}.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}.border{border-width:1px}.border-r-0{border-right-width:0}.border-l-0{border-left-width:0}.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-indigo-600{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity))}.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-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.bg-inherit{background-color:inherit}.fill-transparent{fill:transparent}.fill-current{fill:currentColor}.p-3{padding:.75rem}.p-10{padding:2.5rem}.p-4{padding:1rem}.p-1{padding:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.py-20{padding-bottom:5rem;padding-top:5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-1{padding-left:.25rem;padding-right:.25rem}.pl-3{padding-left:.75rem}.pr-9{padding-right:2.25rem}.pt-2{padding-top:.5rem}.pb-4{padding-bottom:1rem}.pr-2{padding-right:.5rem}.pl-2{padding-left:.5rem}.pb-2{padding-bottom:.5rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-xs{font-size:.75rem;line-height:1rem}.text-base{font-size:1rem;line-height:1.5rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.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-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}.opacity-50{opacity:.5}.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)}.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))}[class~=theme-dark] .dark\:border-gray-500{--tw-border-opacity:1;border-color:rgb(107 114 128/var(--tw-border-opacity))}[class~=theme-dark] .dark\:bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-gray-300{--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-gray-50{--tw-text-opacity:1;color:rgb(249 250 251/var(--tw-text-opacity))}[class~=theme-dark] .dark\:\!text-indigo-400{--tw-text-opacity:1!important;color:rgb(129 140 248/var(--tw-text-opacity))!important}@media (min-width:640px){.sm\:inline{display:inline}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parca/profile",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.112",
|
|
4
4
|
"description": "Profile viewing libraries",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@parca/client": "^0.16.62",
|
|
7
|
-
"@parca/components": "^0.16.
|
|
7
|
+
"@parca/components": "^0.16.94",
|
|
8
8
|
"@parca/dynamicsize": "^0.16.52",
|
|
9
9
|
"@parca/functions": "^0.16.60",
|
|
10
10
|
"@parca/parser": "^0.16.53",
|
|
11
|
-
"@parca/store": "^0.16.
|
|
11
|
+
"@parca/store": "^0.16.56",
|
|
12
12
|
"@types/react-beautiful-dnd": "^13.1.3",
|
|
13
13
|
"d3": "7.8.2",
|
|
14
14
|
"d3-scale": "^4.0.2",
|
|
@@ -45,5 +45,5 @@
|
|
|
45
45
|
"access": "public",
|
|
46
46
|
"registry": "https://registry.npmjs.org/"
|
|
47
47
|
},
|
|
48
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "20614b1f95352017f7cec344edf8bd152df30856"
|
|
49
49
|
}
|
package/src/Callgraph/index.tsx
CHANGED
|
@@ -12,11 +12,12 @@
|
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
|
|
14
14
|
import {useState, useEffect, useRef} from 'react';
|
|
15
|
+
import cx from 'classnames';
|
|
15
16
|
import graphviz from 'graphviz-wasm';
|
|
16
17
|
import * as d3 from 'd3';
|
|
17
18
|
import {Stage, Layer, Rect, Arrow, Text, Label} from 'react-konva';
|
|
18
19
|
import type {KonvaEventObject} from 'konva/lib/Node';
|
|
19
|
-
import {Button} from '@parca/components';
|
|
20
|
+
import {Button, useURLState} from '@parca/components';
|
|
20
21
|
import {CallgraphNode, CallgraphEdge, Callgraph as CallgraphType} from '@parca/client';
|
|
21
22
|
import {jsonToDot, getCurvePoints} from './utils';
|
|
22
23
|
import type {HoveringNode} from '../GraphTooltip';
|
|
@@ -181,6 +182,9 @@ const Callgraph = ({graph, sampleUnit, width, colorRange}: Props): JSX.Element =
|
|
|
181
182
|
const {nodes: rawNodes, cumulative: total} = graph;
|
|
182
183
|
const currentSearchString = (selectQueryParam('search_string') as string) ?? '';
|
|
183
184
|
const isSearchEmpty = currentSearchString === undefined || currentSearchString === '';
|
|
185
|
+
const [rawDashboardItems] = useURLState({param: 'dashboard_items'});
|
|
186
|
+
|
|
187
|
+
const dashboardItems = rawDashboardItems as string[];
|
|
184
188
|
|
|
185
189
|
useEffect(() => {
|
|
186
190
|
const getDataWithPositions = async (): Promise<void> => {
|
|
@@ -345,9 +349,16 @@ const Callgraph = ({graph, sampleUnit, width, colorRange}: Props): JSX.Element =
|
|
|
345
349
|
contextElement={containerRef.current}
|
|
346
350
|
/>
|
|
347
351
|
{stage.scale.x !== 1 && (
|
|
348
|
-
<
|
|
349
|
-
|
|
350
|
-
|
|
352
|
+
<div
|
|
353
|
+
className={cx(
|
|
354
|
+
dashboardItems.length > 1 ? 'left-[25px]' : 'left-0',
|
|
355
|
+
'w-auto absolute top-[-46px]'
|
|
356
|
+
)}
|
|
357
|
+
>
|
|
358
|
+
<Button variant="neutral" onClick={resetZoom}>
|
|
359
|
+
Reset Zoom
|
|
360
|
+
</Button>
|
|
361
|
+
</div>
|
|
351
362
|
)}
|
|
352
363
|
</div>
|
|
353
364
|
</div>
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
} from '@parca/client/dist/parca/metastore/v1alpha1/metastore';
|
|
23
23
|
import {isSearchMatch} from '@parca/functions';
|
|
24
24
|
import {FlamegraphNode, FlamegraphRootNode} from '@parca/client';
|
|
25
|
-
|
|
25
|
+
import {useAppSelector, selectBinaries} from '@parca/store';
|
|
26
26
|
import {nodeLabel} from './utils';
|
|
27
27
|
import useNodeColor from './useNodeColor';
|
|
28
28
|
import {useKeyDown} from '@parca/components';
|
|
@@ -68,11 +68,15 @@ export const IcicleGraphNodes = React.memo(function IcicleGraphNodes({
|
|
|
68
68
|
searchString,
|
|
69
69
|
compareMode,
|
|
70
70
|
}: IcicleGraphNodesProps): JSX.Element {
|
|
71
|
+
const binaries = useAppSelector(selectBinaries);
|
|
71
72
|
const nodes =
|
|
72
73
|
curPath.length === 0
|
|
73
74
|
? data
|
|
74
75
|
: data.filter(
|
|
75
|
-
d =>
|
|
76
|
+
d =>
|
|
77
|
+
d != null &&
|
|
78
|
+
curPath[0] ===
|
|
79
|
+
nodeLabel(d, strings, mappings, locations, functions, binaries.length > 1)
|
|
76
80
|
);
|
|
77
81
|
|
|
78
82
|
return (
|
|
@@ -162,11 +166,14 @@ export const IcicleNode = React.memo(function IcicleNode({
|
|
|
162
166
|
searchString,
|
|
163
167
|
compareMode,
|
|
164
168
|
}: IcicleNodeProps): JSX.Element {
|
|
169
|
+
const binaries = useAppSelector(selectBinaries);
|
|
165
170
|
const {isShiftDown} = useKeyDown();
|
|
166
171
|
const colorResult = useNodeColor({data, compareMode});
|
|
167
172
|
const name = useMemo(() => {
|
|
168
|
-
return isRoot
|
|
169
|
-
|
|
173
|
+
return isRoot
|
|
174
|
+
? 'root'
|
|
175
|
+
: nodeLabel(data, strings, mappings, locations, functions, binaries.length > 1);
|
|
176
|
+
}, [data, strings, mappings, locations, functions, isRoot, binaries]);
|
|
170
177
|
const nextPath = path.concat([name]);
|
|
171
178
|
const isFaded = curPath.length > 0 && name !== curPath[curPath.length - 1];
|
|
172
179
|
const styles = isFaded ? fadedIcicleRectStyles : icicleRectStyles;
|
|
@@ -27,6 +27,7 @@ import useColoredGraph from './useColoredGraph';
|
|
|
27
27
|
import {selectQueryParam} from '@parca/functions';
|
|
28
28
|
import type {NavigateFunction} from '@parca/functions';
|
|
29
29
|
import ColorStackLegend from './ColorStackLegend';
|
|
30
|
+
import useUserPreference, {USER_PREFERENCES} from '@parca/functions/useUserPreference';
|
|
30
31
|
|
|
31
32
|
interface IcicleGraphProps {
|
|
32
33
|
graph: Flamegraph;
|
|
@@ -64,6 +65,10 @@ export const IcicleGraph = memo(function IcicleGraph({
|
|
|
64
65
|
const compareMode: boolean =
|
|
65
66
|
selectQueryParam('compare_a') === 'true' && selectQueryParam('compare_b') === 'true';
|
|
66
67
|
|
|
68
|
+
const [colorProfileName] = useUserPreference<string>(
|
|
69
|
+
USER_PREFERENCES.FLAMEGRAPH_COLOR_PROFILE.key
|
|
70
|
+
);
|
|
71
|
+
|
|
67
72
|
useEffect(() => {
|
|
68
73
|
if (ref.current != null) {
|
|
69
74
|
setHeight(ref?.current.getBoundingClientRect().height);
|
|
@@ -89,6 +94,7 @@ export const IcicleGraph = memo(function IcicleGraph({
|
|
|
89
94
|
|
|
90
95
|
throttledSetPos([rel[0], rel[1]]);
|
|
91
96
|
};
|
|
97
|
+
const isColorStackLegendVisible = colorProfileName !== 'default';
|
|
92
98
|
|
|
93
99
|
return (
|
|
94
100
|
<div onMouseLeave={() => setHoveringNode(undefined)}>
|
|
@@ -106,14 +112,20 @@ export const IcicleGraph = memo(function IcicleGraph({
|
|
|
106
112
|
functions={coloredGraph.function}
|
|
107
113
|
/>
|
|
108
114
|
<div
|
|
109
|
-
className={cx(
|
|
110
|
-
dashboardItems.length
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
className={cx('flex justify-start absolute', {
|
|
116
|
+
'top-[-48px]': dashboardItems.length <= 1 && !isTrimmed && !isColorStackLegendVisible,
|
|
117
|
+
'top-[-69px]': dashboardItems.length <= 1 && !isTrimmed,
|
|
118
|
+
'top-[-54px]': dashboardItems.length <= 1 && isTrimmed && isColorStackLegendVisible,
|
|
119
|
+
'top-[-54px] ': dashboardItems.length <= 1 && isTrimmed && !isColorStackLegendVisible,
|
|
120
|
+
'top-[-54px] left-[25px]':
|
|
121
|
+
dashboardItems.length > 1 && isTrimmed && isColorStackLegendVisible,
|
|
122
|
+
'top-[-54px] left-[25px] ':
|
|
123
|
+
dashboardItems.length > 1 && isTrimmed && !isColorStackLegendVisible,
|
|
124
|
+
'top-[-70px] left-[25px]':
|
|
125
|
+
dashboardItems.length > 1 && !isTrimmed && isColorStackLegendVisible,
|
|
126
|
+
'top-[-46px] left-[25px]':
|
|
127
|
+
dashboardItems.length > 1 && !isTrimmed && !isColorStackLegendVisible,
|
|
128
|
+
})}
|
|
117
129
|
>
|
|
118
130
|
<Button
|
|
119
131
|
color="neutral"
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
import type {ColorProfileName} from '@parca/functions';
|
|
21
21
|
import useUserPreference, {USER_PREFERENCES} from '@parca/functions/useUserPreference';
|
|
22
22
|
import {setFeatures, useAppDispatch, useAppSelector, selectDarkMode} from '@parca/store';
|
|
23
|
+
import type {FeatureType, FeaturesMap} from '@parca/store';
|
|
23
24
|
import {useEffect, useMemo} from 'react';
|
|
24
25
|
import {extractFeature} from './utils';
|
|
25
26
|
|
|
@@ -43,7 +44,7 @@ const colorNodes = (
|
|
|
43
44
|
mappings: Mapping[],
|
|
44
45
|
locations: Location[],
|
|
45
46
|
functions: ParcaFunction[],
|
|
46
|
-
features: {[key: string]:
|
|
47
|
+
features: {[key: string]: FeatureType}
|
|
47
48
|
): ColoredFlamegraphNode[] => {
|
|
48
49
|
if (nodes === undefined) {
|
|
49
50
|
return [];
|
|
@@ -62,8 +63,9 @@ const colorNodes = (
|
|
|
62
63
|
features
|
|
63
64
|
);
|
|
64
65
|
}
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
const feature = extractFeature(node, mappings, locations, strings, functions);
|
|
67
|
+
coloredNode.feature = feature.name;
|
|
68
|
+
features[feature.name] = feature.type;
|
|
67
69
|
return coloredNode;
|
|
68
70
|
});
|
|
69
71
|
};
|
|
@@ -75,11 +77,11 @@ const useColoredGraph = (graph: Flamegraph): ColoredFlamegraph => {
|
|
|
75
77
|
);
|
|
76
78
|
const isDarkMode = useAppSelector(selectDarkMode);
|
|
77
79
|
|
|
78
|
-
const [coloredGraph, features]: [ColoredFlamegraph,
|
|
80
|
+
const [coloredGraph, features]: [ColoredFlamegraph, FeaturesMap] = useMemo(() => {
|
|
79
81
|
if (graph.root == null) {
|
|
80
|
-
return [graph as ColoredFlamegraph,
|
|
82
|
+
return [graph as ColoredFlamegraph, {}];
|
|
81
83
|
}
|
|
82
|
-
const features:
|
|
84
|
+
const features: FeaturesMap = {};
|
|
83
85
|
const coloredGraph = {
|
|
84
86
|
...graph,
|
|
85
87
|
root: {
|
|
@@ -94,7 +96,7 @@ const useColoredGraph = (graph: Flamegraph): ColoredFlamegraph => {
|
|
|
94
96
|
),
|
|
95
97
|
},
|
|
96
98
|
};
|
|
97
|
-
return [coloredGraph,
|
|
99
|
+
return [coloredGraph, features];
|
|
98
100
|
}, [graph]);
|
|
99
101
|
|
|
100
102
|
useEffect(() => {
|
|
@@ -19,7 +19,8 @@ import {
|
|
|
19
19
|
Location,
|
|
20
20
|
} from '@parca/client/dist/parca/metastore/v1alpha1/metastore';
|
|
21
21
|
import {hexifyAddress} from '../../utils';
|
|
22
|
-
import {EVERYTHING_ELSE} from '@parca/store';
|
|
22
|
+
import {EVERYTHING_ELSE, FEATURE_TYPES} from '@parca/store';
|
|
23
|
+
import type {Feature} from '@parca/store';
|
|
23
24
|
|
|
24
25
|
export const getBinaryName = (
|
|
25
26
|
node: FlamegraphNode,
|
|
@@ -50,21 +51,25 @@ export function nodeLabel(
|
|
|
50
51
|
strings: string[],
|
|
51
52
|
mappings: Mapping[],
|
|
52
53
|
locations: Location[],
|
|
53
|
-
functions: ParcaFunction[]
|
|
54
|
+
functions: ParcaFunction[],
|
|
55
|
+
showBinaryName: boolean
|
|
54
56
|
): string {
|
|
55
57
|
if (node.meta?.locationIndex === undefined) return '<unknown>';
|
|
56
58
|
if (node.meta?.locationIndex === 0) return '<unknown>';
|
|
57
59
|
|
|
58
60
|
const location = locations[node.meta.locationIndex - 1];
|
|
59
61
|
|
|
60
|
-
|
|
62
|
+
let mappingString = '';
|
|
61
63
|
|
|
62
|
-
|
|
64
|
+
if (showBinaryName) {
|
|
65
|
+
const binary = getBinaryName(node, mappings, locations, strings);
|
|
66
|
+
if (binary != null) mappingString = `[${binary}]`;
|
|
67
|
+
}
|
|
63
68
|
|
|
64
69
|
if (location.lines.length > 0) {
|
|
65
70
|
const funcName =
|
|
66
71
|
strings[functions[location.lines[node.meta.lineIndex].functionIndex - 1].nameStringIndex];
|
|
67
|
-
return `${mappingString} ${funcName}`;
|
|
72
|
+
return `${mappingString.length > 0 ? `${mappingString} ` : ''}${funcName}`;
|
|
68
73
|
}
|
|
69
74
|
|
|
70
75
|
const address = hexifyAddress(location.address);
|
|
@@ -79,16 +84,16 @@ export const extractFeature = (
|
|
|
79
84
|
locations: Location[],
|
|
80
85
|
strings: string[],
|
|
81
86
|
functions: ParcaFunction[]
|
|
82
|
-
):
|
|
83
|
-
const name = nodeLabel(data, strings, mappings, locations, functions).trim();
|
|
87
|
+
): Feature => {
|
|
88
|
+
const name = nodeLabel(data, strings, mappings, locations, functions, false).trim();
|
|
84
89
|
if (name.startsWith('runtime') || name === 'root') {
|
|
85
|
-
return 'runtime';
|
|
90
|
+
return {name: 'runtime', type: FEATURE_TYPES.Runtime};
|
|
86
91
|
}
|
|
87
92
|
|
|
88
93
|
const binaryName = getBinaryName(data, mappings, locations, strings);
|
|
89
94
|
if (binaryName != null) {
|
|
90
|
-
return binaryName;
|
|
95
|
+
return {name: binaryName, type: FEATURE_TYPES.Binary};
|
|
91
96
|
}
|
|
92
97
|
|
|
93
|
-
return EVERYTHING_ELSE;
|
|
98
|
+
return {name: EVERYTHING_ELSE, type: FEATURE_TYPES.Misc};
|
|
94
99
|
};
|
package/src/TopTable/index.tsx
CHANGED
|
@@ -13,16 +13,10 @@
|
|
|
13
13
|
|
|
14
14
|
import {useCallback, useMemo} from 'react';
|
|
15
15
|
|
|
16
|
-
import {
|
|
17
|
-
getLastItem,
|
|
18
|
-
valueFormatter,
|
|
19
|
-
isSearchMatch,
|
|
20
|
-
parseParams,
|
|
21
|
-
selectQueryParam,
|
|
22
|
-
} from '@parca/functions';
|
|
16
|
+
import {getLastItem, valueFormatter, isSearchMatch, parseParams} from '@parca/functions';
|
|
23
17
|
import type {NavigateFunction} from '@parca/functions';
|
|
24
18
|
import {TopNode, TopNodeMeta, Top} from '@parca/client';
|
|
25
|
-
import {Table} from '@parca/components';
|
|
19
|
+
import {Button, Table, useURLState} from '@parca/components';
|
|
26
20
|
import {createColumnHelper} from '@tanstack/react-table';
|
|
27
21
|
import type {ColumnDef} from '@tanstack/react-table';
|
|
28
22
|
|
|
@@ -70,9 +64,13 @@ export const TopTable = ({
|
|
|
70
64
|
loading,
|
|
71
65
|
}: TopTableProps): JSX.Element => {
|
|
72
66
|
const router = parseParams(window.location.search);
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
-
|
|
67
|
+
const [rawDashboardItems] = useURLState({param: 'dashboard_items'});
|
|
68
|
+
const [currentSearchString] = useURLState({param: 'search_string'});
|
|
69
|
+
const [rawcompareMode] = useURLState({param: 'compare_a'});
|
|
70
|
+
|
|
71
|
+
const compareMode: boolean = rawcompareMode === undefined ? false : rawcompareMode === 'true';
|
|
72
|
+
|
|
73
|
+
const dashboardItems = rawDashboardItems as string[];
|
|
76
74
|
|
|
77
75
|
const columns = useMemo(() => {
|
|
78
76
|
const cols: Array<ColumnDef<TopNode, any>> = [
|
|
@@ -142,6 +140,11 @@ export const TopTable = ({
|
|
|
142
140
|
|
|
143
141
|
const onRowClick = useCallback(
|
|
144
142
|
(row: TopNode) => {
|
|
143
|
+
// If there is only one dashboard item, we don't want to select a span
|
|
144
|
+
if (dashboardItems.length <= 1) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
145
148
|
const meta = row.meta;
|
|
146
149
|
if (meta === undefined) {
|
|
147
150
|
return;
|
|
@@ -149,7 +152,7 @@ export const TopTable = ({
|
|
|
149
152
|
const name = RowLabel(meta);
|
|
150
153
|
selectSpan(name);
|
|
151
154
|
},
|
|
152
|
-
[selectSpan]
|
|
155
|
+
[selectSpan, dashboardItems.length]
|
|
153
156
|
);
|
|
154
157
|
|
|
155
158
|
const shouldHighlightRow = useCallback(
|
|
@@ -157,7 +160,7 @@ export const TopTable = ({
|
|
|
157
160
|
const meta = row.meta;
|
|
158
161
|
if (meta === undefined) return false;
|
|
159
162
|
const name = RowLabel(meta);
|
|
160
|
-
return isSearchMatch(currentSearchString, name);
|
|
163
|
+
return isSearchMatch(currentSearchString as string, name);
|
|
161
164
|
},
|
|
162
165
|
[currentSearchString]
|
|
163
166
|
);
|
|
@@ -166,6 +169,19 @@ export const TopTable = ({
|
|
|
166
169
|
return currentSearchString != null && currentSearchString?.length > 0;
|
|
167
170
|
}, [currentSearchString]);
|
|
168
171
|
|
|
172
|
+
const clearSelection = useCallback((): void => {
|
|
173
|
+
if (navigateTo != null) {
|
|
174
|
+
navigateTo(
|
|
175
|
+
'/',
|
|
176
|
+
{
|
|
177
|
+
...router,
|
|
178
|
+
...{search_string: ''},
|
|
179
|
+
},
|
|
180
|
+
{replace: true}
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
}, [navigateTo, router]);
|
|
184
|
+
|
|
169
185
|
const initialSorting = useMemo(() => {
|
|
170
186
|
return [{id: compareMode ? 'diff' : 'cumulative', desc: true}];
|
|
171
187
|
}, [compareMode]);
|
|
@@ -175,7 +191,22 @@ export const TopTable = ({
|
|
|
175
191
|
if (total === 0 && !loading) return <>Profile has no samples</>;
|
|
176
192
|
|
|
177
193
|
return (
|
|
178
|
-
|
|
194
|
+
<div className="relative">
|
|
195
|
+
{/* Clearing the selection is only useful when two visualizations types are selected. So we'll only show it in that case */}
|
|
196
|
+
{dashboardItems.length > 1 && (
|
|
197
|
+
<div className="left-[25px] top-[-45px] absolute">
|
|
198
|
+
<Button
|
|
199
|
+
color="neutral"
|
|
200
|
+
onClick={clearSelection}
|
|
201
|
+
className="w-auto"
|
|
202
|
+
variant="neutral"
|
|
203
|
+
disabled={currentSearchString === undefined || currentSearchString.length === 0}
|
|
204
|
+
>
|
|
205
|
+
Clear selection
|
|
206
|
+
</Button>
|
|
207
|
+
</div>
|
|
208
|
+
)}
|
|
209
|
+
|
|
179
210
|
<div className="w-full font-robotoMono h-[80vh] overflow-scroll">
|
|
180
211
|
<Table
|
|
181
212
|
data={top?.list ?? []}
|
|
@@ -184,9 +215,10 @@ export const TopTable = ({
|
|
|
184
215
|
onRowClick={onRowClick}
|
|
185
216
|
enableHighlighting={enableHighlighting}
|
|
186
217
|
shouldHighlightRow={shouldHighlightRow}
|
|
218
|
+
usePointerCursor={dashboardItems.length > 1}
|
|
187
219
|
/>
|
|
188
220
|
</div>
|
|
189
|
-
|
|
221
|
+
</div>
|
|
190
222
|
);
|
|
191
223
|
};
|
|
192
224
|
|