mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-13 17:14:02 +03:00
chore: various trace viewer ui fixes (#21447)
This commit is contained in:
parent
65117702e7
commit
9e477a183e
@ -29,7 +29,7 @@ export interface ActionListProps {
|
||||
sdkLanguage: Language | undefined;
|
||||
onSelected: (action: ActionTraceEvent) => void,
|
||||
onHighlighted: (action: ActionTraceEvent | undefined) => void,
|
||||
setSelectedTab: (tab: string) => void,
|
||||
revealConsole: () => void,
|
||||
}
|
||||
|
||||
export const ActionList: React.FC<ActionListProps> = ({
|
||||
@ -38,7 +38,7 @@ export const ActionList: React.FC<ActionListProps> = ({
|
||||
sdkLanguage,
|
||||
onSelected = () => {},
|
||||
onHighlighted = () => {},
|
||||
setSelectedTab = () => {},
|
||||
revealConsole = () => {},
|
||||
}) => {
|
||||
return <ListView
|
||||
items={actions}
|
||||
@ -47,7 +47,7 @@ export const ActionList: React.FC<ActionListProps> = ({
|
||||
onHighlighted={(action: ActionTraceEvent) => onHighlighted(action)}
|
||||
itemKey={(action: ActionTraceEvent) => action.callId}
|
||||
itemType={(action: ActionTraceEvent) => action.error?.message ? 'error' : undefined}
|
||||
itemRender={(action: ActionTraceEvent) => renderAction(action, sdkLanguage, setSelectedTab)}
|
||||
itemRender={(action: ActionTraceEvent) => renderAction(action, sdkLanguage, revealConsole)}
|
||||
showNoItemsMessage={true}
|
||||
></ListView>;
|
||||
};
|
||||
@ -55,7 +55,7 @@ export const ActionList: React.FC<ActionListProps> = ({
|
||||
const renderAction = (
|
||||
action: ActionTraceEvent,
|
||||
sdkLanguage: Language | undefined,
|
||||
setSelectedTab: (tab: string) => void
|
||||
revealConsole: () => void
|
||||
) => {
|
||||
const { errors, warnings } = modelUtil.stats(action);
|
||||
const locator = action.params.selector ? asLocator(sdkLanguage || 'javascript', action.params.selector) : undefined;
|
||||
@ -67,7 +67,7 @@ const renderAction = (
|
||||
{action.method === 'goto' && action.params.url && <div className='action-url' title={action.params.url}>{action.params.url}</div>}
|
||||
</div>
|
||||
<div className='action-duration' style={{ flex: 'none' }}>{action.endTime ? msToString(action.endTime - action.startTime) : 'Timed Out'}</div>
|
||||
<div className='action-icons' onClick={() => setSelectedTab('console')}>
|
||||
<div className='action-icons' onClick={() => revealConsole()}>
|
||||
{!!errors && <div className='action-icon'><span className={'codicon codicon-error'}></span><span className="action-icon-value">{errors}</span></div>}
|
||||
{!!warnings && <div className='action-icon'><span className={'codicon codicon-warning'}></span><span className="action-icon-value">{warnings}</span></div>}
|
||||
</div>
|
||||
|
@ -25,7 +25,7 @@ import type { MultiTraceModel } from './modelUtil';
|
||||
const tileSize = { width: 200, height: 45 };
|
||||
|
||||
export const FilmStrip: React.FunctionComponent<{
|
||||
model: MultiTraceModel,
|
||||
model?: MultiTraceModel,
|
||||
boundaries: Boundaries,
|
||||
previewPoint?: { x: number, clientY: number },
|
||||
}> = ({ model, boundaries, previewPoint }) => {
|
||||
@ -37,7 +37,7 @@ export const FilmStrip: React.FunctionComponent<{
|
||||
pageIndex = ((previewPoint.clientY - bounds.top) / tileSize.height) | 0;
|
||||
}
|
||||
|
||||
const screencastFrames = model.pages[pageIndex]?.screencastFrames;
|
||||
const screencastFrames = model?.pages?.[pageIndex]?.screencastFrames;
|
||||
let previewImage = undefined;
|
||||
let previewSize = undefined;
|
||||
if (previewPoint !== undefined && screencastFrames) {
|
||||
@ -48,7 +48,7 @@ export const FilmStrip: React.FunctionComponent<{
|
||||
}
|
||||
|
||||
return <div className='film-strip' ref={ref}>{
|
||||
model.pages.filter(p => p.screencastFrames.length).map((page, index) => <FilmStripLane
|
||||
model?.pages.filter(p => p.screencastFrames.length).map((page, index) => <FilmStripLane
|
||||
boundaries={boundaries}
|
||||
page={page}
|
||||
width={measure.width}
|
||||
|
@ -20,8 +20,10 @@ import type { MultiTraceModel } from './modelUtil';
|
||||
import './callTab.css';
|
||||
|
||||
export const MetadataView: React.FunctionComponent<{
|
||||
model: MultiTraceModel,
|
||||
model?: MultiTraceModel,
|
||||
}> = ({ model }) => {
|
||||
if (!model)
|
||||
return <></>;
|
||||
return <div className='vbox'>
|
||||
<div className='call-section' style={{ paddingTop: 2 }}>Time</div>
|
||||
{model.wallTime && <div className='call-line'>start time:<span className='call-value datetime' title={new Date(model.wallTime).toLocaleString()}>{new Date(model.wallTime).toLocaleString()}</span></div>}
|
||||
|
@ -16,13 +16,13 @@
|
||||
|
||||
.timeline-view {
|
||||
flex: none;
|
||||
flex-basis: 60px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 20px 0 5px;
|
||||
cursor: text;
|
||||
user-select: none;
|
||||
border-bottom: 1px solid var(--vscode-panel-border);
|
||||
}
|
||||
|
||||
.timeline-divider {
|
||||
@ -30,7 +30,7 @@
|
||||
width: 1px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
background-color: rgb(0 0 0 / 10%);
|
||||
background-color: var(--vscode-panel-border);
|
||||
}
|
||||
|
||||
.timeline-time {
|
||||
|
@ -38,7 +38,7 @@ type TimelineBar = {
|
||||
};
|
||||
|
||||
export const Timeline: React.FunctionComponent<{
|
||||
model: MultiTraceModel,
|
||||
model: MultiTraceModel | undefined,
|
||||
selectedAction: ActionTraceEvent | undefined,
|
||||
onSelected: (action: ActionTraceEvent) => void,
|
||||
}> = ({ model, selectedAction, onSelected }) => {
|
||||
@ -49,7 +49,7 @@ export const Timeline: React.FunctionComponent<{
|
||||
const [hoveredBarIndex, setHoveredBarIndex] = React.useState<number | undefined>();
|
||||
|
||||
const { boundaries, offsets } = React.useMemo(() => {
|
||||
const boundaries = { minimum: model.startTime, maximum: model.endTime };
|
||||
const boundaries = { minimum: model?.startTime || 0, maximum: model?.endTime || 30000 };
|
||||
// Leave some nice free space on the right hand side.
|
||||
boundaries.maximum += (boundaries.maximum - boundaries.minimum) / 20;
|
||||
return { boundaries, offsets: calculateDividerOffsets(measure.width, boundaries) };
|
||||
@ -57,7 +57,7 @@ export const Timeline: React.FunctionComponent<{
|
||||
|
||||
const bars = React.useMemo(() => {
|
||||
const bars: TimelineBar[] = [];
|
||||
for (const entry of model.actions) {
|
||||
for (const entry of model?.actions || []) {
|
||||
let detail = trimRight(entry.params.selector || '', 50);
|
||||
if (entry.method === 'goto')
|
||||
detail = trimRight(entry.params.url || '', 50);
|
||||
@ -74,7 +74,7 @@ export const Timeline: React.FunctionComponent<{
|
||||
});
|
||||
}
|
||||
|
||||
for (const event of model.events) {
|
||||
for (const event of model?.events || []) {
|
||||
const startTime = event.time;
|
||||
bars.push({
|
||||
event,
|
||||
|
@ -53,13 +53,11 @@ export const Workbench: React.FunctionComponent<{
|
||||
tabs.push({ id: 'source', title: 'Source', count: 0, render: () => <SourceTab action={activeAction} /> });
|
||||
|
||||
return <div className='vbox'>
|
||||
<div style={{ paddingLeft: '20px', flex: 'none', borderBottom: '1px solid var(--vscode-panel-border)' }}>
|
||||
<Timeline
|
||||
model={model}
|
||||
selectedAction={activeAction}
|
||||
onSelected={action => setSelectedAction(action)}
|
||||
/>
|
||||
</div>
|
||||
<Timeline
|
||||
model={model}
|
||||
selectedAction={activeAction}
|
||||
onSelected={action => setSelectedAction(action)}
|
||||
/>
|
||||
<SplitView sidebarSize={300} orientation='horizontal' sidebarIsFirst={true}>
|
||||
<SplitView sidebarSize={300} orientation='vertical'>
|
||||
<SnapshotTab action={activeAction} sdkLanguage={model.sdkLanguage || 'javascript'} testIdAttributeName={model.testIdAttributeName || 'data-testid'} />
|
||||
@ -77,7 +75,7 @@ export const Workbench: React.FunctionComponent<{
|
||||
onHighlighted={action => {
|
||||
setHighlightedAction(action);
|
||||
}}
|
||||
setSelectedTab={setSelectedPropertiesTab}
|
||||
revealConsole={() => setSelectedPropertiesTab('console')}
|
||||
/> },
|
||||
{ id: 'metadata',
|
||||
title: 'Metadata',
|
||||
|
@ -112,3 +112,23 @@ input[type=text], input[type=search] {
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
body.dark-mode ::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
body.dark-mode ::-webkit-scrollbar-thumb {
|
||||
background-color: #555;
|
||||
}
|
||||
|
||||
body.dark-mode ::-webkit-scrollbar-track {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
body.dark-mode ::-webkit-scrollbar-thumb:hover {
|
||||
background-color: #777;
|
||||
}
|
||||
|
||||
body.dark-mode ::-webkit-scrollbar-track:hover {
|
||||
background-color: #444;
|
||||
}
|
||||
|
@ -45,3 +45,7 @@ export function toggleTheme() {
|
||||
document.body.classList.add(newTheme);
|
||||
localStorage.setItem('theme', newTheme);
|
||||
}
|
||||
|
||||
export function isDarkTheme() {
|
||||
return document.body.classList.contains('dark-mode');
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user