@parca/profile 0.19.95 → 0.19.102
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 +28 -0
- package/dist/ProfileSelector/MetricsGraphSection.d.ts +1 -1
- package/dist/ProfileSelector/MetricsGraphSection.d.ts.map +1 -1
- package/dist/ProfileSelector/MetricsGraphSection.js +1 -1
- package/dist/ProfileSelector/index.d.ts.map +1 -1
- package/dist/ProfileSelector/index.js +1 -2
- package/dist/ProfileView/hooks/useResetStateOnProfileTypeChange.d.ts.map +1 -1
- package/dist/ProfileView/hooks/useResetStateOnProfileTypeChange.js +8 -0
- package/dist/SimpleMatchers/Select.d.ts.map +1 -1
- package/dist/SimpleMatchers/Select.js +3 -3
- package/dist/hooks/useLabels.d.ts.map +1 -1
- package/dist/hooks/useLabels.js +4 -1
- package/dist/hooks/useQueryState.d.ts.map +1 -1
- package/dist/hooks/useQueryState.js +53 -23
- package/dist/hooks/useQueryState.test.js +32 -22
- package/dist/useSumBy.d.ts +10 -2
- package/dist/useSumBy.d.ts.map +1 -1
- package/dist/useSumBy.js +30 -7
- package/package.json +15 -10
- package/src/ProfileSelector/MetricsGraphSection.tsx +2 -2
- package/src/ProfileSelector/index.tsx +1 -5
- package/src/ProfileView/hooks/useResetStateOnProfileTypeChange.ts +8 -0
- package/src/SimpleMatchers/Select.tsx +3 -3
- package/src/hooks/useLabels.ts +5 -1
- package/src/hooks/useQueryState.test.tsx +41 -22
- package/src/hooks/useQueryState.ts +72 -31
- package/src/useSumBy.ts +58 -4
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,34 @@
|
|
|
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.102](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.101...@parca/profile@0.19.102) (2025-12-15)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @parca/profile
|
|
9
|
+
|
|
10
|
+
## [0.19.101](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.100...@parca/profile@0.19.101) (2025-12-15)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @parca/profile
|
|
13
|
+
|
|
14
|
+
## [0.19.100](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.99...@parca/profile@0.19.100) (2025-12-15)
|
|
15
|
+
|
|
16
|
+
**Note:** Version bump only for package @parca/profile
|
|
17
|
+
|
|
18
|
+
## [0.19.99](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.98...@parca/profile@0.19.99) (2025-12-12)
|
|
19
|
+
|
|
20
|
+
**Note:** Version bump only for package @parca/profile
|
|
21
|
+
|
|
22
|
+
## [0.19.98](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.97...@parca/profile@0.19.98) (2025-12-12)
|
|
23
|
+
|
|
24
|
+
**Note:** Version bump only for package @parca/profile
|
|
25
|
+
|
|
26
|
+
## [0.19.97](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.96...@parca/profile@0.19.97) (2025-12-12)
|
|
27
|
+
|
|
28
|
+
**Note:** Version bump only for package @parca/profile
|
|
29
|
+
|
|
30
|
+
## [0.19.96](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.95...@parca/profile@0.19.96) (2025-12-12)
|
|
31
|
+
|
|
32
|
+
**Note:** Version bump only for package @parca/profile
|
|
33
|
+
|
|
6
34
|
## [0.19.95](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.94...@parca/profile@0.19.95) (2025-12-09)
|
|
7
35
|
|
|
8
36
|
**Note:** Version bump only for package @parca/profile
|
|
@@ -10,7 +10,7 @@ interface MetricsGraphSectionProps {
|
|
|
10
10
|
querySelection: QuerySelection;
|
|
11
11
|
profileSelection: ProfileSelection | null;
|
|
12
12
|
comparing: boolean;
|
|
13
|
-
sumBy: string[] |
|
|
13
|
+
sumBy: string[] | undefined;
|
|
14
14
|
defaultSumByLoading: boolean;
|
|
15
15
|
queryClient: QueryServiceClient;
|
|
16
16
|
queryExpressionString: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MetricsGraphSection.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/MetricsGraphSection.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAQ,kBAAkB,EAAC,MAAM,eAAe,CAAC;AACxD,OAAO,EAAC,aAAa,EAAmB,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAEpC,OAAO,EAAC,gBAAgB,EAAC,MAAM,IAAI,CAAC;AAGpC,OAAO,EAAC,cAAc,EAAC,MAAM,SAAS,CAAC;AAEvC,UAAU,wBAAwB;IAChC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gCAAgC,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,cAAc,CAAC;IAC/B,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,EAAE,GAAG,
|
|
1
|
+
{"version":3,"file":"MetricsGraphSection.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/MetricsGraphSection.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAQ,kBAAkB,EAAC,MAAM,eAAe,CAAC;AACxD,OAAO,EAAC,aAAa,EAAmB,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAEpC,OAAO,EAAC,gBAAgB,EAAC,MAAM,IAAI,CAAC;AAGpC,OAAO,EAAC,cAAc,EAAC,MAAM,SAAS,CAAC;AAEvC,UAAU,wBAAwB;IAChC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gCAAgC,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,cAAc,CAAC;IAC/B,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC5B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,WAAW,EAAE,kBAAkB,CAAC;IAChC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,qBAAqB,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACtD,WAAW,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC7C,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAChF,KAAK,EAAE,KAAK,CAAC;IACb,qBAAqB,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,IAAI,CAAC;IACzD,kBAAkB,EAAE,CAAC,QAAQ,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD,WAAW,EAAE,CACX,kBAAkB,CAAC,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAC,EACtE,UAAU,CAAC,EAAE,MAAM,KAChB,IAAI,CAAC;CACX;AAED,wBAAgB,mBAAmB,CAAC,EAClC,gBAAgB,EAChB,gCAAgC,EAChC,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,SAAS,EACT,KAAK,EACL,mBAAmB,EACnB,WAAW,EACX,qBAAqB,EACrB,qBAAqB,EACrB,WAAW,EACX,mBAAmB,EACnB,KAAK,EACL,qBAAqB,EACrB,WAAW,GACZ,EAAE,wBAAwB,GAAG,GAAG,CAAC,OAAO,CA+HxC"}
|
|
@@ -84,5 +84,5 @@ export function MetricsGraphSection({ showMetricsGraph, setDisplayHideMetricsGra
|
|
|
84
84
|
};
|
|
85
85
|
return (_jsxs("div", { className: cx('relative', { 'py-4': !showMetricsGraph }), children: [setDisplayHideMetricsGraphButton != null ? (_jsxs("button", { onClick: () => setDisplayHideMetricsGraphButton(!showMetricsGraph), className: cx('hidden px-3 py-1 text-sm font-medium text-gray-700 dark:text-gray-200 bg-gray-100 rounded-md hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:bg-gray-900 z-[5]', showMetricsGraph && 'absolute right-0 bottom-3 !flex', !showMetricsGraph && 'relative !flex ml-auto'), children: [showMetricsGraph ? 'Hide' : 'Show', " Metrics Graph"] })) : null, showMetricsGraph && (_jsx(_Fragment, { children: _jsx("div", { style: { height: heightStyle }, children: (querySelection.expression !== '' || defaultSumByLoading) &&
|
|
86
86
|
querySelection.from !== undefined &&
|
|
87
|
-
querySelection.to !== undefined ? (_jsx(_Fragment, { children: _jsx(ProfileMetricsGraph, { queryClient: queryClient, queryExpression: querySelection.expression, from: querySelection.from, to: querySelection.to, profile: profileSelection, comparing: comparing, sumBy:
|
|
87
|
+
querySelection.to !== undefined ? (_jsx(_Fragment, { children: _jsx(ProfileMetricsGraph, { queryClient: queryClient, queryExpression: querySelection.expression, from: querySelection.from, to: querySelection.to, profile: profileSelection, comparing: comparing, sumBy: sumBy ?? [], sumByLoading: defaultSumByLoading, setTimeRange: handleTimeRangeChange, addLabelMatcher: addLabelMatcher, onPointClick: handlePointClick }) })) : (profileSelection === null && (_jsx("div", { className: "p-2", children: _jsx(ProfileMetricsEmptyState, { message: "Please select a profile type and click 'Search' to begin." }) }))) }) }))] }));
|
|
88
88
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,QAAQ,EAAE,cAAc,EAAoD,MAAM,OAAO,CAAC;AAElG,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAElD,OAAO,EAAsB,oBAAoB,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAY5F,OAAO,EAAyB,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAY/E,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,uBAAuB;IAC/B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC;AAED,UAAU,oBAAqB,SAAQ,uBAAuB;IAC5D,WAAW,EAAE,kBAAkB,CAAC;IAChC,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,gCAAgC,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IACrE,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,KAAK,CAAC,EAAE,QAAQ,CAAC;CAClB;AAED,eAAO,MAAM,eAAe,GAC1B,QAAQ,kBAAkB,EAC1B,QAAQ,MAAM,EACd,MAAM,MAAM,KACX,mBAsBF,CAAC;AAEF,QAAA,MAAM,eAAe,GAAI,kMAYtB,oBAAoB,KAAG,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,QAAQ,EAAE,cAAc,EAAoD,MAAM,OAAO,CAAC;AAElG,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAElD,OAAO,EAAsB,oBAAoB,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAY5F,OAAO,EAAyB,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAY/E,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,uBAAuB;IAC/B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC;AAED,UAAU,oBAAqB,SAAQ,uBAAuB;IAC5D,WAAW,EAAE,kBAAkB,CAAC;IAChC,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,gCAAgC,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IACrE,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,KAAK,CAAC,EAAE,QAAQ,CAAC;CAClB;AAED,eAAO,MAAM,eAAe,GAC1B,QAAQ,kBAAkB,EAC1B,QAAQ,MAAM,EACd,MAAM,MAAM,KACX,mBAsBF,CAAC;AAEF,QAAA,MAAM,eAAe,GAAI,kMAYtB,oBAAoB,KAAG,GAAG,CAAC,OAqO7B,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -101,7 +101,6 @@ const ProfileSelector = ({ queryClient, closeProfile, enforcedProfileName, compa
|
|
|
101
101
|
const currentTo = timeRangeSelection.getToMs(true);
|
|
102
102
|
const currentRangeKey = timeRangeSelection.getRangeKey();
|
|
103
103
|
// Commit with refreshed time range
|
|
104
|
-
console.log('[draftExpression] setQueryExpression: committing with refreshed time range:', draftSelection.expression);
|
|
105
104
|
commitDraft({
|
|
106
105
|
from: currentFrom,
|
|
107
106
|
to: currentTo,
|
|
@@ -150,7 +149,7 @@ const ProfileSelector = ({ queryClient, closeProfile, enforcedProfileName, compa
|
|
|
150
149
|
queryExpressionString === '{}';
|
|
151
150
|
const queryBrowserRef = useRef(null);
|
|
152
151
|
const sumByRef = useRef(null);
|
|
153
|
-
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "mb-2 flex", children: [_jsx(LabelsQueryProvider, { setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query, profileType: selectedProfileName ?? profileType.toString(), queryClient: queryClient, start: timeRangeSelection.getFromMs(), end: timeRangeSelection.getToMs(), suffix: suffix, children: _jsx(LabelsSource, { children: _jsx(QueryControls, { showProfileTypeSelector: showProfileTypeSelector, showSumBySelector: showSumBySelector, profileTypesData: profileTypesData, profileTypesLoading: profileTypesLoading, selectedProfileName: selectedProfileName, setProfileName: setProfileName, setMatchersString: setMatchersString, setQueryExpression: setQueryExpression, query: query, queryBrowserRef: queryBrowserRef, timeRangeSelection: timeRangeSelection, setTimeRangeSelection: handleTimeRangeChange, searchDisabled: searchDisabled, setQueryBrowserMode: setQueryBrowserMode, advancedModeForQueryBrowser: advancedModeForQueryBrowser, setAdvancedModeForQueryBrowser: setAdvancedModeForQueryBrowser, queryClient: queryClient, sumByRef: sumByRef, labels: labels, sumBySelection: draftSelection.sumBy ?? [], sumBySelectionLoading: sumByLoading, setUserSumBySelection: setDraftSumBy, profileType: profileType, profileTypesError: error, viewComponent: viewComponent, draftSelection: draftSelection, setDraftMatchers: setDraftMatchers, draftParsedQuery: draftParsedQuery, commitDraft: commitDraft }) }) }), comparing && (_jsx("div", { children: _jsx(IconButton, { onClick: () => closeProfile(), icon: _jsx(CloseIcon, {}), ...testId(TEST_IDS.COMPARE_CLOSE_BUTTON) }) }))] }), _jsx(MetricsGraphSection, { showMetricsGraph: showMetricsGraph, setDisplayHideMetricsGraphButton: setDisplayHideMetricsGraphButton, heightStyle: heightStyle, querySelection: querySelection, profileSelection: profileSelection, comparing: comparing, sumBy: querySelection.sumBy
|
|
152
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "mb-2 flex", children: [_jsx(LabelsQueryProvider, { setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query, profileType: selectedProfileName ?? profileType.toString(), queryClient: queryClient, start: timeRangeSelection.getFromMs(), end: timeRangeSelection.getToMs(), suffix: suffix, children: _jsx(LabelsSource, { children: _jsx(QueryControls, { showProfileTypeSelector: showProfileTypeSelector, showSumBySelector: showSumBySelector, profileTypesData: profileTypesData, profileTypesLoading: profileTypesLoading, selectedProfileName: selectedProfileName, setProfileName: setProfileName, setMatchersString: setMatchersString, setQueryExpression: setQueryExpression, query: query, queryBrowserRef: queryBrowserRef, timeRangeSelection: timeRangeSelection, setTimeRangeSelection: handleTimeRangeChange, searchDisabled: searchDisabled, setQueryBrowserMode: setQueryBrowserMode, advancedModeForQueryBrowser: advancedModeForQueryBrowser, setAdvancedModeForQueryBrowser: setAdvancedModeForQueryBrowser, queryClient: queryClient, sumByRef: sumByRef, labels: labels, sumBySelection: draftSelection.sumBy ?? [], sumBySelectionLoading: sumByLoading, setUserSumBySelection: setDraftSumBy, profileType: profileType, profileTypesError: error, viewComponent: viewComponent, draftSelection: draftSelection, setDraftMatchers: setDraftMatchers, draftParsedQuery: draftParsedQuery, commitDraft: commitDraft }) }) }), comparing && (_jsx("div", { children: _jsx(IconButton, { onClick: () => closeProfile(), icon: _jsx(CloseIcon, {}), ...testId(TEST_IDS.COMPARE_CLOSE_BUTTON) }) }))] }), _jsx(MetricsGraphSection, { showMetricsGraph: showMetricsGraph, setDisplayHideMetricsGraphButton: setDisplayHideMetricsGraphButton, heightStyle: heightStyle, querySelection: querySelection, profileSelection: profileSelection, comparing: comparing, sumBy: querySelection.sumBy, defaultSumByLoading: sumByLoading, queryClient: queryClient, queryExpressionString: queryExpressionString, setTimeRangeSelection: handleTimeRangeChange, selectQuery: commitDraft, setProfileSelection: setProfileSelection, query: query, setQueryExpression: setQueryExpression, setNewQueryExpression: setDraftExpression, commitDraft: commitDraft })] }));
|
|
154
153
|
};
|
|
155
154
|
export default ProfileSelector;
|
|
156
155
|
const LabelsSource = ({ children }) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useResetStateOnProfileTypeChange.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useResetStateOnProfileTypeChange.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,gCAAgC,QAAO,CAAC,MAAM,IAAI,
|
|
1
|
+
{"version":3,"file":"useResetStateOnProfileTypeChange.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useResetStateOnProfileTypeChange.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,gCAAgC,QAAO,CAAC,MAAM,IAAI,CA+B9D,CAAC"}
|
|
@@ -15,6 +15,8 @@ import { useProfileFilters } from '../components/ProfileFilters/useProfileFilter
|
|
|
15
15
|
export const useResetStateOnProfileTypeChange = () => {
|
|
16
16
|
const [groupBy, setGroupBy] = useURLState('group_by');
|
|
17
17
|
const [curPath, setCurPath] = useURLState('cur_path');
|
|
18
|
+
const [sumByA, setSumByA] = useURLState('sum_by_a');
|
|
19
|
+
const [sumByB, setSumByB] = useURLState('sum_by_b');
|
|
18
20
|
const { resetFilters } = useProfileFilters();
|
|
19
21
|
const [sandwichFunctionName, setSandwichFunctionName] = useURLState('sandwich_function_name');
|
|
20
22
|
const batchUpdates = useURLStateBatch();
|
|
@@ -30,6 +32,12 @@ export const useResetStateOnProfileTypeChange = () => {
|
|
|
30
32
|
if (sandwichFunctionName !== undefined) {
|
|
31
33
|
setSandwichFunctionName(undefined);
|
|
32
34
|
}
|
|
35
|
+
if (sumByA !== undefined) {
|
|
36
|
+
setSumByA(undefined);
|
|
37
|
+
}
|
|
38
|
+
if (sumByB !== undefined) {
|
|
39
|
+
setSumByB(undefined);
|
|
40
|
+
}
|
|
33
41
|
resetFilters();
|
|
34
42
|
});
|
|
35
43
|
};
|
|
@@ -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,KAA2D,MAAM,OAAO,CAAC;AAShF,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,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAwUnE,CAAC;AAkDF,eAAe,YAAY,CAAC"}
|
|
@@ -11,7 +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 { useCallback, useEffect, useRef, useState } from 'react';
|
|
14
|
+
import { Fragment, 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';
|
|
@@ -177,9 +177,9 @@ const CustomSelect = ({ items: itemsProp, selectedKey, onSelection, placeholder
|
|
|
177
177
|
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, ...restProps, 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 max-h-[50vh] w-max overflow-auto rounded-md bg-gray-50 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: "relative flex flex-col", 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: () => {
|
|
178
178
|
onSelection(searchTerm);
|
|
179
179
|
setIsOpen(false);
|
|
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(
|
|
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 results", testId: TEST_IDS.LABEL_VALUE_REFRESH_BUTTON, sticky: true, loading: isRefetching }))] }) }))] }));
|
|
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)))] }, group.type)))) }), 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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useLabels.d.ts","sourceRoot":"","sources":["../../src/hooks/useLabels.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useLabels.d.ts","sourceRoot":"","sources":["../../src/hooks/useLabels.ts"],"names":[],"mappings":"AAeA,OAAO,EAAgB,cAAc,EAAE,kBAAkB,EAAgB,MAAM,eAAe,CAAC;AAM/F,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,UAAU,cAAc;IACtB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;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;IACjB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,eAAO,MAAM,aAAa,GACxB,QAAQ,kBAAkB,EAC1B,aAAa,MAAM,EACnB,QAAQ,MAAM,EACd,MAAM,MAAM,EACZ,QAAQ,MAAM,EAAE,KACf,aAkCF,CAAC;AAEF,eAAO,MAAM,cAAc,GACzB,QAAQ,kBAAkB,EAC1B,WAAW,MAAM,EACjB,aAAa,MAAM,EACnB,QAAQ,MAAM,EACd,MAAM,MAAM,KACX,cAiCF,CAAC"}
|
package/dist/hooks/useLabels.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
|
+
import { useEffect } from 'react';
|
|
13
14
|
import { useGrpcMetadata } from '@parca/components';
|
|
14
15
|
import { millisToProtoTimestamp, sanitizeLabelValue } from '@parca/utilities';
|
|
15
16
|
import useGrpcQuery from '../useGrpcQuery';
|
|
@@ -34,7 +35,9 @@ export const useLabelNames = (client, profileType, start, end, match) => {
|
|
|
34
35
|
keepPreviousData: false,
|
|
35
36
|
},
|
|
36
37
|
});
|
|
37
|
-
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
console.log('Label names query result:', { data, error, isLoading });
|
|
40
|
+
}, [data, error, isLoading]);
|
|
38
41
|
return {
|
|
39
42
|
result: { response: data, error: error },
|
|
40
43
|
loading: isLoading,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useQueryState.d.ts","sourceRoot":"","sources":["../../src/hooks/useQueryState.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAEpC,OAAO,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAC,gBAAgB,EAA8B,aAAa,EAAC,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"useQueryState.d.ts","sourceRoot":"","sources":["../../src/hooks/useQueryState.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAEpC,OAAO,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAC,gBAAgB,EAA8B,aAAa,EAAC,MAAM,kBAAkB,CAAC;AAK7F,UAAU,oBAAoB;IAC5B,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,UAAU,mBAAmB;IAE3B,cAAc,EAAE,cAAc,CAAC;IAG/B,cAAc,EAAE,cAAc,CAAC;IAG/B,kBAAkB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7E,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,KAAK,IAAI,CAAC;IACrD,mBAAmB,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,gBAAgB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAG7C,WAAW,EAAE,CAAC,kBAAkB,CAAC,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAC,KAAK,IAAI,CAAC;IAG9F,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAG1C,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;IAGpC,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAGhF,YAAY,EAAE,OAAO,CAAC;IAGtB,gBAAgB,EAAE,KAAK,GAAG,IAAI,CAAC;IAG/B,WAAW,EAAE,KAAK,GAAG,IAAI,CAAC;CAC3B;AAED,eAAO,MAAM,aAAa,GAAI,UAAS,oBAAyB,KAAG,mBAgZlE,CAAC"}
|
|
@@ -15,13 +15,15 @@ import { DateTimeRange, useParcaContext, useURLState, useURLStateBatch } from '@
|
|
|
15
15
|
import { Query } from '@parca/parser';
|
|
16
16
|
import { ProfileSelectionFromParams } from '../ProfileSource';
|
|
17
17
|
import { useResetFlameGraphState } from '../ProfileView/hooks/useResetFlameGraphState';
|
|
18
|
-
import {
|
|
18
|
+
import { useResetStateOnProfileTypeChange } from '../ProfileView/hooks/useResetStateOnProfileTypeChange';
|
|
19
|
+
import { DEFAULT_EMPTY_SUM_BY, sumByToParam, useSumBy, useSumByFromParams } from '../useSumBy';
|
|
19
20
|
export const useQueryState = (options = {}) => {
|
|
20
21
|
const { queryServiceClient: queryClient } = useParcaContext();
|
|
21
22
|
const { suffix = '', defaultExpression = '', defaultTimeSelection = 'relative:minute|15', // Default to 15 minutes relative
|
|
22
23
|
defaultFrom, defaultTo, comparing = false, } = options;
|
|
23
24
|
const batchUpdates = useURLStateBatch();
|
|
24
25
|
const resetFlameGraphState = useResetFlameGraphState();
|
|
26
|
+
const resetStateOnProfileTypeChange = useResetStateOnProfileTypeChange();
|
|
25
27
|
// URL state hooks with appropriate suffixes
|
|
26
28
|
const [expression, setExpressionState] = useURLState(`expression${suffix}`, {
|
|
27
29
|
defaultValue: defaultExpression,
|
|
@@ -47,23 +49,6 @@ export const useQueryState = (options = {}) => {
|
|
|
47
49
|
const [draftFrom, setDraftFrom] = useState(from ?? defaultFrom?.toString() ?? '');
|
|
48
50
|
const [draftTo, setDraftTo] = useState(to ?? defaultTo?.toString() ?? '');
|
|
49
51
|
const [draftTimeSelection, setDraftTimeSelection] = useState(timeSelection ?? defaultTimeSelection);
|
|
50
|
-
const [draftSumBy, setDraftSumBy] = useState(sumBy);
|
|
51
|
-
// Sync draft state with URL state when URL changes externally
|
|
52
|
-
useEffect(() => {
|
|
53
|
-
setDraftExpression(expression ?? defaultExpression);
|
|
54
|
-
}, [expression, defaultExpression]);
|
|
55
|
-
useEffect(() => {
|
|
56
|
-
setDraftFrom(from ?? defaultFrom?.toString() ?? '');
|
|
57
|
-
}, [from, defaultFrom]);
|
|
58
|
-
useEffect(() => {
|
|
59
|
-
setDraftTo(to ?? defaultTo?.toString() ?? '');
|
|
60
|
-
}, [to, defaultTo]);
|
|
61
|
-
useEffect(() => {
|
|
62
|
-
setDraftTimeSelection(timeSelection ?? defaultTimeSelection);
|
|
63
|
-
}, [timeSelection, defaultTimeSelection]);
|
|
64
|
-
useEffect(() => {
|
|
65
|
-
setDraftSumBy(sumBy);
|
|
66
|
-
}, [sumBy]);
|
|
67
52
|
// Parse the draft query to extract profile information
|
|
68
53
|
const draftQuery = useMemo(() => {
|
|
69
54
|
try {
|
|
@@ -73,14 +58,46 @@ export const useQueryState = (options = {}) => {
|
|
|
73
58
|
return Query.parse('');
|
|
74
59
|
}
|
|
75
60
|
}, [draftExpression]);
|
|
61
|
+
const query = useMemo(() => {
|
|
62
|
+
try {
|
|
63
|
+
return Query.parse(expression ?? '');
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return Query.parse('');
|
|
67
|
+
}
|
|
68
|
+
}, [expression]);
|
|
76
69
|
const draftProfileType = useMemo(() => draftQuery.profileType(), [draftQuery]);
|
|
77
70
|
const draftProfileName = useMemo(() => draftQuery.profileName(), [draftQuery]);
|
|
71
|
+
const profileType = useMemo(() => query.profileType(), [query]);
|
|
78
72
|
// Compute draft time range for label fetching
|
|
79
73
|
const draftTimeRange = useMemo(() => {
|
|
80
74
|
return DateTimeRange.fromRangeKey(draftTimeSelection ?? defaultTimeSelection, draftFrom !== '' ? parseInt(draftFrom) : defaultFrom, draftTo !== '' ? parseInt(draftTo) : defaultTo);
|
|
81
75
|
}, [draftTimeSelection, draftFrom, draftTo, defaultTimeSelection, defaultFrom, defaultTo]);
|
|
82
76
|
// Use combined sumBy hook for fetching labels and computing defaults (based on committed state)
|
|
83
|
-
const { sumBy: computedSumByFromURL, isLoading: sumBySelectionLoading } = useSumBy(queryClient, draftProfileType, draftTimeRange, sumBy);
|
|
77
|
+
const { sumBy: computedSumByFromURL, isLoading: sumBySelectionLoading, draftSumBy, setDraftSumBy, isDraftSumByLoading, } = useSumBy(queryClient, profileType?.profileName !== '' ? profileType : draftProfileType, draftTimeRange, draftProfileType, draftTimeRange, sumBy);
|
|
78
|
+
// Sync draft state with URL state when URL changes externally
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
setDraftExpression(expression ?? defaultExpression);
|
|
81
|
+
}, [expression, defaultExpression]);
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
setDraftFrom(from ?? defaultFrom?.toString() ?? '');
|
|
84
|
+
}, [from, defaultFrom]);
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
setDraftTo(to ?? defaultTo?.toString() ?? '');
|
|
87
|
+
}, [to, defaultTo]);
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
setDraftTimeSelection(timeSelection ?? defaultTimeSelection);
|
|
90
|
+
}, [timeSelection, defaultTimeSelection]);
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
setDraftSumBy(sumBy);
|
|
93
|
+
}, [sumBy, setDraftSumBy]);
|
|
94
|
+
// Sync computed sumBy to URL if URL doesn't already have a value
|
|
95
|
+
// to ensure the shared URL can always pick it up.
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
if (sumByParam === undefined && computedSumByFromURL !== undefined && !sumBySelectionLoading) {
|
|
98
|
+
setSumByParam(sumByToParam(computedSumByFromURL));
|
|
99
|
+
}
|
|
100
|
+
}, [sumByParam, computedSumByFromURL, sumBySelectionLoading, setSumByParam]);
|
|
84
101
|
// Construct the QuerySelection object (committed state from URL)
|
|
85
102
|
const querySelection = useMemo(() => {
|
|
86
103
|
const range = DateTimeRange.fromRangeKey(timeSelection ?? defaultTimeSelection, from !== undefined && from !== '' ? parseInt(from) : defaultFrom, to !== undefined && to !== '' ? parseInt(to) : defaultTo);
|
|
@@ -180,11 +197,16 @@ export const useQueryState = (options = {}) => {
|
|
|
180
197
|
setFromState(finalFrom);
|
|
181
198
|
setToState(finalTo);
|
|
182
199
|
setTimeSelectionState(finalTimeSelection);
|
|
183
|
-
setSumByParam(sumByToParam(draftSumBy));
|
|
184
200
|
// Auto-calculate merge parameters for delta profiles
|
|
185
201
|
// Parse the final expression to check if it's a delta profile
|
|
186
202
|
const finalQuery = Query.parse(finalExpression);
|
|
187
203
|
const isDelta = finalQuery.profileType().delta;
|
|
204
|
+
if (isDelta) {
|
|
205
|
+
setSumByParam(sumByToParam(draftSumBy));
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
setSumByParam(DEFAULT_EMPTY_SUM_BY);
|
|
209
|
+
}
|
|
188
210
|
if (isDelta && finalFrom !== '' && finalTo !== '') {
|
|
189
211
|
const fromMs = parseInt(finalFrom);
|
|
190
212
|
const toMs = parseInt(finalTo);
|
|
@@ -207,6 +229,10 @@ export const useQueryState = (options = {}) => {
|
|
|
207
229
|
setSelectionParam(undefined);
|
|
208
230
|
}
|
|
209
231
|
resetFlameGraphState();
|
|
232
|
+
if (draftProfileType.toString() !==
|
|
233
|
+
Query.parse(querySelection.expression).profileType().toString()) {
|
|
234
|
+
resetStateOnProfileTypeChange();
|
|
235
|
+
}
|
|
210
236
|
});
|
|
211
237
|
}, [
|
|
212
238
|
batchUpdates,
|
|
@@ -227,6 +253,9 @@ export const useQueryState = (options = {}) => {
|
|
|
227
253
|
setMergeToState,
|
|
228
254
|
setSelectionParam,
|
|
229
255
|
resetFlameGraphState,
|
|
256
|
+
resetStateOnProfileTypeChange,
|
|
257
|
+
draftProfileType,
|
|
258
|
+
querySelection.expression,
|
|
230
259
|
]);
|
|
231
260
|
const setDraftTimeRange = useCallback((newFrom, newTo, newTimeSelection) => {
|
|
232
261
|
setDraftFrom(newFrom.toString());
|
|
@@ -235,15 +264,16 @@ export const useQueryState = (options = {}) => {
|
|
|
235
264
|
}, []);
|
|
236
265
|
const setDraftSumByCallback = useCallback((newSumBy) => {
|
|
237
266
|
setDraftSumBy(newSumBy);
|
|
238
|
-
}, []);
|
|
267
|
+
}, [setDraftSumBy]);
|
|
239
268
|
const setDraftProfileName = useCallback((newProfileName) => {
|
|
240
269
|
if (newProfileName === '')
|
|
241
270
|
return;
|
|
242
271
|
const [newQuery, changed] = draftQuery.setProfileName(newProfileName);
|
|
243
272
|
if (changed) {
|
|
244
273
|
setDraftExpression(newQuery.toString());
|
|
274
|
+
setDraftSumBy(undefined);
|
|
245
275
|
}
|
|
246
|
-
}, [draftQuery]);
|
|
276
|
+
}, [draftQuery, setDraftSumBy]);
|
|
247
277
|
const setDraftMatchers = useCallback((matchers) => {
|
|
248
278
|
const newExpression = `${draftProfileName}{${matchers}}`;
|
|
249
279
|
setDraftExpression(newExpression);
|
|
@@ -290,7 +320,7 @@ export const useQueryState = (options = {}) => {
|
|
|
290
320
|
profileSource,
|
|
291
321
|
setProfileSelection,
|
|
292
322
|
// Loading state
|
|
293
|
-
sumByLoading: sumBySelectionLoading,
|
|
323
|
+
sumByLoading: isDraftSumByLoading || sumBySelectionLoading,
|
|
294
324
|
draftParsedQuery,
|
|
295
325
|
parsedQuery,
|
|
296
326
|
};
|
|
@@ -52,16 +52,24 @@ vi.mock('@parca/components/src/hooks/URLState/utils', async () => {
|
|
|
52
52
|
},
|
|
53
53
|
};
|
|
54
54
|
});
|
|
55
|
-
// Mock useSumBy
|
|
55
|
+
// Mock useSumBy with stateful behavior using React's useState
|
|
56
56
|
vi.mock('../useSumBy', async () => {
|
|
57
57
|
const actual = await vi.importActual('../useSumBy');
|
|
58
|
+
const react = await import('react');
|
|
58
59
|
return {
|
|
59
60
|
...actual,
|
|
60
|
-
useSumBy: (_queryClient, _profileType, _timeRange, defaultValue) =>
|
|
61
|
-
|
|
62
|
-
setSumBy
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
useSumBy: (_queryClient, _profileType, _timeRange, _draftProfileType, _draftTimeRange, defaultValue) => {
|
|
62
|
+
const [draftSumBy, setDraftSumBy] = react.useState(defaultValue);
|
|
63
|
+
const [sumBy, setSumBy] = react.useState(defaultValue);
|
|
64
|
+
return {
|
|
65
|
+
sumBy,
|
|
66
|
+
setSumBy,
|
|
67
|
+
isLoading: false,
|
|
68
|
+
draftSumBy,
|
|
69
|
+
setDraftSumBy,
|
|
70
|
+
isDraftSumByLoading: false,
|
|
71
|
+
};
|
|
72
|
+
},
|
|
65
73
|
};
|
|
66
74
|
});
|
|
67
75
|
// Helper to create wrapper with URLStateProvider
|
|
@@ -154,7 +162,9 @@ describe('useQueryState', () => {
|
|
|
154
162
|
});
|
|
155
163
|
it('should update sumBy', async () => {
|
|
156
164
|
const { result } = renderHook(() => useQueryState(), { wrapper: createWrapper() });
|
|
165
|
+
// sumBy only applies to delta profiles, so we need to set one first
|
|
157
166
|
act(() => {
|
|
167
|
+
result.current.setDraftExpression('process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta{}');
|
|
158
168
|
result.current.setDraftSumBy(['namespace', 'container']);
|
|
159
169
|
});
|
|
160
170
|
// Draft should be updated
|
|
@@ -193,13 +203,13 @@ describe('useQueryState', () => {
|
|
|
193
203
|
it('should batch multiple updates into single navigation', async () => {
|
|
194
204
|
const { result } = renderHook(() => useQueryState(), { wrapper: createWrapper() });
|
|
195
205
|
act(() => {
|
|
196
|
-
// Update multiple draft values
|
|
197
|
-
result.current.setDraftExpression('memory:
|
|
206
|
+
// Update multiple draft values (using delta profile since sumBy only applies to delta)
|
|
207
|
+
result.current.setDraftExpression('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
198
208
|
result.current.setDraftTimeRange(7000, 8000, 'relative:minute|30');
|
|
199
209
|
result.current.setDraftSumBy(['pod', 'node']);
|
|
200
210
|
});
|
|
201
211
|
// All drafts should be updated
|
|
202
|
-
expect(result.current.draftSelection.expression).toBe('memory:
|
|
212
|
+
expect(result.current.draftSelection.expression).toBe('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
203
213
|
expect(result.current.draftSelection.from).toBe(7000);
|
|
204
214
|
expect(result.current.draftSelection.to).toBe(8000);
|
|
205
215
|
expect(result.current.draftSelection.sumBy).toEqual(['pod', 'node']);
|
|
@@ -210,7 +220,7 @@ describe('useQueryState', () => {
|
|
|
210
220
|
// Should only navigate once for all updates
|
|
211
221
|
expect(mockNavigateTo).toHaveBeenCalledTimes(1);
|
|
212
222
|
const [, params] = mockNavigateTo.mock.calls[0];
|
|
213
|
-
expect(params.expression).toBe('memory:
|
|
223
|
+
expect(params.expression).toBe('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
214
224
|
expect(params.from).toBe('7000');
|
|
215
225
|
expect(params.to).toBe('8000');
|
|
216
226
|
expect(params.time_selection).toBe('relative:minute|30');
|
|
@@ -325,9 +335,9 @@ describe('useQueryState', () => {
|
|
|
325
335
|
});
|
|
326
336
|
it('should handle _b suffix correctly', async () => {
|
|
327
337
|
const { result } = renderHook(() => useQueryState({ suffix: '_b' }), { wrapper: createWrapper() });
|
|
328
|
-
// Update draft state
|
|
338
|
+
// Update draft state (using delta profile since sumBy only applies to delta)
|
|
329
339
|
act(() => {
|
|
330
|
-
result.current.setDraftExpression('memory:
|
|
340
|
+
result.current.setDraftExpression('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
331
341
|
result.current.setDraftTimeRange(3333, 4444, 'relative:hour|2');
|
|
332
342
|
result.current.setDraftSumBy(['label_b']);
|
|
333
343
|
});
|
|
@@ -338,7 +348,7 @@ describe('useQueryState', () => {
|
|
|
338
348
|
await waitFor(() => {
|
|
339
349
|
expect(mockNavigateTo).toHaveBeenCalled();
|
|
340
350
|
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
341
|
-
expect(params.expression_b).toBe('memory:
|
|
351
|
+
expect(params.expression_b).toBe('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
342
352
|
expect(params.from_b).toBe('3333');
|
|
343
353
|
expect(params.to_b).toBe('4444');
|
|
344
354
|
expect(params.sum_by_b).toBe('label_b');
|
|
@@ -348,9 +358,9 @@ describe('useQueryState', () => {
|
|
|
348
358
|
describe('Draft state pattern', () => {
|
|
349
359
|
it('should not update URL until commit', async () => {
|
|
350
360
|
const { result } = renderHook(() => useQueryState(), { wrapper: createWrapper() });
|
|
351
|
-
// Make multiple draft changes
|
|
361
|
+
// Make multiple draft changes (using delta profile since sumBy only applies to delta)
|
|
352
362
|
act(() => {
|
|
353
|
-
result.current.setDraftExpression('memory:
|
|
363
|
+
result.current.setDraftExpression('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
354
364
|
result.current.setDraftTimeRange(5000, 6000, 'relative:hour|3');
|
|
355
365
|
result.current.setDraftSumBy(['namespace', 'pod']);
|
|
356
366
|
});
|
|
@@ -364,7 +374,7 @@ describe('useQueryState', () => {
|
|
|
364
374
|
await waitFor(() => {
|
|
365
375
|
expect(mockNavigateTo).toHaveBeenCalledTimes(1);
|
|
366
376
|
const [, params] = mockNavigateTo.mock.calls[0];
|
|
367
|
-
expect(params.expression).toBe('memory:
|
|
377
|
+
expect(params.expression).toBe('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
368
378
|
expect(params.from).toBe('5000');
|
|
369
379
|
expect(params.to).toBe('6000');
|
|
370
380
|
expect(params.sum_by).toBe('namespace,pod');
|
|
@@ -563,15 +573,15 @@ describe('useQueryState', () => {
|
|
|
563
573
|
});
|
|
564
574
|
describe('State persistence after page reload', () => {
|
|
565
575
|
it('should retain committed values after page reload simulation', async () => {
|
|
566
|
-
// Initial state
|
|
576
|
+
// Initial state (using delta profile since sumBy only applies to delta)
|
|
567
577
|
mockLocation.search =
|
|
568
|
-
'?expression=process_cpu:cpu:nanoseconds:cpu:nanoseconds{}&from=1000&to=2000';
|
|
578
|
+
'?expression=process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta{}&from=1000&to=2000';
|
|
569
579
|
const { result: result1, unmount } = renderHook(() => useQueryState(), {
|
|
570
580
|
wrapper: createWrapper(),
|
|
571
581
|
});
|
|
572
|
-
// User makes changes to draft
|
|
582
|
+
// User makes changes to draft (using delta profile since sumBy only applies to delta)
|
|
573
583
|
act(() => {
|
|
574
|
-
result1.current.setDraftExpression('memory:
|
|
584
|
+
result1.current.setDraftExpression('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
575
585
|
result1.current.setDraftTimeRange(5000, 6000, 'relative:minute|15');
|
|
576
586
|
result1.current.setDraftSumBy(['namespace', 'pod']);
|
|
577
587
|
});
|
|
@@ -600,13 +610,13 @@ describe('useQueryState', () => {
|
|
|
600
610
|
// Create new hook instance (simulating page reload)
|
|
601
611
|
const { result: result2 } = renderHook(() => useQueryState(), { wrapper: createWrapper() });
|
|
602
612
|
// Verify state is loaded from URL after "reload"
|
|
603
|
-
expect(result2.current.querySelection.expression).toBe('memory:
|
|
613
|
+
expect(result2.current.querySelection.expression).toBe('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
604
614
|
expect(result2.current.querySelection.from).toBe(5000);
|
|
605
615
|
expect(result2.current.querySelection.to).toBe(6000);
|
|
606
616
|
expect(result2.current.querySelection.timeSelection).toBe('relative:minute|15');
|
|
607
617
|
expect(result2.current.querySelection.sumBy).toEqual(['namespace', 'pod']);
|
|
608
618
|
// Draft should be synced with URL state on page load
|
|
609
|
-
expect(result2.current.draftSelection.expression).toBe('memory:
|
|
619
|
+
expect(result2.current.draftSelection.expression).toBe('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
610
620
|
expect(result2.current.draftSelection.from).toBe(5000);
|
|
611
621
|
expect(result2.current.draftSelection.to).toBe(6000);
|
|
612
622
|
expect(result2.current.draftSelection.sumBy).toEqual(['namespace', 'pod']);
|
package/dist/useSumBy.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { QueryServiceClient } from '@parca/client';
|
|
|
2
2
|
import { DateTimeRange } from '@parca/components';
|
|
3
3
|
import { ProfileType } from '@parca/parser';
|
|
4
4
|
export declare const DEFAULT_EMPTY_SUM_BY: string[];
|
|
5
|
-
export declare const useSumBySelection: (profileType: ProfileType | undefined, labelNamesLoading: boolean, labels: string[] | undefined, { defaultValue, }?: {
|
|
5
|
+
export declare const useSumBySelection: (profileType: ProfileType | undefined, labelNamesLoading: boolean, labels: string[] | undefined, draftSumBy: string[] | undefined, { defaultValue, }?: {
|
|
6
6
|
defaultValue?: string[];
|
|
7
7
|
}) => [string[] | undefined, (labels: string[]) => void, {
|
|
8
8
|
isLoading: boolean;
|
|
@@ -13,9 +13,17 @@ export declare const useDefaultSumBy: (profileType: ProfileType | undefined, lab
|
|
|
13
13
|
};
|
|
14
14
|
export declare const useSumByFromParams: (param: string | string[] | undefined) => string[] | undefined;
|
|
15
15
|
export declare const sumByToParam: (sumBy: string[] | undefined) => string | string[] | undefined;
|
|
16
|
-
export declare const useSumBy: (queryClient: QueryServiceClient, profileType: ProfileType | undefined, timeRange: DateTimeRange, defaultValue?: string[]) => {
|
|
16
|
+
export declare const useSumBy: (queryClient: QueryServiceClient, profileType: ProfileType | undefined, timeRange: DateTimeRange, draftProfileType: ProfileType | undefined, draftTimeRange: DateTimeRange, defaultValue?: string[]) => {
|
|
17
17
|
sumBy: string[] | undefined;
|
|
18
18
|
setSumBy: (sumBy: string[]) => void;
|
|
19
19
|
isLoading: boolean;
|
|
20
|
+
draftSumBy: string[] | undefined;
|
|
21
|
+
setDraftSumBy: (sumBy: string[] | undefined) => void;
|
|
22
|
+
isDraftSumByLoading: boolean;
|
|
23
|
+
};
|
|
24
|
+
export declare const useDraftSumBy: (queryClient: QueryServiceClient, profileType: ProfileType | undefined, timeRange: DateTimeRange, defaultValue?: string[]) => {
|
|
25
|
+
draftSumBy: string[] | undefined;
|
|
26
|
+
setDraftSumBy: (sumBy: string[] | undefined) => void;
|
|
27
|
+
isDraftSumByLoading: boolean;
|
|
20
28
|
};
|
|
21
29
|
//# sourceMappingURL=useSumBy.d.ts.map
|
package/dist/useSumBy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSumBy.d.ts","sourceRoot":"","sources":["../src/useSumBy.ts"],"names":[],"mappings":"AAeA,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AACjD,OAAO,EAAC,aAAa,EAAC,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAI1C,eAAO,MAAM,oBAAoB,EAAE,MAAM,EAAO,CAAC;AA6BjD,eAAO,MAAM,iBAAiB,GAC5B,aAAa,WAAW,GAAG,SAAS,EACpC,mBAAmB,OAAO,EAC1B,QAAQ,MAAM,EAAE,GAAG,SAAS,EAC5B,oBAEG;IACD,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,KACL,CACD,MAAM,EAAE,GAAG,SAAS,EACpB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,EAC1B;IACE,SAAS,EAAE,OAAO,CAAC;CACpB,
|
|
1
|
+
{"version":3,"file":"useSumBy.d.ts","sourceRoot":"","sources":["../src/useSumBy.ts"],"names":[],"mappings":"AAeA,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AACjD,OAAO,EAAC,aAAa,EAAC,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAI1C,eAAO,MAAM,oBAAoB,EAAE,MAAM,EAAO,CAAC;AA6BjD,eAAO,MAAM,iBAAiB,GAC5B,aAAa,WAAW,GAAG,SAAS,EACpC,mBAAmB,OAAO,EAC1B,QAAQ,MAAM,EAAE,GAAG,SAAS,EAC5B,YAAY,MAAM,EAAE,GAAG,SAAS,EAChC,oBAEG;IACD,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,KACL,CACD,MAAM,EAAE,GAAG,SAAS,EACpB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,EAC1B;IACE,SAAS,EAAE,OAAO,CAAC;CACpB,CAqEF,CAAC;AAEF,eAAO,MAAM,eAAe,GAC1B,aAAa,WAAW,GAAG,SAAS,EACpC,mBAAmB,OAAO,EAC1B,QAAQ,MAAM,EAAE,GAAG,SAAS,KAC3B;IAAC,YAAY,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAMzD,CAAC;AAyBF,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,KAAG,MAAM,EAAE,GAAG,SAMpF,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,OAAO,MAAM,EAAE,GAAG,SAAS,KAAG,MAAM,GAAG,MAAM,EAAE,GAAG,SAU9E,CAAC;AAGF,eAAO,MAAM,QAAQ,GACnB,aAAa,kBAAkB,EAC/B,aAAa,WAAW,GAAG,SAAS,EACpC,WAAW,aAAa,EACxB,kBAAkB,WAAW,GAAG,SAAS,EACzC,gBAAgB,aAAa,EAC7B,eAAe,MAAM,EAAE,KACtB;IACD,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC5B,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACpC,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACjC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,KAAK,IAAI,CAAC;IACrD,mBAAmB,EAAE,OAAO,CAAC;CAoC9B,CAAC;AAEF,eAAO,MAAM,aAAa,GACxB,aAAa,kBAAkB,EAC/B,aAAa,WAAW,GAAG,SAAS,EACpC,WAAW,aAAa,EACxB,eAAe,MAAM,EAAE,KACtB;IACD,UAAU,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACjC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,KAAK,IAAI,CAAC;IACrD,mBAAmB,EAAE,OAAO,CAAC;CAqB9B,CAAC"}
|
package/dist/useSumBy.js
CHANGED
|
@@ -31,7 +31,7 @@ const getDefaultSumBy = (profile, labels) => {
|
|
|
31
31
|
}
|
|
32
32
|
return undefined;
|
|
33
33
|
};
|
|
34
|
-
export const useSumBySelection = (profileType, labelNamesLoading, labels, { defaultValue, } = {}) => {
|
|
34
|
+
export const useSumBySelection = (profileType, labelNamesLoading, labels, draftSumBy, { defaultValue, } = {}) => {
|
|
35
35
|
const [userSelectedSumBy, setUserSelectedSumBy] = useState(profileType != null ? { [profileType.toString()]: defaultValue } : {});
|
|
36
36
|
// Update userSelectedSumBy when defaultValue changes (e.g., during navigation)
|
|
37
37
|
useEffect(() => {
|
|
@@ -57,9 +57,15 @@ export const useSumBySelection = (profileType, labelNamesLoading, labels, { defa
|
|
|
57
57
|
// Store the last valid sumBy value to return during loading
|
|
58
58
|
const lastValidSumByRef = useRef(DEFAULT_EMPTY_SUM_BY);
|
|
59
59
|
const sumBy = useMemo(() => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
if (labelNamesLoading) {
|
|
61
|
+
// For smoother UX, return draftSumBy first if available during loading
|
|
62
|
+
// as this must be recently computed with the draft time range labels.
|
|
63
|
+
if (draftSumBy !== undefined) {
|
|
64
|
+
return draftSumBy;
|
|
65
|
+
}
|
|
66
|
+
if (lastValidSumByRef.current == null) {
|
|
67
|
+
return lastValidSumByRef.current;
|
|
68
|
+
}
|
|
63
69
|
}
|
|
64
70
|
let result = userSelectedSumBy[profileType?.toString() ?? ''] ?? defaultSumBy ?? DEFAULT_EMPTY_SUM_BY;
|
|
65
71
|
if (profileType?.delta !== true) {
|
|
@@ -68,7 +74,7 @@ export const useSumBySelection = (profileType, labelNamesLoading, labels, { defa
|
|
|
68
74
|
// Store the computed value for next loading state
|
|
69
75
|
lastValidSumByRef.current = result;
|
|
70
76
|
return result;
|
|
71
|
-
}, [userSelectedSumBy, profileType, defaultSumBy, labelNamesLoading]);
|
|
77
|
+
}, [userSelectedSumBy, profileType, defaultSumBy, labelNamesLoading, draftSumBy]);
|
|
72
78
|
return [
|
|
73
79
|
sumBy,
|
|
74
80
|
setSumBy,
|
|
@@ -118,15 +124,32 @@ export const sumByToParam = (sumBy) => {
|
|
|
118
124
|
return sumBy;
|
|
119
125
|
};
|
|
120
126
|
// Combined hook that handles all sumBy logic: fetching labels, computing defaults, and managing selection
|
|
121
|
-
export const useSumBy = (queryClient, profileType, timeRange, defaultValue) => {
|
|
127
|
+
export const useSumBy = (queryClient, profileType, timeRange, draftProfileType, draftTimeRange, defaultValue) => {
|
|
122
128
|
const { loading: labelNamesLoading, result } = useLabelNames(queryClient, profileType?.toString() ?? '', timeRange.getFromMs(), timeRange.getToMs());
|
|
129
|
+
const { draftSumBy, setDraftSumBy, isDraftSumByLoading } = useDraftSumBy(queryClient, draftProfileType, draftTimeRange, defaultValue);
|
|
123
130
|
const labels = useMemo(() => {
|
|
124
131
|
return result.response?.labelNames === undefined ? [] : result.response.labelNames;
|
|
125
132
|
}, [result]);
|
|
126
|
-
const [sumBySelection, setSumByInternal, { isLoading }] = useSumBySelection(profileType, labelNamesLoading, labels, { defaultValue });
|
|
133
|
+
const [sumBySelection, setSumByInternal, { isLoading }] = useSumBySelection(profileType, labelNamesLoading, labels, draftSumBy, { defaultValue });
|
|
127
134
|
return {
|
|
128
135
|
sumBy: sumBySelection,
|
|
129
136
|
setSumBy: setSumByInternal,
|
|
130
137
|
isLoading,
|
|
138
|
+
draftSumBy,
|
|
139
|
+
setDraftSumBy,
|
|
140
|
+
isDraftSumByLoading,
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
export const useDraftSumBy = (queryClient, profileType, timeRange, defaultValue) => {
|
|
144
|
+
const [draftSumBy, setDraftSumBy] = useState(defaultValue);
|
|
145
|
+
const { loading: labelNamesLoading, result } = useLabelNames(queryClient, profileType?.toString() ?? '', timeRange.getFromMs(), timeRange.getToMs());
|
|
146
|
+
const labels = useMemo(() => {
|
|
147
|
+
return result.response?.labelNames === undefined ? [] : result.response.labelNames;
|
|
148
|
+
}, [result]);
|
|
149
|
+
const { defaultSumBy, isLoading } = useDefaultSumBy(profileType, labelNamesLoading, labels);
|
|
150
|
+
return {
|
|
151
|
+
draftSumBy: draftSumBy ?? defaultSumBy ?? DEFAULT_EMPTY_SUM_BY,
|
|
152
|
+
setDraftSumBy: setDraftSumBy,
|
|
153
|
+
isDraftSumByLoading: isLoading,
|
|
131
154
|
};
|
|
132
155
|
};
|
package/package.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parca/profile",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.102",
|
|
4
4
|
"description": "Profile viewing libraries",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@floating-ui/react": "^0.27.12",
|
|
7
7
|
"@headlessui/react": "^1.7.19",
|
|
8
8
|
"@iconify/react": "^4.0.0",
|
|
9
|
-
"@parca/client": "0.17.
|
|
10
|
-
"@parca/components": "0.16.
|
|
11
|
-
"@parca/dynamicsize": "0.16.
|
|
12
|
-
"@parca/hooks": "0.0.
|
|
13
|
-
"@parca/icons": "0.16.
|
|
14
|
-
"@parca/parser": "0.16.
|
|
15
|
-
"@parca/store": "0.16.
|
|
9
|
+
"@parca/client": "0.17.16",
|
|
10
|
+
"@parca/components": "0.16.392",
|
|
11
|
+
"@parca/dynamicsize": "0.16.72",
|
|
12
|
+
"@parca/hooks": "0.0.116",
|
|
13
|
+
"@parca/icons": "0.16.79",
|
|
14
|
+
"@parca/parser": "0.16.86",
|
|
15
|
+
"@parca/store": "0.16.199",
|
|
16
16
|
"@parca/test-utils": "0.0.17",
|
|
17
|
-
"@parca/utilities": "0.0.
|
|
17
|
+
"@parca/utilities": "0.0.122",
|
|
18
18
|
"@popperjs/core": "^2.11.8",
|
|
19
19
|
"@protobuf-ts/runtime-rpc": "^2.5.0",
|
|
20
20
|
"@storybook/preview-api": "^8.4.3",
|
|
@@ -75,9 +75,14 @@
|
|
|
75
75
|
"keywords": [],
|
|
76
76
|
"author": "",
|
|
77
77
|
"license": "ISC",
|
|
78
|
+
"repository": {
|
|
79
|
+
"type": "git",
|
|
80
|
+
"url": "https://github.com/parca-dev/parca",
|
|
81
|
+
"directory": "ui/packages/shared/profile"
|
|
82
|
+
},
|
|
78
83
|
"publishConfig": {
|
|
79
84
|
"access": "public",
|
|
80
85
|
"registry": "https://registry.npmjs.org/"
|
|
81
86
|
},
|
|
82
|
-
"gitHead": "
|
|
87
|
+
"gitHead": "71d719bdbc5b9591b427c668b4ab9685eeb44b4a"
|
|
83
88
|
}
|
|
@@ -29,7 +29,7 @@ interface MetricsGraphSectionProps {
|
|
|
29
29
|
querySelection: QuerySelection;
|
|
30
30
|
profileSelection: ProfileSelection | null;
|
|
31
31
|
comparing: boolean;
|
|
32
|
-
sumBy: string[] |
|
|
32
|
+
sumBy: string[] | undefined;
|
|
33
33
|
defaultSumByLoading: boolean;
|
|
34
34
|
queryClient: QueryServiceClient;
|
|
35
35
|
queryExpressionString: string;
|
|
@@ -170,7 +170,7 @@ export function MetricsGraphSection({
|
|
|
170
170
|
to={querySelection.to}
|
|
171
171
|
profile={profileSelection}
|
|
172
172
|
comparing={comparing}
|
|
173
|
-
sumBy={
|
|
173
|
+
sumBy={sumBy ?? []}
|
|
174
174
|
sumByLoading={defaultSumByLoading}
|
|
175
175
|
setTimeRange={handleTimeRangeChange}
|
|
176
176
|
addLabelMatcher={addLabelMatcher}
|
|
@@ -209,10 +209,6 @@ const ProfileSelector = ({
|
|
|
209
209
|
const currentTo = timeRangeSelection.getToMs(true);
|
|
210
210
|
const currentRangeKey = timeRangeSelection.getRangeKey();
|
|
211
211
|
// Commit with refreshed time range
|
|
212
|
-
console.log(
|
|
213
|
-
'[draftExpression] setQueryExpression: committing with refreshed time range:',
|
|
214
|
-
draftSelection.expression
|
|
215
|
-
);
|
|
216
212
|
commitDraft({
|
|
217
213
|
from: currentFrom,
|
|
218
214
|
to: currentTo,
|
|
@@ -332,7 +328,7 @@ const ProfileSelector = ({
|
|
|
332
328
|
querySelection={querySelection}
|
|
333
329
|
profileSelection={profileSelection}
|
|
334
330
|
comparing={comparing}
|
|
335
|
-
sumBy={querySelection.sumBy
|
|
331
|
+
sumBy={querySelection.sumBy}
|
|
336
332
|
defaultSumByLoading={sumByLoading}
|
|
337
333
|
queryClient={queryClient}
|
|
338
334
|
queryExpressionString={queryExpressionString}
|
|
@@ -18,6 +18,8 @@ import {useProfileFilters} from '../components/ProfileFilters/useProfileFilters'
|
|
|
18
18
|
export const useResetStateOnProfileTypeChange = (): (() => void) => {
|
|
19
19
|
const [groupBy, setGroupBy] = useURLState('group_by');
|
|
20
20
|
const [curPath, setCurPath] = useURLState('cur_path');
|
|
21
|
+
const [sumByA, setSumByA] = useURLState('sum_by_a');
|
|
22
|
+
const [sumByB, setSumByB] = useURLState('sum_by_b');
|
|
21
23
|
const {resetFilters} = useProfileFilters();
|
|
22
24
|
const [sandwichFunctionName, setSandwichFunctionName] = useURLState('sandwich_function_name');
|
|
23
25
|
const batchUpdates = useURLStateBatch();
|
|
@@ -34,6 +36,12 @@ export const useResetStateOnProfileTypeChange = (): (() => void) => {
|
|
|
34
36
|
if (sandwichFunctionName !== undefined) {
|
|
35
37
|
setSandwichFunctionName(undefined);
|
|
36
38
|
}
|
|
39
|
+
if (sumByA !== undefined) {
|
|
40
|
+
setSumByA(undefined);
|
|
41
|
+
}
|
|
42
|
+
if (sumByB !== undefined) {
|
|
43
|
+
setSumByB(undefined);
|
|
44
|
+
}
|
|
37
45
|
|
|
38
46
|
resetFilters();
|
|
39
47
|
});
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
|
|
14
|
-
import React, {useCallback, useEffect, useRef, useState} from 'react';
|
|
14
|
+
import React, {Fragment, useCallback, useEffect, useRef, useState} from 'react';
|
|
15
15
|
|
|
16
16
|
import {Icon} from '@iconify/react';
|
|
17
17
|
import cx from 'classnames';
|
|
@@ -350,7 +350,7 @@ const CustomSelect: React.FC<CustomSelectProps & Record<string, any>> = ({
|
|
|
350
350
|
</div>
|
|
351
351
|
) : (
|
|
352
352
|
groupedFilteredItems.map(group => (
|
|
353
|
-
|
|
353
|
+
<Fragment key={group.type}>
|
|
354
354
|
{groupedFilteredItems.length > 1 &&
|
|
355
355
|
groupedFilteredItems.every(g => g.type !== '') &&
|
|
356
356
|
group.type !== '' ? (
|
|
@@ -369,7 +369,7 @@ const CustomSelect: React.FC<CustomSelectProps & Record<string, any>> = ({
|
|
|
369
369
|
handleSelection={handleSelection}
|
|
370
370
|
/>
|
|
371
371
|
))}
|
|
372
|
-
|
|
372
|
+
</Fragment>
|
|
373
373
|
))
|
|
374
374
|
)}
|
|
375
375
|
</div>
|
package/src/hooks/useLabels.ts
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
|
|
14
|
+
import {useEffect} from 'react';
|
|
15
|
+
|
|
14
16
|
import {LabelsRequest, LabelsResponse, QueryServiceClient, ValuesRequest} from '@parca/client';
|
|
15
17
|
import {useGrpcMetadata} from '@parca/components';
|
|
16
18
|
import {millisToProtoTimestamp, sanitizeLabelValue} from '@parca/utilities';
|
|
@@ -68,7 +70,9 @@ export const useLabelNames = (
|
|
|
68
70
|
},
|
|
69
71
|
});
|
|
70
72
|
|
|
71
|
-
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
console.log('Label names query result:', {data, error, isLoading});
|
|
75
|
+
}, [data, error, isLoading]);
|
|
72
76
|
|
|
73
77
|
return {
|
|
74
78
|
result: {response: data, error: error as Error},
|
|
@@ -69,16 +69,33 @@ vi.mock('@parca/components/src/hooks/URLState/utils', async () => {
|
|
|
69
69
|
};
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
-
// Mock useSumBy
|
|
72
|
+
// Mock useSumBy with stateful behavior using React's useState
|
|
73
73
|
vi.mock('../useSumBy', async () => {
|
|
74
74
|
const actual = await vi.importActual('../useSumBy');
|
|
75
|
+
const react = await import('react');
|
|
76
|
+
|
|
75
77
|
return {
|
|
76
78
|
...actual,
|
|
77
|
-
useSumBy: (
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
useSumBy: (
|
|
80
|
+
_queryClient: any,
|
|
81
|
+
_profileType: any,
|
|
82
|
+
_timeRange: any,
|
|
83
|
+
_draftProfileType: any,
|
|
84
|
+
_draftTimeRange: any,
|
|
85
|
+
defaultValue: any
|
|
86
|
+
) => {
|
|
87
|
+
const [draftSumBy, setDraftSumBy] = react.useState<string[] | undefined>(defaultValue);
|
|
88
|
+
const [sumBy, setSumBy] = react.useState<string[] | undefined>(defaultValue);
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
sumBy,
|
|
92
|
+
setSumBy,
|
|
93
|
+
isLoading: false,
|
|
94
|
+
draftSumBy,
|
|
95
|
+
setDraftSumBy,
|
|
96
|
+
isDraftSumByLoading: false,
|
|
97
|
+
};
|
|
98
|
+
},
|
|
82
99
|
};
|
|
83
100
|
});
|
|
84
101
|
|
|
@@ -207,7 +224,9 @@ describe('useQueryState', () => {
|
|
|
207
224
|
it('should update sumBy', async () => {
|
|
208
225
|
const {result} = renderHook(() => useQueryState(), {wrapper: createWrapper()});
|
|
209
226
|
|
|
227
|
+
// sumBy only applies to delta profiles, so we need to set one first
|
|
210
228
|
act(() => {
|
|
229
|
+
result.current.setDraftExpression('process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta{}');
|
|
211
230
|
result.current.setDraftSumBy(['namespace', 'container']);
|
|
212
231
|
});
|
|
213
232
|
|
|
@@ -256,15 +275,15 @@ describe('useQueryState', () => {
|
|
|
256
275
|
const {result} = renderHook(() => useQueryState(), {wrapper: createWrapper()});
|
|
257
276
|
|
|
258
277
|
act(() => {
|
|
259
|
-
// Update multiple draft values
|
|
260
|
-
result.current.setDraftExpression('memory:
|
|
278
|
+
// Update multiple draft values (using delta profile since sumBy only applies to delta)
|
|
279
|
+
result.current.setDraftExpression('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
261
280
|
result.current.setDraftTimeRange(7000, 8000, 'relative:minute|30');
|
|
262
281
|
result.current.setDraftSumBy(['pod', 'node']);
|
|
263
282
|
});
|
|
264
283
|
|
|
265
284
|
// All drafts should be updated
|
|
266
285
|
expect(result.current.draftSelection.expression).toBe(
|
|
267
|
-
'memory:
|
|
286
|
+
'memory:alloc_space:bytes:space:bytes:delta{}'
|
|
268
287
|
);
|
|
269
288
|
expect(result.current.draftSelection.from).toBe(7000);
|
|
270
289
|
expect(result.current.draftSelection.to).toBe(8000);
|
|
@@ -278,7 +297,7 @@ describe('useQueryState', () => {
|
|
|
278
297
|
// Should only navigate once for all updates
|
|
279
298
|
expect(mockNavigateTo).toHaveBeenCalledTimes(1);
|
|
280
299
|
const [, params] = mockNavigateTo.mock.calls[0];
|
|
281
|
-
expect(params.expression).toBe('memory:
|
|
300
|
+
expect(params.expression).toBe('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
282
301
|
expect(params.from).toBe('7000');
|
|
283
302
|
expect(params.to).toBe('8000');
|
|
284
303
|
expect(params.time_selection).toBe('relative:minute|30');
|
|
@@ -430,9 +449,9 @@ describe('useQueryState', () => {
|
|
|
430
449
|
it('should handle _b suffix correctly', async () => {
|
|
431
450
|
const {result} = renderHook(() => useQueryState({suffix: '_b'}), {wrapper: createWrapper()});
|
|
432
451
|
|
|
433
|
-
// Update draft state
|
|
452
|
+
// Update draft state (using delta profile since sumBy only applies to delta)
|
|
434
453
|
act(() => {
|
|
435
|
-
result.current.setDraftExpression('memory:
|
|
454
|
+
result.current.setDraftExpression('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
436
455
|
result.current.setDraftTimeRange(3333, 4444, 'relative:hour|2');
|
|
437
456
|
result.current.setDraftSumBy(['label_b']);
|
|
438
457
|
});
|
|
@@ -445,7 +464,7 @@ describe('useQueryState', () => {
|
|
|
445
464
|
await waitFor(() => {
|
|
446
465
|
expect(mockNavigateTo).toHaveBeenCalled();
|
|
447
466
|
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
448
|
-
expect(params.expression_b).toBe('memory:
|
|
467
|
+
expect(params.expression_b).toBe('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
449
468
|
expect(params.from_b).toBe('3333');
|
|
450
469
|
expect(params.to_b).toBe('4444');
|
|
451
470
|
expect(params.sum_by_b).toBe('label_b');
|
|
@@ -457,9 +476,9 @@ describe('useQueryState', () => {
|
|
|
457
476
|
it('should not update URL until commit', async () => {
|
|
458
477
|
const {result} = renderHook(() => useQueryState(), {wrapper: createWrapper()});
|
|
459
478
|
|
|
460
|
-
// Make multiple draft changes
|
|
479
|
+
// Make multiple draft changes (using delta profile since sumBy only applies to delta)
|
|
461
480
|
act(() => {
|
|
462
|
-
result.current.setDraftExpression('memory:
|
|
481
|
+
result.current.setDraftExpression('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
463
482
|
result.current.setDraftTimeRange(5000, 6000, 'relative:hour|3');
|
|
464
483
|
result.current.setDraftSumBy(['namespace', 'pod']);
|
|
465
484
|
});
|
|
@@ -476,7 +495,7 @@ describe('useQueryState', () => {
|
|
|
476
495
|
await waitFor(() => {
|
|
477
496
|
expect(mockNavigateTo).toHaveBeenCalledTimes(1);
|
|
478
497
|
const [, params] = mockNavigateTo.mock.calls[0];
|
|
479
|
-
expect(params.expression).toBe('memory:
|
|
498
|
+
expect(params.expression).toBe('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
480
499
|
expect(params.from).toBe('5000');
|
|
481
500
|
expect(params.to).toBe('6000');
|
|
482
501
|
expect(params.sum_by).toBe('namespace,pod');
|
|
@@ -737,17 +756,17 @@ describe('useQueryState', () => {
|
|
|
737
756
|
|
|
738
757
|
describe('State persistence after page reload', () => {
|
|
739
758
|
it('should retain committed values after page reload simulation', async () => {
|
|
740
|
-
// Initial state
|
|
759
|
+
// Initial state (using delta profile since sumBy only applies to delta)
|
|
741
760
|
mockLocation.search =
|
|
742
|
-
'?expression=process_cpu:cpu:nanoseconds:cpu:nanoseconds{}&from=1000&to=2000';
|
|
761
|
+
'?expression=process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta{}&from=1000&to=2000';
|
|
743
762
|
|
|
744
763
|
const {result: result1, unmount} = renderHook(() => useQueryState(), {
|
|
745
764
|
wrapper: createWrapper(),
|
|
746
765
|
});
|
|
747
766
|
|
|
748
|
-
// User makes changes to draft
|
|
767
|
+
// User makes changes to draft (using delta profile since sumBy only applies to delta)
|
|
749
768
|
act(() => {
|
|
750
|
-
result1.current.setDraftExpression('memory:
|
|
769
|
+
result1.current.setDraftExpression('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
751
770
|
result1.current.setDraftTimeRange(5000, 6000, 'relative:minute|15');
|
|
752
771
|
result1.current.setDraftSumBy(['namespace', 'pod']);
|
|
753
772
|
});
|
|
@@ -786,7 +805,7 @@ describe('useQueryState', () => {
|
|
|
786
805
|
|
|
787
806
|
// Verify state is loaded from URL after "reload"
|
|
788
807
|
expect(result2.current.querySelection.expression).toBe(
|
|
789
|
-
'memory:
|
|
808
|
+
'memory:alloc_space:bytes:space:bytes:delta{}'
|
|
790
809
|
);
|
|
791
810
|
expect(result2.current.querySelection.from).toBe(5000);
|
|
792
811
|
expect(result2.current.querySelection.to).toBe(6000);
|
|
@@ -795,7 +814,7 @@ describe('useQueryState', () => {
|
|
|
795
814
|
|
|
796
815
|
// Draft should be synced with URL state on page load
|
|
797
816
|
expect(result2.current.draftSelection.expression).toBe(
|
|
798
|
-
'memory:
|
|
817
|
+
'memory:alloc_space:bytes:space:bytes:delta{}'
|
|
799
818
|
);
|
|
800
819
|
expect(result2.current.draftSelection.from).toBe(5000);
|
|
801
820
|
expect(result2.current.draftSelection.to).toBe(6000);
|
|
@@ -19,7 +19,8 @@ import {Query} from '@parca/parser';
|
|
|
19
19
|
import {QuerySelection} from '../ProfileSelector';
|
|
20
20
|
import {ProfileSelection, ProfileSelectionFromParams, ProfileSource} from '../ProfileSource';
|
|
21
21
|
import {useResetFlameGraphState} from '../ProfileView/hooks/useResetFlameGraphState';
|
|
22
|
-
import {
|
|
22
|
+
import {useResetStateOnProfileTypeChange} from '../ProfileView/hooks/useResetStateOnProfileTypeChange';
|
|
23
|
+
import {DEFAULT_EMPTY_SUM_BY, sumByToParam, useSumBy, useSumByFromParams} from '../useSumBy';
|
|
23
24
|
|
|
24
25
|
interface UseQueryStateOptions {
|
|
25
26
|
suffix?: '_a' | '_b'; // For comparison mode
|
|
@@ -79,6 +80,7 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
|
|
|
79
80
|
|
|
80
81
|
const batchUpdates = useURLStateBatch();
|
|
81
82
|
const resetFlameGraphState = useResetFlameGraphState();
|
|
83
|
+
const resetStateOnProfileTypeChange = useResetStateOnProfileTypeChange();
|
|
82
84
|
|
|
83
85
|
// URL state hooks with appropriate suffixes
|
|
84
86
|
const [expression, setExpressionState] = useURLState<string>(`expression${suffix}`, {
|
|
@@ -115,29 +117,6 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
|
|
|
115
117
|
const [draftTimeSelection, setDraftTimeSelection] = useState<string>(
|
|
116
118
|
timeSelection ?? defaultTimeSelection
|
|
117
119
|
);
|
|
118
|
-
const [draftSumBy, setDraftSumBy] = useState<string[] | undefined>(sumBy);
|
|
119
|
-
|
|
120
|
-
// Sync draft state with URL state when URL changes externally
|
|
121
|
-
useEffect(() => {
|
|
122
|
-
setDraftExpression(expression ?? defaultExpression);
|
|
123
|
-
}, [expression, defaultExpression]);
|
|
124
|
-
|
|
125
|
-
useEffect(() => {
|
|
126
|
-
setDraftFrom(from ?? defaultFrom?.toString() ?? '');
|
|
127
|
-
}, [from, defaultFrom]);
|
|
128
|
-
|
|
129
|
-
useEffect(() => {
|
|
130
|
-
setDraftTo(to ?? defaultTo?.toString() ?? '');
|
|
131
|
-
}, [to, defaultTo]);
|
|
132
|
-
|
|
133
|
-
useEffect(() => {
|
|
134
|
-
setDraftTimeSelection(timeSelection ?? defaultTimeSelection);
|
|
135
|
-
}, [timeSelection, defaultTimeSelection]);
|
|
136
|
-
|
|
137
|
-
useEffect(() => {
|
|
138
|
-
setDraftSumBy(sumBy);
|
|
139
|
-
}, [sumBy]);
|
|
140
|
-
|
|
141
120
|
// Parse the draft query to extract profile information
|
|
142
121
|
const draftQuery = useMemo(() => {
|
|
143
122
|
try {
|
|
@@ -147,8 +126,16 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
|
|
|
147
126
|
}
|
|
148
127
|
}, [draftExpression]);
|
|
149
128
|
|
|
129
|
+
const query = useMemo(() => {
|
|
130
|
+
try {
|
|
131
|
+
return Query.parse(expression ?? '');
|
|
132
|
+
} catch {
|
|
133
|
+
return Query.parse('');
|
|
134
|
+
}
|
|
135
|
+
}, [expression]);
|
|
150
136
|
const draftProfileType = useMemo(() => draftQuery.profileType(), [draftQuery]);
|
|
151
137
|
const draftProfileName = useMemo(() => draftQuery.profileName(), [draftQuery]);
|
|
138
|
+
const profileType = useMemo(() => query.profileType(), [query]);
|
|
152
139
|
|
|
153
140
|
// Compute draft time range for label fetching
|
|
154
141
|
const draftTimeRange = useMemo(() => {
|
|
@@ -159,13 +146,50 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
|
|
|
159
146
|
);
|
|
160
147
|
}, [draftTimeSelection, draftFrom, draftTo, defaultTimeSelection, defaultFrom, defaultTo]);
|
|
161
148
|
// Use combined sumBy hook for fetching labels and computing defaults (based on committed state)
|
|
162
|
-
const {
|
|
149
|
+
const {
|
|
150
|
+
sumBy: computedSumByFromURL,
|
|
151
|
+
isLoading: sumBySelectionLoading,
|
|
152
|
+
draftSumBy,
|
|
153
|
+
setDraftSumBy,
|
|
154
|
+
isDraftSumByLoading,
|
|
155
|
+
} = useSumBy(
|
|
163
156
|
queryClient,
|
|
157
|
+
profileType?.profileName !== '' ? profileType : draftProfileType,
|
|
158
|
+
draftTimeRange,
|
|
164
159
|
draftProfileType,
|
|
165
160
|
draftTimeRange,
|
|
166
161
|
sumBy
|
|
167
162
|
);
|
|
168
163
|
|
|
164
|
+
// Sync draft state with URL state when URL changes externally
|
|
165
|
+
useEffect(() => {
|
|
166
|
+
setDraftExpression(expression ?? defaultExpression);
|
|
167
|
+
}, [expression, defaultExpression]);
|
|
168
|
+
|
|
169
|
+
useEffect(() => {
|
|
170
|
+
setDraftFrom(from ?? defaultFrom?.toString() ?? '');
|
|
171
|
+
}, [from, defaultFrom]);
|
|
172
|
+
|
|
173
|
+
useEffect(() => {
|
|
174
|
+
setDraftTo(to ?? defaultTo?.toString() ?? '');
|
|
175
|
+
}, [to, defaultTo]);
|
|
176
|
+
|
|
177
|
+
useEffect(() => {
|
|
178
|
+
setDraftTimeSelection(timeSelection ?? defaultTimeSelection);
|
|
179
|
+
}, [timeSelection, defaultTimeSelection]);
|
|
180
|
+
|
|
181
|
+
useEffect(() => {
|
|
182
|
+
setDraftSumBy(sumBy);
|
|
183
|
+
}, [sumBy, setDraftSumBy]);
|
|
184
|
+
|
|
185
|
+
// Sync computed sumBy to URL if URL doesn't already have a value
|
|
186
|
+
// to ensure the shared URL can always pick it up.
|
|
187
|
+
useEffect(() => {
|
|
188
|
+
if (sumByParam === undefined && computedSumByFromURL !== undefined && !sumBySelectionLoading) {
|
|
189
|
+
setSumByParam(sumByToParam(computedSumByFromURL));
|
|
190
|
+
}
|
|
191
|
+
}, [sumByParam, computedSumByFromURL, sumBySelectionLoading, setSumByParam]);
|
|
192
|
+
|
|
169
193
|
// Construct the QuerySelection object (committed state from URL)
|
|
170
194
|
const querySelection: QuerySelection = useMemo(() => {
|
|
171
195
|
const range = DateTimeRange.fromRangeKey(
|
|
@@ -285,12 +309,16 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
|
|
|
285
309
|
setFromState(finalFrom);
|
|
286
310
|
setToState(finalTo);
|
|
287
311
|
setTimeSelectionState(finalTimeSelection);
|
|
288
|
-
setSumByParam(sumByToParam(draftSumBy));
|
|
289
312
|
|
|
290
313
|
// Auto-calculate merge parameters for delta profiles
|
|
291
314
|
// Parse the final expression to check if it's a delta profile
|
|
292
315
|
const finalQuery = Query.parse(finalExpression);
|
|
293
316
|
const isDelta = finalQuery.profileType().delta;
|
|
317
|
+
if (isDelta) {
|
|
318
|
+
setSumByParam(sumByToParam(draftSumBy));
|
|
319
|
+
} else {
|
|
320
|
+
setSumByParam(DEFAULT_EMPTY_SUM_BY);
|
|
321
|
+
}
|
|
294
322
|
|
|
295
323
|
if (isDelta && finalFrom !== '' && finalTo !== '') {
|
|
296
324
|
const fromMs = parseInt(finalFrom);
|
|
@@ -313,6 +341,12 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
|
|
|
313
341
|
setSelectionParam(undefined);
|
|
314
342
|
}
|
|
315
343
|
resetFlameGraphState();
|
|
344
|
+
if (
|
|
345
|
+
draftProfileType.toString() !==
|
|
346
|
+
Query.parse(querySelection.expression).profileType().toString()
|
|
347
|
+
) {
|
|
348
|
+
resetStateOnProfileTypeChange();
|
|
349
|
+
}
|
|
316
350
|
});
|
|
317
351
|
},
|
|
318
352
|
[
|
|
@@ -334,6 +368,9 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
|
|
|
334
368
|
setMergeToState,
|
|
335
369
|
setSelectionParam,
|
|
336
370
|
resetFlameGraphState,
|
|
371
|
+
resetStateOnProfileTypeChange,
|
|
372
|
+
draftProfileType,
|
|
373
|
+
querySelection.expression,
|
|
337
374
|
]
|
|
338
375
|
);
|
|
339
376
|
|
|
@@ -346,9 +383,12 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
|
|
|
346
383
|
[]
|
|
347
384
|
);
|
|
348
385
|
|
|
349
|
-
const setDraftSumByCallback = useCallback(
|
|
350
|
-
|
|
351
|
-
|
|
386
|
+
const setDraftSumByCallback = useCallback(
|
|
387
|
+
(newSumBy: string[] | undefined) => {
|
|
388
|
+
setDraftSumBy(newSumBy);
|
|
389
|
+
},
|
|
390
|
+
[setDraftSumBy]
|
|
391
|
+
);
|
|
352
392
|
|
|
353
393
|
const setDraftProfileName = useCallback(
|
|
354
394
|
(newProfileName: string) => {
|
|
@@ -357,9 +397,10 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
|
|
|
357
397
|
const [newQuery, changed] = draftQuery.setProfileName(newProfileName);
|
|
358
398
|
if (changed) {
|
|
359
399
|
setDraftExpression(newQuery.toString());
|
|
400
|
+
setDraftSumBy(undefined);
|
|
360
401
|
}
|
|
361
402
|
},
|
|
362
|
-
[draftQuery]
|
|
403
|
+
[draftQuery, setDraftSumBy]
|
|
363
404
|
);
|
|
364
405
|
|
|
365
406
|
const setDraftMatchers = useCallback(
|
|
@@ -421,7 +462,7 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
|
|
|
421
462
|
setProfileSelection,
|
|
422
463
|
|
|
423
464
|
// Loading state
|
|
424
|
-
sumByLoading: sumBySelectionLoading,
|
|
465
|
+
sumByLoading: isDraftSumByLoading || sumBySelectionLoading,
|
|
425
466
|
|
|
426
467
|
draftParsedQuery,
|
|
427
468
|
parsedQuery,
|
package/src/useSumBy.ts
CHANGED
|
@@ -52,6 +52,7 @@ export const useSumBySelection = (
|
|
|
52
52
|
profileType: ProfileType | undefined,
|
|
53
53
|
labelNamesLoading: boolean,
|
|
54
54
|
labels: string[] | undefined,
|
|
55
|
+
draftSumBy: string[] | undefined,
|
|
55
56
|
{
|
|
56
57
|
defaultValue,
|
|
57
58
|
}: {
|
|
@@ -100,9 +101,15 @@ export const useSumBySelection = (
|
|
|
100
101
|
const lastValidSumByRef = useRef<string[]>(DEFAULT_EMPTY_SUM_BY);
|
|
101
102
|
|
|
102
103
|
const sumBy = useMemo(() => {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
if (labelNamesLoading) {
|
|
105
|
+
// For smoother UX, return draftSumBy first if available during loading
|
|
106
|
+
// as this must be recently computed with the draft time range labels.
|
|
107
|
+
if (draftSumBy !== undefined) {
|
|
108
|
+
return draftSumBy;
|
|
109
|
+
}
|
|
110
|
+
if (lastValidSumByRef.current == null) {
|
|
111
|
+
return lastValidSumByRef.current;
|
|
112
|
+
}
|
|
106
113
|
}
|
|
107
114
|
|
|
108
115
|
let result =
|
|
@@ -116,7 +123,7 @@ export const useSumBySelection = (
|
|
|
116
123
|
lastValidSumByRef.current = result;
|
|
117
124
|
|
|
118
125
|
return result;
|
|
119
|
-
}, [userSelectedSumBy, profileType, defaultSumBy, labelNamesLoading]);
|
|
126
|
+
}, [userSelectedSumBy, profileType, defaultSumBy, labelNamesLoading, draftSumBy]);
|
|
120
127
|
|
|
121
128
|
return [
|
|
122
129
|
sumBy,
|
|
@@ -187,11 +194,16 @@ export const useSumBy = (
|
|
|
187
194
|
queryClient: QueryServiceClient,
|
|
188
195
|
profileType: ProfileType | undefined,
|
|
189
196
|
timeRange: DateTimeRange,
|
|
197
|
+
draftProfileType: ProfileType | undefined,
|
|
198
|
+
draftTimeRange: DateTimeRange,
|
|
190
199
|
defaultValue?: string[]
|
|
191
200
|
): {
|
|
192
201
|
sumBy: string[] | undefined;
|
|
193
202
|
setSumBy: (sumBy: string[]) => void;
|
|
194
203
|
isLoading: boolean;
|
|
204
|
+
draftSumBy: string[] | undefined;
|
|
205
|
+
setDraftSumBy: (sumBy: string[] | undefined) => void;
|
|
206
|
+
isDraftSumByLoading: boolean;
|
|
195
207
|
} => {
|
|
196
208
|
const {loading: labelNamesLoading, result} = useLabelNames(
|
|
197
209
|
queryClient,
|
|
@@ -200,6 +212,13 @@ export const useSumBy = (
|
|
|
200
212
|
timeRange.getToMs()
|
|
201
213
|
);
|
|
202
214
|
|
|
215
|
+
const {draftSumBy, setDraftSumBy, isDraftSumByLoading} = useDraftSumBy(
|
|
216
|
+
queryClient,
|
|
217
|
+
draftProfileType,
|
|
218
|
+
draftTimeRange,
|
|
219
|
+
defaultValue
|
|
220
|
+
);
|
|
221
|
+
|
|
203
222
|
const labels = useMemo(() => {
|
|
204
223
|
return result.response?.labelNames === undefined ? [] : result.response.labelNames;
|
|
205
224
|
}, [result]);
|
|
@@ -208,6 +227,7 @@ export const useSumBy = (
|
|
|
208
227
|
profileType,
|
|
209
228
|
labelNamesLoading,
|
|
210
229
|
labels,
|
|
230
|
+
draftSumBy,
|
|
211
231
|
{defaultValue}
|
|
212
232
|
);
|
|
213
233
|
|
|
@@ -215,5 +235,39 @@ export const useSumBy = (
|
|
|
215
235
|
sumBy: sumBySelection,
|
|
216
236
|
setSumBy: setSumByInternal,
|
|
217
237
|
isLoading,
|
|
238
|
+
draftSumBy,
|
|
239
|
+
setDraftSumBy,
|
|
240
|
+
isDraftSumByLoading,
|
|
241
|
+
};
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
export const useDraftSumBy = (
|
|
245
|
+
queryClient: QueryServiceClient,
|
|
246
|
+
profileType: ProfileType | undefined,
|
|
247
|
+
timeRange: DateTimeRange,
|
|
248
|
+
defaultValue?: string[]
|
|
249
|
+
): {
|
|
250
|
+
draftSumBy: string[] | undefined;
|
|
251
|
+
setDraftSumBy: (sumBy: string[] | undefined) => void;
|
|
252
|
+
isDraftSumByLoading: boolean;
|
|
253
|
+
} => {
|
|
254
|
+
const [draftSumBy, setDraftSumBy] = useState<string[] | undefined>(defaultValue);
|
|
255
|
+
const {loading: labelNamesLoading, result} = useLabelNames(
|
|
256
|
+
queryClient,
|
|
257
|
+
profileType?.toString() ?? '',
|
|
258
|
+
timeRange.getFromMs(),
|
|
259
|
+
timeRange.getToMs()
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
const labels = useMemo(() => {
|
|
263
|
+
return result.response?.labelNames === undefined ? [] : result.response.labelNames;
|
|
264
|
+
}, [result]);
|
|
265
|
+
|
|
266
|
+
const {defaultSumBy, isLoading} = useDefaultSumBy(profileType, labelNamesLoading, labels);
|
|
267
|
+
|
|
268
|
+
return {
|
|
269
|
+
draftSumBy: draftSumBy ?? defaultSumBy ?? DEFAULT_EMPTY_SUM_BY,
|
|
270
|
+
setDraftSumBy: setDraftSumBy,
|
|
271
|
+
isDraftSumByLoading: isLoading,
|
|
218
272
|
};
|
|
219
273
|
};
|