chore: trace viewer UX (auto scroll to action + timeline duration) (#20001)

Fixes https://github.com/microsoft/playwright/issues/19916
This commit is contained in:
Max Schmitt 2023-01-10 18:33:20 +01:00 committed by GitHub
parent 0fe327c21b
commit 3918e33c91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 68 additions and 31 deletions

View File

@ -72,28 +72,55 @@ export const ActionList: React.FC<ActionListProps> = ({
newIndex = Math.max(index - 1, 0);
}
const element = actionListRef.current?.children.item(newIndex);
if ((element as any)?.scrollIntoViewIfNeeded)
(element as any).scrollIntoViewIfNeeded(false);
else
element?.scrollIntoView();
scrollIntoViewIfNeeded(element);
onSelected(actions[newIndex]);
}}
ref={actionListRef}
>
{actions.length === 0 && <div className='no-actions-entry'>No actions recorded</div>}
{actions.map(action => {
{actions.map(action => <ActionListItem
action={action}
highlightedAction={highlightedAction}
onSelected={onSelected}
onHighlighted={onHighlighted}
selectedAction={selectedAction}
sdkLanguage={sdkLanguage}
setSelectedTab={setSelectedTab}
/>)}
</div>
</div>;
};
const ActionListItem: React.FC<{
action: ActionTraceEvent,
highlightedAction: ActionTraceEvent | undefined,
onSelected: (action: ActionTraceEvent) => void,
onHighlighted: (action: ActionTraceEvent | undefined) => void,
selectedAction: ActionTraceEvent | undefined,
sdkLanguage: Language | undefined,
setSelectedTab: (tab: string) => void,
}> = ({ action, onSelected, onHighlighted, highlightedAction, selectedAction, sdkLanguage, setSelectedTab }) => {
const { metadata } = action;
const selectedSuffix = action === selectedAction ? ' selected' : '';
const highlightedSuffix = action === highlightedAction ? ' highlighted' : '';
const error = metadata.error?.error?.message;
const { errors, warnings } = modelUtil.stats(action);
const locator = metadata.params.selector ? asLocator(sdkLanguage || 'javascript', metadata.params.selector) : undefined;
const divRef = React.useRef<HTMLDivElement>(null);
React.useEffect(() => {
if (divRef.current && selectedAction === action)
scrollIntoViewIfNeeded(divRef.current);
}, [selectedAction, action]);
return <div
className={'action-entry' + selectedSuffix + highlightedSuffix}
key={metadata.id}
onClick={() => onSelected(action)}
onMouseEnter={() => onHighlighted(action)}
onMouseLeave={() => (highlightedAction === action) && onHighlighted(undefined)}
ref={divRef}
>
<div className='action-title'>
<span>{metadata.apiName}</span>
@ -107,7 +134,13 @@ export const ActionList: React.FC<ActionListProps> = ({
</div>
{error && <div className='codicon codicon-issues' title={error} />}
</div>;
})}
</div>
</div>;
};
function scrollIntoViewIfNeeded(element?: Element | null) {
if (!element)
return;
if ((element as any)?.scrollIntoViewIfNeeded)
(element as any).scrollIntoViewIfNeeded(false);
else
element?.scrollIntoView();
}

View File

@ -33,6 +33,7 @@ type TimelineBar = {
rightTime: number;
type: string;
label: string;
title: string;
className: string;
};
@ -67,6 +68,7 @@ export const Timeline: React.FunctionComponent<{
leftPosition: timeToPosition(measure.width, boundaries, entry.metadata.startTime),
rightPosition: timeToPosition(measure.width, boundaries, entry.metadata.endTime),
label: entry.metadata.apiName + ' ' + detail,
title: entry.metadata.endTime ? msToString(entry.metadata.endTime - entry.metadata.startTime) : 'Timed Out',
type: entry.metadata.type + '.' + entry.metadata.method,
className: `${entry.metadata.type}_${entry.metadata.method}`.toLowerCase()
});
@ -81,6 +83,7 @@ export const Timeline: React.FunctionComponent<{
leftPosition: timeToPosition(measure.width, boundaries, startTime),
rightPosition: timeToPosition(measure.width, boundaries, startTime),
label: event.metadata.method,
title: event.metadata.endTime ? msToString(event.metadata.endTime - event.metadata.startTime) : 'Timed Out',
type: event.metadata.type + '.' + event.metadata.method,
className: `${event.metadata.type}_${event.metadata.method}`.toLowerCase()
});
@ -183,6 +186,7 @@ export const Timeline: React.FunctionComponent<{
width: Math.max(1, bar.rightPosition - bar.leftPosition) + 'px',
top: barTop(bar) + 'px',
}}
title={bar.title}
></div>;
})
}</div>