@parca/profile 0.19.83 → 0.19.85
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 +2 -34
- package/dist/MatchersInput/index.d.ts.map +1 -1
- package/dist/MatchersInput/index.js +14 -91
- package/dist/MetricsGraph/index.d.ts.map +1 -1
- package/dist/MetricsGraph/index.js +13 -1
- package/dist/ProfileMetricsGraph/index.d.ts.map +1 -1
- package/dist/ProfileMetricsGraph/index.js +6 -29
- package/dist/ProfileSelector/MetricsGraphSection.d.ts +8 -10
- package/dist/ProfileSelector/MetricsGraphSection.d.ts.map +1 -1
- package/dist/ProfileSelector/MetricsGraphSection.js +8 -41
- package/dist/ProfileSelector/index.d.ts +1 -29
- package/dist/ProfileSelector/index.d.ts.map +1 -1
- package/dist/ProfileSelector/index.js +14 -10
- package/dist/QueryControls/index.d.ts +46 -0
- package/dist/QueryControls/index.d.ts.map +1 -0
- package/dist/{ProfileSelector/QueryControls.js → QueryControls/index.js} +16 -13
- package/dist/SimpleMatchers/Select.js +1 -1
- package/dist/SimpleMatchers/index.d.ts +6 -10
- package/dist/SimpleMatchers/index.d.ts.map +1 -1
- package/dist/SimpleMatchers/index.js +30 -45
- package/dist/ViewMatchers/index.d.ts +0 -9
- package/dist/ViewMatchers/index.d.ts.map +1 -1
- package/dist/ViewMatchers/index.js +20 -12
- package/dist/contexts/LabelsQueryProvider.d.ts +35 -0
- package/dist/contexts/LabelsQueryProvider.d.ts.map +1 -0
- package/dist/contexts/LabelsQueryProvider.js +70 -0
- package/dist/contexts/UnifiedLabelsContext.d.ts +37 -0
- package/dist/contexts/UnifiedLabelsContext.d.ts.map +1 -0
- package/dist/contexts/UnifiedLabelsContext.js +88 -0
- package/dist/contexts/utils.d.ts +10 -0
- package/dist/contexts/utils.d.ts.map +1 -0
- package/dist/contexts/utils.js +31 -0
- package/dist/hooks/useLabels.d.ts +23 -0
- package/dist/hooks/useLabels.d.ts.map +1 -0
- package/dist/hooks/useLabels.js +75 -0
- package/dist/hooks/useQueryState.d.ts +3 -1
- package/dist/hooks/useQueryState.d.ts.map +1 -1
- package/dist/hooks/useQueryState.js +19 -12
- package/dist/index.d.ts +9 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -3
- package/dist/styles.css +1 -1
- package/dist/useSumBy.js +1 -1
- package/package.json +2 -2
- package/src/MatchersInput/index.tsx +17 -163
- package/src/MetricsGraph/index.tsx +17 -1
- package/src/ProfileMetricsGraph/index.tsx +17 -98
- package/src/ProfileSelector/MetricsGraphSection.tsx +25 -119
- package/src/ProfileSelector/index.tsx +115 -109
- package/src/{ProfileSelector/QueryControls.tsx → QueryControls/index.tsx} +76 -84
- package/src/SimpleMatchers/Select.tsx +1 -1
- package/src/SimpleMatchers/index.tsx +46 -84
- package/src/ViewMatchers/index.tsx +22 -30
- package/src/contexts/LabelsQueryProvider.tsx +142 -0
- package/src/contexts/UnifiedLabelsContext.tsx +155 -0
- package/src/contexts/utils.ts +43 -0
- package/src/hooks/useLabels.ts +121 -0
- package/src/hooks/useQueryState.ts +27 -16
- package/src/index.tsx +29 -3
- package/src/useSumBy.ts +1 -1
- package/dist/MetricsGraph/UtilizationMetrics/Throughput.d.ts +0 -29
- package/dist/MetricsGraph/UtilizationMetrics/Throughput.d.ts.map +0 -1
- package/dist/MetricsGraph/UtilizationMetrics/Throughput.js +0 -175
- package/dist/MetricsGraph/UtilizationMetrics/index.d.ts +0 -28
- package/dist/MetricsGraph/UtilizationMetrics/index.d.ts.map +0 -1
- package/dist/MetricsGraph/UtilizationMetrics/index.js +0 -186
- package/dist/ProfileSelector/QueryControls.d.ts +0 -43
- package/dist/ProfileSelector/QueryControls.d.ts.map +0 -1
- package/dist/contexts/MatchersInputLabelsContext.d.ts +0 -29
- package/dist/contexts/MatchersInputLabelsContext.d.ts.map +0 -1
- package/dist/contexts/MatchersInputLabelsContext.js +0 -79
- package/dist/contexts/SimpleMatchersLabelContext.d.ts +0 -25
- package/dist/contexts/SimpleMatchersLabelContext.d.ts.map +0 -1
- package/dist/contexts/SimpleMatchersLabelContext.js +0 -115
- package/dist/contexts/UtilizationLabelsContext.d.ts +0 -15
- package/dist/contexts/UtilizationLabelsContext.d.ts.map +0 -1
- package/dist/contexts/UtilizationLabelsContext.js +0 -25
- package/src/MetricsGraph/UtilizationMetrics/Throughput.tsx +0 -405
- package/src/MetricsGraph/UtilizationMetrics/index.tsx +0 -426
- package/src/contexts/MatchersInputLabelsContext.tsx +0 -141
- package/src/contexts/SimpleMatchersLabelContext.tsx +0 -189
- package/src/contexts/UtilizationLabelsContext.tsx +0 -45
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.19.85](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.84...@parca/profile@0.19.85) (2025-11-27)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @parca/profile
|
|
9
|
+
|
|
10
|
+
## [0.19.84](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.83...@parca/profile@0.19.84) (2025-11-27)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @parca/profile
|
|
13
|
+
|
|
6
14
|
## [0.19.83](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.82...@parca/profile@0.19.83) (2025-11-26)
|
|
7
15
|
|
|
8
16
|
### Reverts
|
|
@@ -1,35 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { UtilizationLabels } from '../ProfileSelector';
|
|
4
|
-
interface MatchersInputProps {
|
|
5
|
-
queryClient: QueryServiceClient;
|
|
6
|
-
setMatchersString: (arg: string) => void;
|
|
7
|
-
runQuery: () => void;
|
|
8
|
-
currentQuery: Query;
|
|
9
|
-
profileType: string;
|
|
10
|
-
start?: number;
|
|
11
|
-
end?: number;
|
|
12
|
-
}
|
|
13
|
-
export interface ILabelNamesResult {
|
|
14
|
-
response?: LabelsResponse;
|
|
15
|
-
error?: Error;
|
|
16
|
-
}
|
|
17
|
-
interface UseLabelNames {
|
|
18
|
-
result: ILabelNamesResult;
|
|
19
|
-
loading: boolean;
|
|
20
|
-
refetch: () => Promise<void>;
|
|
21
|
-
}
|
|
22
|
-
export declare const useLabelNames: (client: QueryServiceClient, profileType: string, start?: number, end?: number, match?: string[]) => UseLabelNames;
|
|
23
|
-
interface UseLabelValues {
|
|
24
|
-
result: {
|
|
25
|
-
response: string[];
|
|
26
|
-
error?: Error;
|
|
27
|
-
};
|
|
28
|
-
loading: boolean;
|
|
29
|
-
refetch: () => Promise<void>;
|
|
30
|
-
}
|
|
31
|
-
export declare const useLabelValues: (client: QueryServiceClient, labelName: string, profileType: string, start?: number, end?: number) => UseLabelValues;
|
|
32
|
-
export declare const useFetchUtilizationLabelValues: (labelName: string, utilizationLabels?: UtilizationLabels) => string[];
|
|
33
|
-
export default function MatchersInputWithProvider(props: MatchersInputProps): JSX.Element;
|
|
34
|
-
export {};
|
|
1
|
+
declare const MatchersInput: () => JSX.Element;
|
|
2
|
+
export default MatchersInput;
|
|
35
3
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/MatchersInput/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/MatchersInput/index.tsx"],"names":[],"mappings":"AAyBA,QAAA,MAAM,aAAa,QAAO,GAAG,CAAC,OAsM7B,CAAC;AAEF,eAAe,aAAa,CAAC"}
|
|
@@ -11,99 +11,24 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
11
11
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
// See the License for the specific language governing permissions and
|
|
13
13
|
// limitations under the License.
|
|
14
|
-
import {
|
|
15
|
-
import { useQuery } from '@tanstack/react-query';
|
|
14
|
+
import { useMemo, useRef, useState } from 'react';
|
|
16
15
|
import cx from 'classnames';
|
|
17
16
|
import TextareaAutosize from 'react-textarea-autosize';
|
|
18
|
-
import { useGrpcMetadata } from '@parca/components';
|
|
19
17
|
import { Query } from '@parca/parser';
|
|
20
18
|
import { TEST_IDS, testId } from '@parca/test-utils';
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import useGrpcQuery from '../useGrpcQuery';
|
|
19
|
+
import { useUnifiedLabels } from '../contexts/UnifiedLabelsContext';
|
|
20
|
+
import { useQueryState } from '../hooks/useQueryState';
|
|
24
21
|
import SuggestionsList, { Suggestion, Suggestions } from './SuggestionsList';
|
|
25
|
-
|
|
26
|
-
const metadata = useGrpcMetadata();
|
|
27
|
-
const { data, isLoading, error, refetch } = useGrpcQuery({
|
|
28
|
-
key: ['labelNames', profileType, match?.join(','), start, end],
|
|
29
|
-
queryFn: async (signal) => {
|
|
30
|
-
const request = { match: match !== undefined ? match : [] };
|
|
31
|
-
if (start !== undefined && end !== undefined) {
|
|
32
|
-
request.start = millisToProtoTimestamp(start);
|
|
33
|
-
request.end = millisToProtoTimestamp(end);
|
|
34
|
-
}
|
|
35
|
-
if (profileType !== undefined) {
|
|
36
|
-
request.profileType = profileType;
|
|
37
|
-
}
|
|
38
|
-
const { response } = await client.labels(request, { meta: metadata, abort: signal });
|
|
39
|
-
return response;
|
|
40
|
-
},
|
|
41
|
-
options: {
|
|
42
|
-
enabled: profileType !== undefined && profileType !== '',
|
|
43
|
-
keepPreviousData: false,
|
|
44
|
-
},
|
|
45
|
-
});
|
|
46
|
-
useEffect(() => {
|
|
47
|
-
console.log('Label names query result:', { data, error, isLoading });
|
|
48
|
-
}, [data, error, isLoading]);
|
|
49
|
-
return {
|
|
50
|
-
result: { response: data, error: error },
|
|
51
|
-
loading: isLoading,
|
|
52
|
-
refetch: async () => {
|
|
53
|
-
await refetch();
|
|
54
|
-
},
|
|
55
|
-
};
|
|
56
|
-
};
|
|
57
|
-
export const useLabelValues = (client, labelName, profileType, start, end) => {
|
|
58
|
-
const metadata = useGrpcMetadata();
|
|
59
|
-
const { data, isLoading, error, refetch } = useGrpcQuery({
|
|
60
|
-
key: ['labelValues', labelName, profileType, start, end],
|
|
61
|
-
queryFn: async (signal) => {
|
|
62
|
-
const request = { labelName, match: [], profileType };
|
|
63
|
-
if (start !== undefined && end !== undefined) {
|
|
64
|
-
request.start = millisToProtoTimestamp(start);
|
|
65
|
-
request.end = millisToProtoTimestamp(end);
|
|
66
|
-
}
|
|
67
|
-
const { response } = await client.values(request, { meta: metadata, abort: signal });
|
|
68
|
-
return sanitizeLabelValue(response.labelValues);
|
|
69
|
-
},
|
|
70
|
-
options: {
|
|
71
|
-
enabled: profileType !== undefined &&
|
|
72
|
-
profileType !== '' &&
|
|
73
|
-
labelName !== undefined &&
|
|
74
|
-
labelName !== '',
|
|
75
|
-
keepPreviousData: false,
|
|
76
|
-
},
|
|
77
|
-
});
|
|
78
|
-
console.log('Label values query result:', { data, error, isLoading, labelName });
|
|
79
|
-
return {
|
|
80
|
-
result: { response: data ?? [], error: error },
|
|
81
|
-
loading: isLoading,
|
|
82
|
-
refetch: async () => {
|
|
83
|
-
await refetch();
|
|
84
|
-
},
|
|
85
|
-
};
|
|
86
|
-
};
|
|
87
|
-
export const useFetchUtilizationLabelValues = (labelName, utilizationLabels) => {
|
|
88
|
-
const { data } = useQuery({
|
|
89
|
-
queryKey: ['utilizationLabelValues', labelName],
|
|
90
|
-
queryFn: async () => {
|
|
91
|
-
const result = await utilizationLabels?.utilizationFetchLabelValues?.(labelName);
|
|
92
|
-
return result ?? [];
|
|
93
|
-
},
|
|
94
|
-
enabled: utilizationLabels?.utilizationFetchLabelValues != null && labelName !== '',
|
|
95
|
-
});
|
|
96
|
-
return data ?? [];
|
|
97
|
-
};
|
|
98
|
-
const MatchersInput = ({ setMatchersString, runQuery, currentQuery, }) => {
|
|
22
|
+
const MatchersInput = () => {
|
|
99
23
|
const inputRef = useRef(null);
|
|
100
24
|
const [focusedInput, setFocusedInput] = useState(false);
|
|
101
25
|
const [lastCompleted, setLastCompleted] = useState(new Suggestion('', '', ''));
|
|
102
|
-
const { labelNames, labelValues, labelNameMappings, isLabelNamesLoading, isLabelValuesLoading, currentLabelName, setCurrentLabelName, shouldHandlePrefixes, refetchLabelValues, refetchLabelNames, } =
|
|
103
|
-
const
|
|
26
|
+
const { labelNames, labelValues, labelNameMappingsForMatchersInput: labelNameMappings, isLabelNamesLoading, isLabelValuesLoading, currentLabelName, setCurrentLabelName, shouldHandlePrefixes, refetchLabelValues, refetchLabelNames, suffix, } = useUnifiedLabels();
|
|
27
|
+
const { setDraftMatchers, commitDraft, draftParsedQuery } = useQueryState({ suffix });
|
|
28
|
+
const value = draftParsedQuery != null ? draftParsedQuery.matchersString() : '';
|
|
104
29
|
const suggestionSections = useMemo(() => {
|
|
105
30
|
const suggestionSections = new Suggestions();
|
|
106
|
-
Query.suggest(`${
|
|
31
|
+
Query.suggest(`${draftParsedQuery?.profileName()}{${value}`).forEach(function (s) {
|
|
107
32
|
// Skip suggestions that we just completed. This really only works,
|
|
108
33
|
// because we know the language is not repetitive. For a language that
|
|
109
34
|
// has a repeating word, this would not work.
|
|
@@ -166,7 +91,7 @@ const MatchersInput = ({ setMatchersString, runQuery, currentQuery, }) => {
|
|
|
166
91
|
});
|
|
167
92
|
return suggestionSections;
|
|
168
93
|
}, [
|
|
169
|
-
|
|
94
|
+
draftParsedQuery,
|
|
170
95
|
lastCompleted,
|
|
171
96
|
labelNames,
|
|
172
97
|
labelValues,
|
|
@@ -179,7 +104,7 @@ const MatchersInput = ({ setMatchersString, runQuery, currentQuery, }) => {
|
|
|
179
104
|
const resetLastCompleted = () => setLastCompleted(new Suggestion('', '', ''));
|
|
180
105
|
const onChange = (e) => {
|
|
181
106
|
const newValue = e.target.value;
|
|
182
|
-
|
|
107
|
+
setDraftMatchers(newValue);
|
|
183
108
|
resetLastCompleted();
|
|
184
109
|
};
|
|
185
110
|
const complete = (suggestion) => {
|
|
@@ -197,7 +122,7 @@ const MatchersInput = ({ setMatchersString, runQuery, currentQuery, }) => {
|
|
|
197
122
|
const applySuggestion = (suggestion) => {
|
|
198
123
|
const newValue = complete(suggestion);
|
|
199
124
|
setLastCompleted(suggestion);
|
|
200
|
-
|
|
125
|
+
setDraftMatchers(newValue);
|
|
201
126
|
if (inputRef.current !== null) {
|
|
202
127
|
inputRef.current.value = newValue;
|
|
203
128
|
inputRef.current.focus();
|
|
@@ -209,13 +134,11 @@ const MatchersInput = ({ setMatchersString, runQuery, currentQuery, }) => {
|
|
|
209
134
|
const unfocus = () => {
|
|
210
135
|
setFocusedInput(false);
|
|
211
136
|
};
|
|
212
|
-
const profileSelected =
|
|
137
|
+
const profileSelected = draftParsedQuery?.profileName() === '';
|
|
213
138
|
return (_jsxs("div", { className: "w-full min-w-[300px] flex-1 font-mono relative", ...testId(TEST_IDS.MATCHERS_INPUT_CONTAINER), children: [_jsx(TextareaAutosize, { ref: inputRef, className: cx('block h-[38px] w-full flex-1 rounded-md border bg-white px-2 py-2 text-sm shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 dark:border-gray-600 dark:bg-gray-900', profileSelected && 'cursor-not-allowed'), placeholder: profileSelected
|
|
214
139
|
? 'Select a profile first to enter a filter...'
|
|
215
140
|
: 'filter profiles... eg. node="test"', onChange: onChange, value: value, onBlur: unfocus, ...testId(TEST_IDS.MATCHERS_TEXTAREA), onFocus: focus, disabled: profileSelected, title: profileSelected
|
|
216
141
|
? 'Select a profile first to enter a filter...'
|
|
217
|
-
: 'filter profiles... eg. node="test"', id: "matchers-input" }), _jsx(SuggestionsList, { isLabelNamesLoading: isLabelNamesLoading, suggestions: suggestionSections, applySuggestion: applySuggestion, inputRef: inputRef.current, runQuery:
|
|
142
|
+
: 'filter profiles... eg. node="test"', id: "matchers-input" }), _jsx(SuggestionsList, { isLabelNamesLoading: isLabelNamesLoading, suggestions: suggestionSections, applySuggestion: applySuggestion, inputRef: inputRef.current, runQuery: commitDraft, focusedInput: focusedInput, isLabelValuesLoading: isLabelValuesLoading && lastCompleted.type === 'literal' && lastCompleted.value !== ',', shouldTrimPrefix: shouldHandlePrefixes, refetchLabelValues: refetchLabelValues, refetchLabelNames: refetchLabelNames })] }));
|
|
218
143
|
};
|
|
219
|
-
export default
|
|
220
|
-
return (_jsx(LabelsProvider, { queryClient: props.queryClient, profileType: props.profileType, start: props.start, end: props.end, children: _jsx(MatchersInput, { ...props }) }));
|
|
221
|
-
}
|
|
144
|
+
export default MatchersInput;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/MetricsGraph/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAgE,MAAM,OAAO,CAAC;AAOrF,OAAO,EAAC,aAAa,EAAkB,MAAM,mBAAmB,CAAC;AAMjE,OAA2B,EACzB,eAAe,EACf,wBAAwB,EACxB,kBAAkB,EACnB,MAAM,sBAAsB,CAAC;AAI9B,UAAU,KAAK;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,CAAC,YAAY,EAAE,WAAW,KAAK,IAAI,CAAC;IACnD,YAAY,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACnC,gBAAgB,CAAC,EAAE,wBAAwB,EAAE,CAAC;IAC9C,oBAAoB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;CACrF;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAChC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,QAAA,MAAM,YAAY,GAAI,uJAcnB,KAAK,KAAG,GAAG,CAAC,OA+Bd,CAAC;AAEF,eAAe,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/MetricsGraph/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAgE,MAAM,OAAO,CAAC;AAOrF,OAAO,EAAC,aAAa,EAAkB,MAAM,mBAAmB,CAAC;AAMjE,OAA2B,EACzB,eAAe,EACf,wBAAwB,EACxB,kBAAkB,EACnB,MAAM,sBAAsB,CAAC;AAI9B,UAAU,KAAK;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,CAAC,YAAY,EAAE,WAAW,KAAK,IAAI,CAAC;IACnD,YAAY,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACnC,gBAAgB,CAAC,EAAE,wBAAwB,EAAE,CAAC;IAC9C,oBAAoB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;CACrF;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAChC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,QAAA,MAAM,YAAY,GAAI,uJAcnB,KAAK,KAAG,GAAG,CAAC,OA+Bd,CAAC;AAEF,eAAe,YAAY,CAAC;AAE5B,YAAY,EAAC,wBAAwB,EAAE,eAAe,EAAE,kBAAkB,EAAC,CAAC;AAE5E,eAAO,MAAM,UAAU,GAAI,OAAO,MAAM,KAAG,MAAM,GAAG,IAKnD,CAAC;AAKF,eAAO,MAAM,eAAe,GAAI,uJAc7B,KAAK,KAAG,GAAG,CAAC,OAgcd,CAAC"}
|
|
@@ -90,6 +90,12 @@ export const RawMetricsGraph = ({ data, from, to, onSampleClick, setTimeRange, y
|
|
|
90
90
|
return null;
|
|
91
91
|
}
|
|
92
92
|
const closestPointPerSeries = series.map(function (s) {
|
|
93
|
+
if (s.values.length === 0) {
|
|
94
|
+
return {
|
|
95
|
+
pointIndex: undefined,
|
|
96
|
+
distance: Infinity,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
93
99
|
const distances = s.values.map(d => {
|
|
94
100
|
const x = xScale(d[0]) + margin / 2; // d[0] is timestamp_ms
|
|
95
101
|
const y = yScale(d[1]) - margin / 3; // d[1] is value
|
|
@@ -97,14 +103,20 @@ export const RawMetricsGraph = ({ data, from, to, onSampleClick, setTimeRange, y
|
|
|
97
103
|
return Math.sqrt(Math.pow(pos[0] - x, 2) + Math.pow(pos[1] - y, 2));
|
|
98
104
|
});
|
|
99
105
|
const pointIndex = d3.minIndex(distances);
|
|
100
|
-
const minDistance = distances[pointIndex];
|
|
106
|
+
const minDistance = pointIndex != null ? distances[pointIndex] : Infinity;
|
|
101
107
|
return {
|
|
102
108
|
pointIndex,
|
|
103
109
|
distance: minDistance,
|
|
104
110
|
};
|
|
105
111
|
});
|
|
106
112
|
const closestSeriesIndex = d3.minIndex(closestPointPerSeries, s => s.distance);
|
|
113
|
+
if (closestSeriesIndex == null || closestPointPerSeries[closestSeriesIndex] == null) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
107
116
|
const pointIndex = closestPointPerSeries[closestSeriesIndex].pointIndex;
|
|
117
|
+
if (pointIndex == null) {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
108
120
|
return {
|
|
109
121
|
seriesIndex: closestSeriesIndex,
|
|
110
122
|
pointIndex,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileMetricsGraph/index.tsx"],"names":[],"mappings":"AAkBA,OAAO,EACL,KAAK,EAGL,kBAAkB,EACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,aAAa,EAId,MAAM,mBAAmB,CAAC;AAK3B,OAAO,EAAyB,gBAAgB,EAAC,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileMetricsGraph/index.tsx"],"names":[],"mappings":"AAkBA,OAAO,EACL,KAAK,EAGL,kBAAkB,EACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,aAAa,EAId,MAAM,mBAAmB,CAAC;AAK3B,OAAO,EAAyB,gBAAgB,EAAC,MAAM,IAAI,CAAC;AA6G5D,UAAU,6BAA6B;IACrC,OAAO,EAAE,MAAM,CAAC;CACjB;AAaD,eAAO,MAAM,wBAAwB,GAAI,aAAW,6BAA6B,KAAG,GAAG,CAAC,OAMvF,CAAC;AAEF,UAAU,wBAAwB;IAChC,WAAW,EAAE,kBAAkB,CAAC;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,YAAY,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC7C,eAAe,EAAE,CACf,MAAM,EAAE;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,GAAG,KAAK,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,CAAC,KACvE,IAAI,CAAC;IACV,YAAY,EAAE,CACZ,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,KAAK,EAAE,EACf,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,KACb,IAAI,CAAC;IACV,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,QAAA,MAAM,mBAAmB,GAAI,qHAW1B,wBAAwB,KAAG,GAAG,CAAC,OAsVjC,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
|
|
@@ -22,14 +22,8 @@ import { MergedProfileSelection } from '..';
|
|
|
22
22
|
import MetricsGraph from '../MetricsGraph';
|
|
23
23
|
import { useMetricsGraphDimensions } from '../MetricsGraph/useMetricsGraphDimensions';
|
|
24
24
|
import { useQueryRange } from './hooks/useQueryRange';
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
return label.replace('attributes.', '').replace('attributes_resource.', '');
|
|
28
|
-
}
|
|
29
|
-
return label;
|
|
30
|
-
};
|
|
31
|
-
const createProfileContextMenuItems = (addLabelMatcher, data, // The original MetricsSeriesPb[] data
|
|
32
|
-
utilizationMetrics = false) => {
|
|
25
|
+
const createProfileContextMenuItems = (addLabelMatcher, data // The original MetricsSeriesPb[] data
|
|
26
|
+
) => {
|
|
33
27
|
return [
|
|
34
28
|
{
|
|
35
29
|
id: 'focus-on-single-series',
|
|
@@ -76,7 +70,7 @@ utilizationMetrics = false) => {
|
|
|
76
70
|
}
|
|
77
71
|
return labels.map((label) => ({
|
|
78
72
|
id: `add-label-${label.name}`,
|
|
79
|
-
label: (_jsx("div", { className: "mr-3 inline-block rounded-lg bg-gray-200 px-2 py-1 text-xs font-bold text-gray-700 dark:bg-gray-700 dark:text-gray-300", children: `${
|
|
73
|
+
label: (_jsx("div", { className: "mr-3 inline-block rounded-lg bg-gray-200 px-2 py-1 text-xs font-bold text-gray-700 dark:bg-gray-700 dark:text-gray-300", children: `${label.name}="${label.value}"` })),
|
|
80
74
|
onClick: () => {
|
|
81
75
|
addLabelMatcher({
|
|
82
76
|
key: label.name,
|
|
@@ -274,32 +268,15 @@ const ProfileMetricsGraph = ({ queryClient, queryExpression, profile, from, to,
|
|
|
274
268
|
const labels = originalSeriesData.labelset?.labels ?? [];
|
|
275
269
|
const nameLabel = labels.find(e => e.name === '__name__');
|
|
276
270
|
const highlightedNameLabel = nameLabel ?? { name: '', value: '' };
|
|
277
|
-
// Calculate attributes maps for utilization metrics
|
|
278
|
-
const utilizationMetrics = false; // This is for profile metrics, not utilization
|
|
279
|
-
const attributesMap = labels
|
|
280
|
-
.filter(label => label.name.startsWith('attributes.') &&
|
|
281
|
-
!label.name.startsWith('attributes_resource.'))
|
|
282
|
-
.reduce((acc, label) => {
|
|
283
|
-
const key = label.name.replace('attributes.', '');
|
|
284
|
-
acc[key] = label.value;
|
|
285
|
-
return acc;
|
|
286
|
-
}, {});
|
|
287
|
-
const attributesResourceMap = labels
|
|
288
|
-
.filter(label => label.name.startsWith('attributes_resource.'))
|
|
289
|
-
.reduce((acc, label) => {
|
|
290
|
-
const key = label.name.replace('attributes_resource.', '');
|
|
291
|
-
acc[key] = label.value;
|
|
292
|
-
return acc;
|
|
293
|
-
}, {});
|
|
294
271
|
const isDeltaType = profile !== null
|
|
295
272
|
? profile?.query.profType.delta
|
|
296
273
|
: false;
|
|
297
274
|
return (_jsx("div", { className: "flex flex-row", children: _jsxs("div", { className: "ml-2 mr-6", children: [_jsx("span", { className: "font-semibold", children: highlightedNameLabel.value }), _jsx("span", { className: "my-2 block text-gray-700 dark:text-gray-300", children: _jsx("table", { className: "table-auto", children: _jsxs("tbody", { children: [isDeltaType ? (_jsxs(_Fragment, { children: [_jsxs("tr", { children: [_jsx("td", { className: "w-1/4 pr-3", children: "Per\u00A0Second" }), _jsx("td", { className: "w-3/4", children: valueFormatter(originalPoint.valuePerSecond, sampleUnit === 'nanoseconds' && sampleType === 'cpu'
|
|
298
275
|
? 'CPU Cores'
|
|
299
276
|
: sampleUnit, 5) })] }), _jsxs("tr", { children: [_jsx("td", { className: "w-1/4", children: "Total" }), _jsx("td", { className: "w-3/4", children: valueFormatter(originalPoint.value ?? 0, sampleUnit, 2) })] })] })) : (_jsxs("tr", { children: [_jsx("td", { className: "w-1/4", children: "Value" }), _jsx("td", { className: "w-3/4", children: valueFormatter(originalPoint.valuePerSecond, sampleUnit, 5) })] })), originalPoint.duration != null &&
|
|
300
|
-
Number(originalPoint.duration) > 0 && (_jsxs("tr", { children: [_jsx("td", { className: "w-1/4", children: "Duration" }), _jsx("td", { className: "w-3/4", children: valueFormatter(Number(originalPoint.duration.toString()), 'nanoseconds', 2) })] })), _jsxs("tr", { children: [_jsx("td", { className: "w-1/4", children: "At" }), _jsx("td", { className: "w-3/4", children: formatDate(new Date(timestampMs), timePattern(timezone), timezone) })] })] }) }) }), _jsx("span", { className: "my-2 block text-gray-500", children:
|
|
301
|
-
|
|
302
|
-
|
|
277
|
+
Number(originalPoint.duration) > 0 && (_jsxs("tr", { children: [_jsx("td", { className: "w-1/4", children: "Duration" }), _jsx("td", { className: "w-3/4", children: valueFormatter(Number(originalPoint.duration.toString()), 'nanoseconds', 2) })] })), _jsxs("tr", { children: [_jsx("td", { className: "w-1/4", children: "At" }), _jsx("td", { className: "w-3/4", children: formatDate(new Date(timestampMs), timePattern(timezone), timezone) })] })] }) }) }), _jsx("span", { className: "my-2 block text-gray-500", children: labels
|
|
278
|
+
.filter((label) => label.name !== '__name__')
|
|
279
|
+
.map((label) => (_jsx("div", { className: "mr-3 inline-block rounded-lg bg-gray-200 px-2 py-1 text-xs font-bold text-gray-700 dark:bg-gray-700 dark:text-gray-400", ...testId(TEST_IDS.TOOLTIP_LABEL), children: _jsx(TextWithTooltip, { text: `${label.name}="${label.value}"`, maxTextLength: 37, id: `tooltip-${label.name}` }) }, label.name))) }), _jsxs("div", { className: "flex w-full items-center gap-1 text-xs text-gray-500", children: [_jsx(Icon, { icon: "iconoir:mouse-button-right" }), _jsx("div", { children: "Right click to add labels to query." })] })] }) }));
|
|
303
280
|
}
|
|
304
281
|
}
|
|
305
282
|
return null;
|
|
@@ -2,7 +2,7 @@ import { QueryServiceClient } from '@parca/client';
|
|
|
2
2
|
import { DateTimeRange } from '@parca/components';
|
|
3
3
|
import { Query } from '@parca/parser';
|
|
4
4
|
import { ProfileSelection } from '..';
|
|
5
|
-
import { QuerySelection
|
|
5
|
+
import { QuerySelection } from './index';
|
|
6
6
|
interface MetricsGraphSectionProps {
|
|
7
7
|
showMetricsGraph: boolean;
|
|
8
8
|
setDisplayHideMetricsGraphButton?: (show: boolean) => void;
|
|
@@ -18,16 +18,14 @@ interface MetricsGraphSectionProps {
|
|
|
18
18
|
selectQuery: (query: QuerySelection) => void;
|
|
19
19
|
setProfileSelection: (mergeFrom: bigint, mergeTo: bigint, query: Query) => void;
|
|
20
20
|
query: Query;
|
|
21
|
-
setNewQueryExpression: (queryExpression: string
|
|
21
|
+
setNewQueryExpression: (queryExpression: string) => void;
|
|
22
22
|
setQueryExpression: (updateTs?: boolean) => void;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
utilizationMetricsLoading?: boolean;
|
|
29
|
-
onUtilizationSeriesSelect?: (name: string, seriesIndex: number) => void;
|
|
23
|
+
commitDraft: (refreshedTimeRange?: {
|
|
24
|
+
from: number;
|
|
25
|
+
to: number;
|
|
26
|
+
timeSelection: string;
|
|
27
|
+
}, expression?: string) => void;
|
|
30
28
|
}
|
|
31
|
-
export declare function MetricsGraphSection({ showMetricsGraph, setDisplayHideMetricsGraphButton, heightStyle, querySelection, profileSelection, comparing, sumBy, defaultSumByLoading, queryClient, queryExpressionString, setTimeRangeSelection, selectQuery, setProfileSelection, query, setNewQueryExpression,
|
|
29
|
+
export declare function MetricsGraphSection({ showMetricsGraph, setDisplayHideMetricsGraphButton, heightStyle, querySelection, profileSelection, comparing, sumBy, defaultSumByLoading, queryClient, queryExpressionString, setTimeRangeSelection, selectQuery, setProfileSelection, query, setNewQueryExpression, commitDraft, }: MetricsGraphSectionProps): JSX.Element;
|
|
32
30
|
export {};
|
|
33
31
|
//# sourceMappingURL=MetricsGraphSection.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MetricsGraphSection.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/MetricsGraphSection.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAQ,kBAAkB,EAAC,MAAM,eAAe,CAAC;AACxD,OAAO,EAAC,aAAa,EAAmB,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAEpC,OAAO,EAAC,gBAAgB,EAAC,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"MetricsGraphSection.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/MetricsGraphSection.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAQ,kBAAkB,EAAC,MAAM,eAAe,CAAC;AACxD,OAAO,EAAC,aAAa,EAAmB,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAEpC,OAAO,EAAC,gBAAgB,EAAC,MAAM,IAAI,CAAC;AAGpC,OAAO,EAAC,cAAc,EAAC,MAAM,SAAS,CAAC;AAEvC,UAAU,wBAAwB;IAChC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gCAAgC,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,cAAc,CAAC;IAC/B,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACvB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,WAAW,EAAE,kBAAkB,CAAC;IAChC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,qBAAqB,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACtD,WAAW,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC7C,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAChF,KAAK,EAAE,KAAK,CAAC;IACb,qBAAqB,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,IAAI,CAAC;IACzD,kBAAkB,EAAE,CAAC,QAAQ,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD,WAAW,EAAE,CACX,kBAAkB,CAAC,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAC,EACtE,UAAU,CAAC,EAAE,MAAM,KAChB,IAAI,CAAC;CACX;AAED,wBAAgB,mBAAmB,CAAC,EAClC,gBAAgB,EAChB,gCAAgC,EAChC,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,SAAS,EACT,KAAK,EACL,mBAAmB,EACnB,WAAW,EACX,qBAAqB,EACrB,qBAAqB,EACrB,WAAW,EACX,mBAAmB,EACnB,KAAK,EACL,qBAAqB,EACrB,WAAW,GACZ,EAAE,wBAAwB,GAAG,GAAG,CAAC,OAAO,CA+HxC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } 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.
|
|
@@ -14,11 +14,9 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
14
14
|
import cx from 'classnames';
|
|
15
15
|
import { useURLStateBatch } from '@parca/components';
|
|
16
16
|
import { Query } from '@parca/parser';
|
|
17
|
-
import UtilizationMetricsGraph from '../MetricsGraph/UtilizationMetrics';
|
|
18
|
-
import AreaChart from '../MetricsGraph/UtilizationMetrics/Throughput';
|
|
19
17
|
import ProfileMetricsGraph, { ProfileMetricsEmptyState } from '../ProfileMetricsGraph';
|
|
20
18
|
import { useResetStateOnSeriesChange } from '../ProfileView/hooks/useResetStateOnSeriesChange';
|
|
21
|
-
export function MetricsGraphSection({ showMetricsGraph, setDisplayHideMetricsGraphButton, heightStyle, querySelection, profileSelection, comparing, sumBy, defaultSumByLoading, queryClient, queryExpressionString, setTimeRangeSelection, selectQuery, setProfileSelection, query, setNewQueryExpression,
|
|
19
|
+
export function MetricsGraphSection({ showMetricsGraph, setDisplayHideMetricsGraphButton, heightStyle, querySelection, profileSelection, comparing, sumBy, defaultSumByLoading, queryClient, queryExpressionString, setTimeRangeSelection, selectQuery, setProfileSelection, query, setNewQueryExpression, commitDraft, }) {
|
|
22
20
|
const resetStateOnSeriesChange = useResetStateOnSeriesChange();
|
|
23
21
|
const batchUpdates = useURLStateBatch();
|
|
24
22
|
const handleTimeRangeChange = (range) => {
|
|
@@ -62,9 +60,11 @@ export function MetricsGraphSection({ showMetricsGraph, setDisplayHideMetricsGra
|
|
|
62
60
|
newQuery = query;
|
|
63
61
|
}
|
|
64
62
|
if (hasChanged) {
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
// Immediately apply the filter when adding label matchers from the graph
|
|
64
|
+
batchUpdates(() => {
|
|
65
|
+
setNewQueryExpression(newQuery.toString());
|
|
66
|
+
commitDraft(undefined, newQuery.toString());
|
|
67
|
+
});
|
|
68
68
|
}
|
|
69
69
|
};
|
|
70
70
|
const handlePointClick = (timestamp, labels, queryExpression, duration) => {
|
|
@@ -82,40 +82,7 @@ export function MetricsGraphSection({ showMetricsGraph, setDisplayHideMetricsGra
|
|
|
82
82
|
setProfileSelection(mergeFrom, mergeTo, query);
|
|
83
83
|
});
|
|
84
84
|
};
|
|
85
|
-
const UtilizationGraphToShow = ({ utilizationMetrics, }) => {
|
|
86
|
-
const throughputMetrics = utilizationMetrics.filter(metric => metric.name === 'gpu_pcie_throughput_transmit_bytes' ||
|
|
87
|
-
metric.name === 'gpu_pcie_throughput_receive_bytes');
|
|
88
|
-
const transmitData = throughputMetrics.find(metric => metric.name === 'gpu_pcie_throughput_transmit_bytes')
|
|
89
|
-
?.data ?? [];
|
|
90
|
-
const receiveData = throughputMetrics.find(metric => metric.name === 'gpu_pcie_throughput_receive_bytes')?.data ??
|
|
91
|
-
[];
|
|
92
|
-
if (utilizationMetrics.length === 0) {
|
|
93
|
-
return _jsx(_Fragment, {});
|
|
94
|
-
}
|
|
95
|
-
return (_jsxs("div", { children: [utilizationMetrics.map(({ name, humanReadableName, data }) => {
|
|
96
|
-
if (name !== 'gpu_pcie_throughput_transmit_bytes' &&
|
|
97
|
-
name !== 'gpu_pcie_throughput_receive_bytes') {
|
|
98
|
-
return (_jsx(UtilizationMetricsGraph, { data: data, setTimeRange: handleTimeRangeChange, utilizationMetricsLoading: utilizationMetricsLoading, humanReadableName: humanReadableName, from: querySelection.from, to: querySelection.to, yAxisUnit: "percentage", addLabelMatcher: addLabelMatcher, onSeriesClick: seriesIndex => {
|
|
99
|
-
// For generic UtilizationMetrics, just pass the series index
|
|
100
|
-
if (onUtilizationSeriesSelect != null) {
|
|
101
|
-
onUtilizationSeriesSelect(name, seriesIndex);
|
|
102
|
-
}
|
|
103
|
-
} }, name));
|
|
104
|
-
}
|
|
105
|
-
return null;
|
|
106
|
-
}), throughputMetrics.length > 0 && (_jsx(AreaChart, { transmitData: transmitData, receiveData: receiveData, addLabelMatcher: addLabelMatcher, setTimeRange: handleTimeRangeChange, name: throughputMetrics[0].name, humanReadableName: throughputMetrics[0].humanReadableName, from: querySelection.from, to: querySelection.to, utilizationMetricsLoading: utilizationMetricsLoading, selectedSeries: undefined, onSeriesClick: (_, seriesIndex) => {
|
|
107
|
-
// For throughput metrics, just pass the series index
|
|
108
|
-
if (onUtilizationSeriesSelect != null) {
|
|
109
|
-
let name = 'gpu_pcie_throughput_transmit_bytes';
|
|
110
|
-
if (seriesIndex > transmitData.length - 1) {
|
|
111
|
-
name = 'gpu_pcie_throughput_receive_bytes';
|
|
112
|
-
seriesIndex -= transmitData.length;
|
|
113
|
-
}
|
|
114
|
-
onUtilizationSeriesSelect(name, seriesIndex);
|
|
115
|
-
}
|
|
116
|
-
} }))] }));
|
|
117
|
-
};
|
|
118
85
|
return (_jsxs("div", { className: cx('relative', { 'py-4': !showMetricsGraph }), children: [setDisplayHideMetricsGraphButton != null ? (_jsxs("button", { onClick: () => setDisplayHideMetricsGraphButton(!showMetricsGraph), className: cx('hidden px-3 py-1 text-sm font-medium text-gray-700 dark:text-gray-200 bg-gray-100 rounded-md hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:bg-gray-900 z-[5]', showMetricsGraph && 'absolute right-0 bottom-3 !flex', !showMetricsGraph && 'relative !flex ml-auto'), children: [showMetricsGraph ? 'Hide' : 'Show', " Metrics Graph"] })) : null, showMetricsGraph && (_jsx(_Fragment, { children: _jsx("div", { style: { height: heightStyle }, children: (querySelection.expression !== '' || defaultSumByLoading) &&
|
|
119
86
|
querySelection.from !== undefined &&
|
|
120
|
-
querySelection.to !== undefined ? (_jsx(_Fragment, { children:
|
|
87
|
+
querySelection.to !== undefined ? (_jsx(_Fragment, { children: _jsx(ProfileMetricsGraph, { queryClient: queryClient, queryExpression: querySelection.expression, from: querySelection.from, to: querySelection.to, profile: profileSelection, comparing: comparing, sumBy: querySelection.sumBy ?? sumBy ?? [], sumByLoading: defaultSumByLoading, setTimeRange: handleTimeRangeChange, addLabelMatcher: addLabelMatcher, onPointClick: handlePointClick }) })) : (profileSelection === null && (_jsx("div", { className: "p-2", children: _jsx(ProfileMetricsEmptyState, { message: "Please select a profile type and click 'Search' to begin." }) }))) }) }))] }));
|
|
121
88
|
}
|
|
@@ -15,28 +15,8 @@ interface ProfileSelectorFeatures {
|
|
|
15
15
|
showMetricsGraph: boolean;
|
|
16
16
|
showSumBySelector?: boolean;
|
|
17
17
|
showProfileTypeSelector?: boolean;
|
|
18
|
-
disableExplorativeQuerying?: boolean;
|
|
19
18
|
disableProfileTypesDropdown?: boolean;
|
|
20
19
|
}
|
|
21
|
-
export interface UtilizationMetrics {
|
|
22
|
-
isSelected: boolean;
|
|
23
|
-
labelset: {
|
|
24
|
-
labels: Array<{
|
|
25
|
-
name: string;
|
|
26
|
-
value: string;
|
|
27
|
-
}>;
|
|
28
|
-
};
|
|
29
|
-
samples: Array<{
|
|
30
|
-
timestamp: number;
|
|
31
|
-
value: number;
|
|
32
|
-
}>;
|
|
33
|
-
}
|
|
34
|
-
export interface UtilizationLabels {
|
|
35
|
-
utilizationLabelNames?: string[];
|
|
36
|
-
utilizationFetchLabelValues?: (key: string) => Promise<string[]>;
|
|
37
|
-
utilizationLabelValues?: string[];
|
|
38
|
-
utilizationLabelNamesLoading?: boolean;
|
|
39
|
-
}
|
|
40
20
|
interface ProfileSelectorProps extends ProfileSelectorFeatures {
|
|
41
21
|
queryClient: QueryServiceClient;
|
|
42
22
|
closeProfile: () => void;
|
|
@@ -45,14 +25,6 @@ interface ProfileSelectorProps extends ProfileSelectorFeatures {
|
|
|
45
25
|
navigateTo: NavigateFunction;
|
|
46
26
|
setDisplayHideMetricsGraphButton?: Dispatch<SetStateAction<boolean>>;
|
|
47
27
|
suffix?: '_a' | '_b';
|
|
48
|
-
utilizationMetrics?: Array<{
|
|
49
|
-
name: string;
|
|
50
|
-
humanReadableName: string;
|
|
51
|
-
data: UtilizationMetrics[];
|
|
52
|
-
}>;
|
|
53
|
-
utilizationMetricsLoading?: boolean;
|
|
54
|
-
utilizationLabels?: UtilizationLabels;
|
|
55
|
-
onUtilizationSeriesSelect?: (name: string, seriesIndex: number) => void;
|
|
56
28
|
onSearchHook?: () => void;
|
|
57
29
|
}
|
|
58
30
|
export interface IProfileTypesResult {
|
|
@@ -61,6 +33,6 @@ export interface IProfileTypesResult {
|
|
|
61
33
|
error?: RpcError;
|
|
62
34
|
}
|
|
63
35
|
export declare const useProfileTypes: (client: QueryServiceClient, start?: number, end?: number) => IProfileTypesResult;
|
|
64
|
-
declare const ProfileSelector: ({ queryClient, closeProfile, enforcedProfileName, comparing, navigateTo, showMetricsGraph, showSumBySelector, showProfileTypeSelector,
|
|
36
|
+
declare const ProfileSelector: ({ queryClient, closeProfile, enforcedProfileName, comparing, navigateTo, showMetricsGraph, showSumBySelector, showProfileTypeSelector, setDisplayHideMetricsGraphButton, suffix, onSearchHook, }: ProfileSelectorProps) => JSX.Element;
|
|
65
37
|
export default ProfileSelector;
|
|
66
38
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,QAAQ,EAAE,cAAc,EAAoD,MAAM,OAAO,CAAC;AAElG,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAElD,OAAO,EAAsB,oBAAoB,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAY5F,OAAO,EAAyB,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,QAAQ,EAAE,cAAc,EAAoD,MAAM,OAAO,CAAC;AAElG,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAElD,OAAO,EAAsB,oBAAoB,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAY5F,OAAO,EAAyB,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAY/E,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,uBAAuB;IAC/B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC;AAED,UAAU,oBAAqB,SAAQ,uBAAuB;IAC5D,WAAW,EAAE,kBAAkB,CAAC;IAChC,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,gCAAgC,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IACrE,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,KAAK,CAAC,EAAE,QAAQ,CAAC;CAClB;AAED,eAAO,MAAM,eAAe,GAC1B,QAAQ,kBAAkB,EAC1B,QAAQ,MAAM,EACd,MAAM,MAAM,KACX,mBAsBF,CAAC;AAEF,QAAA,MAAM,eAAe,GAAI,kMAYtB,oBAAoB,KAAG,GAAG,CAAC,OAwO7B,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -17,13 +17,14 @@ import { CloseIcon } from '@parca/icons';
|
|
|
17
17
|
import { Query } from '@parca/parser';
|
|
18
18
|
import { TEST_IDS, testId } from '@parca/test-utils';
|
|
19
19
|
import { millisToProtoTimestamp } from '@parca/utilities';
|
|
20
|
-
import { useLabelNames } from '../MatchersInput/index';
|
|
21
20
|
import { useMetricsGraphDimensions } from '../MetricsGraph/useMetricsGraphDimensions';
|
|
22
|
-
import {
|
|
21
|
+
import { QueryControls } from '../QueryControls';
|
|
22
|
+
import { LabelsQueryProvider, useLabelsQueryProvider } from '../contexts/LabelsQueryProvider';
|
|
23
|
+
import { UnifiedLabelsProvider } from '../contexts/UnifiedLabelsContext';
|
|
24
|
+
import { useLabelNames } from '../hooks/useLabels';
|
|
23
25
|
import { useQueryState } from '../hooks/useQueryState';
|
|
24
26
|
import useGrpcQuery from '../useGrpcQuery';
|
|
25
27
|
import { MetricsGraphSection } from './MetricsGraphSection';
|
|
26
|
-
import { QueryControls } from './QueryControls';
|
|
27
28
|
import { useAutoQuerySelector } from './useAutoQuerySelector';
|
|
28
29
|
export const useProfileTypes = (client, start, end) => {
|
|
29
30
|
const metadata = useGrpcMetadata();
|
|
@@ -45,13 +46,13 @@ export const useProfileTypes = (client, start, end) => {
|
|
|
45
46
|
});
|
|
46
47
|
return { loading: isLoading, data, error: error };
|
|
47
48
|
};
|
|
48
|
-
const ProfileSelector = ({ queryClient, closeProfile, enforcedProfileName, comparing, navigateTo, showMetricsGraph = true, showSumBySelector = true, showProfileTypeSelector = true,
|
|
49
|
-
const { heightStyle } = useMetricsGraphDimensions(comparing,
|
|
49
|
+
const ProfileSelector = ({ queryClient, closeProfile, enforcedProfileName, comparing, navigateTo, showMetricsGraph = true, showSumBySelector = true, showProfileTypeSelector = true, setDisplayHideMetricsGraphButton, suffix, onSearchHook, }) => {
|
|
50
|
+
const { heightStyle } = useMetricsGraphDimensions(comparing, false);
|
|
50
51
|
const { viewComponent } = useParcaContext();
|
|
51
52
|
const [queryBrowserMode, setQueryBrowserMode] = useURLState('query_browser_mode');
|
|
52
53
|
const batchUpdates = useURLStateBatch();
|
|
53
54
|
// Use the new useQueryState hook - reads directly from URL params
|
|
54
|
-
const { querySelection, draftSelection, setDraftExpression, setDraftTimeRange, setDraftSumBy, setDraftProfileName, setDraftMatchers, commitDraft, profileSelection, setProfileSelection, sumByLoading, } = useQueryState({ suffix });
|
|
55
|
+
const { querySelection, draftSelection, setDraftExpression, setDraftTimeRange, setDraftSumBy, setDraftProfileName, setDraftMatchers, commitDraft, profileSelection, setProfileSelection, sumByLoading, draftParsedQuery, } = useQueryState({ suffix });
|
|
55
56
|
// Use draft state for local state instead of committed state
|
|
56
57
|
const [timeRangeSelection, setTimeRangeSelection] = useState(DateTimeRange.fromRangeKey(draftSelection.timeSelection, draftSelection.from, draftSelection.to));
|
|
57
58
|
const [queryExpressionString, setQueryExpressionString] = useState(draftSelection.expression);
|
|
@@ -67,7 +68,7 @@ const ProfileSelector = ({ queryClient, closeProfile, enforcedProfileName, compa
|
|
|
67
68
|
const from = timeRangeSelection.getFromMs();
|
|
68
69
|
const to = timeRangeSelection.getToMs();
|
|
69
70
|
const { loading: profileTypesLoading, data: profileTypesData, error, } = useProfileTypes(queryClient, from, to);
|
|
70
|
-
const { result
|
|
71
|
+
const { result } = useLabelNames(queryClient, profileType.toString(), from, to);
|
|
71
72
|
const labels = useMemo(() => {
|
|
72
73
|
return result.response?.labelNames === undefined ? [] : result.response.labelNames;
|
|
73
74
|
}, [result]);
|
|
@@ -100,6 +101,7 @@ const ProfileSelector = ({ queryClient, closeProfile, enforcedProfileName, compa
|
|
|
100
101
|
const currentTo = timeRangeSelection.getToMs(true);
|
|
101
102
|
const currentRangeKey = timeRangeSelection.getRangeKey();
|
|
102
103
|
// Commit with refreshed time range
|
|
104
|
+
console.log('[draftExpression] setQueryExpression: committing with refreshed time range:', draftSelection.expression);
|
|
103
105
|
commitDraft({
|
|
104
106
|
from: currentFrom,
|
|
105
107
|
to: currentTo,
|
|
@@ -148,8 +150,10 @@ const ProfileSelector = ({ queryClient, closeProfile, enforcedProfileName, compa
|
|
|
148
150
|
queryExpressionString === '{}';
|
|
149
151
|
const queryBrowserRef = useRef(null);
|
|
150
152
|
const sumByRef = useRef(null);
|
|
151
|
-
return (
|
|
152
|
-
? 'auto'
|
|
153
|
-
: heightStyle, querySelection: querySelection, profileSelection: profileSelection, comparing: comparing, sumBy: querySelection.sumBy ?? [], defaultSumByLoading: sumByLoading, queryClient: queryClient, queryExpressionString: queryExpressionString, setTimeRangeSelection: handleTimeRangeChange, selectQuery: commitDraft, setProfileSelection: setProfileSelection, query: query, setQueryExpression: setQueryExpression, setNewQueryExpression: setDraftExpression, utilizationMetrics: utilizationMetrics, utilizationMetricsLoading: utilizationMetricsLoading, onUtilizationSeriesSelect: onUtilizationSeriesSelect })] }) }));
|
|
153
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "mb-2 flex", children: [_jsx(LabelsQueryProvider, { setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query, profileType: selectedProfileName ?? profileType.toString(), queryClient: queryClient, start: timeRangeSelection.getFromMs(), end: timeRangeSelection.getToMs(), suffix: suffix, children: _jsx(LabelsSource, { children: _jsx(QueryControls, { showProfileTypeSelector: showProfileTypeSelector, showSumBySelector: showSumBySelector, profileTypesData: profileTypesData, profileTypesLoading: profileTypesLoading, selectedProfileName: selectedProfileName, setProfileName: setProfileName, setMatchersString: setMatchersString, setQueryExpression: setQueryExpression, query: query, queryBrowserRef: queryBrowserRef, timeRangeSelection: timeRangeSelection, setTimeRangeSelection: handleTimeRangeChange, searchDisabled: searchDisabled, setQueryBrowserMode: setQueryBrowserMode, advancedModeForQueryBrowser: advancedModeForQueryBrowser, setAdvancedModeForQueryBrowser: setAdvancedModeForQueryBrowser, queryClient: queryClient, sumByRef: sumByRef, labels: labels, sumBySelection: draftSelection.sumBy ?? [], sumBySelectionLoading: sumByLoading, setUserSumBySelection: setDraftSumBy, profileType: profileType, profileTypesError: error, viewComponent: viewComponent, draftSelection: draftSelection, setDraftMatchers: setDraftMatchers, draftParsedQuery: draftParsedQuery }) }) }), comparing && (_jsx("div", { children: _jsx(IconButton, { onClick: () => closeProfile(), icon: _jsx(CloseIcon, {}), ...testId(TEST_IDS.COMPARE_CLOSE_BUTTON) }) }))] }), _jsx(MetricsGraphSection, { showMetricsGraph: showMetricsGraph, setDisplayHideMetricsGraphButton: setDisplayHideMetricsGraphButton, heightStyle: heightStyle, querySelection: querySelection, profileSelection: profileSelection, comparing: comparing, sumBy: querySelection.sumBy ?? [], defaultSumByLoading: sumByLoading, queryClient: queryClient, queryExpressionString: queryExpressionString, setTimeRangeSelection: handleTimeRangeChange, selectQuery: commitDraft, setProfileSelection: setProfileSelection, query: query, setQueryExpression: setQueryExpression, setNewQueryExpression: setDraftExpression, commitDraft: commitDraft })] }));
|
|
154
154
|
};
|
|
155
155
|
export default ProfileSelector;
|
|
156
|
+
const LabelsSource = ({ children }) => {
|
|
157
|
+
const { labelNames, labelValues, isLabelNamesLoading, isLabelValuesLoading, refetchLabelValues, refetchLabelNames, currentLabelName, setCurrentLabelName, suffix, } = useLabelsQueryProvider();
|
|
158
|
+
return (_jsx(UnifiedLabelsProvider, { labelNames: labelNames, labelValues: labelValues, isLabelNamesLoading: isLabelNamesLoading, isLabelValuesLoading: isLabelValuesLoading, refetchLabelValues: refetchLabelValues, refetchLabelNames: refetchLabelNames, currentLabelName: currentLabelName, setCurrentLabelName: setCurrentLabelName, suffix: suffix, children: children }));
|
|
159
|
+
};
|