@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
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.19.124](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.123...@parca/profile@0.19.124) (2026-02-18)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @parca/profile
|
|
9
|
+
|
|
10
|
+
## [0.19.123](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.122...@parca/profile@0.19.123) (2026-02-16)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @parca/profile
|
|
13
|
+
|
|
6
14
|
## [0.19.122](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.121...@parca/profile@0.19.122) (2026-02-13)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @parca/profile
|
|
@@ -81,7 +81,7 @@ const ZoomWindow = ({ zoomWindow, onZoomWindowChange, setIsHoveringDragHandle, }
|
|
|
81
81
|
height: '100%',
|
|
82
82
|
width: zoomWindowState[1] - zoomWindowState[0],
|
|
83
83
|
left: zoomWindowState[0],
|
|
84
|
-
}, className: cx('bg-gray-500/50 dark:bg-gray-
|
|
84
|
+
}, className: cx('bg-gray-500/50 dark:bg-gray-400/90 absolute top-0 border-x-2 border-gray-900 dark:border-gray-100 z-20'), children: [_jsx("div", { className: "w-3 h-4 absolute top-0 left-[-7px] rounded-b bg-gray-200 dark:bg-gray-600 cursor-ew-resize flex justify-center z-30", onMouseDown: e => {
|
|
85
85
|
setDraggingStart(true);
|
|
86
86
|
e.stopPropagation();
|
|
87
87
|
e.preventDefault();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileFlameChart/index.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAoC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAQpF,OAAO,EAAwB,WAAW,EAAQ,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileFlameChart/index.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAoC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAQpF,OAAO,EAAwB,WAAW,EAAQ,MAAM,eAAe,CAAC;AAKxE,OAAO,EAAsB,aAAa,EAAC,MAAM,kBAAkB,CAAC;AACpE,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,oCAAoC,CAAC;AA4CpE,UAAU,sBAAsB;IAC9B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,WAAW,EAAE,kBAAkB,CAAC;IAChC,aAAa,EAAE,aAAa,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,EAAE,OAAO,CAAC;IACtB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;CAClC;AA+BD,eAAO,MAAM,iBAAiB,GAAI,6JAY/B,sBAAsB,KAAG,GAAG,CAAC,OAqM/B,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
|
@@ -15,6 +15,7 @@ import { useEffect, useMemo, useRef } from 'react';
|
|
|
15
15
|
import { QueryRequest_ReportType } from '@parca/client';
|
|
16
16
|
import { Button, useParcaContext, useURLState, useURLStateCustom, } from '@parca/components';
|
|
17
17
|
import { Matcher, MatcherTypes, Query } from '@parca/parser';
|
|
18
|
+
import { TimeUnits, formatDateTimeDownToMS, formatDuration } from '@parca/utilities';
|
|
18
19
|
import ProfileFlameGraph, { validateFlameChartQuery } from '../ProfileFlameGraph';
|
|
19
20
|
import { boundsFromProfileSource } from '../ProfileFlameGraph/FlameGraphArrow/utils';
|
|
20
21
|
import { MergedProfileSource } from '../ProfileSource';
|
|
@@ -71,6 +72,7 @@ const createFilteredProfileSource = (profileSource, selectedTimeframe) => {
|
|
|
71
72
|
};
|
|
72
73
|
export const ProfileFlameChart = ({ samplesData, queryClient, profileSource, width, total, filtered, profileType, isHalfScreen, metadataMappingFiles, metadataLoading, onSwitchToOneMinute, }) => {
|
|
73
74
|
const { loader } = useParcaContext();
|
|
75
|
+
const zoomControlsRef = useRef(null);
|
|
74
76
|
const [selectedTimeframe, setSelectedTimeframe] = useURLStateCustom('flamechart_timeframe', TimeframeStateSerializer);
|
|
75
77
|
// Read flamechart dimension from URL state to detect changes
|
|
76
78
|
const [flamechartDimension] = useURLState('flamechart_dimension', {
|
|
@@ -150,6 +152,14 @@ export const ProfileFlameChart = ({ samplesData, queryClient, profileSource, wid
|
|
|
150
152
|
if (samplesData?.loading === true) {
|
|
151
153
|
return _jsx(_Fragment, { children: loader });
|
|
152
154
|
}
|
|
153
|
-
return (_jsxs("div", { children: [stripsData.cpus.length > 0 && stripsData.data.length > 0 && (_jsx("div", { className: "mb-2", children: _jsx(SamplesStrip, { cpus: stripsData.cpus, data: stripsData.data, selectedTimeframe: selectedTimeframe, onSelectedTimeframe: handleSelectedTimeframe, width: width, bounds: [Number(timeBounds[0] / 1000000n), Number(timeBounds[1] / 1000000n)], stepMs: stripsData.stepMs }) })), selectedTimeframe != null &&
|
|
155
|
+
return (_jsxs("div", { children: [stripsData.cpus.length > 0 && stripsData.data.length > 0 && (_jsx("div", { className: "mb-2", children: _jsx(SamplesStrip, { cpus: stripsData.cpus, data: stripsData.data, selectedTimeframe: selectedTimeframe, onSelectedTimeframe: handleSelectedTimeframe, width: width, bounds: [Number(timeBounds[0] / 1000000n), Number(timeBounds[1] / 1000000n)], stepMs: stripsData.stepMs }) })), selectedTimeframe != null &&
|
|
156
|
+
(() => {
|
|
157
|
+
const labels = selectedTimeframe.labels.labels
|
|
158
|
+
.map(l => `${l.name} = ${l.value}`)
|
|
159
|
+
.join(', ');
|
|
160
|
+
const durationMs = selectedTimeframe.bounds[1] - selectedTimeframe.bounds[0];
|
|
161
|
+
const duration = formatDuration({ [TimeUnits.Milliseconds]: durationMs });
|
|
162
|
+
return (_jsxs("div", { className: "flex items-center justify-between px-2 py-1", children: [_jsxs("div", { className: "text-xs font-medium text-gray-500 dark:text-gray-400", children: ["Samples matching ", labels, " over ", duration, " from", ' ', formatDateTimeDownToMS(selectedTimeframe.bounds[0]), " to", ' ', formatDateTimeDownToMS(selectedTimeframe.bounds[1])] }), _jsx("div", { ref: zoomControlsRef })] }));
|
|
163
|
+
})(), selectedTimeframe != null && filteredProfileSource != null ? (_jsx(ProfileFlameGraph, { arrow: flamechartArrow, loading: flamechartLoading, error: flamechartError, profileSource: filteredProfileSource, width: width, total: flamechartTotal, filtered: flamechartFiltered, profileType: profileType, isHalfScreen: isHalfScreen, metadataMappingFiles: metadataMappingFiles, metadataLoading: metadataLoading, isFlameChart: true, curPathArrow: [], setNewCurPathArrow: () => { }, zoomControlsRef: zoomControlsRef })) : (_jsx("div", { className: "flex justify-center items-center py-10 text-gray-500 dark:text-gray-400 text-sm", children: "Select a time range in the samples strips above to view the flamechart." }))] }));
|
|
154
164
|
};
|
|
155
165
|
export default ProfileFlameChart;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Table } from '@uwdata/flechette';
|
|
3
|
+
import { ProfileSource } from '../../ProfileSource';
|
|
4
|
+
import { type colorByColors } from './FlameGraphNodes';
|
|
5
|
+
interface MiniMapProps {
|
|
6
|
+
containerRef: React.RefObject<HTMLDivElement | null>;
|
|
7
|
+
table: Table;
|
|
8
|
+
width: number;
|
|
9
|
+
zoomedWidth: number;
|
|
10
|
+
totalHeight: number;
|
|
11
|
+
maxDepth: number;
|
|
12
|
+
colorByColors: colorByColors;
|
|
13
|
+
colorBy: string;
|
|
14
|
+
profileSource: ProfileSource;
|
|
15
|
+
isDarkMode: boolean;
|
|
16
|
+
scrollLeft: number;
|
|
17
|
+
}
|
|
18
|
+
export declare const MiniMap: React.NamedExoticComponent<MiniMapProps>;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=MiniMap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MiniMap.d.ts","sourceRoot":"","sources":["../../../src/ProfileFlameGraph/FlameGraphArrow/MiniMap.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAE5D,OAAO,EAAC,KAAK,EAAC,MAAM,mBAAmB,CAAC;AAKxC,OAAO,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAY,KAAK,aAAa,EAAC,MAAM,mBAAmB,CAAC;AAYhE,UAAU,YAAY;IACpB,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IACrD,KAAK,EAAE,KAAK,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,aAAa,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,aAAa,CAAC;IAC7B,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,OAAO,0CA8NlB,CAAC"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// Copyright 2022 The Parca Authors
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
import React, { useCallback, useEffect, useRef } from 'react';
|
|
15
|
+
import { EVERYTHING_ELSE } from '@parca/store';
|
|
16
|
+
import { getLastItem } from '@parca/utilities';
|
|
17
|
+
import { RowHeight } from './FlameGraphNodes';
|
|
18
|
+
import { FIELD_CUMULATIVE, FIELD_DEPTH, FIELD_FUNCTION_FILE_NAME, FIELD_MAPPING_FILE, FIELD_TIMESTAMP, } from './index';
|
|
19
|
+
import { arrowToString, boundsFromProfileSource } from './utils';
|
|
20
|
+
const MINIMAP_HEIGHT = 20;
|
|
21
|
+
export const MiniMap = React.memo(function MiniMap({ containerRef, table, width, zoomedWidth, totalHeight, maxDepth, colorByColors: colors, colorBy, profileSource, isDarkMode, scrollLeft, }) {
|
|
22
|
+
const canvasRef = useRef(null);
|
|
23
|
+
const containerElRef = useRef(null);
|
|
24
|
+
const isDragging = useRef(false);
|
|
25
|
+
const dragStartX = useRef(0);
|
|
26
|
+
const dragStartScrollLeft = useRef(0);
|
|
27
|
+
// Render minimap canvas
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
const canvas = canvasRef.current;
|
|
30
|
+
if (canvas == null || width <= 0 || zoomedWidth <= 0)
|
|
31
|
+
return;
|
|
32
|
+
const dpr = window.devicePixelRatio !== 0 ? window.devicePixelRatio : 1;
|
|
33
|
+
canvas.width = width * dpr;
|
|
34
|
+
canvas.height = MINIMAP_HEIGHT * dpr;
|
|
35
|
+
const ctx = canvas.getContext('2d');
|
|
36
|
+
if (ctx == null)
|
|
37
|
+
return;
|
|
38
|
+
ctx.scale(dpr, dpr);
|
|
39
|
+
ctx.clearRect(0, 0, width, MINIMAP_HEIGHT);
|
|
40
|
+
// Background
|
|
41
|
+
ctx.fillStyle = isDarkMode ? '#374151' : '#f3f4f6';
|
|
42
|
+
ctx.fillRect(0, 0, width, MINIMAP_HEIGHT);
|
|
43
|
+
const xScale = width / zoomedWidth;
|
|
44
|
+
const yScale = MINIMAP_HEIGHT / totalHeight;
|
|
45
|
+
const tsBounds = boundsFromProfileSource(profileSource);
|
|
46
|
+
const tsRange = Number(tsBounds[1]) - Number(tsBounds[0]);
|
|
47
|
+
if (tsRange <= 0)
|
|
48
|
+
return;
|
|
49
|
+
const depthCol = table.getChild(FIELD_DEPTH);
|
|
50
|
+
const cumulativeCol = table.getChild(FIELD_CUMULATIVE);
|
|
51
|
+
const tsCol = table.getChild(FIELD_TIMESTAMP);
|
|
52
|
+
const mappingCol = table.getChild(FIELD_MAPPING_FILE);
|
|
53
|
+
const filenameCol = table.getChild(FIELD_FUNCTION_FILE_NAME);
|
|
54
|
+
if (depthCol == null || cumulativeCol == null)
|
|
55
|
+
return;
|
|
56
|
+
const numRows = table.numRows;
|
|
57
|
+
for (let row = 0; row < numRows; row++) {
|
|
58
|
+
const depth = depthCol.get(row) ?? 0;
|
|
59
|
+
if (depth === 0)
|
|
60
|
+
continue; // skip root
|
|
61
|
+
if (depth > maxDepth)
|
|
62
|
+
continue;
|
|
63
|
+
const cumulative = Number(cumulativeCol.get(row) ?? 0n);
|
|
64
|
+
if (cumulative <= 0)
|
|
65
|
+
continue;
|
|
66
|
+
const nodeWidth = (cumulative / tsRange) * zoomedWidth * xScale;
|
|
67
|
+
if (nodeWidth < 0.5)
|
|
68
|
+
continue;
|
|
69
|
+
const ts = tsCol != null ? Number(tsCol.get(row)) : 0;
|
|
70
|
+
const x = ((ts - Number(tsBounds[0])) / tsRange) * zoomedWidth * xScale;
|
|
71
|
+
const y = (depth - 1) * RowHeight * yScale;
|
|
72
|
+
const h = Math.max(1, RowHeight * yScale);
|
|
73
|
+
// Get color using same logic as useNodeColor
|
|
74
|
+
const colorAttribute = colorBy === 'filename'
|
|
75
|
+
? arrowToString(filenameCol?.get(row))
|
|
76
|
+
: colorBy === 'binary'
|
|
77
|
+
? arrowToString(mappingCol?.get(row))
|
|
78
|
+
: null;
|
|
79
|
+
const color = colors[getLastItem(colorAttribute ?? '') ?? EVERYTHING_ELSE];
|
|
80
|
+
ctx.fillStyle = color ?? (isDarkMode ? '#6b7280' : '#9ca3af');
|
|
81
|
+
ctx.fillRect(x, y, Math.max(0.5, nodeWidth), h);
|
|
82
|
+
}
|
|
83
|
+
}, [
|
|
84
|
+
table,
|
|
85
|
+
width,
|
|
86
|
+
zoomedWidth,
|
|
87
|
+
totalHeight,
|
|
88
|
+
maxDepth,
|
|
89
|
+
colorBy,
|
|
90
|
+
colors,
|
|
91
|
+
isDarkMode,
|
|
92
|
+
profileSource,
|
|
93
|
+
]);
|
|
94
|
+
const isZoomed = zoomedWidth > width;
|
|
95
|
+
const sliderWidth = Math.max(20, (width / zoomedWidth) * width);
|
|
96
|
+
const sliderLeft = Math.min((scrollLeft / zoomedWidth) * width, width - sliderWidth);
|
|
97
|
+
const handleMouseDown = useCallback((e) => {
|
|
98
|
+
e.preventDefault();
|
|
99
|
+
const rect = containerElRef.current?.getBoundingClientRect();
|
|
100
|
+
if (rect == null)
|
|
101
|
+
return;
|
|
102
|
+
const clickX = e.clientX - rect.left;
|
|
103
|
+
// Check if clicking inside the slider
|
|
104
|
+
if (clickX >= sliderLeft && clickX <= sliderLeft + sliderWidth) {
|
|
105
|
+
// Start dragging
|
|
106
|
+
isDragging.current = true;
|
|
107
|
+
dragStartX.current = e.clientX;
|
|
108
|
+
dragStartScrollLeft.current = scrollLeft;
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
// Click-to-jump: center viewport at click position
|
|
112
|
+
const targetCenter = (clickX / width) * zoomedWidth;
|
|
113
|
+
const containerWidth = containerRef.current?.clientWidth ?? width;
|
|
114
|
+
const newScrollLeft = targetCenter - containerWidth / 2;
|
|
115
|
+
if (containerRef.current != null) {
|
|
116
|
+
containerRef.current.scrollLeft = Math.max(0, Math.min(newScrollLeft, zoomedWidth - containerWidth));
|
|
117
|
+
}
|
|
118
|
+
// Also start dragging from new position
|
|
119
|
+
isDragging.current = true;
|
|
120
|
+
dragStartX.current = e.clientX;
|
|
121
|
+
dragStartScrollLeft.current = containerRef.current?.scrollLeft ?? 0;
|
|
122
|
+
}
|
|
123
|
+
const handleMouseMove = (moveEvent) => {
|
|
124
|
+
if (!isDragging.current)
|
|
125
|
+
return;
|
|
126
|
+
const delta = moveEvent.clientX - dragStartX.current;
|
|
127
|
+
const scrollDelta = delta * (zoomedWidth / width);
|
|
128
|
+
const containerWidth = containerRef.current?.clientWidth ?? width;
|
|
129
|
+
if (containerRef.current != null) {
|
|
130
|
+
containerRef.current.scrollLeft = Math.max(0, Math.min(dragStartScrollLeft.current + scrollDelta, zoomedWidth - containerWidth));
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
const handleMouseUp = () => {
|
|
134
|
+
isDragging.current = false;
|
|
135
|
+
document.removeEventListener('mousemove', handleMouseMove);
|
|
136
|
+
document.removeEventListener('mouseup', handleMouseUp);
|
|
137
|
+
};
|
|
138
|
+
document.addEventListener('mousemove', handleMouseMove);
|
|
139
|
+
document.addEventListener('mouseup', handleMouseUp);
|
|
140
|
+
}, [sliderLeft, sliderWidth, scrollLeft, width, zoomedWidth, containerRef]);
|
|
141
|
+
// Forward wheel events to the container so zoom (Ctrl+scroll) works on the minimap
|
|
142
|
+
useEffect(() => {
|
|
143
|
+
const el = containerElRef.current;
|
|
144
|
+
if (el == null)
|
|
145
|
+
return;
|
|
146
|
+
const handleWheel = (e) => {
|
|
147
|
+
if (!e.ctrlKey && !e.metaKey)
|
|
148
|
+
return;
|
|
149
|
+
e.preventDefault();
|
|
150
|
+
containerRef.current?.dispatchEvent(new WheelEvent('wheel', {
|
|
151
|
+
deltaY: e.deltaY,
|
|
152
|
+
deltaX: e.deltaX,
|
|
153
|
+
ctrlKey: e.ctrlKey,
|
|
154
|
+
metaKey: e.metaKey,
|
|
155
|
+
clientX: e.clientX,
|
|
156
|
+
clientY: e.clientY,
|
|
157
|
+
bubbles: true,
|
|
158
|
+
}));
|
|
159
|
+
};
|
|
160
|
+
el.addEventListener('wheel', handleWheel, { passive: false });
|
|
161
|
+
return () => {
|
|
162
|
+
el.removeEventListener('wheel', handleWheel);
|
|
163
|
+
};
|
|
164
|
+
}, [containerRef]);
|
|
165
|
+
if (width <= 0)
|
|
166
|
+
return null;
|
|
167
|
+
return (_jsxs("div", { ref: containerElRef, className: "relative select-none", style: { width, height: MINIMAP_HEIGHT, cursor: isZoomed ? 'pointer' : 'default' }, onMouseDown: isZoomed ? handleMouseDown : undefined, children: [_jsx("canvas", { ref: canvasRef, style: {
|
|
168
|
+
width,
|
|
169
|
+
height: MINIMAP_HEIGHT,
|
|
170
|
+
display: 'block',
|
|
171
|
+
visibility: isZoomed ? 'visible' : 'hidden',
|
|
172
|
+
} }), isZoomed && (_jsxs(_Fragment, { children: [_jsx("div", { className: "absolute top-0 bottom-0 bg-black/30 dark:bg-black/50", style: { left: 0, width: Math.max(0, sliderLeft) } }), _jsx("div", { className: "absolute top-0 bottom-0 border-x-2 border-gray-500", style: { left: sliderLeft, width: sliderWidth } }), _jsx("div", { className: "absolute top-0 bottom-0 bg-black/30 dark:bg-black/50", style: { left: sliderLeft + sliderWidth, right: 0 } })] }))] }));
|
|
173
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface ZoomControlsProps {
|
|
3
|
+
zoomLevel: number;
|
|
4
|
+
zoomIn: () => void;
|
|
5
|
+
zoomOut: () => void;
|
|
6
|
+
resetZoom: () => void;
|
|
7
|
+
portalRef?: React.RefObject<HTMLDivElement | null>;
|
|
8
|
+
}
|
|
9
|
+
export declare const ZoomControls: ({ zoomLevel, zoomIn, zoomOut, resetZoom, portalRef, }: ZoomControlsProps) => React.JSX.Element;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=ZoomControls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ZoomControls.d.ts","sourceRoot":"","sources":["../../../src/ProfileFlameGraph/FlameGraphArrow/ZoomControls.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,UAAU,iBAAiB;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;CACpD;AAED,eAAO,MAAM,YAAY,GAAI,uDAM1B,iBAAiB,KAAG,KAAK,CAAC,GAAG,CAAC,OAkChC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Icon } from '@iconify/react';
|
|
3
|
+
import { createPortal } from 'react-dom';
|
|
4
|
+
export const ZoomControls = ({ zoomLevel, zoomIn, zoomOut, resetZoom, portalRef, }) => {
|
|
5
|
+
const controls = (_jsxs("div", { className: "flex items-center gap-1 rounded-md border border-gray-200 bg-white/90 px-1 py-0.5 shadow-sm backdrop-blur-sm dark:border-gray-600 dark:bg-gray-800/90", children: [_jsx("button", { onClick: zoomOut, disabled: zoomLevel <= 1, className: "rounded p-1 text-gray-600 hover:bg-gray-100 disabled:opacity-30 dark:text-gray-300 dark:hover:bg-gray-700", title: "Zoom out", children: _jsx(Icon, { icon: "mdi:minus", width: 16, height: 16 }) }), _jsxs("button", { onClick: resetZoom, className: "min-w-[3rem] px-1 text-center text-xs text-gray-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700 rounded", title: "Reset zoom", children: [Math.round(zoomLevel * 100), "%"] }), _jsx("button", { onClick: zoomIn, disabled: zoomLevel >= 20, className: "rounded p-1 text-gray-600 hover:bg-gray-100 disabled:opacity-30 dark:text-gray-300 dark:hover:bg-gray-700", title: "Zoom in", children: _jsx(Icon, { icon: "mdi:plus", width: 16, height: 16 }) })] }));
|
|
6
|
+
if (portalRef?.current != null) {
|
|
7
|
+
return createPortal(controls, portalRef.current);
|
|
8
|
+
}
|
|
9
|
+
return controls;
|
|
10
|
+
};
|
|
@@ -46,6 +46,7 @@ interface FlameGraphArrowProps {
|
|
|
46
46
|
tooltipId?: string;
|
|
47
47
|
maxFrameCount?: number;
|
|
48
48
|
isExpanded?: boolean;
|
|
49
|
+
zoomControlsRef?: React.RefObject<HTMLDivElement | null>;
|
|
49
50
|
}
|
|
50
51
|
export declare const getMappingColors: (mappingsList: string[], isDarkMode: boolean, currentColorProfile: ColorConfig) => colorByColors;
|
|
51
52
|
export declare const getFilenameColors: (filenamesList: string[], isDarkMode: boolean, currentColorProfile: ColorConfig) => colorByColors;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ProfileFlameGraph/FlameGraphArrow/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAQN,MAAM,OAAO,CAAC;AAKf,OAAO,EAAC,eAAe,EAAC,MAAM,eAAe,CAAC;AAG9C,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAC,KAAK,WAAW,EAAC,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ProfileFlameGraph/FlameGraphArrow/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAQN,MAAM,OAAO,CAAC;AAKf,OAAO,EAAC,eAAe,EAAC,MAAM,eAAe,CAAC;AAG9C,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAC,KAAK,WAAW,EAAC,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAMlD,OAAO,EAAuB,aAAa,EAAC,MAAM,mBAAmB,CAAC;AAStE,OAAO,EACL,gBAAgB,EAOjB,MAAM,SAAS,CAAC;AAEjB,eAAO,MAAM,iBAAiB,gBAAgB,CAAC;AAC/C,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AACjD,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AACzD,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AACzD,eAAO,MAAM,mBAAmB,kBAAkB,CAAC;AACnD,eAAO,MAAM,aAAa,YAAY,CAAC;AACvC,eAAO,MAAM,eAAe,cAAc,CAAC;AAC3C,eAAO,MAAM,cAAc,aAAa,CAAC;AACzC,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AACzD,eAAO,MAAM,mBAAmB,kBAAkB,CAAC;AACnD,eAAO,MAAM,0BAA0B,yBAAyB,CAAC;AACjE,eAAO,MAAM,wBAAwB,uBAAuB,CAAC;AAC7D,eAAO,MAAM,yBAAyB,uBAAuB,CAAC;AAC9D,eAAO,MAAM,cAAc,aAAa,CAAC;AACzC,eAAO,MAAM,YAAY,WAAW,CAAC;AACrC,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAC7C,eAAO,MAAM,UAAU,SAAS,CAAC;AACjC,eAAO,MAAM,UAAU,SAAS,CAAC;AACjC,eAAO,MAAM,YAAY,WAAW,CAAC;AACrC,eAAO,MAAM,WAAW,UAAU,CAAC;AACnC,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AAEjD,UAAU,oBAAoB;IAC5B,KAAK,EAAE,eAAe,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,aAAa,EAAE,aAAa,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,UAAU,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAC/C,YAAY,EAAE,OAAO,CAAC;IACtB,wBAAwB,EAAE,MAAM,EAAE,CAAC;IACnC,yBAAyB,EAAE,MAAM,EAAE,CAAC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;CAC1D;AAED,eAAO,MAAM,gBAAgB,GAC3B,cAAc,MAAM,EAAE,EACtB,YAAY,OAAO,EACnB,qBAAqB,WAAW,KAC/B,aAQF,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,eAAe,MAAM,EAAE,EACvB,YAAY,OAAO,EACnB,qBAAqB,WAAW,KAC/B,aAQF,CAAC;AAIF,eAAO,MAAM,eAAe,kDAuU1B,CAAC;AAEH,eAAe,eAAe,CAAC"}
|
|
@@ -16,18 +16,22 @@ import { tableFromIPC } from '@uwdata/flechette';
|
|
|
16
16
|
import { useContextMenu } from 'react-contexify';
|
|
17
17
|
import { FlameGraphSkeleton, SandwichFlameGraphSkeleton, useParcaContext } from '@parca/components';
|
|
18
18
|
import { USER_PREFERENCES, useCurrentColorProfile, useUserPreference } from '@parca/hooks';
|
|
19
|
-
import { getColorForFeature
|
|
19
|
+
import { getColorForFeature } from '@parca/store';
|
|
20
20
|
import { useProfileFilters } from '../../ProfileView/components/ProfileFilters/useProfileFilters';
|
|
21
21
|
import { useProfileViewContext } from '../../ProfileView/context/ProfileViewContext';
|
|
22
|
+
import { TimelineGuide } from '../../TimelineGuide';
|
|
22
23
|
import { alignedUint8Array } from '../../utils';
|
|
23
24
|
import ContextMenuWrapper from './ContextMenuWrapper';
|
|
24
25
|
import { FlameNode, RowHeight } from './FlameGraphNodes';
|
|
25
26
|
import { MemoizedTooltip } from './MemoizedTooltip';
|
|
27
|
+
import { MiniMap } from './MiniMap';
|
|
26
28
|
import { TooltipProvider } from './TooltipContext';
|
|
29
|
+
import { ZoomControls } from './ZoomControls';
|
|
27
30
|
import { useBatchedRendering } from './useBatchedRendering';
|
|
28
31
|
import { useScrollViewport } from './useScrollViewport';
|
|
29
32
|
import { useVisibleNodes } from './useVisibleNodes';
|
|
30
|
-
import {
|
|
33
|
+
import { useZoom } from './useZoom';
|
|
34
|
+
import { boundsFromProfileSource, extractFeature, extractFilenameFeature, getCurrentPathFrameData, getMaxDepth, isCurrentPathFrameMatch, } from './utils';
|
|
31
35
|
export const FIELD_LABELS_ONLY = 'labels_only';
|
|
32
36
|
export const FIELD_MAPPING_FILE = 'mapping_file';
|
|
33
37
|
export const FIELD_MAPPING_BUILD_ID = 'mapping_build_id';
|
|
@@ -66,12 +70,11 @@ export const getFilenameColors = (filenamesList, isDarkMode, currentColorProfile
|
|
|
66
70
|
return colors;
|
|
67
71
|
};
|
|
68
72
|
const noop = () => { };
|
|
69
|
-
export const FlameGraphArrow = memo(function FlameGraphArrow({ arrow, total, filtered, width, setCurPath, curPath, profileType, profileSource, compareAbsolute, isFlameChart = false, isRenderedAsFlamegraph = false, isInSandwichView = false, isHalfScreen, tooltipId = 'default', maxFrameCount, isExpanded = false, mappingsListFromMetadata, filenamesListFromMetadata, colorBy, }) {
|
|
73
|
+
export const FlameGraphArrow = memo(function FlameGraphArrow({ arrow, total, filtered, width, setCurPath, curPath, profileType, profileSource, compareAbsolute, isFlameChart = false, isRenderedAsFlamegraph = false, isInSandwichView = false, isHalfScreen, tooltipId = 'default', maxFrameCount, isExpanded = false, mappingsListFromMetadata, filenamesListFromMetadata, colorBy, zoomControlsRef, }) {
|
|
70
74
|
const [highlightSimilarStacksPreference] = useUserPreference(USER_PREFERENCES.HIGHLIGHT_SIMILAR_STACKS.key);
|
|
71
75
|
const [hoveringRow, setHoveringRow] = useState(undefined);
|
|
72
76
|
const [dockedMetainfo] = useUserPreference(USER_PREFERENCES.GRAPH_METAINFO_DOCKED.key);
|
|
73
|
-
const isDarkMode =
|
|
74
|
-
const { perf } = useParcaContext();
|
|
77
|
+
const { perf, isDarkMode } = useParcaContext();
|
|
75
78
|
const table = useMemo(() => {
|
|
76
79
|
const result = tableFromIPC(alignedUint8Array(arrow.record), { useBigInt: true });
|
|
77
80
|
if (perf?.setMeasurement != null) {
|
|
@@ -150,6 +153,13 @@ export const FlameGraphArrow = memo(function FlameGraphArrow({ arrow, total, fil
|
|
|
150
153
|
: (deferredEffectiveDepth + 1) * RowHeight;
|
|
151
154
|
// Get the viewport of the container, this is used to determine which rows are visible.
|
|
152
155
|
const viewport = useScrollViewport(containerRef);
|
|
156
|
+
const isZoomEnabled = isFlameChart;
|
|
157
|
+
const { zoomLevel, zoomIn, zoomOut, resetZoom } = useZoom(isZoomEnabled ? containerRef : { current: null });
|
|
158
|
+
const zoomedWidth = isZoomEnabled ? Math.round((width ?? 1) * zoomLevel) : width ?? 0;
|
|
159
|
+
// Reset zoom when the data changes (e.g. new query, different time range)
|
|
160
|
+
useEffect(() => {
|
|
161
|
+
resetZoom();
|
|
162
|
+
}, [table, resetZoom]);
|
|
153
163
|
// To find the selected row, we must walk the current path and look at which
|
|
154
164
|
// children of the current frame matches the path element exactly. Until the
|
|
155
165
|
// end, the row we find at the end is our selected row.
|
|
@@ -178,7 +188,7 @@ export const FlameGraphArrow = memo(function FlameGraphArrow({ arrow, total, fil
|
|
|
178
188
|
table,
|
|
179
189
|
viewport,
|
|
180
190
|
total,
|
|
181
|
-
width:
|
|
191
|
+
width: zoomedWidth,
|
|
182
192
|
selectedRow,
|
|
183
193
|
effectiveDepth: deferredEffectiveDepth,
|
|
184
194
|
});
|
|
@@ -199,10 +209,11 @@ export const FlameGraphArrow = memo(function FlameGraphArrow({ arrow, total, fil
|
|
|
199
209
|
useEffect(() => {
|
|
200
210
|
setSvgElement(svg.current);
|
|
201
211
|
}, [tooltipId]);
|
|
202
|
-
return (_jsx(TooltipProvider, { table: table, total: total, totalUnfiltered: total + filtered, profileType: profileType, unit: arrow.unit, compareAbsolute: compareAbsolute, tooltipId: tooltipId, children: _jsxs("div", { className: "relative", children: [_jsx(ContextMenuWrapper, { ref: contextMenuRef, menuId: MENU_ID, table: table, total: total, totalUnfiltered: total + filtered, compareAbsolute: compareAbsolute, resetPath: () => setCurPath([]), hideMenu: hideAll, hideBinary: hideBinary, unit: arrow.unit, profileType: profileType, isInSandwichView: isInSandwichView }), _jsx(MemoizedTooltip, { contextElement: svgElement, dockedMetainfo: dockedMetainfo }), showSkeleton && (_jsx("div", { className: "absolute inset-0 z-10", children: isRenderedAsFlamegraph ? (_jsx(SandwichFlameGraphSkeleton, { isHalfScreen: isHalfScreen, isDarkMode: isDarkMode })) : (_jsx(FlameGraphSkeleton, { isHalfScreen: isHalfScreen, isDarkMode: isDarkMode })) })), _jsx("div", { ref: containerRef, className:
|
|
212
|
+
return (_jsx(TooltipProvider, { table: table, total: total, totalUnfiltered: total + filtered, profileType: profileType, unit: arrow.unit, compareAbsolute: compareAbsolute, tooltipId: tooltipId, children: _jsxs("div", { className: "relative", children: [isZoomEnabled && (_jsx(ZoomControls, { zoomLevel: zoomLevel, zoomIn: zoomIn, zoomOut: zoomOut, resetZoom: resetZoom, portalRef: zoomControlsRef })), _jsx(ContextMenuWrapper, { ref: contextMenuRef, menuId: MENU_ID, table: table, total: total, totalUnfiltered: total + filtered, compareAbsolute: compareAbsolute, resetPath: () => setCurPath([]), hideMenu: hideAll, hideBinary: hideBinary, unit: arrow.unit, profileType: profileType, isInSandwichView: isInSandwichView }), _jsx(MemoizedTooltip, { contextElement: svgElement, dockedMetainfo: dockedMetainfo }), showSkeleton && (_jsx("div", { className: "absolute inset-0 z-10", children: isRenderedAsFlamegraph ? (_jsx(SandwichFlameGraphSkeleton, { isHalfScreen: isHalfScreen, isDarkMode: isDarkMode })) : (_jsx(FlameGraphSkeleton, { isHalfScreen: isHalfScreen, isDarkMode: isDarkMode })) })), isZoomEnabled && (_jsx(MiniMap, { containerRef: containerRef, table: table, width: width ?? 0, zoomedWidth: zoomedWidth, totalHeight: totalHeight, maxDepth: deferredEffectiveDepth, colorByColors: colorByColors, colorBy: colorByValue, profileSource: profileSource, isDarkMode: isDarkMode, scrollLeft: viewport.scrollLeft })), _jsx("div", { ref: containerRef, className: `${isZoomEnabled ? '[scrollbar-width:none] [&::-webkit-scrollbar]:hidden' : ''} will-change-transform webkit-overflow-scrolling-touch contain ${!isZoomEnabled ? 'overflow-auto' : ''}`, style: {
|
|
203
213
|
width: width ?? '100%',
|
|
214
|
+
...(isZoomEnabled ? { overflowX: 'scroll', overflowY: 'auto' } : {}),
|
|
204
215
|
contain: 'layout style paint',
|
|
205
216
|
visibility: !showSkeleton ? 'visible' : 'hidden',
|
|
206
|
-
}, children: _jsx("svg", { className: "font-robotoMono", width:
|
|
217
|
+
}, children: _jsxs("div", { children: [isFlameChart && (_jsx(TimelineGuide, { bounds: boundsFromProfileSource(profileSource), width: zoomedWidth, height: totalHeight, margin: 0, ticks: 12, timeUnit: "nanoseconds" })), _jsx("svg", { className: "relative font-robotoMono", width: zoomedWidth, height: totalHeight, preserveAspectRatio: "xMinYMid", ref: svg, children: batchedNodes.map(row => (_jsx(FlameNode, { table: table, row: row, colors: colorByColors, colorBy: colorByValue, totalWidth: zoomedWidth, height: RowHeight, darkMode: isDarkMode, compareMode: compareMode, colorForSimilarNodes: colorForSimilarNodes, selectedRow: selectedRow, onClick: () => handleRowClick(row), onContextMenu: displayMenu, hoveringRow: highlightSimilarStacksPreference ? hoveringRow : undefined, setHoveringRow: highlightSimilarStacksPreference ? setHoveringRow : noop, isFlameChart: isFlameChart, profileSource: profileSource, isRenderedAsFlamegraph: isRenderedAsFlamegraph, isInSandwichView: isInSandwichView, maxDepth: maxDepth, effectiveDepth: deferredEffectiveDepth, tooltipId: tooltipId }, row))) })] }) })] }) }));
|
|
207
218
|
});
|
|
208
219
|
export default FlameGraphArrow;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface UseZoomResult {
|
|
2
|
+
zoomLevel: number;
|
|
3
|
+
zoomIn: () => void;
|
|
4
|
+
zoomOut: () => void;
|
|
5
|
+
resetZoom: () => void;
|
|
6
|
+
}
|
|
7
|
+
export declare const useZoom: (containerRef: React.RefObject<HTMLDivElement | null>) => UseZoomResult;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=useZoom.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useZoom.d.ts","sourceRoot":"","sources":["../../../src/ProfileFlameGraph/FlameGraphArrow/useZoom.ts"],"names":[],"mappings":"AAuBA,UAAU,aAAa;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAMD,eAAO,MAAM,OAAO,GAAI,cAAc,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,KAAG,aAiF9E,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
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 { useCallback, useEffect, useRef, useState } from 'react';
|
|
14
|
+
import { flushSync } from 'react-dom';
|
|
15
|
+
const MIN_ZOOM = 1.0;
|
|
16
|
+
const MAX_ZOOM = 20.0;
|
|
17
|
+
const BUTTON_ZOOM_STEP = 1.5;
|
|
18
|
+
// Sensitivity for trackpad/wheel zoom - smaller = smoother
|
|
19
|
+
const WHEEL_ZOOM_SENSITIVITY = 0.01;
|
|
20
|
+
const clampZoom = (zoom) => {
|
|
21
|
+
return Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, zoom));
|
|
22
|
+
};
|
|
23
|
+
export const useZoom = (containerRef) => {
|
|
24
|
+
const [zoomLevel, setZoomLevel] = useState(MIN_ZOOM);
|
|
25
|
+
const zoomLevelRef = useRef(MIN_ZOOM);
|
|
26
|
+
// Adjust scrollLeft so the content under focalX stays fixed after zoom change.
|
|
27
|
+
const adjustScroll = useCallback((oldZoom, newZoom, focalX) => {
|
|
28
|
+
const container = containerRef.current;
|
|
29
|
+
if (container === null)
|
|
30
|
+
return;
|
|
31
|
+
const contentX = container.scrollLeft + focalX;
|
|
32
|
+
const ratio = contentX / oldZoom;
|
|
33
|
+
container.scrollLeft = ratio * newZoom - focalX;
|
|
34
|
+
}, [containerRef]);
|
|
35
|
+
// Apply a new zoom level around a focal point
|
|
36
|
+
const applyZoom = useCallback((newZoom, focalX) => {
|
|
37
|
+
const oldZoom = zoomLevelRef.current;
|
|
38
|
+
if (newZoom === oldZoom)
|
|
39
|
+
return;
|
|
40
|
+
zoomLevelRef.current = newZoom;
|
|
41
|
+
// flushSync ensures the DOM updates with the new content width before adjustScroll reads it
|
|
42
|
+
flushSync(() => setZoomLevel(newZoom));
|
|
43
|
+
adjustScroll(oldZoom, newZoom, focalX);
|
|
44
|
+
}, [adjustScroll]);
|
|
45
|
+
const zoomIn = useCallback(() => {
|
|
46
|
+
const newZoom = clampZoom(zoomLevelRef.current * BUTTON_ZOOM_STEP);
|
|
47
|
+
const container = containerRef.current;
|
|
48
|
+
applyZoom(newZoom, container !== null ? container.clientWidth / 2 : 0);
|
|
49
|
+
}, [containerRef, applyZoom]);
|
|
50
|
+
const zoomOut = useCallback(() => {
|
|
51
|
+
const newZoom = clampZoom(zoomLevelRef.current / BUTTON_ZOOM_STEP);
|
|
52
|
+
const container = containerRef.current;
|
|
53
|
+
applyZoom(newZoom, container !== null ? container.clientWidth / 2 : 0);
|
|
54
|
+
}, [containerRef, applyZoom]);
|
|
55
|
+
const resetZoom = useCallback(() => {
|
|
56
|
+
zoomLevelRef.current = MIN_ZOOM;
|
|
57
|
+
setZoomLevel(MIN_ZOOM);
|
|
58
|
+
const container = containerRef.current;
|
|
59
|
+
if (container !== null) {
|
|
60
|
+
container.scrollLeft = 0;
|
|
61
|
+
}
|
|
62
|
+
}, [containerRef]);
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
const container = containerRef.current;
|
|
65
|
+
if (container === null)
|
|
66
|
+
return;
|
|
67
|
+
const handleWheel = (e) => {
|
|
68
|
+
if (!e.ctrlKey && !e.metaKey)
|
|
69
|
+
return;
|
|
70
|
+
e.preventDefault();
|
|
71
|
+
let delta = e.deltaY;
|
|
72
|
+
if (e.deltaMode === 1) {
|
|
73
|
+
delta *= 20;
|
|
74
|
+
}
|
|
75
|
+
// Limiting the max zoom step per event to 15%, so to fix the huge jumps in Linux OS.
|
|
76
|
+
const MAX_FACTOR = 0.15;
|
|
77
|
+
const rawFactor = -delta * WHEEL_ZOOM_SENSITIVITY;
|
|
78
|
+
const zoomFactor = 1 + Math.max(-MAX_FACTOR, Math.min(MAX_FACTOR, rawFactor));
|
|
79
|
+
const newZoom = clampZoom(zoomLevelRef.current * zoomFactor);
|
|
80
|
+
applyZoom(newZoom, e.clientX - container.getBoundingClientRect().left);
|
|
81
|
+
};
|
|
82
|
+
container.addEventListener('wheel', handleWheel, { passive: false });
|
|
83
|
+
return () => {
|
|
84
|
+
container.removeEventListener('wheel', handleWheel);
|
|
85
|
+
};
|
|
86
|
+
}, [containerRef, applyZoom]);
|
|
87
|
+
return { zoomLevel, zoomIn, zoomOut, resetZoom };
|
|
88
|
+
};
|
|
@@ -25,12 +25,13 @@ interface ProfileFlameGraphProps {
|
|
|
25
25
|
tooltipId?: string;
|
|
26
26
|
maxFrameCount?: number;
|
|
27
27
|
isExpanded?: boolean;
|
|
28
|
+
zoomControlsRef?: React.RefObject<HTMLDivElement | null>;
|
|
28
29
|
}
|
|
29
30
|
export declare const validateFlameChartQuery: (profileSource: MergedProfileSource) => {
|
|
30
31
|
isValid: boolean;
|
|
31
32
|
isNonDelta: boolean;
|
|
32
33
|
isDurationTooLong: boolean;
|
|
33
34
|
};
|
|
34
|
-
declare const ProfileFlameGraph: ({ arrow, total, filtered, curPathArrow, setNewCurPathArrow, profileType, loading, error, width, isHalfScreen, metadataMappingFiles, isFlameChart, profileSource, isInSandwichView, isRenderedAsFlamegraph, tooltipId, maxFrameCount, isExpanded, metadataLoading, }: ProfileFlameGraphProps) => JSX.Element;
|
|
35
|
+
declare const ProfileFlameGraph: ({ arrow, total, filtered, curPathArrow, setNewCurPathArrow, profileType, loading, error, width, isHalfScreen, metadataMappingFiles, isFlameChart, profileSource, isInSandwichView, isRenderedAsFlamegraph, tooltipId, maxFrameCount, isExpanded, metadataLoading, zoomControlsRef, }: ProfileFlameGraphProps) => JSX.Element;
|
|
35
36
|
export default ProfileFlameGraph;
|
|
36
37
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileFlameGraph/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAwE,MAAM,OAAO,CAAC;AAM7F,OAAO,EAAC,eAAe,EAAC,MAAM,eAAe,CAAC;AAO9C,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAI1C,OAAO,EAAC,mBAAmB,EAAE,aAAa,EAAC,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileFlameGraph/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAwE,MAAM,OAAO,CAAC;AAM7F,OAAO,EAAC,eAAe,EAAC,MAAM,eAAe,CAAC;AAO9C,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAI1C,OAAO,EAAC,mBAAmB,EAAE,aAAa,EAAC,MAAM,kBAAkB,CAAC;AAMpE,OAAO,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAIzD,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;AAEpE,UAAU,sBAAsB;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,aAAa,EAAE,aAAa,CAAC;IAC7B,YAAY,EAAE,gBAAgB,EAAE,GAAG,EAAE,CAAC;IACtC,kBAAkB,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IACvD,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC;IACxD,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,YAAY,EAAE,OAAO,CAAC;IACtB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;CAC1D;AAUD,eAAO,MAAM,uBAAuB,GAClC,eAAe,mBAAmB,KACjC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,CAAC;IAAC,iBAAiB,EAAE,OAAO,CAAA;CAKpE,CAAC;AAEF,QAAA,MAAM,iBAAiB,GAAqC,sRAqBzD,sBAAsB,KAAG,GAAG,CAAC,OAiT/B,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
|
@@ -22,9 +22,7 @@ import DiffLegend from '../ProfileView/components/DiffLegend';
|
|
|
22
22
|
import { useProfileViewContext } from '../ProfileView/context/ProfileViewContext';
|
|
23
23
|
import { useProfileMetadata } from '../ProfileView/hooks/useProfileMetadata';
|
|
24
24
|
import { useVisualizationState } from '../ProfileView/hooks/useVisualizationState';
|
|
25
|
-
import { TimelineGuide } from '../TimelineGuide';
|
|
26
25
|
import { FlameGraphArrow } from './FlameGraphArrow';
|
|
27
|
-
import { boundsFromProfileSource } from './FlameGraphArrow/utils';
|
|
28
26
|
const numberFormatter = new Intl.NumberFormat('en-US');
|
|
29
27
|
const ErrorContent = ({ errorMessage }) => {
|
|
30
28
|
return (_jsx("div", { className: "flex flex-col justify-center p-10 text-center gap-6 text-sm", children: errorMessage }));
|
|
@@ -35,11 +33,11 @@ export const validateFlameChartQuery = (profileSource) => {
|
|
|
35
33
|
const isDurationTooLong = duration > 60000000000n; // 60 seconds in nanoseconds
|
|
36
34
|
return { isValid: !isNonDelta && !isDurationTooLong, isNonDelta, isDurationTooLong };
|
|
37
35
|
};
|
|
38
|
-
const ProfileFlameGraph = function ProfileFlameGraphNonMemo({ arrow, total, filtered, curPathArrow, setNewCurPathArrow, profileType, loading, error, width, isHalfScreen, metadataMappingFiles, isFlameChart = false, profileSource, isInSandwichView = false, isRenderedAsFlamegraph = false, tooltipId, maxFrameCount, isExpanded = false, metadataLoading = false, }) {
|
|
36
|
+
const ProfileFlameGraph = function ProfileFlameGraphNonMemo({ arrow, total, filtered, curPathArrow, setNewCurPathArrow, profileType, loading, error, width, isHalfScreen, metadataMappingFiles, isFlameChart = false, profileSource, isInSandwichView = false, isRenderedAsFlamegraph = false, tooltipId, maxFrameCount, isExpanded = false, metadataLoading = false, zoomControlsRef, }) {
|
|
39
37
|
const { onError, authenticationErrorMessage, isDarkMode, flamechartHelpText } = useParcaContext();
|
|
40
38
|
const { compareMode } = useProfileViewContext();
|
|
41
39
|
const [isLoading, setIsLoading] = useState(true);
|
|
42
|
-
const [flameChartRef
|
|
40
|
+
const [flameChartRef] = useMeasure();
|
|
43
41
|
const { colorBy, setColorBy } = useVisualizationState();
|
|
44
42
|
// Create local state for paths when in sandwich view to avoid URL updates
|
|
45
43
|
const [localCurPathArrow, setLocalCurPathArrow] = useState([]);
|
|
@@ -124,7 +122,7 @@ const ProfileFlameGraph = function ProfileFlameGraphNonMemo({ arrow, total, filt
|
|
|
124
122
|
if (total === 0n && !loading)
|
|
125
123
|
return _jsx("div", { className: "mx-auto text-center", children: "Profile has no samples" });
|
|
126
124
|
if (arrow !== undefined) {
|
|
127
|
-
return (
|
|
125
|
+
return (_jsx("div", { className: "relative", children: _jsx("div", { ref: flameChartRef, children: _jsx(FlameGraphArrow, { width: width, arrow: arrow, total: total, filtered: filtered, curPath: effectiveCurPathArrow, setCurPath: setCurPathArrowWrapper, profileType: profileType, isHalfScreen: isHalfScreen, mappingsListFromMetadata: mappingsList, filenamesListFromMetadata: filenamesList, compareAbsolute: isCompareAbsolute, isFlameChart: isFlameChart, profileSource: profileSource, isRenderedAsFlamegraph: isRenderedAsFlamegraph, isInSandwichView: isInSandwichView, tooltipId: tooltipId, maxFrameCount: maxFrameCount, isExpanded: isExpanded, colorBy: colorBy, zoomControlsRef: zoomControlsRef }) }) }));
|
|
128
126
|
}
|
|
129
127
|
}, [
|
|
130
128
|
isLoading,
|
|
@@ -139,7 +137,6 @@ const ProfileFlameGraph = function ProfileFlameGraphNonMemo({ arrow, total, filt
|
|
|
139
137
|
isCompareAbsolute,
|
|
140
138
|
isFlameChart,
|
|
141
139
|
profileSource,
|
|
142
|
-
flameChartHeight,
|
|
143
140
|
flameChartRef,
|
|
144
141
|
flamechartHelpText,
|
|
145
142
|
isRenderedAsFlamegraph,
|
|
@@ -152,6 +149,7 @@ const ProfileFlameGraph = function ProfileFlameGraphNonMemo({ arrow, total, filt
|
|
|
152
149
|
mappingsList,
|
|
153
150
|
filenamesList,
|
|
154
151
|
colorBy,
|
|
152
|
+
zoomControlsRef,
|
|
155
153
|
]);
|
|
156
154
|
useEffect(() => {
|
|
157
155
|
if (isTrimmed) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,QAAQ,EAAE,cAAc,EAAoD,MAAM,OAAO,CAAC;AAElG,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAElD,OAAO,EAAsB,oBAAoB,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAY5F,OAAO,EAAyB,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAe/E,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,uBAAuB;IAC/B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC;AAED,UAAU,oBAAqB,SAAQ,uBAAuB;IAC5D,WAAW,EAAE,kBAAkB,CAAC;IAChC,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,gCAAgC,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IACrE,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,KAAK,CAAC,EAAE,QAAQ,CAAC;CAClB;AAED,eAAO,MAAM,eAAe,GAC1B,QAAQ,kBAAkB,EAC1B,QAAQ,MAAM,EACd,MAAM,MAAM,KACX,mBAsBF,CAAC;AAEF,QAAA,MAAM,eAAe,GAAI,kMAYtB,oBAAoB,KAAG,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,QAAQ,EAAE,cAAc,EAAoD,MAAM,OAAO,CAAC;AAElG,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAElD,OAAO,EAAsB,oBAAoB,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAY5F,OAAO,EAAyB,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAe/E,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,uBAAuB;IAC/B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC;AAED,UAAU,oBAAqB,SAAQ,uBAAuB;IAC5D,WAAW,EAAE,kBAAkB,CAAC;IAChC,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,gCAAgC,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IACrE,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,KAAK,CAAC,EAAE,QAAQ,CAAC;CAClB;AAED,eAAO,MAAM,eAAe,GAC1B,QAAQ,kBAAkB,EAC1B,QAAQ,MAAM,EACd,MAAM,MAAM,KACX,mBAsBF,CAAC;AAEF,QAAA,MAAM,eAAe,GAAI,kMAYtB,oBAAoB,KAAG,GAAG,CAAC,OA4Q7B,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -153,6 +153,7 @@ const ProfileSelector = ({ queryClient, closeProfile, enforcedProfileName, compa
|
|
|
153
153
|
querySelection,
|
|
154
154
|
navigateTo,
|
|
155
155
|
loading: sumByLoading,
|
|
156
|
+
defaultProfileType: viewComponent?.defaultProfileType,
|
|
156
157
|
});
|
|
157
158
|
const searchDisabled = queryExpressionString === undefined ||
|
|
158
159
|
queryExpressionString === '' ||
|
|
@@ -9,7 +9,8 @@ interface Props {
|
|
|
9
9
|
querySelection: QuerySelection;
|
|
10
10
|
navigateTo: NavigateFunction;
|
|
11
11
|
loading: boolean;
|
|
12
|
+
defaultProfileType?: string;
|
|
12
13
|
}
|
|
13
|
-
export declare const useAutoQuerySelector: ({ selectedProfileName, profileTypesData, setProfileName, setQueryExpression, querySelection, navigateTo, loading, }: Props) => void;
|
|
14
|
+
export declare const useAutoQuerySelector: ({ selectedProfileName, profileTypesData, setProfileName, setQueryExpression, querySelection, navigateTo, loading, defaultProfileType, }: Props) => void;
|
|
14
15
|
export {};
|
|
15
16
|
//# sourceMappingURL=useAutoQuerySelector.d.ts.map
|
|
@@ -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;
|
|
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;IACjB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,eAAO,MAAM,oBAAoB,GAAI,yIASlC,KAAK,KAAG,IA+JV,CAAC"}
|