@parca/profile 0.19.73 → 0.19.74
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.map +1 -1
- package/dist/MatchersInput/index.js +4 -2
- package/dist/ProfileExplorer/ProfileExplorerCompare.d.ts +1 -12
- package/dist/ProfileExplorer/ProfileExplorerCompare.d.ts.map +1 -1
- package/dist/ProfileExplorer/ProfileExplorerCompare.js +52 -11
- package/dist/ProfileExplorer/ProfileExplorerSingle.d.ts +1 -7
- package/dist/ProfileExplorer/ProfileExplorerSingle.d.ts.map +1 -1
- package/dist/ProfileExplorer/ProfileExplorerSingle.js +4 -2
- package/dist/ProfileExplorer/index.d.ts +1 -4
- package/dist/ProfileExplorer/index.d.ts.map +1 -1
- package/dist/ProfileExplorer/index.js +11 -225
- package/dist/ProfileMetricsGraph/index.d.ts +1 -1
- package/dist/ProfileMetricsGraph/index.d.ts.map +1 -1
- package/dist/ProfileMetricsGraph/index.js +16 -20
- package/dist/ProfileSelector/MetricsGraphSection.d.ts +3 -3
- package/dist/ProfileSelector/MetricsGraphSection.d.ts.map +1 -1
- package/dist/ProfileSelector/MetricsGraphSection.js +10 -6
- package/dist/ProfileSelector/index.d.ts +2 -7
- package/dist/ProfileSelector/index.d.ts.map +1 -1
- package/dist/ProfileSelector/index.js +40 -46
- package/dist/ProfileSelector/useAutoQuerySelector.d.ts.map +1 -1
- package/dist/ProfileSelector/useAutoQuerySelector.js +19 -4
- package/dist/ProfileTypeSelector/index.d.ts.map +1 -1
- package/dist/ProfileTypeSelector/index.js +1 -1
- package/dist/ProfileView/components/ViewSelector/index.d.ts.map +1 -1
- package/dist/ProfileView/components/ViewSelector/index.js +10 -4
- package/dist/ProfileView/hooks/useResetStateOnProfileTypeChange.d.ts.map +1 -1
- package/dist/ProfileView/hooks/useResetStateOnProfileTypeChange.js +4 -2
- package/dist/ProfileView/hooks/useVisualizationState.d.ts.map +1 -1
- package/dist/ProfileView/hooks/useVisualizationState.js +20 -13
- package/dist/Table/MoreDropdown.d.ts.map +1 -1
- package/dist/Table/MoreDropdown.js +7 -3
- package/dist/Table/TableContextMenu.d.ts.map +1 -1
- package/dist/Table/TableContextMenu.js +9 -5
- package/dist/hooks/useCompareModeMeta.d.ts +10 -0
- package/dist/hooks/useCompareModeMeta.d.ts.map +1 -0
- package/dist/hooks/useCompareModeMeta.js +113 -0
- package/dist/hooks/useQueryState.d.ts +32 -0
- package/dist/hooks/useQueryState.d.ts.map +1 -0
- package/dist/hooks/useQueryState.js +285 -0
- package/dist/hooks/useQueryState.test.d.ts +2 -0
- package/dist/hooks/useQueryState.test.d.ts.map +1 -0
- package/dist/hooks/useQueryState.test.js +910 -0
- package/dist/index.d.ts +4 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3
- package/dist/useSumBy.d.ts +7 -0
- package/dist/useSumBy.d.ts.map +1 -1
- package/dist/useSumBy.js +31 -6
- package/package.json +6 -6
- package/src/MatchersInput/index.tsx +4 -2
- package/src/ProfileExplorer/ProfileExplorerCompare.tsx +64 -46
- package/src/ProfileExplorer/ProfileExplorerSingle.tsx +7 -19
- package/src/ProfileExplorer/index.tsx +11 -339
- package/src/ProfileMetricsGraph/index.tsx +16 -20
- package/src/ProfileSelector/MetricsGraphSection.tsx +14 -10
- package/src/ProfileSelector/index.tsx +65 -83
- package/src/ProfileSelector/useAutoQuerySelector.ts +23 -5
- package/src/ProfileTypeSelector/index.tsx +3 -1
- package/src/ProfileView/components/ViewSelector/index.tsx +9 -4
- package/src/ProfileView/hooks/useResetStateOnProfileTypeChange.ts +4 -2
- package/src/ProfileView/hooks/useVisualizationState.ts +25 -12
- package/src/Table/MoreDropdown.tsx +7 -3
- package/src/Table/TableContextMenu.tsx +9 -5
- package/src/hooks/useCompareModeMeta.ts +131 -0
- package/src/hooks/useQueryState.test.tsx +1202 -0
- package/src/hooks/useQueryState.ts +414 -0
- package/src/index.tsx +9 -11
- package/src/useSumBy.ts +62 -7
- package/src/ProfileExplorer/index.test.ts +0 -97
|
@@ -12,14 +12,15 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
12
12
|
// See the License for the specific language governing permissions and
|
|
13
13
|
// limitations under the License.
|
|
14
14
|
import cx from 'classnames';
|
|
15
|
+
import { useURLStateBatch } from '@parca/components';
|
|
15
16
|
import { Query } from '@parca/parser';
|
|
16
|
-
import { MergedProfileSelection } from '..';
|
|
17
17
|
import UtilizationMetricsGraph from '../MetricsGraph/UtilizationMetrics';
|
|
18
18
|
import AreaChart from '../MetricsGraph/UtilizationMetrics/Throughput';
|
|
19
19
|
import ProfileMetricsGraph, { ProfileMetricsEmptyState } from '../ProfileMetricsGraph';
|
|
20
20
|
import { useResetStateOnSeriesChange } from '../ProfileView/hooks/useResetStateOnSeriesChange';
|
|
21
|
-
export function MetricsGraphSection({ showMetricsGraph, setDisplayHideMetricsGraphButton, heightStyle, querySelection, profileSelection, comparing, sumBy, defaultSumByLoading, queryClient, queryExpressionString, setTimeRangeSelection, selectQuery,
|
|
21
|
+
export function MetricsGraphSection({ showMetricsGraph, setDisplayHideMetricsGraphButton, heightStyle, querySelection, profileSelection, comparing, sumBy, defaultSumByLoading, queryClient, queryExpressionString, setTimeRangeSelection, selectQuery, setProfileSelection, query, setNewQueryExpression, utilizationMetrics, utilizationMetricsLoading, onUtilizationSeriesSelect, }) {
|
|
22
22
|
const resetStateOnSeriesChange = useResetStateOnSeriesChange();
|
|
23
|
+
const batchUpdates = useURLStateBatch();
|
|
23
24
|
const handleTimeRangeChange = (range) => {
|
|
24
25
|
const from = range.getFromMs();
|
|
25
26
|
const to = range.getToMs();
|
|
@@ -62,7 +63,8 @@ export function MetricsGraphSection({ showMetricsGraph, setDisplayHideMetricsGra
|
|
|
62
63
|
}
|
|
63
64
|
if (hasChanged) {
|
|
64
65
|
// TODO: Change this to store the query object
|
|
65
|
-
|
|
66
|
+
// Pass commit: true to immediately apply the filter when clicking on metrics graph labels
|
|
67
|
+
setNewQueryExpression(newQuery.toString(), true);
|
|
66
68
|
}
|
|
67
69
|
};
|
|
68
70
|
const handlePointClick = (timestamp, labels, queryExpression, duration) => {
|
|
@@ -75,8 +77,10 @@ export function MetricsGraphSection({ showMetricsGraph, setDisplayHideMetricsGra
|
|
|
75
77
|
});
|
|
76
78
|
const mergeFrom = timestamp;
|
|
77
79
|
const mergeTo = query.profileType().delta ? mergeFrom + BigInt(duration) : mergeFrom;
|
|
78
|
-
|
|
79
|
-
|
|
80
|
+
batchUpdates(() => {
|
|
81
|
+
resetStateOnSeriesChange(); // reset some state when a new series is selected
|
|
82
|
+
setProfileSelection(mergeFrom, mergeTo, query);
|
|
83
|
+
});
|
|
80
84
|
};
|
|
81
85
|
const UtilizationGraphToShow = ({ utilizationMetrics, }) => {
|
|
82
86
|
const throughputMetrics = utilizationMetrics.filter(metric => metric.name === 'gpu_pcie_throughput_transmit_bytes' ||
|
|
@@ -99,7 +103,7 @@ export function MetricsGraphSection({ showMetricsGraph, setDisplayHideMetricsGra
|
|
|
99
103
|
?.data ?? [], receiveData: throughputMetrics.find(metric => metric.name === 'gpu_pcie_throughput_receive_bytes')
|
|
100
104
|
?.data ?? [], addLabelMatcher: addLabelMatcher, setTimeRange: handleTimeRangeChange, name: throughputMetrics[0].name, humanReadableName: throughputMetrics[0].humanReadableName, from: querySelection.from, to: querySelection.to, utilizationMetricsLoading: utilizationMetricsLoading, selectedSeries: undefined, onSeriesClick: onUtilizationSeriesSelect }))] }));
|
|
101
105
|
};
|
|
102
|
-
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 !== '' &&
|
|
106
|
+
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) &&
|
|
103
107
|
querySelection.from !== undefined &&
|
|
104
108
|
querySelection.to !== undefined ? (_jsx(_Fragment, { children: utilizationMetrics !== undefined ? (_jsx(UtilizationGraphToShow, { utilizationMetrics: utilizationMetrics })) : (_jsx(_Fragment, { children: _jsx(ProfileMetricsGraph, { queryClient: queryClient, queryExpression: querySelection.expression, from: querySelection.from, to: querySelection.to, profile: profileSelection, comparing: comparing, sumBy: querySelection.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." }) }))) }) }))] }));
|
|
105
109
|
}
|
|
@@ -2,7 +2,6 @@ import { Dispatch, SetStateAction } from 'react';
|
|
|
2
2
|
import { RpcError } from '@protobuf-ts/runtime-rpc';
|
|
3
3
|
import { ProfileTypesResponse, QueryServiceClient } from '@parca/client';
|
|
4
4
|
import { type NavigateFunction } from '@parca/utilities';
|
|
5
|
-
import { ProfileSelection } from '..';
|
|
6
5
|
export interface QuerySelection {
|
|
7
6
|
expression: string;
|
|
8
7
|
from: number;
|
|
@@ -40,16 +39,12 @@ export interface UtilizationLabels {
|
|
|
40
39
|
}
|
|
41
40
|
interface ProfileSelectorProps extends ProfileSelectorFeatures {
|
|
42
41
|
queryClient: QueryServiceClient;
|
|
43
|
-
querySelection: QuerySelection;
|
|
44
|
-
selectProfile: (source: ProfileSelection) => void;
|
|
45
|
-
selectQuery: (query: QuerySelection) => void;
|
|
46
42
|
closeProfile: () => void;
|
|
47
43
|
enforcedProfileName: string;
|
|
48
|
-
profileSelection: ProfileSelection | null;
|
|
49
44
|
comparing: boolean;
|
|
50
45
|
navigateTo: NavigateFunction;
|
|
51
46
|
setDisplayHideMetricsGraphButton?: Dispatch<SetStateAction<boolean>>;
|
|
52
|
-
suffix?:
|
|
47
|
+
suffix?: '_a' | '_b';
|
|
53
48
|
utilizationMetrics?: Array<{
|
|
54
49
|
name: string;
|
|
55
50
|
humanReadableName: string;
|
|
@@ -65,6 +60,6 @@ export interface IProfileTypesResult {
|
|
|
65
60
|
error?: RpcError;
|
|
66
61
|
}
|
|
67
62
|
export declare const useProfileTypes: (client: QueryServiceClient, start?: number, end?: number) => IProfileTypesResult;
|
|
68
|
-
declare const ProfileSelector: ({ queryClient,
|
|
63
|
+
declare const ProfileSelector: ({ queryClient, closeProfile, enforcedProfileName, comparing, navigateTo, showMetricsGraph, showSumBySelector, showProfileTypeSelector, disableExplorativeQuerying, setDisplayHideMetricsGraphButton, suffix, utilizationMetrics, utilizationMetricsLoading, utilizationLabels, onUtilizationSeriesSelect, }: ProfileSelectorProps) => JSX.Element;
|
|
69
64
|
export default ProfileSelector;
|
|
70
65
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,QAAQ,EAAE,cAAc,
|
|
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;AAW5F,OAAO,EAAyB,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAW/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,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE;QACR,MAAM,EAAE,KAAK,CAAC;YACZ,IAAI,EAAE,MAAM,CAAC;YACb,KAAK,EAAE,MAAM,CAAC;SACf,CAAC,CAAC;KACJ,CAAC;IACF,OAAO,EAAE,KAAK,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,iBAAiB;IAChC,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,2BAA2B,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACjE,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;IAClC,4BAA4B,CAAC,EAAE,OAAO,CAAC;CACxC;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,kBAAkB,CAAC,EAAE,KAAK,CAAC;QACzB,IAAI,EAAE,MAAM,CAAC;QACb,iBAAiB,EAAE,MAAM,CAAC;QAC1B,IAAI,EAAE,kBAAkB,EAAE,CAAC;KAC5B,CAAC,CAAC;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,yBAAyB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3D;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,6SAgBtB,oBAAoB,KAAG,GAAG,CAAC,OAwN7B,CAAC;AAEF,eAAe,eAAe,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 { useEffect, useMemo, useRef, useState } from 'react';
|
|
14
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
15
15
|
import { DateTimeRange, IconButton, useGrpcMetadata, useParcaContext, useURLState, } from '@parca/components';
|
|
16
16
|
import { CloseIcon } from '@parca/icons';
|
|
17
17
|
import { Query } from '@parca/parser';
|
|
@@ -20,8 +20,8 @@ import { millisToProtoTimestamp } from '@parca/utilities';
|
|
|
20
20
|
import { useLabelNames } from '../MatchersInput/index';
|
|
21
21
|
import { useMetricsGraphDimensions } from '../MetricsGraph/useMetricsGraphDimensions';
|
|
22
22
|
import { UtilizationLabelsProvider } from '../contexts/UtilizationLabelsContext';
|
|
23
|
+
import { useQueryState } from '../hooks/useQueryState';
|
|
23
24
|
import useGrpcQuery from '../useGrpcQuery';
|
|
24
|
-
import { useDefaultSumBy, useSumBySelection } from '../useSumBy';
|
|
25
25
|
import { MetricsGraphSection } from './MetricsGraphSection';
|
|
26
26
|
import { QueryControls } from './QueryControls';
|
|
27
27
|
import { useAutoQuerySelector } from './useAutoQuerySelector';
|
|
@@ -45,36 +45,31 @@ export const useProfileTypes = (client, start, end) => {
|
|
|
45
45
|
});
|
|
46
46
|
return { loading: isLoading, data, error: error };
|
|
47
47
|
};
|
|
48
|
-
const ProfileSelector = ({ queryClient,
|
|
48
|
+
const ProfileSelector = ({ queryClient, closeProfile, enforcedProfileName, comparing, navigateTo, showMetricsGraph = true, showSumBySelector = true, showProfileTypeSelector = true, disableExplorativeQuerying = false, setDisplayHideMetricsGraphButton, suffix, utilizationMetrics, utilizationMetricsLoading, utilizationLabels, onUtilizationSeriesSelect, }) => {
|
|
49
49
|
const { heightStyle } = useMetricsGraphDimensions(comparing, utilizationMetrics != null);
|
|
50
50
|
const { viewComponent } = useParcaContext();
|
|
51
51
|
const [queryBrowserMode, setQueryBrowserMode] = useURLState('query_browser_mode');
|
|
52
|
-
|
|
53
|
-
const
|
|
52
|
+
// Use the new useQueryState hook - reads directly from URL params
|
|
53
|
+
const { querySelection, draftSelection, setDraftExpression, setDraftTimeRange, setDraftSumBy, setDraftProfileName, setDraftMatchers, commitDraft, profileSelection, setProfileSelection, sumByLoading, } = useQueryState({ suffix });
|
|
54
|
+
// Use draft state for local state instead of committed state
|
|
55
|
+
const [timeRangeSelection, setTimeRangeSelection] = useState(DateTimeRange.fromRangeKey(draftSelection.timeSelection, draftSelection.from, draftSelection.to));
|
|
56
|
+
const [queryExpressionString, setQueryExpressionString] = useState(draftSelection.expression);
|
|
54
57
|
const [advancedModeForQueryBrowser, setAdvancedModeForQueryBrowser] = useState(queryBrowserMode === 'advanced');
|
|
58
|
+
// Handler to update draft when time range changes
|
|
59
|
+
const handleTimeRangeChange = useCallback((range) => {
|
|
60
|
+
setTimeRangeSelection(range);
|
|
61
|
+
setDraftTimeRange(range.getFromMs(), range.getToMs(), range.getRangeKey());
|
|
62
|
+
}, [setDraftTimeRange]);
|
|
55
63
|
const profileType = useMemo(() => {
|
|
56
64
|
return Query.parse(queryExpressionString).profileType();
|
|
57
65
|
}, [queryExpressionString]);
|
|
58
|
-
const selectedProfileType = useMemo(() => {
|
|
59
|
-
return Query.parse(querySelection.expression).profileType();
|
|
60
|
-
}, [querySelection.expression]);
|
|
61
66
|
const from = timeRangeSelection.getFromMs();
|
|
62
67
|
const to = timeRangeSelection.getToMs();
|
|
63
68
|
const { loading: profileTypesLoading, data: profileTypesData, error, } = useProfileTypes(queryClient, from, to);
|
|
64
|
-
const {
|
|
65
|
-
const { loading: selectedLabelNamesLoading, result: selectedLabelNamesResult } = useLabelNames(queryClient, selectedProfileType.toString(), from, to);
|
|
69
|
+
const { result, refetch } = useLabelNames(queryClient, profileType.toString(), from, to);
|
|
66
70
|
const labels = useMemo(() => {
|
|
67
71
|
return result.response?.labelNames === undefined ? [] : result.response.labelNames;
|
|
68
72
|
}, [result]);
|
|
69
|
-
const selectedLabels = useMemo(() => {
|
|
70
|
-
return selectedLabelNamesResult.response?.labelNames === undefined
|
|
71
|
-
? []
|
|
72
|
-
: selectedLabelNamesResult.response.labelNames;
|
|
73
|
-
}, [selectedLabelNamesResult]);
|
|
74
|
-
const [sumBySelection, setUserSumBySelection, { isLoading: sumBySelectionLoading }] = useSumBySelection(profileType, labelNamesLoading, labels, {
|
|
75
|
-
defaultValue: querySelection.sumBy,
|
|
76
|
-
});
|
|
77
|
-
const { defaultSumBy, isLoading: defaultSumByLoading } = useDefaultSumBy(selectedProfileType, selectedLabelNamesLoading, selectedLabels);
|
|
78
73
|
useEffect(() => {
|
|
79
74
|
if (enforcedProfileName !== '') {
|
|
80
75
|
const [q, changed] = Query.parse(querySelection.expression).setProfileName(enforcedProfileName);
|
|
@@ -92,37 +87,36 @@ const ProfileSelector = ({ queryClient, querySelection, selectProfile, selectQue
|
|
|
92
87
|
};
|
|
93
88
|
const query = enforcedProfileName !== '' ? enforcedProfileNameQuery() : Query.parse(queryExpressionString);
|
|
94
89
|
const selectedProfileName = query.profileName();
|
|
95
|
-
const setNewQueryExpression = (expr, updateTs = false) => {
|
|
96
|
-
const query = enforcedProfileName !== '' ? enforcedProfileNameQuery() : Query.parse(expr);
|
|
97
|
-
const delta = query.profileType().delta;
|
|
98
|
-
const from = timeRangeSelection.getFromMs(updateTs);
|
|
99
|
-
const to = timeRangeSelection.getToMs(updateTs);
|
|
100
|
-
const mergeParams = delta
|
|
101
|
-
? {
|
|
102
|
-
mergeFrom: (BigInt(from) * 1000000n).toString(),
|
|
103
|
-
mergeTo: (BigInt(to) * 1000000n).toString(),
|
|
104
|
-
}
|
|
105
|
-
: {};
|
|
106
|
-
selectQuery({
|
|
107
|
-
expression: expr,
|
|
108
|
-
from,
|
|
109
|
-
to,
|
|
110
|
-
timeSelection: timeRangeSelection.getRangeKey(),
|
|
111
|
-
sumBy: sumBySelection,
|
|
112
|
-
...mergeParams,
|
|
113
|
-
});
|
|
114
|
-
};
|
|
115
90
|
const setQueryExpression = (updateTs = false) => {
|
|
116
|
-
|
|
91
|
+
// When updateTs is true, re-evaluate the time range to current values
|
|
92
|
+
if (updateTs) {
|
|
93
|
+
// Force re-evaluation of time range (important for relative ranges like "last 15 minutes")
|
|
94
|
+
const currentFrom = timeRangeSelection.getFromMs(true);
|
|
95
|
+
const currentTo = timeRangeSelection.getToMs(true);
|
|
96
|
+
const currentRangeKey = timeRangeSelection.getRangeKey();
|
|
97
|
+
// Commit with refreshed time range
|
|
98
|
+
commitDraft({
|
|
99
|
+
from: currentFrom,
|
|
100
|
+
to: currentTo,
|
|
101
|
+
timeSelection: currentRangeKey,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
// Commit the draft with existing values
|
|
106
|
+
commitDraft();
|
|
107
|
+
}
|
|
117
108
|
};
|
|
118
109
|
const setMatchersString = (matchers) => {
|
|
119
|
-
|
|
120
|
-
|
|
110
|
+
// Update draft state only
|
|
111
|
+
setDraftMatchers(matchers);
|
|
112
|
+
setQueryExpressionString(`${selectedProfileName}{${matchers}}`);
|
|
121
113
|
};
|
|
122
114
|
const setProfileName = (profileName) => {
|
|
123
115
|
if (profileName === undefined) {
|
|
124
116
|
return;
|
|
125
117
|
}
|
|
118
|
+
// Update draft state only
|
|
119
|
+
setDraftProfileName(profileName);
|
|
126
120
|
const [newQuery, changed] = query.setProfileName(profileName);
|
|
127
121
|
if (changed) {
|
|
128
122
|
const q = newQuery.toString();
|
|
@@ -139,17 +133,17 @@ const ProfileSelector = ({ queryClient, querySelection, selectProfile, selectQue
|
|
|
139
133
|
profileTypesData,
|
|
140
134
|
setProfileName,
|
|
141
135
|
setQueryExpression,
|
|
142
|
-
querySelection
|
|
136
|
+
querySelection,
|
|
143
137
|
navigateTo,
|
|
144
|
-
loading:
|
|
138
|
+
loading: sumByLoading,
|
|
145
139
|
});
|
|
146
140
|
const searchDisabled = queryExpressionString === undefined ||
|
|
147
141
|
queryExpressionString === '' ||
|
|
148
142
|
queryExpressionString === '{}';
|
|
149
143
|
const queryBrowserRef = useRef(null);
|
|
150
144
|
const sumByRef = useRef(null);
|
|
151
|
-
return (_jsx(UtilizationLabelsProvider, { value: { ...utilizationLabels }, children: _jsxs(_Fragment, { children: [_jsxs("div", { className: "mb-2 flex", children: [_jsx(QueryControls, { showProfileTypeSelector: showProfileTypeSelector, showSumBySelector: showSumBySelector, disableExplorativeQuerying: disableExplorativeQuerying, profileTypesData: profileTypesData, profileTypesLoading: profileTypesLoading, selectedProfileName: selectedProfileName, setProfileName: setProfileName, setMatchersString: setMatchersString, setQueryExpression: setQueryExpression, query: query, queryBrowserRef: queryBrowserRef, timeRangeSelection: timeRangeSelection, setTimeRangeSelection:
|
|
145
|
+
return (_jsx(UtilizationLabelsProvider, { value: { ...utilizationLabels }, children: _jsxs(_Fragment, { children: [_jsxs("div", { className: "mb-2 flex", children: [_jsx(QueryControls, { showProfileTypeSelector: showProfileTypeSelector, showSumBySelector: showSumBySelector, disableExplorativeQuerying: disableExplorativeQuerying, profileTypesData: profileTypesData, profileTypesLoading: profileTypesLoading, selectedProfileName: selectedProfileName, setProfileName: setProfileName, setMatchersString: setMatchersString, setQueryExpression: setQueryExpression, query: query, queryBrowserRef: queryBrowserRef, timeRangeSelection: timeRangeSelection, setTimeRangeSelection: handleTimeRangeChange, searchDisabled: searchDisabled, queryBrowserMode: queryBrowserMode, 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, refreshLabelNames: refetch }), comparing && (_jsx("div", { children: _jsx(IconButton, { onClick: () => closeProfile(), icon: _jsx(CloseIcon, {}), ...testId(TEST_IDS.COMPARE_CLOSE_BUTTON) }) }))] }), _jsx(MetricsGraphSection, { showMetricsGraph: showMetricsGraph, setDisplayHideMetricsGraphButton: setDisplayHideMetricsGraphButton, heightStyle: utilizationMetrics !== undefined && utilizationMetrics?.length > 0
|
|
152
146
|
? 'auto'
|
|
153
|
-
: heightStyle, querySelection: querySelection, profileSelection: profileSelection, comparing: comparing, sumBy: querySelection.sumBy ??
|
|
147
|
+
: 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, utilizationMetrics: utilizationMetrics, utilizationMetricsLoading: utilizationMetricsLoading, onUtilizationSeriesSelect: onUtilizationSeriesSelect })] }) }));
|
|
154
148
|
};
|
|
155
149
|
export default ProfileSelector;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAutoQuerySelector.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/useAutoQuerySelector.ts"],"names":[],"mappings":"AAeA,OAAO,EAAC,oBAAoB,EAAC,MAAM,eAAe,CAAC;AAEnD,OAAO,EAAC,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAGvD,OAAO,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAGlD,UAAU,KAAK;IACb,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,oBAAoB,GAAG,SAAS,CAAC;IACnD,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,cAAc,EAAE,cAAc,CAAC;IAC/B,UAAU,EAAE,gBAAgB,CAAC;IAC7B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,oBAAoB,GAAI,qHAQlC,KAAK,KAAG,
|
|
1
|
+
{"version":3,"file":"useAutoQuerySelector.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/useAutoQuerySelector.ts"],"names":[],"mappings":"AAeA,OAAO,EAAC,oBAAoB,EAAC,MAAM,eAAe,CAAC;AAEnD,OAAO,EAAC,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAGvD,OAAO,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAGlD,UAAU,KAAK;IACb,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,oBAAoB,GAAG,SAAS,CAAC;IACnD,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,cAAc,EAAE,cAAc,CAAC;IAC/B,UAAU,EAAE,gBAAgB,CAAC;IAC7B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,oBAAoB,GAAI,qHAQlC,KAAK,KAAG,IAwJV,CAAC"}
|
|
@@ -10,7 +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
|
+
import { useEffect, useRef } from 'react';
|
|
14
14
|
import { selectAutoQuery, setAutoQuery, useAppDispatch, useAppSelector } from '@parca/store';
|
|
15
15
|
import { ProfileSelectionFromParams, SuffixParams } from '..';
|
|
16
16
|
import { constructProfileName } from '../ProfileTypeSelector';
|
|
@@ -18,13 +18,27 @@ export const useAutoQuerySelector = ({ selectedProfileName, profileTypesData, se
|
|
|
18
18
|
const autoQuery = useAppSelector(selectAutoQuery);
|
|
19
19
|
const dispatch = useAppDispatch();
|
|
20
20
|
const queryParams = new URLSearchParams(location.search);
|
|
21
|
-
const
|
|
21
|
+
const compareA = queryParams.get('compare_a');
|
|
22
|
+
const compareB = queryParams.get('compare_b');
|
|
23
|
+
const comparing = compareA === 'true' || compareB === 'true';
|
|
22
24
|
const expressionA = queryParams.get('expression_a');
|
|
25
|
+
const expressionB = queryParams.get('expression_b');
|
|
26
|
+
// Track if we've already set up compare mode to prevent infinite loops
|
|
27
|
+
const hasSetupCompareMode = useRef(false);
|
|
23
28
|
useEffect(() => {
|
|
24
29
|
if (loading) {
|
|
25
30
|
return;
|
|
26
31
|
}
|
|
27
|
-
|
|
32
|
+
// Only run this effect if:
|
|
33
|
+
// 1. We're in compare mode
|
|
34
|
+
// 2. expressionA exists
|
|
35
|
+
// 3. expressionB doesn't exist yet (meaning we need to set it up)
|
|
36
|
+
// 4. We haven't already set it up in this session
|
|
37
|
+
if (comparing &&
|
|
38
|
+
expressionA !== null &&
|
|
39
|
+
expressionA !== undefined &&
|
|
40
|
+
expressionB === null &&
|
|
41
|
+
!hasSetupCompareMode.current) {
|
|
28
42
|
if (querySelection.expression === undefined) {
|
|
29
43
|
return;
|
|
30
44
|
}
|
|
@@ -59,13 +73,14 @@ export const useAutoQuerySelector = ({ selectedProfileName, profileTypesData, se
|
|
|
59
73
|
...compareQuery,
|
|
60
74
|
};
|
|
61
75
|
}
|
|
76
|
+
hasSetupCompareMode.current = true;
|
|
62
77
|
void navigateTo('/', {
|
|
63
78
|
...compareQuery,
|
|
64
79
|
search_string: '',
|
|
65
80
|
dashboard_items: ['flamegraph'],
|
|
66
81
|
});
|
|
67
82
|
}
|
|
68
|
-
}, [comparing, querySelection, navigateTo, expressionA, dispatch, loading]);
|
|
83
|
+
}, [comparing, querySelection, navigateTo, expressionA, expressionB, dispatch, loading]);
|
|
69
84
|
// Effect to load some initial data on load when is no selection
|
|
70
85
|
useEffect(() => {
|
|
71
86
|
void (async () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileTypeSelector/index.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAElD,OAAO,EAAC,WAAW,EAAE,oBAAoB,EAAC,MAAM,eAAe,CAAC;AAChE,OAAO,EAAS,KAAK,aAAa,EAAC,MAAM,mBAAmB,CAAC;AAG7D,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,iBAAiB;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAAC;CACjC;AAED,eAAO,MAAM,iBAAiB,EAAE,iBAiF/B,CAAC;AAEF,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAU3F;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,8BAA8B,EAAE,OAAO,GACtC,aAAa,CAiBf;AAED,eAAO,MAAM,oBAAoB,GAAI,MAAM,WAAW,KAAG,MAIxD,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAI,OAAO,WAAW,EAAE,KAAG,MAAM,EAItE,CAAC;AAEF,UAAU,KAAK;IACb,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,8BAA8B,CAAC,EAAE,OAAO,CAAC;IACzC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IACjD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,QAAA,MAAM,mBAAmB,GAAI,2GAQ1B,KAAK,KAAG,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileTypeSelector/index.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAElD,OAAO,EAAC,WAAW,EAAE,oBAAoB,EAAC,MAAM,eAAe,CAAC;AAChE,OAAO,EAAS,KAAK,aAAa,EAAC,MAAM,mBAAmB,CAAC;AAG7D,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,iBAAiB;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAAC;CACjC;AAED,eAAO,MAAM,iBAAiB,EAAE,iBAiF/B,CAAC;AAEF,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAU3F;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,8BAA8B,EAAE,OAAO,GACtC,aAAa,CAiBf;AAED,eAAO,MAAM,oBAAoB,GAAI,MAAM,WAAW,KAAG,MAIxD,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAI,OAAO,WAAW,EAAE,KAAG,MAAM,EAItE,CAAC;AAEF,UAAU,KAAK;IACb,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,8BAA8B,CAAC,EAAE,OAAO,CAAC;IACzC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IACjD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,QAAA,MAAM,mBAAmB,GAAI,2GAQ1B,KAAK,KAAG,GAAG,CAAC,OA4Bd,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
|
|
@@ -135,7 +135,7 @@ const ProfileTypeSelector = ({ profileTypesData, loading = false, error, selecte
|
|
|
135
135
|
? normalizeProfileTypesData(profileTypesData.types)
|
|
136
136
|
: [];
|
|
137
137
|
}, [profileTypesData, error]);
|
|
138
|
-
const profileLabels = profileNames.map(name => ({
|
|
138
|
+
const profileLabels = (profileNames.length > 0 ? profileNames : selectedKey != null ? [selectedKey] : []).map(name => ({
|
|
139
139
|
key: name,
|
|
140
140
|
element: profileSelectElement(name, flexibleKnownProfilesDetection),
|
|
141
141
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ViewSelector/index.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAGrD,UAAU,KAAK;IACb,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,QAAA,MAAM,YAAY,GAAI,mBAAiB,KAAK,KAAG,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ViewSelector/index.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAGrD,UAAU,KAAK;IACb,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,QAAA,MAAM,YAAY,GAAI,mBAAiB,KAAK,KAAG,GAAG,CAAC,OA+JlD,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useParcaContext, useURLState } from '@parca/components';
|
|
2
|
+
import { useParcaContext, useURLState, useURLStateBatch } from '@parca/components';
|
|
3
3
|
import Dropdown from './Dropdown';
|
|
4
4
|
const ViewSelector = ({ profileSource }) => {
|
|
5
5
|
const [dashboardItems = ['flamegraph'], setDashboardItems] = useURLState('dashboard_items', {
|
|
@@ -7,6 +7,7 @@ const ViewSelector = ({ profileSource }) => {
|
|
|
7
7
|
});
|
|
8
8
|
const [, setSandwichFunctionName] = useURLState('sandwich_function_name');
|
|
9
9
|
const { enableSourcesView, enableSandwichView } = useParcaContext();
|
|
10
|
+
const batchUpdates = useURLStateBatch();
|
|
10
11
|
const allItems = [
|
|
11
12
|
{
|
|
12
13
|
key: 'flamegraph',
|
|
@@ -60,10 +61,15 @@ const ViewSelector = ({ profileSource }) => {
|
|
|
60
61
|
}
|
|
61
62
|
else {
|
|
62
63
|
const newDashboardItems = dashboardItems.filter(v => v !== item.key);
|
|
63
|
-
|
|
64
|
-
// Reset sandwich function name when removing sandwich panel
|
|
64
|
+
// Batch updates when removing sandwich panel to combine both URL changes
|
|
65
65
|
if (item.key === 'sandwich') {
|
|
66
|
-
|
|
66
|
+
batchUpdates(() => {
|
|
67
|
+
setDashboardItems(newDashboardItems);
|
|
68
|
+
setSandwichFunctionName(undefined);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
setDashboardItems(newDashboardItems);
|
|
67
73
|
}
|
|
68
74
|
}
|
|
69
75
|
},
|
|
@@ -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,CAuB9D,CAAC"}
|
|
@@ -10,15 +10,17 @@
|
|
|
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 { useURLState } from '@parca/components';
|
|
13
|
+
import { useURLState, useURLStateBatch } from '@parca/components';
|
|
14
14
|
import { useProfileFilters } from '../components/ProfileFilters/useProfileFilters';
|
|
15
15
|
export const useResetStateOnProfileTypeChange = () => {
|
|
16
16
|
const [groupBy, setGroupBy] = useURLState('group_by');
|
|
17
17
|
const [curPath, setCurPath] = useURLState('cur_path');
|
|
18
18
|
const { resetFilters } = useProfileFilters();
|
|
19
19
|
const [sandwichFunctionName, setSandwichFunctionName] = useURLState('sandwich_function_name');
|
|
20
|
+
const batchUpdates = useURLStateBatch();
|
|
20
21
|
return () => {
|
|
21
|
-
|
|
22
|
+
// Batch all URL state resets into a single navigation
|
|
23
|
+
batchUpdates(() => {
|
|
22
24
|
if (groupBy !== undefined) {
|
|
23
25
|
setGroupBy(undefined);
|
|
24
26
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useVisualizationState.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useVisualizationState.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useVisualizationState.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useVisualizationState.ts"],"names":[],"mappings":"AA+BA,OAAO,EAAC,gBAAgB,EAAC,MAAM,+CAA+C,CAAC;AAG/E,eAAO,MAAM,qBAAqB,QAAO;IACvC,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,eAAe,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IACpD,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACrC,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,uBAAuB,EAAE,CAAC,oBAAoB,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IAC5E,yBAAyB,EAAE,MAAM,IAAI,CAAC;IACtC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAiH/C,CAAC"}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
import { useCallback, useMemo } from 'react';
|
|
14
|
-
import { JSONParser, JSONSerializer, useURLState, useURLStateCustom } from '@parca/components';
|
|
14
|
+
import { JSONParser, JSONSerializer, useURLState, useURLStateBatch, useURLStateCustom, } from '@parca/components';
|
|
15
15
|
import { USER_PREFERENCES, useUserPreference } from '@parca/hooks';
|
|
16
16
|
import { FIELD_FUNCTION_FILE_NAME, FIELD_FUNCTION_NAME, FIELD_LABELS, FIELD_LOCATION_ADDRESS, FIELD_MAPPING_FILE, } from '../../ProfileFlameGraph/FlameGraphArrow';
|
|
17
17
|
import { useResetFlameGraphState } from './useResetFlameGraphState';
|
|
@@ -36,6 +36,7 @@ export const useVisualizationState = () => {
|
|
|
36
36
|
});
|
|
37
37
|
const [sandwichFunctionName, setSandwichFunctionName] = useURLState('sandwich_function_name');
|
|
38
38
|
const resetFlameGraphState = useResetFlameGraphState();
|
|
39
|
+
const batchUpdates = useURLStateBatch();
|
|
39
40
|
const levelsOfProfiling = useMemo(() => [
|
|
40
41
|
FIELD_FUNCTION_NAME,
|
|
41
42
|
FIELD_FUNCTION_FILE_NAME,
|
|
@@ -46,19 +47,25 @@ export const useVisualizationState = () => {
|
|
|
46
47
|
setStoreGroupBy(keys);
|
|
47
48
|
}, [setStoreGroupBy]);
|
|
48
49
|
const toggleGroupBy = useCallback((key) => {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
50
|
+
// Batch updates to combine setGroupBy + resetFlameGraphState into single URL navigation
|
|
51
|
+
batchUpdates(() => {
|
|
52
|
+
if (groupBy.includes(key)) {
|
|
53
|
+
setGroupBy(groupBy.filter(v => v !== key)); // remove
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
const filteredGroupBy = groupBy.filter(item => !levelsOfProfiling.includes(item));
|
|
57
|
+
setGroupBy([...filteredGroupBy, key]); // add
|
|
58
|
+
}
|
|
59
|
+
resetFlameGraphState();
|
|
60
|
+
});
|
|
61
|
+
}, [groupBy, setGroupBy, levelsOfProfiling, resetFlameGraphState, batchUpdates]);
|
|
58
62
|
const setGroupByLabels = useCallback((labels) => {
|
|
59
|
-
setGroupBy
|
|
60
|
-
|
|
61
|
-
|
|
63
|
+
// Batch updates to combine setGroupBy + resetFlameGraphState into single URL navigation
|
|
64
|
+
batchUpdates(() => {
|
|
65
|
+
setGroupBy(groupBy.filter(l => !l.startsWith(`${FIELD_LABELS}.`)).concat(labels));
|
|
66
|
+
resetFlameGraphState();
|
|
67
|
+
});
|
|
68
|
+
}, [groupBy, setGroupBy, resetFlameGraphState, batchUpdates]);
|
|
62
69
|
const resetSandwichFunctionName = useCallback(() => {
|
|
63
70
|
setSandwichFunctionName(undefined);
|
|
64
71
|
}, [setSandwichFunctionName]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MoreDropdown.d.ts","sourceRoot":"","sources":["../../src/Table/MoreDropdown.tsx"],"names":[],"mappings":"AAkBA,QAAA,MAAM,YAAY,GAAI,kBAAgB;IAAC,YAAY,EAAE,MAAM,CAAA;CAAC,KAAG,KAAK,CAAC,GAAG,CAAC,OAAO,GAAG,
|
|
1
|
+
{"version":3,"file":"MoreDropdown.d.ts","sourceRoot":"","sources":["../../src/Table/MoreDropdown.tsx"],"names":[],"mappings":"AAkBA,QAAA,MAAM,YAAY,GAAI,kBAAgB;IAAC,YAAY,EAAE,MAAM,CAAA;CAAC,KAAG,KAAK,CAAC,GAAG,CAAC,OAAO,GAAG,IAgElF,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -13,16 +13,20 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
13
13
|
// limitations under the License.
|
|
14
14
|
import { Menu } from '@headlessui/react';
|
|
15
15
|
import { Icon } from '@iconify/react';
|
|
16
|
-
import { useParcaContext, useURLState } from '@parca/components';
|
|
16
|
+
import { useParcaContext, useURLState, useURLStateBatch } from '@parca/components';
|
|
17
17
|
const MoreDropdown = ({ functionName }) => {
|
|
18
18
|
const [_, setSandwichFunctionName] = useURLState('sandwich_function_name');
|
|
19
19
|
const [dashboardItems, setDashboardItems] = useURLState('dashboard_items', {
|
|
20
20
|
alwaysReturnArray: true,
|
|
21
21
|
});
|
|
22
22
|
const { enableSandwichView } = useParcaContext();
|
|
23
|
+
const batchUpdates = useURLStateBatch();
|
|
23
24
|
const onSandwichViewSelect = () => {
|
|
24
|
-
setSandwichFunctionName
|
|
25
|
-
|
|
25
|
+
// Batch updates to combine setSandwichFunctionName + setDashboardItems into single URL navigation
|
|
26
|
+
batchUpdates(() => {
|
|
27
|
+
setSandwichFunctionName(functionName.trim());
|
|
28
|
+
setDashboardItems([...dashboardItems, 'sandwich']);
|
|
29
|
+
});
|
|
26
30
|
};
|
|
27
31
|
const menuItems = [];
|
|
28
32
|
if (enableSandwichView === true) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TableContextMenu.d.ts","sourceRoot":"","sources":["../../src/Table/TableContextMenu.tsx"],"names":[],"mappings":"AAiBA,OAAO,yCAAyC,CAAC;AAKjD,OAAO,EAAC,KAAK,GAAG,EAAC,MAAM,GAAG,CAAC;AAG3B,OAAO,EAAC,KAAK,UAAU,EAAC,MAAM,mBAAmB,CAAC;AAElD,UAAU,qBAAqB;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,GAAG,GAAG,IAAI,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;CAChD;AAED,QAAA,MAAM,gBAAgB,GAAI,kEAOvB,qBAAqB,KAAG,KAAK,CAAC,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"TableContextMenu.d.ts","sourceRoot":"","sources":["../../src/Table/TableContextMenu.tsx"],"names":[],"mappings":"AAiBA,OAAO,yCAAyC,CAAC;AAKjD,OAAO,EAAC,KAAK,GAAG,EAAC,MAAM,GAAG,CAAC;AAG3B,OAAO,EAAC,KAAK,UAAU,EAAC,MAAM,mBAAmB,CAAC;AAElD,UAAU,qBAAqB;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,GAAG,GAAG,IAAI,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;CAChD;AAED,QAAA,MAAM,gBAAgB,GAAI,kEAOvB,qBAAqB,KAAG,KAAK,CAAC,GAAG,CAAC,OAmMpC,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -15,7 +15,7 @@ import { Icon } from '@iconify/react';
|
|
|
15
15
|
import cx from 'classnames';
|
|
16
16
|
import { Item, Menu, Submenu } from 'react-contexify';
|
|
17
17
|
import 'react-contexify/dist/ReactContexify.css';
|
|
18
|
-
import { useParcaContext, useURLState } from '@parca/components';
|
|
18
|
+
import { useParcaContext, useURLState, useURLStateBatch } from '@parca/components';
|
|
19
19
|
import { valueFormatter } from '@parca/utilities';
|
|
20
20
|
import { getTextForCumulative } from '../ProfileFlameGraph/FlameGraphArrow/utils';
|
|
21
21
|
import { truncateString } from '../utils';
|
|
@@ -25,12 +25,16 @@ const TableContextMenu = ({ menuId, row, unit, total, totalUnfiltered, columnVis
|
|
|
25
25
|
alwaysReturnArray: true,
|
|
26
26
|
});
|
|
27
27
|
const { enableSandwichView, isDarkMode } = useParcaContext();
|
|
28
|
+
const batchUpdates = useURLStateBatch();
|
|
28
29
|
const onSandwichViewSelect = () => {
|
|
29
30
|
if (row?.name != null && row.name.length > 0) {
|
|
30
|
-
setSandwichFunctionName
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
// Batch updates to combine setSandwichFunctionName + setDashboardItems into single URL navigation
|
|
32
|
+
batchUpdates(() => {
|
|
33
|
+
setSandwichFunctionName(row.name.trim());
|
|
34
|
+
if (!dashboardItems.includes('sandwich')) {
|
|
35
|
+
setDashboardItems([...dashboardItems, 'sandwich']);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
34
38
|
}
|
|
35
39
|
};
|
|
36
40
|
const handleCopyItem = (text) => {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook to manage compare mode state and operations
|
|
3
|
+
* Returns compare mode flags and a function to close compare mode
|
|
4
|
+
*/
|
|
5
|
+
export declare const useCompareModeMeta: () => {
|
|
6
|
+
isCompareMode: boolean;
|
|
7
|
+
isCompareAbsolute: boolean;
|
|
8
|
+
closeCompareMode: (card: "A" | "B") => void;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=useCompareModeMeta.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCompareModeMeta.d.ts","sourceRoot":"","sources":["../../src/hooks/useCompareModeMeta.ts"],"names":[],"mappings":"AAiBA;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAO;IACpC,aAAa,EAAE,OAAO,CAAC;IACvB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,gBAAgB,EAAE,CAAC,IAAI,EAAE,GAAG,GAAG,GAAG,KAAK,IAAI,CAAC;CA0G7C,CAAC"}
|