@parca/profile 0.19.80 → 0.19.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/MatchersInput/index.d.ts +2 -34
- package/dist/MatchersInput/index.d.ts.map +1 -1
- package/dist/MatchersInput/index.js +14 -91
- package/dist/MetricsGraph/index.d.ts.map +1 -1
- package/dist/MetricsGraph/index.js +13 -1
- package/dist/ProfileMetricsGraph/index.d.ts.map +1 -1
- package/dist/ProfileMetricsGraph/index.js +24 -33
- package/dist/ProfileSelector/MetricsGraphSection.d.ts +2 -9
- package/dist/ProfileSelector/MetricsGraphSection.d.ts.map +1 -1
- package/dist/ProfileSelector/MetricsGraphSection.js +3 -38
- package/dist/ProfileSelector/index.d.ts +1 -29
- package/dist/ProfileSelector/index.d.ts.map +1 -1
- package/dist/ProfileSelector/index.js +12 -9
- package/dist/ProfileView/components/ProfileFilters/filterPresets.d.ts.map +1 -1
- package/dist/ProfileView/components/ProfileFilters/filterPresets.js +15 -3
- package/dist/QueryControls/index.d.ts +42 -0
- package/dist/QueryControls/index.d.ts.map +1 -0
- package/dist/{ProfileSelector/QueryControls.js → QueryControls/index.js} +16 -13
- package/dist/SimpleMatchers/Select.js +1 -1
- package/dist/SimpleMatchers/index.d.ts +2 -11
- package/dist/SimpleMatchers/index.d.ts.map +1 -1
- package/dist/SimpleMatchers/index.js +34 -45
- package/dist/ViewMatchers/index.d.ts +0 -9
- package/dist/ViewMatchers/index.d.ts.map +1 -1
- package/dist/ViewMatchers/index.js +20 -12
- package/dist/contexts/LabelsQueryProvider.d.ts +35 -0
- package/dist/contexts/LabelsQueryProvider.d.ts.map +1 -0
- package/dist/contexts/LabelsQueryProvider.js +70 -0
- package/dist/contexts/UnifiedLabelsContext.d.ts +37 -0
- package/dist/contexts/UnifiedLabelsContext.d.ts.map +1 -0
- package/dist/contexts/UnifiedLabelsContext.js +88 -0
- package/dist/contexts/utils.d.ts +10 -0
- package/dist/contexts/utils.d.ts.map +1 -0
- package/dist/contexts/utils.js +31 -0
- package/dist/hooks/useLabels.d.ts +23 -0
- package/dist/hooks/useLabels.d.ts.map +1 -0
- package/dist/hooks/useLabels.js +75 -0
- package/dist/hooks/useQueryState.d.ts +2 -0
- package/dist/hooks/useQueryState.d.ts.map +1 -1
- package/dist/hooks/useQueryState.js +18 -0
- package/dist/index.d.ts +9 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -3
- package/dist/styles.css +1 -1
- package/dist/useSumBy.js +1 -1
- package/package.json +2 -2
- package/src/MatchersInput/index.tsx +17 -163
- package/src/MetricsGraph/index.tsx +17 -1
- package/src/ProfileMetricsGraph/index.tsx +37 -102
- package/src/ProfileSelector/MetricsGraphSection.tsx +14 -115
- package/src/ProfileSelector/index.tsx +106 -109
- package/src/ProfileView/components/ProfileFilters/filterPresets.ts +15 -3
- package/src/{ProfileSelector/QueryControls.tsx → QueryControls/index.tsx} +66 -84
- package/src/SimpleMatchers/Select.tsx +1 -1
- package/src/SimpleMatchers/index.tsx +46 -85
- package/src/ViewMatchers/index.tsx +22 -30
- package/src/contexts/LabelsQueryProvider.tsx +142 -0
- package/src/contexts/UnifiedLabelsContext.tsx +155 -0
- package/src/contexts/utils.ts +43 -0
- package/src/hooks/useLabels.ts +121 -0
- package/src/hooks/useQueryState.ts +25 -0
- package/src/index.tsx +29 -3
- package/src/useSumBy.ts +1 -1
- package/dist/MetricsGraph/UtilizationMetrics/Throughput.d.ts +0 -29
- package/dist/MetricsGraph/UtilizationMetrics/Throughput.d.ts.map +0 -1
- package/dist/MetricsGraph/UtilizationMetrics/Throughput.js +0 -175
- package/dist/MetricsGraph/UtilizationMetrics/index.d.ts +0 -28
- package/dist/MetricsGraph/UtilizationMetrics/index.d.ts.map +0 -1
- package/dist/MetricsGraph/UtilizationMetrics/index.js +0 -186
- package/dist/ProfileSelector/QueryControls.d.ts +0 -43
- package/dist/ProfileSelector/QueryControls.d.ts.map +0 -1
- package/dist/contexts/MatchersInputLabelsContext.d.ts +0 -29
- package/dist/contexts/MatchersInputLabelsContext.d.ts.map +0 -1
- package/dist/contexts/MatchersInputLabelsContext.js +0 -79
- package/dist/contexts/SimpleMatchersLabelContext.d.ts +0 -25
- package/dist/contexts/SimpleMatchersLabelContext.d.ts.map +0 -1
- package/dist/contexts/SimpleMatchersLabelContext.js +0 -115
- package/dist/contexts/UtilizationLabelsContext.d.ts +0 -15
- package/dist/contexts/UtilizationLabelsContext.d.ts.map +0 -1
- package/dist/contexts/UtilizationLabelsContext.js +0 -25
- package/src/MetricsGraph/UtilizationMetrics/Throughput.tsx +0 -405
- package/src/MetricsGraph/UtilizationMetrics/index.tsx +0 -426
- package/src/contexts/MatchersInputLabelsContext.tsx +0 -141
- package/src/contexts/SimpleMatchersLabelContext.tsx +0 -189
- package/src/contexts/UtilizationLabelsContext.tsx +0 -45
|
@@ -97,19 +97,31 @@ export const filterPresets = [
|
|
|
97
97
|
type: 'frame',
|
|
98
98
|
field: 'binary',
|
|
99
99
|
matchType: 'not_contains',
|
|
100
|
-
value: '
|
|
100
|
+
value: 'libcudart.so',
|
|
101
101
|
},
|
|
102
102
|
{
|
|
103
103
|
type: 'frame',
|
|
104
104
|
field: 'binary',
|
|
105
105
|
matchType: 'not_contains',
|
|
106
|
-
value: '
|
|
106
|
+
value: 'libcuda.so',
|
|
107
107
|
},
|
|
108
108
|
{
|
|
109
109
|
type: 'frame',
|
|
110
110
|
field: 'binary',
|
|
111
111
|
matchType: 'not_contains',
|
|
112
|
-
value: '
|
|
112
|
+
value: 'libcudnn.so',
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
type: 'frame',
|
|
116
|
+
field: 'binary',
|
|
117
|
+
matchType: 'not_contains',
|
|
118
|
+
value: 'libcudnn_graph.so',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
type: 'frame',
|
|
122
|
+
field: 'binary',
|
|
123
|
+
matchType: 'not_contains',
|
|
124
|
+
value: 'libparcagpucupti.so',
|
|
113
125
|
},
|
|
114
126
|
],
|
|
115
127
|
},
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { RpcError } from '@protobuf-ts/runtime-rpc';
|
|
2
|
+
import { type SelectInstance } from 'react-select';
|
|
3
|
+
import { ProfileTypesResponse, QueryServiceClient } from '@parca/client';
|
|
4
|
+
import { DateTimeRange } from '@parca/components';
|
|
5
|
+
import { ProfileType, Query } from '@parca/parser';
|
|
6
|
+
interface QueryControlsProps {
|
|
7
|
+
queryClient: QueryServiceClient;
|
|
8
|
+
query: Query;
|
|
9
|
+
profileType: string | ProfileType;
|
|
10
|
+
timeRangeSelection: DateTimeRange;
|
|
11
|
+
setTimeRangeSelection: (range: DateTimeRange) => void;
|
|
12
|
+
setMatchersString: (matchers: string) => void;
|
|
13
|
+
setQueryExpression: (updateTs?: boolean) => void;
|
|
14
|
+
searchDisabled: boolean;
|
|
15
|
+
showProfileTypeSelector?: boolean;
|
|
16
|
+
showSumBySelector?: boolean;
|
|
17
|
+
showAdvancedMode?: boolean;
|
|
18
|
+
disableExplorativeQuerying?: boolean;
|
|
19
|
+
profileTypesData?: ProfileTypesResponse;
|
|
20
|
+
profileTypesLoading?: boolean;
|
|
21
|
+
selectedProfileName?: string;
|
|
22
|
+
setProfileName?: (name: string | undefined) => void;
|
|
23
|
+
profileTypesError?: RpcError;
|
|
24
|
+
viewComponent?: {
|
|
25
|
+
disableProfileTypesDropdown?: boolean;
|
|
26
|
+
disableExplorativeQuerying?: boolean;
|
|
27
|
+
labelnames?: string[];
|
|
28
|
+
createViewComponent?: React.ReactNode;
|
|
29
|
+
};
|
|
30
|
+
setQueryBrowserMode?: (mode: string) => void;
|
|
31
|
+
advancedModeForQueryBrowser?: boolean;
|
|
32
|
+
setAdvancedModeForQueryBrowser?: (mode: boolean) => void;
|
|
33
|
+
queryBrowserRef?: React.RefObject<HTMLDivElement>;
|
|
34
|
+
labels?: string[];
|
|
35
|
+
sumBySelection?: string[];
|
|
36
|
+
sumBySelectionLoading?: boolean;
|
|
37
|
+
setUserSumBySelection?: (sumBy: string[]) => void;
|
|
38
|
+
sumByRef?: React.RefObject<SelectInstance>;
|
|
39
|
+
}
|
|
40
|
+
export declare function QueryControls({ profileType, timeRangeSelection, setTimeRangeSelection, setQueryExpression, searchDisabled, showProfileTypeSelector, showSumBySelector, showAdvancedMode, profileTypesData, profileTypesLoading, selectedProfileName, setProfileName, profileTypesError, viewComponent, setQueryBrowserMode, advancedModeForQueryBrowser, setAdvancedModeForQueryBrowser, queryBrowserRef, labels, sumBySelection, sumBySelectionLoading, setUserSumBySelection, sumByRef, queryClient, }: QueryControlsProps): JSX.Element;
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/QueryControls/index.tsx"],"names":[],"mappings":"AAgBA,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAC,KAAK,cAAc,EAAC,MAAM,cAAc,CAAC;AAEjD,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;AAejD,UAAU,kBAAkB;IAC1B,WAAW,EAAE,kBAAkB,CAAC;IAChC,KAAK,EAAE,KAAK,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,WAAW,CAAC;IAClC,kBAAkB,EAAE,aAAa,CAAC;IAClC,qBAAqB,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACtD,iBAAiB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,kBAAkB,EAAE,CAAC,QAAQ,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD,cAAc,EAAE,OAAO,CAAC;IACxB,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;IACxC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IACpD,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,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC,8BAA8B,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACzD,eAAe,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IAClD,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,qBAAqB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAClD,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;CAC5C;AAED,wBAAgB,aAAa,CAAC,EAC5B,WAAW,EACX,kBAAkB,EAClB,qBAAqB,EACrB,kBAAkB,EAClB,cAAc,EACd,uBAA+B,EAC/B,iBAAyB,EACzB,gBAAuB,EACvB,gBAAgB,EAChB,mBAA2B,EAC3B,mBAAmB,EACnB,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,mBAAmB,EACnB,2BAAmC,EACnC,8BAA8B,EAC9B,eAAe,EACf,MAAW,EACX,cAAmB,EACnB,qBAA6B,EAC7B,qBAAqB,EACrB,QAAQ,EACR,WAAW,GACZ,EAAE,kBAAkB,GAAG,GAAG,CAAC,OAAO,CAmLlC"}
|
|
@@ -11,25 +11,29 @@ 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
|
+
import { useRef, useState } from 'react';
|
|
15
15
|
import { Switch } from '@headlessui/react';
|
|
16
16
|
import { Button, DateTimeRangePicker, useParcaContext } from '@parca/components';
|
|
17
17
|
import { TEST_IDS, testId } from '@parca/test-utils';
|
|
18
18
|
import MatchersInput from '../MatchersInput';
|
|
19
19
|
import ProfileTypeSelector from '../ProfileTypeSelector';
|
|
20
|
-
import SelectWithRefresh from '../SelectWithRefresh';
|
|
21
|
-
import SimpleMatchers from '../SimpleMatchers';
|
|
20
|
+
import { SelectWithRefresh } from '../SelectWithRefresh';
|
|
21
|
+
import SimpleMatchers from '../SimpleMatchers/';
|
|
22
22
|
import ViewMatchers from '../ViewMatchers';
|
|
23
|
-
|
|
23
|
+
import { useLabelNames } from '../hooks/useLabels';
|
|
24
|
+
export function QueryControls({ profileType, timeRangeSelection, setTimeRangeSelection, setQueryExpression, searchDisabled, showProfileTypeSelector = false, showSumBySelector = false, showAdvancedMode = true, profileTypesData, profileTypesLoading = false, selectedProfileName, setProfileName, profileTypesError, viewComponent, setQueryBrowserMode, advancedModeForQueryBrowser = false, setAdvancedModeForQueryBrowser, queryBrowserRef, labels = [], sumBySelection = [], sumBySelectionLoading = false, setUserSumBySelection, sumByRef, queryClient, }) {
|
|
24
25
|
const { timezone } = useParcaContext();
|
|
26
|
+
const defaultQueryBrowserRef = useRef(null);
|
|
27
|
+
const actualQueryBrowserRef = queryBrowserRef ?? defaultQueryBrowserRef;
|
|
25
28
|
const [searchExecutedTimestamp, setSearchExecutedTimestamp] = useState(0);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
const { refetch: refetchLabelNames } = useLabelNames(queryClient, profileType, timeRangeSelection.getFromMs(), timeRangeSelection.getToMs());
|
|
30
|
+
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: actualQueryBrowserRef, ...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" }), showAdvancedMode && viewComponent?.disableExplorativeQuerying !== true && (_jsxs(_Fragment, { children: [_jsxs(Switch, { checked: advancedModeForQueryBrowser, onChange: () => {
|
|
31
|
+
setAdvancedModeForQueryBrowser?.(!advancedModeForQueryBrowser);
|
|
32
|
+
setQueryBrowserMode?.(advancedModeForQueryBrowser ? 'simple' : 'advanced');
|
|
29
33
|
}, 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 &&
|
|
30
34
|
viewComponent?.labelnames !== undefined &&
|
|
31
|
-
viewComponent?.labelnames.length >= 1 ? (_jsx(ViewMatchers, { labelNames: viewComponent.labelnames
|
|
32
|
-
setUserSumBySelection(newValue.map(option => option.value));
|
|
35
|
+
viewComponent?.labelnames.length >= 1 ? (_jsx(ViewMatchers, { labelNames: viewComponent.labelnames })) : showAdvancedMode && advancedModeForQueryBrowser ? (_jsx(MatchersInput, {})) : (_jsx(SimpleMatchers, { queryBrowserRef: actualQueryBrowserRef, 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(SelectWithRefresh, { 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 => {
|
|
36
|
+
setUserSumBySelection?.(newValue.map(option => option.value));
|
|
33
37
|
}, placeholder: "Labels...", styles: {
|
|
34
38
|
indicatorSeparator: () => ({ display: 'none' }),
|
|
35
39
|
menu: provided => ({
|
|
@@ -41,11 +45,10 @@ export function QueryControls({ showProfileTypeSelector, profileTypesData, profi
|
|
|
41
45
|
minWidth: '320px',
|
|
42
46
|
position: 'absolute',
|
|
43
47
|
}),
|
|
44
|
-
|
|
45
|
-
}, isLoading: sumBySelectionLoading, isDisabled: !profileType.delta,
|
|
48
|
+
}, isLoading: sumBySelectionLoading, isDisabled: !profileType?.delta,
|
|
46
49
|
// @ts-expect-error
|
|
47
50
|
ref: sumByRef, onKeyDown: e => {
|
|
48
|
-
const currentRef = sumByRef
|
|
51
|
+
const currentRef = sumByRef?.current;
|
|
49
52
|
if (currentRef == null) {
|
|
50
53
|
return;
|
|
51
54
|
}
|
|
@@ -60,7 +63,7 @@ export function QueryControls({ showProfileTypeSelector, profileTypesData, profi
|
|
|
60
63
|
setQueryExpression(true);
|
|
61
64
|
currentRef.blur();
|
|
62
65
|
}
|
|
63
|
-
}, onRefresh:
|
|
66
|
+
}, onRefresh: refetchLabelNames, refreshTitle: "Refresh label names", refreshTestId: "sum-by-refresh-button", menuTestId: TEST_IDS.SUM_BY_SELECT_FLYOUT })] })), _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) => {
|
|
64
67
|
e.preventDefault();
|
|
65
68
|
setSearchExecutedTimestamp(Date.now());
|
|
66
69
|
setQueryExpression(true);
|
|
@@ -179,7 +179,7 @@ const CustomSelect = ({ items: itemsProp, selectedKey, onSelection, placeholder
|
|
|
179
179
|
setIsOpen(false);
|
|
180
180
|
}, 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) })) }) })), _jsx("div", { className: "flex-1 min-h-0", children: 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", ...testId(TEST_IDS.LABEL_VALUE_NO_RESULTS), children: "No values found" })) : (groupedFilteredItems.map(group => (_jsxs(_Fragment, { children: [groupedFilteredItems.length > 1 &&
|
|
181
181
|
groupedFilteredItems.every(g => g.type !== '') &&
|
|
182
|
-
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)))] })))) }), refetchValues !== undefined && loading !== true && (_jsx(RefreshButton, { onClick: () => void handleRefetch(), disabled: isRefetching, title: "Refresh
|
|
182
|
+
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)))] })))) }), refetchValues !== undefined && loading !== true && (_jsx(RefreshButton, { onClick: () => void handleRefetch(), disabled: isRefetching, title: "Refresh results", testId: TEST_IDS.LABEL_VALUE_REFRESH_BUTTON, sticky: true, loading: isRefetching }))] }) }))] }));
|
|
183
183
|
};
|
|
184
184
|
const OptionItem = ({ item, optionRefs, index, focusedIndex, selectedKey, handleSelection, }) => {
|
|
185
185
|
return (_jsxs("div", { ref: el => {
|
|
@@ -1,18 +1,9 @@
|
|
|
1
|
-
import { QueryServiceClient } from '@parca/client';
|
|
2
|
-
import { Query } from '@parca/parser';
|
|
3
1
|
import { type SelectItem } from './Select';
|
|
4
2
|
interface Props {
|
|
5
|
-
queryClient: QueryServiceClient;
|
|
6
|
-
setMatchersString: (arg: string) => void;
|
|
7
|
-
runQuery: () => void;
|
|
8
|
-
currentQuery: Query;
|
|
9
|
-
profileType: string;
|
|
10
3
|
queryBrowserRef: React.RefObject<HTMLDivElement>;
|
|
11
|
-
start?: number;
|
|
12
|
-
end?: number;
|
|
13
4
|
searchExecutedTimestamp?: number;
|
|
14
5
|
}
|
|
15
6
|
export declare const transformLabelsForSelect: (labelNames: string[]) => SelectItem[];
|
|
16
|
-
|
|
17
|
-
export
|
|
7
|
+
declare const SimpleMatchers: ({ queryBrowserRef, searchExecutedTimestamp, }: Props) => JSX.Element;
|
|
8
|
+
export default SimpleMatchers;
|
|
18
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/SimpleMatchers/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/SimpleMatchers/index.tsx"],"names":[],"mappings":"AA0BA,OAAe,EAAC,KAAK,UAAU,EAAC,MAAM,UAAU,CAAC;AAEjD,UAAU,KAAK;IACb,eAAe,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IACjD,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AAUD,eAAO,MAAM,wBAAwB,GAAI,YAAY,MAAM,EAAE,KAAG,UAAU,EAQzE,CAAC;AAiDF,QAAA,MAAM,cAAc,GAAI,+CAIrB,KAAK,KAAG,GAAG,CAAC,OAyZd,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -11,31 +11,23 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } 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 { useCallback, useEffect,
|
|
14
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
15
15
|
import { Icon } from '@iconify/react';
|
|
16
16
|
import { useQueryClient } from '@tanstack/react-query';
|
|
17
17
|
import cx from 'classnames';
|
|
18
|
-
import { useGrpcMetadata } from '@parca/components';
|
|
18
|
+
import { useGrpcMetadata, useParcaContext } from '@parca/components';
|
|
19
19
|
import { TEST_IDS, testId } from '@parca/test-utils';
|
|
20
20
|
import { millisToProtoTimestamp, sanitizeLabelValue } from '@parca/utilities';
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
21
|
+
import { useUnifiedLabels } from '../contexts/UnifiedLabelsContext';
|
|
22
|
+
import { transformLabelName } from '../contexts/utils';
|
|
23
|
+
import { useQueryState } from '../hooks/useQueryState';
|
|
23
24
|
import Select from './Select';
|
|
24
|
-
const trimOtelPrefix = (labelName) => {
|
|
25
|
-
if (labelName.startsWith('attributes_resource.')) {
|
|
26
|
-
return labelName.replace('attributes_resource.', '');
|
|
27
|
-
}
|
|
28
|
-
if (labelName.startsWith('attributes.')) {
|
|
29
|
-
return labelName.replace('attributes.', '');
|
|
30
|
-
}
|
|
31
|
-
return labelName;
|
|
32
|
-
};
|
|
33
25
|
export const transformLabelsForSelect = (labelNames) => {
|
|
34
26
|
return labelNames.map(labelName => ({
|
|
35
27
|
key: labelName,
|
|
36
28
|
element: {
|
|
37
|
-
active: _jsx(_Fragment, { children:
|
|
38
|
-
expanded: _jsx(_Fragment, { children:
|
|
29
|
+
active: _jsx(_Fragment, { children: transformLabelName(labelName) }),
|
|
30
|
+
expanded: _jsx(_Fragment, { children: transformLabelName(labelName) }),
|
|
39
31
|
},
|
|
40
32
|
}));
|
|
41
33
|
};
|
|
@@ -69,15 +61,19 @@ const operatorOptions = [
|
|
|
69
61
|
},
|
|
70
62
|
},
|
|
71
63
|
];
|
|
72
|
-
const SimpleMatchers = ({
|
|
73
|
-
const utilizationLabels = useUtilizationLabels();
|
|
64
|
+
const SimpleMatchers = ({ queryBrowserRef, searchExecutedTimestamp, }) => {
|
|
74
65
|
const [queryRows, setQueryRows] = useState([
|
|
75
66
|
{ labelName: '', operator: '=', labelValue: '', labelValues: [], isLoading: false },
|
|
76
67
|
]);
|
|
77
68
|
const reactQueryClient = useQueryClient();
|
|
78
69
|
const metadata = useGrpcMetadata();
|
|
70
|
+
const { queryServiceClient: parcaQueryClient } = useParcaContext();
|
|
79
71
|
const [showAll, setShowAll] = useState(false);
|
|
80
72
|
const [isActivelyEditing, setIsActivelyEditing] = useState(false);
|
|
73
|
+
const { labelNameMappingsForSimpleMatchers: labelNameOptions, isLabelNamesLoading: labelNamesLoading, refetchLabelNames, suffix, } = useUnifiedLabels();
|
|
74
|
+
const { draftSelection, setDraftMatchers, draftParsedQuery } = useQueryState({
|
|
75
|
+
suffix,
|
|
76
|
+
});
|
|
81
77
|
// Reset editing mode when search is executed
|
|
82
78
|
useEffect(() => {
|
|
83
79
|
if (searchExecutedTimestamp !== undefined && searchExecutedTimestamp > 0) {
|
|
@@ -88,14 +84,20 @@ const SimpleMatchers = ({ queryClient, setMatchersString, currentQuery, profileT
|
|
|
88
84
|
const visibleRows = showAll || isActivelyEditing ? queryRows : queryRows.slice(0, 3);
|
|
89
85
|
const hiddenRowsCount = queryRows.length - 3;
|
|
90
86
|
const maxWidthInPixels = `max-w-[${queryBrowserRef.current?.offsetWidth.toString()}px]`;
|
|
91
|
-
const currentMatchers =
|
|
87
|
+
const currentMatchers = draftParsedQuery?.matchersString();
|
|
88
|
+
const profileType = draftParsedQuery?.profileType().toString();
|
|
89
|
+
const start = draftSelection.from;
|
|
90
|
+
const end = draftSelection.to;
|
|
92
91
|
const fetchLabelValues = useCallback(async (labelName) => {
|
|
93
|
-
if (labelName == null || labelName === ''
|
|
92
|
+
if (labelName == null || labelName === '') {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
if (profileType == null || profileType === '') {
|
|
94
96
|
return [];
|
|
95
97
|
}
|
|
96
98
|
try {
|
|
97
99
|
const values = await reactQueryClient.fetchQuery([labelName, profileType, start, end], async () => {
|
|
98
|
-
const response = await
|
|
100
|
+
const response = await parcaQueryClient.values({
|
|
99
101
|
labelName,
|
|
100
102
|
match: [],
|
|
101
103
|
profileType,
|
|
@@ -116,18 +118,14 @@ const SimpleMatchers = ({ queryClient, setMatchersString, currentQuery, profileT
|
|
|
116
118
|
console.error('Error fetching label values:', error);
|
|
117
119
|
return [];
|
|
118
120
|
}
|
|
119
|
-
}, [
|
|
120
|
-
const fetchLabelValuesUtilization = useCallback(async (labelName) => {
|
|
121
|
-
return (await utilizationLabels?.utilizationFetchLabelValues?.(labelName)) ?? [];
|
|
122
|
-
}, [utilizationLabels]);
|
|
121
|
+
}, [parcaQueryClient, metadata, profileType, reactQueryClient, start, end]);
|
|
123
122
|
const updateMatchersString = useCallback((rows) => {
|
|
124
123
|
const matcherString = rows
|
|
125
124
|
.filter(row => row.labelName.length > 0 && row.labelValue)
|
|
126
125
|
.map(row => `${row.labelName}${row.operator}"${row.labelValue}"`)
|
|
127
126
|
.join(',');
|
|
128
|
-
|
|
129
|
-
}, [
|
|
130
|
-
const { labelNameOptions, isLoading: labelNamesLoading, refetchLabelValues, refetchLabelNames, } = useLabels();
|
|
127
|
+
setDraftMatchers(matcherString);
|
|
128
|
+
}, [setDraftMatchers]);
|
|
131
129
|
// Helper to ensure selected label name is in the options (for page load before API returns)
|
|
132
130
|
const getLabelNameOptionsWithSelected = useCallback((selectedLabelName) => {
|
|
133
131
|
if (selectedLabelName === '')
|
|
@@ -184,14 +182,10 @@ const SimpleMatchers = ({ queryClient, setMatchersString, currentQuery, profileT
|
|
|
184
182
|
}
|
|
185
183
|
}, [labelNameOptions]);
|
|
186
184
|
const fetchLabelValuesUnified = useCallback(async (labelName) => {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
? await fetchLabelValuesUtilization(labelName)
|
|
190
|
-
: await fetchLabelValues(labelName);
|
|
191
|
-
return labelValues;
|
|
192
|
-
}, [fetchLabelValues, fetchLabelValuesUtilization, labelNameOptions]);
|
|
185
|
+
return await fetchLabelValues(labelName);
|
|
186
|
+
}, [fetchLabelValues]);
|
|
193
187
|
useEffect(() => {
|
|
194
|
-
if (currentMatchers === '') {
|
|
188
|
+
if (currentMatchers === '' || currentMatchers === undefined) {
|
|
195
189
|
const defaultRow = {
|
|
196
190
|
labelName: '',
|
|
197
191
|
operator: '=',
|
|
@@ -205,7 +199,7 @@ const SimpleMatchers = ({ queryClient, setMatchersString, currentQuery, profileT
|
|
|
205
199
|
let isCancelled = false;
|
|
206
200
|
const fetchAndSetQueryRows = async () => {
|
|
207
201
|
const newRows = await Promise.all(currentMatchers.split(',').map(async (matcher) => {
|
|
208
|
-
const match = matcher.match(
|
|
202
|
+
const match = matcher.match(/^([^=!~]+)([=!~]{1,2})(.+)$/);
|
|
209
203
|
if (match === null)
|
|
210
204
|
return null;
|
|
211
205
|
const [, labelName, operator, labelValue] = match;
|
|
@@ -314,11 +308,14 @@ const SimpleMatchers = ({ queryClient, setMatchersString, currentQuery, profileT
|
|
|
314
308
|
};
|
|
315
309
|
}, [queryRows, fetchLabelValuesUnified]);
|
|
316
310
|
const isRowRegex = (row) => row.operator === '=~' || row.operator === '!~';
|
|
311
|
+
const handleRefetchForLabelValues = useCallback(async (labelName) => {
|
|
312
|
+
await fetchLabelValuesUnified(labelName);
|
|
313
|
+
}, [fetchLabelValuesUnified]);
|
|
317
314
|
return (_jsxs("div", { className: `flex items-center gap-3 ${maxWidthInPixels} w-full flex-wrap`, id: "simple-matchers", ...testId(TEST_IDS.SIMPLE_MATCHERS_CONTAINER), children: [visibleRows.map((row, index) => (_jsxs("div", { className: "flex items-center", ...testId(TEST_IDS.SIMPLE_MATCHER_ROW), children: [_jsx(Select, { items: getLabelNameOptionsWithSelected(row.labelName), 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, ...testId(TEST_IDS.LABEL_NAME_SELECT), refetchValues: refetchLabelNames }), _jsx(Select, { items: operatorOptions, onSelection: value => handleUpdateRow(index, 'operator', value), selectedKey: row.operator, className: "rounded-none ring-0 focus:ring-0 outline-none", ...testId(TEST_IDS.OPERATOR_SELECT) }), _jsx(Select, { items: transformLabelsForSelect(row.labelValue !== '' && !row.labelValues.includes(row.labelValue)
|
|
318
315
|
? [...row.labelValues, row.labelValue]
|
|
319
316
|
: 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-[600px]', {
|
|
320
317
|
'w-[300px]': isRowRegex(row),
|
|
321
|
-
}), searchable: true, disabled: row.labelName === '', loading: row.isLoading, onButtonClick: () => handleLabelValueClick(index), editable: isRowRegex(row), ...testId(TEST_IDS.LABEL_VALUE_SELECT), refetchValues: async () => await
|
|
318
|
+
}), searchable: true, disabled: row.labelName === '', loading: row.isLoading, onButtonClick: () => handleLabelValueClick(index), editable: isRowRegex(row), ...testId(TEST_IDS.LABEL_VALUE_SELECT), refetchValues: async () => await handleRefetchForLabelValues(row.labelName), showLoadingInButton: true }), _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'), ...testId(TEST_IDS.REMOVE_MATCHER_BUTTON), children: _jsx(Icon, { icon: "carbon:close", className: "h-5 w-5 text-gray-400", "aria-hidden": "true" }) })] }, index))), queryRows.length > 3 && !isActivelyEditing && (_jsx("button", { onClick: () => {
|
|
322
319
|
if (showAll) {
|
|
323
320
|
// Clicking "Show less" - collapse and stop editing mode
|
|
324
321
|
setShowAll(false);
|
|
@@ -330,12 +327,4 @@ const SimpleMatchers = ({ queryClient, setMatchersString, currentQuery, profileT
|
|
|
330
327
|
}
|
|
331
328
|
}, 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", ...testId(showAll ? TEST_IDS.SHOW_LESS_BUTTON : TEST_IDS.SHOW_MORE_BUTTON), 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", ...testId(TEST_IDS.ADD_MATCHER_BUTTON), children: _jsx(Icon, { icon: "material-symbols:add", className: "h-5 w-5 text-gray-400", "aria-hidden": "true" }) })] }));
|
|
332
329
|
};
|
|
333
|
-
export default
|
|
334
|
-
const labelNameFromMatchers = useMemo(() => {
|
|
335
|
-
if (props.currentQuery === undefined)
|
|
336
|
-
return [];
|
|
337
|
-
const matchers = props.currentQuery.matchers;
|
|
338
|
-
return matchers.map(matcher => matcher.key);
|
|
339
|
-
}, [props.currentQuery]);
|
|
340
|
-
return (_jsx(LabelProvider, { queryClient: props.queryClient, profileType: props.profileType, labelNameFromMatchers: labelNameFromMatchers, start: props.start, end: props.end, children: _jsx(SimpleMatchers, { ...props }) }));
|
|
341
|
-
}
|
|
330
|
+
export default SimpleMatchers;
|
|
@@ -1,15 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { QueryServiceClient } from '@parca/client';
|
|
3
|
-
import { Query } from '@parca/parser';
|
|
4
2
|
interface Props {
|
|
5
3
|
labelNames: string[];
|
|
6
|
-
profileType: string;
|
|
7
|
-
runQuery: () => void;
|
|
8
|
-
currentQuery: Query;
|
|
9
|
-
queryClient: QueryServiceClient;
|
|
10
|
-
setMatchersString: (arg: string) => void;
|
|
11
|
-
start?: number;
|
|
12
|
-
end?: number;
|
|
13
4
|
}
|
|
14
5
|
declare const ViewMatchers: React.FC<Props>;
|
|
15
6
|
export default ViewMatchers;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ViewMatchers/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAiD,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ViewMatchers/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAatE,UAAU,KAAK;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAwKjC,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -14,15 +14,23 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
14
14
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
15
15
|
import { Icon } from '@iconify/react';
|
|
16
16
|
import cx from 'classnames';
|
|
17
|
-
import { useGrpcMetadata } from '@parca/components';
|
|
17
|
+
import { useGrpcMetadata, useParcaContext } from '@parca/components';
|
|
18
18
|
import { TEST_IDS, testId } from '@parca/test-utils';
|
|
19
19
|
import { millisToProtoTimestamp, sanitizeLabelValue } from '@parca/utilities';
|
|
20
20
|
import CustomSelect from '../SimpleMatchers/Select';
|
|
21
|
-
|
|
21
|
+
import { useUnifiedLabels } from '../contexts/UnifiedLabelsContext';
|
|
22
|
+
import { useQueryState } from '../hooks/useQueryState';
|
|
23
|
+
const ViewMatchers = ({ labelNames }) => {
|
|
22
24
|
const [labelValuesMap, setLabelValuesMap] = useState({});
|
|
23
25
|
const [isLoading, setIsLoading] = useState({});
|
|
24
26
|
const metadata = useGrpcMetadata();
|
|
25
|
-
const
|
|
27
|
+
const { queryServiceClient: parcaQueryClient } = useParcaContext();
|
|
28
|
+
const { suffix } = useUnifiedLabels();
|
|
29
|
+
const { draftSelection, setDraftMatchers, commitDraft, draftParsedQuery } = useQueryState({ suffix });
|
|
30
|
+
const currentMatchers = draftParsedQuery?.matchersString();
|
|
31
|
+
const profileType = draftParsedQuery?.profileType().toString();
|
|
32
|
+
const start = draftSelection.from;
|
|
33
|
+
const end = draftSelection.to;
|
|
26
34
|
const parseCurrentMatchers = useCallback((matchersString) => {
|
|
27
35
|
const matches = matchersString.match(/(\w+)="([^"]+)"/g);
|
|
28
36
|
if (matches === null)
|
|
@@ -37,19 +45,19 @@ const ViewMatchers = ({ labelNames, profileType, queryClient, runQuery, setMatch
|
|
|
37
45
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
38
46
|
{});
|
|
39
47
|
}, []);
|
|
40
|
-
const initialSelections = parseCurrentMatchers(currentMatchers);
|
|
48
|
+
const initialSelections = parseCurrentMatchers(currentMatchers ?? '');
|
|
41
49
|
const selectionsRef = useRef(initialSelections);
|
|
42
|
-
const
|
|
50
|
+
const commitDraftRef = useRef(commitDraft);
|
|
43
51
|
const timeoutRef = useRef(null);
|
|
44
52
|
useEffect(() => {
|
|
45
|
-
|
|
46
|
-
}, [
|
|
53
|
+
commitDraftRef.current = commitDraft;
|
|
54
|
+
}, [commitDraft]);
|
|
47
55
|
useEffect(() => {
|
|
48
56
|
selectionsRef.current = initialSelections;
|
|
49
57
|
}, [initialSelections]);
|
|
50
58
|
const fetchLabelValues = useCallback(async (labelName) => {
|
|
51
59
|
try {
|
|
52
|
-
const response = await
|
|
60
|
+
const response = await parcaQueryClient.values({
|
|
53
61
|
labelName,
|
|
54
62
|
match: [],
|
|
55
63
|
profileType,
|
|
@@ -66,7 +74,7 @@ const ViewMatchers = ({ labelNames, profileType, queryClient, runQuery, setMatch
|
|
|
66
74
|
console.error('Error fetching label values:', error);
|
|
67
75
|
return [];
|
|
68
76
|
}
|
|
69
|
-
}, [
|
|
77
|
+
}, [parcaQueryClient, metadata, profileType, start, end]);
|
|
70
78
|
const fetchAllLabelValues = useCallback(async () => {
|
|
71
79
|
const newLabelValuesMap = {};
|
|
72
80
|
const newIsLoading = {};
|
|
@@ -88,14 +96,14 @@ const ViewMatchers = ({ labelNames, profileType, queryClient, runQuery, setMatch
|
|
|
88
96
|
.filter(([_, v]) => v !== null && v !== '')
|
|
89
97
|
.map(([ln, v]) => `${ln}="${v}"`);
|
|
90
98
|
const matcherString = matcherParts.join(',');
|
|
91
|
-
|
|
99
|
+
setDraftMatchers(matcherString);
|
|
92
100
|
if (timeoutRef.current !== null) {
|
|
93
101
|
clearTimeout(timeoutRef.current);
|
|
94
102
|
}
|
|
95
103
|
timeoutRef.current = setTimeout(() => {
|
|
96
|
-
|
|
104
|
+
commitDraftRef.current();
|
|
97
105
|
}, 300);
|
|
98
|
-
}, [
|
|
106
|
+
}, [setDraftMatchers]);
|
|
99
107
|
const handleSelection = useCallback((labelName, value) => {
|
|
100
108
|
selectionsRef.current = {
|
|
101
109
|
...selectionsRef.current,
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { QueryServiceClient } from '@parca/client';
|
|
2
|
+
import { Query } from '@parca/parser';
|
|
3
|
+
export interface LabelsQueryProviderContextType {
|
|
4
|
+
isLabelNamesLoading: boolean;
|
|
5
|
+
isLabelValuesLoading: boolean;
|
|
6
|
+
currentLabelName: string | null;
|
|
7
|
+
setCurrentLabelName: (name: string | null) => void;
|
|
8
|
+
refetchLabelValues: () => Promise<void>;
|
|
9
|
+
refetchLabelNames: () => Promise<void>;
|
|
10
|
+
labelNames: string[];
|
|
11
|
+
labelValues: string[];
|
|
12
|
+
queryClient: QueryServiceClient;
|
|
13
|
+
setMatchersString: (arg: string) => void;
|
|
14
|
+
runQuery: () => void;
|
|
15
|
+
currentQuery: Query;
|
|
16
|
+
profileType: string;
|
|
17
|
+
start?: number;
|
|
18
|
+
end?: number;
|
|
19
|
+
suffix?: '_a' | '_b';
|
|
20
|
+
}
|
|
21
|
+
interface LabelsQueryProviderProps {
|
|
22
|
+
children: React.ReactNode;
|
|
23
|
+
queryClient: QueryServiceClient;
|
|
24
|
+
setMatchersString: (arg: string) => void;
|
|
25
|
+
runQuery: () => void;
|
|
26
|
+
currentQuery: Query;
|
|
27
|
+
profileType: string;
|
|
28
|
+
start?: number;
|
|
29
|
+
end?: number;
|
|
30
|
+
suffix?: '_a' | '_b';
|
|
31
|
+
}
|
|
32
|
+
export declare function LabelsQueryProvider({ children, queryClient, setMatchersString, runQuery, currentQuery, profileType, start, end, suffix, }: LabelsQueryProviderProps): JSX.Element;
|
|
33
|
+
export declare function useLabelsQueryProvider(): LabelsQueryProviderContextType;
|
|
34
|
+
export {};
|
|
35
|
+
//# sourceMappingURL=LabelsQueryProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LabelsQueryProvider.d.ts","sourceRoot":"","sources":["../../src/contexts/LabelsQueryProvider.tsx"],"names":[],"mappings":"AAoCA,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AACjD,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAKpC,MAAM,WAAW,8BAA8B;IAC7C,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,kBAAkB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IAEtB,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;IAEb,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;CACtB;AAID,UAAU,wBAAwB;IAChC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAE1B,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;IAEb,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;CACtB;AAED,wBAAgB,mBAAmB,CAAC,EAClC,QAAQ,EACR,WAAW,EACX,iBAAiB,EACjB,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,KAAK,EACL,GAAG,EACH,MAAM,GACP,EAAE,wBAAwB,GAAG,GAAG,CAAC,OAAO,CA2CxC;AAED,wBAAgB,sBAAsB,IAAI,8BAA8B,CAMvE"}
|
|
@@ -0,0 +1,70 @@
|
|
|
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
|
+
/**
|
|
15
|
+
* LabelsQueryProvider - Data Fetching Layer
|
|
16
|
+
*
|
|
17
|
+
* This context provider is responsible for fetching label data from the Parca API
|
|
18
|
+
* and making it available to child components through React Context.
|
|
19
|
+
*
|
|
20
|
+
* Purpose:
|
|
21
|
+
* - Fetches label names and values from the Parca profiling API
|
|
22
|
+
* - Manages loading states for label data
|
|
23
|
+
* - Provides refetch functions for manual data refresh
|
|
24
|
+
* - Acts as the primary data source in the label provider architecture
|
|
25
|
+
*
|
|
26
|
+
* Architecture Pattern:
|
|
27
|
+
* This is the first layer in a three-layer architecture:
|
|
28
|
+
* 1. LabelsQueryProvider (this file) - Fetches data from API
|
|
29
|
+
* 2. LabelsSource (in ProfileSelector) - Transforms/merges data
|
|
30
|
+
* 3. UnifiedLabelsProvider - Provides unified interface to UI components
|
|
31
|
+
*
|
|
32
|
+
* Consumer Hook: useLabelsQueryProvider()
|
|
33
|
+
*/
|
|
34
|
+
import { createContext, useContext, useState } from 'react';
|
|
35
|
+
import { useLabelNames, useLabelValues } from '../hooks/useLabels';
|
|
36
|
+
import { useExtractedLabelNames } from './utils';
|
|
37
|
+
const LabelsQueryProviderContext = createContext(null);
|
|
38
|
+
export function LabelsQueryProvider({ children, queryClient, setMatchersString, runQuery, currentQuery, profileType, start, end, suffix, }) {
|
|
39
|
+
const [currentLabelName, setCurrentLabelName] = useState(null);
|
|
40
|
+
const { result: labelNamesResponse, loading: isLabelNamesLoading, refetch: labelNamesRefetch, } = useLabelNames(queryClient, profileType, start, end);
|
|
41
|
+
const labelNames = useExtractedLabelNames(labelNamesResponse.response, labelNamesResponse.error);
|
|
42
|
+
const { result: labelValuesOriginal, loading: isLabelValuesLoading, refetch: labelValuesRefetch, } = useLabelValues(queryClient, currentLabelName ?? '', profileType, start, end);
|
|
43
|
+
const labelValues = labelValuesOriginal.response;
|
|
44
|
+
const value = {
|
|
45
|
+
labelNames,
|
|
46
|
+
labelValues,
|
|
47
|
+
isLabelNamesLoading,
|
|
48
|
+
isLabelValuesLoading,
|
|
49
|
+
refetchLabelValues: labelValuesRefetch,
|
|
50
|
+
refetchLabelNames: labelNamesRefetch,
|
|
51
|
+
queryClient,
|
|
52
|
+
setMatchersString,
|
|
53
|
+
runQuery,
|
|
54
|
+
currentQuery,
|
|
55
|
+
profileType,
|
|
56
|
+
start,
|
|
57
|
+
end,
|
|
58
|
+
setCurrentLabelName,
|
|
59
|
+
currentLabelName,
|
|
60
|
+
suffix,
|
|
61
|
+
};
|
|
62
|
+
return (_jsx(LabelsQueryProviderContext.Provider, { value: value, children: children }));
|
|
63
|
+
}
|
|
64
|
+
export function useLabelsQueryProvider() {
|
|
65
|
+
const context = useContext(LabelsQueryProviderContext);
|
|
66
|
+
if (context === null) {
|
|
67
|
+
throw new Error('useLabelsQueryProvider must be used within a LabelsQueryProvider');
|
|
68
|
+
}
|
|
69
|
+
return context;
|
|
70
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { SelectItem } from '../SimpleMatchers/Select';
|
|
2
|
+
import { type LabelNameMapping } from './utils';
|
|
3
|
+
interface LabelNameSection {
|
|
4
|
+
type: string;
|
|
5
|
+
values: SelectItem[];
|
|
6
|
+
}
|
|
7
|
+
interface UnifiedLabelsContextType {
|
|
8
|
+
labelNameMappingsForMatchersInput: LabelNameMapping[];
|
|
9
|
+
labelNameMappingsForSimpleMatchers: LabelNameSection[];
|
|
10
|
+
labelNames: string[];
|
|
11
|
+
labelValues: string[];
|
|
12
|
+
isLabelNamesLoading: boolean;
|
|
13
|
+
isLabelValuesLoading: boolean;
|
|
14
|
+
currentLabelName: string | null;
|
|
15
|
+
setCurrentLabelName: (name: string | null) => void;
|
|
16
|
+
shouldHandlePrefixes: boolean;
|
|
17
|
+
refetchLabelValues: () => Promise<void>;
|
|
18
|
+
refetchLabelNames: () => Promise<void>;
|
|
19
|
+
labelNameFromMatchers: string[];
|
|
20
|
+
suffix?: '_a' | '_b';
|
|
21
|
+
}
|
|
22
|
+
interface UnifiedLabelsProviderProps {
|
|
23
|
+
children: React.ReactNode;
|
|
24
|
+
currentLabelName: string | null;
|
|
25
|
+
setCurrentLabelName: (name: string | null) => void;
|
|
26
|
+
labelNames: string[];
|
|
27
|
+
labelValues: string[];
|
|
28
|
+
isLabelNamesLoading: boolean;
|
|
29
|
+
isLabelValuesLoading: boolean;
|
|
30
|
+
refetchLabelValues: () => Promise<void>;
|
|
31
|
+
refetchLabelNames: () => Promise<void>;
|
|
32
|
+
suffix?: '_a' | '_b';
|
|
33
|
+
}
|
|
34
|
+
export declare function UnifiedLabelsProvider({ children, labelNames, isLabelNamesLoading, isLabelValuesLoading, refetchLabelValues, refetchLabelNames, currentLabelName, setCurrentLabelName, labelValues, suffix, }: UnifiedLabelsProviderProps): JSX.Element;
|
|
35
|
+
export declare function useUnifiedLabels(): UnifiedLabelsContextType;
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=UnifiedLabelsContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UnifiedLabelsContext.d.ts","sourceRoot":"","sources":["../../src/contexts/UnifiedLabelsContext.tsx"],"names":[],"mappings":"AAqCA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAuB,KAAK,gBAAgB,EAAC,MAAM,SAAS,CAAC;AAEpE,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB;AAED,UAAU,wBAAwB;IAChC,iCAAiC,EAAE,gBAAgB,EAAE,CAAC;IACtD,kCAAkC,EAAE,gBAAgB,EAAE,CAAC;IACvD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IAEtB,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;IAC9B,kBAAkB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAEhC,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;CACtB;AAID,UAAU,0BAA0B;IAClC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAE1B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAEnD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,oBAAoB,EAAE,OAAO,CAAC;IAE9B,kBAAkB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvC,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;CACtB;AAED,wBAAgB,qBAAqB,CAAC,EACpC,QAAQ,EACR,UAAU,EACV,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,WAAW,EACX,MAAM,GACP,EAAE,0BAA0B,GAAG,GAAG,CAAC,OAAO,CAqD1C;AAED,wBAAgB,gBAAgB,IAAI,wBAAwB,CAM3D"}
|