feat(inspector): collapse completed items (#5484)
This commit is contained in:
Родитель
dc51536bca
Коммит
3248c2449c
|
@ -35,6 +35,7 @@ export type CallLog = {
|
|||
messages: string[];
|
||||
status: 'in-progress' | 'done' | 'error' | 'paused';
|
||||
error?: string;
|
||||
reveal?: boolean;
|
||||
};
|
||||
|
||||
export type SourceHighlight = {
|
||||
|
|
|
@ -81,10 +81,6 @@ body {
|
|||
display: none !important;
|
||||
}
|
||||
|
||||
.codicon {
|
||||
color: var(--toolbar-color);
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: currentColor;
|
||||
}
|
||||
|
|
|
@ -25,9 +25,9 @@ export default {
|
|||
} as Meta;
|
||||
|
||||
const Template: Story<ToolbarProps> = () => <Toolbar>
|
||||
<ToolbarButton icon="clone" title="Copy" onClick={() => {}}></ToolbarButton>
|
||||
<ToolbarButton icon="trashcan" title="Erase" onClick={() => {}}></ToolbarButton>
|
||||
<ToolbarButton icon="close" title="Close" onClick={() => {}}></ToolbarButton>
|
||||
<ToolbarButton icon='record' title='Record' onClick={() => {}}>Record</ToolbarButton>
|
||||
<ToolbarButton icon='question' title='Inspect' onClick={() => {}}>Explore</ToolbarButton>
|
||||
<ToolbarButton icon='files' title='Copy' onClick={() => {}}></ToolbarButton>
|
||||
</Toolbar>;
|
||||
|
||||
export const Primary = Template.bind({});
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
padding: 0;
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.toolbar-button:disabled {
|
||||
|
@ -29,24 +31,10 @@
|
|||
cursor: default;
|
||||
}
|
||||
|
||||
.toolbar-button:not(.disabled):hover {
|
||||
.toolbar-button:not(.disabled):not(.toggled):hover {
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.toolbar-button.toggled {
|
||||
color: #1ea7fd;
|
||||
}
|
||||
|
||||
.toolbar-button.codicon-record.toggled {
|
||||
color: #fd1e1e;
|
||||
}
|
||||
|
||||
.toolbar-button.codicon-debug-continue,
|
||||
.toolbar-button.codicon-debug-step-over {
|
||||
color: #01bb01;
|
||||
}
|
||||
|
||||
.toolbar-button.codicon-debug-continue:hover,
|
||||
.toolbar-button.codicon-debug-step-over:hover {
|
||||
color: #41ca1e;
|
||||
.toolbar-button .codicon {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
|
|
@ -27,14 +27,15 @@ export interface ToolbarButtonProps {
|
|||
}
|
||||
|
||||
export const ToolbarButton: React.FC<ToolbarButtonProps> = ({
|
||||
children,
|
||||
title = '',
|
||||
icon = '',
|
||||
disabled = false,
|
||||
toggled = false,
|
||||
onClick = () => {},
|
||||
}) => {
|
||||
let className = `toolbar-button codicon codicon-${icon}`;
|
||||
let className = `toolbar-button ${icon}`;
|
||||
if (toggled)
|
||||
className += ' toggled';
|
||||
return <button className={className} onClick={onClick} title={title} disabled={!!disabled}></button>;
|
||||
return <button className={className} onClick={onClick} title={title} disabled={!!disabled}><span className={`codicon codicon-${icon}`}></span>{ children }</button>;
|
||||
};
|
||||
|
|
|
@ -50,7 +50,7 @@ export function exampleCallLog(): CallLog[] {
|
|||
'status': 'paused'
|
||||
},
|
||||
{
|
||||
'id': 5,
|
||||
'id': 6,
|
||||
'messages': [
|
||||
'navigating to "https://github.com/microsoft", waiting until "load"',
|
||||
],
|
||||
|
|
|
@ -23,27 +23,37 @@ export interface CallLogProps {
|
|||
}
|
||||
|
||||
export const CallLogView: React.FC<CallLogProps> = ({
|
||||
log
|
||||
log,
|
||||
}) => {
|
||||
const messagesEndRef = React.createRef<HTMLDivElement>();
|
||||
const [expandOverrides, setExpandOverrides] = React.useState<Map<number, boolean>>(new Map());
|
||||
React.useLayoutEffect(() => {
|
||||
messagesEndRef.current?.scrollIntoView({ block: 'center', inline: 'nearest' });
|
||||
if (log.find(callLog => callLog.reveal))
|
||||
messagesEndRef.current?.scrollIntoView({ block: 'center', inline: 'nearest' });
|
||||
}, [messagesEndRef]);
|
||||
|
||||
|
||||
return <div className='vbox'>
|
||||
<div className='call-log-header' style={{flex: 'none'}}>Log</div>
|
||||
<div className='call-log' style={{flex: 'auto'}}>
|
||||
{log.map(callLog => {
|
||||
const expandOverride = expandOverrides.get(callLog.id);
|
||||
const isExpanded = typeof expandOverride === 'boolean' ? expandOverride : callLog.status !== 'done';
|
||||
return <div className={`call-log-call ${callLog.status}`} key={callLog.id}>
|
||||
<div className='call-log-call-header'>
|
||||
<span className={'codicon ' + iconClass(callLog)}></span>{ callLog.title }
|
||||
<span className={`codicon codicon-chevron-${isExpanded ? 'down' : 'right'}`} style={{ cursor: 'pointer' }}onClick={() => {
|
||||
const newOverrides = new Map(expandOverrides);
|
||||
newOverrides.set(callLog.id, !isExpanded);
|
||||
setExpandOverrides(newOverrides);
|
||||
}}></span>
|
||||
{ callLog.title }
|
||||
<span className={'codicon ' + iconClass(callLog)}></span>
|
||||
</div>
|
||||
{ callLog.messages.map((message, i) => {
|
||||
{ (isExpanded ? callLog.messages : []).map((message, i) => {
|
||||
return <div className='call-log-message' key={i}>
|
||||
{ message.trim() }
|
||||
</div>;
|
||||
})}
|
||||
{ callLog.error ? <div className='call-log-message error'>
|
||||
{ callLog.error ? <div className='call-log-message error' hidden={!isExpanded}>
|
||||
{ callLog.error }
|
||||
</div> : undefined }
|
||||
</div>
|
||||
|
|
|
@ -42,8 +42,10 @@ export const Main: React.FC = ({
|
|||
window.playwrightSetPaused = setPaused;
|
||||
window.playwrightUpdateLogs = callLogs => {
|
||||
const newLog = new Map<number, CallLog>(log);
|
||||
for (const callLog of callLogs)
|
||||
for (const callLog of callLogs) {
|
||||
callLog.reveal = !log.has(callLog.id);
|
||||
newLog.set(callLog.id, callLog);
|
||||
}
|
||||
setLog(newLog);
|
||||
};
|
||||
|
||||
|
|
|
@ -37,3 +37,21 @@
|
|||
color: var(--toolbar-color);
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
.recorder .toolbar-button.toggled.question {
|
||||
color: #12a3ff;
|
||||
}
|
||||
|
||||
.recorder .toolbar-button.toggled.record {
|
||||
color: #fd1e1e;
|
||||
}
|
||||
|
||||
.recorder .toolbar-button:not([disabled]) .codicon-debug-continue,
|
||||
.recorder .toolbar-button:not([disabled]) .codicon-debug-step-over {
|
||||
color: #01bb01;
|
||||
}
|
||||
|
||||
.recorder .toolbar-button:not([disabled]):hover .codicon-debug-continue,
|
||||
.recorder .toolbar-button:not([disabled]):hover .codicon-debug-step-over {
|
||||
color: #41ca1e;
|
||||
}
|
||||
|
|
|
@ -57,15 +57,14 @@ export const Recorder: React.FC<RecorderProps> = ({
|
|||
React.useLayoutEffect(() => {
|
||||
messagesEndRef.current?.scrollIntoView({ block: 'center', inline: 'nearest' });
|
||||
}, [messagesEndRef]);
|
||||
|
||||
return <div className='recorder'>
|
||||
<Toolbar>
|
||||
<ToolbarButton icon='record' title='Record' toggled={mode == 'recording'} onClick={() => {
|
||||
window.dispatch({ event: 'setMode', params: { mode: mode === 'recording' ? 'none' : 'recording' }}).catch(() => { });
|
||||
}}></ToolbarButton>
|
||||
<ToolbarButton icon='question' title='Inspect' toggled={mode == 'inspecting'} onClick={() => {
|
||||
}}>Record</ToolbarButton>
|
||||
<ToolbarButton icon='question' title='Explore' toggled={mode == 'inspecting'} onClick={() => {
|
||||
window.dispatch({ event: 'setMode', params: { mode: mode === 'inspecting' ? 'none' : 'inspecting' }}).catch(() => { });
|
||||
}}></ToolbarButton>
|
||||
}}>Explore</ToolbarButton>
|
||||
<ToolbarButton icon='files' title='Copy' disabled={!source || !source.text} onClick={() => {
|
||||
copy(source.text);
|
||||
}}></ToolbarButton>
|
||||
|
@ -78,12 +77,12 @@ export const Recorder: React.FC<RecorderProps> = ({
|
|||
<ToolbarButton icon='debug-step-over' title='Step over' disabled={!paused} onClick={() => {
|
||||
window.dispatch({ event: 'step' }).catch(() => {});
|
||||
}}></ToolbarButton>
|
||||
<select className='recorder-chooser' hidden={!sources.length} onChange={event => {
|
||||
<select className='recorder-chooser' hidden={!sources.length} value={file} onChange={event => {
|
||||
setFile(event.target.selectedOptions[0].value);
|
||||
}}>{
|
||||
sources.map(s => {
|
||||
const title = s.file.replace(/.*[/\\]([^/\\]+)/, '$1');
|
||||
return <option key={s.file} value={s.file} selected={s.file === file}>{title}</option>;
|
||||
return <option key={s.file} value={s.file}>{title}</option>;
|
||||
})
|
||||
}
|
||||
</select>
|
||||
|
|
|
@ -148,19 +148,6 @@ describe('pause', (suite, { mode }) => {
|
|||
expect(await sanitizeLog(recorderPage)).toEqual([
|
||||
'pause',
|
||||
'click',
|
||||
'waiting for selector "button"',
|
||||
'selector resolved to visible <button>Submit</button>',
|
||||
'attempting click action',
|
||||
'waiting for element to be visible, enabled and stable',
|
||||
'element is visible, enabled and stable',
|
||||
'scrolling into view if needed',
|
||||
'done scrolling',
|
||||
'checking that element receives pointer events at ()',
|
||||
'element does receive pointer events',
|
||||
'performing click action',
|
||||
'click action done',
|
||||
'waiting for scheduled navigations to finish',
|
||||
'navigations have finished',
|
||||
'pause',
|
||||
]);
|
||||
await recorderPage.click('[title="Resume"]');
|
||||
|
@ -183,21 +170,7 @@ describe('pause', (suite, { mode }) => {
|
|||
expect(await sanitizeLog(recorderPage)).toEqual([
|
||||
'pause',
|
||||
'waitForEvent()',
|
||||
'waiting for event \"console\"',
|
||||
'click',
|
||||
'waiting for selector "button"',
|
||||
'selector resolved to visible <button onclick=\"console.log()\">Submit</button>',
|
||||
'attempting click action',
|
||||
'waiting for element to be visible, enabled and stable',
|
||||
'element is visible, enabled and stable',
|
||||
'scrolling into view if needed',
|
||||
'done scrolling',
|
||||
'checking that element receives pointer events at ()',
|
||||
'element does receive pointer events',
|
||||
'performing click action',
|
||||
'click action done',
|
||||
'waiting for scheduled navigations to finish',
|
||||
'navigations have finished',
|
||||
'pause',
|
||||
]);
|
||||
await recorderPage.click('[title="Resume"]');
|
||||
|
|
Загрузка…
Ссылка в новой задаче