@parca/profile 0.16.376 → 0.16.378
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/ProfileIcicleGraph/IcicleGraphArrow/ColorStackLegend.d.ts +2 -2
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ColorStackLegend.js +4 -18
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.d.ts +1 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.js +20 -6
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/useMappingList.d.ts +2 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/useMappingList.js +33 -0
- package/dist/ProfileIcicleGraph/index.d.ts +1 -1
- package/dist/ProfileIcicleGraph/index.js +11 -7
- package/package.json +2 -2
- package/src/ProfileIcicleGraph/IcicleGraphArrow/ColorStackLegend.tsx +6 -23
- package/src/ProfileIcicleGraph/IcicleGraphArrow/index.tsx +27 -9
- package/src/ProfileIcicleGraph/IcicleGraphArrow/useMappingList.ts +42 -0
- package/src/ProfileIcicleGraph/index.tsx +13 -6
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
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.16.378](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.377...@parca/profile@0.16.378) (2024-05-31)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @parca/profile
|
|
9
|
+
|
|
10
|
+
## [0.16.377](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.376...@parca/profile@0.16.377) (2024-05-30)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @parca/profile
|
|
13
|
+
|
|
6
14
|
## 0.16.376 (2024-05-30)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @parca/profile
|
|
@@ -2,9 +2,9 @@ import React from 'react';
|
|
|
2
2
|
import { type NavigateFunction } from '@parca/utilities';
|
|
3
3
|
interface Props {
|
|
4
4
|
mappings?: string[];
|
|
5
|
-
|
|
5
|
+
loading?: boolean;
|
|
6
6
|
navigateTo?: NavigateFunction;
|
|
7
7
|
compareMode?: boolean;
|
|
8
8
|
}
|
|
9
|
-
declare const ColorStackLegend: ({ mappings, navigateTo, compareMode,
|
|
9
|
+
declare const ColorStackLegend: ({ mappings, navigateTo, compareMode, loading, }: Props) => React.JSX.Element;
|
|
10
10
|
export default ColorStackLegend;
|
|
@@ -17,9 +17,9 @@ import cx from 'classnames';
|
|
|
17
17
|
import { useURLState } from '@parca/components';
|
|
18
18
|
import { USER_PREFERENCES, useCurrentColorProfile, useUserPreference } from '@parca/hooks';
|
|
19
19
|
import { EVERYTHING_ELSE, selectDarkMode, useAppSelector } from '@parca/store';
|
|
20
|
-
import { getLastItem } from '@parca/utilities';
|
|
21
20
|
import { getMappingColors } from '.';
|
|
22
|
-
|
|
21
|
+
import useMappingList from './useMappingList';
|
|
22
|
+
const ColorStackLegend = ({ mappings, navigateTo, compareMode = false, loading, }) => {
|
|
23
23
|
const isDarkMode = useAppSelector(selectDarkMode);
|
|
24
24
|
const currentColorProfile = useCurrentColorProfile();
|
|
25
25
|
const [colorProfileName] = useUserPreference(USER_PREFERENCES.FLAMEGRAPH_COLOR_PROFILE.key);
|
|
@@ -27,21 +27,7 @@ const ColorStackLegend = ({ mappings, navigateTo, compareMode = false, mappingsL
|
|
|
27
27
|
param: 'binary_frame_filter',
|
|
28
28
|
navigateTo,
|
|
29
29
|
});
|
|
30
|
-
const mappingsList =
|
|
31
|
-
if (mappings === undefined) {
|
|
32
|
-
return [];
|
|
33
|
-
}
|
|
34
|
-
const list = mappings
|
|
35
|
-
?.map(mapping => {
|
|
36
|
-
return getLastItem(mapping);
|
|
37
|
-
})
|
|
38
|
-
.flat() ?? [];
|
|
39
|
-
// We add a EVERYTHING ELSE mapping to the list.
|
|
40
|
-
list.push('');
|
|
41
|
-
// We sort the mappings alphabetically to make sure that the order is always the same.
|
|
42
|
-
list.sort((a, b) => a.localeCompare(b));
|
|
43
|
-
return list;
|
|
44
|
-
}, [mappings]);
|
|
30
|
+
const mappingsList = useMappingList(mappings);
|
|
45
31
|
const mappingColors = useMemo(() => {
|
|
46
32
|
const colors = getMappingColors(mappingsList, isDarkMode, currentColorProfile);
|
|
47
33
|
return colors;
|
|
@@ -57,7 +43,7 @@ const ColorStackLegend = ({ mappings, navigateTo, compareMode = false, mappingsL
|
|
|
57
43
|
return featureA?.localeCompare(featureB ?? '') ?? 0;
|
|
58
44
|
});
|
|
59
45
|
}, [mappingColors]);
|
|
60
|
-
if (
|
|
46
|
+
if (stackColorArray.length === 0 && loading === false) {
|
|
61
47
|
return _jsx(_Fragment, {});
|
|
62
48
|
}
|
|
63
49
|
if (Object.entries(mappingColors).length === 0) {
|
|
@@ -31,6 +31,7 @@ interface IcicleGraphArrowProps {
|
|
|
31
31
|
sortBy: string;
|
|
32
32
|
flamegraphLoading: boolean;
|
|
33
33
|
isHalfScreen: boolean;
|
|
34
|
+
mappingsListFromMetadata: string[];
|
|
34
35
|
}
|
|
35
36
|
export declare const getMappingColors: (mappingsList: string[], isDarkMode: boolean, currentColorProfile: ColorConfig) => mappingColors;
|
|
36
37
|
export declare const IcicleGraphArrow: React.NamedExoticComponent<IcicleGraphArrowProps>;
|
|
@@ -49,7 +49,8 @@ export const getMappingColors = (mappingsList, isDarkMode, currentColorProfile)
|
|
|
49
49
|
});
|
|
50
50
|
return colors;
|
|
51
51
|
};
|
|
52
|
-
|
|
52
|
+
const noop = () => { };
|
|
53
|
+
export const IcicleGraphArrow = memo(function IcicleGraphArrow({ arrow, total, filtered, width, setCurPath, curPath, profileType, navigateTo, sortBy, flamegraphLoading, mappingsListFromMetadata, }) {
|
|
53
54
|
const [isContextMenuOpen, setIsContextMenuOpen] = useState(false);
|
|
54
55
|
const dispatch = useAppDispatch();
|
|
55
56
|
const [highlightSimilarStacksPreference] = useUserPreference(USER_PREFERENCES.HIGHLIGHT_SIMILAR_STACKS.key);
|
|
@@ -70,7 +71,6 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({ arrow, total, f
|
|
|
70
71
|
});
|
|
71
72
|
const currentSearchString = selectQueryParam('search_string') ?? '';
|
|
72
73
|
const { compareMode } = useProfileViewContext();
|
|
73
|
-
// const isColorStackLegendEnabled = selectQueryParam('color_stack_legend') === 'true';
|
|
74
74
|
const currentColorProfile = useCurrentColorProfile();
|
|
75
75
|
const colorForSimilarNodes = currentColorProfile.colorForSimilarNodes;
|
|
76
76
|
const mappingsList = useMemo(() => {
|
|
@@ -137,12 +137,23 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({ arrow, total, f
|
|
|
137
137
|
return;
|
|
138
138
|
}
|
|
139
139
|
// first time hiding a binary
|
|
140
|
-
const newMappingsList =
|
|
140
|
+
const newMappingsList = mappingsListFromMetadata.filter(mapping => mapping !== binaryToRemove);
|
|
141
141
|
setBinaryFrameFilter(newMappingsList);
|
|
142
142
|
};
|
|
143
|
+
const highlightSimilarStacksName = highlightSimilarStacksPreference ? hoveringName : null;
|
|
144
|
+
const highlightSimilarStacksSetName = useMemo(() => {
|
|
145
|
+
return highlightSimilarStacksPreference ? setHoveringName : noop;
|
|
146
|
+
}, [highlightSimilarStacksPreference]);
|
|
147
|
+
const highlightSimilarStacksSetLevel = useMemo(() => {
|
|
148
|
+
return highlightSimilarStacksPreference ? setHoveringLevel : noop;
|
|
149
|
+
}, [highlightSimilarStacksPreference]);
|
|
150
|
+
const highlightSimilarStacksRow = highlightSimilarStacksPreference ? hoveringRow : null;
|
|
151
|
+
const path = useMemo(() => {
|
|
152
|
+
return [];
|
|
153
|
+
}, []);
|
|
143
154
|
// useMemo for the root graph as it otherwise renders the whole graph if the hoveringRow changes.
|
|
144
155
|
const root = useMemo(() => {
|
|
145
|
-
return (_jsx("svg", { className: "font-robotoMono", width: width, height: height, preserveAspectRatio: "xMinYMid", ref: svg, onContextMenu: displayMenu, children: _jsx("g", { ref: ref, children: _jsx("g", { transform: 'translate(0, 0)', children: _jsx(IcicleNode, { table: table, row: 0, mappingColors: mappingColors, x: 0, y: 0, totalWidth: width ?? 1, height: RowHeight, setCurPath: setCurPath, curPath: curPath, total: total, xScale: xScale, path:
|
|
156
|
+
return (_jsx("svg", { className: "font-robotoMono", width: width, height: height, preserveAspectRatio: "xMinYMid", ref: svg, onContextMenu: displayMenu, children: _jsx("g", { ref: ref, children: _jsx("g", { transform: 'translate(0, 0)', children: _jsx(IcicleNode, { table: table, row: 0, mappingColors: mappingColors, x: 0, y: 0, totalWidth: width ?? 1, height: RowHeight, setCurPath: setCurPath, curPath: curPath, total: total, xScale: xScale, path: path, level: 0, isRoot: true, searchString: currentSearchString, setHoveringRow: setHoveringRow, setHoveringLevel: highlightSimilarStacksSetLevel, sortBy: sortBy, darkMode: isDarkMode, compareMode: compareMode, profileType: profileType, isContextMenuOpen: isContextMenuOpen, hoveringName: highlightSimilarStacksName, setHoveringName: highlightSimilarStacksSetName, hoveringRow: highlightSimilarStacksRow, colorForSimilarNodes: colorForSimilarNodes, highlightSimilarStacksPreference: highlightSimilarStacksPreference }) }) }) }));
|
|
146
157
|
}, [
|
|
147
158
|
width,
|
|
148
159
|
height,
|
|
@@ -159,10 +170,13 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({ arrow, total, f
|
|
|
159
170
|
compareMode,
|
|
160
171
|
profileType,
|
|
161
172
|
isContextMenuOpen,
|
|
162
|
-
|
|
163
|
-
|
|
173
|
+
highlightSimilarStacksName,
|
|
174
|
+
highlightSimilarStacksRow,
|
|
164
175
|
colorForSimilarNodes,
|
|
165
176
|
highlightSimilarStacksPreference,
|
|
177
|
+
path,
|
|
178
|
+
highlightSimilarStacksSetLevel,
|
|
179
|
+
highlightSimilarStacksSetName,
|
|
166
180
|
]);
|
|
167
181
|
return (_jsx(_Fragment, { children: _jsxs("div", { onMouseLeave: () => dispatch(setHoveringNode(undefined)), children: [_jsx(ContextMenu, { menuId: MENU_ID, table: table, row: hoveringRow ?? 0, level: hoveringLevel ?? 0, total: total, totalUnfiltered: total + filtered, profileType: profileType, navigateTo: navigateTo, trackVisibility: trackVisibility, curPath: curPath, setCurPath: setCurPath, hideMenu: hideAll, hideBinary: hideBinary }), dockedMetainfo ? (_jsx(DockedGraphTooltip, { table: table, row: hoveringRow, level: hoveringLevel ?? 0, total: total, totalUnfiltered: total + filtered, profileType: profileType })) : (!isContextMenuOpen && (_jsx(GraphTooltipArrow, { contextElement: svg.current, isContextMenuOpen: isContextMenuOpen, children: _jsx(GraphTooltipArrowContent, { table: table, row: hoveringRow, level: hoveringLevel ?? 0, isFixed: false, total: total, totalUnfiltered: total + filtered, profileType: profileType, navigateTo: navigateTo }) }))), root] }) }));
|
|
168
182
|
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Copyright 2022 The Parca Authors
|
|
2
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
// you may not use this file except in compliance with the License.
|
|
4
|
+
// You may obtain a copy of the License at
|
|
5
|
+
//
|
|
6
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
//
|
|
8
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
// See the License for the specific language governing permissions and
|
|
12
|
+
// limitations under the License.
|
|
13
|
+
import { useMemo } from 'react';
|
|
14
|
+
import { getLastItem } from '@parca/utilities';
|
|
15
|
+
const useMappingList = (mappings) => {
|
|
16
|
+
const mappingsList = useMemo(() => {
|
|
17
|
+
if (mappings === undefined) {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
const list = mappings
|
|
21
|
+
?.map(mapping => {
|
|
22
|
+
return getLastItem(mapping);
|
|
23
|
+
})
|
|
24
|
+
.flat() ?? [];
|
|
25
|
+
// We add a EVERYTHING ELSE mapping to the list.
|
|
26
|
+
list.push('');
|
|
27
|
+
// We sort the mappings alphabetically to make sure that the order is always the same.
|
|
28
|
+
list.sort((a, b) => a.localeCompare(b));
|
|
29
|
+
return list;
|
|
30
|
+
}, [mappings]);
|
|
31
|
+
return mappingsList;
|
|
32
|
+
};
|
|
33
|
+
export default useMappingList;
|
|
@@ -20,5 +20,5 @@ interface ProfileIcicleGraphProps {
|
|
|
20
20
|
mappings?: string[];
|
|
21
21
|
mappingsLoading?: boolean;
|
|
22
22
|
}
|
|
23
|
-
declare const ProfileIcicleGraph: ({ graph, arrow, total, filtered, curPath, setNewCurPath, profileType, navigateTo, loading, setActionButtons, error, width, isHalfScreen, mappings,
|
|
23
|
+
declare const ProfileIcicleGraph: ({ graph, arrow, total, filtered, curPath, setNewCurPath, profileType, navigateTo, loading, setActionButtons, error, width, isHalfScreen, mappings, }: ProfileIcicleGraphProps) => JSX.Element;
|
|
24
24
|
export default ProfileIcicleGraph;
|
|
@@ -24,6 +24,7 @@ import SortBySelect from './ActionButtons/SortBySelect';
|
|
|
24
24
|
import IcicleGraph from './IcicleGraph';
|
|
25
25
|
import IcicleGraphArrow, { FIELD_FUNCTION_NAME } from './IcicleGraphArrow';
|
|
26
26
|
import ColorStackLegend from './IcicleGraphArrow/ColorStackLegend';
|
|
27
|
+
import useMappingList from './IcicleGraphArrow/useMappingList';
|
|
27
28
|
const numberFormatter = new Intl.NumberFormat('en-US');
|
|
28
29
|
const ErrorContent = ({ errorMessage }) => {
|
|
29
30
|
return _jsx("div", { className: "flex justify-center p-10", children: errorMessage });
|
|
@@ -77,11 +78,12 @@ const GroupAndSortActionButtons = ({ navigateTo }) => {
|
|
|
77
78
|
}, [groupBy, setGroupBy]);
|
|
78
79
|
return (_jsxs(_Fragment, { children: [_jsx(GroupByDropdown, { groupBy: groupBy, toggleGroupBy: toggleGroupBy }), _jsx(SortBySelect, { compareMode: compareMode, sortBy: storeSortBy, setSortBy: setStoreSortBy })] }));
|
|
79
80
|
};
|
|
80
|
-
const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ graph, arrow, total, filtered, curPath, setNewCurPath, profileType, navigateTo, loading, setActionButtons, error, width, isHalfScreen, mappings,
|
|
81
|
+
const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ graph, arrow, total, filtered, curPath, setNewCurPath, profileType, navigateTo, loading, setActionButtons, error, width, isHalfScreen, mappings, }) {
|
|
81
82
|
const { onError, authenticationErrorMessage, isDarkMode } = useParcaContext();
|
|
82
83
|
const { compareMode } = useProfileViewContext();
|
|
83
84
|
const [isLoading, setIsLoading] = useState(true);
|
|
84
85
|
const isColorStackLegendEnabled = selectQueryParam('color_stack_legend') === 'true';
|
|
86
|
+
const mappingsList = useMappingList(mappings);
|
|
85
87
|
const [storeSortBy = FIELD_FUNCTION_NAME] = useURLState({
|
|
86
88
|
param: 'sort_by',
|
|
87
89
|
navigateTo,
|
|
@@ -123,14 +125,15 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ graph, arrow, to
|
|
|
123
125
|
isHalfScreen,
|
|
124
126
|
isLoading,
|
|
125
127
|
]);
|
|
128
|
+
const loadingState = !loading && (arrow !== undefined || graph !== undefined) && mappings !== undefined;
|
|
126
129
|
useEffect(() => {
|
|
127
|
-
if (
|
|
130
|
+
if (loadingState) {
|
|
128
131
|
setIsLoading(false);
|
|
129
132
|
}
|
|
130
133
|
else {
|
|
131
134
|
setIsLoading(true);
|
|
132
135
|
}
|
|
133
|
-
}, [
|
|
136
|
+
}, [loadingState]);
|
|
134
137
|
if (error != null) {
|
|
135
138
|
onError?.(error);
|
|
136
139
|
if (authenticationErrorMessage !== undefined && error.code === 'UNAUTHENTICATED') {
|
|
@@ -150,26 +153,27 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ graph, arrow, to
|
|
|
150
153
|
if (graph !== undefined)
|
|
151
154
|
return (_jsx(IcicleGraph, { width: width, graph: graph, total: total, filtered: filtered, curPath: curPath, setCurPath: setNewCurPath, profileType: profileType, navigateTo: navigateTo }));
|
|
152
155
|
if (arrow !== undefined)
|
|
153
|
-
return (_jsx(IcicleGraphArrow, { width: width, arrow: arrow, total: total, filtered: filtered, curPath: curPath, setCurPath: setNewCurPath, profileType: profileType, navigateTo: navigateTo, sortBy: storeSortBy, flamegraphLoading: isLoading, isHalfScreen: isHalfScreen }));
|
|
156
|
+
return (_jsx(IcicleGraphArrow, { width: width, arrow: arrow, total: total, filtered: filtered, curPath: curPath, setCurPath: setNewCurPath, profileType: profileType, navigateTo: navigateTo, sortBy: storeSortBy, flamegraphLoading: isLoading, isHalfScreen: isHalfScreen, mappingsListFromMetadata: mappingsList }));
|
|
154
157
|
}, [
|
|
155
158
|
isLoading,
|
|
156
159
|
graph,
|
|
157
160
|
arrow,
|
|
158
161
|
total,
|
|
162
|
+
loading,
|
|
163
|
+
width,
|
|
159
164
|
filtered,
|
|
160
165
|
curPath,
|
|
161
166
|
setNewCurPath,
|
|
162
167
|
profileType,
|
|
163
168
|
navigateTo,
|
|
164
|
-
width,
|
|
165
169
|
storeSortBy,
|
|
166
170
|
isHalfScreen,
|
|
167
171
|
isDarkMode,
|
|
168
|
-
|
|
172
|
+
mappingsList,
|
|
169
173
|
]);
|
|
170
174
|
if (isTrimmed) {
|
|
171
175
|
console.info(`Trimmed ${trimmedFormatted} (${trimmedPercentage}%) too small values.`);
|
|
172
176
|
}
|
|
173
|
-
return (_jsx(AnimatePresence, { children: _jsxs(motion.div, { className: "relative h-full w-full", initial: { opacity: 0 }, animate: { opacity: 1 }, transition: { duration: 0.5 }, children: [compareMode ? _jsx(DiffLegend, {}) : null, isColorStackLegendEnabled && (_jsx(ColorStackLegend, { navigateTo: navigateTo, compareMode: compareMode, mappings: mappings,
|
|
177
|
+
return (_jsx(AnimatePresence, { children: _jsxs(motion.div, { className: "relative h-full w-full", initial: { opacity: 0 }, animate: { opacity: 1 }, transition: { duration: 0.5 }, children: [compareMode ? _jsx(DiffLegend, {}) : null, isColorStackLegendEnabled && (_jsx(ColorStackLegend, { navigateTo: navigateTo, compareMode: compareMode, mappings: mappings, loading: isLoading })), _jsx("div", { className: "min-h-48", id: "h-icicle-graph", children: _jsx(_Fragment, { children: icicleGraph }) }), _jsxs("p", { className: "my-2 text-xs", children: ["Showing ", totalFormatted, ' ', isFiltered ? (_jsxs("span", { children: ["(", filteredPercentage, "%) filtered of ", totalUnfilteredFormatted, ' '] })) : (_jsx(_Fragment, {})), "values.", ' '] })] }, "icicle-graph-loaded") }));
|
|
174
178
|
};
|
|
175
179
|
export default ProfileIcicleGraph;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parca/profile",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.378",
|
|
4
4
|
"description": "Profile viewing libraries",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@headlessui/react": "^1.7.19",
|
|
@@ -71,5 +71,5 @@
|
|
|
71
71
|
"access": "public",
|
|
72
72
|
"registry": "https://registry.npmjs.org/"
|
|
73
73
|
},
|
|
74
|
-
"gitHead": "
|
|
74
|
+
"gitHead": "fbab8208a5a08c44a96f81c90bdd69494914c11c"
|
|
75
75
|
}
|
|
@@ -19,13 +19,14 @@ 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 {
|
|
22
|
+
import {type NavigateFunction} from '@parca/utilities';
|
|
23
23
|
|
|
24
24
|
import {getMappingColors} from '.';
|
|
25
|
+
import useMappingList from './useMappingList';
|
|
25
26
|
|
|
26
27
|
interface Props {
|
|
27
28
|
mappings?: string[];
|
|
28
|
-
|
|
29
|
+
loading?: boolean;
|
|
29
30
|
navigateTo?: NavigateFunction;
|
|
30
31
|
compareMode?: boolean;
|
|
31
32
|
}
|
|
@@ -34,7 +35,7 @@ const ColorStackLegend = ({
|
|
|
34
35
|
mappings,
|
|
35
36
|
navigateTo,
|
|
36
37
|
compareMode = false,
|
|
37
|
-
|
|
38
|
+
loading,
|
|
38
39
|
}: Props): React.JSX.Element => {
|
|
39
40
|
const isDarkMode = useAppSelector(selectDarkMode);
|
|
40
41
|
const currentColorProfile = useCurrentColorProfile();
|
|
@@ -46,25 +47,7 @@ const ColorStackLegend = ({
|
|
|
46
47
|
navigateTo,
|
|
47
48
|
});
|
|
48
49
|
|
|
49
|
-
const mappingsList =
|
|
50
|
-
if (mappings === undefined) {
|
|
51
|
-
return [];
|
|
52
|
-
}
|
|
53
|
-
const list =
|
|
54
|
-
mappings
|
|
55
|
-
?.map(mapping => {
|
|
56
|
-
return getLastItem(mapping) as string;
|
|
57
|
-
})
|
|
58
|
-
.flat() ?? [];
|
|
59
|
-
|
|
60
|
-
// We add a EVERYTHING ELSE mapping to the list.
|
|
61
|
-
list.push('');
|
|
62
|
-
|
|
63
|
-
// We sort the mappings alphabetically to make sure that the order is always the same.
|
|
64
|
-
list.sort((a, b) => a.localeCompare(b));
|
|
65
|
-
|
|
66
|
-
return list;
|
|
67
|
-
}, [mappings]);
|
|
50
|
+
const mappingsList = useMappingList(mappings);
|
|
68
51
|
|
|
69
52
|
const mappingColors = useMemo(() => {
|
|
70
53
|
const colors = getMappingColors(mappingsList, isDarkMode, currentColorProfile);
|
|
@@ -83,7 +66,7 @@ const ColorStackLegend = ({
|
|
|
83
66
|
});
|
|
84
67
|
}, [mappingColors]);
|
|
85
68
|
|
|
86
|
-
if (
|
|
69
|
+
if (stackColorArray.length === 0 && loading === false) {
|
|
87
70
|
return <></>;
|
|
88
71
|
}
|
|
89
72
|
|
|
@@ -72,6 +72,7 @@ interface IcicleGraphArrowProps {
|
|
|
72
72
|
sortBy: string;
|
|
73
73
|
flamegraphLoading: boolean;
|
|
74
74
|
isHalfScreen: boolean;
|
|
75
|
+
mappingsListFromMetadata: string[];
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
export const getMappingColors = (
|
|
@@ -88,6 +89,8 @@ export const getMappingColors = (
|
|
|
88
89
|
return colors;
|
|
89
90
|
};
|
|
90
91
|
|
|
92
|
+
const noop = (): void => {};
|
|
93
|
+
|
|
91
94
|
export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
92
95
|
arrow,
|
|
93
96
|
total,
|
|
@@ -99,6 +102,7 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
99
102
|
navigateTo,
|
|
100
103
|
sortBy,
|
|
101
104
|
flamegraphLoading,
|
|
105
|
+
mappingsListFromMetadata,
|
|
102
106
|
}: IcicleGraphArrowProps): React.JSX.Element {
|
|
103
107
|
const [isContextMenuOpen, setIsContextMenuOpen] = useState<boolean>(false);
|
|
104
108
|
const dispatch = useAppDispatch();
|
|
@@ -126,7 +130,6 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
126
130
|
|
|
127
131
|
const currentSearchString = (selectQueryParam('search_string') as string) ?? '';
|
|
128
132
|
const {compareMode} = useProfileViewContext();
|
|
129
|
-
// const isColorStackLegendEnabled = selectQueryParam('color_stack_legend') === 'true';
|
|
130
133
|
const currentColorProfile = useCurrentColorProfile();
|
|
131
134
|
const colorForSimilarNodes = currentColorProfile.colorForSimilarNodes;
|
|
132
135
|
|
|
@@ -209,10 +212,22 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
209
212
|
}
|
|
210
213
|
|
|
211
214
|
// first time hiding a binary
|
|
212
|
-
const newMappingsList =
|
|
215
|
+
const newMappingsList = mappingsListFromMetadata.filter(mapping => mapping !== binaryToRemove);
|
|
213
216
|
setBinaryFrameFilter(newMappingsList);
|
|
214
217
|
};
|
|
215
218
|
|
|
219
|
+
const highlightSimilarStacksName = highlightSimilarStacksPreference ? hoveringName : null;
|
|
220
|
+
const highlightSimilarStacksSetName = useMemo(() => {
|
|
221
|
+
return highlightSimilarStacksPreference ? setHoveringName : noop;
|
|
222
|
+
}, [highlightSimilarStacksPreference]);
|
|
223
|
+
const highlightSimilarStacksSetLevel = useMemo(() => {
|
|
224
|
+
return highlightSimilarStacksPreference ? setHoveringLevel : noop;
|
|
225
|
+
}, [highlightSimilarStacksPreference]);
|
|
226
|
+
const highlightSimilarStacksRow = highlightSimilarStacksPreference ? hoveringRow : null;
|
|
227
|
+
const path = useMemo(() => {
|
|
228
|
+
return [];
|
|
229
|
+
}, []);
|
|
230
|
+
|
|
216
231
|
// useMemo for the root graph as it otherwise renders the whole graph if the hoveringRow changes.
|
|
217
232
|
const root = useMemo(() => {
|
|
218
233
|
return (
|
|
@@ -238,20 +253,20 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
238
253
|
curPath={curPath}
|
|
239
254
|
total={total}
|
|
240
255
|
xScale={xScale}
|
|
241
|
-
path={
|
|
256
|
+
path={path}
|
|
242
257
|
level={0}
|
|
243
258
|
isRoot={true}
|
|
244
259
|
searchString={currentSearchString}
|
|
245
260
|
setHoveringRow={setHoveringRow}
|
|
246
|
-
setHoveringLevel={
|
|
261
|
+
setHoveringLevel={highlightSimilarStacksSetLevel}
|
|
247
262
|
sortBy={sortBy}
|
|
248
263
|
darkMode={isDarkMode}
|
|
249
264
|
compareMode={compareMode}
|
|
250
265
|
profileType={profileType}
|
|
251
266
|
isContextMenuOpen={isContextMenuOpen}
|
|
252
|
-
hoveringName={
|
|
253
|
-
setHoveringName={
|
|
254
|
-
hoveringRow={
|
|
267
|
+
hoveringName={highlightSimilarStacksName}
|
|
268
|
+
setHoveringName={highlightSimilarStacksSetName}
|
|
269
|
+
hoveringRow={highlightSimilarStacksRow}
|
|
255
270
|
colorForSimilarNodes={colorForSimilarNodes}
|
|
256
271
|
highlightSimilarStacksPreference={highlightSimilarStacksPreference}
|
|
257
272
|
/>
|
|
@@ -275,10 +290,13 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
275
290
|
compareMode,
|
|
276
291
|
profileType,
|
|
277
292
|
isContextMenuOpen,
|
|
278
|
-
|
|
279
|
-
|
|
293
|
+
highlightSimilarStacksName,
|
|
294
|
+
highlightSimilarStacksRow,
|
|
280
295
|
colorForSimilarNodes,
|
|
281
296
|
highlightSimilarStacksPreference,
|
|
297
|
+
path,
|
|
298
|
+
highlightSimilarStacksSetLevel,
|
|
299
|
+
highlightSimilarStacksSetName,
|
|
282
300
|
]);
|
|
283
301
|
|
|
284
302
|
return (
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Copyright 2022 The Parca Authors
|
|
2
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
// you may not use this file except in compliance with the License.
|
|
4
|
+
// You may obtain a copy of the License at
|
|
5
|
+
//
|
|
6
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
//
|
|
8
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
// See the License for the specific language governing permissions and
|
|
12
|
+
// limitations under the License.
|
|
13
|
+
|
|
14
|
+
import {useMemo} from 'react';
|
|
15
|
+
|
|
16
|
+
import {getLastItem} from '@parca/utilities';
|
|
17
|
+
|
|
18
|
+
const useMappingList = (mappings: string[] | undefined): string[] => {
|
|
19
|
+
const mappingsList = useMemo(() => {
|
|
20
|
+
if (mappings === undefined) {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
const list =
|
|
24
|
+
mappings
|
|
25
|
+
?.map(mapping => {
|
|
26
|
+
return getLastItem(mapping) as string;
|
|
27
|
+
})
|
|
28
|
+
.flat() ?? [];
|
|
29
|
+
|
|
30
|
+
// We add a EVERYTHING ELSE mapping to the list.
|
|
31
|
+
list.push('');
|
|
32
|
+
|
|
33
|
+
// We sort the mappings alphabetically to make sure that the order is always the same.
|
|
34
|
+
list.sort((a, b) => a.localeCompare(b));
|
|
35
|
+
|
|
36
|
+
return list;
|
|
37
|
+
}, [mappings]);
|
|
38
|
+
|
|
39
|
+
return mappingsList;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export default useMappingList;
|
|
@@ -40,6 +40,7 @@ import SortBySelect from './ActionButtons/SortBySelect';
|
|
|
40
40
|
import IcicleGraph from './IcicleGraph';
|
|
41
41
|
import IcicleGraphArrow, {FIELD_FUNCTION_NAME} from './IcicleGraphArrow';
|
|
42
42
|
import ColorStackLegend from './IcicleGraphArrow/ColorStackLegend';
|
|
43
|
+
import useMappingList from './IcicleGraphArrow/useMappingList';
|
|
43
44
|
|
|
44
45
|
const numberFormatter = new Intl.NumberFormat('en-US');
|
|
45
46
|
|
|
@@ -220,13 +221,14 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
220
221
|
width,
|
|
221
222
|
isHalfScreen,
|
|
222
223
|
mappings,
|
|
223
|
-
mappingsLoading,
|
|
224
224
|
}: ProfileIcicleGraphProps): JSX.Element {
|
|
225
225
|
const {onError, authenticationErrorMessage, isDarkMode} = useParcaContext();
|
|
226
226
|
const {compareMode} = useProfileViewContext();
|
|
227
227
|
const [isLoading, setIsLoading] = useState<boolean>(true);
|
|
228
228
|
const isColorStackLegendEnabled = selectQueryParam('color_stack_legend') === 'true';
|
|
229
229
|
|
|
230
|
+
const mappingsList = useMappingList(mappings);
|
|
231
|
+
|
|
230
232
|
const [storeSortBy = FIELD_FUNCTION_NAME] = useURLState({
|
|
231
233
|
param: 'sort_by',
|
|
232
234
|
navigateTo,
|
|
@@ -327,13 +329,16 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
327
329
|
isLoading,
|
|
328
330
|
]);
|
|
329
331
|
|
|
332
|
+
const loadingState =
|
|
333
|
+
!loading && (arrow !== undefined || graph !== undefined) && mappings !== undefined;
|
|
334
|
+
|
|
330
335
|
useEffect(() => {
|
|
331
|
-
if (
|
|
336
|
+
if (loadingState) {
|
|
332
337
|
setIsLoading(false);
|
|
333
338
|
} else {
|
|
334
339
|
setIsLoading(true);
|
|
335
340
|
}
|
|
336
|
-
}, [
|
|
341
|
+
}, [loadingState]);
|
|
337
342
|
|
|
338
343
|
if (error != null) {
|
|
339
344
|
onError?.(error);
|
|
@@ -389,6 +394,7 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
389
394
|
sortBy={storeSortBy as string}
|
|
390
395
|
flamegraphLoading={isLoading}
|
|
391
396
|
isHalfScreen={isHalfScreen}
|
|
397
|
+
mappingsListFromMetadata={mappingsList}
|
|
392
398
|
/>
|
|
393
399
|
);
|
|
394
400
|
}, [
|
|
@@ -396,16 +402,17 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
396
402
|
graph,
|
|
397
403
|
arrow,
|
|
398
404
|
total,
|
|
405
|
+
loading,
|
|
406
|
+
width,
|
|
399
407
|
filtered,
|
|
400
408
|
curPath,
|
|
401
409
|
setNewCurPath,
|
|
402
410
|
profileType,
|
|
403
411
|
navigateTo,
|
|
404
|
-
width,
|
|
405
412
|
storeSortBy,
|
|
406
413
|
isHalfScreen,
|
|
407
414
|
isDarkMode,
|
|
408
|
-
|
|
415
|
+
mappingsList,
|
|
409
416
|
]);
|
|
410
417
|
|
|
411
418
|
if (isTrimmed) {
|
|
@@ -427,7 +434,7 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
427
434
|
navigateTo={navigateTo}
|
|
428
435
|
compareMode={compareMode}
|
|
429
436
|
mappings={mappings}
|
|
430
|
-
|
|
437
|
+
loading={isLoading}
|
|
431
438
|
/>
|
|
432
439
|
)}
|
|
433
440
|
<div className="min-h-48" id="h-icicle-graph">
|