@parca/profile 0.19.122 → 0.19.124
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/ProfileFlameChart/SamplesStrips/SamplesGraph/index.js +1 -1
- package/dist/ProfileFlameChart/index.d.ts.map +1 -1
- package/dist/ProfileFlameChart/index.js +11 -1
- package/dist/ProfileFlameGraph/FlameGraphArrow/MiniMap.d.ts +20 -0
- package/dist/ProfileFlameGraph/FlameGraphArrow/MiniMap.d.ts.map +1 -0
- package/dist/ProfileFlameGraph/FlameGraphArrow/MiniMap.js +173 -0
- package/dist/ProfileFlameGraph/FlameGraphArrow/ZoomControls.d.ts +11 -0
- package/dist/ProfileFlameGraph/FlameGraphArrow/ZoomControls.d.ts.map +1 -0
- package/dist/ProfileFlameGraph/FlameGraphArrow/ZoomControls.js +10 -0
- package/dist/ProfileFlameGraph/FlameGraphArrow/index.d.ts +1 -0
- package/dist/ProfileFlameGraph/FlameGraphArrow/index.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/FlameGraphArrow/index.js +19 -8
- package/dist/ProfileFlameGraph/FlameGraphArrow/useZoom.d.ts +9 -0
- package/dist/ProfileFlameGraph/FlameGraphArrow/useZoom.d.ts.map +1 -0
- package/dist/ProfileFlameGraph/FlameGraphArrow/useZoom.js +88 -0
- package/dist/ProfileFlameGraph/index.d.ts +2 -1
- package/dist/ProfileFlameGraph/index.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/index.js +4 -6
- package/dist/ProfileSelector/index.d.ts.map +1 -1
- package/dist/ProfileSelector/index.js +1 -0
- package/dist/ProfileSelector/useAutoQuerySelector.d.ts +2 -1
- package/dist/ProfileSelector/useAutoQuerySelector.d.ts.map +1 -1
- package/dist/ProfileSelector/useAutoQuerySelector.js +6 -1
- package/dist/TimelineGuide/index.js +1 -1
- package/dist/styles.css +1 -1
- package/package.json +3 -3
- package/src/ProfileFlameChart/SamplesStrips/SamplesGraph/index.tsx +1 -1
- package/src/ProfileFlameChart/index.tsx +23 -0
- package/src/ProfileFlameGraph/FlameGraphArrow/MiniMap.tsx +270 -0
- package/src/ProfileFlameGraph/FlameGraphArrow/ZoomControls.tsx +67 -0
- package/src/ProfileFlameGraph/FlameGraphArrow/index.tsx +97 -38
- package/src/ProfileFlameGraph/FlameGraphArrow/useZoom.ts +116 -0
- package/src/ProfileFlameGraph/index.tsx +6 -14
- package/src/ProfileSelector/index.tsx +1 -0
- package/src/ProfileSelector/useAutoQuerySelector.ts +9 -0
- package/src/TimelineGuide/index.tsx +2 -2
|
@@ -28,22 +28,27 @@ import {FlamegraphArrow} from '@parca/client';
|
|
|
28
28
|
import {FlameGraphSkeleton, SandwichFlameGraphSkeleton, useParcaContext} from '@parca/components';
|
|
29
29
|
import {USER_PREFERENCES, useCurrentColorProfile, useUserPreference} from '@parca/hooks';
|
|
30
30
|
import {ProfileType} from '@parca/parser';
|
|
31
|
-
import {getColorForFeature
|
|
31
|
+
import {getColorForFeature} from '@parca/store';
|
|
32
32
|
import {type ColorConfig} from '@parca/utilities';
|
|
33
33
|
|
|
34
34
|
import {ProfileSource} from '../../ProfileSource';
|
|
35
35
|
import {useProfileFilters} from '../../ProfileView/components/ProfileFilters/useProfileFilters';
|
|
36
36
|
import {useProfileViewContext} from '../../ProfileView/context/ProfileViewContext';
|
|
37
|
+
import {TimelineGuide} from '../../TimelineGuide';
|
|
37
38
|
import {alignedUint8Array} from '../../utils';
|
|
38
39
|
import ContextMenuWrapper, {ContextMenuWrapperRef} from './ContextMenuWrapper';
|
|
39
40
|
import {FlameNode, RowHeight, colorByColors} from './FlameGraphNodes';
|
|
40
41
|
import {MemoizedTooltip} from './MemoizedTooltip';
|
|
42
|
+
import {MiniMap} from './MiniMap';
|
|
41
43
|
import {TooltipProvider} from './TooltipContext';
|
|
44
|
+
import {ZoomControls} from './ZoomControls';
|
|
42
45
|
import {useBatchedRendering} from './useBatchedRendering';
|
|
43
46
|
import {useScrollViewport} from './useScrollViewport';
|
|
44
47
|
import {useVisibleNodes} from './useVisibleNodes';
|
|
48
|
+
import {useZoom} from './useZoom';
|
|
45
49
|
import {
|
|
46
50
|
CurrentPathFrame,
|
|
51
|
+
boundsFromProfileSource,
|
|
47
52
|
extractFeature,
|
|
48
53
|
extractFilenameFeature,
|
|
49
54
|
getCurrentPathFrameData,
|
|
@@ -93,6 +98,7 @@ interface FlameGraphArrowProps {
|
|
|
93
98
|
tooltipId?: string;
|
|
94
99
|
maxFrameCount?: number;
|
|
95
100
|
isExpanded?: boolean;
|
|
101
|
+
zoomControlsRef?: React.RefObject<HTMLDivElement | null>;
|
|
96
102
|
}
|
|
97
103
|
|
|
98
104
|
export const getMappingColors = (
|
|
@@ -145,14 +151,14 @@ export const FlameGraphArrow = memo(function FlameGraphArrow({
|
|
|
145
151
|
mappingsListFromMetadata,
|
|
146
152
|
filenamesListFromMetadata,
|
|
147
153
|
colorBy,
|
|
154
|
+
zoomControlsRef,
|
|
148
155
|
}: FlameGraphArrowProps): React.JSX.Element {
|
|
149
156
|
const [highlightSimilarStacksPreference] = useUserPreference<boolean>(
|
|
150
157
|
USER_PREFERENCES.HIGHLIGHT_SIMILAR_STACKS.key
|
|
151
158
|
);
|
|
152
159
|
const [hoveringRow, setHoveringRow] = useState<number | undefined>(undefined);
|
|
153
160
|
const [dockedMetainfo] = useUserPreference<boolean>(USER_PREFERENCES.GRAPH_METAINFO_DOCKED.key);
|
|
154
|
-
const isDarkMode =
|
|
155
|
-
const {perf} = useParcaContext();
|
|
161
|
+
const {perf, isDarkMode} = useParcaContext();
|
|
156
162
|
|
|
157
163
|
const table: Table = useMemo(() => {
|
|
158
164
|
const result = tableFromIPC(alignedUint8Array(arrow.record), {useBigInt: true});
|
|
@@ -261,6 +267,18 @@ export const FlameGraphArrow = memo(function FlameGraphArrow({
|
|
|
261
267
|
// Get the viewport of the container, this is used to determine which rows are visible.
|
|
262
268
|
const viewport = useScrollViewport(containerRef);
|
|
263
269
|
|
|
270
|
+
const isZoomEnabled = isFlameChart;
|
|
271
|
+
|
|
272
|
+
const {zoomLevel, zoomIn, zoomOut, resetZoom} = useZoom(
|
|
273
|
+
isZoomEnabled ? containerRef : {current: null}
|
|
274
|
+
);
|
|
275
|
+
const zoomedWidth = isZoomEnabled ? Math.round((width ?? 1) * zoomLevel) : width ?? 0;
|
|
276
|
+
|
|
277
|
+
// Reset zoom when the data changes (e.g. new query, different time range)
|
|
278
|
+
useEffect(() => {
|
|
279
|
+
resetZoom();
|
|
280
|
+
}, [table, resetZoom]);
|
|
281
|
+
|
|
264
282
|
// To find the selected row, we must walk the current path and look at which
|
|
265
283
|
// children of the current frame matches the path element exactly. Until the
|
|
266
284
|
// end, the row we find at the end is our selected row.
|
|
@@ -290,7 +308,7 @@ export const FlameGraphArrow = memo(function FlameGraphArrow({
|
|
|
290
308
|
table,
|
|
291
309
|
viewport,
|
|
292
310
|
total,
|
|
293
|
-
width:
|
|
311
|
+
width: zoomedWidth,
|
|
294
312
|
selectedRow,
|
|
295
313
|
effectiveDepth: deferredEffectiveDepth,
|
|
296
314
|
});
|
|
@@ -328,6 +346,15 @@ export const FlameGraphArrow = memo(function FlameGraphArrow({
|
|
|
328
346
|
tooltipId={tooltipId}
|
|
329
347
|
>
|
|
330
348
|
<div className="relative">
|
|
349
|
+
{isZoomEnabled && (
|
|
350
|
+
<ZoomControls
|
|
351
|
+
zoomLevel={zoomLevel}
|
|
352
|
+
zoomIn={zoomIn}
|
|
353
|
+
zoomOut={zoomOut}
|
|
354
|
+
resetZoom={resetZoom}
|
|
355
|
+
portalRef={zoomControlsRef}
|
|
356
|
+
/>
|
|
357
|
+
)}
|
|
331
358
|
<ContextMenuWrapper
|
|
332
359
|
ref={contextMenuRef}
|
|
333
360
|
menuId={MENU_ID}
|
|
@@ -352,49 +379,81 @@ export const FlameGraphArrow = memo(function FlameGraphArrow({
|
|
|
352
379
|
)}
|
|
353
380
|
</div>
|
|
354
381
|
)}
|
|
382
|
+
{isZoomEnabled && (
|
|
383
|
+
<MiniMap
|
|
384
|
+
containerRef={containerRef}
|
|
385
|
+
table={table}
|
|
386
|
+
width={width ?? 0}
|
|
387
|
+
zoomedWidth={zoomedWidth}
|
|
388
|
+
totalHeight={totalHeight}
|
|
389
|
+
maxDepth={deferredEffectiveDepth}
|
|
390
|
+
colorByColors={colorByColors}
|
|
391
|
+
colorBy={colorByValue}
|
|
392
|
+
profileSource={profileSource}
|
|
393
|
+
isDarkMode={isDarkMode}
|
|
394
|
+
scrollLeft={viewport.scrollLeft}
|
|
395
|
+
/>
|
|
396
|
+
)}
|
|
355
397
|
<div
|
|
356
398
|
ref={containerRef}
|
|
357
|
-
className=
|
|
399
|
+
className={`${
|
|
400
|
+
isZoomEnabled ? '[scrollbar-width:none] [&::-webkit-scrollbar]:hidden' : ''
|
|
401
|
+
} will-change-transform webkit-overflow-scrolling-touch contain ${
|
|
402
|
+
!isZoomEnabled ? 'overflow-auto' : ''
|
|
403
|
+
}`}
|
|
358
404
|
style={{
|
|
359
405
|
width: width ?? '100%',
|
|
406
|
+
...(isZoomEnabled ? {overflowX: 'scroll' as const, overflowY: 'auto' as const} : {}),
|
|
360
407
|
contain: 'layout style paint',
|
|
361
408
|
visibility: !showSkeleton ? 'visible' : 'hidden',
|
|
362
409
|
}}
|
|
363
410
|
>
|
|
364
|
-
<
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
key={row}
|
|
374
|
-
table={table}
|
|
375
|
-
row={row}
|
|
376
|
-
colors={colorByColors}
|
|
377
|
-
colorBy={colorByValue}
|
|
378
|
-
totalWidth={width ?? 1}
|
|
379
|
-
height={RowHeight}
|
|
380
|
-
darkMode={isDarkMode}
|
|
381
|
-
compareMode={compareMode}
|
|
382
|
-
colorForSimilarNodes={colorForSimilarNodes}
|
|
383
|
-
selectedRow={selectedRow}
|
|
384
|
-
onClick={() => handleRowClick(row)}
|
|
385
|
-
onContextMenu={displayMenu}
|
|
386
|
-
hoveringRow={highlightSimilarStacksPreference ? hoveringRow : undefined}
|
|
387
|
-
setHoveringRow={highlightSimilarStacksPreference ? setHoveringRow : noop}
|
|
388
|
-
isFlameChart={isFlameChart}
|
|
389
|
-
profileSource={profileSource}
|
|
390
|
-
isRenderedAsFlamegraph={isRenderedAsFlamegraph}
|
|
391
|
-
isInSandwichView={isInSandwichView}
|
|
392
|
-
maxDepth={maxDepth}
|
|
393
|
-
effectiveDepth={deferredEffectiveDepth}
|
|
394
|
-
tooltipId={tooltipId}
|
|
411
|
+
<div>
|
|
412
|
+
{isFlameChart && (
|
|
413
|
+
<TimelineGuide
|
|
414
|
+
bounds={boundsFromProfileSource(profileSource)}
|
|
415
|
+
width={zoomedWidth}
|
|
416
|
+
height={totalHeight}
|
|
417
|
+
margin={0}
|
|
418
|
+
ticks={12}
|
|
419
|
+
timeUnit="nanoseconds"
|
|
395
420
|
/>
|
|
396
|
-
)
|
|
397
|
-
|
|
421
|
+
)}
|
|
422
|
+
<svg
|
|
423
|
+
className="relative font-robotoMono"
|
|
424
|
+
width={zoomedWidth}
|
|
425
|
+
height={totalHeight}
|
|
426
|
+
preserveAspectRatio="xMinYMid"
|
|
427
|
+
ref={svg}
|
|
428
|
+
>
|
|
429
|
+
{batchedNodes.map(row => (
|
|
430
|
+
<FlameNode
|
|
431
|
+
key={row}
|
|
432
|
+
table={table}
|
|
433
|
+
row={row}
|
|
434
|
+
colors={colorByColors}
|
|
435
|
+
colorBy={colorByValue}
|
|
436
|
+
totalWidth={zoomedWidth}
|
|
437
|
+
height={RowHeight}
|
|
438
|
+
darkMode={isDarkMode}
|
|
439
|
+
compareMode={compareMode}
|
|
440
|
+
colorForSimilarNodes={colorForSimilarNodes}
|
|
441
|
+
selectedRow={selectedRow}
|
|
442
|
+
onClick={() => handleRowClick(row)}
|
|
443
|
+
onContextMenu={displayMenu}
|
|
444
|
+
hoveringRow={highlightSimilarStacksPreference ? hoveringRow : undefined}
|
|
445
|
+
setHoveringRow={highlightSimilarStacksPreference ? setHoveringRow : noop}
|
|
446
|
+
isFlameChart={isFlameChart}
|
|
447
|
+
profileSource={profileSource}
|
|
448
|
+
isRenderedAsFlamegraph={isRenderedAsFlamegraph}
|
|
449
|
+
isInSandwichView={isInSandwichView}
|
|
450
|
+
maxDepth={maxDepth}
|
|
451
|
+
effectiveDepth={deferredEffectiveDepth}
|
|
452
|
+
tooltipId={tooltipId}
|
|
453
|
+
/>
|
|
454
|
+
))}
|
|
455
|
+
</svg>
|
|
456
|
+
</div>
|
|
398
457
|
</div>
|
|
399
458
|
</div>
|
|
400
459
|
</TooltipProvider>
|
|
@@ -0,0 +1,116 @@
|
|
|
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 {useCallback, useEffect, useRef, useState} from 'react';
|
|
15
|
+
|
|
16
|
+
import {flushSync} from 'react-dom';
|
|
17
|
+
|
|
18
|
+
const MIN_ZOOM = 1.0;
|
|
19
|
+
const MAX_ZOOM = 20.0;
|
|
20
|
+
const BUTTON_ZOOM_STEP = 1.5;
|
|
21
|
+
// Sensitivity for trackpad/wheel zoom - smaller = smoother
|
|
22
|
+
const WHEEL_ZOOM_SENSITIVITY = 0.01;
|
|
23
|
+
|
|
24
|
+
interface UseZoomResult {
|
|
25
|
+
zoomLevel: number;
|
|
26
|
+
zoomIn: () => void;
|
|
27
|
+
zoomOut: () => void;
|
|
28
|
+
resetZoom: () => void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const clampZoom = (zoom: number): number => {
|
|
32
|
+
return Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, zoom));
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const useZoom = (containerRef: React.RefObject<HTMLDivElement | null>): UseZoomResult => {
|
|
36
|
+
const [zoomLevel, setZoomLevel] = useState(MIN_ZOOM);
|
|
37
|
+
const zoomLevelRef = useRef(MIN_ZOOM);
|
|
38
|
+
|
|
39
|
+
// Adjust scrollLeft so the content under focalX stays fixed after zoom change.
|
|
40
|
+
const adjustScroll = useCallback(
|
|
41
|
+
(oldZoom: number, newZoom: number, focalX: number) => {
|
|
42
|
+
const container = containerRef.current;
|
|
43
|
+
if (container === null) return;
|
|
44
|
+
|
|
45
|
+
const contentX = container.scrollLeft + focalX;
|
|
46
|
+
const ratio = contentX / oldZoom;
|
|
47
|
+
container.scrollLeft = ratio * newZoom - focalX;
|
|
48
|
+
},
|
|
49
|
+
[containerRef]
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
// Apply a new zoom level around a focal point
|
|
53
|
+
const applyZoom = useCallback(
|
|
54
|
+
(newZoom: number, focalX: number) => {
|
|
55
|
+
const oldZoom = zoomLevelRef.current;
|
|
56
|
+
if (newZoom === oldZoom) return;
|
|
57
|
+
zoomLevelRef.current = newZoom;
|
|
58
|
+
|
|
59
|
+
// flushSync ensures the DOM updates with the new content width before adjustScroll reads it
|
|
60
|
+
flushSync(() => setZoomLevel(newZoom));
|
|
61
|
+
adjustScroll(oldZoom, newZoom, focalX);
|
|
62
|
+
},
|
|
63
|
+
[adjustScroll]
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const zoomIn = useCallback(() => {
|
|
67
|
+
const newZoom = clampZoom(zoomLevelRef.current * BUTTON_ZOOM_STEP);
|
|
68
|
+
const container = containerRef.current;
|
|
69
|
+
applyZoom(newZoom, container !== null ? container.clientWidth / 2 : 0);
|
|
70
|
+
}, [containerRef, applyZoom]);
|
|
71
|
+
|
|
72
|
+
const zoomOut = useCallback(() => {
|
|
73
|
+
const newZoom = clampZoom(zoomLevelRef.current / BUTTON_ZOOM_STEP);
|
|
74
|
+
const container = containerRef.current;
|
|
75
|
+
applyZoom(newZoom, container !== null ? container.clientWidth / 2 : 0);
|
|
76
|
+
}, [containerRef, applyZoom]);
|
|
77
|
+
|
|
78
|
+
const resetZoom = useCallback(() => {
|
|
79
|
+
zoomLevelRef.current = MIN_ZOOM;
|
|
80
|
+
setZoomLevel(MIN_ZOOM);
|
|
81
|
+
const container = containerRef.current;
|
|
82
|
+
if (container !== null) {
|
|
83
|
+
container.scrollLeft = 0;
|
|
84
|
+
}
|
|
85
|
+
}, [containerRef]);
|
|
86
|
+
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
const container = containerRef.current;
|
|
89
|
+
if (container === null) return;
|
|
90
|
+
|
|
91
|
+
const handleWheel = (e: WheelEvent): void => {
|
|
92
|
+
if (!e.ctrlKey && !e.metaKey) return;
|
|
93
|
+
e.preventDefault();
|
|
94
|
+
|
|
95
|
+
let delta = e.deltaY;
|
|
96
|
+
if (e.deltaMode === 1) {
|
|
97
|
+
delta *= 20;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Limiting the max zoom step per event to 15%, so to fix the huge jumps in Linux OS.
|
|
101
|
+
const MAX_FACTOR = 0.15;
|
|
102
|
+
const rawFactor = -delta * WHEEL_ZOOM_SENSITIVITY;
|
|
103
|
+
const zoomFactor = 1 + Math.max(-MAX_FACTOR, Math.min(MAX_FACTOR, rawFactor));
|
|
104
|
+
|
|
105
|
+
const newZoom = clampZoom(zoomLevelRef.current * zoomFactor);
|
|
106
|
+
applyZoom(newZoom, e.clientX - container.getBoundingClientRect().left);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
container.addEventListener('wheel', handleWheel, {passive: false});
|
|
110
|
+
return () => {
|
|
111
|
+
container.removeEventListener('wheel', handleWheel);
|
|
112
|
+
};
|
|
113
|
+
}, [containerRef, applyZoom]);
|
|
114
|
+
|
|
115
|
+
return {zoomLevel, zoomIn, zoomOut, resetZoom};
|
|
116
|
+
};
|
|
@@ -33,9 +33,8 @@ import DiffLegend from '../ProfileView/components/DiffLegend';
|
|
|
33
33
|
import {useProfileViewContext} from '../ProfileView/context/ProfileViewContext';
|
|
34
34
|
import {useProfileMetadata} from '../ProfileView/hooks/useProfileMetadata';
|
|
35
35
|
import {useVisualizationState} from '../ProfileView/hooks/useVisualizationState';
|
|
36
|
-
import {TimelineGuide} from '../TimelineGuide';
|
|
37
36
|
import {FlameGraphArrow} from './FlameGraphArrow';
|
|
38
|
-
import {CurrentPathFrame
|
|
37
|
+
import {CurrentPathFrame} from './FlameGraphArrow/utils';
|
|
39
38
|
|
|
40
39
|
const numberFormatter = new Intl.NumberFormat('en-US');
|
|
41
40
|
|
|
@@ -62,6 +61,7 @@ interface ProfileFlameGraphProps {
|
|
|
62
61
|
tooltipId?: string;
|
|
63
62
|
maxFrameCount?: number;
|
|
64
63
|
isExpanded?: boolean;
|
|
64
|
+
zoomControlsRef?: React.RefObject<HTMLDivElement | null>;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
const ErrorContent = ({errorMessage}: {errorMessage: string | ReactNode}): JSX.Element => {
|
|
@@ -101,11 +101,12 @@ const ProfileFlameGraph = function ProfileFlameGraphNonMemo({
|
|
|
101
101
|
maxFrameCount,
|
|
102
102
|
isExpanded = false,
|
|
103
103
|
metadataLoading = false,
|
|
104
|
+
zoomControlsRef,
|
|
104
105
|
}: ProfileFlameGraphProps): JSX.Element {
|
|
105
106
|
const {onError, authenticationErrorMessage, isDarkMode, flamechartHelpText} = useParcaContext();
|
|
106
107
|
const {compareMode} = useProfileViewContext();
|
|
107
108
|
const [isLoading, setIsLoading] = useState<boolean>(true);
|
|
108
|
-
const [flameChartRef
|
|
109
|
+
const [flameChartRef] = useMeasure();
|
|
109
110
|
const {colorBy, setColorBy} = useVisualizationState();
|
|
110
111
|
|
|
111
112
|
// Create local state for paths when in sandwich view to avoid URL updates
|
|
@@ -263,16 +264,6 @@ const ProfileFlameGraph = function ProfileFlameGraphNonMemo({
|
|
|
263
264
|
if (arrow !== undefined) {
|
|
264
265
|
return (
|
|
265
266
|
<div className="relative">
|
|
266
|
-
{isFlameChart ? (
|
|
267
|
-
<TimelineGuide
|
|
268
|
-
bounds={boundsFromProfileSource(profileSource)}
|
|
269
|
-
width={width}
|
|
270
|
-
height={flameChartHeight ?? 420}
|
|
271
|
-
margin={0}
|
|
272
|
-
ticks={12}
|
|
273
|
-
timeUnit="nanoseconds"
|
|
274
|
-
/>
|
|
275
|
-
) : null}
|
|
276
267
|
<div ref={flameChartRef as LegacyRef<HTMLDivElement>}>
|
|
277
268
|
<FlameGraphArrow
|
|
278
269
|
width={width}
|
|
@@ -294,6 +285,7 @@ const ProfileFlameGraph = function ProfileFlameGraphNonMemo({
|
|
|
294
285
|
maxFrameCount={maxFrameCount}
|
|
295
286
|
isExpanded={isExpanded}
|
|
296
287
|
colorBy={colorBy}
|
|
288
|
+
zoomControlsRef={zoomControlsRef}
|
|
297
289
|
/>
|
|
298
290
|
</div>
|
|
299
291
|
</div>
|
|
@@ -312,7 +304,6 @@ const ProfileFlameGraph = function ProfileFlameGraphNonMemo({
|
|
|
312
304
|
isCompareAbsolute,
|
|
313
305
|
isFlameChart,
|
|
314
306
|
profileSource,
|
|
315
|
-
flameChartHeight,
|
|
316
307
|
flameChartRef,
|
|
317
308
|
flamechartHelpText,
|
|
318
309
|
isRenderedAsFlamegraph,
|
|
@@ -325,6 +316,7 @@ const ProfileFlameGraph = function ProfileFlameGraphNonMemo({
|
|
|
325
316
|
mappingsList,
|
|
326
317
|
filenamesList,
|
|
327
318
|
colorBy,
|
|
319
|
+
zoomControlsRef,
|
|
328
320
|
]);
|
|
329
321
|
|
|
330
322
|
useEffect(() => {
|
|
@@ -29,6 +29,7 @@ interface Props {
|
|
|
29
29
|
querySelection: QuerySelection;
|
|
30
30
|
navigateTo: NavigateFunction;
|
|
31
31
|
loading: boolean;
|
|
32
|
+
defaultProfileType?: string;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
export const useAutoQuerySelector = ({
|
|
@@ -39,6 +40,7 @@ export const useAutoQuerySelector = ({
|
|
|
39
40
|
querySelection,
|
|
40
41
|
navigateTo,
|
|
41
42
|
loading,
|
|
43
|
+
defaultProfileType,
|
|
42
44
|
}: Props): void => {
|
|
43
45
|
const autoQuery = useAppSelector(selectAutoQuery);
|
|
44
46
|
const dispatch = useAppDispatch();
|
|
@@ -136,6 +138,12 @@ export const useAutoQuerySelector = ({
|
|
|
136
138
|
return;
|
|
137
139
|
}
|
|
138
140
|
dispatch(setAutoQuery('true'));
|
|
141
|
+
|
|
142
|
+
if (defaultProfileType != null && defaultProfileType.length > 0) {
|
|
143
|
+
setProfileName(defaultProfileType);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
139
147
|
let profileType = profileTypesData.types.find(
|
|
140
148
|
type => type.name === 'parca_agent' && type.sampleType === 'samples' && type.delta
|
|
141
149
|
);
|
|
@@ -166,6 +174,7 @@ export const useAutoQuerySelector = ({
|
|
|
166
174
|
dispatch,
|
|
167
175
|
setQueryExpression,
|
|
168
176
|
setProfileName,
|
|
177
|
+
defaultProfileType,
|
|
169
178
|
]);
|
|
170
179
|
|
|
171
180
|
useEffect(() => {
|
|
@@ -49,8 +49,8 @@ export const TimelineGuide = ({
|
|
|
49
49
|
|
|
50
50
|
return (
|
|
51
51
|
<div className="relative h-5">
|
|
52
|
-
<div className="absolute" style={{width, height}}>
|
|
53
|
-
<svg style={{width: '100%', height: '100%'}}
|
|
52
|
+
<div className="pointer-events-none absolute" style={{width, height}}>
|
|
53
|
+
<svg style={{width: '100%', height: '100%'}}>
|
|
54
54
|
<g
|
|
55
55
|
className="x axis"
|
|
56
56
|
fill="none"
|