@parca/profile 0.16.0 → 0.16.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -0
- package/dist/Callgraph/Edge/index.d.ts +22 -0
- package/dist/Callgraph/Edge/index.js +30 -0
- package/dist/Callgraph/Node/index.d.ts +19 -0
- package/dist/Callgraph/Node/index.js +37 -0
- package/dist/Callgraph/index.d.ts +8 -0
- package/dist/Callgraph/index.js +137 -0
- package/dist/Callgraph/mockData/index.d.ts +148 -0
- package/dist/Callgraph/mockData/index.js +577 -0
- package/dist/Callgraph/utils.d.ts +19 -0
- package/dist/Callgraph/utils.js +82 -0
- package/dist/GraphTooltip/index.d.ts +19 -0
- package/dist/GraphTooltip/index.js +119 -0
- package/dist/IcicleGraph.d.ts +35 -0
- package/dist/IcicleGraph.js +139 -0
- package/dist/MatchersInput/index.d.ts +23 -0
- package/dist/MatchersInput/index.js +479 -0
- package/dist/MetricsCircle/index.d.ts +7 -0
- package/dist/MetricsCircle/index.js +18 -0
- package/dist/MetricsGraph/index.d.ts +35 -0
- package/dist/MetricsGraph/index.js +349 -0
- package/dist/MetricsSeries/index.d.ts +11 -0
- package/dist/MetricsSeries/index.js +21 -0
- package/dist/ProfileExplorer/ProfileExplorerCompare.d.ts +19 -0
- package/dist/ProfileExplorer/ProfileExplorerCompare.js +38 -0
- package/dist/ProfileExplorer/ProfileExplorerSingle.d.ts +15 -0
- package/dist/ProfileExplorer/ProfileExplorerSingle.js +19 -0
- package/dist/ProfileExplorer/index.d.ts +9 -0
- package/dist/ProfileExplorer/index.js +203 -0
- package/dist/ProfileIcicleGraph.d.ts +10 -0
- package/dist/ProfileIcicleGraph.js +28 -0
- package/dist/ProfileMetricsGraph/index.d.ts +22 -0
- package/dist/ProfileMetricsGraph/index.js +127 -0
- package/dist/ProfileSVG.module.css +3 -0
- package/dist/ProfileSelector/CompareButton.d.ts +5 -0
- package/dist/ProfileSelector/CompareButton.js +41 -0
- package/dist/ProfileSelector/MergeButton.d.ts +5 -0
- package/dist/ProfileSelector/MergeButton.js +41 -0
- package/dist/ProfileSelector/index.d.ts +29 -0
- package/dist/ProfileSelector/index.js +133 -0
- package/dist/ProfileSource.d.ts +88 -0
- package/dist/ProfileSource.js +239 -0
- package/dist/ProfileTypeSelector/index.d.ts +20 -0
- package/dist/ProfileTypeSelector/index.js +138 -0
- package/dist/ProfileView.d.ts +39 -0
- package/dist/ProfileView.js +111 -0
- package/dist/ProfileView.styles.css +3 -0
- package/dist/ProfileViewWithData.d.ts +11 -0
- package/dist/ProfileViewWithData.js +116 -0
- package/dist/TopTable.d.ts +9 -0
- package/dist/TopTable.js +140 -0
- package/dist/TopTable.styles.css +7 -0
- package/dist/components/DiffLegend.d.ts +2 -0
- package/dist/components/DiffLegend.js +62 -0
- package/dist/components/ProfileShareButton/ResultBox.d.ts +6 -0
- package/dist/components/ProfileShareButton/ResultBox.js +46 -0
- package/dist/components/ProfileShareButton/index.d.ts +7 -0
- package/dist/components/ProfileShareButton/index.js +119 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +64 -0
- package/dist/styles.css +1 -0
- package/dist/useDelayedLoader.d.ts +5 -0
- package/dist/useDelayedLoader.js +33 -0
- package/dist/useQuery.d.ts +13 -0
- package/dist/useQuery.js +41 -0
- package/dist/utils.d.ts +4 -0
- package/dist/utils.js +83 -0
- package/package.json +12 -8
- package/src/Callgraph/Edge/index.tsx +59 -0
- package/src/Callgraph/Node/index.tsx +66 -0
- package/src/Callgraph/index.tsx +169 -0
- package/src/Callgraph/mockData/index.ts +605 -0
- package/src/Callgraph/utils.ts +116 -0
- package/src/GraphTooltip/index.tsx +245 -0
- package/src/IcicleGraph.tsx +3 -3
- package/src/MatchersInput/index.tsx +698 -0
- package/src/MetricsCircle/index.tsx +28 -0
- package/src/MetricsGraph/index.tsx +614 -0
- package/src/MetricsSeries/index.tsx +38 -0
- package/src/ProfileExplorer/ProfileExplorerCompare.tsx +109 -0
- package/src/ProfileExplorer/ProfileExplorerSingle.tsx +72 -0
- package/src/ProfileExplorer/index.tsx +377 -0
- package/src/ProfileMetricsGraph/index.tsx +143 -0
- package/src/ProfileSelector/CompareButton.tsx +72 -0
- package/src/ProfileSelector/MergeButton.tsx +72 -0
- package/src/ProfileSelector/index.tsx +270 -0
- package/src/ProfileTypeSelector/index.tsx +180 -0
- package/src/ProfileView.tsx +2 -7
- package/src/index.tsx +11 -0
- package/src/useQuery.tsx +1 -0
- package/tailwind.config.js +8 -0
- package/tsconfig.json +7 -3
- package/typings.d.ts +14 -0
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
13
|
+
var t = {};
|
|
14
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
15
|
+
t[p] = s[p];
|
|
16
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
17
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
18
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
19
|
+
t[p[i]] = s[p[i]];
|
|
20
|
+
}
|
|
21
|
+
return t;
|
|
22
|
+
};
|
|
23
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
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 { useEffect, useRef, useState } from 'react';
|
|
37
|
+
import * as d3 from 'd3';
|
|
38
|
+
import MetricsSeries from '../MetricsSeries';
|
|
39
|
+
import MetricsCircle from '../MetricsCircle';
|
|
40
|
+
import { pointer } from 'd3-selection';
|
|
41
|
+
import { formatForTimespan } from '@parca/functions/time';
|
|
42
|
+
import { timeFormat } from '..';
|
|
43
|
+
import { cutToMaxStringLength } from '@parca/functions/string';
|
|
44
|
+
import throttle from 'lodash.throttle';
|
|
45
|
+
import { usePopper } from 'react-popper';
|
|
46
|
+
import { valueFormatter, formatDate } from '@parca/functions';
|
|
47
|
+
import { DateTimeRange } from '@parca/components';
|
|
48
|
+
import { useContainerDimensions } from '@parca/dynamicsize';
|
|
49
|
+
var MetricsGraph = function (_a) {
|
|
50
|
+
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
|
+
var _b = useContainerDimensions(), ref = _b.ref, dimensions = _b.dimensions;
|
|
52
|
+
return (_jsx("div", __assign({ ref: ref }, { children: _jsx(RawMetricsGraph, { data: data, from: from, to: to, profile: profile, onSampleClick: onSampleClick, onLabelClick: onLabelClick, setTimeRange: setTimeRange, sampleUnit: sampleUnit, width: dimensions === null || dimensions === void 0 ? void 0 : dimensions.width }) })));
|
|
53
|
+
};
|
|
54
|
+
export default MetricsGraph;
|
|
55
|
+
export var parseValue = function (value) {
|
|
56
|
+
var val = parseFloat(value);
|
|
57
|
+
// "+Inf", "-Inf", "+Inf" will be parsed into NaN by parseFloat(). They
|
|
58
|
+
// can't be graphed, so show them as gaps (null).
|
|
59
|
+
return isNaN(val) ? null : val;
|
|
60
|
+
};
|
|
61
|
+
var lineStroke = '1px';
|
|
62
|
+
var lineStrokeHover = '2px';
|
|
63
|
+
function generateGetBoundingClientRect(contextElement, x, y) {
|
|
64
|
+
if (x === void 0) { x = 0; }
|
|
65
|
+
if (y === void 0) { y = 0; }
|
|
66
|
+
var domRect = contextElement.getBoundingClientRect();
|
|
67
|
+
return function () {
|
|
68
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
69
|
+
return ({
|
|
70
|
+
width: 0,
|
|
71
|
+
height: 0,
|
|
72
|
+
top: domRect.y + y,
|
|
73
|
+
left: domRect.x + x,
|
|
74
|
+
right: domRect.x + x,
|
|
75
|
+
bottom: domRect.y + y,
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
var virtualElement = {
|
|
80
|
+
getBoundingClientRect: function () {
|
|
81
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
82
|
+
return {
|
|
83
|
+
width: 0,
|
|
84
|
+
height: 0,
|
|
85
|
+
top: 0,
|
|
86
|
+
left: 0,
|
|
87
|
+
right: 0,
|
|
88
|
+
bottom: 0,
|
|
89
|
+
};
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
export var MetricsTooltip = function (_a) {
|
|
93
|
+
var x = _a.x, y = _a.y, highlighted = _a.highlighted, onLabelClick = _a.onLabelClick, contextElement = _a.contextElement, sampleUnit = _a.sampleUnit;
|
|
94
|
+
var _b = useState(null), popperElement = _b[0], setPopperElement = _b[1];
|
|
95
|
+
var _c = usePopper(virtualElement, popperElement, {
|
|
96
|
+
placement: 'auto-start',
|
|
97
|
+
strategy: 'absolute',
|
|
98
|
+
modifiers: [
|
|
99
|
+
{
|
|
100
|
+
name: 'preventOverflow',
|
|
101
|
+
options: {
|
|
102
|
+
tether: false,
|
|
103
|
+
altAxis: true,
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: 'offset',
|
|
108
|
+
options: {
|
|
109
|
+
offset: [30, 30],
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
}), styles = _c.styles, attributes = _c.attributes, popperProps = __rest(_c, ["styles", "attributes"]);
|
|
114
|
+
var update = popperProps.update;
|
|
115
|
+
useEffect(function () {
|
|
116
|
+
if (contextElement != null) {
|
|
117
|
+
virtualElement.getBoundingClientRect = generateGetBoundingClientRect(contextElement, x, y);
|
|
118
|
+
void (update === null || update === void 0 ? void 0 : update());
|
|
119
|
+
}
|
|
120
|
+
}, [x, y, contextElement, update]);
|
|
121
|
+
var nameLabel = highlighted === null || highlighted === void 0 ? void 0 : highlighted.labels.find(function (e) { return e.name === '__name__'; });
|
|
122
|
+
var highlightedNameLabel = nameLabel !== undefined ? nameLabel : { name: '', value: '' };
|
|
123
|
+
return (_jsx("div", __assign({ ref: setPopperElement, style: styles.popper }, attributes.popper, { className: "z-10" }, { children: _jsx("div", __assign({ className: "flex max-w-md" }, { children: _jsx("div", __assign({ className: "m-auto" }, { 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" }, { children: highlightedNameLabel.value })), _jsx("span", __assign({ className: "block text-gray-700 dark:text-gray-300 my-2" }, { children: _jsx("table", __assign({ className: "table-auto" }, { children: _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", __assign({ className: "w-1/4" }, { children: "Value" })), _jsx("td", __assign({ className: "w-3/4" }, { children: valueFormatter(highlighted.value, sampleUnit, 1) }))] }), _jsxs("tr", { children: [_jsx("td", __assign({ className: "w-1/4" }, { children: "At" })), _jsx("td", __assign({ className: "w-3/4" }, { children: formatDate(highlighted.timestamp, timeFormat) }))] })] }) })) })), _jsx("span", __assign({ className: "block text-gray-500 my-2" }, { children: highlighted.labels
|
|
124
|
+
.filter(function (label) { return label.name !== '__name__'; })
|
|
125
|
+
.map(function (label) {
|
|
126
|
+
return (_jsx("button", __assign({ type: "button", className: "inline-block rounded-lg text-gray-700 bg-gray-200 dark:bg-gray-700 dark:text-gray-400 px-2 py-1 text-xs font-bold mr-3", onClick: function () { return onLabelClick(label.name, label.value); } }, { children: cutToMaxStringLength("".concat(label.name, "=\"").concat(label.value, "\""), 37) }), label.name));
|
|
127
|
+
}) })), _jsx("span", __assign({ className: "block text-gray-500 text-xs" }, { children: "Hold shift and click label to add to query." }))] })) })) })) })) })) })));
|
|
128
|
+
};
|
|
129
|
+
export var RawMetricsGraph = function (_a) {
|
|
130
|
+
var data = _a.data, from = _a.from, to = _a.to, profile = _a.profile, onSampleClick = _a.onSampleClick, onLabelClick = _a.onLabelClick, setTimeRange = _a.setTimeRange, width = _a.width, sampleUnit = _a.sampleUnit;
|
|
131
|
+
var graph = useRef(null);
|
|
132
|
+
var _b = useState(false), dragging = _b[0], setDragging = _b[1];
|
|
133
|
+
var _c = useState(false), hovering = _c[0], setHovering = _c[1];
|
|
134
|
+
var _d = useState(-1), relPos = _d[0], setRelPos = _d[1];
|
|
135
|
+
var _e = useState([0, 0]), pos = _e[0], setPos = _e[1];
|
|
136
|
+
var _f = useState(false), freezeTooltip = _f[0], setFreezeTooltip = _f[1];
|
|
137
|
+
var metricPointRef = useRef(null);
|
|
138
|
+
useEffect(function () {
|
|
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
|
+
}, []);
|
|
160
|
+
var time = parseFloat(profile === null || profile === void 0 ? void 0 : profile.HistoryParams().time);
|
|
161
|
+
if (width === undefined || width == null) {
|
|
162
|
+
width = 0;
|
|
163
|
+
}
|
|
164
|
+
var height = Math.min(width / 2.5, 400);
|
|
165
|
+
var margin = 50;
|
|
166
|
+
var marginRight = 20;
|
|
167
|
+
var series = data.reduce(function (agg, s) {
|
|
168
|
+
if (s.labelset !== undefined) {
|
|
169
|
+
agg.push({
|
|
170
|
+
metric: s.labelset.labels,
|
|
171
|
+
values: s.samples.reduce(function (agg, d) {
|
|
172
|
+
if (d.timestamp !== undefined && d.value !== undefined) {
|
|
173
|
+
var t = (+d.timestamp.seconds * 1e9 + d.timestamp.nanos) / 1e6; // https://github.com/microsoft/TypeScript/issues/5710#issuecomment-157886246
|
|
174
|
+
agg.push([t, parseFloat(d.value)]);
|
|
175
|
+
}
|
|
176
|
+
return agg;
|
|
177
|
+
}, []),
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
return agg;
|
|
181
|
+
}, []);
|
|
182
|
+
var extentsY = series.map(function (s) {
|
|
183
|
+
return d3.extent(s.values, function (d) {
|
|
184
|
+
return d[1];
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
var minY = d3.min(extentsY, function (d) {
|
|
188
|
+
return d[0];
|
|
189
|
+
});
|
|
190
|
+
var maxY = d3.max(extentsY, function (d) {
|
|
191
|
+
return d[1];
|
|
192
|
+
});
|
|
193
|
+
/* Scale */
|
|
194
|
+
var xScale = d3
|
|
195
|
+
.scaleUtc()
|
|
196
|
+
.domain([from, to])
|
|
197
|
+
.range([0, width - margin - marginRight]);
|
|
198
|
+
var yScale = d3
|
|
199
|
+
.scaleLinear()
|
|
200
|
+
// tslint:disable-next-line
|
|
201
|
+
.domain([minY, maxY])
|
|
202
|
+
.range([height - margin, 0]);
|
|
203
|
+
var color = d3.scaleOrdinal(d3.schemeCategory10);
|
|
204
|
+
var l = d3.line(function (d) { return xScale(d[0]); }, function (d) { return yScale(d[1]); });
|
|
205
|
+
var getClosest = function () {
|
|
206
|
+
var closestPointPerSeries = series.map(function (s) {
|
|
207
|
+
var distances = s.values.map(function (d) {
|
|
208
|
+
var x = xScale(d[0]);
|
|
209
|
+
var y = yScale(d[1]);
|
|
210
|
+
return Math.sqrt(Math.pow(pos[0] - x, 2) + Math.pow(pos[1] - y, 2));
|
|
211
|
+
});
|
|
212
|
+
var pointIndex = d3.minIndex(distances);
|
|
213
|
+
var minDistance = distances[pointIndex];
|
|
214
|
+
return {
|
|
215
|
+
pointIndex: pointIndex,
|
|
216
|
+
distance: minDistance,
|
|
217
|
+
};
|
|
218
|
+
});
|
|
219
|
+
var closestSeriesIndex = d3.minIndex(closestPointPerSeries, function (s) { return s.distance; });
|
|
220
|
+
var pointIndex = closestPointPerSeries[closestSeriesIndex].pointIndex;
|
|
221
|
+
var point = series[closestSeriesIndex].values[pointIndex];
|
|
222
|
+
return {
|
|
223
|
+
seriesIndex: closestSeriesIndex,
|
|
224
|
+
labels: series[closestSeriesIndex].metric,
|
|
225
|
+
timestamp: point[0],
|
|
226
|
+
value: point[1],
|
|
227
|
+
x: xScale(point[0]),
|
|
228
|
+
y: yScale(point[1]),
|
|
229
|
+
};
|
|
230
|
+
};
|
|
231
|
+
var highlighted = getClosest();
|
|
232
|
+
var onMouseDown = function (e) {
|
|
233
|
+
// only left mouse button
|
|
234
|
+
if (e.button !== 0) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
// X/Y coordinate array relative to svg
|
|
238
|
+
var rel = pointer(e);
|
|
239
|
+
var xCoordinate = rel[0];
|
|
240
|
+
var xCoordinateWithoutMargin = xCoordinate - margin;
|
|
241
|
+
if (xCoordinateWithoutMargin >= 0) {
|
|
242
|
+
setRelPos(xCoordinateWithoutMargin);
|
|
243
|
+
setDragging(true);
|
|
244
|
+
}
|
|
245
|
+
e.stopPropagation();
|
|
246
|
+
e.preventDefault();
|
|
247
|
+
};
|
|
248
|
+
var openClosestProfile = function () {
|
|
249
|
+
if (highlighted != null) {
|
|
250
|
+
onSampleClick(Math.round(highlighted.timestamp), highlighted.value, highlighted.labels);
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
var onMouseUp = function (e) {
|
|
254
|
+
setDragging(false);
|
|
255
|
+
if (relPos === -1) {
|
|
256
|
+
// MouseDown happened outside of this element.
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
// This is a normal click. We tolerate tiny movements to still be a
|
|
260
|
+
// click as they can occur when clicking based on user feedback.
|
|
261
|
+
if (Math.abs(relPos - pos[0]) <= 1) {
|
|
262
|
+
openClosestProfile();
|
|
263
|
+
setRelPos(-1);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
var firstTime = xScale.invert(relPos).valueOf();
|
|
267
|
+
var secondTime = xScale.invert(pos[0]).valueOf();
|
|
268
|
+
if (firstTime > secondTime) {
|
|
269
|
+
setTimeRange(DateTimeRange.fromAbsoluteDates(secondTime, firstTime));
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
setTimeRange(DateTimeRange.fromAbsoluteDates(firstTime, secondTime));
|
|
273
|
+
}
|
|
274
|
+
setRelPos(-1);
|
|
275
|
+
e.stopPropagation();
|
|
276
|
+
e.preventDefault();
|
|
277
|
+
};
|
|
278
|
+
var throttledSetPos = throttle(setPos, 20);
|
|
279
|
+
var onMouseMove = function (e) {
|
|
280
|
+
// X/Y coordinate array relative to svg
|
|
281
|
+
var rel = pointer(e);
|
|
282
|
+
var xCoordinate = rel[0];
|
|
283
|
+
var xCoordinateWithoutMargin = xCoordinate - margin;
|
|
284
|
+
var yCoordinate = rel[1];
|
|
285
|
+
var yCoordinateWithoutMargin = yCoordinate - margin;
|
|
286
|
+
if (!freezeTooltip) {
|
|
287
|
+
throttledSetPos([xCoordinateWithoutMargin, yCoordinateWithoutMargin]);
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
var findSelectedProfile = function () {
|
|
291
|
+
if (profile == null) {
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
var s = null;
|
|
295
|
+
var seriesIndex = -1;
|
|
296
|
+
outer: for (var i = 0; i < series.length; i++) {
|
|
297
|
+
var keys = profile.labels.map(function (e) { return e.name; });
|
|
298
|
+
var _loop_1 = function (j) {
|
|
299
|
+
var labelName = keys[j];
|
|
300
|
+
var label = series[i].metric.find(function (e) { return e.name === labelName; });
|
|
301
|
+
if (label === undefined) {
|
|
302
|
+
return "continue-outer";
|
|
303
|
+
}
|
|
304
|
+
if (profile.labels[j].value !== label.value) {
|
|
305
|
+
return "continue-outer";
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
for (var j = 0; j < keys.length; j++) {
|
|
309
|
+
var state_1 = _loop_1(j);
|
|
310
|
+
switch (state_1) {
|
|
311
|
+
case "continue-outer": continue outer;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
seriesIndex = i;
|
|
315
|
+
s = series[i];
|
|
316
|
+
}
|
|
317
|
+
if (s == null) {
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
// Find the sample that matches the timestamp
|
|
321
|
+
var sample = s.values.find(function (v) {
|
|
322
|
+
return Math.round(v[0]) === time;
|
|
323
|
+
});
|
|
324
|
+
if (sample === undefined) {
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
return {
|
|
328
|
+
labels: [],
|
|
329
|
+
seriesIndex: seriesIndex,
|
|
330
|
+
timestamp: sample[0],
|
|
331
|
+
value: sample[1],
|
|
332
|
+
x: xScale(sample[0]),
|
|
333
|
+
y: yScale(sample[1]),
|
|
334
|
+
};
|
|
335
|
+
};
|
|
336
|
+
var selected = findSelectedProfile();
|
|
337
|
+
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
|
+
setHovering(true);
|
|
339
|
+
setFreezeTooltip(false);
|
|
340
|
+
}, 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
|
+
? lineStrokeHover
|
|
342
|
+
: 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
|
|
343
|
+
? { fill: color(selected.seriesIndex.toString()) }
|
|
344
|
+
: {} }, { children: _jsx(MetricsCircle, { cx: selected.x, cy: selected.y, radius: 5 }) }))), _jsx("g", __assign({ className: "x axis", fill: "none", fontSize: "10", textAnchor: "middle", transform: "translate(0,".concat(height - margin, ")") }, { children: xScale.ticks(5).map(function (d, i) { return (_jsxs("g", __assign({ className: "tick",
|
|
345
|
+
/* eslint-disable-next-line @typescript-eslint/restrict-template-expressions */
|
|
346
|
+
transform: "translate(".concat(xScale(d), ", 0)") }, { children: [_jsx("line", { y2: 6, stroke: "currentColor" }), _jsx("text", __assign({ fill: "currentColor", dy: ".71em", y: 9 }, { children: formatDate(d, formatForTimespan(from, to)) }))] }), i)); }) })), _jsx("g", __assign({ className: "y axis", textAnchor: "end", fontSize: "10", fill: "none" }, { children: yScale.ticks(3).map(function (d, i) { return (_jsxs("g", __assign({ className: "tick",
|
|
347
|
+
/* eslint-disable-next-line @typescript-eslint/restrict-template-expressions */
|
|
348
|
+
transform: "translate(0, ".concat(yScale(d), ")") }, { children: [_jsx("line", { stroke: "currentColor", x2: -6 }), _jsx("text", __assign({ fill: "currentColor", x: -9, dy: '0.32em' }, { children: valueFormatter(d, sampleUnit, 1) }))] }), i)); }) }))] }))] })) }))] }));
|
|
349
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as d3 from 'd3';
|
|
2
|
+
interface MetricsSeriesProps {
|
|
3
|
+
data: any;
|
|
4
|
+
line: d3.Line<[number, number]>;
|
|
5
|
+
color: string;
|
|
6
|
+
strokeWidth: string;
|
|
7
|
+
xScale: (input: number) => number;
|
|
8
|
+
yScale: (input: number) => number;
|
|
9
|
+
}
|
|
10
|
+
declare const MetricsSeries: ({ data, line, color, strokeWidth }: MetricsSeriesProps) => JSX.Element;
|
|
11
|
+
export default MetricsSeries;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
13
|
+
var MetricsSeries = function (_a) {
|
|
14
|
+
var _b;
|
|
15
|
+
var data = _a.data, line = _a.line, color = _a.color, strokeWidth = _a.strokeWidth;
|
|
16
|
+
return (_jsx("g", __assign({ className: "line-group" }, { children: _jsx("path", { className: "line", d: (_b = line(data.values)) !== null && _b !== void 0 ? _b : undefined, style: {
|
|
17
|
+
stroke: color,
|
|
18
|
+
strokeWidth: strokeWidth,
|
|
19
|
+
} }) })));
|
|
20
|
+
};
|
|
21
|
+
export default MetricsSeries;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ProfileSelection } from '..';
|
|
2
|
+
import { QueryServiceClient } from '@parca/client';
|
|
3
|
+
import { NavigateFunction } from '.';
|
|
4
|
+
import { QuerySelection } from '../ProfileSelector';
|
|
5
|
+
interface ProfileExplorerCompareProps {
|
|
6
|
+
queryClient: QueryServiceClient;
|
|
7
|
+
queryA: QuerySelection;
|
|
8
|
+
queryB: QuerySelection;
|
|
9
|
+
profileA: ProfileSelection | null;
|
|
10
|
+
profileB: ProfileSelection | null;
|
|
11
|
+
selectQueryA: (query: QuerySelection) => void;
|
|
12
|
+
selectQueryB: (query: QuerySelection) => void;
|
|
13
|
+
selectProfileA: (source: ProfileSelection) => void;
|
|
14
|
+
selectProfileB: (source: ProfileSelection) => void;
|
|
15
|
+
closeProfile: (card: string) => void;
|
|
16
|
+
navigateTo: NavigateFunction;
|
|
17
|
+
}
|
|
18
|
+
declare const ProfileExplorerCompare: ({ queryClient, queryA, queryB, profileA, profileB, selectQueryA, selectQueryB, selectProfileA, selectProfileB, closeProfile, navigateTo, }: ProfileExplorerCompareProps) => JSX.Element;
|
|
19
|
+
export default ProfileExplorerCompare;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
13
|
+
// Copyright 2022 The Parca Authors
|
|
14
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
15
|
+
// you may not use this file except in compliance with the License.
|
|
16
|
+
// You may obtain a copy of the License at
|
|
17
|
+
//
|
|
18
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
19
|
+
//
|
|
20
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
21
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
22
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
23
|
+
// See the License for the specific language governing permissions and
|
|
24
|
+
// limitations under the License.
|
|
25
|
+
import { ProfileDiffSource, ProfileViewWithData } from '..';
|
|
26
|
+
import { Query } from '@parca/parser';
|
|
27
|
+
import ProfileSelector from '../ProfileSelector';
|
|
28
|
+
var ProfileExplorerCompare = function (_a) {
|
|
29
|
+
var queryClient = _a.queryClient, queryA = _a.queryA, queryB = _a.queryB, profileA = _a.profileA, profileB = _a.profileB, selectQueryA = _a.selectQueryA, selectQueryB = _a.selectQueryB, selectProfileA = _a.selectProfileA, selectProfileB = _a.selectProfileB, closeProfile = _a.closeProfile, navigateTo = _a.navigateTo;
|
|
30
|
+
var closeProfileA = function () {
|
|
31
|
+
closeProfile('A');
|
|
32
|
+
};
|
|
33
|
+
var closeProfileB = function () {
|
|
34
|
+
closeProfile('B');
|
|
35
|
+
};
|
|
36
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", __assign({ className: "grid grid-cols-2" }, { children: [_jsx("div", __assign({ className: "pr-2" }, { children: _jsx(ProfileSelector, { queryClient: queryClient, querySelection: queryA, profileSelection: profileA, selectProfile: selectProfileA, selectQuery: selectQueryA, closeProfile: closeProfileA, enforcedProfileName: '', comparing: true, onCompareProfile: function () { } }) })), _jsx("div", __assign({ className: "pl-2" }, { children: _jsx(ProfileSelector, { queryClient: queryClient, querySelection: queryB, profileSelection: profileB, selectProfile: selectProfileB, selectQuery: selectQueryB, closeProfile: closeProfileB, enforcedProfileName: Query.parse(queryA.expression).profileName(), comparing: true, onCompareProfile: function () { } }) }))] })), _jsx("div", __assign({ className: "grid grid-cols-1" }, { children: profileA != null && profileB != null ? (_jsx(ProfileViewWithData, { navigateTo: navigateTo, queryClient: queryClient, profileSource: new ProfileDiffSource(profileA.ProfileSource(), profileB.ProfileSource()) })) : (_jsx("div", { children: _jsx("div", __assign({ className: "my-20 text-center" }, { children: _jsx("p", { children: "Select a profile on both sides." }) })) })) }))] }));
|
|
37
|
+
};
|
|
38
|
+
export default ProfileExplorerCompare;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { QueryServiceClient } from '@parca/client';
|
|
2
|
+
import { ProfileSelection } from '..';
|
|
3
|
+
import { NavigateFunction } from '../ProfileExplorer';
|
|
4
|
+
import { QuerySelection } from '../ProfileSelector';
|
|
5
|
+
interface ProfileExplorerSingleProps {
|
|
6
|
+
queryClient: QueryServiceClient;
|
|
7
|
+
query: QuerySelection;
|
|
8
|
+
selectQuery: (query: QuerySelection) => void;
|
|
9
|
+
selectProfile: (source: ProfileSelection) => void;
|
|
10
|
+
profile: ProfileSelection | null;
|
|
11
|
+
compareProfile: () => void;
|
|
12
|
+
navigateTo: NavigateFunction;
|
|
13
|
+
}
|
|
14
|
+
declare const ProfileExplorerSingle: ({ queryClient, query, selectQuery, selectProfile, profile, compareProfile, navigateTo, }: ProfileExplorerSingleProps) => JSX.Element;
|
|
15
|
+
export default ProfileExplorerSingle;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
+
import { ProfileViewWithData } from '..';
|
|
14
|
+
import ProfileSelector from '../ProfileSelector';
|
|
15
|
+
var ProfileExplorerSingle = function (_a) {
|
|
16
|
+
var queryClient = _a.queryClient, query = _a.query, selectQuery = _a.selectQuery, selectProfile = _a.selectProfile, profile = _a.profile, compareProfile = _a.compareProfile, navigateTo = _a.navigateTo;
|
|
17
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", __assign({ className: "grid grid-cols-1" }, { children: _jsx("div", { children: _jsx(ProfileSelector, { queryClient: queryClient, querySelection: query, selectQuery: selectQuery, selectProfile: selectProfile, closeProfile: function () { }, profileSelection: profile, comparing: false, onCompareProfile: compareProfile, enforcedProfileName: '' }) }) })), _jsx("div", __assign({ className: "grid grid-cols-1" }, { children: _jsx("div", { children: profile != null ? (_jsx(ProfileViewWithData, { queryClient: queryClient, profileSource: profile.ProfileSource(), navigateTo: navigateTo })) : (_jsx(_Fragment, {})) }) }))] }));
|
|
18
|
+
};
|
|
19
|
+
export default ProfileExplorerSingle;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { QueryServiceClient } from '@parca/client';
|
|
2
|
+
export declare type NavigateFunction = (path: string, queryParams: any) => void;
|
|
3
|
+
interface ProfileExplorerProps {
|
|
4
|
+
queryClient: QueryServiceClient;
|
|
5
|
+
queryParams: any;
|
|
6
|
+
navigateTo: NavigateFunction;
|
|
7
|
+
}
|
|
8
|
+
declare const ProfileExplorer: ({ queryClient, queryParams, navigateTo, }: ProfileExplorerProps) => JSX.Element;
|
|
9
|
+
export default ProfileExplorer;
|