@parca/profile 0.19.83 → 0.19.84
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 +4 -0
- package/dist/MatchersInput/index.d.ts +2 -34
- package/dist/MatchersInput/index.d.ts.map +1 -1
- package/dist/MatchersInput/index.js +14 -91
- package/dist/MetricsGraph/index.d.ts.map +1 -1
- package/dist/MetricsGraph/index.js +13 -1
- package/dist/ProfileMetricsGraph/index.d.ts.map +1 -1
- package/dist/ProfileMetricsGraph/index.js +6 -29
- package/dist/ProfileSelector/MetricsGraphSection.d.ts +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 +14 -10
- package/dist/QueryControls/index.d.ts +46 -0
- package/dist/QueryControls/index.d.ts.map +1 -0
- package/dist/{ProfileSelector/QueryControls.js → QueryControls/index.js} +16 -13
- package/dist/SimpleMatchers/Select.js +1 -1
- package/dist/SimpleMatchers/index.d.ts +6 -10
- package/dist/SimpleMatchers/index.d.ts.map +1 -1
- package/dist/SimpleMatchers/index.js +30 -45
- package/dist/ViewMatchers/index.d.ts +0 -9
- package/dist/ViewMatchers/index.d.ts.map +1 -1
- package/dist/ViewMatchers/index.js +20 -12
- package/dist/contexts/LabelsQueryProvider.d.ts +35 -0
- package/dist/contexts/LabelsQueryProvider.d.ts.map +1 -0
- package/dist/contexts/LabelsQueryProvider.js +70 -0
- package/dist/contexts/UnifiedLabelsContext.d.ts +37 -0
- package/dist/contexts/UnifiedLabelsContext.d.ts.map +1 -0
- package/dist/contexts/UnifiedLabelsContext.js +88 -0
- package/dist/contexts/utils.d.ts +10 -0
- package/dist/contexts/utils.d.ts.map +1 -0
- package/dist/contexts/utils.js +31 -0
- package/dist/hooks/useLabels.d.ts +23 -0
- package/dist/hooks/useLabels.d.ts.map +1 -0
- package/dist/hooks/useLabels.js +75 -0
- package/dist/hooks/useQueryState.d.ts +2 -0
- package/dist/hooks/useQueryState.d.ts.map +1 -1
- package/dist/hooks/useQueryState.js +19 -12
- package/dist/index.d.ts +9 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -3
- package/dist/styles.css +1 -1
- package/dist/useSumBy.js +1 -1
- package/package.json +2 -2
- package/src/MatchersInput/index.tsx +17 -163
- package/src/MetricsGraph/index.tsx +17 -1
- package/src/ProfileMetricsGraph/index.tsx +17 -98
- package/src/ProfileSelector/MetricsGraphSection.tsx +14 -115
- package/src/ProfileSelector/index.tsx +114 -109
- package/src/{ProfileSelector/QueryControls.tsx → QueryControls/index.tsx} +76 -84
- package/src/SimpleMatchers/Select.tsx +1 -1
- package/src/SimpleMatchers/index.tsx +46 -84
- package/src/ViewMatchers/index.tsx +22 -30
- package/src/contexts/LabelsQueryProvider.tsx +142 -0
- package/src/contexts/UnifiedLabelsContext.tsx +155 -0
- package/src/contexts/utils.ts +43 -0
- package/src/hooks/useLabels.ts +121 -0
- package/src/hooks/useQueryState.ts +26 -15
- 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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/QueryControls/index.tsx"],"names":[],"mappings":"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"}
|
|
@@ -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, draftSelection, setDraftMatchers, draftParsedQuery, }) {
|
|
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, draftSelection: draftSelection, setDraftMatchers: setDraftMatchers, draftParsedQuery: draftParsedQuery }))] }), 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,14 @@
|
|
|
1
|
-
import { QueryServiceClient } from '@parca/client';
|
|
2
1
|
import { Query } from '@parca/parser';
|
|
2
|
+
import { QuerySelection } from '../ProfileSelector';
|
|
3
3
|
import { type SelectItem } from './Select';
|
|
4
4
|
interface Props {
|
|
5
|
-
queryClient: QueryServiceClient;
|
|
6
|
-
setMatchersString: (arg: string) => void;
|
|
7
|
-
runQuery: () => void;
|
|
8
|
-
currentQuery: Query;
|
|
9
|
-
profileType: string;
|
|
10
5
|
queryBrowserRef: React.RefObject<HTMLDivElement>;
|
|
11
|
-
start?: number;
|
|
12
|
-
end?: number;
|
|
13
6
|
searchExecutedTimestamp?: number;
|
|
7
|
+
draftSelection: QuerySelection;
|
|
8
|
+
setDraftMatchers: (selection: string) => void;
|
|
9
|
+
draftParsedQuery?: Query | null;
|
|
14
10
|
}
|
|
15
11
|
export declare const transformLabelsForSelect: (labelNames: string[]) => SelectItem[];
|
|
16
|
-
|
|
17
|
-
export
|
|
12
|
+
declare const SimpleMatchers: ({ queryBrowserRef, searchExecutedTimestamp, draftSelection, setDraftMatchers, draftParsedQuery, }: Props) => JSX.Element;
|
|
13
|
+
export default SimpleMatchers;
|
|
18
14
|
//# 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":"AAoBA,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAIpC,OAAO,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAGlD,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;IACjC,cAAc,EAAE,cAAc,CAAC;IAC/B,gBAAgB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,gBAAgB,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;CACjC;AAUD,eAAO,MAAM,wBAAwB,GAAI,YAAY,MAAM,EAAE,KAAG,UAAU,EAQzE,CAAC;AAiDF,QAAA,MAAM,cAAc,GAAI,mGAMrB,KAAK,KAAG,GAAG,CAAC,OAoZd,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -11,31 +11,22 @@ 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
23
|
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
24
|
export const transformLabelsForSelect = (labelNames) => {
|
|
34
25
|
return labelNames.map(labelName => ({
|
|
35
26
|
key: labelName,
|
|
36
27
|
element: {
|
|
37
|
-
active: _jsx(_Fragment, { children:
|
|
38
|
-
expanded: _jsx(_Fragment, { children:
|
|
28
|
+
active: _jsx(_Fragment, { children: transformLabelName(labelName) }),
|
|
29
|
+
expanded: _jsx(_Fragment, { children: transformLabelName(labelName) }),
|
|
39
30
|
},
|
|
40
31
|
}));
|
|
41
32
|
};
|
|
@@ -69,15 +60,16 @@ const operatorOptions = [
|
|
|
69
60
|
},
|
|
70
61
|
},
|
|
71
62
|
];
|
|
72
|
-
const SimpleMatchers = ({
|
|
73
|
-
const utilizationLabels = useUtilizationLabels();
|
|
63
|
+
const SimpleMatchers = ({ queryBrowserRef, searchExecutedTimestamp, draftSelection, setDraftMatchers, draftParsedQuery, }) => {
|
|
74
64
|
const [queryRows, setQueryRows] = useState([
|
|
75
65
|
{ labelName: '', operator: '=', labelValue: '', labelValues: [], isLoading: false },
|
|
76
66
|
]);
|
|
77
67
|
const reactQueryClient = useQueryClient();
|
|
78
68
|
const metadata = useGrpcMetadata();
|
|
69
|
+
const { queryServiceClient: parcaQueryClient } = useParcaContext();
|
|
79
70
|
const [showAll, setShowAll] = useState(false);
|
|
80
71
|
const [isActivelyEditing, setIsActivelyEditing] = useState(false);
|
|
72
|
+
const { labelNameMappingsForSimpleMatchers: labelNameOptions, isLabelNamesLoading: labelNamesLoading, refetchLabelNames, } = useUnifiedLabels();
|
|
81
73
|
// Reset editing mode when search is executed
|
|
82
74
|
useEffect(() => {
|
|
83
75
|
if (searchExecutedTimestamp !== undefined && searchExecutedTimestamp > 0) {
|
|
@@ -88,14 +80,20 @@ const SimpleMatchers = ({ queryClient, setMatchersString, currentQuery, profileT
|
|
|
88
80
|
const visibleRows = showAll || isActivelyEditing ? queryRows : queryRows.slice(0, 3);
|
|
89
81
|
const hiddenRowsCount = queryRows.length - 3;
|
|
90
82
|
const maxWidthInPixels = `max-w-[${queryBrowserRef.current?.offsetWidth.toString()}px]`;
|
|
91
|
-
const currentMatchers =
|
|
83
|
+
const currentMatchers = draftParsedQuery?.matchersString();
|
|
84
|
+
const profileType = draftParsedQuery?.profileType().toString();
|
|
85
|
+
const start = draftSelection.from;
|
|
86
|
+
const end = draftSelection.to;
|
|
92
87
|
const fetchLabelValues = useCallback(async (labelName) => {
|
|
93
|
-
if (labelName == null || labelName === ''
|
|
88
|
+
if (labelName == null || labelName === '') {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
if (profileType == null || profileType === '') {
|
|
94
92
|
return [];
|
|
95
93
|
}
|
|
96
94
|
try {
|
|
97
95
|
const values = await reactQueryClient.fetchQuery([labelName, profileType, start, end], async () => {
|
|
98
|
-
const response = await
|
|
96
|
+
const response = await parcaQueryClient.values({
|
|
99
97
|
labelName,
|
|
100
98
|
match: [],
|
|
101
99
|
profileType,
|
|
@@ -116,18 +114,14 @@ const SimpleMatchers = ({ queryClient, setMatchersString, currentQuery, profileT
|
|
|
116
114
|
console.error('Error fetching label values:', error);
|
|
117
115
|
return [];
|
|
118
116
|
}
|
|
119
|
-
}, [
|
|
120
|
-
const fetchLabelValuesUtilization = useCallback(async (labelName) => {
|
|
121
|
-
return (await utilizationLabels?.utilizationFetchLabelValues?.(labelName)) ?? [];
|
|
122
|
-
}, [utilizationLabels]);
|
|
117
|
+
}, [parcaQueryClient, metadata, profileType, reactQueryClient, start, end]);
|
|
123
118
|
const updateMatchersString = useCallback((rows) => {
|
|
124
119
|
const matcherString = rows
|
|
125
120
|
.filter(row => row.labelName.length > 0 && row.labelValue)
|
|
126
121
|
.map(row => `${row.labelName}${row.operator}"${row.labelValue}"`)
|
|
127
122
|
.join(',');
|
|
128
|
-
|
|
129
|
-
}, [
|
|
130
|
-
const { labelNameOptions, isLoading: labelNamesLoading, refetchLabelValues, refetchLabelNames, } = useLabels();
|
|
123
|
+
setDraftMatchers(matcherString);
|
|
124
|
+
}, [setDraftMatchers]);
|
|
131
125
|
// Helper to ensure selected label name is in the options (for page load before API returns)
|
|
132
126
|
const getLabelNameOptionsWithSelected = useCallback((selectedLabelName) => {
|
|
133
127
|
if (selectedLabelName === '')
|
|
@@ -184,14 +178,10 @@ const SimpleMatchers = ({ queryClient, setMatchersString, currentQuery, profileT
|
|
|
184
178
|
}
|
|
185
179
|
}, [labelNameOptions]);
|
|
186
180
|
const fetchLabelValuesUnified = useCallback(async (labelName) => {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
? await fetchLabelValuesUtilization(labelName)
|
|
190
|
-
: await fetchLabelValues(labelName);
|
|
191
|
-
return labelValues;
|
|
192
|
-
}, [fetchLabelValues, fetchLabelValuesUtilization, labelNameOptions]);
|
|
181
|
+
return await fetchLabelValues(labelName);
|
|
182
|
+
}, [fetchLabelValues]);
|
|
193
183
|
useEffect(() => {
|
|
194
|
-
if (currentMatchers === '') {
|
|
184
|
+
if (currentMatchers === '' || currentMatchers === undefined) {
|
|
195
185
|
const defaultRow = {
|
|
196
186
|
labelName: '',
|
|
197
187
|
operator: '=',
|
|
@@ -205,7 +195,7 @@ const SimpleMatchers = ({ queryClient, setMatchersString, currentQuery, profileT
|
|
|
205
195
|
let isCancelled = false;
|
|
206
196
|
const fetchAndSetQueryRows = async () => {
|
|
207
197
|
const newRows = await Promise.all(currentMatchers.split(',').map(async (matcher) => {
|
|
208
|
-
const match = matcher.match(
|
|
198
|
+
const match = matcher.match(/^([^=!~]+)([=!~]{1,2})(.+)$/);
|
|
209
199
|
if (match === null)
|
|
210
200
|
return null;
|
|
211
201
|
const [, labelName, operator, labelValue] = match;
|
|
@@ -314,11 +304,14 @@ const SimpleMatchers = ({ queryClient, setMatchersString, currentQuery, profileT
|
|
|
314
304
|
};
|
|
315
305
|
}, [queryRows, fetchLabelValuesUnified]);
|
|
316
306
|
const isRowRegex = (row) => row.operator === '=~' || row.operator === '!~';
|
|
307
|
+
const handleRefetchForLabelValues = useCallback(async (labelName) => {
|
|
308
|
+
await fetchLabelValuesUnified(labelName);
|
|
309
|
+
}, [fetchLabelValuesUnified]);
|
|
317
310
|
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
311
|
? [...row.labelValues, row.labelValue]
|
|
319
312
|
: 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
313
|
'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
|
|
314
|
+
}), 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
315
|
if (showAll) {
|
|
323
316
|
// Clicking "Show less" - collapse and stop editing mode
|
|
324
317
|
setShowAll(false);
|
|
@@ -330,12 +323,4 @@ const SimpleMatchers = ({ queryClient, setMatchersString, currentQuery, profileT
|
|
|
330
323
|
}
|
|
331
324
|
}, 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
325
|
};
|
|
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
|
-
}
|
|
326
|
+
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"}
|