@parca/profile 0.16.391 → 0.16.393
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/MatchersInput/index.d.ts +1 -1
- package/dist/MatchersInput/index.js +12 -4
- package/dist/ProfileExplorer/ProfileExplorerCompare.js +1 -1
- package/dist/ProfileExplorer/ProfileExplorerSingle.js +1 -1
- package/dist/ProfileMetricsGraph/Toolbar/index.d.ts +8 -0
- package/dist/ProfileMetricsGraph/Toolbar/index.js +29 -0
- package/dist/ProfileMetricsGraph/index.d.ts +1 -1
- package/dist/ProfileMetricsGraph/index.js +20 -8
- package/dist/ProfileMetricsGraph/useSumBy.d.ts +2 -0
- package/dist/ProfileMetricsGraph/useSumBy.js +47 -0
- package/dist/ProfileSelector/index.d.ts +3 -1
- package/dist/ProfileSelector/index.js +3 -1
- package/dist/ProfileSelector/useAutoQuerySelector.d.ts +5 -1
- package/dist/ProfileSelector/useAutoQuerySelector.js +42 -1
- package/dist/styles.css +1 -1
- package/dist/utils.d.ts +0 -2
- package/dist/utils.js +0 -46
- package/package.json +9 -7
- package/src/MatchersInput/index.tsx +18 -5
- package/src/ProfileExplorer/ProfileExplorerCompare.tsx +2 -0
- package/src/ProfileExplorer/ProfileExplorerSingle.tsx +1 -0
- package/src/ProfileMetricsGraph/Toolbar/index.tsx +94 -0
- package/src/ProfileMetricsGraph/index.tsx +46 -7
- package/src/ProfileMetricsGraph/useSumBy.ts +70 -0
- package/src/ProfileSelector/index.tsx +5 -0
- package/src/ProfileSelector/useAutoQuerySelector.ts +58 -0
- package/src/utils.ts +0 -73
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.393](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.392...@parca/profile@0.16.393) (2024-06-27)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @parca/profile
|
|
9
|
+
|
|
10
|
+
## [0.16.392](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.391...@parca/profile@0.16.392) (2024-06-27)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @parca/profile
|
|
13
|
+
|
|
6
14
|
## 0.16.391 (2024-06-24)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @parca/profile
|
|
@@ -15,6 +15,6 @@ interface UseLabelNames {
|
|
|
15
15
|
result: ILabelNamesResult;
|
|
16
16
|
loading: boolean;
|
|
17
17
|
}
|
|
18
|
-
export declare const useLabelNames: (client: QueryServiceClient) => UseLabelNames;
|
|
18
|
+
export declare const useLabelNames: (client: QueryServiceClient, start?: number, end?: number, profileType?: string) => UseLabelNames;
|
|
19
19
|
declare const MatchersInput: ({ queryClient, setMatchersString, runQuery, currentQuery, }: MatchersInputProps) => JSX.Element;
|
|
20
20
|
export default MatchersInput;
|
|
@@ -16,20 +16,28 @@ import cx from 'classnames';
|
|
|
16
16
|
import TextareaAutosize from 'react-textarea-autosize';
|
|
17
17
|
import { useGrpcMetadata } from '@parca/components';
|
|
18
18
|
import { Query } from '@parca/parser';
|
|
19
|
-
import { sanitizeLabelValue } from '@parca/utilities';
|
|
19
|
+
import { millisToProtoTimestamp, sanitizeLabelValue } from '@parca/utilities';
|
|
20
20
|
import SuggestionsList, { Suggestion, Suggestions } from './SuggestionsList';
|
|
21
|
-
export const useLabelNames = (client) => {
|
|
21
|
+
export const useLabelNames = (client, start, end, profileType) => {
|
|
22
22
|
const [loading, setLoading] = useState(true);
|
|
23
23
|
const [result, setResult] = useState({});
|
|
24
24
|
const metadata = useGrpcMetadata();
|
|
25
25
|
useEffect(() => {
|
|
26
|
-
const
|
|
26
|
+
const request = { match: [] };
|
|
27
|
+
if (start !== undefined && end !== undefined) {
|
|
28
|
+
request.start = millisToProtoTimestamp(start);
|
|
29
|
+
request.end = millisToProtoTimestamp(end);
|
|
30
|
+
}
|
|
31
|
+
if (profileType !== undefined) {
|
|
32
|
+
request.profileType = profileType;
|
|
33
|
+
}
|
|
34
|
+
const call = client.labels(request, { meta: metadata });
|
|
27
35
|
setLoading(true);
|
|
28
36
|
call.response
|
|
29
37
|
.then(response => setResult({ response }))
|
|
30
38
|
.catch(error => setResult({ error }))
|
|
31
39
|
.finally(() => setLoading(false));
|
|
32
|
-
}, [client, metadata]);
|
|
40
|
+
}, [client, metadata, start, end, profileType]);
|
|
33
41
|
return { result, loading };
|
|
34
42
|
};
|
|
35
43
|
const MatchersInput = ({ queryClient, setMatchersString, runQuery, currentQuery, }) => {
|
|
@@ -10,6 +10,6 @@ const ProfileExplorerCompare = ({ queryClient, queryA, queryB, profileA, profile
|
|
|
10
10
|
const closeProfileB = () => {
|
|
11
11
|
closeProfile('B');
|
|
12
12
|
};
|
|
13
|
-
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex justify-between gap-2", children: [_jsx(Card, { className: "mt-2 p-2", children: _jsx(ProfileSelector, { queryClient: queryClient, querySelection: queryA, profileSelection: profileA, selectProfile: selectProfileA, selectQuery: selectQueryA, closeProfile: closeProfileA, enforcedProfileName: '', comparing: true }) }), _jsx(Card, { className: "mt-2 p-2", children: _jsx(ProfileSelector, { queryClient: queryClient, querySelection: queryB, profileSelection: profileB, selectProfile: selectProfileB, selectQuery: selectQueryB, closeProfile: closeProfileB, enforcedProfileName: Query.parse(queryA.expression).profileName(), comparing: true }) })] }), _jsx("div", { className: "grid grid-cols-1", children: profileA != null && profileB != null ? (_jsx("div", { children: _jsx(Card, { className: "mt-2 px-6 py-4", children: _jsx(ProfileViewWithData, { navigateTo: navigateTo, queryClient: queryClient, profileSource: new ProfileDiffSource(profileA.ProfileSource(), profileB.ProfileSource()) }) }) })) : (_jsx("div", { children: _jsx("div", { className: "my-20 text-center", children: _jsx("p", { children: "Select a profile on both sides." }) }) })) })] }));
|
|
13
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex justify-between gap-2", children: [_jsx(Card, { className: "mt-2 p-2", children: _jsx(ProfileSelector, { queryClient: queryClient, querySelection: queryA, profileSelection: profileA, selectProfile: selectProfileA, selectQuery: selectQueryA, closeProfile: closeProfileA, enforcedProfileName: '', comparing: true, navigateTo: navigateTo }) }), _jsx(Card, { className: "mt-2 p-2", children: _jsx(ProfileSelector, { queryClient: queryClient, querySelection: queryB, profileSelection: profileB, selectProfile: selectProfileB, selectQuery: selectQueryB, closeProfile: closeProfileB, enforcedProfileName: Query.parse(queryA.expression).profileName(), comparing: true, navigateTo: navigateTo }) })] }), _jsx("div", { className: "grid grid-cols-1", children: profileA != null && profileB != null ? (_jsx("div", { children: _jsx(Card, { className: "mt-2 px-6 py-4", children: _jsx(ProfileViewWithData, { navigateTo: navigateTo, queryClient: queryClient, profileSource: new ProfileDiffSource(profileA.ProfileSource(), profileB.ProfileSource()) }) }) })) : (_jsx("div", { children: _jsx("div", { className: "my-20 text-center", children: _jsx("p", { children: "Select a profile on both sides." }) }) })) })] }));
|
|
14
14
|
};
|
|
15
15
|
export default ProfileExplorerCompare;
|
|
@@ -3,6 +3,6 @@ import { Card } from '@parca/components';
|
|
|
3
3
|
import { ProfileViewWithData } from '..';
|
|
4
4
|
import ProfileSelector from '../ProfileSelector';
|
|
5
5
|
const ProfileExplorerSingle = ({ queryClient, query, selectQuery, selectProfile, profile, navigateTo, }) => {
|
|
6
|
-
return (_jsxs(_Fragment, { children: [_jsx(Card, { className: "mt-2 px-6 py-4", children: _jsx(ProfileSelector, { queryClient: queryClient, querySelection: query, selectQuery: selectQuery, selectProfile: selectProfile, closeProfile: () => { }, profileSelection: profile, comparing: false, enforcedProfileName: '' }) }), profile != null ? (_jsx(Card, { className: "mt-2 px-6 py-4", children: _jsx(ProfileViewWithData, { queryClient: queryClient, profileSource: profile.ProfileSource(), navigateTo: navigateTo }) })) : (_jsx(_Fragment, {}))] }));
|
|
6
|
+
return (_jsxs(_Fragment, { children: [_jsx(Card, { className: "mt-2 px-6 py-4", children: _jsx(ProfileSelector, { queryClient: queryClient, querySelection: query, selectQuery: selectQuery, selectProfile: selectProfile, closeProfile: () => { }, profileSelection: profile, comparing: false, enforcedProfileName: '', navigateTo: navigateTo }) }), profile != null ? (_jsx(Card, { className: "mt-2 px-6 py-4", children: _jsx(ProfileViewWithData, { queryClient: queryClient, profileSource: profile.ProfileSource(), navigateTo: navigateTo }) })) : (_jsx(_Fragment, {}))] }));
|
|
7
7
|
};
|
|
8
8
|
export default ProfileExplorerSingle;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// Copyright 2022 The Parca Authors
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
import { useId, useMemo, useState } from 'react';
|
|
15
|
+
import { Icon } from '@iconify/react';
|
|
16
|
+
import Draggable from 'react-draggable';
|
|
17
|
+
import Select from 'react-select';
|
|
18
|
+
import { IconButton } from '@parca/components';
|
|
19
|
+
export const Toolbar = ({ sumBy, setSumBy, labels }) => {
|
|
20
|
+
const [collapsed, setCollapsed] = useState(false);
|
|
21
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
22
|
+
const idWithColon = useId();
|
|
23
|
+
const id = useMemo(() => idWithColon.replace(/[^a-zA-Z0-9]/g, ''), [idWithColon]);
|
|
24
|
+
return (_jsx(Draggable, { handle: `#${id}`, onStart: () => setIsDragging(true), onStop: () => setIsDragging(false), bounds: "parent", defaultPosition: { x: 96, y: 4 }, children: _jsx("div", { className: "absolute rounded-full bg-gray-100 dark:bg-gray-800 z-10 text-xs", children: _jsxs("div", { className: "flex items-center h-14 gap-4 py-1 px-3", children: [_jsx(Icon, { icon: "radix-icons:drag-handle-dots-2", height: 20, className: isDragging ? 'cursor-grabbing' : 'cursor-grab', id: id }), !collapsed ? (_jsxs("div", { className: "flex gap-2 items-center mr-4", children: [_jsx("span", { children: "Sum by" }), _jsx(Select, { defaultValue: [], isMulti: true, name: "colors", options: labels.map(label => ({ label, value: label })), className: "parca-select-container min-w-60", classNamePrefix: "parca-select", value: sumBy.map(sumBy => ({ label: sumBy, value: sumBy })), onChange: selectedOptions => {
|
|
25
|
+
setSumBy(selectedOptions.map(option => option.value));
|
|
26
|
+
}, placeholder: "Labels...", styles: {
|
|
27
|
+
indicatorSeparator: () => ({ display: 'none' }),
|
|
28
|
+
} })] })) : null, _jsxs("div", { className: "relative", children: [_jsx(IconButton, { icon: _jsx(Icon, { icon: collapsed ? 'iconamoon:arrow-right-2-light' : 'iconamoon:arrow-left-2-light', height: 24 }), onClick: () => setCollapsed(!collapsed), className: "hover:bg-gray-200 dark:hover:bg-gray-700 rounded-full p-1" }), collapsed && sumBy.length > 0 ? (_jsx("div", { className: "rounded-full bg-indigo-600 dark:bg-indigo-500 absolute text-xs h-4 w-4 flex items-center justify-center -top-3 -right-3 text-white text-[10px]", children: sumBy.length })) : null] })] }) }) }));
|
|
29
|
+
};
|
|
@@ -29,6 +29,6 @@ export interface IQueryRangeState {
|
|
|
29
29
|
isLoading: boolean;
|
|
30
30
|
error: RpcError | null;
|
|
31
31
|
}
|
|
32
|
-
export declare const useQueryRange: (client: QueryServiceClient, queryExpression: string, start: number, end: number) => IQueryRangeState;
|
|
32
|
+
export declare const useQueryRange: (client: QueryServiceClient, queryExpression: string, start: number, end: number, sumBy?: string[], skip?: boolean) => IQueryRangeState;
|
|
33
33
|
declare const ProfileMetricsGraph: ({ queryClient, queryExpression, profile, from, to, setTimeRange, addLabelMatcher, onPointClick, comparing, }: ProfileMetricsGraphProps) => JSX.Element;
|
|
34
34
|
export default ProfileMetricsGraph;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
// Copyright 2022 The Parca Authors
|
|
3
3
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
// you may not use this file except in compliance with the License.
|
|
@@ -17,25 +17,31 @@ import { Duration, Timestamp } from '@parca/client';
|
|
|
17
17
|
import { MetricsGraphSkeleton, useGrpcMetadata, useParcaContext, } from '@parca/components';
|
|
18
18
|
import { Query } from '@parca/parser';
|
|
19
19
|
import { capitalizeOnlyFirstLetter, getStepDuration } from '@parca/utilities';
|
|
20
|
+
import { useLabelNames } from '../MatchersInput';
|
|
20
21
|
import MetricsGraph from '../MetricsGraph';
|
|
21
22
|
import { useMetricsGraphDimensions } from '../MetricsGraph/useMetricsGraphDimensions';
|
|
22
23
|
import useDelayedLoader from '../useDelayedLoader';
|
|
24
|
+
import { Toolbar } from './Toolbar';
|
|
25
|
+
import { useSumBy } from './useSumBy';
|
|
23
26
|
const ErrorContent = ({ errorMessage }) => {
|
|
24
27
|
return (_jsx("div", { className: "relative rounded border border-red-400 bg-red-100 px-4 py-3 text-red-700", role: "alert", children: _jsx("span", { className: "block sm:inline", children: errorMessage }) }));
|
|
25
28
|
};
|
|
26
29
|
export const ProfileMetricsEmptyState = ({ message }) => {
|
|
27
30
|
return (_jsx("div", { className: "flex h-full w-full flex-col items-center justify-center", children: _jsx("p", { children: message }) }));
|
|
28
31
|
};
|
|
29
|
-
export const useQueryRange = (client, queryExpression, start, end) => {
|
|
32
|
+
export const useQueryRange = (client, queryExpression, start, end, sumBy = [], skip = false) => {
|
|
33
|
+
const [isLoading, setLoading] = useState(!skip);
|
|
30
34
|
const [state, setState] = useState({
|
|
31
35
|
response: null,
|
|
32
|
-
isLoading
|
|
36
|
+
isLoading,
|
|
33
37
|
error: null,
|
|
34
38
|
});
|
|
35
|
-
const [isLoading, setLoading] = useState(true);
|
|
36
39
|
const metadata = useGrpcMetadata();
|
|
37
40
|
useEffect(() => {
|
|
38
41
|
void (async () => {
|
|
42
|
+
if (skip) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
39
45
|
setLoading(true);
|
|
40
46
|
const stepDuration = getStepDuration(start, end);
|
|
41
47
|
const call = client.queryRange({
|
|
@@ -44,6 +50,7 @@ export const useQueryRange = (client, queryExpression, start, end) => {
|
|
|
44
50
|
end: Timestamp.fromDate(new Date(end)),
|
|
45
51
|
step: Duration.create(stepDuration),
|
|
46
52
|
limit: 0,
|
|
53
|
+
sumBy,
|
|
47
54
|
}, { meta: metadata });
|
|
48
55
|
call.response
|
|
49
56
|
.then(response => {
|
|
@@ -56,11 +63,13 @@ export const useQueryRange = (client, queryExpression, start, end) => {
|
|
|
56
63
|
setLoading(false);
|
|
57
64
|
});
|
|
58
65
|
})();
|
|
59
|
-
}, [client, queryExpression, start, end, metadata]);
|
|
66
|
+
}, [client, queryExpression, start, end, metadata, sumBy, skip]);
|
|
60
67
|
return { ...state, isLoading };
|
|
61
68
|
};
|
|
62
69
|
const ProfileMetricsGraph = ({ queryClient, queryExpression, profile, from, to, setTimeRange, addLabelMatcher, onPointClick, comparing = false, }) => {
|
|
63
|
-
const {
|
|
70
|
+
const { loading: labelNamesLoading, result: labelNamesResult } = useLabelNames(queryClient, from, to, profile?.ProfileSource()?.ProfileType()?.toString());
|
|
71
|
+
const [sumBy, setSumBy] = useSumBy(profile?.ProfileSource()?.ProfileType(), labelNamesResult.response?.labelNames);
|
|
72
|
+
const { isLoading, response, error } = useQueryRange(queryClient, queryExpression, from, to, sumBy, labelNamesLoading);
|
|
64
73
|
const isLoaderVisible = useDelayedLoader(isLoading);
|
|
65
74
|
const { onError, perf, authenticationErrorMessage, isDarkMode } = useParcaContext();
|
|
66
75
|
const { width, height, margin, heightStyle } = useMetricsGraphDimensions(comparing);
|
|
@@ -77,7 +86,7 @@ const ProfileMetricsGraph = ({ queryClient, queryExpression, profile, from, to,
|
|
|
77
86
|
}, [perf, response]);
|
|
78
87
|
const series = response?.series;
|
|
79
88
|
const dataAvailable = series !== null && series !== undefined && series?.length > 0;
|
|
80
|
-
const metricsGraphLoading = isLoaderVisible || (isLoading && !dataAvailable);
|
|
89
|
+
const metricsGraphLoading = isLoaderVisible || (isLoading && !dataAvailable && !labelNamesLoading);
|
|
81
90
|
if (metricsGraphLoading) {
|
|
82
91
|
return _jsx(MetricsGraphSkeleton, { heightStyle: heightStyle, isDarkMode: isDarkMode });
|
|
83
92
|
}
|
|
@@ -87,6 +96,9 @@ const ProfileMetricsGraph = ({ queryClient, queryExpression, profile, from, to,
|
|
|
87
96
|
}
|
|
88
97
|
return _jsx(ErrorContent, { errorMessage: capitalizeOnlyFirstLetter(error.message) });
|
|
89
98
|
}
|
|
99
|
+
if (!labelNamesLoading && labelNamesResult?.error != null) {
|
|
100
|
+
return (_jsx(ErrorContent, { errorMessage: capitalizeOnlyFirstLetter(labelNamesResult.error.message) }));
|
|
101
|
+
}
|
|
90
102
|
if (dataAvailable) {
|
|
91
103
|
const handleSampleClick = (timestamp, _value, labels, duration) => {
|
|
92
104
|
onPointClick(timestamp, labels, queryExpression, duration);
|
|
@@ -98,7 +110,7 @@ const ProfileMetricsGraph = ({ queryClient, queryExpression, profile, from, to,
|
|
|
98
110
|
if (sampleUnit === '') {
|
|
99
111
|
sampleUnit = Query.parse(queryExpression).profileType().sampleUnit;
|
|
100
112
|
}
|
|
101
|
-
return (_jsx(AnimatePresence, { children:
|
|
113
|
+
return (_jsx(AnimatePresence, { children: _jsxs(motion.div, { className: "h-full w-full relative", initial: { display: 'none', opacity: 0 }, animate: { display: 'block', opacity: 1 }, transition: { duration: 0.5 }, children: [_jsx(Toolbar, { sumBy: sumBy, setSumBy: setSumBy, labels: labelNamesResult.response?.labelNames ?? [] }), _jsx(MetricsGraph, { data: series, from: from, to: to, profile: profile, setTimeRange: setTimeRange, onSampleClick: handleSampleClick, addLabelMatcher: addLabelMatcher, sampleUnit: sampleUnit, height: height, width: width, margin: margin })] }, "metrics-graph-loaded") }));
|
|
102
114
|
}
|
|
103
115
|
return _jsx(ProfileMetricsEmptyState, { message: "No data found. Try a different query." });
|
|
104
116
|
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Copyright 2022 The Parca Authors
|
|
2
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
// you may not use this file except in compliance with the License.
|
|
4
|
+
// You may obtain a copy of the License at
|
|
5
|
+
//
|
|
6
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
//
|
|
8
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
// See the License for the specific language governing permissions and
|
|
12
|
+
// limitations under the License.
|
|
13
|
+
import { useEffect, useState } from 'react';
|
|
14
|
+
const DEFAULT_EMPTY_SUM_BY = [];
|
|
15
|
+
const getDefaultSumBy = (profile, labels) => {
|
|
16
|
+
if (profile === undefined || labels === undefined) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
if (!profile.delta) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
if (labels.includes('comm')) {
|
|
23
|
+
return ['comm'];
|
|
24
|
+
}
|
|
25
|
+
if (labels.includes('namespace')) {
|
|
26
|
+
return ['namespace'];
|
|
27
|
+
}
|
|
28
|
+
if (labels.includes('container')) {
|
|
29
|
+
return ['container'];
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
};
|
|
33
|
+
export const useSumBy = (profileType, labels) => {
|
|
34
|
+
const [userSelectedSumBy, setUserSelectedSumBy] = useState(undefined);
|
|
35
|
+
const [defaultSumBy, setDefaultSumBy] = useState(getDefaultSumBy(profileType, labels));
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
setDefaultSumBy(getDefaultSumBy(profileType, labels));
|
|
38
|
+
}, [profileType, labels]);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
if (profileType === undefined) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// Reset user selected sumBy if profile type changes
|
|
44
|
+
setUserSelectedSumBy(undefined);
|
|
45
|
+
}, [profileType]);
|
|
46
|
+
return [userSelectedSumBy ?? defaultSumBy ?? DEFAULT_EMPTY_SUM_BY, setUserSelectedSumBy];
|
|
47
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { RpcError } from '@protobuf-ts/runtime-rpc';
|
|
3
3
|
import { ProfileTypesResponse, QueryServiceClient } from '@parca/client';
|
|
4
|
+
import { type NavigateFunction } from '@parca/utilities';
|
|
4
5
|
import { ProfileSelection } from '..';
|
|
5
6
|
export interface QuerySelection {
|
|
6
7
|
expression: string;
|
|
@@ -19,6 +20,7 @@ interface ProfileSelectorProps {
|
|
|
19
20
|
enforcedProfileName: string;
|
|
20
21
|
profileSelection: ProfileSelection | null;
|
|
21
22
|
comparing: boolean;
|
|
23
|
+
navigateTo: NavigateFunction;
|
|
22
24
|
}
|
|
23
25
|
export interface IProfileTypesResult {
|
|
24
26
|
loading: boolean;
|
|
@@ -26,5 +28,5 @@ export interface IProfileTypesResult {
|
|
|
26
28
|
error?: RpcError;
|
|
27
29
|
}
|
|
28
30
|
export declare const useProfileTypes: (client: QueryServiceClient) => IProfileTypesResult;
|
|
29
|
-
declare const ProfileSelector: ({ queryClient, querySelection, selectProfile, selectQuery, closeProfile, enforcedProfileName, profileSelection, comparing, }: ProfileSelectorProps) => JSX.Element;
|
|
31
|
+
declare const ProfileSelector: ({ queryClient, querySelection, selectProfile, selectQuery, closeProfile, enforcedProfileName, profileSelection, comparing, navigateTo, }: ProfileSelectorProps) => JSX.Element;
|
|
30
32
|
export default ProfileSelector;
|
|
@@ -38,7 +38,7 @@ export const useProfileTypes = (client) => {
|
|
|
38
38
|
}, [client, metadata, loading]);
|
|
39
39
|
return { loading, data: result, error };
|
|
40
40
|
};
|
|
41
|
-
const ProfileSelector = ({ queryClient, querySelection, selectProfile, selectQuery, closeProfile, enforcedProfileName, profileSelection, comparing, }) => {
|
|
41
|
+
const ProfileSelector = ({ queryClient, querySelection, selectProfile, selectQuery, closeProfile, enforcedProfileName, profileSelection, comparing, navigateTo, }) => {
|
|
42
42
|
const { loading: profileTypesLoading, data: profileTypesData, error, } = useProfileTypes(queryClient);
|
|
43
43
|
const { heightStyle } = useMetricsGraphDimensions(comparing);
|
|
44
44
|
const { viewComponent } = useParcaContext();
|
|
@@ -136,6 +136,8 @@ const ProfileSelector = ({ queryClient, querySelection, selectProfile, selectQue
|
|
|
136
136
|
profileTypesData,
|
|
137
137
|
setProfileName,
|
|
138
138
|
setQueryExpression,
|
|
139
|
+
querySelection,
|
|
140
|
+
navigateTo,
|
|
139
141
|
});
|
|
140
142
|
const searchDisabled = queryExpressionString === undefined ||
|
|
141
143
|
queryExpressionString === '' ||
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { ProfileTypesResponse } from '@parca/client';
|
|
2
|
+
import { type NavigateFunction } from '@parca/utilities';
|
|
3
|
+
import { QuerySelection } from '../ProfileSelector';
|
|
2
4
|
interface Props {
|
|
3
5
|
selectedProfileName: string;
|
|
4
6
|
profileTypesData: ProfileTypesResponse | undefined;
|
|
5
7
|
setProfileName: (name: string) => void;
|
|
6
8
|
setQueryExpression: () => void;
|
|
9
|
+
querySelection: QuerySelection;
|
|
10
|
+
navigateTo: NavigateFunction;
|
|
7
11
|
}
|
|
8
|
-
export declare const useAutoQuerySelector: ({ selectedProfileName, profileTypesData, setProfileName, setQueryExpression, }: Props) => void;
|
|
12
|
+
export declare const useAutoQuerySelector: ({ selectedProfileName, profileTypesData, setProfileName, setQueryExpression, querySelection, navigateTo, }: Props) => void;
|
|
9
13
|
export {};
|
|
@@ -12,10 +12,51 @@
|
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
import { useEffect } from 'react';
|
|
14
14
|
import { selectAutoQuery, setAutoQuery, useAppDispatch, useAppSelector } from '@parca/store';
|
|
15
|
+
import { ProfileSelectionFromParams, SuffixParams } from '..';
|
|
15
16
|
import { constructProfileName } from '../ProfileTypeSelector';
|
|
16
|
-
export const useAutoQuerySelector = ({ selectedProfileName, profileTypesData, setProfileName, setQueryExpression, }) => {
|
|
17
|
+
export const useAutoQuerySelector = ({ selectedProfileName, profileTypesData, setProfileName, setQueryExpression, querySelection, navigateTo, }) => {
|
|
17
18
|
const autoQuery = useAppSelector(selectAutoQuery);
|
|
18
19
|
const dispatch = useAppDispatch();
|
|
20
|
+
const queryParams = new URLSearchParams(location.search);
|
|
21
|
+
const comparing = queryParams.get('comparing') === 'true';
|
|
22
|
+
const expressionA = queryParams.get('expression_a');
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (comparing && expressionA !== null && expressionA !== undefined) {
|
|
25
|
+
if (querySelection.expression === undefined) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const profileA = ProfileSelectionFromParams(querySelection.mergeFrom?.toString(), querySelection.mergeTo?.toString(), querySelection.expression, '');
|
|
29
|
+
const queryA = {
|
|
30
|
+
expression: querySelection.expression,
|
|
31
|
+
from: querySelection.from,
|
|
32
|
+
to: querySelection.to,
|
|
33
|
+
timeSelection: querySelection.timeSelection,
|
|
34
|
+
};
|
|
35
|
+
let compareQuery = {
|
|
36
|
+
compare_a: 'true',
|
|
37
|
+
expression_a: encodeURIComponent(queryA.expression),
|
|
38
|
+
from_a: queryA.from.toString(),
|
|
39
|
+
to_a: queryA.to.toString(),
|
|
40
|
+
time_selection_a: queryA.timeSelection,
|
|
41
|
+
compare_b: 'true',
|
|
42
|
+
expression_b: encodeURIComponent(queryA.expression),
|
|
43
|
+
from_b: queryA.from.toString(),
|
|
44
|
+
to_b: queryA.to.toString(),
|
|
45
|
+
time_selection_b: queryA.timeSelection,
|
|
46
|
+
};
|
|
47
|
+
if (profileA != null) {
|
|
48
|
+
compareQuery = {
|
|
49
|
+
...SuffixParams(profileA.HistoryParams(), '_a'),
|
|
50
|
+
...compareQuery,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
void navigateTo('/', {
|
|
54
|
+
...compareQuery,
|
|
55
|
+
search_string: '',
|
|
56
|
+
dashboard_items: ['icicle'],
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}, [comparing, querySelection, navigateTo, expressionA, dispatch]);
|
|
19
60
|
// Effect to load some initial data on load when is no selection
|
|
20
61
|
useEffect(() => {
|
|
21
62
|
void (async () => {
|
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}}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.-inset-2{bottom:-.5rem;left:-.5rem;right:-.5rem;top:-.5rem}.inset-y-0{bottom:0;top:0}.left-\[25px\]{left:25px}.left-0{left:0}.top-\[-46px\]{top:-46px}.right-0{right:0}.top-0{top:0}.top-\[-1px\]{top:-1px}.left-\[18px\]{left:18px}.bottom-0{bottom:0}.z-50{z-index:50}.z-10{z-index:10}.z-20{z-index:20}.m-auto{margin:auto}.m-2{margin:.5rem}.mx-auto{margin-left:auto;margin-right:auto}.mx-2{margin-left:.5rem;margin-right:.5rem}.my-2{margin-bottom:.5rem;margin-top:.5rem}.my-20{margin-bottom:5rem;margin-top:5rem}.my-6{margin-bottom:1.5rem;margin-top:1.5rem}.my-4{margin-bottom:1rem;margin-top:1rem}.mr-3{margin-right:.75rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.ml-2{margin-left:.5rem}.mb-2{margin-bottom:.5rem}.mb-0\.5{margin-bottom:.125rem}.mt-1\.5{margin-top:.375rem}.mb-0{margin-bottom:0}.mb-4{margin-bottom:1rem}.ml-3{margin-left:.75rem}.mr-6{margin-right:1.5rem}.mr-1{margin-right:.25rem}.mb-1{margin-bottom:.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}.hidden{display:none}.h-fit{height:-moz-fit-content;height:fit-content}.h-10{height:2.5rem}.h-\[38px\]{height:38px}.h-auto{height:auto}.h-full{height:100%}.h-1{height:.25rem}.h-6{height:1.5rem}.h-4{height:1rem}.h-\[700px\]{height:700px}.h-\[80vh\]{height:80vh}.h-5{height:1.25rem}.max-h-\[400px\]{max-height:400px}.max-h-\[300px\]{max-height:300px}.min-h-52{min-height:13rem}.min-h-\[38px\]{min-height:38px}.min-h-48{min-height:12rem}.min-h-\[78px\]{min-height:78px}.min-h-96{min-height:24rem}.min-h-\[700px\]{min-height:700px}.w-full{width:100%}.w-auto{width:auto}.w-1\/4{width:25%}.w-3\/4{width:75%}.w-\[500px\]{width:500px}.w-max{width:-moz-max-content;width:max-content}.w-40{width:10rem}.w-3{width:.75rem}.w-5{width:1.25rem}.w-7{width:1.75rem}.w-9{width:2.25rem}.w-11{width:2.75rem}.w-\[52px\]{width:52px}.w-\[68px\]{width:68px}.w-\[76px\]{width:76px}.w-\[84px\]{width:84px}.w-\[92px\]{width:92px}.w-\[100px\]{width:100px}.w-\[108px\]{width:108px}.w-\[116px\]{width:116px}.w-4{width:1rem}.w-\[18px\]{width:18px}.w-8{width:2rem}.w-44{width:11rem}.w-\[460px\]{width:460px}.w-1\/5{width:20%}.w-11\/12{width:91.666667%}.w-1\/12{width:8.333333%}.w-16{width:4rem}.w-fit{width:-moz-fit-content;width:fit-content}.w-\[420px\]{width:420px}.min-w-\[300px\]{min-width:300px}.min-w-\[400px\]{min-width:400px}.max-w-\[500px\]{max-width:500px}.max-w-\[300px\]{max-width:300px}.max-w-\[400px\]{max-width:400px}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.flex-grow-0{flex-grow:0}.flex-grow{flex-grow:1}.table-auto{table-layout:auto}.table-fixed{table-layout:fixed}.origin-top-left{transform-origin:top left}.origin-bottom-left{transform-origin:bottom left}.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}.-rotate-90{--tw-rotate:-90deg}.-rotate-90,.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}.cursor-auto{cursor:auto}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.content-start{align-content:flex-start}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.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-4{gap:1rem}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1.25rem*var(--tw-space-y-reverse));margin-top:calc(1.25rem*(1 - var(--tw-space-y-reverse)))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-clip{overflow:clip}.overflow-scroll{overflow:scroll}.overflow-x-hidden{overflow-x:hidden}.text-ellipsis{text-overflow:ellipsis}.whitespace-normal{white-space:normal}.whitespace-nowrap{white-space:nowrap}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-none{border-radius:0}.rounded-t-lg{border-top-left-radius:.5rem;border-top-right-radius:.5rem}.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-x{border-left-width:1px;border-right-width:1px}.border-y{border-bottom-width:1px;border-top-width:1px}.border-r{border-right-width:1px}.border-l{border-left-width:1px}.border-b{border-bottom-width:1px}.border-t{border-top-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))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity))}.border-gray-400{--tw-border-opacity:1;border-color:rgb(156 163 175/var(--tw-border-opacity))}.border-r-gray-200{--tw-border-opacity:1;border-right-color:rgb(229 231 235/var(--tw-border-opacity))}.border-l-amber-900{--tw-border-opacity:1;border-left-color:rgb(120 53 15/var(--tw-border-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-indigo-600{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/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-yellow-200{--tw-bg-opacity:1;background-color:rgb(254 240 138/var(--tw-bg-opacity))}.bg-yellow-700{--tw-bg-opacity:1;background-color:rgb(161 98 7/var(--tw-bg-opacity))}.bg-indigo-100{--tw-bg-opacity:1;background-color:rgb(224 231 255/var(--tw-bg-opacity))}.bg-gray-600{--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}.bg-indigo-50{--tw-bg-opacity:1;background-color:rgb(238 242 255/var(--tw-bg-opacity))}.bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.bg-indigo-500{--tw-bg-opacity:1;background-color:rgb(99 102 241/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}.bg-opacity-90{--tw-bg-opacity:0.9}.fill-transparent{fill:transparent}.fill-current{fill:currentColor}.stroke-gray-300{stroke:#d1d5db}.stroke-white{stroke:#fff}.stroke-\[3\]{stroke-width:3}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-10{padding:2.5rem}.p-4{padding:1rem}.p-1\.5{padding:.375rem}.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-6{padding-left:1.5rem;padding-right:1.5rem}.py-4{padding-bottom:1rem;padding-top:1rem}.px-4{padding-left:1rem;padding-right:1rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.\!py-2{padding-bottom:.5rem!important;padding-top:.5rem!important}.\!px-3{padding-left:.75rem!important;padding-right:.75rem!important}.px-3{padding-left:.75rem;padding-right:.75rem}.py-0{padding-bottom:0;padding-top:0}.px-1{padding-left:.25rem;padding-right:.25rem}.px-8{padding-left:2rem;padding-right:2rem}.pr-0{padding-right:0}.pt-2{padding-top:.5rem}.pl-3{padding-left:.75rem}.pr-9{padding-right:2.25rem}.pb-4{padding-bottom:1rem}.pb-2{padding-bottom:.5rem}.pb-6{padding-bottom:1.5rem}.pb-\[10px\]{padding-bottom:10px}.pl-1{padding-left:.25rem}.pr-10{padding-right:2.5rem}.pr-2{padding-right:.5rem}.pl-5{padding-left:1.25rem}.pr-\[1\.7rem\]{padding-right:1.7rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-top{vertical-align:top}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.text-base{font-size:1rem;line-height:1.5rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-\[10px\]{font-size:10px}.text-lg{font-size:1.125rem;line-height:1.75rem}.font-semibold{font-weight:600}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.leading-6{line-height:1.5rem}.leading-5{line-height:1.25rem}.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-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-indigo-600{--tw-text-opacity:1;color:rgb(79 70 229/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.\!text-indigo-600{--tw-text-opacity:1!important;color:rgb(79 70 229/var(--tw-text-opacity))!important}.opacity-100{opacity:1}.opacity-0{opacity:0}.opacity-90{opacity:.9}.opacity-50{opacity:.5}.shadow-\[0_0_10px_2px_rgba\(0\2c 0\2c 0\2c 0\.3\)\]{--tw-shadow:0 0 10px 2px rgba(0,0,0,.3);--tw-shadow-colored:0 0 10px 2px var(--tw-shadow-color)}.shadow-\[0_0_10px_2px_rgba\(0\2c 0\2c 0\2c 0\.3\)\],.shadow-lg{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.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)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.shadow,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.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)}.\[stroke-dasharray\:6\2c 4\]{stroke-dasharray:6,4}.\[stroke-linecap\:round\]{stroke-linecap:round}.\[stroke-linejoin\:round\]{stroke-linejoin:round}.hover\:whitespace-normal:hover{white-space:normal}.hover\:bg-\[\#62626212\]:hover{background-color:#62626212}.hover\:bg-indigo-200:hover{--tw-bg-opacity:1;background-color:rgb(199 210 254/var(--tw-bg-opacity))}.focus\:border-indigo-500:focus{--tw-border-opacity:1;border-color:rgb(99 102 241/var(--tw-border-opacity))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-1:focus{--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)}.focus\:ring-1:focus,.focus\:ring-2:focus{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-2:focus{--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(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-indigo-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(99 102 241/var(--tw-ring-opacity))}.focus\:ring-indigo-600:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(79 70 229/var(--tw-ring-opacity))}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px}.group:hover .group-hover\:flex{display:flex}[class~=theme-dark] .dark\:border{border-width:1px}[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\:border-gray-600{--tw-border-opacity:1;border-color:rgb(75 85 99/var(--tw-border-opacity))}[class~=theme-dark] .dark\:border-gray-700{--tw-border-opacity:1;border-color:rgb(55 65 81/var(--tw-border-opacity))}[class~=theme-dark] .dark\:border-r-gray-700{--tw-border-opacity:1;border-right-color:rgb(55 65 81/var(--tw-border-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\:bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-500{--tw-bg-opacity:1;background-color:rgb(107 114 128/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-yellow-700{--tw-bg-opacity:1;background-color:rgb(161 98 7/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-600{--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-indigo-500{--tw-bg-opacity:1;background-color:rgb(99 102 241/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-opacity-80{--tw-bg-opacity:0.8}[class~=theme-dark] .dark\:stroke-gray-500{stroke:#6b7280}[class~=theme-dark] .dark\:stroke-gray-700{stroke:#374151}[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-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-gray-200{--tw-text-opacity:1;color:rgb(229 231 235/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-500{--tw-text-opacity:1;color:rgb(99 102 241/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}[class~=theme-dark] .dark\:ring-white{--tw-ring-opacity:1;--tw-ring-color:rgb(255 255 255/var(--tw-ring-opacity))}[class~=theme-dark] .dark\:ring-opacity-20{--tw-ring-opacity:0.2}[class~=theme-dark] .dark\:hover\:bg-\[\#ffffff12\]:hover{background-color:#ffffff12}[class~=theme-dark] .dark\:hover\:bg-indigo-500:hover{--tw-bg-opacity:1;background-color:rgb(99 102 241/var(--tw-bg-opacity))}[class~=theme-dark] .hover\:dark\:text-gray-100:hover{--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}@media (min-width:640px){.sm\:inline{display:inline}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width:768px){.md\:block{display:block}.md\:flex-row{flex-direction:row}.md\:items-end{align-items:flex-end}.md\:justify-end{justify-content:flex-end}}@media (min-width:1024px){.lg\:flex{display:flex}}
|
|
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}}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.-inset-2{bottom:-.5rem;left:-.5rem;right:-.5rem;top:-.5rem}.inset-y-0{bottom:0;top:0}.left-\[25px\]{left:25px}.left-0{left:0}.top-\[-46px\]{top:-46px}.right-0{right:0}.top-0{top:0}.top-\[-1px\]{top:-1px}.left-\[18px\]{left:18px}.bottom-0{bottom:0}.-top-3{top:-.75rem}.-right-3{right:-.75rem}.z-50{z-index:50}.z-10{z-index:10}.z-20{z-index:20}.m-auto{margin:auto}.m-2{margin:.5rem}.mx-auto{margin-left:auto;margin-right:auto}.mx-2{margin-left:.5rem;margin-right:.5rem}.my-2{margin-bottom:.5rem;margin-top:.5rem}.my-20{margin-bottom:5rem;margin-top:5rem}.my-6{margin-bottom:1.5rem;margin-top:1.5rem}.my-4{margin-bottom:1rem;margin-top:1rem}.mr-3{margin-right:.75rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.ml-2{margin-left:.5rem}.mb-2{margin-bottom:.5rem}.mb-0\.5{margin-bottom:.125rem}.mt-1\.5{margin-top:.375rem}.mb-0{margin-bottom:0}.mb-4{margin-bottom:1rem}.ml-3{margin-left:.75rem}.mr-6{margin-right:1.5rem}.mr-1{margin-right:.25rem}.mb-1{margin-bottom:.25rem}.mr-4{margin-right:1rem}.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}.hidden{display:none}.h-fit{height:-moz-fit-content;height:fit-content}.h-10{height:2.5rem}.h-\[38px\]{height:38px}.h-auto{height:auto}.h-full{height:100%}.h-1{height:.25rem}.h-6{height:1.5rem}.h-4{height:1rem}.h-\[700px\]{height:700px}.h-\[80vh\]{height:80vh}.h-5{height:1.25rem}.h-14{height:3.5rem}.max-h-\[400px\]{max-height:400px}.max-h-\[300px\]{max-height:300px}.min-h-52{min-height:13rem}.min-h-\[38px\]{min-height:38px}.min-h-48{min-height:12rem}.min-h-\[78px\]{min-height:78px}.min-h-96{min-height:24rem}.min-h-\[700px\]{min-height:700px}.w-full{width:100%}.w-auto{width:auto}.w-1\/4{width:25%}.w-3\/4{width:75%}.w-\[500px\]{width:500px}.w-max{width:-moz-max-content;width:max-content}.w-40{width:10rem}.w-3{width:.75rem}.w-5{width:1.25rem}.w-7{width:1.75rem}.w-9{width:2.25rem}.w-11{width:2.75rem}.w-\[52px\]{width:52px}.w-\[68px\]{width:68px}.w-\[76px\]{width:76px}.w-\[84px\]{width:84px}.w-\[92px\]{width:92px}.w-\[100px\]{width:100px}.w-\[108px\]{width:108px}.w-\[116px\]{width:116px}.w-4{width:1rem}.w-\[18px\]{width:18px}.w-8{width:2rem}.w-44{width:11rem}.w-\[460px\]{width:460px}.w-1\/5{width:20%}.w-11\/12{width:91.666667%}.w-1\/12{width:8.333333%}.w-16{width:4rem}.w-fit{width:-moz-fit-content;width:fit-content}.w-\[420px\]{width:420px}.min-w-\[300px\]{min-width:300px}.min-w-\[400px\]{min-width:400px}.min-w-60{min-width:15rem}.max-w-\[500px\]{max-width:500px}.max-w-\[300px\]{max-width:300px}.max-w-\[400px\]{max-width:400px}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.flex-grow-0{flex-grow:0}.flex-grow{flex-grow:1}.table-auto{table-layout:auto}.table-fixed{table-layout:fixed}.origin-top-left{transform-origin:top left}.origin-bottom-left{transform-origin:bottom left}.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}.-rotate-90{--tw-rotate:-90deg}.-rotate-90,.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}.cursor-auto{cursor:auto}.cursor-grabbing{cursor:grabbing}.cursor-grab{cursor:grab}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.content-start{align-content:flex-start}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.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-4{gap:1rem}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1.25rem*var(--tw-space-y-reverse));margin-top:calc(1.25rem*(1 - var(--tw-space-y-reverse)))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-clip{overflow:clip}.overflow-scroll{overflow:scroll}.overflow-x-hidden{overflow-x:hidden}.text-ellipsis{text-overflow:ellipsis}.whitespace-normal{white-space:normal}.whitespace-nowrap{white-space:nowrap}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-full{border-radius:9999px}.rounded-none{border-radius:0}.rounded-t-lg{border-top-left-radius:.5rem;border-top-right-radius:.5rem}.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-x{border-left-width:1px;border-right-width:1px}.border-y{border-bottom-width:1px;border-top-width:1px}.border-r{border-right-width:1px}.border-l{border-left-width:1px}.border-b{border-bottom-width:1px}.border-t{border-top-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))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity))}.border-gray-400{--tw-border-opacity:1;border-color:rgb(156 163 175/var(--tw-border-opacity))}.border-r-gray-200{--tw-border-opacity:1;border-right-color:rgb(229 231 235/var(--tw-border-opacity))}.border-l-amber-900{--tw-border-opacity:1;border-left-color:rgb(120 53 15/var(--tw-border-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-indigo-600{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/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-yellow-200{--tw-bg-opacity:1;background-color:rgb(254 240 138/var(--tw-bg-opacity))}.bg-yellow-700{--tw-bg-opacity:1;background-color:rgb(161 98 7/var(--tw-bg-opacity))}.bg-indigo-100{--tw-bg-opacity:1;background-color:rgb(224 231 255/var(--tw-bg-opacity))}.bg-gray-600{--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}.bg-indigo-50{--tw-bg-opacity:1;background-color:rgb(238 242 255/var(--tw-bg-opacity))}.bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.bg-indigo-500{--tw-bg-opacity:1;background-color:rgb(99 102 241/var(--tw-bg-opacity))}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-inherit{background-color:inherit}.bg-opacity-90{--tw-bg-opacity:0.9}.fill-transparent{fill:transparent}.fill-current{fill:currentColor}.stroke-gray-300{stroke:#d1d5db}.stroke-white{stroke:#fff}.stroke-\[3\]{stroke-width:3}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-10{padding:2.5rem}.p-4{padding:1rem}.p-1\.5{padding:.375rem}.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-6{padding-left:1.5rem;padding-right:1.5rem}.py-4{padding-bottom:1rem;padding-top:1rem}.px-4{padding-left:1rem;padding-right:1rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.\!py-2{padding-bottom:.5rem!important;padding-top:.5rem!important}.\!px-3{padding-left:.75rem!important;padding-right:.75rem!important}.px-3{padding-left:.75rem;padding-right:.75rem}.py-0{padding-bottom:0;padding-top:0}.px-1{padding-left:.25rem;padding-right:.25rem}.px-8{padding-left:2rem;padding-right:2rem}.pr-0{padding-right:0}.pt-2{padding-top:.5rem}.pl-3{padding-left:.75rem}.pr-9{padding-right:2.25rem}.pb-4{padding-bottom:1rem}.pb-2{padding-bottom:.5rem}.pb-6{padding-bottom:1.5rem}.pb-\[10px\]{padding-bottom:10px}.pl-1{padding-left:.25rem}.pr-10{padding-right:2.5rem}.pr-2{padding-right:.5rem}.pl-5{padding-left:1.25rem}.pr-\[1\.7rem\]{padding-right:1.7rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-top{vertical-align:top}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.text-base{font-size:1rem;line-height:1.5rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-\[10px\]{font-size:10px}.text-lg{font-size:1.125rem;line-height:1.75rem}.font-semibold{font-weight:600}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.leading-6{line-height:1.5rem}.leading-5{line-height:1.25rem}.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-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-indigo-600{--tw-text-opacity:1;color:rgb(79 70 229/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.\!text-indigo-600{--tw-text-opacity:1!important;color:rgb(79 70 229/var(--tw-text-opacity))!important}.opacity-100{opacity:1}.opacity-0{opacity:0}.opacity-90{opacity:.9}.opacity-50{opacity:.5}.shadow-\[0_0_10px_2px_rgba\(0\2c 0\2c 0\2c 0\.3\)\]{--tw-shadow:0 0 10px 2px rgba(0,0,0,.3);--tw-shadow-colored:0 0 10px 2px var(--tw-shadow-color)}.shadow-\[0_0_10px_2px_rgba\(0\2c 0\2c 0\2c 0\.3\)\],.shadow-lg{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.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)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.shadow,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.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)}.\[stroke-dasharray\:6\2c 4\]{stroke-dasharray:6,4}.\[stroke-linecap\:round\]{stroke-linecap:round}.\[stroke-linejoin\:round\]{stroke-linejoin:round}.hover\:whitespace-normal:hover{white-space:normal}.hover\:bg-\[\#62626212\]:hover{background-color:#62626212}.hover\:bg-indigo-200:hover{--tw-bg-opacity:1;background-color:rgb(199 210 254/var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.focus\:border-indigo-500:focus{--tw-border-opacity:1;border-color:rgb(99 102 241/var(--tw-border-opacity))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-1:focus{--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)}.focus\:ring-1:focus,.focus\:ring-2:focus{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-2:focus{--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(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-indigo-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(99 102 241/var(--tw-ring-opacity))}.focus\:ring-indigo-600:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(79 70 229/var(--tw-ring-opacity))}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px}.group:hover .group-hover\:flex{display:flex}[class~=theme-dark] .dark\:border{border-width:1px}[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\:border-gray-600{--tw-border-opacity:1;border-color:rgb(75 85 99/var(--tw-border-opacity))}[class~=theme-dark] .dark\:border-gray-700{--tw-border-opacity:1;border-color:rgb(55 65 81/var(--tw-border-opacity))}[class~=theme-dark] .dark\:border-r-gray-700{--tw-border-opacity:1;border-right-color:rgb(55 65 81/var(--tw-border-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\:bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-500{--tw-bg-opacity:1;background-color:rgb(107 114 128/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-yellow-700{--tw-bg-opacity:1;background-color:rgb(161 98 7/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-600{--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-indigo-500{--tw-bg-opacity:1;background-color:rgb(99 102 241/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-opacity-80{--tw-bg-opacity:0.8}[class~=theme-dark] .dark\:stroke-gray-500{stroke:#6b7280}[class~=theme-dark] .dark\:stroke-gray-700{stroke:#374151}[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-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-gray-200{--tw-text-opacity:1;color:rgb(229 231 235/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-500{--tw-text-opacity:1;color:rgb(99 102 241/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}[class~=theme-dark] .dark\:ring-white{--tw-ring-opacity:1;--tw-ring-color:rgb(255 255 255/var(--tw-ring-opacity))}[class~=theme-dark] .dark\:ring-opacity-20{--tw-ring-opacity:0.2}[class~=theme-dark] .dark\:hover\:bg-\[\#ffffff12\]:hover{background-color:#ffffff12}[class~=theme-dark] .dark\:hover\:bg-indigo-500:hover{--tw-bg-opacity:1;background-color:rgb(99 102 241/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:hover\:bg-gray-700:hover{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}[class~=theme-dark] .hover\:dark\:text-gray-100:hover{--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}@media (min-width:640px){.sm\:inline{display:inline}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width:768px){.md\:block{display:block}.md\:flex-row{flex-direction:row}.md\:items-end{align-items:flex-end}.md\:justify-end{justify-content:flex-end}}@media (min-width:1024px){.lg\:flex{display:flex}}
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import type { RpcMetadata } from '@protobuf-ts/runtime-rpc';
|
|
2
2
|
import { QueryRequest, QueryServiceClient } from '@parca/client';
|
|
3
|
-
import { type NavigateFunction } from '@parca/utilities';
|
|
4
3
|
export declare const hexifyAddress: (address?: bigint) => string;
|
|
5
4
|
export declare const downloadPprof: (request: QueryRequest, queryClient: QueryServiceClient, metadata: RpcMetadata) => Promise<Blob>;
|
|
6
5
|
export declare const truncateString: (str: string, num: number) => string;
|
|
7
6
|
export declare const truncateStringReverse: (str: string, num: number) => string;
|
|
8
|
-
export declare const compareProfile: (navigateTo: NavigateFunction, defaultDashboardItems?: string[]) => void;
|
package/dist/utils.js
CHANGED
|
@@ -11,8 +11,6 @@
|
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
import { QueryRequest_ReportType } from '@parca/client';
|
|
14
|
-
import { parseParams } from '@parca/utilities';
|
|
15
|
-
import { ProfileSelectionFromParams, SuffixParams, getExpressionAsAString } from '.';
|
|
16
14
|
export const hexifyAddress = (address) => {
|
|
17
15
|
if (address == null) {
|
|
18
16
|
return '';
|
|
@@ -43,47 +41,3 @@ export const truncateStringReverse = (str, num) => {
|
|
|
43
41
|
}
|
|
44
42
|
return '...' + str.slice(str.length - num);
|
|
45
43
|
};
|
|
46
|
-
export const compareProfile = (navigateTo, defaultDashboardItems = ['icicle']) => {
|
|
47
|
-
const queryParams = parseParams(window.location.search);
|
|
48
|
-
/* eslint-disable @typescript-eslint/naming-convention */
|
|
49
|
-
const { from_a, to_a, merge_from_a, merge_to_a, time_selection_a, filter_by_function, dashboard_items, } = queryParams;
|
|
50
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
51
|
-
const selection_a = getExpressionAsAString(queryParams.selection_a);
|
|
52
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
53
|
-
const expression_a = getExpressionAsAString(queryParams.expression_a);
|
|
54
|
-
if (expression_a === undefined || selection_a === undefined) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
const mergeFrom = merge_from_a ?? undefined;
|
|
58
|
-
const mergeTo = merge_to_a ?? undefined;
|
|
59
|
-
const profileA = ProfileSelectionFromParams(mergeFrom, mergeTo, selection_a, filter_by_function);
|
|
60
|
-
const queryA = {
|
|
61
|
-
expression: expression_a,
|
|
62
|
-
from: parseInt(from_a),
|
|
63
|
-
to: parseInt(to_a),
|
|
64
|
-
timeSelection: time_selection_a,
|
|
65
|
-
};
|
|
66
|
-
let compareQuery = {
|
|
67
|
-
compare_a: 'true',
|
|
68
|
-
expression_a: encodeURIComponent(queryA.expression),
|
|
69
|
-
from_a: queryA.from.toString(),
|
|
70
|
-
to_a: queryA.to.toString(),
|
|
71
|
-
time_selection_a: queryA.timeSelection,
|
|
72
|
-
compare_b: 'true',
|
|
73
|
-
expression_b: encodeURIComponent(queryA.expression),
|
|
74
|
-
from_b: queryA.from.toString(),
|
|
75
|
-
to_b: queryA.to.toString(),
|
|
76
|
-
time_selection_b: queryA.timeSelection,
|
|
77
|
-
};
|
|
78
|
-
if (profileA != null) {
|
|
79
|
-
compareQuery = {
|
|
80
|
-
...SuffixParams(profileA.HistoryParams(), '_a'),
|
|
81
|
-
...compareQuery,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
void navigateTo('/', {
|
|
85
|
-
...compareQuery,
|
|
86
|
-
search_string: '',
|
|
87
|
-
dashboard_items: dashboard_items ?? defaultDashboardItems,
|
|
88
|
-
});
|
|
89
|
-
};
|
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parca/profile",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.393",
|
|
4
4
|
"description": "Profile viewing libraries",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@headlessui/react": "^1.7.19",
|
|
7
7
|
"@iconify/react": "^4.0.0",
|
|
8
|
-
"@parca/client": "0.16.
|
|
9
|
-
"@parca/components": "0.16.
|
|
8
|
+
"@parca/client": "0.16.118",
|
|
9
|
+
"@parca/components": "0.16.285",
|
|
10
10
|
"@parca/dynamicsize": "0.16.65",
|
|
11
|
-
"@parca/hooks": "0.0.
|
|
11
|
+
"@parca/hooks": "0.0.61",
|
|
12
12
|
"@parca/icons": "0.16.69",
|
|
13
13
|
"@parca/parser": "0.16.75",
|
|
14
|
-
"@parca/store": "0.16.
|
|
15
|
-
"@parca/utilities": "0.0.
|
|
14
|
+
"@parca/store": "0.16.150",
|
|
15
|
+
"@parca/utilities": "0.0.78",
|
|
16
16
|
"@popperjs/core": "^2.11.8",
|
|
17
17
|
"@protobuf-ts/runtime-rpc": "^2.5.0",
|
|
18
18
|
"@tanstack/react-query": "^4.0.5",
|
|
@@ -38,11 +38,13 @@
|
|
|
38
38
|
"react-beautiful-dnd": "^13.1.1",
|
|
39
39
|
"react-contexify": "^6.0.0",
|
|
40
40
|
"react-dom": "18.3.1",
|
|
41
|
+
"react-draggable": "^4.4.6",
|
|
41
42
|
"react-flame-graph": "^1.4.0",
|
|
42
43
|
"react-inlinesvg": "^3.0.2",
|
|
43
44
|
"react-map-interaction": "^2.1.0",
|
|
44
45
|
"react-popper": "^2.3.0",
|
|
45
46
|
"react-redux": "^8.0.2",
|
|
47
|
+
"react-select": "^5.8.0",
|
|
46
48
|
"react-syntax-highlighter": "^15.5.0",
|
|
47
49
|
"react-textarea-autosize": "^8.4.0",
|
|
48
50
|
"react-tooltip": "^5.26.3",
|
|
@@ -71,5 +73,5 @@
|
|
|
71
73
|
"access": "public",
|
|
72
74
|
"registry": "https://registry.npmjs.org/"
|
|
73
75
|
},
|
|
74
|
-
"gitHead": "
|
|
76
|
+
"gitHead": "6c04fc4c249509a65e48a0a9273c28c1c1c41b62"
|
|
75
77
|
}
|
|
@@ -16,10 +16,10 @@ import React, {useEffect, useMemo, useRef, useState} from 'react';
|
|
|
16
16
|
import cx from 'classnames';
|
|
17
17
|
import TextareaAutosize from 'react-textarea-autosize';
|
|
18
18
|
|
|
19
|
-
import {LabelsResponse, QueryServiceClient} from '@parca/client';
|
|
19
|
+
import {LabelsRequest, LabelsResponse, QueryServiceClient} from '@parca/client';
|
|
20
20
|
import {useGrpcMetadata} from '@parca/components';
|
|
21
21
|
import {Query} from '@parca/parser';
|
|
22
|
-
import {sanitizeLabelValue} from '@parca/utilities';
|
|
22
|
+
import {millisToProtoTimestamp, sanitizeLabelValue} from '@parca/utilities';
|
|
23
23
|
|
|
24
24
|
import SuggestionsList, {Suggestion, Suggestions} from './SuggestionsList';
|
|
25
25
|
|
|
@@ -40,20 +40,33 @@ interface UseLabelNames {
|
|
|
40
40
|
loading: boolean;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
export const useLabelNames = (
|
|
43
|
+
export const useLabelNames = (
|
|
44
|
+
client: QueryServiceClient,
|
|
45
|
+
start?: number,
|
|
46
|
+
end?: number,
|
|
47
|
+
profileType?: string
|
|
48
|
+
): UseLabelNames => {
|
|
44
49
|
const [loading, setLoading] = useState(true);
|
|
45
50
|
const [result, setResult] = useState<ILabelNamesResult>({});
|
|
46
51
|
const metadata = useGrpcMetadata();
|
|
47
52
|
|
|
48
53
|
useEffect(() => {
|
|
49
|
-
const
|
|
54
|
+
const request: LabelsRequest = {match: []};
|
|
55
|
+
if (start !== undefined && end !== undefined) {
|
|
56
|
+
request.start = millisToProtoTimestamp(start);
|
|
57
|
+
request.end = millisToProtoTimestamp(end);
|
|
58
|
+
}
|
|
59
|
+
if (profileType !== undefined) {
|
|
60
|
+
request.profileType = profileType;
|
|
61
|
+
}
|
|
62
|
+
const call = client.labels(request, {meta: metadata});
|
|
50
63
|
setLoading(true);
|
|
51
64
|
|
|
52
65
|
call.response
|
|
53
66
|
.then(response => setResult({response}))
|
|
54
67
|
.catch(error => setResult({error}))
|
|
55
68
|
.finally(() => setLoading(false));
|
|
56
|
-
}, [client, metadata]);
|
|
69
|
+
}, [client, metadata, start, end, profileType]);
|
|
57
70
|
|
|
58
71
|
return {result, loading};
|
|
59
72
|
};
|
|
@@ -69,6 +69,7 @@ const ProfileExplorerCompare = ({
|
|
|
69
69
|
closeProfile={closeProfileA}
|
|
70
70
|
enforcedProfileName={''}
|
|
71
71
|
comparing={true}
|
|
72
|
+
navigateTo={navigateTo}
|
|
72
73
|
/>
|
|
73
74
|
</Card>
|
|
74
75
|
<Card className="mt-2 p-2">
|
|
@@ -81,6 +82,7 @@ const ProfileExplorerCompare = ({
|
|
|
81
82
|
closeProfile={closeProfileB}
|
|
82
83
|
enforcedProfileName={Query.parse(queryA.expression).profileName()}
|
|
83
84
|
comparing={true}
|
|
85
|
+
navigateTo={navigateTo}
|
|
84
86
|
/>
|
|
85
87
|
</Card>
|
|
86
88
|
</div>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// Copyright 2022 The Parca Authors
|
|
2
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
// you may not use this file except in compliance with the License.
|
|
4
|
+
// You may obtain a copy of the License at
|
|
5
|
+
//
|
|
6
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
//
|
|
8
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
// See the License for the specific language governing permissions and
|
|
12
|
+
// limitations under the License.
|
|
13
|
+
|
|
14
|
+
import {ReactNode, useId, useMemo, useState} from 'react';
|
|
15
|
+
|
|
16
|
+
import {Icon} from '@iconify/react';
|
|
17
|
+
import Draggable from 'react-draggable';
|
|
18
|
+
import Select from 'react-select';
|
|
19
|
+
|
|
20
|
+
import {IconButton} from '@parca/components';
|
|
21
|
+
|
|
22
|
+
interface Props {
|
|
23
|
+
sumBy: string[];
|
|
24
|
+
setSumBy: (sumBy: string[]) => void;
|
|
25
|
+
labels: string[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const Toolbar = ({sumBy, setSumBy, labels}: Props): ReactNode => {
|
|
29
|
+
const [collapsed, setCollapsed] = useState<boolean>(false);
|
|
30
|
+
const [isDragging, setIsDragging] = useState<boolean>(false);
|
|
31
|
+
const idWithColon = useId();
|
|
32
|
+
const id = useMemo(() => idWithColon.replace(/[^a-zA-Z0-9]/g, ''), [idWithColon]);
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<Draggable
|
|
36
|
+
handle={`#${id}`}
|
|
37
|
+
onStart={() => setIsDragging(true)}
|
|
38
|
+
onStop={() => setIsDragging(false)}
|
|
39
|
+
bounds="parent"
|
|
40
|
+
defaultPosition={{x: 96, y: 4}}
|
|
41
|
+
>
|
|
42
|
+
<div className="absolute rounded-full bg-gray-100 dark:bg-gray-800 z-10 text-xs">
|
|
43
|
+
<div className="flex items-center h-14 gap-4 py-1 px-3">
|
|
44
|
+
<Icon
|
|
45
|
+
icon="radix-icons:drag-handle-dots-2"
|
|
46
|
+
height={20}
|
|
47
|
+
className={isDragging ? 'cursor-grabbing' : 'cursor-grab'}
|
|
48
|
+
id={id}
|
|
49
|
+
/>
|
|
50
|
+
{!collapsed ? (
|
|
51
|
+
<div className="flex gap-2 items-center mr-4">
|
|
52
|
+
<span>Sum by</span>
|
|
53
|
+
<Select
|
|
54
|
+
defaultValue={[]}
|
|
55
|
+
isMulti
|
|
56
|
+
name="colors"
|
|
57
|
+
options={labels.map(label => ({label, value: label}))}
|
|
58
|
+
className="parca-select-container min-w-60"
|
|
59
|
+
classNamePrefix="parca-select"
|
|
60
|
+
value={sumBy.map(sumBy => ({label: sumBy, value: sumBy}))}
|
|
61
|
+
onChange={selectedOptions => {
|
|
62
|
+
setSumBy(selectedOptions.map(option => option.value));
|
|
63
|
+
}}
|
|
64
|
+
placeholder="Labels..."
|
|
65
|
+
styles={{
|
|
66
|
+
indicatorSeparator: () => ({display: 'none'}),
|
|
67
|
+
}}
|
|
68
|
+
/>
|
|
69
|
+
</div>
|
|
70
|
+
) : null}
|
|
71
|
+
<div className="relative">
|
|
72
|
+
<IconButton
|
|
73
|
+
icon={
|
|
74
|
+
<Icon
|
|
75
|
+
icon={
|
|
76
|
+
collapsed ? 'iconamoon:arrow-right-2-light' : 'iconamoon:arrow-left-2-light'
|
|
77
|
+
}
|
|
78
|
+
height={24}
|
|
79
|
+
/>
|
|
80
|
+
}
|
|
81
|
+
onClick={() => setCollapsed(!collapsed)}
|
|
82
|
+
className="hover:bg-gray-200 dark:hover:bg-gray-700 rounded-full p-1"
|
|
83
|
+
/>
|
|
84
|
+
{collapsed && sumBy.length > 0 ? (
|
|
85
|
+
<div className="rounded-full bg-indigo-600 dark:bg-indigo-500 absolute text-xs h-4 w-4 flex items-center justify-center -top-3 -right-3 text-white text-[10px]">
|
|
86
|
+
{sumBy.length}
|
|
87
|
+
</div>
|
|
88
|
+
) : null}
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
</Draggable>
|
|
93
|
+
);
|
|
94
|
+
};
|
|
@@ -27,9 +27,12 @@ import {Query} from '@parca/parser';
|
|
|
27
27
|
import {capitalizeOnlyFirstLetter, getStepDuration} from '@parca/utilities';
|
|
28
28
|
|
|
29
29
|
import {MergedProfileSelection, ProfileSelection} from '..';
|
|
30
|
+
import {useLabelNames} from '../MatchersInput';
|
|
30
31
|
import MetricsGraph from '../MetricsGraph';
|
|
31
32
|
import {useMetricsGraphDimensions} from '../MetricsGraph/useMetricsGraphDimensions';
|
|
32
33
|
import useDelayedLoader from '../useDelayedLoader';
|
|
34
|
+
import {Toolbar} from './Toolbar';
|
|
35
|
+
import {useSumBy} from './useSumBy';
|
|
33
36
|
|
|
34
37
|
interface ProfileMetricsEmptyStateProps {
|
|
35
38
|
message: string;
|
|
@@ -83,18 +86,23 @@ export const useQueryRange = (
|
|
|
83
86
|
client: QueryServiceClient,
|
|
84
87
|
queryExpression: string,
|
|
85
88
|
start: number,
|
|
86
|
-
end: number
|
|
89
|
+
end: number,
|
|
90
|
+
sumBy: string[] = [],
|
|
91
|
+
skip = false
|
|
87
92
|
): IQueryRangeState => {
|
|
93
|
+
const [isLoading, setLoading] = useState<boolean>(!skip);
|
|
88
94
|
const [state, setState] = useState<IQueryRangeState>({
|
|
89
95
|
response: null,
|
|
90
|
-
isLoading
|
|
96
|
+
isLoading,
|
|
91
97
|
error: null,
|
|
92
98
|
});
|
|
93
|
-
const [isLoading, setLoading] = useState<boolean>(true);
|
|
94
99
|
const metadata = useGrpcMetadata();
|
|
95
100
|
|
|
96
101
|
useEffect(() => {
|
|
97
102
|
void (async () => {
|
|
103
|
+
if (skip) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
98
106
|
setLoading(true);
|
|
99
107
|
|
|
100
108
|
const stepDuration = getStepDuration(start, end);
|
|
@@ -105,6 +113,7 @@ export const useQueryRange = (
|
|
|
105
113
|
end: Timestamp.fromDate(new Date(end)),
|
|
106
114
|
step: Duration.create(stepDuration),
|
|
107
115
|
limit: 0,
|
|
116
|
+
sumBy,
|
|
108
117
|
},
|
|
109
118
|
{meta: metadata}
|
|
110
119
|
);
|
|
@@ -120,7 +129,7 @@ export const useQueryRange = (
|
|
|
120
129
|
setLoading(false);
|
|
121
130
|
});
|
|
122
131
|
})();
|
|
123
|
-
}, [client, queryExpression, start, end, metadata]);
|
|
132
|
+
}, [client, queryExpression, start, end, metadata, sumBy, skip]);
|
|
124
133
|
|
|
125
134
|
return {...state, isLoading};
|
|
126
135
|
};
|
|
@@ -136,7 +145,25 @@ const ProfileMetricsGraph = ({
|
|
|
136
145
|
onPointClick,
|
|
137
146
|
comparing = false,
|
|
138
147
|
}: ProfileMetricsGraphProps): JSX.Element => {
|
|
139
|
-
const {
|
|
148
|
+
const {loading: labelNamesLoading, result: labelNamesResult} = useLabelNames(
|
|
149
|
+
queryClient,
|
|
150
|
+
from,
|
|
151
|
+
to,
|
|
152
|
+
profile?.ProfileSource()?.ProfileType()?.toString()
|
|
153
|
+
);
|
|
154
|
+
const [sumBy, setSumBy] = useSumBy(
|
|
155
|
+
profile?.ProfileSource()?.ProfileType(),
|
|
156
|
+
labelNamesResult.response?.labelNames
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
const {isLoading, response, error} = useQueryRange(
|
|
160
|
+
queryClient,
|
|
161
|
+
queryExpression,
|
|
162
|
+
from,
|
|
163
|
+
to,
|
|
164
|
+
sumBy,
|
|
165
|
+
labelNamesLoading
|
|
166
|
+
);
|
|
140
167
|
const isLoaderVisible = useDelayedLoader(isLoading);
|
|
141
168
|
const {onError, perf, authenticationErrorMessage, isDarkMode} = useParcaContext();
|
|
142
169
|
const {width, height, margin, heightStyle} = useMetricsGraphDimensions(comparing);
|
|
@@ -158,7 +185,8 @@ const ProfileMetricsGraph = ({
|
|
|
158
185
|
const series = response?.series;
|
|
159
186
|
const dataAvailable = series !== null && series !== undefined && series?.length > 0;
|
|
160
187
|
|
|
161
|
-
const metricsGraphLoading =
|
|
188
|
+
const metricsGraphLoading =
|
|
189
|
+
isLoaderVisible || (isLoading && !dataAvailable && !labelNamesLoading);
|
|
162
190
|
|
|
163
191
|
if (metricsGraphLoading) {
|
|
164
192
|
return <MetricsGraphSkeleton heightStyle={heightStyle} isDarkMode={isDarkMode} />;
|
|
@@ -172,6 +200,12 @@ const ProfileMetricsGraph = ({
|
|
|
172
200
|
return <ErrorContent errorMessage={capitalizeOnlyFirstLetter(error.message)} />;
|
|
173
201
|
}
|
|
174
202
|
|
|
203
|
+
if (!labelNamesLoading && labelNamesResult?.error != null) {
|
|
204
|
+
return (
|
|
205
|
+
<ErrorContent errorMessage={capitalizeOnlyFirstLetter(labelNamesResult.error.message)} />
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
175
209
|
if (dataAvailable) {
|
|
176
210
|
const handleSampleClick = (
|
|
177
211
|
timestamp: number,
|
|
@@ -193,12 +227,17 @@ const ProfileMetricsGraph = ({
|
|
|
193
227
|
return (
|
|
194
228
|
<AnimatePresence>
|
|
195
229
|
<motion.div
|
|
196
|
-
className="h-full w-full"
|
|
230
|
+
className="h-full w-full relative"
|
|
197
231
|
key="metrics-graph-loaded"
|
|
198
232
|
initial={{display: 'none', opacity: 0}}
|
|
199
233
|
animate={{display: 'block', opacity: 1}}
|
|
200
234
|
transition={{duration: 0.5}}
|
|
201
235
|
>
|
|
236
|
+
<Toolbar
|
|
237
|
+
sumBy={sumBy}
|
|
238
|
+
setSumBy={setSumBy}
|
|
239
|
+
labels={labelNamesResult.response?.labelNames ?? []}
|
|
240
|
+
/>
|
|
202
241
|
<MetricsGraph
|
|
203
242
|
data={series}
|
|
204
243
|
from={from}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// Copyright 2022 The Parca Authors
|
|
2
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
// you may not use this file except in compliance with the License.
|
|
4
|
+
// You may obtain a copy of the License at
|
|
5
|
+
//
|
|
6
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
//
|
|
8
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
// See the License for the specific language governing permissions and
|
|
12
|
+
// limitations under the License.
|
|
13
|
+
|
|
14
|
+
import {useEffect, useState} from 'react';
|
|
15
|
+
|
|
16
|
+
import {ProfileType} from '@parca/parser';
|
|
17
|
+
|
|
18
|
+
const DEFAULT_EMPTY_SUM_BY: string[] = [];
|
|
19
|
+
|
|
20
|
+
const getDefaultSumBy = (
|
|
21
|
+
profile: ProfileType | undefined,
|
|
22
|
+
labels: string[] | undefined
|
|
23
|
+
): string[] | undefined => {
|
|
24
|
+
if (profile === undefined || labels === undefined) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!profile.delta) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (labels.includes('comm')) {
|
|
33
|
+
return ['comm'];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (labels.includes('namespace')) {
|
|
37
|
+
return ['namespace'];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (labels.includes('container')) {
|
|
41
|
+
return ['container'];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return undefined;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const useSumBy = (
|
|
48
|
+
profileType: ProfileType | undefined,
|
|
49
|
+
labels: string[] | undefined
|
|
50
|
+
): [string[], (labels: string[]) => void] => {
|
|
51
|
+
const [userSelectedSumBy, setUserSelectedSumBy] = useState<string[] | undefined>(undefined);
|
|
52
|
+
const [defaultSumBy, setDefaultSumBy] = useState<string[] | undefined>(
|
|
53
|
+
getDefaultSumBy(profileType, labels)
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
setDefaultSumBy(getDefaultSumBy(profileType, labels));
|
|
58
|
+
}, [profileType, labels]);
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (profileType === undefined) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Reset user selected sumBy if profile type changes
|
|
66
|
+
setUserSelectedSumBy(undefined);
|
|
67
|
+
}, [profileType]);
|
|
68
|
+
|
|
69
|
+
return [userSelectedSumBy ?? defaultSumBy ?? DEFAULT_EMPTY_SUM_BY, setUserSelectedSumBy];
|
|
70
|
+
};
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
} from '@parca/components';
|
|
28
28
|
import {CloseIcon} from '@parca/icons';
|
|
29
29
|
import {Query} from '@parca/parser';
|
|
30
|
+
import {type NavigateFunction} from '@parca/utilities';
|
|
30
31
|
|
|
31
32
|
import {MergedProfileSelection, ProfileSelection} from '..';
|
|
32
33
|
import MatchersInput from '../MatchersInput/index';
|
|
@@ -53,6 +54,7 @@ interface ProfileSelectorProps {
|
|
|
53
54
|
enforcedProfileName: string;
|
|
54
55
|
profileSelection: ProfileSelection | null;
|
|
55
56
|
comparing: boolean;
|
|
57
|
+
navigateTo: NavigateFunction;
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
export interface IProfileTypesResult {
|
|
@@ -90,6 +92,7 @@ const ProfileSelector = ({
|
|
|
90
92
|
enforcedProfileName,
|
|
91
93
|
profileSelection,
|
|
92
94
|
comparing,
|
|
95
|
+
navigateTo,
|
|
93
96
|
}: ProfileSelectorProps): JSX.Element => {
|
|
94
97
|
const {
|
|
95
98
|
loading: profileTypesLoading,
|
|
@@ -214,6 +217,8 @@ const ProfileSelector = ({
|
|
|
214
217
|
profileTypesData,
|
|
215
218
|
setProfileName,
|
|
216
219
|
setQueryExpression,
|
|
220
|
+
querySelection,
|
|
221
|
+
navigateTo,
|
|
217
222
|
});
|
|
218
223
|
|
|
219
224
|
const searchDisabled =
|
|
@@ -15,7 +15,10 @@ import {useEffect} from 'react';
|
|
|
15
15
|
|
|
16
16
|
import {ProfileTypesResponse} from '@parca/client';
|
|
17
17
|
import {selectAutoQuery, setAutoQuery, useAppDispatch, useAppSelector} from '@parca/store';
|
|
18
|
+
import {type NavigateFunction} from '@parca/utilities';
|
|
18
19
|
|
|
20
|
+
import {ProfileSelectionFromParams, SuffixParams} from '..';
|
|
21
|
+
import {QuerySelection} from '../ProfileSelector';
|
|
19
22
|
import {constructProfileName} from '../ProfileTypeSelector';
|
|
20
23
|
|
|
21
24
|
interface Props {
|
|
@@ -23,6 +26,8 @@ interface Props {
|
|
|
23
26
|
profileTypesData: ProfileTypesResponse | undefined;
|
|
24
27
|
setProfileName: (name: string) => void;
|
|
25
28
|
setQueryExpression: () => void;
|
|
29
|
+
querySelection: QuerySelection;
|
|
30
|
+
navigateTo: NavigateFunction;
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
export const useAutoQuerySelector = ({
|
|
@@ -30,9 +35,62 @@ export const useAutoQuerySelector = ({
|
|
|
30
35
|
profileTypesData,
|
|
31
36
|
setProfileName,
|
|
32
37
|
setQueryExpression,
|
|
38
|
+
querySelection,
|
|
39
|
+
navigateTo,
|
|
33
40
|
}: Props): void => {
|
|
34
41
|
const autoQuery = useAppSelector(selectAutoQuery);
|
|
35
42
|
const dispatch = useAppDispatch();
|
|
43
|
+
const queryParams = new URLSearchParams(location.search);
|
|
44
|
+
|
|
45
|
+
const comparing = queryParams.get('comparing') === 'true';
|
|
46
|
+
const expressionA = queryParams.get('expression_a');
|
|
47
|
+
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (comparing && expressionA !== null && expressionA !== undefined) {
|
|
50
|
+
if (querySelection.expression === undefined) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const profileA = ProfileSelectionFromParams(
|
|
54
|
+
querySelection.mergeFrom?.toString(),
|
|
55
|
+
querySelection.mergeTo?.toString(),
|
|
56
|
+
querySelection.expression,
|
|
57
|
+
''
|
|
58
|
+
);
|
|
59
|
+
const queryA = {
|
|
60
|
+
expression: querySelection.expression,
|
|
61
|
+
from: querySelection.from,
|
|
62
|
+
to: querySelection.to,
|
|
63
|
+
timeSelection: querySelection.timeSelection,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
let compareQuery = {
|
|
67
|
+
compare_a: 'true',
|
|
68
|
+
expression_a: encodeURIComponent(queryA.expression),
|
|
69
|
+
from_a: queryA.from.toString(),
|
|
70
|
+
to_a: queryA.to.toString(),
|
|
71
|
+
time_selection_a: queryA.timeSelection,
|
|
72
|
+
|
|
73
|
+
compare_b: 'true',
|
|
74
|
+
expression_b: encodeURIComponent(queryA.expression),
|
|
75
|
+
from_b: queryA.from.toString(),
|
|
76
|
+
to_b: queryA.to.toString(),
|
|
77
|
+
time_selection_b: queryA.timeSelection,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
if (profileA != null) {
|
|
81
|
+
compareQuery = {
|
|
82
|
+
...SuffixParams(profileA.HistoryParams(), '_a'),
|
|
83
|
+
...compareQuery,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
void navigateTo('/', {
|
|
88
|
+
...compareQuery,
|
|
89
|
+
search_string: '',
|
|
90
|
+
dashboard_items: ['icicle'],
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}, [comparing, querySelection, navigateTo, expressionA, dispatch]);
|
|
36
94
|
|
|
37
95
|
// Effect to load some initial data on load when is no selection
|
|
38
96
|
useEffect(() => {
|
package/src/utils.ts
CHANGED
|
@@ -14,9 +14,6 @@
|
|
|
14
14
|
import type {RpcMetadata} from '@protobuf-ts/runtime-rpc';
|
|
15
15
|
|
|
16
16
|
import {QueryRequest, QueryRequest_ReportType, QueryServiceClient} from '@parca/client';
|
|
17
|
-
import {parseParams, type NavigateFunction} from '@parca/utilities';
|
|
18
|
-
|
|
19
|
-
import {ProfileSelectionFromParams, SuffixParams, getExpressionAsAString} from '.';
|
|
20
17
|
|
|
21
18
|
export const hexifyAddress = (address?: bigint): string => {
|
|
22
19
|
if (address == null) {
|
|
@@ -62,73 +59,3 @@ export const truncateStringReverse = (str: string, num: number): string => {
|
|
|
62
59
|
|
|
63
60
|
return '...' + str.slice(str.length - num);
|
|
64
61
|
};
|
|
65
|
-
|
|
66
|
-
export const compareProfile = (
|
|
67
|
-
navigateTo: NavigateFunction,
|
|
68
|
-
defaultDashboardItems: string[] = ['icicle']
|
|
69
|
-
): void => {
|
|
70
|
-
const queryParams = parseParams(window.location.search);
|
|
71
|
-
|
|
72
|
-
/* eslint-disable @typescript-eslint/naming-convention */
|
|
73
|
-
const {
|
|
74
|
-
from_a,
|
|
75
|
-
to_a,
|
|
76
|
-
merge_from_a,
|
|
77
|
-
merge_to_a,
|
|
78
|
-
time_selection_a,
|
|
79
|
-
filter_by_function,
|
|
80
|
-
dashboard_items,
|
|
81
|
-
} = queryParams;
|
|
82
|
-
|
|
83
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
84
|
-
const selection_a = getExpressionAsAString(queryParams.selection_a as string | []);
|
|
85
|
-
|
|
86
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
87
|
-
const expression_a = getExpressionAsAString(queryParams.expression_a as string | []);
|
|
88
|
-
|
|
89
|
-
if (expression_a === undefined || selection_a === undefined) {
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const mergeFrom = merge_from_a ?? undefined;
|
|
94
|
-
const mergeTo = merge_to_a ?? undefined;
|
|
95
|
-
const profileA = ProfileSelectionFromParams(
|
|
96
|
-
mergeFrom as string,
|
|
97
|
-
mergeTo as string,
|
|
98
|
-
selection_a,
|
|
99
|
-
filter_by_function as string
|
|
100
|
-
);
|
|
101
|
-
const queryA = {
|
|
102
|
-
expression: expression_a,
|
|
103
|
-
from: parseInt(from_a as string),
|
|
104
|
-
to: parseInt(to_a as string),
|
|
105
|
-
timeSelection: time_selection_a as string,
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
let compareQuery = {
|
|
109
|
-
compare_a: 'true',
|
|
110
|
-
expression_a: encodeURIComponent(queryA.expression),
|
|
111
|
-
from_a: queryA.from.toString(),
|
|
112
|
-
to_a: queryA.to.toString(),
|
|
113
|
-
time_selection_a: queryA.timeSelection,
|
|
114
|
-
|
|
115
|
-
compare_b: 'true',
|
|
116
|
-
expression_b: encodeURIComponent(queryA.expression),
|
|
117
|
-
from_b: queryA.from.toString(),
|
|
118
|
-
to_b: queryA.to.toString(),
|
|
119
|
-
time_selection_b: queryA.timeSelection,
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
if (profileA != null) {
|
|
123
|
-
compareQuery = {
|
|
124
|
-
...SuffixParams(profileA.HistoryParams(), '_a'),
|
|
125
|
-
...compareQuery,
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
void navigateTo('/', {
|
|
130
|
-
...compareQuery,
|
|
131
|
-
search_string: '',
|
|
132
|
-
dashboard_items: dashboard_items ?? defaultDashboardItems,
|
|
133
|
-
});
|
|
134
|
-
};
|