@parca/profile 0.19.60 → 0.19.62
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/SuggestionsList.d.ts +2 -1
- package/dist/MatchersInput/SuggestionsList.d.ts.map +1 -1
- package/dist/MatchersInput/SuggestionsList.js +24 -3
- package/dist/MatchersInput/index.d.ts +1 -0
- package/dist/MatchersInput/index.d.ts.map +1 -1
- package/dist/MatchersInput/index.js +13 -7
- package/dist/ProfileSelector/QueryControls.d.ts.map +1 -1
- package/dist/ProfileSelector/QueryControls.js +4 -1
- package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.d.ts +4 -0
- package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.d.ts.map +1 -1
- package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.js +2 -4
- package/dist/ProfileView/components/Toolbars/index.d.ts +4 -0
- package/dist/ProfileView/components/Toolbars/index.d.ts.map +1 -1
- package/dist/ProfileView/components/Toolbars/index.js +2 -2
- package/dist/ProfileView/hooks/useVisualizationState.d.ts +2 -0
- package/dist/ProfileView/hooks/useVisualizationState.d.ts.map +1 -1
- package/dist/ProfileView/hooks/useVisualizationState.js +19 -1
- package/dist/ProfileView/index.d.ts.map +1 -1
- package/dist/ProfileView/index.js +2 -2
- package/dist/SimpleMatchers/Select.d.ts +3 -0
- package/dist/SimpleMatchers/Select.d.ts.map +1 -1
- package/dist/SimpleMatchers/Select.js +29 -6
- package/dist/SimpleMatchers/index.d.ts +1 -0
- package/dist/SimpleMatchers/index.d.ts.map +1 -1
- package/dist/SimpleMatchers/index.js +92 -9
- package/dist/ViewMatchers/index.js +14 -14
- package/dist/contexts/MatchersInputLabelsContext.d.ts +1 -0
- package/dist/contexts/MatchersInputLabelsContext.d.ts.map +1 -1
- package/dist/contexts/MatchersInputLabelsContext.js +3 -1
- package/dist/contexts/SimpleMatchersLabelContext.d.ts +1 -0
- package/dist/contexts/SimpleMatchersLabelContext.d.ts.map +1 -1
- package/dist/contexts/SimpleMatchersLabelContext.js +19 -2
- package/dist/styles.css +1 -1
- package/dist/useGrpcQuery/index.d.ts +2 -1
- package/dist/useGrpcQuery/index.d.ts.map +1 -1
- package/dist/useGrpcQuery/index.js +2 -1
- package/package.json +8 -8
- package/src/MatchersInput/SuggestionsList.tsx +119 -40
- package/src/MatchersInput/index.tsx +14 -5
- package/src/ProfileSelector/QueryControls.tsx +5 -1
- package/src/ProfileView/components/Toolbars/MultiLevelDropdown.tsx +10 -5
- package/src/ProfileView/components/Toolbars/index.tsx +12 -0
- package/src/ProfileView/hooks/useVisualizationState.ts +34 -1
- package/src/ProfileView/index.tsx +7 -0
- package/src/SimpleMatchers/Select.tsx +128 -60
- package/src/SimpleMatchers/index.tsx +109 -12
- package/src/ViewMatchers/index.tsx +15 -15
- package/src/contexts/MatchersInputLabelsContext.tsx +8 -7
- package/src/contexts/SimpleMatchersLabelContext.tsx +28 -2
- package/src/useGrpcQuery/index.ts +3 -1
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.62](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.61...@parca/profile@0.19.62) (2025-10-08)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @parca/profile
|
|
9
|
+
|
|
10
|
+
## [0.19.61](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.60...@parca/profile@0.19.61) (2025-10-02)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @parca/profile
|
|
13
|
+
|
|
6
14
|
## [0.19.60](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.59...@parca/profile@0.19.60) (2025-10-01)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @parca/profile
|
|
@@ -19,7 +19,8 @@ interface Props {
|
|
|
19
19
|
isLabelNamesLoading: boolean;
|
|
20
20
|
isLabelValuesLoading: boolean;
|
|
21
21
|
shouldTrimPrefix: boolean;
|
|
22
|
+
refetchLabelValues: () => void;
|
|
22
23
|
}
|
|
23
|
-
declare const SuggestionsList: ({ suggestions, applySuggestion, inputRef, runQuery, focusedInput, isLabelNamesLoading, isLabelValuesLoading, shouldTrimPrefix, }: Props) => JSX.Element;
|
|
24
|
+
declare const SuggestionsList: ({ suggestions, applySuggestion, inputRef, runQuery, focusedInput, isLabelNamesLoading, isLabelValuesLoading, shouldTrimPrefix, refetchLabelValues, }: Props) => JSX.Element;
|
|
24
25
|
export default SuggestionsList;
|
|
25
26
|
//# sourceMappingURL=SuggestionsList.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SuggestionsList.d.ts","sourceRoot":"","sources":["../../src/MatchersInput/SuggestionsList.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SuggestionsList.d.ts","sourceRoot":"","sources":["../../src/MatchersInput/SuggestionsList.tsx"],"names":[],"mappings":"AAwBA,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;IAC1B,kBAAkB,EAAE,MAAM,IAAI,CAAC;CAChC;AAaD,QAAA,MAAM,eAAe,GAAI,sJAUtB,KAAK,KAAG,GAAG,CAAC,OAwSd,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -13,6 +13,8 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
13
13
|
// limitations under the License.
|
|
14
14
|
import { Fragment, useCallback, useEffect, useState } from 'react';
|
|
15
15
|
import { Transition } from '@headlessui/react';
|
|
16
|
+
import { Icon } from '@iconify/react';
|
|
17
|
+
import cx from 'classnames';
|
|
16
18
|
import { usePopper } from 'react-popper';
|
|
17
19
|
import { useParcaContext } from '@parca/components';
|
|
18
20
|
import SuggestionItem from './SuggestionItem';
|
|
@@ -38,13 +40,25 @@ const transformLabelsForSuggestions = (labelNames, shouldTrimPrefix = false) =>
|
|
|
38
40
|
const trimmedLabel = shouldTrimPrefix ? labelNames.split('.').pop() ?? labelNames : labelNames;
|
|
39
41
|
return trimmedLabel;
|
|
40
42
|
};
|
|
41
|
-
const SuggestionsList = ({ suggestions, applySuggestion, inputRef, runQuery, focusedInput, isLabelNamesLoading, isLabelValuesLoading, shouldTrimPrefix = false, }) => {
|
|
43
|
+
const SuggestionsList = ({ suggestions, applySuggestion, inputRef, runQuery, focusedInput, isLabelNamesLoading, isLabelValuesLoading, shouldTrimPrefix = false, refetchLabelValues, }) => {
|
|
42
44
|
const [popperElement, setPopperElement] = useState(null);
|
|
43
45
|
const { styles, attributes } = usePopper(inputRef, popperElement, {
|
|
44
46
|
placement: 'bottom-start',
|
|
45
47
|
});
|
|
46
48
|
const [highlightedSuggestionIndex, setHighlightedSuggestionIndex] = useState(-1);
|
|
47
49
|
const [showSuggest, setShowSuggest] = useState(true);
|
|
50
|
+
const [isRefetching, setIsRefetching] = useState(false);
|
|
51
|
+
const handleRefetch = useCallback(async () => {
|
|
52
|
+
if (isRefetching)
|
|
53
|
+
return;
|
|
54
|
+
setIsRefetching(true);
|
|
55
|
+
try {
|
|
56
|
+
await refetchLabelValues();
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
setIsRefetching(false);
|
|
60
|
+
}
|
|
61
|
+
}, [refetchLabelValues, isRefetching]);
|
|
48
62
|
const suggestionsLength = suggestions.literals.length + suggestions.labelNames.length + suggestions.labelValues.length;
|
|
49
63
|
const getSuggestion = useCallback((index) => {
|
|
50
64
|
if (index < suggestions.labelNames.length) {
|
|
@@ -136,7 +150,14 @@ const SuggestionsList = ({ suggestions, applySuggestion, inputRef, runQuery, foc
|
|
|
136
150
|
inputRef.removeEventListener('keypress', handleKeyPress);
|
|
137
151
|
};
|
|
138
152
|
}, [inputRef, highlightedSuggestionIndex, suggestions, handleKeyPress, handleKeyDown]);
|
|
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:
|
|
140
|
-
|
|
153
|
+
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: _jsx("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: _jsxs("div", { className: "relative pb-12", 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, {})) : suggestions.labelNames.length === 0 && suggestions.literals.length === 0 ? (_jsxs(_Fragment, { children: [suggestions.labelValues.length === 0 ? (_jsx("div", { className: "px-4 py-3 text-sm text-gray-500 dark:text-gray-400 text-center", "data-testid": "suggestions-no-results", children: "No label values found" })) : (suggestions.labelValues.map((l, i) => (_jsx(SuggestionItem, { isHighlighted: highlightedSuggestionIndex ===
|
|
154
|
+
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)))), _jsx("div", { className: "absolute w-full flex items-center justify-center bottom-0 px-3 py-2 bg-gray-50 dark:bg-gray-800", children: _jsxs("button", { onClick: e => {
|
|
155
|
+
e.preventDefault();
|
|
156
|
+
e.stopPropagation();
|
|
157
|
+
void handleRefetch();
|
|
158
|
+
}, disabled: isRefetching, className: cx('p-1 flex items-center gap-1 rounded-full transition-all duration-200 w-auto justify-center', isRefetching
|
|
159
|
+
? 'cursor-wait opacity-50'
|
|
160
|
+
: 'hover:bg-gray-200 dark:hover:bg-gray-700 cursor-pointer'), title: "Refresh label values", type: "button", "data-testid": "suggestions-refresh-button", children: [_jsx(Icon, { icon: "system-uicons:reset", className: cx('w-3 h-3 text-gray-500 dark:text-gray-400', isRefetching && 'animate-spin') }), _jsx("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Refresh results" })] }) })] })) : (suggestions.labelValues.map((l, i) => (_jsx(SuggestionItem, { isHighlighted: highlightedSuggestionIndex ===
|
|
161
|
+
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))))] }) }) }) })) }));
|
|
141
162
|
};
|
|
142
163
|
export default SuggestionsList;
|
|
@@ -25,6 +25,7 @@ interface UseLabelValues {
|
|
|
25
25
|
error?: Error;
|
|
26
26
|
};
|
|
27
27
|
loading: boolean;
|
|
28
|
+
refetch: () => void;
|
|
28
29
|
}
|
|
29
30
|
export declare const useLabelValues: (client: QueryServiceClient, labelName: string, profileType: string, start?: number, end?: number) => UseLabelValues;
|
|
30
31
|
export declare const useFetchUtilizationLabelValues: (labelName: string, utilizationLabels?: UtilizationLabels) => string[];
|
|
@@ -1 +1 @@
|
|
|
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;AAIpC,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;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;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,GACxB,QAAQ,kBAAkB,EAC1B,aAAa,MAAM,EACnB,QAAQ,MAAM,EACd,MAAM,MAAM,EACZ,QAAQ,MAAM,EAAE,KACf,
|
|
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;AAIpC,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;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;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,GACxB,QAAQ,kBAAkB,EAC1B,aAAa,MAAM,EACnB,QAAQ,MAAM,EACd,MAAM,MAAM,EACZ,QAAQ,MAAM,EAAE,KACf,aAwBF,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;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,eAAO,MAAM,cAAc,GACzB,QAAQ,kBAAkB,EAC1B,WAAW,MAAM,EACjB,aAAa,MAAM,EACnB,QAAQ,MAAM,EACd,MAAM,MAAM,KACX,cA+BF,CAAC;AAEF,eAAO,MAAM,8BAA8B,GACzC,WAAW,MAAM,EACjB,oBAAoB,iBAAiB,KACpC,MAAM,EAWR,CAAC;AAuMF,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,KAAK,EAAE,kBAAkB,GAAG,GAAG,CAAC,OAAO,CAWxF"}
|
|
@@ -40,7 +40,6 @@ export const useLabelNames = (client, profileType, start, end, match) => {
|
|
|
40
40
|
},
|
|
41
41
|
options: {
|
|
42
42
|
enabled: profileType !== undefined && profileType !== '',
|
|
43
|
-
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
44
43
|
keepPreviousData: false,
|
|
45
44
|
},
|
|
46
45
|
});
|
|
@@ -48,7 +47,7 @@ export const useLabelNames = (client, profileType, start, end, match) => {
|
|
|
48
47
|
};
|
|
49
48
|
export const useLabelValues = (client, labelName, profileType, start, end) => {
|
|
50
49
|
const metadata = useGrpcMetadata();
|
|
51
|
-
const { data, isLoading, error } = useGrpcQuery({
|
|
50
|
+
const { data, isLoading, error, refetch } = useGrpcQuery({
|
|
52
51
|
key: ['labelValues', labelName, profileType, start, end],
|
|
53
52
|
queryFn: async (signal) => {
|
|
54
53
|
const request = { labelName, match: [], profileType };
|
|
@@ -64,18 +63,25 @@ export const useLabelValues = (client, labelName, profileType, start, end) => {
|
|
|
64
63
|
profileType !== '' &&
|
|
65
64
|
labelName !== undefined &&
|
|
66
65
|
labelName !== '',
|
|
67
|
-
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
68
66
|
keepPreviousData: false,
|
|
69
67
|
},
|
|
70
68
|
});
|
|
71
|
-
return {
|
|
69
|
+
return {
|
|
70
|
+
result: { response: data ?? [], error: error },
|
|
71
|
+
loading: isLoading,
|
|
72
|
+
refetch: () => {
|
|
73
|
+
void refetch();
|
|
74
|
+
},
|
|
75
|
+
};
|
|
72
76
|
};
|
|
73
77
|
export const useFetchUtilizationLabelValues = (labelName, utilizationLabels) => {
|
|
74
78
|
const { data } = useQuery({
|
|
75
79
|
queryKey: ['utilizationLabelValues', labelName],
|
|
76
80
|
queryFn: async () => {
|
|
77
|
-
|
|
81
|
+
const result = await utilizationLabels?.utilizationFetchLabelValues?.(labelName);
|
|
82
|
+
return result ?? [];
|
|
78
83
|
},
|
|
84
|
+
enabled: utilizationLabels?.utilizationFetchLabelValues != null && labelName !== '',
|
|
79
85
|
});
|
|
80
86
|
return data ?? [];
|
|
81
87
|
};
|
|
@@ -83,7 +89,7 @@ const MatchersInput = ({ setMatchersString, runQuery, currentQuery, }) => {
|
|
|
83
89
|
const inputRef = useRef(null);
|
|
84
90
|
const [focusedInput, setFocusedInput] = useState(false);
|
|
85
91
|
const [lastCompleted, setLastCompleted] = useState(new Suggestion('', '', ''));
|
|
86
|
-
const { labelNames, labelValues, labelNameMappings, isLabelNamesLoading, isLabelValuesLoading, currentLabelName, setCurrentLabelName, shouldHandlePrefixes, } = useLabels();
|
|
92
|
+
const { labelNames, labelValues, labelNameMappings, isLabelNamesLoading, isLabelValuesLoading, currentLabelName, setCurrentLabelName, shouldHandlePrefixes, refetchLabelValues, } = useLabels();
|
|
87
93
|
const value = currentQuery.matchersString();
|
|
88
94
|
const suggestionSections = useMemo(() => {
|
|
89
95
|
const suggestionSections = new Suggestions();
|
|
@@ -198,7 +204,7 @@ const MatchersInput = ({ setMatchersString, runQuery, currentQuery, }) => {
|
|
|
198
204
|
? 'Select a profile first to enter a filter...'
|
|
199
205
|
: 'filter profiles... eg. node="test"', onChange: onChange, value: value, onBlur: unfocus, ...testId(TEST_IDS.MATCHERS_TEXTAREA), onFocus: focus, disabled: profileSelected, title: profileSelected
|
|
200
206
|
? 'Select a profile first to enter a filter...'
|
|
201
|
-
: '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 })] }));
|
|
207
|
+
: '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, refetchLabelValues: refetchLabelValues })] }));
|
|
202
208
|
};
|
|
203
209
|
export default function MatchersInputWithProvider(props) {
|
|
204
210
|
return (_jsx(LabelsProvider, { queryClient: props.queryClient, profileType: props.profileType, start: props.start, end: props.end, children: _jsx(MatchersInput, { ...props }) }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryControls.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/QueryControls.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"QueryControls.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/QueryControls.tsx"],"names":[],"mappings":"AAgBA,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAClD,OAAe,EAAC,KAAK,cAAc,EAAC,MAAM,cAAc,CAAC;AAEzD,OAAO,EAAC,oBAAoB,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AACvE,OAAO,EAAS,aAAa,EAAuC,MAAM,mBAAmB,CAAC;AAC9F,OAAO,EAAC,WAAW,EAAE,KAAK,EAAC,MAAM,eAAe,CAAC;AAajD,UAAU,kBAAkB;IAC1B,uBAAuB,EAAE,OAAO,CAAC;IACjC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,0BAA0B,EAAE,OAAO,CAAC;IACpC,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;IACxC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IACnD,iBAAiB,CAAC,EAAE,QAAQ,CAAC;IAC7B,aAAa,CAAC,EAAE;QACd,2BAA2B,CAAC,EAAE,OAAO,CAAC;QACtC,0BAA0B,CAAC,EAAE,OAAO,CAAC;QACrC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,mBAAmB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;KACvC,CAAC;IACF,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,2BAA2B,EAAE,OAAO,CAAC;IACrC,8BAA8B,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACxD,iBAAiB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,kBAAkB,EAAE,CAAC,QAAQ,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD,KAAK,EAAE,KAAK,CAAC;IACb,eAAe,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IACjD,kBAAkB,EAAE,aAAa,CAAC;IAClC,qBAAqB,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACtD,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,EAAE,kBAAkB,CAAC;IAChC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,qBAAqB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACjD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IAC1C,WAAW,EAAE,WAAW,CAAC;CAC1B;AAED,wBAAgB,aAAa,CAAC,EAC5B,uBAAuB,EACvB,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,2BAA2B,EAC3B,8BAA8B,EAC9B,iBAAiB,EACjB,kBAAkB,EAClB,KAAK,EACL,eAAe,EACf,kBAAkB,EAClB,qBAAqB,EACrB,cAAc,EACd,WAAW,EACX,MAAM,EACN,cAAc,EACd,qBAAqB,EACrB,qBAAqB,EACrB,QAAQ,EACR,WAAW,EACX,iBAAiB,EACjB,iBAAiB,GAClB,EAAE,kBAAkB,GAAG,GAAG,CAAC,OAAO,CAsLlC"}
|
|
@@ -11,6 +11,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
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 { useState } from 'react';
|
|
14
15
|
import { Switch } from '@headlessui/react';
|
|
15
16
|
import Select from 'react-select';
|
|
16
17
|
import { Button, DateTimeRangePicker, useParcaContext } from '@parca/components';
|
|
@@ -21,12 +22,13 @@ import SimpleMatchers from '../SimpleMatchers';
|
|
|
21
22
|
import ViewMatchers from '../ViewMatchers';
|
|
22
23
|
export function QueryControls({ showProfileTypeSelector, profileTypesData, profileTypesLoading, selectedProfileName, setProfileName, viewComponent, setQueryBrowserMode, advancedModeForQueryBrowser, setAdvancedModeForQueryBrowser, setMatchersString, setQueryExpression, query, queryBrowserRef, timeRangeSelection, setTimeRangeSelection, searchDisabled, queryClient, labels, sumBySelection, sumBySelectionLoading, setUserSumBySelection, sumByRef, profileType, showSumBySelector, profileTypesError, }) {
|
|
23
24
|
const { timezone } = useParcaContext();
|
|
25
|
+
const [searchExecutedTimestamp, setSearchExecutedTimestamp] = useState(0);
|
|
24
26
|
return (_jsxs("div", { className: "flex w-full flex-wrap items-start gap-2", ...testId(TEST_IDS.QUERY_CONTROLS_CONTAINER), children: [showProfileTypeSelector && (_jsxs("div", { children: [_jsx("label", { className: "text-xs", ...testId(TEST_IDS.PROFILE_TYPE_LABEL), children: "Profile type" }), _jsx(ProfileTypeSelector, { profileTypesData: profileTypesData, loading: profileTypesLoading, selectedKey: selectedProfileName, onSelection: setProfileName, error: profileTypesError, disabled: viewComponent?.disableProfileTypesDropdown })] })), _jsxs("div", { className: "w-full flex-1 flex flex-col gap-1 mt-auto", ref: queryBrowserRef, ...testId(TEST_IDS.QUERY_BROWSER_CONTAINER), children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("label", { className: "text-xs", ...testId(TEST_IDS.QUERY_LABEL), children: "Query" }), viewComponent?.disableExplorativeQuerying !== true && (_jsxs(_Fragment, { children: [_jsxs(Switch, { checked: advancedModeForQueryBrowser, onChange: () => {
|
|
25
27
|
setAdvancedModeForQueryBrowser(!advancedModeForQueryBrowser);
|
|
26
28
|
setQueryBrowserMode(advancedModeForQueryBrowser ? 'simple' : 'advanced');
|
|
27
29
|
}, className: `${advancedModeForQueryBrowser ? 'bg-indigo-600' : 'bg-gray-400 dark:bg-gray-800'} relative inline-flex h-[20px] w-[44px] shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus-visible:ring-2 focus-visible:ring-white/75`, ...testId(TEST_IDS.ADVANCED_MODE_SWITCH), children: [_jsx("span", { className: "sr-only", children: "Use setting" }), _jsx("span", { "aria-hidden": "true", className: `${advancedModeForQueryBrowser ? 'translate-x-6' : 'translate-x-0'} pointer-events-none inline-block h-[16px] w-[16px] transform rounded-full bg-white shadow-lg ring-0 transition duration-200 ease-in-out` })] }), _jsx("label", { className: "text-xs", ...testId(TEST_IDS.QUERY_MODE_LABEL), children: "Advanced Mode" })] }))] }), viewComponent?.createViewComponent] }), viewComponent?.disableExplorativeQuerying === true &&
|
|
28
30
|
viewComponent?.labelnames !== undefined &&
|
|
29
|
-
viewComponent?.labelnames.length >= 1 ? (_jsx(ViewMatchers, { labelNames: viewComponent.labelnames, setMatchersString: setMatchersString, profileType: selectedProfileName, runQuery: setQueryExpression, currentQuery: query, queryClient: queryClient, start: timeRangeSelection.getFromMs(), end: timeRangeSelection.getToMs() })) : advancedModeForQueryBrowser ? (_jsx(MatchersInput, { setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query, profileType: selectedProfileName, queryClient: queryClient, start: timeRangeSelection.getFromMs(), end: timeRangeSelection.getToMs() })) : (_jsx(SimpleMatchers, { setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query, profileType: selectedProfileName, queryBrowserRef: queryBrowserRef, queryClient: queryClient, start: timeRangeSelection.getFromMs(), end: timeRangeSelection.getToMs() }
|
|
31
|
+
viewComponent?.labelnames.length >= 1 ? (_jsx(ViewMatchers, { labelNames: viewComponent.labelnames, setMatchersString: setMatchersString, profileType: selectedProfileName, runQuery: setQueryExpression, currentQuery: query, queryClient: queryClient, start: timeRangeSelection.getFromMs(), end: timeRangeSelection.getToMs() })) : advancedModeForQueryBrowser ? (_jsx(MatchersInput, { setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query, profileType: selectedProfileName, queryClient: queryClient, start: timeRangeSelection.getFromMs(), end: timeRangeSelection.getToMs() })) : (_jsx(SimpleMatchers, { setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query, profileType: selectedProfileName, queryBrowserRef: queryBrowserRef, queryClient: queryClient, start: timeRangeSelection.getFromMs(), end: timeRangeSelection.getToMs(), searchExecutedTimestamp: searchExecutedTimestamp }))] }), showSumBySelector && (_jsxs("div", { ...testId(TEST_IDS.SUM_BY_CONTAINER), children: [_jsx("div", { className: "mb-0.5 mt-1.5 flex items-center justify-between", children: _jsx("label", { className: "text-xs", ...testId(TEST_IDS.SUM_BY_LABEL), children: "Sum by" }) }), _jsx(Select, { id: "h-sum-by-selector", "data-testid": testId(TEST_IDS.SUM_BY_SELECT)['data-testid'], defaultValue: [], isMulti: true, isClearable: false, name: "colors", options: labels.map(label => ({ label, value: label })), className: "parca-select-container text-sm w-full max-w-80", classNamePrefix: "parca-select", value: (sumBySelection ?? []).map(sumBy => ({ label: sumBy, value: sumBy })), onChange: newValue => {
|
|
30
32
|
setUserSumBySelection(newValue.map(option => option.value));
|
|
31
33
|
}, placeholder: "Labels...", styles: {
|
|
32
34
|
indicatorSeparator: () => ({ display: 'none' }),
|
|
@@ -51,6 +53,7 @@ export function QueryControls({ showProfileTypeSelector, profileTypesData, profi
|
|
|
51
53
|
}
|
|
52
54
|
} })] })), _jsx(DateTimeRangePicker, { onRangeSelection: setTimeRangeSelection, range: timeRangeSelection, timezone: timezone, ...testId(TEST_IDS.DATE_TIME_RANGE_PICKER) }), _jsxs("div", { children: [_jsx("label", { className: "text-xs", ...testId(TEST_IDS.SEARCH_BUTTON_LABEL), children: "\u00A0" }), _jsx(Button, { disabled: searchDisabled, onClick: (e) => {
|
|
53
55
|
e.preventDefault();
|
|
56
|
+
setSearchExecutedTimestamp(Date.now());
|
|
54
57
|
setQueryExpression(true);
|
|
55
58
|
}, id: "h-matcher-search-button", ...testId(TEST_IDS.SEARCH_BUTTON), children: "Search" })] })] }));
|
|
56
59
|
}
|
|
@@ -6,6 +6,10 @@ interface MultiLevelDropdownProps {
|
|
|
6
6
|
groupBy: string[];
|
|
7
7
|
toggleGroupBy: (key: string) => void;
|
|
8
8
|
isTableVizOnly: boolean;
|
|
9
|
+
alignFunctionName: string;
|
|
10
|
+
setAlignFunctionName: (align: string) => void;
|
|
11
|
+
colorBy: string;
|
|
12
|
+
setColorBy: (colorBy: string) => void;
|
|
9
13
|
}
|
|
10
14
|
declare const MultiLevelDropdown: React.FC<MultiLevelDropdownProps>;
|
|
11
15
|
export default MultiLevelDropdown;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultiLevelDropdown.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/Toolbars/MultiLevelDropdown.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAQtE,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAkK1C,UAAU,uBAAuB;IAC/B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,cAAc,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"MultiLevelDropdown.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/Toolbars/MultiLevelDropdown.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAQtE,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAkK1C,UAAU,uBAAuB;IAC/B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,cAAc,EAAE,OAAO,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACvC;AAED,QAAA,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAsPzD,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
|
|
@@ -70,14 +70,13 @@ const MenuItem = ({ label, items, onclick, onSelect, path = [], id, closeDropdow
|
|
|
70
70
|
closeDropdown();
|
|
71
71
|
}, path: [...path, label], closeDropdown: closeDropdown, isNested: true, activeValueForSortBy: activeValueForSortBy, activeValueForColorBy: activeValueForColorBy, activeValuesForLevel: activeValuesForLevel }, index))) }))] })) }) }));
|
|
72
72
|
};
|
|
73
|
-
const MultiLevelDropdown = ({ onSelect, profileType, groupBy, toggleGroupBy, isTableVizOnly, }) => {
|
|
73
|
+
const MultiLevelDropdown = ({ onSelect, profileType, groupBy, toggleGroupBy, isTableVizOnly, alignFunctionName, setAlignFunctionName, colorBy, setColorBy, }) => {
|
|
74
74
|
const dropdownRef = useRef(null);
|
|
75
75
|
const [shouldOpenLeft, setShouldOpenLeft] = useState(false);
|
|
76
76
|
const [storeSortBy] = useURLState('sort_by', {
|
|
77
77
|
defaultValue: FIELD_FUNCTION_NAME,
|
|
78
78
|
});
|
|
79
79
|
const [colorStackLegend, setStoreColorStackLegend] = useURLState('color_stack_legend');
|
|
80
|
-
const [colorBy, setColorBy] = useURLState('color_by');
|
|
81
80
|
const [hiddenBinaries, setHiddenBinaries] = useURLState('hidden_binaries', {
|
|
82
81
|
defaultValue: [],
|
|
83
82
|
alwaysReturnArray: true,
|
|
@@ -85,8 +84,7 @@ const MultiLevelDropdown = ({ onSelect, profileType, groupBy, toggleGroupBy, isT
|
|
|
85
84
|
const { compareMode } = useProfileViewContext();
|
|
86
85
|
const [colorProfileName] = useUserPreference(USER_PREFERENCES.FLAMEGRAPH_COLOR_PROFILE.key);
|
|
87
86
|
const isColorStackLegendEnabled = colorStackLegend === 'true';
|
|
88
|
-
const
|
|
89
|
-
const isLeftAligned = alignFunctionName === 'left' || alignFunctionName === undefined;
|
|
87
|
+
const isLeftAligned = alignFunctionName === 'left';
|
|
90
88
|
// By default, we want delta profiles (CPU) to be relatively compared.
|
|
91
89
|
// For non-delta profiles, like goroutines or memory, we want the profiles to be compared absolutely.
|
|
92
90
|
const compareAbsoluteDefault = profileType?.delta === false ? 'true' : 'false';
|
|
@@ -22,6 +22,10 @@ export interface VisualisationToolbarProps {
|
|
|
22
22
|
setGroupByLabels: (labels: string[]) => void;
|
|
23
23
|
showVisualizationSelector?: boolean;
|
|
24
24
|
sandwichFunctionName?: string;
|
|
25
|
+
alignFunctionName: string;
|
|
26
|
+
setAlignFunctionName: (align: string) => void;
|
|
27
|
+
colorBy: string;
|
|
28
|
+
setColorBy: (colorBy: string) => void;
|
|
25
29
|
}
|
|
26
30
|
export interface TableToolbarProps {
|
|
27
31
|
profileType?: ProfileType;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/Toolbars/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,EAAE,EAAC,MAAM,OAAO,CAAC;AAIzB,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAG1C,OAAO,EAAC,gBAAgB,EAAC,MAAM,kDAAkD,CAAC;AAClF,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAUrD,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAClD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,6BAA6B,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAChD,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,oBAAoB,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/Toolbars/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,EAAE,EAAC,MAAM,OAAO,CAAC;AAIzB,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAG1C,OAAO,EAAC,gBAAgB,EAAC,MAAM,kDAAkD,CAAC;AAClF,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAUrD,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAClD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,6BAA6B,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAChD,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;CACnD;AAED,MAAM,WAAW,8BAA8B;IAC7C,yBAAyB,EAAE,MAAM,IAAI,CAAC;IACtC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CAQ9C,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,sBAAsB,CAkBxD,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,EAAE,CAAC,8BAA8B,CAmBxE,CAAC;AAMF,eAAO,MAAM,oBAAoB,EAAE,EAAE,CAAC,yBAAyB,CAiG9D,CAAC"}
|
|
@@ -20,7 +20,7 @@ export const SandwichFlameGraphToolbar = ({ resetSandwichFunctionName, sandwichF
|
|
|
20
20
|
return (_jsx(_Fragment, { children: _jsx("div", { className: "flex w-full gap-2 items-end justify-between", children: _jsx(Button, { color: "neutral", onClick: () => resetSandwichFunctionName(), className: "w-auto", variant: "neutral", disabled: sandwichFunctionName === undefined || sandwichFunctionName.length === 0, children: "Reset view" }) }) }));
|
|
21
21
|
};
|
|
22
22
|
const Divider = () => (_jsx("div", { className: "border-t mt-4 border-gray-200 dark:border-gray-700 h-[1px] w-full pb-4" }));
|
|
23
|
-
export const VisualisationToolbar = ({ groupBy, toggleGroupBy, groupByLabels, setGroupByLabels, profileType, profileSource, queryClient, onDownloadPProf, pprofdownloading, profileViewExternalSubActions, curPath, setNewCurPath, total, filtered, showVisualizationSelector = true, }) => {
|
|
23
|
+
export const VisualisationToolbar = ({ groupBy, toggleGroupBy, groupByLabels, setGroupByLabels, profileType, profileSource, queryClient, onDownloadPProf, pprofdownloading, profileViewExternalSubActions, curPath, setNewCurPath, total, filtered, showVisualizationSelector = true, alignFunctionName, setAlignFunctionName, colorBy, setColorBy, }) => {
|
|
24
24
|
const { dashboardItems } = useDashboard();
|
|
25
25
|
const isTableViz = dashboardItems?.includes('table');
|
|
26
26
|
const isTableVizOnly = dashboardItems?.length === 1 && isTableViz;
|
|
@@ -32,5 +32,5 @@ export const VisualisationToolbar = ({ groupBy, toggleGroupBy, groupByLabels, se
|
|
|
32
32
|
fields: groupBy ?? [],
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
|
-
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex w-full justify-between items-start gap-2", children: [_jsxs("div", { className: "flex gap-2 items-start", children: [isGraphViz && (_jsxs(_Fragment, { children: [_jsx(GroupByDropdown, { groupBy: groupBy, labels: groupByLabels, setGroupByLabels: setGroupByLabels }), _jsx(InvertCallStack, {})] })), _jsxs("div", { className: "flex mt-5", children: [_jsx(ProfileFilters, {}), profileViewExternalSubActions != null ? profileViewExternalSubActions : null] })] }), _jsxs("div", { className: "flex gap-2 mt-5", children: [_jsx(MultiLevelDropdown, { groupBy: groupBy, toggleGroupBy: toggleGroupBy, profileType: profileType, onSelect: () => { }, isTableVizOnly: isTableVizOnly }), _jsx(ShareButton, { profileSource: profileSource, queryClient: queryClient, queryRequest: req, onDownloadPProf: onDownloadPProf, pprofdownloading: pprofdownloading ?? false, profileViewExternalSubActions: profileViewExternalSubActions }), showVisualizationSelector ? _jsx(ViewSelector, { profileSource: profileSource }) : null] })] }), isGraphVizOnly && (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(FlameGraphToolbar, { curPath: curPath, setNewCurPath: setNewCurPath })] })), isTableVizOnly && (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(TableToolbar, { profileType: profileType, total: total, filtered: filtered })] }))] }));
|
|
35
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex w-full justify-between items-start gap-2", children: [_jsxs("div", { className: "flex gap-2 items-start", children: [isGraphViz && (_jsxs(_Fragment, { children: [_jsx(GroupByDropdown, { groupBy: groupBy, labels: groupByLabels, setGroupByLabels: setGroupByLabels }), _jsx(InvertCallStack, {})] })), _jsxs("div", { className: "flex mt-5", children: [_jsx(ProfileFilters, {}), profileViewExternalSubActions != null ? profileViewExternalSubActions : null] })] }), _jsxs("div", { className: "flex gap-2 mt-5", children: [_jsx(MultiLevelDropdown, { groupBy: groupBy, toggleGroupBy: toggleGroupBy, profileType: profileType, onSelect: () => { }, isTableVizOnly: isTableVizOnly, alignFunctionName: alignFunctionName, setAlignFunctionName: setAlignFunctionName, colorBy: colorBy, setColorBy: setColorBy }), _jsx(ShareButton, { profileSource: profileSource, queryClient: queryClient, queryRequest: req, onDownloadPProf: onDownloadPProf, pprofdownloading: pprofdownloading ?? false, profileViewExternalSubActions: profileViewExternalSubActions }), showVisualizationSelector ? _jsx(ViewSelector, { profileSource: profileSource }) : null] })] }), isGraphVizOnly && (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(FlameGraphToolbar, { curPath: curPath, setNewCurPath: setNewCurPath })] })), isTableVizOnly && (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(TableToolbar, { profileType: profileType, total: total, filtered: filtered })] }))] }));
|
|
36
36
|
};
|
|
@@ -12,5 +12,7 @@ export declare const useVisualizationState: () => {
|
|
|
12
12
|
sandwichFunctionName: string | undefined;
|
|
13
13
|
setSandwichFunctionName: (sandwichFunctionName: string | undefined) => void;
|
|
14
14
|
resetSandwichFunctionName: () => void;
|
|
15
|
+
alignFunctionName: string;
|
|
16
|
+
setAlignFunctionName: (align: string) => void;
|
|
15
17
|
};
|
|
16
18
|
//# sourceMappingURL=useVisualizationState.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useVisualizationState.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useVisualizationState.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useVisualizationState.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useVisualizationState.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAC,gBAAgB,EAAC,MAAM,+CAA+C,CAAC;AAG/E,eAAO,MAAM,qBAAqB,QAAO;IACvC,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,eAAe,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IACpD,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACrC,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,uBAAuB,EAAE,CAAC,oBAAoB,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IAC5E,yBAAyB,EAAE,MAAM,IAAI,CAAC;IACtC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CA0G/C,CAAC"}
|
|
@@ -12,16 +12,24 @@
|
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
import { useCallback, useMemo } from 'react';
|
|
14
14
|
import { JSONParser, JSONSerializer, useURLState, useURLStateCustom } from '@parca/components';
|
|
15
|
+
import { USER_PREFERENCES, useUserPreference } from '@parca/hooks';
|
|
15
16
|
import { FIELD_FUNCTION_FILE_NAME, FIELD_FUNCTION_NAME, FIELD_LABELS, FIELD_LOCATION_ADDRESS, FIELD_MAPPING_FILE, } from '../../ProfileFlameGraph/FlameGraphArrow';
|
|
16
17
|
import { useResetFlameGraphState } from './useResetFlameGraphState';
|
|
17
18
|
export const useVisualizationState = () => {
|
|
19
|
+
const [colorByPreference, setColorByPreference] = useUserPreference(USER_PREFERENCES.COLOR_BY.key);
|
|
20
|
+
const [alignFunctionNamePreference, setAlignFunctionNamePreference] = useUserPreference(USER_PREFERENCES.ALIGN_FUNCTION_NAME.key);
|
|
18
21
|
const [curPathArrow, setCurPathArrow] = useURLStateCustom('cur_path', {
|
|
19
22
|
parse: (JSONParser),
|
|
20
23
|
stringify: JSONSerializer,
|
|
21
24
|
defaultValue: '[]',
|
|
22
25
|
});
|
|
23
26
|
const [colorStackLegend] = useURLState('color_stack_legend');
|
|
24
|
-
const [colorBy,
|
|
27
|
+
const [colorBy, setStoreColorBy] = useURLState('color_by', {
|
|
28
|
+
defaultValue: colorByPreference,
|
|
29
|
+
});
|
|
30
|
+
const [alignFunctionName, setStoreAlignFunctionName] = useURLState('align_function_name', {
|
|
31
|
+
defaultValue: alignFunctionNamePreference,
|
|
32
|
+
});
|
|
25
33
|
const [groupBy, setStoreGroupBy] = useURLState('group_by', {
|
|
26
34
|
defaultValue: [FIELD_FUNCTION_NAME],
|
|
27
35
|
alwaysReturnArray: true,
|
|
@@ -54,6 +62,14 @@ export const useVisualizationState = () => {
|
|
|
54
62
|
const resetSandwichFunctionName = useCallback(() => {
|
|
55
63
|
setSandwichFunctionName(undefined);
|
|
56
64
|
}, [setSandwichFunctionName]);
|
|
65
|
+
const setColorBy = useCallback((value) => {
|
|
66
|
+
setStoreColorBy(value);
|
|
67
|
+
setColorByPreference(value);
|
|
68
|
+
}, [setStoreColorBy, setColorByPreference]);
|
|
69
|
+
const setAlignFunctionName = useCallback((value) => {
|
|
70
|
+
setStoreAlignFunctionName(value);
|
|
71
|
+
setAlignFunctionNamePreference(value);
|
|
72
|
+
}, [setStoreAlignFunctionName, setAlignFunctionNamePreference]);
|
|
57
73
|
return {
|
|
58
74
|
curPathArrow,
|
|
59
75
|
setCurPathArrow,
|
|
@@ -67,5 +83,7 @@ export const useVisualizationState = () => {
|
|
|
67
83
|
sandwichFunctionName,
|
|
68
84
|
setSandwichFunctionName,
|
|
69
85
|
resetSandwichFunctionName,
|
|
86
|
+
alignFunctionName: alignFunctionName ?? 'left',
|
|
87
|
+
setAlignFunctionName,
|
|
70
88
|
};
|
|
71
89
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileView/index.tsx"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAC,gBAAgB,EAAoB,MAAM,uBAAuB,CAAC;AAE/E,eAAO,MAAM,WAAW,GAAI,iMAczB,gBAAgB,KAAG,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileView/index.tsx"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAC,gBAAgB,EAAoB,MAAM,uBAAuB,CAAC;AAE/E,eAAO,MAAM,WAAW,GAAI,iMAczB,gBAAgB,KAAG,GAAG,CAAC,OAkIzB,CAAC"}
|
|
@@ -26,7 +26,7 @@ import { useVisualizationState } from './hooks/useVisualizationState';
|
|
|
26
26
|
export const ProfileView = ({ total, filtered, flamegraphData, flamechartData, topTableData, sourceData, profileSource, queryClient, onDownloadPProf, pprofDownloading, compare, showVisualizationSelector, sandwichData, }) => {
|
|
27
27
|
const { timezone, perf, profileViewExternalMainActions, preferencesModal, profileViewExternalSubActions, } = useParcaContext();
|
|
28
28
|
const { ref, dimensions } = useContainerDimensions();
|
|
29
|
-
const { curPathArrow, setCurPathArrow, colorStackLegend, colorBy, groupBy, toggleGroupBy, setGroupByLabels, sandwichFunctionName, resetSandwichFunctionName, } = useVisualizationState();
|
|
29
|
+
const { curPathArrow, setCurPathArrow, colorStackLegend, colorBy, setColorBy, groupBy, toggleGroupBy, setGroupByLabels, sandwichFunctionName, resetSandwichFunctionName, alignFunctionName, setAlignFunctionName, } = useVisualizationState();
|
|
30
30
|
const { colorMappings } = useProfileMetadata({
|
|
31
31
|
flamegraphArrow: flamegraphData.arrow,
|
|
32
32
|
metadataMappingFiles: flamegraphData.metadataMappingFiles,
|
|
@@ -61,5 +61,5 @@ export const ProfileView = ({ total, filtered, flamegraphData, flamechartData, t
|
|
|
61
61
|
sandwich: (_jsx(SandwichFlameGraphToolbar, { resetSandwichFunctionName: resetSandwichFunctionName, sandwichFunctionName: sandwichFunctionName })),
|
|
62
62
|
};
|
|
63
63
|
const hasProfileSource = profileSource !== undefined && profileSource.toString(timezone) !== '';
|
|
64
|
-
return (_jsx(KeyDownProvider, { children: _jsx(ProfileViewContextProvider, { value: { profileSource, compareMode }, children: _jsxs(DashboardProvider, { children: [_jsx(ProfileHeader, { profileSourceString: profileSource?.toString(timezone), hasProfileSource: hasProfileSource, externalMainActions: profileViewExternalMainActions }), _jsx(VisualisationToolbar, { groupBy: groupBy, toggleGroupBy: toggleGroupBy, hasProfileSource: hasProfileSource, pprofdownloading: pprofDownloading, profileSource: profileSource, queryClient: queryClient, onDownloadPProf: onDownloadPProf, curPath: curPathArrow, setNewCurPath: setCurPathArrow, profileType: profileSource?.ProfileType(), total: total, filtered: filtered, groupByLabels: flamegraphData.metadataLabels ?? [], preferencesModal: preferencesModal, profileViewExternalSubActions: profileViewExternalSubActions, setGroupByLabels: setGroupByLabels, showVisualizationSelector: showVisualizationSelector, sandwichFunctionName: sandwichFunctionName }), isColorStackLegendEnabled && (_jsx(ColorStackLegend, { compareMode: compareMode, mappings: colorMappings, loading: flamegraphData.metadataLoading })), _jsx("div", { className: "w-full", ref: ref, children: _jsx(DashboardLayout, { getDashboardItemByType: getDashboardItemByType, actionButtons: actionButtons }) })] }) }) }));
|
|
64
|
+
return (_jsx(KeyDownProvider, { children: _jsx(ProfileViewContextProvider, { value: { profileSource, compareMode }, children: _jsxs(DashboardProvider, { children: [_jsx(ProfileHeader, { profileSourceString: profileSource?.toString(timezone), hasProfileSource: hasProfileSource, externalMainActions: profileViewExternalMainActions }), _jsx(VisualisationToolbar, { groupBy: groupBy, toggleGroupBy: toggleGroupBy, hasProfileSource: hasProfileSource, pprofdownloading: pprofDownloading, profileSource: profileSource, queryClient: queryClient, onDownloadPProf: onDownloadPProf, curPath: curPathArrow, setNewCurPath: setCurPathArrow, profileType: profileSource?.ProfileType(), total: total, filtered: filtered, groupByLabels: flamegraphData.metadataLabels ?? [], preferencesModal: preferencesModal, profileViewExternalSubActions: profileViewExternalSubActions, setGroupByLabels: setGroupByLabels, showVisualizationSelector: showVisualizationSelector, sandwichFunctionName: sandwichFunctionName, alignFunctionName: alignFunctionName, setAlignFunctionName: setAlignFunctionName, colorBy: colorBy, setColorBy: setColorBy }), isColorStackLegendEnabled && (_jsx(ColorStackLegend, { compareMode: compareMode, mappings: colorMappings, loading: flamegraphData.metadataLoading })), _jsx("div", { className: "w-full", ref: ref, children: _jsx(DashboardLayout, { getDashboardItemByType: getDashboardItemByType, actionButtons: actionButtons }) })] }) }) }));
|
|
65
65
|
};
|
|
@@ -31,6 +31,9 @@ interface CustomSelectProps {
|
|
|
31
31
|
searchable?: boolean;
|
|
32
32
|
onButtonClick?: () => void;
|
|
33
33
|
editable?: boolean;
|
|
34
|
+
refetchLabelValues?: () => void;
|
|
35
|
+
showLoadingInButton?: boolean;
|
|
36
|
+
hasRefreshButton?: boolean;
|
|
34
37
|
}
|
|
35
38
|
declare const CustomSelect: React.FC<CustomSelectProps>;
|
|
36
39
|
export default CustomSelect;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../src/SimpleMatchers/Select.tsx"],"names":[],"mappings":"AAaA,OAAO,
|
|
1
|
+
{"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../src/SimpleMatchers/Select.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAQtE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC;IACpB,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,aAAa,CAAC;CACxB;AAED,MAAM,WAAW,eAAgB,SAAQ,UAAU;IACjD,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB;AAED,UAAU,iBAAiB;IACzB,KAAK,EAAE,iBAAiB,EAAE,GAAG,UAAU,EAAE,CAAC;IAC1C,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAsV7C,CAAC;AAkDF,eAAe,YAAY,CAAC"}
|
|
@@ -11,20 +11,32 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
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 { useEffect, useRef, useState } from 'react';
|
|
14
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
15
15
|
import { Icon } from '@iconify/react';
|
|
16
16
|
import cx from 'classnames';
|
|
17
17
|
import levenshtein from 'fast-levenshtein';
|
|
18
18
|
import { Button, DividerWithLabel, useParcaContext } from '@parca/components';
|
|
19
|
-
const CustomSelect = ({ items: itemsProp, selectedKey, onSelection, placeholder = 'Select an item', width, className = '', loading, primary = false, disabled = false, icon, id, optionsClassname = '', searchable = false, onButtonClick, editable = false, }) => {
|
|
19
|
+
const CustomSelect = ({ items: itemsProp, selectedKey, onSelection, placeholder = 'Select an item', width, className = '', loading, primary = false, disabled = false, icon, id, optionsClassname = '', searchable = false, onButtonClick, editable = false, refetchLabelValues, showLoadingInButton = false, hasRefreshButton = false, }) => {
|
|
20
20
|
const { loader } = useParcaContext();
|
|
21
21
|
const [isOpen, setIsOpen] = useState(false);
|
|
22
22
|
const [focusedIndex, setFocusedIndex] = useState(-1);
|
|
23
23
|
const [searchTerm, setSearchTerm] = useState('');
|
|
24
|
+
const [isRefetching, setIsRefetching] = useState(false);
|
|
24
25
|
const containerRef = useRef(null);
|
|
25
26
|
const optionsRef = useRef(null);
|
|
26
27
|
const searchInputRef = useRef(null);
|
|
27
28
|
const optionRefs = useRef([]);
|
|
29
|
+
const handleRefetch = useCallback(async () => {
|
|
30
|
+
if (refetchLabelValues == null || isRefetching)
|
|
31
|
+
return;
|
|
32
|
+
setIsRefetching(true);
|
|
33
|
+
try {
|
|
34
|
+
await refetchLabelValues();
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
setIsRefetching(false);
|
|
38
|
+
}
|
|
39
|
+
}, [refetchLabelValues, isRefetching]);
|
|
28
40
|
let items = [];
|
|
29
41
|
if (itemsProp[0] != null && 'type' in itemsProp[0]) {
|
|
30
42
|
items = itemsProp.flatMap(item => item.values.map(v => ({ ...v, type: item.type })));
|
|
@@ -124,6 +136,9 @@ const CustomSelect = ({ items: itemsProp, selectedKey, onSelection, placeholder
|
|
|
124
136
|
const defaultStyles = 'bg-white dark:bg-gray-900 dark:border-gray-600';
|
|
125
137
|
const primaryStyles = 'text-gray-100 dark:gray-900 bg-indigo-600 border-indigo-500 font-medium py-2 px-4';
|
|
126
138
|
const renderSelection = (selection) => {
|
|
139
|
+
if (showLoadingInButton && loading === true && selectedKey === '') {
|
|
140
|
+
return (_jsxs("span", { className: "flex items-center gap-2", "data-testid": "label-value-loading-indicator", children: [_jsx(Icon, { icon: "svg-spinners:ring-resize", className: "w-4 h-4" }), _jsx("span", { children: "Loading..." })] }));
|
|
141
|
+
}
|
|
127
142
|
if (editable) {
|
|
128
143
|
return typeof selection === 'string' && selection.length > 0 ? selection : placeholder;
|
|
129
144
|
}
|
|
@@ -158,10 +173,18 @@ const CustomSelect = ({ items: itemsProp, selectedKey, onSelection, placeholder
|
|
|
158
173
|
return acc;
|
|
159
174
|
}, [])
|
|
160
175
|
.sort((a, b) => a.values.length - b.values.length);
|
|
161
|
-
return (_jsxs("div", { ref: containerRef, className: "relative", onKeyDown: handleKeyDown, onClick: onButtonClick, children: [_jsxs("div", { id: id, onClick: () => !disabled && setIsOpen(!isOpen), className: cx(styles, width !== undefined ? `w-${width}` : 'w-full', disabled ? 'cursor-not-allowed opacity-50 pointer-events-none' : '', primary ? primaryStyles : defaultStyles, { [className]: className.length > 0 }), tabIndex: 0, role: "button", "aria-haspopup": "listbox", "aria-expanded": isOpen, children: [_jsx("div", { className: cx(icon != null ? '' : 'block overflow-x-hidden text-ellipsis whitespace-nowrap'), children: renderSelection(selection) }), _jsx("div", { className: cx(icon != null ? '' : 'pointer-events-none text-gray-400'), children: icon ?? _jsx(Icon, { icon: "heroicons:chevron-up-down-20-solid", "aria-hidden": "true" }) })] }), isOpen && (
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
176
|
+
return (_jsxs("div", { ref: containerRef, className: "relative", onKeyDown: handleKeyDown, onClick: onButtonClick, children: [_jsxs("div", { id: id, onClick: () => !disabled && setIsOpen(!isOpen), className: cx(styles, width !== undefined ? `w-${width}` : 'w-full', disabled ? 'cursor-not-allowed opacity-50 pointer-events-none' : '', primary ? primaryStyles : defaultStyles, { [className]: className.length > 0 }), tabIndex: 0, role: "button", "aria-haspopup": "listbox", "aria-expanded": isOpen, children: [_jsx("div", { className: cx(icon != null ? '' : 'block overflow-x-hidden text-ellipsis whitespace-nowrap'), children: renderSelection(selection) }), _jsx("div", { className: cx(icon != null ? '' : 'pointer-events-none text-gray-400'), children: icon ?? _jsx(Icon, { icon: "heroicons:chevron-up-down-20-solid", "aria-hidden": "true" }) })] }), isOpen && (_jsx("div", { ref: optionsRef, className: cx('absolute z-50 mt-1 pt-0 max-h-[50vh] w-max overflow-auto rounded-md bg-gray-50 py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:ring-white dark:ring-opacity-20 sm:text-sm', { [optionsClassname]: optionsClassname.length > 0 }), role: "listbox", children: _jsxs("div", { className: cx('relative', { 'pb-6': hasRefreshButton }), children: [searchable && (_jsx("div", { className: "sticky z-10 top-[-5px] w-auto max-w-full", children: _jsx("div", { className: "flex flex-col", children: editable ? (_jsxs(_Fragment, { children: [_jsx("textarea", { ref: searchInputRef, className: "w-full px-4 py-2 text-sm border-b border-gray-200 rounded-none ring-0 outline-none bg-gray-50 dark:bg-gray-800 dark:text-white min-h-[50px]", placeholder: "Type a RegEx to add", value: searchTerm, onChange: e => setSearchTerm(e.target.value), onFocus: e => moveCaretToEnd(e) }), editable && searchTerm.length > 0 && (_jsx("div", { className: "p-2 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800", children: _jsx(Button, { variant: "primary", className: "w-full h-[30px]", onClick: () => {
|
|
177
|
+
onSelection(searchTerm);
|
|
178
|
+
setIsOpen(false);
|
|
179
|
+
}, children: "Add" }) }))] })) : (_jsx("input", { ref: searchInputRef, type: "text", className: "w-full px-4 h-[45px] text-sm border-none rounded-none ring-0 outline-none bg-gray-50 dark:bg-gray-800 dark:text-white", placeholder: "Search...", value: searchTerm, onChange: e => setSearchTerm(e.target.value) })) }) })), refetchLabelValues !== undefined && loading !== true && (_jsx("div", { className: "absolute w-full bottom-0 px-3 bg-gray-50 dark:bg-gray-800", children: _jsxs("button", { onClick: e => {
|
|
180
|
+
e.preventDefault();
|
|
181
|
+
e.stopPropagation();
|
|
182
|
+
void handleRefetch();
|
|
183
|
+
}, disabled: isRefetching, className: cx('p-1 flex items-center gap-1 rounded-full transition-all duration-200 w-full justify-center', isRefetching
|
|
184
|
+
? 'cursor-wait opacity-50'
|
|
185
|
+
: 'hover:bg-gray-200 dark:hover:bg-gray-700 cursor-pointer'), title: "Refresh label values", type: "button", "data-testid": "label-value-refresh-button", children: [_jsx(Icon, { icon: "system-uicons:reset", className: cx('w-3 h-3 text-gray-500 dark:text-gray-400', isRefetching && 'animate-spin') }), _jsx("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Refresh results" })] }) })), loading === true ? (_jsx("div", { className: "w-[270px]", children: loader })) : groupedFilteredItems.length === 0 ? (_jsx("div", { className: "px-4 py-3 text-sm text-gray-500 dark:text-gray-400 text-center", "data-testid": "label-value-no-results", children: "No values found" })) : (groupedFilteredItems.map(group => (_jsxs(_Fragment, { children: [groupedFilteredItems.length > 1 &&
|
|
186
|
+
groupedFilteredItems.every(g => g.type !== '') &&
|
|
187
|
+
group.type !== '' ? (_jsx("div", { className: "pl-2", children: _jsx(DividerWithLabel, { label: group.type }) })) : null, group.values.map((item, index) => (_jsx(OptionItem, { item: item, index: index, optionRefs: optionRefs, focusedIndex: focusedIndex, selectedKey: selectedKey, handleSelection: handleSelection }, item.key)))] }))))] }) }))] }));
|
|
165
188
|
};
|
|
166
189
|
const OptionItem = ({ item, optionRefs, index, focusedIndex, selectedKey, handleSelection, }) => {
|
|
167
190
|
return (_jsxs("div", { ref: el => {
|
|
@@ -10,6 +10,7 @@ interface Props {
|
|
|
10
10
|
queryBrowserRef: React.RefObject<HTMLDivElement>;
|
|
11
11
|
start?: number;
|
|
12
12
|
end?: number;
|
|
13
|
+
searchExecutedTimestamp?: number;
|
|
13
14
|
}
|
|
14
15
|
export declare const transformLabelsForSelect: (labelNames: string[]) => SelectItem[];
|
|
15
16
|
export default function SimpleMathersWithProvider(props: Props): JSX.Element;
|
|
@@ -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,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;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,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;AAMpC,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;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AAoBD,eAAO,MAAM,wBAAwB,GAAI,YAAY,MAAM,EAAE,KAAG,UAAU,EAQzE,CAAC;AA2cF,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,KAAK,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAoB3E"}
|