diff --git a/frontend/app/components/shared/DevTools/ConsolePanel/ConsolePanel.tsx b/frontend/app/components/shared/DevTools/ConsolePanel/ConsolePanel.tsx index efc4f735a..38714b92d 100644 --- a/frontend/app/components/shared/DevTools/ConsolePanel/ConsolePanel.tsx +++ b/frontend/app/components/shared/DevTools/ConsolePanel/ConsolePanel.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import { connectPlayer, jump } from 'Player'; import Log from 'Types/session/log'; import BottomBlock from '../BottomBlock'; @@ -7,12 +7,11 @@ import { Tabs, Input, Icon, NoContent } from 'UI'; import cn from 'classnames'; import ConsoleRow from '../ConsoleRow'; import { getRE } from 'App/utils'; -import { - List, - CellMeasurer, - CellMeasurerCache, - AutoSizer, -} from 'react-virtualized'; +import { List, CellMeasurer, CellMeasurerCache, AutoSizer } from 'react-virtualized'; +import { useObserver } from 'mobx-react-lite'; +import { useStore } from 'App/mstore'; +import ErrorDetailsModal from 'App/components/Dashboard/components/Errors/ErrorDetailsModal'; +import { useModal } from 'App/components/Modal'; const ALL = 'ALL'; const INFO = 'INFO'; @@ -57,26 +56,97 @@ const getIconProps = (level: any) => { return null; }; +const INDEX_KEY = 'console'; +let timeOut: any = null; +const TIMEOUT_DURATION = 5000; interface Props { logs: any; exceptions: any; + time: any; } function ConsolePanel(props: Props) { - const { logs } = props; + const { logs, time } = props; const additionalHeight = 0; - const [activeTab, setActiveTab] = useState(ALL); - const [filter, setFilter] = useState(''); + // const [activeTab, setActiveTab] = useState(ALL); + // const [filter, setFilter] = useState(''); + const { + sessionStore: { devTools }, + } = useStore(); + const [isDetailsModalActive, setIsDetailsModalActive] = useState(false); + const [filteredList, setFilteredList] = useState([]); + const filter = useObserver(() => devTools[INDEX_KEY].filter); + const activeTab = useObserver(() => devTools[INDEX_KEY].activeTab); + const activeIndex = useObserver(() => devTools[INDEX_KEY].index); + const [pauseSync, setPauseSync] = useState(activeIndex > 0); + const synRef: any = useRef({}); + const { showModal } = useModal(); + + const onTabClick = (activeTab: any) => devTools.update(INDEX_KEY, { activeTab }); + const onFilterChange = ({ target: { value } }: any) => { + devTools.update(INDEX_KEY, { filter: value }); + }; + + synRef.current = { + pauseSync, + activeIndex, + }; + + const removePause = () => { + setIsDetailsModalActive(false); + clearTimeout(timeOut); + timeOut = setTimeout(() => { + devTools.update(INDEX_KEY, { index: getCurrentIndex() }); + setPauseSync(false); + }, TIMEOUT_DURATION); + }; + + const onMouseLeave = () => { + if (isDetailsModalActive) return; + removePause(); + }; + + useEffect(() => { + if (pauseSync) { + removePause(); + } + + return () => { + clearTimeout(timeOut); + if (!synRef.current.pauseSync) { + devTools.update(INDEX_KEY, { index: 0 }); + } + }; + }, []); + + const getCurrentIndex = () => { + return filteredList.filter((item: any) => item.time <= time).length - 1; + }; + + useEffect(() => { + const currentIndex = getCurrentIndex(); + if (currentIndex !== activeIndex && !pauseSync) { + devTools.update(INDEX_KEY, { index: currentIndex }); + } + }, [time]); const cache = new CellMeasurerCache({ fixedWidth: true, - keyMapper: (index: number) => filtered[index], + keyMapper: (index: number) => filteredList[index], }); const _list = React.useRef(); + const showDetails = (log: any) => { + setIsDetailsModalActive(true); + showModal(, { right: true, onClose: removePause }); + devTools.update(INDEX_KEY, { index: filteredList.indexOf(log) }); + setPauseSync(true); + }; + const _rowRenderer = ({ index, key, parent, style }: any) => { - const item = filtered[index]; + const item = filteredList[index]; return ( + // @ts-ignore {({ measure }: any) => ( showDetails(item)} recalcHeight={() => { measure(); (_list as any).current.recomputeRowHeights(index); @@ -95,7 +166,7 @@ function ConsolePanel(props: Props) { ); }; - const filtered = React.useMemo(() => { + React.useMemo(() => { const filterRE = getRE(filter, 'i'); let list = logs; @@ -104,14 +175,23 @@ function ConsolePanel(props: Props) { (!!filter ? filterRE.test(value) : true) && (activeTab === ALL || activeTab === LEVEL_TAB[level]) ); - return list; - }, [filter, activeTab]); + setFilteredList(list); + }, [logs, filter, activeTab]); - const onTabClick = (activeTab: any) => setActiveTab(activeTab); - const onFilterChange = ({ target: { value } }: any) => setFilter(value); + useEffect(() => { + if (_list.current) { + // @ts-ignore + _list.current.scrollToRow(activeIndex); + } + }, [activeIndex]); return ( - + setPauseSync(true)} + onMouseLeave={onMouseLeave} + > + {/* @ts-ignore */}
Console @@ -125,8 +205,11 @@ function ConsolePanel(props: Props) { name="filter" height={28} onChange={onFilterChange} + value={filter} /> + {/* @ts-ignore */} + {/* @ts-ignore */} } size="small" - show={filtered.length === 0} + show={filteredList.length === 0} > + {/* @ts-ignore */} {({ height, width }: any) => ( + // @ts-ignore )} + {/* @ts-ignore */} ); @@ -170,6 +258,7 @@ export default connectPlayer((state: any) => { }) ); return { + time: state.time, logs: logs.concat(logExceptions), }; })(ConsolePanel); diff --git a/frontend/app/components/shared/DevTools/ConsoleRow/ConsoleRow.tsx b/frontend/app/components/shared/DevTools/ConsoleRow/ConsoleRow.tsx index aae911d42..83929cbed 100644 --- a/frontend/app/components/shared/DevTools/ConsoleRow/ConsoleRow.tsx +++ b/frontend/app/components/shared/DevTools/ConsoleRow/ConsoleRow.tsx @@ -2,8 +2,6 @@ import React, { useState } from 'react'; import cn from 'classnames'; import { Icon } from 'UI'; import JumpButton from 'Shared/DevTools/JumpButton'; -import { useModal } from 'App/components/Modal'; -import ErrorDetailsModal from 'App/components/Dashboard/components/Errors/ErrorDetailsModal'; interface Props { log: any; @@ -12,24 +10,20 @@ interface Props { renderWithNL?: any; style?: any; recalcHeight?: () => void; + onClick: () => void; } function ConsoleRow(props: Props) { const { log, iconProps, jump, renderWithNL, style, recalcHeight } = props; - const { showModal } = useModal(); const [expanded, setExpanded] = useState(false); const lines = log.value.split('\n').filter((l: any) => !!l); const canExpand = lines.length > 1; const clickable = canExpand || !!log.errorId; - const onErrorClick = () => { - showModal(, { right: true }); - }; - const toggleExpand = () => { - setExpanded(!expanded) - setTimeout(() => recalcHeight(), 0) - } + setExpanded(!expanded); + setTimeout(() => recalcHeight(), 0); + }; return (
(!!log.errorId ? onErrorClick() : toggleExpand()) : () => {} - } + onClick={clickable ? () => (!!log.errorId ? props.onClick() : toggleExpand()) : () => {}} >
@@ -57,7 +49,13 @@ function ConsoleRow(props: Props) { )} {renderWithNL(lines.pop())}
- {canExpand && expanded && lines.map((l: string, i: number) =>
{l}
)} + {canExpand && + expanded && + lines.map((l: string, i: number) => ( +
+ {l} +
+ ))}
jump(log.time)} />
diff --git a/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx b/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx index 1acb51ac2..634aa9bae 100644 --- a/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx +++ b/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx @@ -142,9 +142,6 @@ function NetworkPanel(props: Props) { const { resources, time, domContentLoadedTime, loadTime, domBuildingTime, fetchList } = props; const { showModal } = useModal(); - const [sortBy, setSortBy] = useState('time'); - const [sortAscending, setSortAscending] = useState(true); - const [filteredList, setFilteredList] = useState([]); const [showOnlyErrors, setShowOnlyErrors] = useState(false); const [isDetailsModalActive, setIsDetailsModalActive] = useState(false); @@ -234,13 +231,6 @@ function NetworkPanel(props: Props) { (list = list.filter((networkCall: any) => networkCall.url !== fetchCall.url)) ); list = list.concat(fetchList); - // list = list.sort((a: any, b: any) => { - // return compare(a, b, sortBy); - // }); - - // if (!sortAscending) { - // list = list.reverse(); - // } list = list.filter( ({ type, name, status, success }: any) => @@ -249,7 +239,7 @@ function NetworkPanel(props: Props) { (showOnlyErrors ? parseInt(status) >= 400 || !success : true) ); setFilteredList(list); - }, [resources, filter, sortBy, sortAscending, showOnlyErrors, activeTab]); + }, [resources, filter, showOnlyErrors, activeTab]); const referenceLines = useMemo(() => { const arr = []; @@ -283,13 +273,6 @@ function NetworkPanel(props: Props) { setPauseSync(true); }; - const handleSort = (sortKey: string) => { - if (sortKey === sortBy) { - setSortAscending(!sortAscending); - } - setSortBy(sortKey); - }; - useEffect(() => { devTools.update(INDEX_KEY, { filter, activeTab }); }, [filter, activeTab]); @@ -387,8 +370,6 @@ function NetworkPanel(props: Props) { devTools.update(INDEX_KEY, { index: filteredList.indexOf(row) }); jump(row.time); }} - sortBy={sortBy} - sortAscending={sortAscending} activeIndex={activeIndex} > {[ @@ -401,28 +382,24 @@ function NetworkPanel(props: Props) { label: 'Status', dataKey: 'status', width: 70, - // onClick: handleSort, }, { label: 'Type', dataKey: 'type', width: 90, render: renderType, - // onClick: handleSort, }, { label: 'Name', width: 240, dataKey: 'name', render: renderName, - // onClick: handleSort, }, { label: 'Size', width: 80, dataKey: 'decodedBodySize', render: renderSize, - // onClick: handleSort, hidden: activeTab === XHR, }, { @@ -430,7 +407,6 @@ function NetworkPanel(props: Props) { width: 80, dataKey: 'duration', render: renderDuration, - // onClick: handleSort, }, ]} diff --git a/frontend/app/components/shared/DevTools/StackEventPanel/StackEventPanel.tsx b/frontend/app/components/shared/DevTools/StackEventPanel/StackEventPanel.tsx index 929a0e283..557c72172 100644 --- a/frontend/app/components/shared/DevTools/StackEventPanel/StackEventPanel.tsx +++ b/frontend/app/components/shared/DevTools/StackEventPanel/StackEventPanel.tsx @@ -127,6 +127,13 @@ function StackEventPanel(props: Props) { ); }; + useEffect(() => { + if (_list.current) { + // @ts-ignore + _list.current.scrollToRow(activeIndex); + } + }, [activeIndex]); + return ( )} diff --git a/frontend/app/components/shared/DevTools/TimeTable/TimeTable.tsx b/frontend/app/components/shared/DevTools/TimeTable/TimeTable.tsx index 1a224d968..8271a6561 100644 --- a/frontend/app/components/shared/DevTools/TimeTable/TimeTable.tsx +++ b/frontend/app/components/shared/DevTools/TimeTable/TimeTable.tsx @@ -72,8 +72,6 @@ type Props = { hoverable?: boolean; onRowClick?: (row: any, index: number) => void; onJump?: (time: any) => void; - sortBy?: string; - sortAscending?: boolean; }; type TimeLineInfo = { @@ -281,8 +279,6 @@ export default class TimeTable extends React.PureComponent { referenceLines = [], additionalHeight = 0, activeIndex, - sortBy = '', - sortAscending = true, } = this.props; const columns = this.props.children.filter((i: any) => !i.hidden); const { timewidth, timestart } = this.state; @@ -338,12 +334,6 @@ export default class TimeTable extends React.PureComponent { // onClick={() => this.onColumnClick(dataKey, onClick)} > {label} - {!!sortBy && sortBy === dataKey && ( - - )} ))} diff --git a/frontend/app/mstore/sessionStore.ts b/frontend/app/mstore/sessionStore.ts index f19f747fd..d055a9aa8 100644 --- a/frontend/app/mstore/sessionStore.ts +++ b/frontend/app/mstore/sessionStore.ts @@ -59,10 +59,12 @@ interface BaseDevState { class DevTools { network: BaseDevState; stackEvent: BaseDevState; + console: BaseDevState; constructor() { this.network = { index: 0, filter: '', activeTab: 'ALL', isError: false }; this.stackEvent = { index: 0, filter: '', activeTab: 'ALL', isError: false }; + this.console = { index: 0, filter: '', activeTab: 'ALL', isError: false }; makeAutoObservable(this, { update: action, });