chore: various trace viewer ui fixes (#21447)

This commit is contained in:
Pavel Feldman 2023-03-06 21:37:39 -08:00 committed by GitHub
parent 65117702e7
commit 9e477a183e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 47 additions and 23 deletions

View File

@ -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>

View File

@ -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}

View File

@ -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>}

View File

@ -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 {

View File

@ -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,

View File

@ -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',

View File

@ -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;
}

View File

@ -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');
}