@parca/profile 0.16.183 → 0.16.185
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/constants.js +2 -2
- package/dist/Callgraph/index.js +35 -45
- package/dist/Callgraph/mockData/index.js +28 -11
- package/dist/Callgraph/utils.js +51 -58
- package/dist/GraphTooltip/ExpandOnHoverValue.js +2 -14
- package/dist/GraphTooltip/index.d.ts +5 -5
- package/dist/GraphTooltip/index.js +96 -122
- package/dist/MatchersInput/SuggestionItem.js +5 -17
- package/dist/MatchersInput/SuggestionsList.js +29 -53
- package/dist/MatchersInput/index.js +58 -74
- package/dist/MetricsCircle/index.js +2 -16
- package/dist/MetricsGraph/MetricsTooltip/index.js +27 -53
- package/dist/MetricsGraph/index.js +79 -98
- package/dist/MetricsSeries/index.js +4 -19
- package/dist/ProfileExplorer/ProfileExplorerCompare.js +4 -16
- package/dist/ProfileExplorer/ProfileExplorerSingle.js +2 -14
- package/dist/ProfileExplorer/index.js +129 -88
- package/dist/ProfileIcicleGraph/IcicleGraph/ColorStackLegend.js +15 -31
- package/dist/ProfileIcicleGraph/IcicleGraph/IcicleGraphNodes.d.ts +4 -4
- package/dist/ProfileIcicleGraph/IcicleGraph/IcicleGraphNodes.js +38 -54
- package/dist/ProfileIcicleGraph/IcicleGraph/index.d.ts +2 -2
- package/dist/ProfileIcicleGraph/IcicleGraph/index.js +15 -31
- package/dist/ProfileIcicleGraph/IcicleGraph/useColoredGraph.js +22 -26
- package/dist/ProfileIcicleGraph/IcicleGraph/useNodeColor.js +8 -9
- package/dist/ProfileIcicleGraph/IcicleGraph/utils.js +18 -20
- package/dist/ProfileIcicleGraph/index.d.ts +2 -2
- package/dist/ProfileIcicleGraph/index.js +18 -30
- package/dist/ProfileMetricsGraph/index.js +36 -88
- package/dist/ProfileSelector/CompareButton.js +8 -20
- package/dist/ProfileSelector/index.js +69 -69
- package/dist/ProfileSource.js +56 -65
- package/dist/ProfileTypeSelector/index.js +14 -28
- package/dist/ProfileView/FilterByFunctionButton.js +6 -7
- package/dist/ProfileView/ViewSelector.js +18 -31
- package/dist/ProfileView/VisualizationPanel.js +4 -16
- package/dist/ProfileView/index.d.ts +2 -1
- package/dist/ProfileView/index.js +73 -151
- package/dist/ProfileViewWithData.js +50 -97
- package/dist/TopTable/index.js +55 -63
- package/dist/components/DiffLegend.js +16 -28
- package/dist/components/ProfileShareButton/ResultBox.js +7 -21
- package/dist/components/ProfileShareButton/index.js +31 -90
- package/dist/useDelayedLoader.js +7 -8
- package/dist/useGrpcQuery/index.js +6 -48
- package/dist/useQuery.js +14 -58
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +16 -68
- package/package.json +6 -6
- package/src/Callgraph/index.tsx +3 -3
- package/src/Callgraph/utils.ts +1 -1
- package/src/GraphTooltip/index.tsx +17 -17
- package/src/MetricsGraph/index.tsx +3 -3
- package/src/ProfileIcicleGraph/IcicleGraph/IcicleGraphNodes.tsx +9 -10
- package/src/ProfileIcicleGraph/IcicleGraph/index.tsx +4 -8
- package/src/ProfileIcicleGraph/IcicleGraph/useNodeColor.ts +2 -2
- package/src/ProfileIcicleGraph/index.tsx +8 -8
- package/src/ProfileView/index.tsx +8 -3
- package/src/ProfileViewWithData.tsx +5 -0
- package/src/TopTable/index.tsx +3 -3
- package/src/utils.ts +2 -2
|
@@ -1,14 +1,3 @@
|
|
|
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
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
2
|
// Copyright 2022 The Parca Authors
|
|
14
3
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -32,31 +21,30 @@ import MatchersInput from '../MatchersInput/index';
|
|
|
32
21
|
import ProfileMetricsGraph from '../ProfileMetricsGraph';
|
|
33
22
|
import ProfileTypeSelector from '../ProfileTypeSelector/index';
|
|
34
23
|
import CompareButton from './CompareButton';
|
|
35
|
-
export
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
useEffect(
|
|
24
|
+
export const useProfileTypes = (client) => {
|
|
25
|
+
const [result, setResult] = useState(undefined);
|
|
26
|
+
const [error, setError] = useState(undefined);
|
|
27
|
+
const [loading, setLoading] = useState(true);
|
|
28
|
+
const metadata = useGrpcMetadata();
|
|
29
|
+
useEffect(() => {
|
|
41
30
|
if (!loading) {
|
|
42
31
|
return;
|
|
43
32
|
}
|
|
44
|
-
|
|
33
|
+
const call = client.profileTypes({}, { meta: metadata });
|
|
45
34
|
call.response
|
|
46
|
-
.then(
|
|
47
|
-
.catch(
|
|
48
|
-
.finally(
|
|
35
|
+
.then(response => setResult(response))
|
|
36
|
+
.catch(error => setError(error))
|
|
37
|
+
.finally(() => setLoading(false));
|
|
49
38
|
}, [client, metadata, loading]);
|
|
50
|
-
return { loading
|
|
39
|
+
return { loading, data: result, error };
|
|
51
40
|
};
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
useEffect(function () {
|
|
41
|
+
const ProfileSelector = ({ queryClient, querySelection, selectProfile, selectQuery, closeProfile, enforcedProfileName, profileSelection, comparing, onCompareProfile, }) => {
|
|
42
|
+
const { loading: profileTypesLoading, data: profileTypesData, error, } = useProfileTypes(queryClient);
|
|
43
|
+
const [timeRangeSelection, setTimeRangeSelection] = useState(DateTimeRange.fromRangeKey(querySelection.timeSelection));
|
|
44
|
+
const [queryExpressionString, setQueryExpressionString] = useState(querySelection.expression);
|
|
45
|
+
useEffect(() => {
|
|
58
46
|
if (enforcedProfileName !== '') {
|
|
59
|
-
|
|
47
|
+
const [q, changed] = Query.parse(querySelection.expression).setProfileName(enforcedProfileName);
|
|
60
48
|
if (changed) {
|
|
61
49
|
setQueryExpressionString(q.toString());
|
|
62
50
|
return;
|
|
@@ -64,89 +52,101 @@ var ProfileSelector = function (_a) {
|
|
|
64
52
|
}
|
|
65
53
|
setQueryExpressionString(querySelection.expression);
|
|
66
54
|
}, [enforcedProfileName, querySelection.expression]);
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
55
|
+
const enforcedProfileNameQuery = () => {
|
|
56
|
+
const pq = Query.parse(queryExpressionString);
|
|
57
|
+
const [q] = pq.setProfileName(enforcedProfileName);
|
|
70
58
|
return q;
|
|
71
59
|
};
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
60
|
+
const query = enforcedProfileName !== '' ? enforcedProfileNameQuery() : Query.parse(queryExpressionString);
|
|
61
|
+
const selectedProfileName = query.profileName();
|
|
62
|
+
const setNewQueryExpression = (expr) => {
|
|
63
|
+
const query = enforcedProfileName !== '' ? enforcedProfileNameQuery() : Query.parse(expr);
|
|
64
|
+
const delta = query.profileType().delta;
|
|
65
|
+
const from = timeRangeSelection.getFromMs();
|
|
66
|
+
const to = timeRangeSelection.getToMs();
|
|
67
|
+
const mergeParams = delta
|
|
80
68
|
? {
|
|
81
69
|
mergeFrom: from,
|
|
82
70
|
mergeTo: to,
|
|
83
71
|
}
|
|
84
72
|
: {};
|
|
85
|
-
selectQuery(
|
|
73
|
+
selectQuery({
|
|
74
|
+
expression: expr,
|
|
75
|
+
from,
|
|
76
|
+
to,
|
|
77
|
+
timeSelection: timeRangeSelection.getRangeKey(),
|
|
78
|
+
...mergeParams,
|
|
79
|
+
});
|
|
86
80
|
};
|
|
87
|
-
|
|
81
|
+
const setQueryExpression = () => {
|
|
88
82
|
setNewQueryExpression(query.toString());
|
|
89
83
|
};
|
|
90
|
-
|
|
84
|
+
const addLabelMatcher = (key, value) => {
|
|
91
85
|
// When a user clicks on a label on the metrics graph tooltip,
|
|
92
86
|
// replace single `\` in the `value` string with doubles `\\` if available.
|
|
93
|
-
|
|
94
|
-
|
|
87
|
+
const newValue = value.includes('\\') ? value.replaceAll('\\', '\\\\') : value;
|
|
88
|
+
const [newQuery, changed] = Query.parse(queryExpressionString).setMatcher(key, newValue);
|
|
95
89
|
if (changed) {
|
|
96
90
|
// TODO: Change this to store the query object
|
|
97
91
|
setNewQueryExpression(newQuery.toString());
|
|
98
92
|
}
|
|
99
93
|
};
|
|
100
|
-
|
|
101
|
-
|
|
94
|
+
const setMatchersString = (matchers) => {
|
|
95
|
+
const newExpressionString = `${selectedProfileName}{${matchers}}`;
|
|
102
96
|
setQueryExpressionString(newExpressionString);
|
|
103
97
|
};
|
|
104
|
-
|
|
98
|
+
const setProfileName = (profileName) => {
|
|
105
99
|
if (profileName === undefined) {
|
|
106
100
|
return;
|
|
107
101
|
}
|
|
108
|
-
|
|
102
|
+
const [newQuery, changed] = query.setProfileName(profileName);
|
|
109
103
|
if (changed) {
|
|
110
|
-
|
|
104
|
+
const q = newQuery.toString();
|
|
111
105
|
setQueryExpressionString(q);
|
|
112
106
|
}
|
|
113
107
|
};
|
|
114
|
-
|
|
115
|
-
|
|
108
|
+
const handleCompareClick = () => onCompareProfile();
|
|
109
|
+
const searchDisabled = queryExpressionString === undefined ||
|
|
116
110
|
queryExpressionString === '' ||
|
|
117
111
|
queryExpressionString === '{}';
|
|
118
|
-
|
|
119
|
-
return (_jsxs(Card,
|
|
112
|
+
const compareDisabled = selectedProfileName === '' || querySelection.expression === undefined;
|
|
113
|
+
return (_jsxs(Card, { className: "overflow-visible", children: [_jsxs(Card.Header, { className: "flex !items-center space-x-2", children: [_jsxs("div", { className: "flex w-full flex-wrap items-center justify-start space-x-2 space-y-1", children: [_jsx("div", { className: "ml-2 mt-1", children: _jsx(ProfileTypeSelector, { profileTypesData: profileTypesData, loading: profileTypesLoading, selectedKey: selectedProfileName, onSelection: setProfileName, error: error }) }), _jsx("div", { className: "w-full flex-1", children: _jsx(MatchersInput, { queryClient: queryClient, setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query }) }), _jsx(DateTimeRangePicker, { onRangeSelection: setTimeRangeSelection, range: timeRangeSelection }), _jsxs(ButtonGroup, { children: [!searchDisabled && (_jsx(_Fragment, { children: !comparing && (_jsx(CompareButton, { disabled: compareDisabled, onClick: handleCompareClick })) })), _jsx(Button, { disabled: searchDisabled, onClick: (e) => {
|
|
120
114
|
e.preventDefault();
|
|
121
115
|
setQueryExpression();
|
|
122
|
-
}
|
|
116
|
+
}, children: "Search" })] })] }), _jsx("div", { children: comparing && _jsx(IconButton, { onClick: () => closeProfile(), icon: _jsx(CloseIcon, {}) }) })] }), _jsx(Card.Body, { children: querySelection.expression !== undefined &&
|
|
123
117
|
querySelection.expression.length > 0 &&
|
|
124
118
|
querySelection.from !== undefined &&
|
|
125
|
-
querySelection.to !== undefined ? (_jsx(ProfileMetricsGraph, { queryClient: queryClient, queryExpression: querySelection.expression, from: querySelection.from, to: querySelection.to, profile: profileSelection, setTimeRange:
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
119
|
+
querySelection.to !== undefined ? (_jsx(ProfileMetricsGraph, { queryClient: queryClient, queryExpression: querySelection.expression, from: querySelection.from, to: querySelection.to, profile: profileSelection, setTimeRange: (range) => {
|
|
120
|
+
const from = range.getFromMs();
|
|
121
|
+
const to = range.getToMs();
|
|
122
|
+
let mergedProfileParams = {};
|
|
129
123
|
if (query.profileType().delta) {
|
|
130
124
|
mergedProfileParams = { mergeFrom: from, mergeTo: to };
|
|
131
125
|
}
|
|
132
126
|
setTimeRangeSelection(range);
|
|
133
|
-
selectQuery(
|
|
134
|
-
|
|
127
|
+
selectQuery({
|
|
128
|
+
expression: queryExpressionString,
|
|
129
|
+
from,
|
|
130
|
+
to,
|
|
131
|
+
timeSelection: range.getRangeKey(),
|
|
132
|
+
...mergedProfileParams,
|
|
133
|
+
});
|
|
134
|
+
}, addLabelMatcher: addLabelMatcher, onPointClick: (timestamp, labels, queryExpression) => {
|
|
135
135
|
// TODO: Pass the query object via click rather than queryExpression
|
|
136
|
-
|
|
137
|
-
labels.forEach(
|
|
138
|
-
|
|
136
|
+
let query = Query.parse(queryExpression);
|
|
137
|
+
labels.forEach(l => {
|
|
138
|
+
const [newQuery, updated] = query.setMatcher(l.name, l.value);
|
|
139
139
|
if (updated) {
|
|
140
140
|
query = newQuery;
|
|
141
141
|
}
|
|
142
142
|
});
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
143
|
+
const stepDuration = getStepDuration(querySelection.from, querySelection.to);
|
|
144
|
+
const stepDurationInMilliseconds = getStepDurationInMilliseconds(stepDuration);
|
|
145
|
+
const mergeFrom = timestamp;
|
|
146
|
+
const mergeTo = query.profileType().delta
|
|
147
147
|
? mergeFrom + stepDurationInMilliseconds
|
|
148
148
|
: mergeFrom;
|
|
149
149
|
selectProfile(new MergedProfileSelection(mergeFrom, mergeTo, query));
|
|
150
|
-
} })) : (_jsx(_Fragment, { children: profileSelection == null && (_jsx("div",
|
|
150
|
+
} })) : (_jsx(_Fragment, { children: profileSelection == null && (_jsx("div", { className: "my-20 text-center", children: _jsx("p", { children: "Run a query, and the result will be displayed here." }) })) })) })] }));
|
|
151
151
|
};
|
|
152
152
|
export default ProfileSelector;
|
package/dist/ProfileSource.js
CHANGED
|
@@ -14,26 +14,23 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
14
14
|
import { ProfileDiffSelection_Mode, QueryRequest_Mode, QueryRequest_ReportType, Timestamp, } from '@parca/client';
|
|
15
15
|
import { ProfileType, Query } from '@parca/parser';
|
|
16
16
|
import { formatDate } from '@parca/utilities';
|
|
17
|
-
export
|
|
18
|
-
export
|
|
17
|
+
export const timeFormat = "MMM d, 'at' h:mm:s a '(UTC)'";
|
|
18
|
+
export const timeFormatShort = 'MMM d, h:mma';
|
|
19
19
|
export function ParamsString(params) {
|
|
20
20
|
return Object.keys(params)
|
|
21
21
|
.map(function (key) {
|
|
22
|
-
return
|
|
22
|
+
return `${key}=${params[key]}`;
|
|
23
23
|
})
|
|
24
24
|
.join('&');
|
|
25
25
|
}
|
|
26
26
|
export function SuffixParams(params, suffix) {
|
|
27
|
-
return Object.fromEntries(Object.entries(params).map(
|
|
28
|
-
var key = _a[0], value = _a[1];
|
|
29
|
-
return ["".concat(key).concat(suffix), value];
|
|
30
|
-
}));
|
|
27
|
+
return Object.fromEntries(Object.entries(params).map(([key, value]) => [`${key}${suffix}`, value]));
|
|
31
28
|
}
|
|
32
29
|
export function ParseLabels(labels) {
|
|
33
30
|
return labels
|
|
34
|
-
.filter(
|
|
31
|
+
.filter(str => str !== '')
|
|
35
32
|
.map(function (labelString) {
|
|
36
|
-
|
|
33
|
+
const parts = labelString.split('=', 2);
|
|
37
34
|
return { name: parts[0], value: parts[1] };
|
|
38
35
|
});
|
|
39
36
|
}
|
|
@@ -44,60 +41,58 @@ export function ProfileSelectionFromParams(expression, from, to, mergeFrom, merg
|
|
|
44
41
|
mergeTo !== undefined &&
|
|
45
42
|
expression !== undefined) {
|
|
46
43
|
// TODO: Refactor parsing the query and adding matchers
|
|
47
|
-
|
|
44
|
+
let query = Query.parse(expression);
|
|
48
45
|
if (labels !== undefined) {
|
|
49
|
-
ParseLabels(labels
|
|
50
|
-
|
|
46
|
+
ParseLabels(labels ?? ['']).forEach(l => {
|
|
47
|
+
const hasLabels = labels.length > 0 && labels.filter(val => val !== '').length > 0;
|
|
51
48
|
if (hasLabels) {
|
|
52
|
-
|
|
49
|
+
const [newQuery, changed] = query.setMatcher(l.name, l.value);
|
|
53
50
|
if (changed) {
|
|
54
|
-
|
|
51
|
+
query = newQuery;
|
|
55
52
|
}
|
|
56
53
|
}
|
|
57
54
|
});
|
|
58
55
|
}
|
|
59
|
-
return new MergedProfileSelection(parseInt(mergeFrom), parseInt(mergeTo),
|
|
56
|
+
return new MergedProfileSelection(parseInt(mergeFrom), parseInt(mergeTo), query, filterQuery);
|
|
60
57
|
}
|
|
61
58
|
return null;
|
|
62
59
|
}
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
export class MergedProfileSelection {
|
|
61
|
+
constructor(mergeFrom, mergeTo, query, filterQuery) {
|
|
65
62
|
this.mergeFrom = mergeFrom;
|
|
66
63
|
this.mergeTo = mergeTo;
|
|
67
64
|
this.query = query;
|
|
68
65
|
this.filterQuery = filterQuery;
|
|
69
66
|
}
|
|
70
|
-
|
|
67
|
+
ProfileName() {
|
|
71
68
|
return this.query.profileName();
|
|
72
|
-
}
|
|
73
|
-
|
|
69
|
+
}
|
|
70
|
+
HistoryParams() {
|
|
74
71
|
return {
|
|
75
72
|
merge_from: this.mergeFrom.toString(),
|
|
76
73
|
merge_to: this.mergeTo.toString(),
|
|
77
74
|
query: this.query,
|
|
78
75
|
profile_name: this.ProfileName(),
|
|
79
|
-
labels: this.query.matchers.map(
|
|
76
|
+
labels: this.query.matchers.map(m => `${m.key}=${encodeURIComponent(m.value)}`),
|
|
80
77
|
};
|
|
81
|
-
}
|
|
82
|
-
|
|
78
|
+
}
|
|
79
|
+
Type() {
|
|
83
80
|
return 'merge';
|
|
84
|
-
}
|
|
85
|
-
|
|
81
|
+
}
|
|
82
|
+
ProfileSource() {
|
|
86
83
|
return new MergedProfileSource(this.mergeFrom, this.mergeTo, this.query, this.filterQuery);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
var ProfileDiffSource = /** @class */ (function () {
|
|
92
|
-
function ProfileDiffSource(a, b, filterQuery) {
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export class ProfileDiffSource {
|
|
87
|
+
constructor(a, b, filterQuery) {
|
|
93
88
|
this.a = a;
|
|
94
89
|
this.b = b;
|
|
95
90
|
this.filterQuery = filterQuery;
|
|
96
91
|
}
|
|
97
|
-
|
|
92
|
+
DiffSelection() {
|
|
98
93
|
throw new Error('Method not implemented.');
|
|
99
|
-
}
|
|
100
|
-
|
|
94
|
+
}
|
|
95
|
+
QueryRequest() {
|
|
101
96
|
return {
|
|
102
97
|
options: {
|
|
103
98
|
oneofKind: 'diff',
|
|
@@ -110,27 +105,25 @@ var ProfileDiffSource = /** @class */ (function () {
|
|
|
110
105
|
mode: QueryRequest_Mode.DIFF,
|
|
111
106
|
filterQuery: this.filterQuery,
|
|
112
107
|
};
|
|
113
|
-
}
|
|
114
|
-
|
|
108
|
+
}
|
|
109
|
+
ProfileType() {
|
|
115
110
|
return this.a.ProfileType();
|
|
116
|
-
}
|
|
117
|
-
|
|
111
|
+
}
|
|
112
|
+
Describe() {
|
|
118
113
|
return (_jsx(_Fragment, { children: _jsx("p", { children: "Browse the comparison" }) }));
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
var MergedProfileSource = /** @class */ (function () {
|
|
127
|
-
function MergedProfileSource(mergeFrom, mergeTo, query, filterQuery) {
|
|
114
|
+
}
|
|
115
|
+
toString() {
|
|
116
|
+
return `${this.a.toString()} compared with ${this.b.toString()}`;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
export class MergedProfileSource {
|
|
120
|
+
constructor(mergeFrom, mergeTo, query, filterQuery) {
|
|
128
121
|
this.mergeFrom = mergeFrom;
|
|
129
122
|
this.mergeTo = mergeTo;
|
|
130
123
|
this.query = query;
|
|
131
124
|
this.filterQuery = filterQuery;
|
|
132
125
|
}
|
|
133
|
-
|
|
126
|
+
DiffSelection() {
|
|
134
127
|
return {
|
|
135
128
|
options: {
|
|
136
129
|
oneofKind: 'merge',
|
|
@@ -142,8 +135,8 @@ var MergedProfileSource = /** @class */ (function () {
|
|
|
142
135
|
},
|
|
143
136
|
mode: ProfileDiffSelection_Mode.MERGE,
|
|
144
137
|
};
|
|
145
|
-
}
|
|
146
|
-
|
|
138
|
+
}
|
|
139
|
+
QueryRequest() {
|
|
147
140
|
return {
|
|
148
141
|
options: {
|
|
149
142
|
oneofKind: 'merge',
|
|
@@ -157,21 +150,19 @@ var MergedProfileSource = /** @class */ (function () {
|
|
|
157
150
|
mode: QueryRequest_Mode.MERGE,
|
|
158
151
|
filterQuery: this.filterQuery,
|
|
159
152
|
};
|
|
160
|
-
}
|
|
161
|
-
|
|
153
|
+
}
|
|
154
|
+
ProfileType() {
|
|
162
155
|
return ProfileType.fromString(Query.parse(this.query.toString()).profileName());
|
|
163
|
-
}
|
|
164
|
-
|
|
156
|
+
}
|
|
157
|
+
Describe() {
|
|
165
158
|
return (_jsxs("a", { children: ["Merge of \"", this.query.toString(), "\" from ", formatDate(this.mergeFrom, timeFormat), ' ', "to ", formatDate(this.mergeTo, timeFormat)] }));
|
|
166
|
-
}
|
|
167
|
-
|
|
159
|
+
}
|
|
160
|
+
stringMatchers() {
|
|
168
161
|
return this.query.matchers
|
|
169
|
-
.filter(
|
|
170
|
-
.map(
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
return
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
}());
|
|
177
|
-
export { MergedProfileSource };
|
|
162
|
+
.filter((m) => m.key !== '__name__')
|
|
163
|
+
.map((m) => `${m.key}=${m.value}`);
|
|
164
|
+
}
|
|
165
|
+
toString() {
|
|
166
|
+
return `merged profiles of query "${this.query.toString()}" from ${formatDate(this.mergeFrom, timeFormat)} to ${formatDate(this.mergeTo, timeFormat)}`;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
@@ -1,14 +1,3 @@
|
|
|
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
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
2
|
// Copyright 2022 The Parca Authors
|
|
14
3
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -24,7 +13,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
24
13
|
// limitations under the License.
|
|
25
14
|
import { useMemo } from 'react';
|
|
26
15
|
import { Select } from '@parca/components';
|
|
27
|
-
export
|
|
16
|
+
export const wellKnownProfiles = {
|
|
28
17
|
'block:contentions:count:contentions:count': {
|
|
29
18
|
name: 'Block Contentions Total',
|
|
30
19
|
help: 'Stack traces that led to blocking on synchronization primitives.',
|
|
@@ -91,9 +80,9 @@ export var wellKnownProfiles = {
|
|
|
91
80
|
},
|
|
92
81
|
};
|
|
93
82
|
function flexibleWellKnownProfileMatching(name) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
83
|
+
const prefixExcludedName = name.split(':').slice(1).join(':');
|
|
84
|
+
const deltaExcludedName = prefixExcludedName.replace(/:delta$/, '');
|
|
85
|
+
const requiredKey = Object.keys(wellKnownProfiles).find(key => {
|
|
97
86
|
if (key.includes(deltaExcludedName)) {
|
|
98
87
|
return true;
|
|
99
88
|
}
|
|
@@ -102,39 +91,36 @@ function flexibleWellKnownProfileMatching(name) {
|
|
|
102
91
|
return requiredKey != null ? wellKnownProfiles[requiredKey] : undefined;
|
|
103
92
|
}
|
|
104
93
|
export function profileSelectElement(name, flexibleKnownProfilesDetection) {
|
|
105
|
-
|
|
94
|
+
const wellKnown = !flexibleKnownProfilesDetection
|
|
106
95
|
? wellKnownProfiles[name]
|
|
107
96
|
: flexibleWellKnownProfileMatching(name);
|
|
108
97
|
if (wellKnown === undefined)
|
|
109
98
|
return { active: _jsx(_Fragment, { children: name }), expanded: _jsx(_Fragment, { children: name }) };
|
|
110
|
-
|
|
99
|
+
const title = wellKnown.name.replace(/ /g, '\u00a0');
|
|
111
100
|
return {
|
|
112
101
|
active: _jsx(_Fragment, { children: title }),
|
|
113
|
-
expanded: (_jsxs(_Fragment, { children: [_jsx("span", { children: title }), _jsx("br", {}), _jsx("span",
|
|
102
|
+
expanded: (_jsxs(_Fragment, { children: [_jsx("span", { children: title }), _jsx("br", {}), _jsx("span", { className: "text-xs", children: wellKnown.help })] })),
|
|
114
103
|
};
|
|
115
104
|
}
|
|
116
|
-
export
|
|
105
|
+
export const normalizeProfileTypesData = (types) => {
|
|
117
106
|
return types
|
|
118
|
-
.map(
|
|
119
|
-
|
|
120
|
-
})
|
|
121
|
-
.sort(function (a, b) {
|
|
107
|
+
.map(type => `${type.name}:${type.sampleType}:${type.sampleUnit}:${type.periodType}:${type.periodUnit}${type.delta ? ':delta' : ''}`)
|
|
108
|
+
.sort((a, b) => {
|
|
122
109
|
return a.localeCompare(b);
|
|
123
110
|
});
|
|
124
111
|
};
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
var profileNames = useMemo(function () {
|
|
112
|
+
const ProfileTypeSelector = ({ profileTypesData, loading = false, error, selectedKey, onSelection, flexibleKnownProfilesDetection = false, }) => {
|
|
113
|
+
const profileNames = useMemo(() => {
|
|
128
114
|
return (error === undefined || error == null) &&
|
|
129
115
|
profileTypesData !== undefined &&
|
|
130
116
|
profileTypesData != null
|
|
131
117
|
? normalizeProfileTypesData(profileTypesData.types)
|
|
132
118
|
: [];
|
|
133
119
|
}, [profileTypesData, error]);
|
|
134
|
-
|
|
120
|
+
const profileLabels = profileNames.map(name => ({
|
|
135
121
|
key: name,
|
|
136
122
|
element: profileSelectElement(name, flexibleKnownProfilesDetection),
|
|
137
|
-
})
|
|
123
|
+
}));
|
|
138
124
|
return (_jsx(Select, { items: profileLabels, selectedKey: selectedKey, onSelection: onSelection, placeholder: "Select profile...", loading: loading }));
|
|
139
125
|
};
|
|
140
126
|
export default ProfileTypeSelector;
|
|
@@ -14,14 +14,13 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
14
14
|
import { useCallback, useMemo, useState } from 'react';
|
|
15
15
|
import { Icon } from '@iconify/react';
|
|
16
16
|
import { Input, useURLState } from '@parca/components';
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
var isClearAction = useMemo(function () {
|
|
17
|
+
const FilterByFunctionButton = ({ navigateTo, }) => {
|
|
18
|
+
const [storeValue, setStoreValue] = useURLState({ param: 'filter_by_function', navigateTo });
|
|
19
|
+
const [localValue, setLocalValue] = useState(storeValue);
|
|
20
|
+
const isClearAction = useMemo(() => {
|
|
22
21
|
return localValue === storeValue && localValue != null && localValue !== '';
|
|
23
22
|
}, [localValue, storeValue]);
|
|
24
|
-
|
|
23
|
+
const onAction = useCallback(() => {
|
|
25
24
|
if (isClearAction) {
|
|
26
25
|
setLocalValue('');
|
|
27
26
|
setStoreValue('');
|
|
@@ -30,6 +29,6 @@ var FilterByFunctionButton = function (_a) {
|
|
|
30
29
|
setStoreValue(localValue);
|
|
31
30
|
}
|
|
32
31
|
}, [localValue, isClearAction, setStoreValue]);
|
|
33
|
-
return (_jsx(Input, { placeholder: "Filter by function", className: "text-sm", onAction: onAction, onChange:
|
|
32
|
+
return (_jsx(Input, { placeholder: "Filter by function", className: "text-sm", onAction: onAction, onChange: e => setLocalValue(e.target.value), value: localValue ?? '', onBlur: () => setLocalValue(storeValue), actionIcon: isClearAction ? _jsx(Icon, { icon: "ep:circle-close" }) : _jsx(Icon, { icon: "ep:arrow-right" }) }));
|
|
34
33
|
};
|
|
35
34
|
export default FilterByFunctionButton;
|
|
@@ -1,14 +1,3 @@
|
|
|
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
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
2
|
// Copyright 2022 The Parca Authors
|
|
14
3
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -24,14 +13,13 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
24
13
|
// limitations under the License.
|
|
25
14
|
import { Select, useURLState } from '@parca/components';
|
|
26
15
|
import { useUIFeatureFlag } from '@parca/hooks';
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
var _e = useURLState({
|
|
16
|
+
const ViewSelector = ({ defaultValue, navigateTo, position, placeholderText, primary = false, addView = false, disabled = false, }) => {
|
|
17
|
+
const [callgraphEnabled] = useUIFeatureFlag('callgraph');
|
|
18
|
+
const [dashboardItems = ['icicle'], setDashboardItems] = useURLState({
|
|
31
19
|
param: 'dashboard_items',
|
|
32
|
-
navigateTo
|
|
33
|
-
})
|
|
34
|
-
|
|
20
|
+
navigateTo,
|
|
21
|
+
});
|
|
22
|
+
const allItems = [
|
|
35
23
|
{ key: 'table', canBeSelected: !dashboardItems.includes('table') },
|
|
36
24
|
{ key: 'icicle', canBeSelected: !dashboardItems.includes('icicle') },
|
|
37
25
|
];
|
|
@@ -41,39 +29,38 @@ var ViewSelector = function (_a) {
|
|
|
41
29
|
canBeSelected: !dashboardItems.includes('callgraph'),
|
|
42
30
|
});
|
|
43
31
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return "".concat(string.charAt(0).toUpperCase()).concat(string.slice(1));
|
|
32
|
+
const getOption = ({ key, supportingText, }) => {
|
|
33
|
+
const capitalizeFirstLetter = (string) => {
|
|
34
|
+
return `${string.charAt(0).toUpperCase()}${string.slice(1)}`;
|
|
48
35
|
};
|
|
49
|
-
|
|
36
|
+
const title = capitalizeFirstLetter(key);
|
|
50
37
|
return {
|
|
51
38
|
active: _jsx(_Fragment, { children: title }),
|
|
52
|
-
expanded: (_jsxs(_Fragment, { children: [_jsx("span", { children: title }), supportingText !== null && _jsx("span",
|
|
39
|
+
expanded: (_jsxs(_Fragment, { children: [_jsx("span", { children: title }), supportingText !== null && _jsx("span", { className: "text-xs", children: supportingText })] })),
|
|
53
40
|
};
|
|
54
41
|
};
|
|
55
|
-
|
|
42
|
+
const items = allItems.map(item => ({
|
|
56
43
|
key: item.key,
|
|
57
44
|
disabled: !item.canBeSelected,
|
|
58
45
|
element: getOption(item),
|
|
59
|
-
})
|
|
60
|
-
|
|
46
|
+
}));
|
|
47
|
+
const onSelection = (value) => {
|
|
61
48
|
if (addView) {
|
|
62
49
|
setDashboardItems([dashboardItems[0], value]);
|
|
63
50
|
return;
|
|
64
51
|
}
|
|
65
|
-
|
|
52
|
+
const isOnlyChart = dashboardItems.length === 1;
|
|
66
53
|
if (isOnlyChart) {
|
|
67
54
|
setDashboardItems([value]);
|
|
68
55
|
return;
|
|
69
56
|
}
|
|
70
57
|
// Note: this will need to be updated if we ever have more more than 2 panels
|
|
71
|
-
|
|
72
|
-
|
|
58
|
+
const isFirstChart = position === 0;
|
|
59
|
+
const newDashboardItems = isFirstChart
|
|
73
60
|
? [value, dashboardItems[1]]
|
|
74
61
|
: [dashboardItems[0], value];
|
|
75
62
|
setDashboardItems(newDashboardItems);
|
|
76
63
|
};
|
|
77
|
-
return (_jsx(Select, { items: items, selectedKey: defaultValue, onSelection: onSelection, placeholder: placeholderText
|
|
64
|
+
return (_jsx(Select, { items: items, selectedKey: defaultValue, onSelection: onSelection, placeholder: placeholderText ?? 'Select view type...', primary: primary, disabled: disabled }));
|
|
78
65
|
};
|
|
79
66
|
export default ViewSelector;
|