feat(trace viewer): fix UI issues (#6890)
This commit is contained in:
parent
cfcf6a8899
commit
85786b1a11
|
|
@ -69,6 +69,7 @@
|
||||||
color: red;
|
color: red;
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-right: 2px;
|
margin-right: 2px;
|
||||||
|
flex: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-selector {
|
.action-selector {
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,6 @@ export const FilmStrip: React.FunctionComponent<{
|
||||||
}
|
}
|
||||||
|
|
||||||
const screencastFrames = context.pages[pageIndex]?.screencastFrames;
|
const screencastFrames = context.pages[pageIndex]?.screencastFrames;
|
||||||
// TODO: pick file from the Y position.
|
|
||||||
let previewImage = undefined;
|
let previewImage = undefined;
|
||||||
if (previewPoint !== undefined && screencastFrames) {
|
if (previewPoint !== undefined && screencastFrames) {
|
||||||
const previewTime = boundaries.minimum + (boundaries.maximum - boundaries.minimum) * previewPoint.x / measure.width;
|
const previewTime = boundaries.minimum + (boundaries.maximum - boundaries.minimum) * previewPoint.x / measure.width;
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,18 @@
|
||||||
user-select: text;
|
user-select: text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.logs-error {
|
||||||
|
border-bottom: 1px solid var(--background);
|
||||||
|
padding: 3px 0 3px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logs-error .codicon {
|
||||||
|
color: red;
|
||||||
|
position: relative;
|
||||||
|
top: 2px;
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
.log-line {
|
.log-line {
|
||||||
flex: none;
|
flex: none;
|
||||||
padding: 3px 0 3px 12px;
|
padding: 3px 0 3px 12px;
|
||||||
|
|
|
||||||
|
|
@ -21,13 +21,13 @@ import { ActionTraceEvent } from '../../../server/trace/common/traceEvents';
|
||||||
export const LogsTab: React.FunctionComponent<{
|
export const LogsTab: React.FunctionComponent<{
|
||||||
action: ActionTraceEvent | undefined,
|
action: ActionTraceEvent | undefined,
|
||||||
}> = ({ action }) => {
|
}> = ({ action }) => {
|
||||||
let logs: string[] = [];
|
const logs = action?.metadata.log || [];
|
||||||
if (action) {
|
const error = action?.metadata.error;
|
||||||
logs = action.metadata.log || [];
|
|
||||||
if (action.metadata.error)
|
|
||||||
logs = [action.metadata.error, ...logs];
|
|
||||||
}
|
|
||||||
return <div className='logs-tab'>{
|
return <div className='logs-tab'>{
|
||||||
|
<div className='logs-error' key='error' hidden={!error}>
|
||||||
|
<div className='codicon codicon-issues'/>
|
||||||
|
{error}
|
||||||
|
</div>}{
|
||||||
logs.map((logLine, index) => {
|
logs.map((logLine, index) => {
|
||||||
return <div key={index} className='log-line'>
|
return <div key={index} className='log-line'>
|
||||||
{logLine}
|
{logLine}
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,6 @@
|
||||||
.timeline-bar {
|
.timeline-bar {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
height: 9px;
|
height: 9px;
|
||||||
top: 11px;
|
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
min-width: 3px;
|
min-width: 3px;
|
||||||
--action-color: gray;
|
--action-color: gray;
|
||||||
|
|
@ -125,13 +124,8 @@
|
||||||
--action-color: var(--blue);
|
--action-color: var(--blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
.timeline-bar.event {
|
.timeline-bar.frame_waitforeventinfo,
|
||||||
top: 22px;
|
.timeline-bar.page_waitforeventinfo {
|
||||||
}
|
|
||||||
|
|
||||||
.timeline-bar.frame_waitforeventinfo {
|
|
||||||
bottom: inherit;
|
|
||||||
top: 0;
|
|
||||||
--action-color: var(--gray);
|
--action-color: var(--gray);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,8 @@ export const Timeline: React.FunctionComponent<{
|
||||||
onHighlighted: (action: ActionTraceEvent | undefined) => void,
|
onHighlighted: (action: ActionTraceEvent | undefined) => void,
|
||||||
}> = ({ context, boundaries, selectedAction, highlightedAction, onSelected, onHighlighted }) => {
|
}> = ({ context, boundaries, selectedAction, highlightedAction, onSelected, onHighlighted }) => {
|
||||||
const [measure, ref] = useMeasure<HTMLDivElement>();
|
const [measure, ref] = useMeasure<HTMLDivElement>();
|
||||||
|
const barsRef = React.useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
const [previewPoint, setPreviewPoint] = React.useState<{ x: number, clientY: number } | undefined>();
|
const [previewPoint, setPreviewPoint] = React.useState<{ x: number, clientY: number } | undefined>();
|
||||||
const [hoveredBarIndex, setHoveredBarIndex] = React.useState<number | undefined>();
|
const [hoveredBarIndex, setHoveredBarIndex] = React.useState<number | undefined>();
|
||||||
|
|
||||||
|
|
@ -58,9 +60,9 @@ export const Timeline: React.FunctionComponent<{
|
||||||
for (const entry of page.actions) {
|
for (const entry of page.actions) {
|
||||||
if (!entry.metadata.params)
|
if (!entry.metadata.params)
|
||||||
console.log(entry);
|
console.log(entry);
|
||||||
let detail = entry.metadata.params.selector || '';
|
let detail = trimRight(entry.metadata.params.selector || '', 50);
|
||||||
if (entry.metadata.method === 'goto')
|
if (entry.metadata.method === 'goto')
|
||||||
detail = entry.metadata.params.url || '';
|
detail = trimRight(entry.metadata.params.url || '', 50);
|
||||||
bars.push({
|
bars.push({
|
||||||
action: entry,
|
action: entry,
|
||||||
leftTime: entry.metadata.startTime,
|
leftTime: entry.metadata.startTime,
|
||||||
|
|
@ -94,32 +96,41 @@ export const Timeline: React.FunctionComponent<{
|
||||||
let targetBar: TimelineBar | undefined = bars.find(bar => bar.action === (highlightedAction || selectedAction));
|
let targetBar: TimelineBar | undefined = bars.find(bar => bar.action === (highlightedAction || selectedAction));
|
||||||
targetBar = hoveredBar || targetBar;
|
targetBar = hoveredBar || targetBar;
|
||||||
|
|
||||||
const findHoveredBarIndex = (x: number) => {
|
const findHoveredBarIndex = (x: number, y: number) => {
|
||||||
const time = positionToTime(measure.width, boundaries, x);
|
const time = positionToTime(measure.width, boundaries, x);
|
||||||
const time1 = positionToTime(measure.width, boundaries, x - 5);
|
const time1 = positionToTime(measure.width, boundaries, x - 5);
|
||||||
const time2 = positionToTime(measure.width, boundaries, x + 5);
|
const time2 = positionToTime(measure.width, boundaries, x + 5);
|
||||||
let index: number | undefined;
|
let index: number | undefined;
|
||||||
let distance: number | undefined;
|
let yDistance: number | undefined;
|
||||||
|
let xDistance: number | undefined;
|
||||||
for (let i = 0; i < bars.length; i++) {
|
for (let i = 0; i < bars.length; i++) {
|
||||||
const bar = bars[i];
|
const bar = bars[i];
|
||||||
|
const yMiddle = kBarHeight / 2 + barTop(bar);
|
||||||
const left = Math.max(bar.leftTime, time1);
|
const left = Math.max(bar.leftTime, time1);
|
||||||
const right = Math.min(bar.rightTime, time2);
|
const right = Math.min(bar.rightTime, time2);
|
||||||
const middle = (bar.leftTime + bar.rightTime) / 2;
|
const xMiddle = (bar.leftTime + bar.rightTime) / 2;
|
||||||
const d = Math.abs(time - middle);
|
const xd = Math.abs(time - xMiddle);
|
||||||
if (left <= right && (index === undefined || d < distance!)) {
|
const yd = Math.abs(y - yMiddle);
|
||||||
|
if (left > right)
|
||||||
|
continue;
|
||||||
|
// Prefer closest yDistance (the same bar), among those prefer the closest xDistance.
|
||||||
|
if (index === undefined ||
|
||||||
|
(yd < yDistance!) ||
|
||||||
|
(Math.abs(yd - yDistance!) < 1e-2 && xd < xDistance!)) {
|
||||||
index = i;
|
index = i;
|
||||||
distance = d;
|
xDistance = xd;
|
||||||
|
yDistance = yd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return index;
|
return index;
|
||||||
};
|
};
|
||||||
|
|
||||||
const onMouseMove = (event: React.MouseEvent) => {
|
const onMouseMove = (event: React.MouseEvent) => {
|
||||||
if (!ref.current)
|
if (!ref.current || !barsRef.current)
|
||||||
return;
|
return;
|
||||||
const bounds = ref.current.getBoundingClientRect();
|
const x = event.clientX - ref.current.getBoundingClientRect().left;
|
||||||
const x = event.clientX - bounds.left;
|
const y = event.clientY - barsRef.current.getBoundingClientRect().top;
|
||||||
const index = findHoveredBarIndex(x);
|
const index = findHoveredBarIndex(x, y);
|
||||||
setPreviewPoint({ x, clientY: event.clientY });
|
setPreviewPoint({ x, clientY: event.clientY });
|
||||||
setHoveredBarIndex(index);
|
setHoveredBarIndex(index);
|
||||||
if (typeof index === 'number')
|
if (typeof index === 'number')
|
||||||
|
|
@ -134,10 +145,11 @@ export const Timeline: React.FunctionComponent<{
|
||||||
|
|
||||||
const onClick = (event: React.MouseEvent) => {
|
const onClick = (event: React.MouseEvent) => {
|
||||||
setPreviewPoint(undefined);
|
setPreviewPoint(undefined);
|
||||||
if (!ref.current)
|
if (!ref.current || !barsRef.current)
|
||||||
return;
|
return;
|
||||||
const x = event.clientX - ref.current.getBoundingClientRect().left;
|
const x = event.clientX - ref.current.getBoundingClientRect().left;
|
||||||
const index = findHoveredBarIndex(x);
|
const y = event.clientY - barsRef.current.getBoundingClientRect().top;
|
||||||
|
const index = findHoveredBarIndex(x, y);
|
||||||
if (index === undefined)
|
if (index === undefined)
|
||||||
return;
|
return;
|
||||||
const entry = bars[index].action;
|
const entry = bars[index].action;
|
||||||
|
|
@ -166,13 +178,14 @@ export const Timeline: React.FunctionComponent<{
|
||||||
</div>;
|
</div>;
|
||||||
})
|
})
|
||||||
}</div>
|
}</div>
|
||||||
<div className='timeline-lane timeline-bars'>{
|
<div className='timeline-lane timeline-bars' ref={barsRef}>{
|
||||||
bars.map((bar, index) => {
|
bars.map((bar, index) => {
|
||||||
return <div key={index}
|
return <div key={index}
|
||||||
className={'timeline-bar ' + (bar.action ? 'action ' : '') + (bar.event ? 'event ' : '') + bar.className + (targetBar === bar ? ' selected' : '')}
|
className={'timeline-bar ' + (bar.action ? 'action ' : '') + (bar.event ? 'event ' : '') + bar.className + (targetBar === bar ? ' selected' : '')}
|
||||||
style={{
|
style={{
|
||||||
left: bar.leftPosition + 'px',
|
left: bar.leftPosition + 'px',
|
||||||
width: Math.max(1, bar.rightPosition - bar.leftPosition) + 'px',
|
width: Math.max(1, bar.rightPosition - bar.leftPosition) + 'px',
|
||||||
|
top: barTop(bar) + 'px',
|
||||||
}}
|
}}
|
||||||
></div>;
|
></div>;
|
||||||
})
|
})
|
||||||
|
|
@ -222,3 +235,12 @@ function timeToPosition(clientWidth: number, boundaries: Boundaries, time: numbe
|
||||||
function positionToTime(clientWidth: number, boundaries: Boundaries, x: number): number {
|
function positionToTime(clientWidth: number, boundaries: Boundaries, x: number): number {
|
||||||
return x / clientWidth * (boundaries.maximum - boundaries.minimum) + boundaries.minimum;
|
return x / clientWidth * (boundaries.maximum - boundaries.minimum) + boundaries.minimum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function trimRight(s: string, maxLength: number): string {
|
||||||
|
return s.length <= maxLength ? s : s.substring(0, maxLength - 1) + '\u2026';
|
||||||
|
}
|
||||||
|
|
||||||
|
const kBarHeight = 11;
|
||||||
|
function barTop(bar: TimelineBar): number {
|
||||||
|
return bar.event ? 22 : (bar.action?.metadata.method === 'waitForEventInfo' ? 0 : 11);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue