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