@parca/profile 0.16.415 → 0.16.417
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/Callgraph/index.js +3 -2
- package/dist/GraphTooltipArrow/Content.d.ts +1 -3
- package/dist/GraphTooltipArrow/Content.d.ts.map +1 -1
- package/dist/GraphTooltipArrow/Content.js +4 -4
- package/dist/GraphTooltipArrow/DockedGraphTooltip/index.js +2 -2
- package/dist/GraphTooltipArrow/useGraphTooltipMetaInfo/index.d.ts +1 -3
- package/dist/GraphTooltipArrow/useGraphTooltipMetaInfo/index.d.ts.map +1 -1
- package/dist/GraphTooltipArrow/useGraphTooltipMetaInfo/index.js +6 -16
- package/dist/ProfileExplorer/ProfileExplorerCompare.d.ts.map +1 -1
- package/dist/ProfileExplorer/ProfileExplorerCompare.js +3 -3
- package/dist/ProfileExplorer/ProfileExplorerSingle.d.ts.map +1 -1
- package/dist/ProfileExplorer/ProfileExplorerSingle.js +1 -1
- package/dist/ProfileExplorer/index.d.ts.map +1 -1
- package/dist/ProfileExplorer/index.js +1 -7
- package/dist/ProfileIcicleGraph/IcicleGraph/ColorStackLegend.d.ts +1 -3
- package/dist/ProfileIcicleGraph/IcicleGraph/ColorStackLegend.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraph/ColorStackLegend.js +2 -2
- package/dist/ProfileIcicleGraph/IcicleGraph/index.d.ts +0 -2
- package/dist/ProfileIcicleGraph/IcicleGraph/index.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraph/index.js +4 -3
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ColorStackLegend.d.ts +1 -3
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ColorStackLegend.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ColorStackLegend.js +8 -20
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.d.ts +1 -3
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.js +2 -2
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.d.ts +1 -2
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.js +6 -9
- package/dist/ProfileIcicleGraph/index.d.ts +1 -3
- package/dist/ProfileIcicleGraph/index.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/index.js +20 -48
- package/dist/ProfileMetricsGraph/index.js +1 -2
- package/dist/ProfileSelector/index.d.ts.map +1 -1
- package/dist/ProfileSelector/index.js +19 -2
- package/dist/ProfileView/FilterByFunctionButton.d.ts +1 -4
- package/dist/ProfileView/FilterByFunctionButton.d.ts.map +1 -1
- package/dist/ProfileView/FilterByFunctionButton.js +12 -3
- package/dist/ProfileView/ViewSelector.d.ts +1 -3
- package/dist/ProfileView/ViewSelector.d.ts.map +1 -1
- package/dist/ProfileView/ViewSelector.js +3 -4
- package/dist/ProfileView/VisualizationPanel.d.ts +0 -2
- package/dist/ProfileView/VisualizationPanel.d.ts.map +1 -1
- package/dist/ProfileView/VisualizationPanel.js +2 -2
- package/dist/ProfileView/index.d.ts +1 -5
- package/dist/ProfileView/index.d.ts.map +1 -1
- package/dist/ProfileView/index.js +11 -18
- package/dist/ProfileViewWithData.d.ts +1 -3
- package/dist/ProfileViewWithData.d.ts.map +1 -1
- package/dist/ProfileViewWithData.js +15 -12
- package/dist/SourceView/index.js +1 -1
- package/dist/SourceView/useSelectedLineRange.js +1 -1
- package/dist/Table/index.d.ts +1 -2
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +9 -25
- package/dist/TopTable/index.d.ts.map +1 -1
- package/dist/TopTable/index.js +3 -7
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/styles.css +1 -1
- package/package.json +7 -7
- package/src/Callgraph/index.tsx +3 -3
- package/src/GraphTooltipArrow/Content.tsx +4 -14
- package/src/GraphTooltipArrow/DockedGraphTooltip/index.tsx +2 -2
- package/src/GraphTooltipArrow/useGraphTooltipMetaInfo/index.ts +6 -22
- package/src/ProfileExplorer/ProfileExplorerCompare.tsx +2 -3
- package/src/ProfileExplorer/ProfileExplorerSingle.tsx +1 -5
- package/src/ProfileExplorer/index.tsx +0 -8
- package/src/ProfileIcicleGraph/IcicleGraph/ColorStackLegend.tsx +2 -4
- package/src/ProfileIcicleGraph/IcicleGraph/index.tsx +5 -8
- package/src/ProfileIcicleGraph/IcicleGraphArrow/ColorStackLegend.tsx +8 -27
- package/src/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.tsx +2 -4
- package/src/ProfileIcicleGraph/IcicleGraphArrow/index.tsx +4 -17
- package/src/ProfileIcicleGraph/index.tsx +19 -67
- package/src/ProfileMetricsGraph/index.tsx +2 -2
- package/src/ProfileSelector/index.tsx +23 -2
- package/src/ProfileView/FilterByFunctionButton.tsx +15 -9
- package/src/ProfileView/ViewSelector.tsx +6 -7
- package/src/ProfileView/VisualizationPanel.tsx +1 -9
- package/src/ProfileView/index.tsx +8 -23
- package/src/ProfileViewWithData.tsx +15 -18
- package/src/SourceView/index.tsx +1 -1
- package/src/SourceView/useSelectedLineRange.ts +2 -2
- package/src/Table/index.tsx +10 -41
- package/src/TopTable/index.tsx +3 -8
- package/src/index.tsx +4 -0
|
@@ -19,7 +19,6 @@ import cx from 'classnames';
|
|
|
19
19
|
import {useURLState} from '@parca/components';
|
|
20
20
|
import {USER_PREFERENCES, useCurrentColorProfile, useUserPreference} from '@parca/hooks';
|
|
21
21
|
import {EVERYTHING_ELSE, selectDarkMode, useAppSelector} from '@parca/store';
|
|
22
|
-
import {type NavigateFunction} from '@parca/utilities';
|
|
23
22
|
|
|
24
23
|
import {getMappingColors} from '.';
|
|
25
24
|
import useMappingList from './useMappingList';
|
|
@@ -27,24 +26,18 @@ import useMappingList from './useMappingList';
|
|
|
27
26
|
interface Props {
|
|
28
27
|
mappings?: string[];
|
|
29
28
|
loading?: boolean;
|
|
30
|
-
navigateTo?: NavigateFunction;
|
|
31
29
|
compareMode?: boolean;
|
|
32
30
|
}
|
|
33
31
|
|
|
34
|
-
const ColorStackLegend = ({
|
|
35
|
-
mappings,
|
|
36
|
-
navigateTo,
|
|
37
|
-
compareMode = false,
|
|
38
|
-
loading,
|
|
39
|
-
}: Props): React.JSX.Element => {
|
|
32
|
+
const ColorStackLegend = ({mappings, compareMode = false, loading}: Props): React.JSX.Element => {
|
|
40
33
|
const isDarkMode = useAppSelector(selectDarkMode);
|
|
41
34
|
const currentColorProfile = useCurrentColorProfile();
|
|
42
35
|
const [colorProfileName] = useUserPreference<string>(
|
|
43
36
|
USER_PREFERENCES.FLAMEGRAPH_COLOR_PROFILE.key
|
|
44
37
|
);
|
|
45
|
-
const [currentSearchString, setSearchString] = useURLState({
|
|
46
|
-
|
|
47
|
-
|
|
38
|
+
const [currentSearchString, setSearchString] = useURLState<string[]>('binary_frame_filter', {
|
|
39
|
+
alwaysReturnArray: true,
|
|
40
|
+
defaultValue: [],
|
|
48
41
|
});
|
|
49
42
|
|
|
50
43
|
const mappingsList = useMappingList(mappings);
|
|
@@ -79,7 +72,7 @@ const ColorStackLegend = ({
|
|
|
79
72
|
}
|
|
80
73
|
|
|
81
74
|
return (
|
|
82
|
-
<div className="my-4 flex w-full flex-wrap justify-start">
|
|
75
|
+
<div className="my-4 flex w-full flex-wrap justify-start column-gap-2">
|
|
83
76
|
{stackColorArray.map(([feature, color]) => {
|
|
84
77
|
const filteringAllowed = feature !== EVERYTHING_ELSE;
|
|
85
78
|
const isHighlighted =
|
|
@@ -88,7 +81,7 @@ const ColorStackLegend = ({
|
|
|
88
81
|
<div
|
|
89
82
|
key={feature}
|
|
90
83
|
className={cx(
|
|
91
|
-
'flex-no-wrap mb-1 flex w-
|
|
84
|
+
'flex-no-wrap mb-1 flex w-[19.25%] items-center justify-between text-ellipsis p-1',
|
|
92
85
|
{
|
|
93
86
|
'cursor-pointer': filteringAllowed,
|
|
94
87
|
'bg-gray-200 dark:bg-gray-800': isHighlighted,
|
|
@@ -100,12 +93,7 @@ const ColorStackLegend = ({
|
|
|
100
93
|
}
|
|
101
94
|
|
|
102
95
|
// Check if the current search string is defined and an array
|
|
103
|
-
const updatedSearchString =
|
|
104
|
-
? [...currentSearchString, feature] // If array, append the feature
|
|
105
|
-
: // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
106
|
-
currentSearchString // If not array, preserve current value
|
|
107
|
-
? currentSearchString.split(',') // If string, split by commas
|
|
108
|
-
: [feature]; // If undefined, initialize array with feature
|
|
96
|
+
const updatedSearchString = [...currentSearchString, feature]; // If array, append the feature
|
|
109
97
|
|
|
110
98
|
setSearchString(updatedSearchString);
|
|
111
99
|
}}
|
|
@@ -123,15 +111,8 @@ const ColorStackLegend = ({
|
|
|
123
111
|
<Icon
|
|
124
112
|
icon="radix-icons:cross-circled"
|
|
125
113
|
onClick={e => {
|
|
126
|
-
let searchString: string[] = [];
|
|
127
|
-
if (typeof currentSearchString === 'string') {
|
|
128
|
-
searchString.push(currentSearchString);
|
|
129
|
-
} else {
|
|
130
|
-
searchString = currentSearchString;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
114
|
// remove the current feature from the search string array of strings
|
|
134
|
-
setSearchString(
|
|
115
|
+
setSearchString(currentSearchString.filter((f: string) => f !== feature));
|
|
135
116
|
e.stopPropagation();
|
|
136
117
|
}}
|
|
137
118
|
/>
|
|
@@ -19,7 +19,7 @@ import {Tooltip} from 'react-tooltip';
|
|
|
19
19
|
import {useParcaContext} from '@parca/components';
|
|
20
20
|
import {USER_PREFERENCES, useUserPreference} from '@parca/hooks';
|
|
21
21
|
import {ProfileType} from '@parca/parser';
|
|
22
|
-
import {getLastItem
|
|
22
|
+
import {getLastItem} from '@parca/utilities';
|
|
23
23
|
|
|
24
24
|
import {useGraphTooltip} from '../../GraphTooltipArrow/useGraphTooltip';
|
|
25
25
|
import {useGraphTooltipMetaInfo} from '../../GraphTooltipArrow/useGraphTooltipMetaInfo';
|
|
@@ -34,7 +34,6 @@ interface ContextMenuProps {
|
|
|
34
34
|
totalUnfiltered: bigint;
|
|
35
35
|
row: number;
|
|
36
36
|
level: number;
|
|
37
|
-
navigateTo: NavigateFunction;
|
|
38
37
|
trackVisibility: (isVisible: boolean) => void;
|
|
39
38
|
curPath: string[];
|
|
40
39
|
setCurPath: (path: string[]) => void;
|
|
@@ -49,7 +48,6 @@ const ContextMenu = ({
|
|
|
49
48
|
totalUnfiltered,
|
|
50
49
|
row,
|
|
51
50
|
level,
|
|
52
|
-
navigateTo,
|
|
53
51
|
trackVisibility,
|
|
54
52
|
curPath,
|
|
55
53
|
setCurPath,
|
|
@@ -83,7 +81,7 @@ const ContextMenu = ({
|
|
|
83
81
|
mappingFile,
|
|
84
82
|
mappingBuildID,
|
|
85
83
|
inlined,
|
|
86
|
-
} = useGraphTooltipMetaInfo({table, row
|
|
84
|
+
} = useGraphTooltipMetaInfo({table, row});
|
|
87
85
|
|
|
88
86
|
if (contextMenuData === null) {
|
|
89
87
|
return <></>;
|
|
@@ -27,13 +27,7 @@ import {
|
|
|
27
27
|
useAppDispatch,
|
|
28
28
|
useAppSelector,
|
|
29
29
|
} from '@parca/store';
|
|
30
|
-
import {
|
|
31
|
-
getLastItem,
|
|
32
|
-
scaleLinear,
|
|
33
|
-
selectQueryParam,
|
|
34
|
-
type ColorConfig,
|
|
35
|
-
type NavigateFunction,
|
|
36
|
-
} from '@parca/utilities';
|
|
30
|
+
import {getLastItem, scaleLinear, type ColorConfig} from '@parca/utilities';
|
|
37
31
|
|
|
38
32
|
import GraphTooltipArrow from '../../GraphTooltipArrow';
|
|
39
33
|
import GraphTooltipArrowContent from '../../GraphTooltipArrow/Content';
|
|
@@ -70,7 +64,6 @@ interface IcicleGraphArrowProps {
|
|
|
70
64
|
width?: number;
|
|
71
65
|
curPath: string[];
|
|
72
66
|
setCurPath: (path: string[]) => void;
|
|
73
|
-
navigateTo?: NavigateFunction;
|
|
74
67
|
sortBy: string;
|
|
75
68
|
flamegraphLoading: boolean;
|
|
76
69
|
isHalfScreen: boolean;
|
|
@@ -101,7 +94,6 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
101
94
|
setCurPath,
|
|
102
95
|
curPath,
|
|
103
96
|
profileType,
|
|
104
|
-
navigateTo,
|
|
105
97
|
sortBy,
|
|
106
98
|
flamegraphLoading,
|
|
107
99
|
mappingsListFromMetadata,
|
|
@@ -125,12 +117,9 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
125
117
|
const svg = useRef(null);
|
|
126
118
|
const ref = useRef<SVGGElement>(null);
|
|
127
119
|
|
|
128
|
-
const [binaryFrameFilter, setBinaryFrameFilter] = useURLState(
|
|
129
|
-
param: 'binary_frame_filter',
|
|
130
|
-
navigateTo,
|
|
131
|
-
});
|
|
120
|
+
const [binaryFrameFilter, setBinaryFrameFilter] = useURLState('binary_frame_filter');
|
|
132
121
|
|
|
133
|
-
const currentSearchString = (
|
|
122
|
+
const [currentSearchString] = useURLState('search_string');
|
|
134
123
|
const {compareMode} = useProfileViewContext();
|
|
135
124
|
const currentColorProfile = useCurrentColorProfile();
|
|
136
125
|
const colorForSimilarNodes = currentColorProfile.colorForSimilarNodes;
|
|
@@ -258,7 +247,7 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
258
247
|
path={path}
|
|
259
248
|
level={0}
|
|
260
249
|
isRoot={true}
|
|
261
|
-
searchString={currentSearchString}
|
|
250
|
+
searchString={(currentSearchString as string) ?? ''}
|
|
262
251
|
setHoveringRow={setHoveringRow}
|
|
263
252
|
setHoveringLevel={highlightSimilarStacksSetLevel}
|
|
264
253
|
sortBy={sortBy}
|
|
@@ -312,7 +301,6 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
312
301
|
total={total}
|
|
313
302
|
totalUnfiltered={total + filtered}
|
|
314
303
|
profileType={profileType}
|
|
315
|
-
navigateTo={navigateTo as NavigateFunction}
|
|
316
304
|
trackVisibility={trackVisibility}
|
|
317
305
|
curPath={curPath}
|
|
318
306
|
setCurPath={setCurPath}
|
|
@@ -341,7 +329,6 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
341
329
|
total={total}
|
|
342
330
|
totalUnfiltered={total + filtered}
|
|
343
331
|
profileType={profileType}
|
|
344
|
-
navigateTo={navigateTo as NavigateFunction}
|
|
345
332
|
unit={arrow.unit}
|
|
346
333
|
/>
|
|
347
334
|
</GraphTooltipArrow>
|
|
@@ -26,19 +26,14 @@ import {
|
|
|
26
26
|
} from '@parca/components';
|
|
27
27
|
import {USER_PREFERENCES, useUserPreference} from '@parca/hooks';
|
|
28
28
|
import {ProfileType} from '@parca/parser';
|
|
29
|
-
import {
|
|
30
|
-
capitalizeOnlyFirstLetter,
|
|
31
|
-
divide,
|
|
32
|
-
selectQueryParam,
|
|
33
|
-
type NavigateFunction,
|
|
34
|
-
} from '@parca/utilities';
|
|
29
|
+
import {capitalizeOnlyFirstLetter, divide, selectQueryParam} from '@parca/utilities';
|
|
35
30
|
|
|
36
31
|
import {useProfileViewContext} from '../ProfileView/ProfileViewContext';
|
|
37
32
|
import DiffLegend from '../components/DiffLegend';
|
|
38
33
|
import GroupByDropdown from './ActionButtons/GroupByDropdown';
|
|
39
34
|
import SortBySelect from './ActionButtons/SortBySelect';
|
|
40
|
-
import IcicleGraph from './IcicleGraph';
|
|
41
|
-
import
|
|
35
|
+
import {IcicleGraph} from './IcicleGraph';
|
|
36
|
+
import {FIELD_FUNCTION_NAME, IcicleGraphArrow} from './IcicleGraphArrow';
|
|
42
37
|
import ColorStackLegend from './IcicleGraphArrow/ColorStackLegend';
|
|
43
38
|
import useMappingList from './IcicleGraphArrow/useMappingList';
|
|
44
39
|
|
|
@@ -55,7 +50,6 @@ interface ProfileIcicleGraphProps {
|
|
|
55
50
|
profileType?: ProfileType;
|
|
56
51
|
curPath: string[] | [];
|
|
57
52
|
setNewCurPath: (path: string[]) => void;
|
|
58
|
-
navigateTo?: NavigateFunction;
|
|
59
53
|
loading: boolean;
|
|
60
54
|
setActionButtons?: (buttons: React.JSX.Element) => void;
|
|
61
55
|
error?: any;
|
|
@@ -68,21 +62,9 @@ const ErrorContent = ({errorMessage}: {errorMessage: string}): JSX.Element => {
|
|
|
68
62
|
return <div className="flex justify-center p-10">{errorMessage}</div>;
|
|
69
63
|
};
|
|
70
64
|
|
|
71
|
-
const ShowHideLegendButton = ({
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}: {
|
|
75
|
-
navigateTo?: NavigateFunction;
|
|
76
|
-
isHalfScreen: boolean;
|
|
77
|
-
}): JSX.Element => {
|
|
78
|
-
const [colorStackLegend, setStoreColorStackLegend] = useURLState({
|
|
79
|
-
param: 'color_stack_legend',
|
|
80
|
-
navigateTo,
|
|
81
|
-
});
|
|
82
|
-
const [binaryFrameFilter, setBinaryFrameFilter] = useURLState({
|
|
83
|
-
param: 'binary_frame_filter',
|
|
84
|
-
navigateTo,
|
|
85
|
-
});
|
|
65
|
+
const ShowHideLegendButton = ({isHalfScreen}: {isHalfScreen: boolean}): JSX.Element => {
|
|
66
|
+
const [colorStackLegend, setStoreColorStackLegend] = useURLState('color_stack_legend');
|
|
67
|
+
const [binaryFrameFilter, setBinaryFrameFilter] = useURLState('binary_frame_filter');
|
|
86
68
|
|
|
87
69
|
const {compareMode} = useProfileViewContext();
|
|
88
70
|
|
|
@@ -156,16 +138,15 @@ const ShowHideLegendButton = ({
|
|
|
156
138
|
);
|
|
157
139
|
};
|
|
158
140
|
|
|
159
|
-
const GroupAndSortActionButtons = (
|
|
160
|
-
const [storeSortBy
|
|
161
|
-
|
|
162
|
-
navigateTo,
|
|
141
|
+
const GroupAndSortActionButtons = (): JSX.Element => {
|
|
142
|
+
const [storeSortBy, setStoreSortBy] = useURLState('sort_by', {
|
|
143
|
+
defaultValue: FIELD_FUNCTION_NAME,
|
|
163
144
|
});
|
|
164
145
|
const {compareMode} = useProfileViewContext();
|
|
165
146
|
|
|
166
|
-
const [
|
|
167
|
-
|
|
168
|
-
|
|
147
|
+
const [groupBy, setStoreGroupBy] = useURLState<string[]>('group_by', {
|
|
148
|
+
defaultValue: [FIELD_FUNCTION_NAME],
|
|
149
|
+
alwaysReturnArray: true,
|
|
169
150
|
});
|
|
170
151
|
|
|
171
152
|
const setGroupBy = useCallback(
|
|
@@ -175,16 +156,6 @@ const GroupAndSortActionButtons = ({navigateTo}: {navigateTo?: NavigateFunction}
|
|
|
175
156
|
[setStoreGroupBy]
|
|
176
157
|
);
|
|
177
158
|
|
|
178
|
-
const groupBy = useMemo(() => {
|
|
179
|
-
if (storeGroupBy !== undefined) {
|
|
180
|
-
if (typeof storeGroupBy === 'string') {
|
|
181
|
-
return [storeGroupBy];
|
|
182
|
-
}
|
|
183
|
-
return storeGroupBy;
|
|
184
|
-
}
|
|
185
|
-
return [FIELD_FUNCTION_NAME];
|
|
186
|
-
}, [storeGroupBy]);
|
|
187
|
-
|
|
188
159
|
const toggleGroupBy = useCallback(
|
|
189
160
|
(key: string): void => {
|
|
190
161
|
groupBy.includes(key)
|
|
@@ -214,7 +185,6 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
214
185
|
curPath,
|
|
215
186
|
setNewCurPath,
|
|
216
187
|
profileType,
|
|
217
|
-
navigateTo,
|
|
218
188
|
loading,
|
|
219
189
|
setActionButtons,
|
|
220
190
|
error,
|
|
@@ -229,26 +199,17 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
229
199
|
|
|
230
200
|
const mappingsList = useMappingList(mappings);
|
|
231
201
|
|
|
232
|
-
const [storeSortBy = FIELD_FUNCTION_NAME] = useURLState(
|
|
233
|
-
param: 'sort_by',
|
|
234
|
-
navigateTo,
|
|
235
|
-
});
|
|
202
|
+
const [storeSortBy = FIELD_FUNCTION_NAME] = useURLState('sort_by');
|
|
236
203
|
|
|
237
|
-
const [invertStack = '', setInvertStack] = useURLState(
|
|
238
|
-
param: 'invert_call_stack',
|
|
239
|
-
navigateTo,
|
|
240
|
-
});
|
|
204
|
+
const [invertStack = '', setInvertStack] = useURLState('invert_call_stack');
|
|
241
205
|
const isInvert = invertStack === 'true';
|
|
242
206
|
|
|
243
207
|
// By default, we want delta profiles (CPU) to be relatively compared.
|
|
244
208
|
// For non-delta profiles, like goroutines or memory, we want the profiles to be compared absolutely.
|
|
245
209
|
const compareAbsoluteDefault = profileType?.delta === false ? 'true' : 'false';
|
|
246
210
|
|
|
247
|
-
const [compareAbsolute = compareAbsoluteDefault, setCompareAbsolute] =
|
|
248
|
-
|
|
249
|
-
navigateTo,
|
|
250
|
-
withURLUpdate: true,
|
|
251
|
-
});
|
|
211
|
+
const [compareAbsolute = compareAbsoluteDefault, setCompareAbsolute] =
|
|
212
|
+
useURLState('compare_absolute');
|
|
252
213
|
const isCompareAbsolute = compareAbsolute === 'true';
|
|
253
214
|
|
|
254
215
|
const [
|
|
@@ -285,7 +246,7 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
285
246
|
setActionButtons?.(
|
|
286
247
|
<div className="flex w-full justify-end gap-2 pb-2">
|
|
287
248
|
<div className="ml-2 flex w-full flex-col items-start justify-between gap-2 md:flex-row md:items-end">
|
|
288
|
-
{<GroupAndSortActionButtons
|
|
249
|
+
{<GroupAndSortActionButtons />}
|
|
289
250
|
{isHalfScreen ? (
|
|
290
251
|
<IconButton
|
|
291
252
|
icon={isInvert ? 'ph:sort-ascending' : 'ph:sort-descending'}
|
|
@@ -303,7 +264,7 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
303
264
|
<Icon icon={isInvert ? 'ph:sort-ascending' : 'ph:sort-descending'} width={20} />
|
|
304
265
|
</Button>
|
|
305
266
|
)}
|
|
306
|
-
<ShowHideLegendButton isHalfScreen={isHalfScreen}
|
|
267
|
+
<ShowHideLegendButton isHalfScreen={isHalfScreen} />
|
|
307
268
|
{compareMode && (
|
|
308
269
|
<Button
|
|
309
270
|
variant="neutral"
|
|
@@ -340,7 +301,6 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
340
301
|
</div>
|
|
341
302
|
);
|
|
342
303
|
}, [
|
|
343
|
-
navigateTo,
|
|
344
304
|
isInvert,
|
|
345
305
|
setInvertStack,
|
|
346
306
|
arrow,
|
|
@@ -391,7 +351,6 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
391
351
|
curPath={curPath}
|
|
392
352
|
setCurPath={setNewCurPath}
|
|
393
353
|
profileType={profileType}
|
|
394
|
-
navigateTo={navigateTo}
|
|
395
354
|
/>
|
|
396
355
|
);
|
|
397
356
|
|
|
@@ -405,7 +364,6 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
405
364
|
curPath={curPath}
|
|
406
365
|
setCurPath={setNewCurPath}
|
|
407
366
|
profileType={profileType}
|
|
408
|
-
navigateTo={navigateTo}
|
|
409
367
|
sortBy={storeSortBy as string}
|
|
410
368
|
flamegraphLoading={isLoading}
|
|
411
369
|
isHalfScreen={isHalfScreen}
|
|
@@ -423,7 +381,6 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
423
381
|
curPath,
|
|
424
382
|
setNewCurPath,
|
|
425
383
|
profileType,
|
|
426
|
-
navigateTo,
|
|
427
384
|
storeSortBy,
|
|
428
385
|
isHalfScreen,
|
|
429
386
|
isDarkMode,
|
|
@@ -455,12 +412,7 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
455
412
|
>
|
|
456
413
|
{compareMode ? <DiffLegend /> : null}
|
|
457
414
|
{isColorStackLegendEnabled && (
|
|
458
|
-
<ColorStackLegend
|
|
459
|
-
navigateTo={navigateTo}
|
|
460
|
-
compareMode={compareMode}
|
|
461
|
-
mappings={mappings}
|
|
462
|
-
loading={isLoading}
|
|
463
|
-
/>
|
|
415
|
+
<ColorStackLegend compareMode={compareMode} mappings={mappings} loading={isLoading} />
|
|
464
416
|
)}
|
|
465
417
|
<div className="min-h-48" id="h-icicle-graph">
|
|
466
418
|
<>{icicleGraph}</>
|
|
@@ -101,8 +101,8 @@ export const useQueryRange = (
|
|
|
101
101
|
skip = false
|
|
102
102
|
): IQueryRangeState => {
|
|
103
103
|
const metadata = useGrpcMetadata();
|
|
104
|
-
const
|
|
105
|
-
|
|
104
|
+
const [stepCountStr, setStepCount] = useURLState('step_count');
|
|
105
|
+
|
|
106
106
|
const defaultStepCount = useMemo(() => {
|
|
107
107
|
return getStepCountFromScreenWidth(10);
|
|
108
108
|
}, []);
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
|
|
14
|
-
import React, {useEffect, useMemo, useState} from 'react';
|
|
14
|
+
import React, {useEffect, useMemo, useRef, useState} from 'react';
|
|
15
15
|
|
|
16
16
|
import {RpcError} from '@protobuf-ts/runtime-rpc';
|
|
17
|
-
import Select from 'react-select';
|
|
17
|
+
import Select, {type SelectInstance} from 'react-select';
|
|
18
18
|
|
|
19
19
|
import {Label, ProfileTypesResponse, QueryServiceClient} from '@parca/client';
|
|
20
20
|
import {
|
|
@@ -105,6 +105,7 @@ const ProfileSelector = ({
|
|
|
105
105
|
} = useProfileTypes(queryClient);
|
|
106
106
|
const {heightStyle} = useMetricsGraphDimensions(comparing);
|
|
107
107
|
const {viewComponent} = useParcaContext();
|
|
108
|
+
const sumByRef = useRef(null);
|
|
108
109
|
|
|
109
110
|
const [timeRangeSelection, setTimeRangeSelection] = useState(
|
|
110
111
|
DateTimeRange.fromRangeKey(querySelection.timeSelection, querySelection.from, querySelection.to)
|
|
@@ -316,6 +317,26 @@ const ProfileSelector = ({
|
|
|
316
317
|
indicatorSeparator: () => ({display: 'none'}),
|
|
317
318
|
}}
|
|
318
319
|
isDisabled={!profileType.delta}
|
|
320
|
+
ref={sumByRef}
|
|
321
|
+
onKeyDown={e => {
|
|
322
|
+
const currentRef = sumByRef.current as unknown as SelectInstance | null;
|
|
323
|
+
if (currentRef == null) {
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
const inputRef = currentRef.inputRef;
|
|
327
|
+
if (inputRef == null) {
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (
|
|
332
|
+
e.key === 'Enter' &&
|
|
333
|
+
inputRef.value === '' &&
|
|
334
|
+
currentRef.state.focusedOptionId === null // menu is not open
|
|
335
|
+
) {
|
|
336
|
+
setQueryExpression(true);
|
|
337
|
+
currentRef.blur();
|
|
338
|
+
}
|
|
339
|
+
}}
|
|
319
340
|
/>
|
|
320
341
|
</div>
|
|
321
342
|
<DateTimeRangePicker
|
|
@@ -16,14 +16,14 @@ import {useCallback, useMemo, useState} from 'react';
|
|
|
16
16
|
import {Icon} from '@iconify/react';
|
|
17
17
|
|
|
18
18
|
import {Input, useURLState} from '@parca/components';
|
|
19
|
-
import
|
|
20
|
-
|
|
21
|
-
const FilterByFunctionButton = ({
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const [
|
|
19
|
+
import {USER_PREFERENCES, useUserPreference} from '@parca/hooks';
|
|
20
|
+
|
|
21
|
+
const FilterByFunctionButton = (): JSX.Element => {
|
|
22
|
+
const [highlightAfterFilteringEnabled] = useUserPreference<boolean>(
|
|
23
|
+
USER_PREFERENCES.HIGHTLIGHT_AFTER_FILTERING.key
|
|
24
|
+
);
|
|
25
|
+
const [storeValue, setStoreValue] = useURLState('filter_by_function');
|
|
26
|
+
const [_, setSearchString] = useURLState('search_string');
|
|
27
27
|
const [localValue, setLocalValue] = useState(storeValue as string);
|
|
28
28
|
|
|
29
29
|
const isClearAction = useMemo(() => {
|
|
@@ -34,10 +34,16 @@ const FilterByFunctionButton = ({
|
|
|
34
34
|
if (isClearAction) {
|
|
35
35
|
setLocalValue('');
|
|
36
36
|
setStoreValue('');
|
|
37
|
+
if (highlightAfterFilteringEnabled) {
|
|
38
|
+
setSearchString('');
|
|
39
|
+
}
|
|
37
40
|
} else {
|
|
38
41
|
setStoreValue(localValue);
|
|
42
|
+
if (highlightAfterFilteringEnabled) {
|
|
43
|
+
setSearchString(localValue);
|
|
44
|
+
}
|
|
39
45
|
}
|
|
40
|
-
}, [localValue, isClearAction, setStoreValue]);
|
|
46
|
+
}, [localValue, isClearAction, setStoreValue, highlightAfterFilteringEnabled, setSearchString]);
|
|
41
47
|
|
|
42
48
|
return (
|
|
43
49
|
<Input
|
|
@@ -13,12 +13,10 @@
|
|
|
13
13
|
|
|
14
14
|
import {Select, useParcaContext, useURLState, type SelectElement} from '@parca/components';
|
|
15
15
|
import {useUIFeatureFlag} from '@parca/hooks';
|
|
16
|
-
import type {NavigateFunction} from '@parca/utilities';
|
|
17
16
|
|
|
18
17
|
interface Props {
|
|
19
18
|
position: number;
|
|
20
19
|
defaultValue: string;
|
|
21
|
-
navigateTo?: NavigateFunction;
|
|
22
20
|
placeholderText?: string;
|
|
23
21
|
primary?: boolean;
|
|
24
22
|
addView?: boolean;
|
|
@@ -29,7 +27,6 @@ interface Props {
|
|
|
29
27
|
|
|
30
28
|
const ViewSelector = ({
|
|
31
29
|
defaultValue,
|
|
32
|
-
navigateTo,
|
|
33
30
|
position,
|
|
34
31
|
placeholderText,
|
|
35
32
|
primary = false,
|
|
@@ -39,10 +36,12 @@ const ViewSelector = ({
|
|
|
39
36
|
id,
|
|
40
37
|
}: Props): JSX.Element => {
|
|
41
38
|
const [callgraphEnabled] = useUIFeatureFlag('callgraph');
|
|
42
|
-
const [dashboardItems = ['icicle'], setDashboardItems] = useURLState(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
39
|
+
const [dashboardItems = ['icicle'], setDashboardItems] = useURLState<string[]>(
|
|
40
|
+
'dashboard_items',
|
|
41
|
+
{
|
|
42
|
+
alwaysReturnArray: true,
|
|
43
|
+
}
|
|
44
|
+
);
|
|
46
45
|
const {enableSourcesView} = useParcaContext();
|
|
47
46
|
|
|
48
47
|
const allItems: Array<{key: string; canBeSelected: boolean; supportingText?: string}> = [
|
|
@@ -19,7 +19,6 @@ import type {DraggableProvidedDragHandleProps} from 'react-beautiful-dnd';
|
|
|
19
19
|
|
|
20
20
|
import {IconButton, useParcaContext} from '@parca/components';
|
|
21
21
|
import {CloseIcon} from '@parca/icons';
|
|
22
|
-
import type {NavigateFunction} from '@parca/utilities';
|
|
23
22
|
|
|
24
23
|
import ViewSelector from './ViewSelector';
|
|
25
24
|
|
|
@@ -28,7 +27,6 @@ interface Props {
|
|
|
28
27
|
index: number;
|
|
29
28
|
isMultiPanelView: boolean;
|
|
30
29
|
handleClosePanel: (dashboardItem: string) => void;
|
|
31
|
-
navigateTo: NavigateFunction | undefined;
|
|
32
30
|
dragHandleProps: DraggableProvidedDragHandleProps | null | undefined;
|
|
33
31
|
getDashboardItemByType: (props: {
|
|
34
32
|
type: string;
|
|
@@ -42,7 +40,6 @@ export const VisualizationPanel = React.memo(function VisualizationPanel({
|
|
|
42
40
|
index,
|
|
43
41
|
isMultiPanelView,
|
|
44
42
|
handleClosePanel,
|
|
45
|
-
navigateTo,
|
|
46
43
|
dragHandleProps,
|
|
47
44
|
getDashboardItemByType,
|
|
48
45
|
}: Props): JSX.Element {
|
|
@@ -73,12 +70,7 @@ export const VisualizationPanel = React.memo(function VisualizationPanel({
|
|
|
73
70
|
isMultiPanelView && dashboardItem === 'icicle' && 'pb-[10px]'
|
|
74
71
|
)}
|
|
75
72
|
>
|
|
76
|
-
<ViewSelector
|
|
77
|
-
id="h-switch-viz"
|
|
78
|
-
defaultValue={dashboardItem}
|
|
79
|
-
navigateTo={navigateTo}
|
|
80
|
-
position={index}
|
|
81
|
-
/>
|
|
73
|
+
<ViewSelector id="h-switch-viz" defaultValue={dashboardItem} position={index} />
|
|
82
74
|
|
|
83
75
|
{dashboardItem === 'icicle' && flamegraphHint != null ? (
|
|
84
76
|
<div className="px-2">{flamegraphHint}</div>
|
|
@@ -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 {Profiler, ProfilerProps, useEffect,
|
|
14
|
+
import {Profiler, ProfilerProps, useEffect, useState} from 'react';
|
|
15
15
|
|
|
16
16
|
import {Icon} from '@iconify/react';
|
|
17
17
|
import cx from 'classnames';
|
|
@@ -51,15 +51,13 @@ import {jsonToDot} from '../Callgraph/utils';
|
|
|
51
51
|
import ProfileIcicleGraph from '../ProfileIcicleGraph';
|
|
52
52
|
import {ProfileSource} from '../ProfileSource';
|
|
53
53
|
import {SourceView} from '../SourceView';
|
|
54
|
-
import Table from '../Table';
|
|
54
|
+
import {Table} from '../Table';
|
|
55
55
|
import ProfileShareButton from '../components/ProfileShareButton';
|
|
56
56
|
import FilterByFunctionButton from './FilterByFunctionButton';
|
|
57
57
|
import {ProfileViewContextProvider} from './ProfileViewContext';
|
|
58
58
|
import ViewSelector from './ViewSelector';
|
|
59
59
|
import {VisualizationPanel} from './VisualizationPanel';
|
|
60
60
|
|
|
61
|
-
type NavigateFunction = (path: string, queryParams: any, options?: {replace?: boolean}) => void;
|
|
62
|
-
|
|
63
61
|
export interface FlamegraphData {
|
|
64
62
|
loading: boolean;
|
|
65
63
|
data?: Flamegraph;
|
|
@@ -104,7 +102,6 @@ export interface ProfileViewProps {
|
|
|
104
102
|
sourceData?: SourceData;
|
|
105
103
|
profileSource?: ProfileSource;
|
|
106
104
|
queryClient?: QueryServiceClient;
|
|
107
|
-
navigateTo?: NavigateFunction;
|
|
108
105
|
compare?: boolean;
|
|
109
106
|
onDownloadPProf: () => void;
|
|
110
107
|
pprofDownloading?: boolean;
|
|
@@ -128,7 +125,6 @@ export const ProfileView = ({
|
|
|
128
125
|
sourceData,
|
|
129
126
|
profileSource,
|
|
130
127
|
queryClient,
|
|
131
|
-
navigateTo,
|
|
132
128
|
onDownloadPProf,
|
|
133
129
|
pprofDownloading,
|
|
134
130
|
compare,
|
|
@@ -136,20 +132,12 @@ export const ProfileView = ({
|
|
|
136
132
|
const {timezone} = useParcaContext();
|
|
137
133
|
const {ref, dimensions} = useContainerDimensions();
|
|
138
134
|
const [curPath, setCurPath] = useState<string[]>([]);
|
|
139
|
-
const [
|
|
140
|
-
|
|
141
|
-
navigateTo,
|
|
135
|
+
const [dashboardItems, setDashboardItems] = useURLState<string[]>('dashboard_items', {
|
|
136
|
+
alwaysReturnArray: true,
|
|
142
137
|
});
|
|
143
138
|
const [graphvizLoaded, setGraphvizLoaded] = useState(false);
|
|
144
139
|
const [callgraphSVG, setCallgraphSVG] = useState<string | undefined>(undefined);
|
|
145
|
-
const [currentSearchString] = useURLState(
|
|
146
|
-
|
|
147
|
-
const dashboardItems = useMemo(() => {
|
|
148
|
-
if (rawDashboardItems !== undefined) {
|
|
149
|
-
return rawDashboardItems as string[];
|
|
150
|
-
}
|
|
151
|
-
return ['icicle'];
|
|
152
|
-
}, [rawDashboardItems]);
|
|
140
|
+
const [currentSearchString, setSearchString] = useURLState<string | undefined>('search_string');
|
|
153
141
|
|
|
154
142
|
const isDarkMode = useAppSelector(selectDarkMode);
|
|
155
143
|
const isMultiPanelView = dashboardItems.length > 1;
|
|
@@ -240,7 +228,6 @@ export const ProfileView = ({
|
|
|
240
228
|
total={total}
|
|
241
229
|
filtered={filtered}
|
|
242
230
|
profileType={profileSource?.ProfileType()}
|
|
243
|
-
navigateTo={navigateTo}
|
|
244
231
|
loading={flamegraphData.loading}
|
|
245
232
|
setActionButtons={setActionButtons}
|
|
246
233
|
error={flamegraphData.error}
|
|
@@ -281,9 +268,9 @@ export const ProfileView = ({
|
|
|
281
268
|
data={topTableData.arrow?.record}
|
|
282
269
|
unit={topTableData.unit}
|
|
283
270
|
profileType={profileSource?.ProfileType()}
|
|
284
|
-
navigateTo={navigateTo}
|
|
285
271
|
setActionButtons={setActionButtons}
|
|
286
|
-
currentSearchString={currentSearchString
|
|
272
|
+
currentSearchString={currentSearchString}
|
|
273
|
+
setSearchString={setSearchString}
|
|
287
274
|
isHalfScreen={isHalfScreen}
|
|
288
275
|
/>
|
|
289
276
|
) : (
|
|
@@ -371,7 +358,7 @@ export const ProfileView = ({
|
|
|
371
358
|
</div>
|
|
372
359
|
|
|
373
360
|
<div className="lg:flex flex-wrap items-center gap-2 md:justify-end hidden">
|
|
374
|
-
<FilterByFunctionButton
|
|
361
|
+
<FilterByFunctionButton />
|
|
375
362
|
{profileViewExternalSubActions != null ? profileViewExternalSubActions : null}
|
|
376
363
|
<UserPreferences
|
|
377
364
|
customButton={
|
|
@@ -402,7 +389,6 @@ export const ProfileView = ({
|
|
|
402
389
|
</Button>
|
|
403
390
|
<ViewSelector
|
|
404
391
|
defaultValue=""
|
|
405
|
-
navigateTo={navigateTo}
|
|
406
392
|
position={-1}
|
|
407
393
|
placeholderText="Add panel"
|
|
408
394
|
icon={<Icon icon="material-symbols:add" width={20} />}
|
|
@@ -451,7 +437,6 @@ export const ProfileView = ({
|
|
|
451
437
|
dashboardItem={dashboardItem}
|
|
452
438
|
getDashboardItemByType={getDashboardItemByType}
|
|
453
439
|
dragHandleProps={provided.dragHandleProps}
|
|
454
|
-
navigateTo={navigateTo}
|
|
455
440
|
index={index}
|
|
456
441
|
/>
|
|
457
442
|
</div>
|