mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-13 17:14:02 +03:00
chore: highlight actions and har entries in timeline (#26781)
This commit is contained in:
parent
c209d7e708
commit
a34deffa43
@ -30,7 +30,8 @@ type Filter = 'status' | 'method' | 'file' | 'time' | 'size' | 'content-type';
|
||||
export const NetworkTab: React.FunctionComponent<{
|
||||
model: modelUtil.MultiTraceModel | undefined,
|
||||
selectedTime: Boundaries | undefined,
|
||||
}> = ({ model, selectedTime }) => {
|
||||
onEntryHovered: (entry: Entry | undefined) => void,
|
||||
}> = ({ model, selectedTime, onEntryHovered }) => {
|
||||
const [resource, setResource] = React.useState<Entry | undefined>();
|
||||
const [filter, setFilter] = React.useState<Filter | undefined>(undefined);
|
||||
const [negateFilter, setNegateFilter] = React.useState<boolean>(false);
|
||||
@ -64,6 +65,7 @@ export const NetworkTab: React.FunctionComponent<{
|
||||
items={resources}
|
||||
render={entry => <NetworkResource resource={entry}></NetworkResource>}
|
||||
onSelected={setResource}
|
||||
onHighlighted={onEntryHovered}
|
||||
/>
|
||||
</div>}
|
||||
{resource && <NetworkResourceDetails resource={resource} onClose={() => setResource(undefined)} />}
|
||||
|
@ -62,26 +62,33 @@
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.timeline-lane.timeline-bars {
|
||||
pointer-events: auto;
|
||||
margin-bottom: 5px;
|
||||
height: 5px;
|
||||
overflow: visible;
|
||||
.timeline-bars {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.timeline-bar {
|
||||
position: absolute;
|
||||
height: 2px;
|
||||
--action-color: gray;
|
||||
background-color: var(--action-color);
|
||||
--action-background-color: #88888802;
|
||||
border-top: 2px solid var(--action-color);
|
||||
}
|
||||
|
||||
.timeline-bar.active {
|
||||
background-color: var(--action-background-color);
|
||||
}
|
||||
|
||||
.timeline-bar.action {
|
||||
--action-color: var(--vscode-charts-red);
|
||||
--action-background-color: #e5140033;
|
||||
}
|
||||
|
||||
.timeline-bar.network {
|
||||
--action-color: var(--vscode-charts-blue);
|
||||
--action-background-color: #1a85ff33;
|
||||
}
|
||||
|
||||
.timeline-label {
|
||||
|
@ -32,16 +32,19 @@ type TimelineBar = {
|
||||
rightPosition: number;
|
||||
leftTime: number;
|
||||
rightTime: number;
|
||||
active: boolean;
|
||||
};
|
||||
|
||||
export const Timeline: React.FunctionComponent<{
|
||||
model: MultiTraceModel | undefined,
|
||||
boundaries: Boundaries,
|
||||
highlightedAction: ActionTraceEventInContext | undefined,
|
||||
highlightedEntry: Entry | undefined,
|
||||
onSelected: (action: ActionTraceEventInContext) => void,
|
||||
selectedTime: Boundaries | undefined,
|
||||
setSelectedTime: (time: Boundaries | undefined) => void,
|
||||
sdkLanguage: Language,
|
||||
}> = ({ model, boundaries, onSelected, selectedTime, setSelectedTime, sdkLanguage }) => {
|
||||
}> = ({ model, boundaries, onSelected, highlightedAction, highlightedEntry, selectedTime, setSelectedTime, sdkLanguage }) => {
|
||||
const [measure, ref] = useMeasure<HTMLDivElement>();
|
||||
const [dragWindow, setDragWindow] = React.useState<{ startX: number, endX: number, pivot?: number, type: 'resize' | 'move' } | undefined>();
|
||||
const [previewPoint, setPreviewPoint] = React.useState<FilmStripPreviewPoint | undefined>();
|
||||
@ -70,6 +73,7 @@ export const Timeline: React.FunctionComponent<{
|
||||
rightTime: entry.endTime || boundaries.maximum,
|
||||
leftPosition: timeToPosition(measure.width, boundaries, entry.startTime),
|
||||
rightPosition: timeToPosition(measure.width, boundaries, entry.endTime || boundaries.maximum),
|
||||
active: highlightedAction === entry,
|
||||
});
|
||||
}
|
||||
|
||||
@ -82,10 +86,11 @@ export const Timeline: React.FunctionComponent<{
|
||||
rightTime: endTime,
|
||||
leftPosition: timeToPosition(measure.width, boundaries, startTime),
|
||||
rightPosition: timeToPosition(measure.width, boundaries, endTime),
|
||||
active: highlightedEntry === resource,
|
||||
});
|
||||
}
|
||||
return bars;
|
||||
}, [model, boundaries, measure]);
|
||||
}, [model, boundaries, measure, highlightedAction, highlightedEntry]);
|
||||
|
||||
const onMouseDown = React.useCallback((event: React.MouseEvent) => {
|
||||
setPreviewPoint(undefined);
|
||||
@ -215,19 +220,21 @@ export const Timeline: React.FunctionComponent<{
|
||||
</div>;
|
||||
})
|
||||
}</div>
|
||||
{<div className='timeline-lane timeline-bars'>{
|
||||
<div style={{ height: 8 }}></div>
|
||||
<FilmStrip model={model} boundaries={boundaries} previewPoint={previewPoint} />
|
||||
<div className='timeline-bars'>{
|
||||
bars.map((bar, index) => {
|
||||
return <div key={index}
|
||||
className={'timeline-bar ' + (bar.action ? 'action ' : '') + (bar.resource ? 'network ' : '')}
|
||||
className={'timeline-bar' + (bar.action ? ' action' : '') + (bar.resource ? ' network' : '') + (bar.active ? ' active' : '')}
|
||||
style={{
|
||||
left: bar.leftPosition + 'px',
|
||||
width: Math.max(1, bar.rightPosition - bar.leftPosition) + 'px',
|
||||
top: barTop(bar) + 'px',
|
||||
left: bar.leftPosition,
|
||||
width: Math.max(1, bar.rightPosition - bar.leftPosition),
|
||||
top: barTop(bar),
|
||||
bottom: 0,
|
||||
}}
|
||||
></div>;
|
||||
})
|
||||
}</div>}
|
||||
<FilmStrip model={model} boundaries={boundaries} previewPoint={previewPoint} />
|
||||
}</div>
|
||||
<div className='timeline-marker' style={{
|
||||
display: (previewPoint !== undefined) ? 'block' : 'none',
|
||||
left: (previewPoint?.x || 0) + 'px',
|
||||
@ -284,5 +291,5 @@ function positionToTime(clientWidth: number, boundaries: Boundaries, x: number):
|
||||
}
|
||||
|
||||
function barTop(bar: TimelineBar): number {
|
||||
return bar.resource ? 5 : 0;
|
||||
return bar.resource ? 25 : 20;
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ import type { Boundaries } from '../geometry';
|
||||
import { InspectorTab } from './inspectorTab';
|
||||
import { ToolbarButton } from '@web/components/toolbarButton';
|
||||
import { useSetting } from '@web/uiUtils';
|
||||
import type { Entry } from '@trace/har';
|
||||
|
||||
export const Workbench: React.FunctionComponent<{
|
||||
model?: MultiTraceModel,
|
||||
@ -46,6 +47,7 @@ export const Workbench: React.FunctionComponent<{
|
||||
}> = ({ model, hideStackFrames, showSourcesFirst, rootDir, fallbackLocation, initialSelection, onSelectionChanged, isLive }) => {
|
||||
const [selectedAction, setSelectedAction] = React.useState<ActionTraceEventInContext | undefined>(undefined);
|
||||
const [highlightedAction, setHighlightedAction] = React.useState<ActionTraceEventInContext | undefined>();
|
||||
const [highlightedEntry, setHighlightedEntry] = React.useState<Entry | undefined>();
|
||||
const [selectedNavigatorTab, setSelectedNavigatorTab] = React.useState<string>('actions');
|
||||
const [selectedPropertiesTab, setSelectedPropertiesTab] = React.useState<string>(showSourcesFirst ? 'source' : 'call');
|
||||
const [isInspecting, setIsInspecting] = React.useState(false);
|
||||
@ -122,7 +124,7 @@ export const Workbench: React.FunctionComponent<{
|
||||
const networkTab: TabbedPaneTabModel = {
|
||||
id: 'network',
|
||||
title: 'Network',
|
||||
render: () => <NetworkTab model={model} selectedTime={selectedTime} />
|
||||
render: () => <NetworkTab model={model} selectedTime={selectedTime} onEntryHovered={setHighlightedEntry}/>
|
||||
};
|
||||
const attachmentsTab: TabbedPaneTabModel = {
|
||||
id: 'attachments',
|
||||
@ -161,6 +163,8 @@ export const Workbench: React.FunctionComponent<{
|
||||
<Timeline
|
||||
model={model}
|
||||
boundaries={boundaries}
|
||||
highlightedAction={highlightedAction}
|
||||
highlightedEntry={highlightedEntry}
|
||||
onSelected={onActionSelected}
|
||||
sdkLanguage={sdkLanguage}
|
||||
selectedTime={selectedTime}
|
||||
|
Loading…
Reference in New Issue
Block a user