ui: fix network panel re-render
This commit is contained in:
parent
0f744ec1a0
commit
778112c751
5 changed files with 295 additions and 311 deletions
|
|
@ -181,39 +181,37 @@ function NetworkPanelCont({ panelHeight }: { panelHeight: number }) {
|
|||
const tabValues = Object.values(tabStates);
|
||||
const dataSource = uiPlayerStore.dataSource;
|
||||
const showSingleTab = dataSource === 'current';
|
||||
const {
|
||||
fetchList = [],
|
||||
resourceList = [],
|
||||
fetchListNow = [],
|
||||
resourceListNow = [],
|
||||
websocketList = [],
|
||||
websocketListNow = [],
|
||||
} = React.useMemo(() => {
|
||||
if (showSingleTab) {
|
||||
return tabStates[currentTab] ?? {};
|
||||
} else {
|
||||
const fetchList = tabValues.flatMap((tab) => tab.fetchList);
|
||||
const resourceList = tabValues.flatMap((tab) => tab.resourceList);
|
||||
const fetchListNow = tabValues
|
||||
.flatMap((tab) => tab.fetchListNow)
|
||||
.filter(Boolean);
|
||||
const resourceListNow = tabValues
|
||||
.flatMap((tab) => tab.resourceListNow)
|
||||
.filter(Boolean);
|
||||
const websocketList = tabValues.flatMap((tab) => tab.websocketList);
|
||||
const websocketListNow = tabValues
|
||||
.flatMap((tab) => tab.websocketListNow)
|
||||
.filter(Boolean);
|
||||
return {
|
||||
fetchList,
|
||||
resourceList,
|
||||
fetchListNow,
|
||||
resourceListNow,
|
||||
websocketList,
|
||||
websocketListNow,
|
||||
};
|
||||
}
|
||||
}, [currentTab, tabStates, dataSource, tabValues]);
|
||||
|
||||
let fetchList = [];
|
||||
let resourceList = [];
|
||||
let fetchListNow = [];
|
||||
let resourceListNow = [];
|
||||
let websocketList = [];
|
||||
let websocketListNow = [];
|
||||
|
||||
if (showSingleTab) {
|
||||
const state = tabStates[currentTab] ?? {};
|
||||
fetchList = state.fetchList ?? [];
|
||||
resourceList = state.resourceList ?? [];
|
||||
fetchListNow = state.fetchListNow ?? [];
|
||||
resourceListNow = state.resourceListNow ?? [];
|
||||
websocketList = state.websocketList ?? [];
|
||||
websocketListNow = state.websocketListNow ?? [];
|
||||
} else {
|
||||
fetchList = tabValues.flatMap((tab) => tab.fetchList);
|
||||
resourceList = tabValues.flatMap((tab) => tab.resourceList);
|
||||
fetchListNow = tabValues
|
||||
.flatMap((tab) => tab.fetchListNow)
|
||||
.filter(Boolean);
|
||||
resourceListNow = tabValues
|
||||
.flatMap((tab) => tab.resourceListNow)
|
||||
.filter(Boolean);
|
||||
websocketList = tabValues.flatMap((tab) => tab.websocketList);
|
||||
websocketListNow = tabValues
|
||||
.flatMap((tab) => tab.websocketListNow)
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
const getTabNum = (tab: string) => tabsArr.findIndex((t) => t === tab) + 1;
|
||||
const getTabName = (tabId: string) => tabNames[tabId]
|
||||
return (
|
||||
|
|
@ -416,7 +414,7 @@ export const NetworkPanelComp = observer(
|
|||
: true
|
||||
)
|
||||
.sort((a, b) => a.time - b.time),
|
||||
[resourceList.length, fetchList.length, socketList]
|
||||
[resourceList.length, fetchList.length, socketList.length]
|
||||
);
|
||||
|
||||
let filteredList = useMemo(() => {
|
||||
|
|
@ -453,7 +451,7 @@ export const NetworkPanelComp = observer(
|
|||
activeIndex,
|
||||
(index) => devTools.update(INDEX_KEY, { index })
|
||||
);
|
||||
const onMouseEnter = stopAutoscroll;
|
||||
const onMouseEnter = () => stopAutoscroll;
|
||||
const onMouseLeave = () => {
|
||||
if (isDetailsModalActive) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -26,40 +26,7 @@ const BarRow = ({
|
|||
}: Props) => {
|
||||
const timeOffset = time - timestart;
|
||||
ttfb = ttfb || 0;
|
||||
// TODO fix the tooltip
|
||||
|
||||
const content = (
|
||||
<React.Fragment>
|
||||
{ttfb != null && (
|
||||
<div className={styles.popupRow}>
|
||||
<div className={styles.title}>{'Waiting (TTFB)'}</div>
|
||||
<div className={styles.popupBarWrapper}>
|
||||
<div
|
||||
className={styles.ttfbBar}
|
||||
style={{
|
||||
left: 0,
|
||||
width: `${percentOf(ttfb, duration)}%`,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.time}>{formatTime(ttfb)}</div>
|
||||
</div>
|
||||
)}
|
||||
<div className={styles.popupRow}>
|
||||
<div className={styles.title}>{'Content Download'}</div>
|
||||
<div className={styles.popupBarWrapper}>
|
||||
<div
|
||||
className={styles.downloadBar}
|
||||
style={{
|
||||
left: `${percentOf(ttfb, duration)}%`,
|
||||
width: `${percentOf(duration - ttfb, duration)}%`,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.time}>{formatTime(duration - ttfb)}</div>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
const trigger = (
|
||||
<div
|
||||
className={styles.barWrapper}
|
||||
|
|
@ -101,4 +68,4 @@ const BarRow = ({
|
|||
|
||||
BarRow.displayName = 'BarRow';
|
||||
|
||||
export default BarRow;
|
||||
export default React.memo(BarRow);
|
||||
|
|
|
|||
|
|
@ -8,8 +8,9 @@ import { percentOf } from 'App/utils';
|
|||
import BarRow from './BarRow';
|
||||
import stl from './timeTable.module.css';
|
||||
|
||||
import autoscrollStl from '../autoscroll.module.css'; //aaa
|
||||
import autoscrollStl from '../autoscroll.module.css';
|
||||
import JumpButton from '../JumpButton';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
||||
type Timed = {
|
||||
time: number;
|
||||
|
|
@ -45,11 +46,6 @@ type Column = {
|
|||
onClick?: void;
|
||||
} & RenderOrKey;
|
||||
|
||||
// type RenderOrKey = { // Disjoint?
|
||||
// render: Row => React.Node
|
||||
// } | {
|
||||
// dataKey: string,
|
||||
// }
|
||||
type RenderOrKey =
|
||||
| {
|
||||
render?: (row: Row) => React.ReactNode;
|
||||
|
|
@ -79,12 +75,8 @@ type TimeLineInfo = {
|
|||
timewidth: number;
|
||||
};
|
||||
|
||||
type State = TimeLineInfo & typeof initialState;
|
||||
|
||||
//const TABLE_HEIGHT = 195;
|
||||
let _additionalHeight = 0;
|
||||
const ROW_HEIGHT = 24;
|
||||
//const VISIBLE_COUNT = Math.ceil(TABLE_HEIGHT/ROW_HEIGHT);
|
||||
|
||||
const TIME_SECTIONS_COUNT = 8;
|
||||
const ZERO_TIMEWIDTH = 1000;
|
||||
|
|
@ -103,10 +95,13 @@ function computeTimeLine(
|
|||
firstVisibleRowIndex,
|
||||
firstVisibleRowIndex + visibleCount + _additionalHeight
|
||||
);
|
||||
let timestart = visibleRows.length > 0 ? Math.min(...visibleRows.map((r) => r.time)) : 0;
|
||||
let timestart =
|
||||
visibleRows.length > 0 ? Math.min(...visibleRows.map((r) => r.time)) : 0;
|
||||
// TODO: GraphQL requests do not have a duration, so their timeline is borked. Assume a duration of 0.2s for every GraphQL request
|
||||
const timeend =
|
||||
visibleRows.length > 0 ? Math.max(...visibleRows.map((r) => r.time + (r.duration ?? 200))) : 0;
|
||||
visibleRows.length > 0
|
||||
? Math.max(...visibleRows.map((r) => r.time + (r.duration ?? 200)))
|
||||
: 0;
|
||||
let timewidth = timeend - timestart;
|
||||
const offset = timewidth / 70;
|
||||
if (timestart >= offset) {
|
||||
|
|
@ -122,245 +117,267 @@ function computeTimeLine(
|
|||
};
|
||||
}
|
||||
|
||||
const initialState = {
|
||||
firstVisibleRowIndex: 0,
|
||||
};
|
||||
function TimeTable(props: Props) {
|
||||
const tableHeight = props.tableHeight || 195;
|
||||
const visibleCount = Math.ceil(tableHeight / ROW_HEIGHT);
|
||||
const [timerange, setTimerange] = React.useState({
|
||||
timestart: 0,
|
||||
timewidth: 0,
|
||||
});
|
||||
const [firstVisibleRowIndex, setFirstVisibleRowIndex] = React.useState(0);
|
||||
const scroller = React.createRef<VListHandle>();
|
||||
const { timestart, timewidth } = timerange;
|
||||
|
||||
export default class TimeTable extends React.PureComponent<Props, State> {
|
||||
state = {
|
||||
...computeTimeLine(this.props.rows, initialState.firstVisibleRowIndex, this.visibleCount),
|
||||
...initialState,
|
||||
};
|
||||
|
||||
get tableHeight() {
|
||||
return this.props.tableHeight || 195;
|
||||
}
|
||||
|
||||
get visibleCount() {
|
||||
return Math.ceil(this.tableHeight / ROW_HEIGHT);
|
||||
}
|
||||
|
||||
scroller = React.createRef<VListHandle>();
|
||||
autoScroll = true;
|
||||
|
||||
adjustScroll(prevActiveIndex: number) {
|
||||
if (
|
||||
this.props.activeIndex &&
|
||||
this.props.activeIndex >= 0 &&
|
||||
prevActiveIndex !== this.props.activeIndex &&
|
||||
this.scroller.current
|
||||
) {
|
||||
this.scroller.current.scrollToIndex(this.props.activeIndex);
|
||||
React.useEffect(() => {
|
||||
const { timestart, timewidth } = computeTimeLine(
|
||||
props.rows,
|
||||
firstVisibleRowIndex,
|
||||
visibleCount
|
||||
);
|
||||
setTimerange({ timestart, timewidth });
|
||||
}, [
|
||||
props.rows.length,
|
||||
visibleCount,
|
||||
_additionalHeight,
|
||||
firstVisibleRowIndex,
|
||||
]);
|
||||
React.useEffect(() => {
|
||||
if (props.activeIndex && props.activeIndex >= 0 && scroller.current) {
|
||||
scroller.current.scrollToIndex(props.activeIndex);
|
||||
setFirstVisibleRowIndex(props.activeIndex ?? 0);
|
||||
}
|
||||
}
|
||||
}, [props.activeIndex]);
|
||||
|
||||
componentDidUpdate(prevProps: any, prevState: any) {
|
||||
if (
|
||||
prevState.firstVisibleRowIndex !== this.state.firstVisibleRowIndex ||
|
||||
(this.props.rows.length <= this.visibleCount + _additionalHeight &&
|
||||
prevProps.rows.length !== this.props.rows.length)
|
||||
) {
|
||||
this.setState({
|
||||
...computeTimeLine(this.props.rows, this.state.firstVisibleRowIndex, this.visibleCount),
|
||||
});
|
||||
}
|
||||
|
||||
// this.adjustScroll(prevProps.activeIndex);
|
||||
}
|
||||
|
||||
onScroll = ({
|
||||
scrollTop,
|
||||
scrollHeight,
|
||||
clientHeight,
|
||||
}: {
|
||||
scrollTop: number;
|
||||
scrollHeight: number;
|
||||
clientHeight: number;
|
||||
}): void => {
|
||||
const firstVisibleRowIndex = Math.floor(scrollTop / ROW_HEIGHT + 0.33);
|
||||
|
||||
if (this.state.firstVisibleRowIndex !== firstVisibleRowIndex) {
|
||||
this.autoScroll = scrollHeight - clientHeight - scrollTop < ROW_HEIGHT / 2;
|
||||
this.setState({ firstVisibleRowIndex });
|
||||
const onJump = (index: any) => {
|
||||
if (props.onJump) {
|
||||
props.onJump(props.rows[index]);
|
||||
}
|
||||
};
|
||||
|
||||
onJump = (index: any) => {
|
||||
if (this.props.onJump) {
|
||||
this.props.onJump(this.props.rows[index]);
|
||||
const onPrevClick = () => {
|
||||
let prevRedIndex = -1;
|
||||
for (let i = firstVisibleRowIndex - 1; i >= 0; i--) {
|
||||
if (props.rows[i].isRed) {
|
||||
prevRedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (scroller.current != null) {
|
||||
scroller.current.scrollToIndex(prevRedIndex);
|
||||
}
|
||||
};
|
||||
|
||||
renderRow = (index: number) => {
|
||||
const { activeIndex } = this.props;
|
||||
const { children: columns, rows, renderPopup, hoverable, onRowClick } = this.props;
|
||||
const { timestart, timewidth } = this.state;
|
||||
const row = rows[index];
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'dev-row border-b border-neutral-950/5 group items-center text-sm',
|
||||
stl.row,
|
||||
{
|
||||
[stl.hoverable]: hoverable,
|
||||
'error color-red': row.isRed,
|
||||
'cursor-pointer': typeof onRowClick === 'function',
|
||||
[stl.activeRow]: activeIndex === index,
|
||||
[stl.inactiveRow]: !activeIndex || index > activeIndex,
|
||||
}
|
||||
)}
|
||||
onClick={typeof onRowClick === 'function' ? () => onRowClick(row, index) : undefined}
|
||||
id="table-row"
|
||||
>
|
||||
{columns
|
||||
.filter((i: any) => !i.hidden)
|
||||
.map(({ dataKey, render, width, label }) => (
|
||||
<div key={parseInt(label.replace(' ', '')+dataKey, 36)} className={cn(stl.cell, 'overflow-ellipsis overflow-hidden !py-0.5')} style={{ width: `${width}px` }}>
|
||||
{render
|
||||
? render(row)
|
||||
: row[dataKey || ''] || <i className="color-gray-light">{'empty'}</i>}
|
||||
const onNextClick = () => {
|
||||
let prevRedIndex = -1;
|
||||
for (let i = firstVisibleRowIndex + 1; i < props.rows.length; i++) {
|
||||
if (props.rows[i].isRed) {
|
||||
prevRedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (scroller.current != null) {
|
||||
scroller.current.scrollToIndex(prevRedIndex);
|
||||
}
|
||||
};
|
||||
|
||||
const {
|
||||
className,
|
||||
rows,
|
||||
navigation = false,
|
||||
referenceLines = [],
|
||||
additionalHeight = 0,
|
||||
renderPopup,
|
||||
hoverable,
|
||||
onRowClick,
|
||||
activeIndex,
|
||||
} = props;
|
||||
const columns = props.children.filter((i: any) => !i.hidden);
|
||||
|
||||
_additionalHeight = additionalHeight;
|
||||
|
||||
const sectionDuration = Math.round(timewidth / TIME_SECTIONS_COUNT);
|
||||
const timeColumns: number[] = [];
|
||||
if (timewidth > 0) {
|
||||
for (let i = 0; i < TIME_SECTIONS_COUNT; i++) {
|
||||
timeColumns.push(timestart + i * sectionDuration);
|
||||
}
|
||||
}
|
||||
|
||||
const visibleRefLines = referenceLines.filter(
|
||||
({ time }) => time > timestart && time < timestart + timewidth
|
||||
);
|
||||
|
||||
const columnsSumWidth = columns.reduce((sum, { width }) => sum + width, 0);
|
||||
|
||||
return (
|
||||
<div className={cn(className, 'relative')}>
|
||||
{navigation && (
|
||||
<div className={cn(autoscrollStl.navButtons, 'flex items-center')}>
|
||||
<Button
|
||||
variant="text-primary"
|
||||
icon="chevron-up"
|
||||
tooltip={{
|
||||
title: 'Previous Error',
|
||||
delay: 0,
|
||||
}}
|
||||
onClick={onPrevClick}
|
||||
/>
|
||||
<Button
|
||||
variant="text-primary"
|
||||
icon="chevron-down"
|
||||
tooltip={{
|
||||
title: 'Next Error',
|
||||
delay: 0,
|
||||
}}
|
||||
onClick={onNextClick}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className={stl.headers}>
|
||||
<div className={stl.infoHeaders}>
|
||||
{columns.map(({ label, width, dataKey, onClick = null }) => (
|
||||
<div
|
||||
key={parseInt(label.replace(' ', ''), 36)}
|
||||
className={cn(stl.headerCell, 'flex items-center select-none', {
|
||||
'cursor-pointer': typeof onClick === 'function',
|
||||
})}
|
||||
style={{ width: `${width}px` }}
|
||||
// onClick={() => onColumnClick(dataKey, onClick)}
|
||||
>
|
||||
<span>{label}</span>
|
||||
</div>
|
||||
))}
|
||||
<div className={cn('relative flex-1 flex', stl.timeBarWrapper)} style={{ height: 15 }}>
|
||||
<BarRow resource={row} timestart={timestart} timewidth={timewidth} popup={renderPopup} />
|
||||
</div>
|
||||
<JumpButton onClick={() => this.onJump(index)} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
onPrevClick = () => {
|
||||
let prevRedIndex = -1;
|
||||
for (let i = this.state.firstVisibleRowIndex - 1; i >= 0; i--) {
|
||||
if (this.props.rows[i].isRed) {
|
||||
prevRedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (this.scroller.current != null) {
|
||||
this.scroller.current.scrollToIndex(prevRedIndex);
|
||||
}
|
||||
};
|
||||
|
||||
onNextClick = () => {
|
||||
let prevRedIndex = -1;
|
||||
for (let i = this.state.firstVisibleRowIndex + 1; i < this.props.rows.length; i++) {
|
||||
if (this.props.rows[i].isRed) {
|
||||
prevRedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (this.scroller.current != null) {
|
||||
this.scroller.current.scrollToIndex(prevRedIndex);
|
||||
}
|
||||
};
|
||||
|
||||
onColumnClick = (dataKey: string, onClick: any) => {
|
||||
if (typeof onClick === 'function') {
|
||||
onClick(dataKey);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
rows,
|
||||
navigation = false,
|
||||
referenceLines = [],
|
||||
additionalHeight = 0,
|
||||
activeIndex,
|
||||
} = this.props;
|
||||
const columns = this.props.children.filter((i: any) => !i.hidden);
|
||||
const { timewidth, timestart } = this.state;
|
||||
|
||||
_additionalHeight = additionalHeight;
|
||||
|
||||
const sectionDuration = Math.round(timewidth / TIME_SECTIONS_COUNT);
|
||||
const timeColumns: number[] = [];
|
||||
if (timewidth > 0) {
|
||||
for (let i = 0; i < TIME_SECTIONS_COUNT; i++) {
|
||||
timeColumns.push(timestart + i * sectionDuration);
|
||||
}
|
||||
}
|
||||
|
||||
const visibleRefLines = referenceLines.filter(
|
||||
({ time }) => time > timestart && time < timestart + timewidth
|
||||
);
|
||||
|
||||
const columnsSumWidth = columns.reduce((sum, { width }) => sum + width, 0);
|
||||
|
||||
return (
|
||||
<div className={cn(className, 'relative')}>
|
||||
{navigation && (
|
||||
<div className={cn(autoscrollStl.navButtons, 'flex items-center')}>
|
||||
<Button
|
||||
variant="text-primary"
|
||||
icon="chevron-up"
|
||||
tooltip={{
|
||||
title: 'Previous Error',
|
||||
delay: 0,
|
||||
}}
|
||||
onClick={this.onPrevClick}
|
||||
/>
|
||||
<Button
|
||||
variant="text-primary"
|
||||
icon="chevron-down"
|
||||
tooltip={{
|
||||
title: 'Next Error',
|
||||
delay: 0,
|
||||
}}
|
||||
onClick={this.onNextClick}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className={stl.headers}>
|
||||
<div className={stl.infoHeaders}>
|
||||
{columns.map(({ label, width, dataKey, onClick = null }) => (
|
||||
<div
|
||||
key={parseInt(label.replace(' ', ''), 36)}
|
||||
className={cn(stl.headerCell, 'flex items-center select-none', {
|
||||
'cursor-pointer': typeof onClick === 'function',
|
||||
})}
|
||||
style={{ width: `${width}px` }}
|
||||
// onClick={() => this.onColumnClick(dataKey, onClick)}
|
||||
>
|
||||
<span>{label}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className={stl.waterfallHeaders}>
|
||||
{timeColumns.map((time, i) => (
|
||||
<div className={stl.timeCell} key={`tc-${i}`}>
|
||||
{formatTime(time)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<NoContent size="small" show={rows.length === 0}>
|
||||
<div className="relative" style={{ height: this.tableHeight }}>
|
||||
<div className={stl.timePart} style={{ left: `${columnsSumWidth}px` }}>
|
||||
{timeColumns.map((_, index) => (
|
||||
<div key={`tc-${index}`} className={stl.timeCell} />
|
||||
))}
|
||||
{visibleRefLines.map(({ time, color, onClick }) => (
|
||||
<div
|
||||
key={time}
|
||||
className={cn(stl.refLine, `bg-${color}`)}
|
||||
style={{
|
||||
left: `${percentOf(time - timestart, timewidth)}%`,
|
||||
cursor: typeof onClick === 'function' ? 'click' : 'auto',
|
||||
}}
|
||||
onClick={onClick}
|
||||
/>
|
||||
))}
|
||||
<div className={stl.waterfallHeaders}>
|
||||
{timeColumns.map((time, i) => (
|
||||
<div className={stl.timeCell} key={`tc-${i}`}>
|
||||
{formatTime(time)}
|
||||
</div>
|
||||
<VList className={stl.list} ref={this.scroller} itemSize={ROW_HEIGHT} count={rows.length}>
|
||||
{this.props.rows.map((_, index) => this.renderRow(index))}
|
||||
</VList>
|
||||
</div>
|
||||
</NoContent>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
<NoContent size="small" show={rows.length === 0}>
|
||||
<div className="relative" style={{ height: tableHeight }}>
|
||||
<div
|
||||
className={stl.timePart}
|
||||
style={{ left: `${columnsSumWidth}px` }}
|
||||
>
|
||||
{timeColumns.map((_, index) => (
|
||||
<div key={`tc-${index}`} className={stl.timeCell} />
|
||||
))}
|
||||
{visibleRefLines.map(({ time, color, onClick }) => (
|
||||
<div
|
||||
key={time}
|
||||
className={cn(stl.refLine, `bg-${color}`)}
|
||||
style={{
|
||||
left: `${percentOf(time - timestart, timewidth)}%`,
|
||||
cursor: typeof onClick === 'function' ? 'click' : 'auto',
|
||||
}}
|
||||
onClick={onClick}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<VList
|
||||
className={stl.list}
|
||||
ref={scroller}
|
||||
itemSize={ROW_HEIGHT}
|
||||
count={rows.length}
|
||||
overscan={10}
|
||||
onScroll={(offset) => {
|
||||
const firstVisibleRowIndex = Math.floor(
|
||||
offset / ROW_HEIGHT + 0.33
|
||||
);
|
||||
setFirstVisibleRowIndex(firstVisibleRowIndex);
|
||||
}}
|
||||
>
|
||||
{(index) => (
|
||||
<RowRenderer
|
||||
row={rows[index]}
|
||||
index={index}
|
||||
columns={columns}
|
||||
timestart={timestart}
|
||||
timewidth={timewidth}
|
||||
renderPopup={renderPopup}
|
||||
hoverable={hoverable}
|
||||
onRowClick={onRowClick}
|
||||
activeIndex={activeIndex}
|
||||
onJump={onJump}
|
||||
/>
|
||||
)}
|
||||
</VList>
|
||||
</div>
|
||||
</NoContent>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function RowRenderer({
|
||||
index,
|
||||
row,
|
||||
columns,
|
||||
timestart,
|
||||
timewidth,
|
||||
renderPopup,
|
||||
hoverable,
|
||||
onRowClick,
|
||||
activeIndex,
|
||||
onJump,
|
||||
}: any) {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'dev-row border-b border-neutral-950/5 group items-center text-sm',
|
||||
stl.row,
|
||||
{
|
||||
[stl.hoverable]: hoverable,
|
||||
'error color-red': row.isRed,
|
||||
'cursor-pointer': typeof onRowClick === 'function',
|
||||
[stl.activeRow]: activeIndex === index,
|
||||
[stl.inactiveRow]: !activeIndex || index > activeIndex,
|
||||
}
|
||||
)}
|
||||
onClick={
|
||||
typeof onRowClick === 'function'
|
||||
? () => onRowClick(row, index)
|
||||
: undefined
|
||||
}
|
||||
id="table-row"
|
||||
>
|
||||
<RowColumns columns={columns} row={row} />
|
||||
<div
|
||||
className={cn('relative flex-1 flex', stl.timeBarWrapper)}
|
||||
style={{ height: 15 }}
|
||||
>
|
||||
<BarRow
|
||||
resource={row}
|
||||
timestart={timestart}
|
||||
timewidth={timewidth}
|
||||
popup={renderPopup}
|
||||
/>
|
||||
</div>
|
||||
<JumpButton onClick={() => onJump(index)} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const RowColumns = React.memo(({ columns, row }: any) => {
|
||||
return columns.map(({ dataKey, render, width, label }: any) => (
|
||||
<div
|
||||
key={label.replace(' ', '') + dataKey}
|
||||
className={cn(
|
||||
stl.cell,
|
||||
'overflow-ellipsis overflow-hidden !py-0.5'
|
||||
)}
|
||||
style={{ width: `${width}px` }}
|
||||
>
|
||||
{render
|
||||
? render(row)
|
||||
: row[dataKey || ''] || (
|
||||
<i className="color-gray-light">{'empty'}</i>
|
||||
)}
|
||||
</div>
|
||||
))
|
||||
})
|
||||
|
||||
export default observer(TimeTable);
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@ function useAutoupdate<T>(
|
|||
updadteValue: (value: T) => void,
|
||||
) {
|
||||
const [ autoupdate, setAutoupdate ] = useState(savedValue === resetValue)
|
||||
|
||||
|
||||
const [ timeoutStartAutoupdate, stopAutoupdate ] = useCancelableTimeout(
|
||||
() => setAutoupdate(true),
|
||||
() => setAutoupdate(true),
|
||||
() => setAutoupdate(false),
|
||||
TIMEOUT_DURATION,
|
||||
)
|
||||
|
|
@ -61,4 +61,4 @@ export default function useAutoscroll(
|
|||
}, [ time, filteredList ])
|
||||
|
||||
return useAutoupdate(savedIndex, filteredIndexNow, 0, updadteIndex)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,6 +131,7 @@ export function getResourceFromResourceTiming(msg: ResourceTiming, sessStart: nu
|
|||
// duration might be duration=0 when cached
|
||||
const failed = msg.duration === 0 && msg.ttfb === 0 && msg.headerSize === 0 && msg.encodedBodySize === 0 && msg.transferredSize === 0
|
||||
const type = getResourceType(msg.initiator, msg.url)
|
||||
console.log(msg.url, msg.timestamp - sessStart)
|
||||
return Resource({
|
||||
...msg,
|
||||
type,
|
||||
|
|
@ -142,6 +143,7 @@ export function getResourceFromResourceTiming(msg: ResourceTiming, sessStart: nu
|
|||
}
|
||||
|
||||
export function getResourceFromNetworkRequest(msg: NetworkRequest | Fetch | MobileNetworkCall, sessStart: number) {
|
||||
console.log(msg.url, msg.timestamp - sessStart)
|
||||
return Resource({
|
||||
...msg,
|
||||
// @ts-ignore
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue