@parca/profile 0.16.467 → 0.16.469

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.
Files changed (30) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/MatchersInput/SuggestionsList.d.ts +2 -1
  3. package/dist/MatchersInput/SuggestionsList.d.ts.map +1 -1
  4. package/dist/MatchersInput/SuggestionsList.js +6 -2
  5. package/dist/MatchersInput/index.d.ts +4 -2
  6. package/dist/MatchersInput/index.d.ts.map +1 -1
  7. package/dist/MatchersInput/index.js +51 -22
  8. package/dist/ProfileSelector/index.d.ts +7 -1
  9. package/dist/ProfileSelector/index.d.ts.map +1 -1
  10. package/dist/ProfileSelector/index.js +3 -2
  11. package/dist/SimpleMatchers/index.d.ts +4 -2
  12. package/dist/SimpleMatchers/index.d.ts.map +1 -1
  13. package/dist/SimpleMatchers/index.js +46 -32
  14. package/dist/contexts/MatchersInputLabelsContext.d.ts +25 -0
  15. package/dist/contexts/MatchersInputLabelsContext.d.ts.map +1 -0
  16. package/dist/contexts/MatchersInputLabelsContext.js +75 -0
  17. package/dist/contexts/SimpleMatchersLabelContext.d.ts +17 -0
  18. package/dist/contexts/SimpleMatchersLabelContext.d.ts.map +1 -0
  19. package/dist/contexts/SimpleMatchersLabelContext.js +45 -0
  20. package/dist/contexts/UtilizationLabelsContext.d.ts +14 -0
  21. package/dist/contexts/UtilizationLabelsContext.d.ts.map +1 -0
  22. package/dist/contexts/UtilizationLabelsContext.js +25 -0
  23. package/package.json +7 -7
  24. package/src/MatchersInput/SuggestionsList.tsx +9 -2
  25. package/src/MatchersInput/index.tsx +71 -27
  26. package/src/ProfileSelector/index.tsx +65 -54
  27. package/src/SimpleMatchers/index.tsx +65 -33
  28. package/src/contexts/MatchersInputLabelsContext.tsx +130 -0
  29. package/src/contexts/SimpleMatchersLabelContext.tsx +78 -0
  30. package/src/contexts/UtilizationLabelsContext.tsx +44 -0
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.469](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.468...@parca/profile@0.16.469) (2025-02-10)
7
+
8
+ **Note:** Version bump only for package @parca/profile
9
+
10
+ ## [0.16.468](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.467...@parca/profile@0.16.468) (2025-02-04)
11
+
12
+ **Note:** Version bump only for package @parca/profile
13
+
6
14
  ## [0.16.467](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.466...@parca/profile@0.16.467) (2025-01-22)
7
15
 
8
16
  **Note:** Version bump only for package @parca/profile
@@ -18,7 +18,8 @@ interface Props {
18
18
  focusedInput: boolean;
19
19
  isLabelNamesLoading: boolean;
20
20
  isLabelValuesLoading: boolean;
21
+ shouldTrimPrefix: boolean;
21
22
  }
22
- declare const SuggestionsList: ({ suggestions, applySuggestion, inputRef, runQuery, focusedInput, isLabelNamesLoading, isLabelValuesLoading, }: Props) => JSX.Element;
23
+ declare const SuggestionsList: ({ suggestions, applySuggestion, inputRef, runQuery, focusedInput, isLabelNamesLoading, isLabelValuesLoading, shouldTrimPrefix, }: Props) => JSX.Element;
23
24
  export default SuggestionsList;
24
25
  //# sourceMappingURL=SuggestionsList.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SuggestionsList.d.ts","sourceRoot":"","sources":["../../src/MatchersInput/SuggestionsList.tsx"],"names":[],"mappings":"AAsBA,qBAAa,UAAU;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;gBAEF,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAK3D;AAED,qBAAa,WAAW;IACtB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,UAAU,EAAE,UAAU,EAAE,CAAC;IACzB,WAAW,EAAE,UAAU,EAAE,CAAC;;CAO3B;AAED,UAAU,KAAK;IACb,WAAW,EAAE,WAAW,CAAC;IACzB,eAAe,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;IAClD,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACrC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,oBAAoB,EAAE,OAAO,CAAC;CAC/B;AAQD,QAAA,MAAM,eAAe,mHAQlB,KAAK,KAAG,GAAG,CAAC,OA6Nd,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"SuggestionsList.d.ts","sourceRoot":"","sources":["../../src/MatchersInput/SuggestionsList.tsx"],"names":[],"mappings":"AAsBA,qBAAa,UAAU;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;gBAEF,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAK3D;AAED,qBAAa,WAAW;IACtB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,UAAU,EAAE,UAAU,EAAE,CAAC;IACzB,WAAW,EAAE,UAAU,EAAE,CAAC;;CAO3B;AAED,UAAU,KAAK;IACb,WAAW,EAAE,WAAW,CAAC;IACzB,eAAe,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;IAClD,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACrC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAaD,QAAA,MAAM,eAAe,qIASlB,KAAK,KAAG,GAAG,CAAC,OA6Nd,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -34,7 +34,11 @@ const LoadingSpinner = () => {
34
34
  const { loader: Spinner } = useParcaContext();
35
35
  return _jsx("div", { className: "pt-2 pb-4", children: Spinner });
36
36
  };
37
- const SuggestionsList = ({ suggestions, applySuggestion, inputRef, runQuery, focusedInput, isLabelNamesLoading, isLabelValuesLoading, }) => {
37
+ const transformLabelsForSuggestions = (labelNames, shouldTrimPrefix = false) => {
38
+ const trimmedLabel = shouldTrimPrefix ? labelNames.split('.').pop() ?? labelNames : labelNames;
39
+ return trimmedLabel;
40
+ };
41
+ const SuggestionsList = ({ suggestions, applySuggestion, inputRef, runQuery, focusedInput, isLabelNamesLoading, isLabelValuesLoading, shouldTrimPrefix = false, }) => {
38
42
  const [popperElement, setPopperElement] = useState(null);
39
43
  const { styles, attributes } = usePopper(inputRef, popperElement, {
40
44
  placement: 'bottom-start',
@@ -132,7 +136,7 @@ const SuggestionsList = ({ suggestions, applySuggestion, inputRef, runQuery, foc
132
136
  inputRef.removeEventListener('keypress', handleKeyPress);
133
137
  };
134
138
  }, [inputRef, highlightedSuggestionIndex, suggestions, handleKeyPress, handleKeyDown]);
135
- return (_jsx(_Fragment, { children: suggestionsLength > 0 && (_jsx("div", { ref: setPopperElement, style: { ...styles.popper, marginLeft: 0 }, ...attributes.popper, className: "z-50", children: _jsx(Transition, { show: focusedInput && showSuggest, as: Fragment, leave: "transition ease-in duration-100", leaveFrom: "opacity-100", leaveTo: "opacity-0", children: _jsxs("div", { style: { width: inputRef?.offsetWidth }, className: "absolute z-10 mt-1 max-h-[400px] overflow-auto rounded-md bg-gray-50 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:bg-gray-900 sm:text-sm", children: [isLabelNamesLoading ? (_jsx(LoadingSpinner, {})) : (_jsx(_Fragment, { children: suggestions.labelNames.map((l, i) => (_jsx(SuggestionItem, { isHighlighted: highlightedSuggestionIndex === i, onHighlight: () => setHighlightedSuggestionIndex(i), onApplySuggestion: () => applySuggestionWithIndex(i), onResetHighlight: () => resetHighlight(), value: l.value }, l.value))) })), suggestions.literals.map((l, i) => (_jsx(SuggestionItem, { isHighlighted: highlightedSuggestionIndex === i + suggestions.labelNames.length, onHighlight: () => setHighlightedSuggestionIndex(i + suggestions.labelNames.length), onApplySuggestion: () => applySuggestionWithIndex(i + suggestions.labelNames.length), onResetHighlight: () => resetHighlight(), value: l.value }, l.value))), isLabelValuesLoading ? (_jsx(LoadingSpinner, {})) : (_jsx(_Fragment, { children: suggestions.labelValues.map((l, i) => (_jsx(SuggestionItem, { isHighlighted: highlightedSuggestionIndex ===
139
+ return (_jsx(_Fragment, { children: suggestionsLength > 0 && (_jsx("div", { ref: setPopperElement, style: { ...styles.popper, marginLeft: 0 }, ...attributes.popper, className: "z-50", children: _jsx(Transition, { show: focusedInput && showSuggest, as: Fragment, leave: "transition ease-in duration-100", leaveFrom: "opacity-100", leaveTo: "opacity-0", children: _jsxs("div", { style: { width: inputRef?.offsetWidth }, className: "absolute z-10 mt-1 max-h-[400px] overflow-auto rounded-md bg-gray-50 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:bg-gray-900 sm:text-sm", children: [isLabelNamesLoading ? (_jsx(LoadingSpinner, {})) : (_jsx(_Fragment, { children: suggestions.labelNames.map((l, i) => (_jsx(SuggestionItem, { isHighlighted: highlightedSuggestionIndex === i, onHighlight: () => setHighlightedSuggestionIndex(i), onApplySuggestion: () => applySuggestionWithIndex(i), onResetHighlight: () => resetHighlight(), value: transformLabelsForSuggestions(l.value, shouldTrimPrefix) }, transformLabelsForSuggestions(l.value, shouldTrimPrefix)))) })), suggestions.literals.map((l, i) => (_jsx(SuggestionItem, { isHighlighted: highlightedSuggestionIndex === i + suggestions.labelNames.length, onHighlight: () => setHighlightedSuggestionIndex(i + suggestions.labelNames.length), onApplySuggestion: () => applySuggestionWithIndex(i + suggestions.labelNames.length), onResetHighlight: () => resetHighlight(), value: l.value }, l.value))), isLabelValuesLoading ? (_jsx(LoadingSpinner, {})) : (_jsx(_Fragment, { children: suggestions.labelValues.map((l, i) => (_jsx(SuggestionItem, { isHighlighted: highlightedSuggestionIndex ===
136
140
  i + suggestions.labelNames.length + suggestions.literals.length, onHighlight: () => setHighlightedSuggestionIndex(i + suggestions.labelNames.length + suggestions.literals.length), onApplySuggestion: () => applySuggestionWithIndex(i + suggestions.labelNames.length + suggestions.literals.length), onResetHighlight: () => resetHighlight(), value: l.value }, l.value))) }))] }) }) })) }));
137
141
  };
138
142
  export default SuggestionsList;
@@ -1,5 +1,6 @@
1
1
  import { LabelsResponse, QueryServiceClient } from '@parca/client';
2
2
  import { Query } from '@parca/parser';
3
+ import { UtilizationLabels } from '../ProfileSelector';
3
4
  interface MatchersInputProps {
4
5
  queryClient: QueryServiceClient;
5
6
  setMatchersString: (arg: string) => void;
@@ -24,6 +25,7 @@ interface UseLabelValues {
24
25
  loading: boolean;
25
26
  }
26
27
  export declare const useLabelValues: (client: QueryServiceClient, labelName: string, profileType: string) => UseLabelValues;
27
- declare const MatchersInput: ({ queryClient, setMatchersString, runQuery, currentQuery, profileType, }: MatchersInputProps) => JSX.Element;
28
- export default MatchersInput;
28
+ export declare const useFetchUtilizationLabelValues: (labelName: string, utilizationLabels?: UtilizationLabels) => string[];
29
+ export default function MatchersInputWithProvider(props: MatchersInputProps): JSX.Element;
30
+ export {};
29
31
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/MatchersInput/index.tsx"],"names":[],"mappings":"AAkBA,OAAO,EAAgB,cAAc,EAAE,kBAAkB,EAAgB,MAAM,eAAe,CAAC;AAE/F,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAMpC,UAAU,kBAAkB;IAC1B,WAAW,EAAE,kBAAkB,CAAC;IAChC,iBAAiB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,EAAE,KAAK,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,UAAU,aAAa;IACrB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,aAAa,WAChB,kBAAkB,eACb,MAAM,UACX,MAAM,QACR,MAAM,UACJ,MAAM,EAAE,KACf,aAyBF,CAAC;AAEF,UAAU,cAAc;IACtB,MAAM,EAAE;QACN,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,KAAK,CAAC,EAAE,KAAK,CAAC;KACf,CAAC;IACF,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,cAAc,WACjB,kBAAkB,aACf,MAAM,eACJ,MAAM,KAClB,cAsBF,CAAC;AAEF,QAAA,MAAM,aAAa,6EAMhB,kBAAkB,KAAG,GAAG,CAAC,OAkK3B,CAAC;AAEF,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/MatchersInput/index.tsx"],"names":[],"mappings":"AAmBA,OAAO,EAAgB,cAAc,EAAE,kBAAkB,EAAgB,MAAM,eAAe,CAAC;AAE/F,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAGpC,OAAO,EAAC,iBAAiB,EAAC,MAAM,oBAAoB,CAAC;AAKrD,UAAU,kBAAkB;IAC1B,WAAW,EAAE,kBAAkB,CAAC;IAChC,iBAAiB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,EAAE,KAAK,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,UAAU,aAAa;IACrB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,aAAa,WAChB,kBAAkB,eACb,MAAM,UACX,MAAM,QACR,MAAM,UACJ,MAAM,EAAE,KACf,aAyBF,CAAC;AAEF,UAAU,cAAc;IACtB,MAAM,EAAE;QACN,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,KAAK,CAAC,EAAE,KAAK,CAAC;KACf,CAAC;IACF,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,cAAc,WACjB,kBAAkB,aACf,MAAM,eACJ,MAAM,KAClB,cAsBF,CAAC;AAEF,eAAO,MAAM,8BAA8B,cAC9B,MAAM,sBACG,iBAAiB,KACpC,MAAM,EASR,CAAC;AAiMF,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,KAAK,EAAE,kBAAkB,GAAG,GAAG,CAAC,OAAO,CAMxF"}
@@ -12,11 +12,13 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
14
  import { useMemo, useRef, useState } from 'react';
15
+ import { useQuery } from '@tanstack/react-query';
15
16
  import cx from 'classnames';
16
17
  import TextareaAutosize from 'react-textarea-autosize';
17
18
  import { useGrpcMetadata } from '@parca/components';
18
19
  import { Query } from '@parca/parser';
19
20
  import { millisToProtoTimestamp, sanitizeLabelValue } from '@parca/utilities';
21
+ import { LabelsProvider, useLabels } from '../contexts/MatchersInputLabelsContext';
20
22
  import useGrpcQuery from '../useGrpcQuery';
21
23
  import SuggestionsList, { Suggestion, Suggestions } from './SuggestionsList';
22
24
  export const useLabelNames = (client, profileType, start, end, match) => {
@@ -63,21 +65,20 @@ export const useLabelValues = (client, labelName, profileType) => {
63
65
  });
64
66
  return { result: { response: data ?? [], error: error }, loading: isLoading };
65
67
  };
66
- const MatchersInput = ({ queryClient, setMatchersString, runQuery, currentQuery, profileType, }) => {
68
+ export const useFetchUtilizationLabelValues = (labelName, utilizationLabels) => {
69
+ const { data } = useQuery({
70
+ queryKey: ['utilizationLabelValues', labelName],
71
+ queryFn: async () => {
72
+ return await utilizationLabels?.utilizationFetchLabelValues?.(labelName);
73
+ },
74
+ });
75
+ return data ?? [];
76
+ };
77
+ const MatchersInput = ({ setMatchersString, runQuery, currentQuery, }) => {
67
78
  const inputRef = useRef(null);
68
79
  const [focusedInput, setFocusedInput] = useState(false);
69
80
  const [lastCompleted, setLastCompleted] = useState(new Suggestion('', '', ''));
70
- const [currentLabelName, setCurrentLabelName] = useState(null);
71
- const { loading: labelNamesLoading, result } = useLabelNames(queryClient, profileType);
72
- const { response: labelNamesResponse, error: labelNamesError } = result;
73
- const { loading: labelValuesLoading, result: { response: labelValues }, } = useLabelValues(queryClient, currentLabelName ?? '', profileType);
74
- const labelNames = useMemo(() => {
75
- return (labelNamesError === undefined || labelNamesError == null) &&
76
- labelNamesResponse !== undefined &&
77
- labelNamesResponse != null
78
- ? labelNamesResponse.labelNames.filter(e => e !== '__name__')
79
- : [];
80
- }, [labelNamesError, labelNamesResponse]);
81
+ const { labelNames, labelValues, labelNameMappings, isLabelNamesLoading, isLabelValuesLoading, currentLabelName, setCurrentLabelName, shouldHandlePrefixes, } = useLabels();
81
82
  const value = currentQuery.matchersString();
82
83
  const suggestionSections = useMemo(() => {
83
84
  const suggestionSections = new Suggestions();
@@ -104,15 +105,31 @@ const MatchersInput = ({ queryClient, setMatchersString, runQuery, currentQuery,
104
105
  const matches = labelNames.filter(function (label) {
105
106
  return label.toLowerCase().slice(0, inputLength) === inputValue;
106
107
  });
107
- matches.forEach(m => suggestionSections.labelNames.push({
108
- type: s.type,
109
- typeahead: s.typeahead,
110
- value: m,
111
- }));
108
+ matches.forEach(m => {
109
+ const suggestion = {
110
+ type: s.type,
111
+ typeahead: s.typeahead,
112
+ value: m,
113
+ };
114
+ if (shouldHandlePrefixes) {
115
+ const mapping = labelNameMappings.find(l => l.displayName === m);
116
+ if (mapping != null) {
117
+ suggestion.fullName = mapping.fullName;
118
+ }
119
+ }
120
+ suggestionSections.labelNames.push(suggestion);
121
+ });
112
122
  }
113
123
  if (s.type === 'labelValue') {
114
- if (currentLabelName === null || s.labelName !== currentLabelName) {
115
- setCurrentLabelName(s.labelName);
124
+ let labelNameForQuery = s.labelName;
125
+ if (shouldHandlePrefixes) {
126
+ const mapping = labelNameMappings.find(l => l.displayName === s.labelName);
127
+ if (mapping != null) {
128
+ labelNameForQuery = mapping.fullName;
129
+ }
130
+ }
131
+ if (currentLabelName === null || labelNameForQuery !== currentLabelName) {
132
+ setCurrentLabelName(labelNameForQuery);
116
133
  return;
117
134
  }
118
135
  if (labelValues !== null) {
@@ -127,7 +144,17 @@ const MatchersInput = ({ queryClient, setMatchersString, runQuery, currentQuery,
127
144
  }
128
145
  });
129
146
  return suggestionSections;
130
- }, [currentQuery, lastCompleted, labelNames, labelValues, currentLabelName, value]);
147
+ }, [
148
+ currentQuery,
149
+ lastCompleted,
150
+ labelNames,
151
+ labelValues,
152
+ currentLabelName,
153
+ value,
154
+ shouldHandlePrefixes,
155
+ labelNameMappings,
156
+ setCurrentLabelName,
157
+ ]);
131
158
  const resetLastCompleted = () => setLastCompleted(new Suggestion('', '', ''));
132
159
  const onChange = (e) => {
133
160
  const newValue = e.target.value;
@@ -166,6 +193,8 @@ const MatchersInput = ({ queryClient, setMatchersString, runQuery, currentQuery,
166
193
  ? 'Select a profile first to enter a filter...'
167
194
  : 'filter profiles... eg. node="test"', onChange: onChange, value: value, onBlur: unfocus, onFocus: focus, disabled: profileSelected, title: profileSelected
168
195
  ? 'Select a profile first to enter a filter...'
169
- : 'filter profiles... eg. node="test"', id: "matchers-input" }), _jsx(SuggestionsList, { isLabelNamesLoading: labelNamesLoading, suggestions: suggestionSections, applySuggestion: applySuggestion, inputRef: inputRef.current, runQuery: runQuery, focusedInput: focusedInput, isLabelValuesLoading: labelValuesLoading && lastCompleted.type === 'literal' })] }));
196
+ : 'filter profiles... eg. node="test"', id: "matchers-input" }), _jsx(SuggestionsList, { isLabelNamesLoading: isLabelNamesLoading, suggestions: suggestionSections, applySuggestion: applySuggestion, inputRef: inputRef.current, runQuery: runQuery, focusedInput: focusedInput, isLabelValuesLoading: isLabelValuesLoading && lastCompleted.type === 'literal', shouldTrimPrefix: shouldHandlePrefixes })] }));
170
197
  };
171
- export default MatchersInput;
198
+ export default function MatchersInputWithProvider(props) {
199
+ return (_jsx(LabelsProvider, { queryClient: props.queryClient, profileType: props.profileType, children: _jsx(MatchersInput, { ...props }) }));
200
+ }
@@ -29,6 +29,11 @@ export interface UtilizationMetrics {
29
29
  [key: string]: string;
30
30
  };
31
31
  }
32
+ export interface UtilizationLabels {
33
+ utilizationLabelNames?: string[];
34
+ utilizationFetchLabelValues?: (key: string) => Promise<string[]>;
35
+ utilizationLabelValues?: string[];
36
+ }
32
37
  interface ProfileSelectorProps extends ProfileSelectorFeatures {
33
38
  queryClient: QueryServiceClient;
34
39
  querySelection: QuerySelection;
@@ -43,6 +48,7 @@ interface ProfileSelectorProps extends ProfileSelectorFeatures {
43
48
  suffix?: string;
44
49
  utilizationMetrics?: UtilizationMetrics[];
45
50
  utilizationMetricsLoading?: boolean;
51
+ utilizationLabels?: UtilizationLabels;
46
52
  }
47
53
  export interface IProfileTypesResult {
48
54
  loading: boolean;
@@ -50,6 +56,6 @@ export interface IProfileTypesResult {
50
56
  error?: RpcError;
51
57
  }
52
58
  export declare const useProfileTypes: (client: QueryServiceClient) => IProfileTypesResult;
53
- declare const ProfileSelector: ({ queryClient, querySelection, selectProfile, selectQuery, closeProfile, enforcedProfileName, profileSelection, comparing, navigateTo, showMetricsGraph, showSumBySelector, showProfileTypeSelector, disableExplorativeQuerying, setDisplayHideMetricsGraphButton, utilizationMetrics, utilizationMetricsLoading, }: ProfileSelectorProps) => JSX.Element;
59
+ declare const ProfileSelector: ({ queryClient, querySelection, selectProfile, selectQuery, closeProfile, enforcedProfileName, profileSelection, comparing, navigateTo, showMetricsGraph, showSumBySelector, showProfileTypeSelector, disableExplorativeQuerying, setDisplayHideMetricsGraphButton, utilizationMetrics, utilizationMetricsLoading, utilizationLabels, }: ProfileSelectorProps) => JSX.Element;
54
60
  export default ProfileSelector;
55
61
  //# 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,EAAuC,MAAM,OAAO,CAAC;AAErF,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAElD,OAAO,EAAC,oBAAoB,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAUvE,OAAO,EAAC,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAC,gBAAgB,EAAC,MAAM,IAAI,CAAC;AAQpC,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,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE;QACR,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;KACvB,CAAC;IACF,UAAU,EAAE;QACV,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;KACvB,CAAC;CACH;AAED,UAAU,oBAAqB,SAAQ,uBAAuB;IAC5D,WAAW,EAAE,kBAAkB,CAAC;IAChC,cAAc,EAAE,cAAc,CAAC;IAC/B,aAAa,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClD,WAAW,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC7C,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,gCAAgC,EAAE,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kBAAkB,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC1C,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;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,WAAY,kBAAkB,KAAG,mBAkB5D,CAAC;AAEF,QAAA,MAAM,eAAe,wTAiBlB,oBAAoB,KAAG,GAAG,CAAC,OA0M7B,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,QAAQ,EAAE,cAAc,EAAuC,MAAM,OAAO,CAAC;AAErF,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAElD,OAAO,EAAC,oBAAoB,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAUvE,OAAO,EAAC,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAC,gBAAgB,EAAC,MAAM,IAAI,CAAC;AASpC,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,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE;QACR,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;KACvB,CAAC;IACF,UAAU,EAAE;QACV,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;KACvB,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,2BAA2B,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACjE,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;CACnC;AAED,UAAU,oBAAqB,SAAQ,uBAAuB;IAC5D,WAAW,EAAE,kBAAkB,CAAC;IAChC,cAAc,EAAE,cAAc,CAAC;IAC/B,aAAa,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClD,WAAW,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC7C,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,gCAAgC,EAAE,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kBAAkB,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC1C,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACvC;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,WAAY,kBAAkB,KAAG,mBAkB5D,CAAC;AAEF,QAAA,MAAM,eAAe,2UAkBlB,oBAAoB,KAAG,GAAG,CAAC,OA4M7B,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -17,6 +17,7 @@ import { CloseIcon } from '@parca/icons';
17
17
  import { Query } from '@parca/parser';
18
18
  import { useLabelNames } from '../MatchersInput/index';
19
19
  import { useMetricsGraphDimensions } from '../MetricsGraph/useMetricsGraphDimensions';
20
+ import { UtilizationLabelsProvider } from '../contexts/UtilizationLabelsContext';
20
21
  import { useDefaultSumBy, useSumBySelection } from '../useSumBy';
21
22
  import { MetricsGraphSection } from './MetricsGraphSection';
22
23
  import { QueryControls } from './QueryControls';
@@ -38,7 +39,7 @@ export const useProfileTypes = (client) => {
38
39
  }, [client, metadata, loading]);
39
40
  return { loading, data: result, error };
40
41
  };
41
- const ProfileSelector = ({ queryClient, querySelection, selectProfile, selectQuery, closeProfile, enforcedProfileName, profileSelection, comparing, navigateTo, showMetricsGraph = true, showSumBySelector = true, showProfileTypeSelector = true, disableExplorativeQuerying = false, setDisplayHideMetricsGraphButton, utilizationMetrics, utilizationMetricsLoading, }) => {
42
+ const ProfileSelector = ({ queryClient, querySelection, selectProfile, selectQuery, closeProfile, enforcedProfileName, profileSelection, comparing, navigateTo, showMetricsGraph = true, showSumBySelector = true, showProfileTypeSelector = true, disableExplorativeQuerying = false, setDisplayHideMetricsGraphButton, utilizationMetrics, utilizationMetricsLoading, utilizationLabels, }) => {
42
43
  const { loading: profileTypesLoading, data: profileTypesData, error, } = useProfileTypes(queryClient);
43
44
  const { heightStyle } = useMetricsGraphDimensions(comparing);
44
45
  const { viewComponent } = useParcaContext();
@@ -139,6 +140,6 @@ const ProfileSelector = ({ queryClient, querySelection, selectProfile, selectQue
139
140
  queryExpressionString === '{}';
140
141
  const queryBrowserRef = useRef(null);
141
142
  const sumByRef = useRef(null);
142
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "mb-2 flex", children: [_jsx(QueryControls, { showProfileTypeSelector: showProfileTypeSelector, showSumBySelector: showSumBySelector, disableExplorativeQuerying: disableExplorativeQuerying, profileTypesData: profileTypesData, profileTypesLoading: profileTypesLoading, selectedProfileName: selectedProfileName, setProfileName: setProfileName, setMatchersString: setMatchersString, setQueryExpression: setQueryExpression, query: query, queryBrowserRef: queryBrowserRef, timeRangeSelection: timeRangeSelection, setTimeRangeSelection: setTimeRangeSelection, searchDisabled: searchDisabled, queryBrowserMode: queryBrowserMode, setQueryBrowserMode: setQueryBrowserMode, advancedModeForQueryBrowser: advancedModeForQueryBrowser, setAdvancedModeForQueryBrowser: setAdvancedModeForQueryBrowser, queryClient: queryClient, sumByRef: sumByRef, labels: labels, sumBySelection: sumBySelection ?? [], setUserSumBySelection: setUserSumBySelection, profileType: profileType, profileTypesError: error }), comparing && (_jsx("div", { children: _jsx(IconButton, { onClick: () => closeProfile(), icon: _jsx(CloseIcon, {}) }) }))] }), _jsx(MetricsGraphSection, { showMetricsGraph: showMetricsGraph, setDisplayHideMetricsGraphButton: setDisplayHideMetricsGraphButton, heightStyle: heightStyle, querySelection: querySelection, profileSelection: profileSelection, comparing: comparing, sumBy: querySelection.sumBy ?? defaultSumBy ?? [], defaultSumByLoading: defaultSumByLoading, queryClient: queryClient, queryExpressionString: queryExpressionString, setTimeRangeSelection: setTimeRangeSelection, selectQuery: selectQuery, selectProfile: selectProfile, query: query, setQueryExpression: setQueryExpression, setNewQueryExpression: setNewQueryExpression, utilizationMetrics: utilizationMetrics, utilizationMetricsLoading: utilizationMetricsLoading })] }));
143
+ return (_jsx(UtilizationLabelsProvider, { value: utilizationLabels, children: _jsxs(_Fragment, { children: [_jsxs("div", { className: "mb-2 flex", children: [_jsx(QueryControls, { showProfileTypeSelector: showProfileTypeSelector, showSumBySelector: showSumBySelector, disableExplorativeQuerying: disableExplorativeQuerying, profileTypesData: profileTypesData, profileTypesLoading: profileTypesLoading, selectedProfileName: selectedProfileName, setProfileName: setProfileName, setMatchersString: setMatchersString, setQueryExpression: setQueryExpression, query: query, queryBrowserRef: queryBrowserRef, timeRangeSelection: timeRangeSelection, setTimeRangeSelection: setTimeRangeSelection, searchDisabled: searchDisabled, queryBrowserMode: queryBrowserMode, setQueryBrowserMode: setQueryBrowserMode, advancedModeForQueryBrowser: advancedModeForQueryBrowser, setAdvancedModeForQueryBrowser: setAdvancedModeForQueryBrowser, queryClient: queryClient, sumByRef: sumByRef, labels: labels, sumBySelection: sumBySelection ?? [], setUserSumBySelection: setUserSumBySelection, profileType: profileType, profileTypesError: error }), comparing && (_jsx("div", { children: _jsx(IconButton, { onClick: () => closeProfile(), icon: _jsx(CloseIcon, {}) }) }))] }), _jsx(MetricsGraphSection, { showMetricsGraph: showMetricsGraph, setDisplayHideMetricsGraphButton: setDisplayHideMetricsGraphButton, heightStyle: heightStyle, querySelection: querySelection, profileSelection: profileSelection, comparing: comparing, sumBy: querySelection.sumBy ?? defaultSumBy ?? [], defaultSumByLoading: defaultSumByLoading, queryClient: queryClient, queryExpressionString: queryExpressionString, setTimeRangeSelection: setTimeRangeSelection, selectQuery: selectQuery, selectProfile: selectProfile, query: query, setQueryExpression: setQueryExpression, setNewQueryExpression: setNewQueryExpression, utilizationMetrics: utilizationMetrics, utilizationMetricsLoading: utilizationMetricsLoading })] }) }));
143
144
  };
144
145
  export default ProfileSelector;
@@ -1,5 +1,6 @@
1
1
  import { QueryServiceClient } from '@parca/client';
2
2
  import { Query } from '@parca/parser';
3
+ import { type SelectItem } from './Select';
3
4
  interface Props {
4
5
  queryClient: QueryServiceClient;
5
6
  setMatchersString: (arg: string) => void;
@@ -8,6 +9,7 @@ interface Props {
8
9
  profileType: string;
9
10
  queryBrowserRef: React.RefObject<HTMLDivElement>;
10
11
  }
11
- declare const SimpleMatchers: ({ queryClient, setMatchersString, currentQuery, profileType, queryBrowserRef, }: Props) => JSX.Element;
12
- export default SimpleMatchers;
12
+ export declare const transformLabelsForSelect: (labelNames: string[], shouldTrimPrefix?: boolean) => SelectItem[];
13
+ export default function SimpleMathersWithProvider(props: Props): JSX.Element;
14
+ export {};
13
15
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/SimpleMatchers/index.tsx"],"names":[],"mappings":"AAmBA,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAMpC,UAAU,KAAK;IACb,WAAW,EAAE,kBAAkB,CAAC;IAChC,iBAAiB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,EAAE,KAAK,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;CAClD;AAgED,QAAA,MAAM,cAAc,oFAOjB,KAAK,KAAG,GAAG,CAAC,OA8Qd,CAAC;AAEF,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/SimpleMatchers/index.tsx"],"names":[],"mappings":"AAmBA,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAKpC,OAAe,EAAC,KAAK,UAAU,EAAC,MAAM,UAAU,CAAC;AAEjD,UAAU,KAAK;IACb,WAAW,EAAE,kBAAkB,CAAC;IAChC,iBAAiB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,EAAE,KAAK,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;CAClD;AAUD,eAAO,MAAM,wBAAwB,eACvB,MAAM,EAAE,iCAEnB,UAAU,EAQZ,CAAC;AA+UF,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,KAAK,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAkB3E"}
@@ -17,12 +17,16 @@ import { useQueryClient } from '@tanstack/react-query';
17
17
  import cx from 'classnames';
18
18
  import { useGrpcMetadata } from '@parca/components';
19
19
  import { sanitizeLabelValue } from '@parca/utilities';
20
- import { useLabelNames } from '../MatchersInput';
20
+ import { LabelProvider, useLabels } from '../contexts/SimpleMatchersLabelContext';
21
+ import { useUtilizationLabels } from '../contexts/UtilizationLabelsContext';
21
22
  import Select from './Select';
22
- const transformLabelsForSelect = (labelNames) => {
23
+ export const transformLabelsForSelect = (labelNames, shouldTrimPrefix = false) => {
23
24
  return labelNames.map(labelName => ({
24
25
  key: labelName,
25
- element: { active: _jsx(_Fragment, { children: labelName }), expanded: _jsx(_Fragment, { children: labelName }) },
26
+ element: {
27
+ active: _jsx(_Fragment, { children: shouldTrimPrefix ? labelName.split('.').pop() : labelName }),
28
+ expanded: _jsx(_Fragment, { children: shouldTrimPrefix ? labelName.split('.').pop() : labelName }),
29
+ },
26
30
  }));
27
31
  };
28
32
  const operatorOptions = [
@@ -55,27 +59,18 @@ const operatorOptions = [
55
59
  },
56
60
  },
57
61
  ];
58
- const SimpleMatchers = ({ queryClient, setMatchersString,
59
- // runQuery,
60
- currentQuery, profileType, queryBrowserRef, }) => {
62
+ const SimpleMatchers = ({ queryClient, setMatchersString, currentQuery, profileType, queryBrowserRef, }) => {
63
+ const utilizationLabels = useUtilizationLabels();
61
64
  const [queryRows, setQueryRows] = useState([
62
65
  { labelName: '', operator: '=', labelValue: '', labelValues: [], isLoading: false },
63
66
  ]);
64
67
  const reactQueryClient = useQueryClient();
65
68
  const metadata = useGrpcMetadata();
66
- const { loading: labelNamesLoading, result } = useLabelNames(queryClient, profileType);
67
- const { response: labelNamesResponse, error: labelNamesError } = result;
68
69
  const [showAll, setShowAll] = useState(false);
69
70
  const visibleRows = showAll ? queryRows : queryRows.slice(0, 3);
70
71
  const hiddenRowsCount = queryRows.length - 3;
71
72
  const maxWidthInPixels = `max-w-[${queryBrowserRef.current?.offsetWidth.toString()}px]`;
72
73
  const currentMatchers = currentQuery.matchersString();
73
- const labelNameFromMatchers = useMemo(() => {
74
- if (currentQuery === undefined)
75
- return [];
76
- const matchers = currentQuery.matchers;
77
- return matchers.map(matcher => matcher.key);
78
- }, [currentQuery]);
79
74
  const fetchLabelValues = useCallback(async (labelName) => {
80
75
  if (labelName == null || labelName === '' || profileType == null || profileType === '') {
81
76
  return [];
@@ -95,6 +90,9 @@ currentQuery, profileType, queryBrowserRef, }) => {
95
90
  return [];
96
91
  }
97
92
  }, [queryClient, metadata, profileType, reactQueryClient]);
93
+ const fetchLabelValuesUtilization = useCallback(async (labelName) => {
94
+ return (await utilizationLabels?.utilizationFetchLabelValues?.(labelName)) ?? [];
95
+ }, [utilizationLabels]);
98
96
  const updateMatchersString = useCallback((rows) => {
99
97
  const matcherString = rows
100
98
  .filter(row => row.labelName.length > 0 && row.labelValue)
@@ -115,7 +113,9 @@ currentQuery, profileType, queryBrowserRef, }) => {
115
113
  const trimmedLabelName = labelName.trim();
116
114
  if (trimmedLabelName === '')
117
115
  return null;
118
- const labelValues = await fetchLabelValues(trimmedLabelName);
116
+ const labelValues = utilizationLabels?.utilizationFetchLabelValues !== undefined
117
+ ? await fetchLabelValuesUtilization(trimmedLabelName)
118
+ : await fetchLabelValues(trimmedLabelName);
119
119
  const sanitizedLabelValue = labelValue.startsWith('"') && labelValue.endsWith('"')
120
120
  ? labelValue.slice(1, -1)
121
121
  : labelValue;
@@ -131,18 +131,14 @@ currentQuery, profileType, queryBrowserRef, }) => {
131
131
  updateMatchersString(filteredRows);
132
132
  };
133
133
  void fetchAndSetQueryRows();
134
- }, [currentMatchers, fetchLabelValues, updateMatchersString]);
135
- const labelNames = useMemo(() => {
136
- return (labelNamesError === undefined || labelNamesError == null) &&
137
- labelNamesResponse !== undefined &&
138
- labelNamesResponse != null
139
- ? labelNamesResponse.labelNames.filter(e => e !== '__name__')
140
- : [];
141
- }, [labelNamesError, labelNamesResponse]);
142
- const labelNameOptions = useMemo(() => {
143
- const uniqueLabelNames = Array.from(new Set([...labelNames, ...labelNameFromMatchers]));
144
- return transformLabelsForSelect(uniqueLabelNames);
145
- }, [labelNames, labelNameFromMatchers]);
134
+ }, [
135
+ currentMatchers,
136
+ fetchLabelValues,
137
+ updateMatchersString,
138
+ fetchLabelValuesUtilization,
139
+ utilizationLabels,
140
+ ]);
141
+ const { labelNameOptions, isLoading: labelNamesLoading } = useLabels();
146
142
  const updateRow = useCallback(async (index, field, value) => {
147
143
  const updatedRows = [...queryRows];
148
144
  const prevLabelName = updatedRows[index].labelName;
@@ -152,13 +148,21 @@ currentQuery, profileType, queryBrowserRef, }) => {
152
148
  updatedRows[index].labelValue = '';
153
149
  updatedRows[index].isLoading = true;
154
150
  setQueryRows([...updatedRows]);
155
- const labelValues = await fetchLabelValues(value);
151
+ const labelValues = utilizationLabels?.utilizationFetchLabelValues !== undefined
152
+ ? await fetchLabelValuesUtilization(value)
153
+ : await fetchLabelValues(value);
156
154
  updatedRows[index].labelValues = labelValues;
157
155
  updatedRows[index].isLoading = false;
158
156
  }
159
157
  setQueryRows([...updatedRows]);
160
158
  updateMatchersString(updatedRows);
161
- }, [queryRows, fetchLabelValues, updateMatchersString]);
159
+ }, [
160
+ queryRows,
161
+ fetchLabelValues,
162
+ updateMatchersString,
163
+ fetchLabelValuesUtilization,
164
+ utilizationLabels,
165
+ ]);
162
166
  const handleUpdateRow = useCallback((index, field, value) => {
163
167
  void updateRow(index, field, value);
164
168
  }, [updateRow]);
@@ -196,7 +200,9 @@ currentQuery, profileType, queryBrowserRef, }) => {
196
200
  updatedRows[index].isLoading = true;
197
201
  setQueryRows([...updatedRows]);
198
202
  try {
199
- const labelValues = await fetchLabelValues(updatedRows[index].labelName);
203
+ const labelValues = utilizationLabels?.utilizationFetchLabelValues !== undefined
204
+ ? await fetchLabelValuesUtilization(updatedRows[index].labelName)
205
+ : await fetchLabelValues(updatedRows[index].labelName);
200
206
  updatedRows[index].labelValues = labelValues;
201
207
  }
202
208
  catch (error) {
@@ -211,10 +217,18 @@ currentQuery, profileType, queryBrowserRef, }) => {
211
217
  console.log(`Label values already present or empty label name`);
212
218
  }
213
219
  };
214
- }, [queryRows, fetchLabelValues]);
220
+ }, [queryRows, fetchLabelValues, fetchLabelValuesUtilization, utilizationLabels]);
215
221
  const isRowRegex = (row) => row.operator === '=~' || row.operator === '!~';
216
222
  return (_jsxs("div", { className: `flex items-center gap-3 ${maxWidthInPixels} w-full flex-wrap`, id: "simple-matchers", children: [visibleRows.map((row, index) => (_jsxs("div", { className: "flex items-center", children: [_jsx(Select, { items: labelNameOptions, onSelection: value => handleUpdateRow(index, 'labelName', value), placeholder: "Select label name", selectedKey: row.labelName, className: "rounded-tr-none rounded-br-none ring-0 focus:ring-0 outline-none", loading: labelNamesLoading, searchable: true }), _jsx(Select, { items: operatorOptions, onSelection: value => handleUpdateRow(index, 'operator', value), selectedKey: row.operator, className: "rounded-none ring-0 focus:ring-0 outline-none" }), _jsx(Select, { items: transformLabelsForSelect(row.labelValues), onSelection: value => handleUpdateRow(index, 'labelValue', value), placeholder: "Select label value", selectedKey: row.labelValue, className: "rounded-none ring-0 focus:ring-0 outline-none max-w-48", optionsClassname: cx('max-w-[300px]', {
217
223
  'w-[300px]': isRowRegex(row),
218
224
  }), searchable: true, disabled: row.labelName === '', loading: row.isLoading, onButtonClick: () => handleLabelValueClick(index), editable: isRowRegex(row) }), _jsx("button", { onClick: () => removeRow(index), className: cx('p-2 border-gray-200 border rounded rounded-tl-none rounded-bl-none focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:border-gray-600 dark:bg-gray-900'), children: _jsx(Icon, { icon: "carbon:close", className: "h-5 w-5 text-gray-400", "aria-hidden": "true" }) })] }, index))), queryRows.length > 3 && (_jsx("button", { onClick: () => setShowAll(!showAll), className: "mr-2 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", children: showAll ? 'Show less' : `Show ${hiddenRowsCount} more` })), _jsx("button", { onClick: addNewRow, className: "p-2 border-gray-200 dark:bg-gray-900 dark:border-gray-600 border rounded focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500", children: _jsx(Icon, { icon: "material-symbols:add", className: "h-5 w-5 text-gray-400", "aria-hidden": "true" }) })] }));
219
225
  };
220
- export default SimpleMatchers;
226
+ export default function SimpleMathersWithProvider(props) {
227
+ const labelNameFromMatchers = useMemo(() => {
228
+ if (props.currentQuery === undefined)
229
+ return [];
230
+ const matchers = props.currentQuery.matchers;
231
+ return matchers.map(matcher => matcher.key);
232
+ }, [props.currentQuery]);
233
+ return (_jsx(LabelProvider, { queryClient: props.queryClient, profileType: props.profileType, labelNameFromMatchers: labelNameFromMatchers, children: _jsx(SimpleMatchers, { ...props }) }));
234
+ }
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import { QueryServiceClient } from '@parca/client';
3
+ interface LabelNameMapping {
4
+ displayName: string;
5
+ fullName: string;
6
+ }
7
+ interface LabelsContextType {
8
+ labelNames: string[];
9
+ labelValues: string[];
10
+ labelNameMappings: LabelNameMapping[];
11
+ isLabelNamesLoading: boolean;
12
+ isLabelValuesLoading: boolean;
13
+ currentLabelName: string | null;
14
+ setCurrentLabelName: (name: string | null) => void;
15
+ shouldHandlePrefixes: boolean;
16
+ }
17
+ interface LabelsProviderProps {
18
+ children: React.ReactNode;
19
+ queryClient: QueryServiceClient;
20
+ profileType: string;
21
+ }
22
+ export declare function LabelsProvider({ children, queryClient, profileType, }: LabelsProviderProps): JSX.Element;
23
+ export declare function useLabels(): LabelsContextType;
24
+ export {};
25
+ //# sourceMappingURL=MatchersInputLabelsContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MatchersInputLabelsContext.d.ts","sourceRoot":"","sources":["../../src/contexts/MatchersInputLabelsContext.tsx"],"names":[],"mappings":"AAaA,OAAO,KAA2C,MAAM,OAAO,CAAC;AAEhE,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAKjD,UAAU,gBAAgB;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,iBAAiB;IACzB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,iBAAiB,EAAE,gBAAgB,EAAE,CAAC;IACtC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACnD,oBAAoB,EAAE,OAAO,CAAC;CAC/B;AAID,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,WAAW,EAAE,kBAAkB,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;CACrB;AAID,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,WAAW,EACX,WAAW,GACZ,EAAE,mBAAmB,GAAG,GAAG,CAAC,OAAO,CAuEnC;AAED,wBAAgB,SAAS,IAAI,iBAAiB,CAM7C"}
@@ -0,0 +1,75 @@
1
+ import { jsx as _jsx } 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 React, { createContext, useContext, useMemo } from 'react';
15
+ import { useFetchUtilizationLabelValues, useLabelNames, useLabelValues } from '../MatchersInput';
16
+ import { useUtilizationLabels } from './UtilizationLabelsContext';
17
+ const LabelsContext = createContext(null);
18
+ // With there being the possibility of having utilization labels, we need to be able to determine whether the labels to be used are utilization labels or profiling data labels.
19
+ // This context is used to determine this.
20
+ export function LabelsProvider({ children, queryClient, profileType, }) {
21
+ const [currentLabelName, setCurrentLabelName] = React.useState(null);
22
+ const utilizationLabels = useUtilizationLabels();
23
+ const { result: labelNamesResponse, loading: isLabelNamesLoading } = useLabelNames(queryClient, profileType);
24
+ const labelNamesFromAPI = useMemo(() => {
25
+ return (labelNamesResponse.error === undefined || labelNamesResponse.error == null) &&
26
+ labelNamesResponse !== undefined &&
27
+ labelNamesResponse != null
28
+ ? labelNamesResponse.response?.labelNames.filter(e => e !== '__name__') ?? []
29
+ : [];
30
+ }, [labelNamesResponse]);
31
+ const { result: labelValuesOriginal, loading: isLabelValuesLoading } = useLabelValues(queryClient, currentLabelName ?? '', profileType);
32
+ const utilizationLabelValues = useFetchUtilizationLabelValues(currentLabelName ?? '', utilizationLabels);
33
+ const shouldHandlePrefixes = utilizationLabels?.utilizationLabelNames !== undefined;
34
+ const labelNameMappings = useMemo(() => {
35
+ const names = utilizationLabels?.utilizationLabelNames ?? labelNamesFromAPI;
36
+ return names.map(name => ({
37
+ displayName: name.replace(/^(attributes\.|attributes_resource\.)/, ''),
38
+ fullName: name,
39
+ }));
40
+ }, [labelNamesFromAPI, utilizationLabels?.utilizationLabelNames]);
41
+ const labelNames = useMemo(() => {
42
+ return shouldHandlePrefixes ? labelNameMappings.map(m => m.displayName) : labelNamesFromAPI;
43
+ }, [labelNameMappings, labelNamesFromAPI, shouldHandlePrefixes]);
44
+ const labelValues = useMemo(() => {
45
+ return utilizationLabels?.utilizationFetchLabelValues !== undefined
46
+ ? utilizationLabelValues
47
+ : labelValuesOriginal.response;
48
+ }, [labelValuesOriginal, utilizationLabelValues, utilizationLabels]);
49
+ const value = useMemo(() => ({
50
+ labelNames,
51
+ labelValues,
52
+ labelNameMappings,
53
+ isLabelNamesLoading,
54
+ isLabelValuesLoading,
55
+ currentLabelName,
56
+ setCurrentLabelName,
57
+ shouldHandlePrefixes,
58
+ }), [
59
+ labelNames,
60
+ labelValues,
61
+ labelNameMappings,
62
+ isLabelNamesLoading,
63
+ isLabelValuesLoading,
64
+ currentLabelName,
65
+ shouldHandlePrefixes,
66
+ ]);
67
+ return _jsx(LabelsContext.Provider, { value: value, children: children });
68
+ }
69
+ export function useLabels() {
70
+ const context = useContext(LabelsContext);
71
+ if (context === null) {
72
+ throw new Error('useLabels must be used within a LabelsProvider');
73
+ }
74
+ return context;
75
+ }
@@ -0,0 +1,17 @@
1
+ import { QueryServiceClient } from '@parca/client';
2
+ import type { SelectItem } from '../SimpleMatchers/Select';
3
+ interface LabelContextValue {
4
+ labelNameOptions: SelectItem[];
5
+ isLoading: boolean;
6
+ error: Error | null;
7
+ }
8
+ interface LabelProviderProps {
9
+ children: React.ReactNode;
10
+ queryClient: QueryServiceClient;
11
+ profileType: string;
12
+ labelNameFromMatchers: string[];
13
+ }
14
+ export declare function LabelProvider({ children, queryClient, profileType, labelNameFromMatchers, }: LabelProviderProps): JSX.Element;
15
+ export declare function useLabels(): LabelContextValue;
16
+ export {};
17
+ //# sourceMappingURL=SimpleMatchersLabelContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SimpleMatchersLabelContext.d.ts","sourceRoot":"","sources":["../../src/contexts/SimpleMatchersLabelContext.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAIjD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAC;AAGzD,UAAU,iBAAiB;IACzB,gBAAgB,EAAE,UAAU,EAAE,CAAC;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAID,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,WAAW,EAAE,kBAAkB,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB,EAAE,MAAM,EAAE,CAAC;CACjC;AAKD,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,WAAW,EACX,WAAW,EACX,qBAAqB,GACtB,EAAE,kBAAkB,GAAG,GAAG,CAAC,OAAO,CAwBlC;AAED,wBAAgB,SAAS,IAAI,iBAAiB,CAM7C"}