From a2a956b4d454ae3cf74e2a7cd35e80ce96dba02d Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Tue, 22 Nov 2022 19:10:17 +0100 Subject: [PATCH 1/5] change(ui) - wip --- .../DevTools/BottomBlock/BottomBlock.js | 24 +- .../DevTools/ConsolePanel/ConsolePanel.tsx | 1 - .../shared/DevTools/JumpButton/JumpButton.tsx | 4 +- .../DevTools/NetworkPanel/NetworkPanel.tsx | 208 ++++++++++-------- .../shared/DevTools/TimeTable/TimeTable.tsx | 73 +++--- frontend/app/mstore/sessionStore.ts | 140 +++++++----- .../MessageDistributor/MessageDistributor.ts | 1 - frontend/app/styles/general.css | 4 + frontend/package.json | 1 + 9 files changed, 267 insertions(+), 189 deletions(-) diff --git a/frontend/app/components/shared/DevTools/BottomBlock/BottomBlock.js b/frontend/app/components/shared/DevTools/BottomBlock/BottomBlock.js index 069757e60..8b7826755 100644 --- a/frontend/app/components/shared/DevTools/BottomBlock/BottomBlock.js +++ b/frontend/app/components/shared/DevTools/BottomBlock/BottomBlock.js @@ -1,17 +1,29 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import cn from 'classnames'; import stl from './bottomBlock.module.css'; +let timer = null; const BottomBlock = ({ children = null, className = '', additionalHeight = 0, + onMouseEnter = () => {}, + onMouseLeave = () => {}, ...props -}) => ( -
- { children } -
-); +}) => { + useEffect(() => {}, []); + + return ( +
+ {children} +
+ ); +}; BottomBlock.displayName = 'BottomBlock'; diff --git a/frontend/app/components/shared/DevTools/ConsolePanel/ConsolePanel.tsx b/frontend/app/components/shared/DevTools/ConsolePanel/ConsolePanel.tsx index 320f76341..8f5835cfa 100644 --- a/frontend/app/components/shared/DevTools/ConsolePanel/ConsolePanel.tsx +++ b/frontend/app/components/shared/DevTools/ConsolePanel/ConsolePanel.tsx @@ -4,7 +4,6 @@ import Log from 'Types/session/log'; import BottomBlock from '../BottomBlock'; import { LEVEL } from 'Types/session/log'; import { Tabs, Input, Icon, NoContent } from 'UI'; -// import Autoscroll from 'App/components/Session_/Autoscroll'; import cn from 'classnames'; import ConsoleRow from '../ConsoleRow'; import { getRE } from 'App/utils'; diff --git a/frontend/app/components/shared/DevTools/JumpButton/JumpButton.tsx b/frontend/app/components/shared/DevTools/JumpButton/JumpButton.tsx index c52b0cffd..31307fd9b 100644 --- a/frontend/app/components/shared/DevTools/JumpButton/JumpButton.tsx +++ b/frontend/app/components/shared/DevTools/JumpButton/JumpButton.tsx @@ -6,10 +6,10 @@ interface Props { tooltip?: string; } function JumpButton(props: Props) { - const { tooltip = '' } = props; + const { tooltip } = props; return (
- +
{ diff --git a/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx b/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx index e62bf25ff..8c087d868 100644 --- a/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx +++ b/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx @@ -1,5 +1,5 @@ -import React, { useState } from 'react'; -import { QuestionMarkHint, Tooltip, Tabs, Input, NoContent, Icon, Toggler, Button } from 'UI'; +import React, { useEffect, useMemo, useRef, useState } from 'react'; +import { Tooltip, Tabs, Input, NoContent, Icon, Toggler } from 'UI'; import { getRE } from 'App/utils'; import Resource, { TYPES } from 'Types/session/resource'; import { formatBytes } from 'App/utils'; @@ -12,6 +12,11 @@ import { Duration } from 'luxon'; import { connectPlayer, jump } from 'Player'; import { useModal } from 'App/components/Modal'; import FetchDetailsModal from 'Shared/FetchDetailsModal'; +import { useStore } from 'App/mstore'; +import { useObserver } from 'mobx-react-lite'; + +const INDEX_KEY = 'networkIndex'; +const INDEX_KEY_ACTIVE = 'networkActive'; const ALL = 'ALL'; const XHR = 'xhr'; @@ -67,37 +72,6 @@ export function renderStart(r: any) { ); } -// const renderXHRText = () => ( -// -// {XHR} -// -// Use our{' '} -// -// Fetch plugin -// -// {' to capture HTTP requests and responses, including status codes and bodies.'}
-// We also provide{' '} -// -// support for GraphQL -// -// {' for easy debugging of your queries.'} -// -// } -// className="ml-1" -// /> -//
-// ); - function renderSize(r: any) { if (r.responseBodySize) return formatBytes(r.responseBodySize); let triggerText; @@ -160,45 +134,76 @@ interface Props { loadTime: any; playing: boolean; domBuildingTime: any; - currentIndex: any; time: any; } function NetworkPanel(props: Props) { - const { - resources, - time, - currentIndex, - domContentLoadedTime, - loadTime, - playing, - domBuildingTime, - fetchList, - } = props; - const { showModal, hideModal } = useModal(); + const { resources, time, domContentLoadedTime, loadTime, domBuildingTime, fetchList } = props; + const { showModal } = useModal(); const [activeTab, setActiveTab] = useState(ALL); const [sortBy, setSortBy] = useState('time'); const [sortAscending, setSortAscending] = useState(true); const [filter, setFilter] = useState(''); + const [filteredList, setFilteredList] = useState([]); const [showOnlyErrors, setShowOnlyErrors] = useState(false); - const [activeRequest, setActiveRequest] = useState(false ) const onTabClick = (activeTab: any) => setActiveTab(activeTab); const onFilterChange = ({ target: { value } }: any) => setFilter(value); const additionalHeight = 0; const fetchPresented = fetchList.length > 0; + const { + sessionStore: { devTools }, + } = useStore(); - const resourcesSize = resources.reduce( - (sum: any, { decodedBodySize }: any) => sum + (decodedBodySize || 0), - 0 - ); + const activeIndex = useObserver(() => devTools[INDEX_KEY]); + const activeClick = useObserver(() => devTools[INDEX_KEY_ACTIVE]); + const [pauseSync, setPauseSync] = useState(!!activeClick); + const synRef: any = useRef({}); - const transferredSize = resources.reduce( - (sum: any, { headerSize, encodedBodySize }: any) => - sum + (headerSize || 0) + (encodedBodySize || 0), - 0 - ); + synRef.current = { + pauseSync, + activeIndex, + activeClick, + }; - const filterRE = getRE(filter, 'i'); - let filtered = React.useMemo(() => { + useEffect(() => { + if (!!activeClick) { + setPauseSync(true); + devTools.update(INDEX_KEY, activeClick); + console.log('mounting at: ', activeClick); + } + return () => { + if (synRef.current.pauseSync) { + console.log('unmouting at: ', synRef.current.activeIndex); + devTools.update(INDEX_KEY_ACTIVE, synRef.current.activeIndex); + } + }; + }, []); + + useEffect(() => { + const lastIndex = filteredList.filter((item: any) => item.time <= time).length - 1; + if (lastIndex !== activeIndex && !pauseSync) { + devTools.update(INDEX_KEY, lastIndex); + } + }, [time]); + + const { resourcesSize, transferredSize } = useMemo(() => { + const resourcesSize = resources.reduce( + (sum: any, { decodedBodySize }: any) => sum + (decodedBodySize || 0), + 0 + ); + + const transferredSize = resources.reduce( + (sum: any, { headerSize, encodedBodySize }: any) => + sum + (headerSize || 0) + (encodedBodySize || 0), + 0 + ); + return { + resourcesSize, + transferredSize, + }; + }, [resources]); + + useEffect(() => { + const filterRE = getRE(filter, 'i'); let list = resources; fetchList.forEach( (fetchCall: any) => @@ -209,9 +214,9 @@ function NetworkPanel(props: Props) { return compare(a, b, sortBy); }); - if (!sortAscending) { - list = list.reverse(); - } + // if (!sortAscending) { + // list = list.reverse(); + // } list = list.filter( ({ type, name, status, success }: any) => @@ -219,41 +224,53 @@ function NetworkPanel(props: Props) { (activeTab === ALL || type === TAB_TO_TYPE_MAP[activeTab]) && (showOnlyErrors ? parseInt(status) >= 400 || !success : true) ); - return list; - }, [filter, sortBy, sortAscending, showOnlyErrors, activeTab]); + setFilteredList(list); + }, [resources, filter, sortBy, sortAscending, showOnlyErrors, activeTab]); - // const lastIndex = currentIndex || filtered.filter((item: any) => item.time <= time).length - 1; - const referenceLines = []; - if (domContentLoadedTime != null) { - referenceLines.push({ - time: domContentLoadedTime.time, - color: DOM_LOADED_TIME_COLOR, - }); - } - if (loadTime != null) { - referenceLines.push({ - time: loadTime.time, - color: LOAD_TIME_COLOR, - }); - } + const referenceLines = useMemo(() => { + const arr = []; + + if (domContentLoadedTime != null) { + arr.push({ + time: domContentLoadedTime.time, + color: DOM_LOADED_TIME_COLOR, + }); + } + if (loadTime != null) { + arr.push({ + time: loadTime.time, + color: LOAD_TIME_COLOR, + }); + } + + return arr; + }, []); const onRowClick = (row: any) => { - showModal(, { - right: true, - }); + showModal( + , + { + right: true, + } + ); + devTools.update(INDEX_KEY, filteredList.indexOf(row)); + setPauseSync(true); }; const handleSort = (sortKey: string) => { if (sortKey === sortBy) { setSortAscending(!sortAscending); - // setSortBy('time'); } setSortBy(sortKey); }; return ( - + setPauseSync(true)} + >
Network @@ -287,7 +304,7 @@ function NetworkPanel(props: Props) { />
- + } size="small" - show={filtered.length === 0} + show={filteredList.length === 0} > { + setPauseSync(true); + devTools.update(INDEX_KEY, filteredList.indexOf(row)); + jump(row.time); + }} sortBy={sortBy} sortAscending={sortAscending} - // activeIndex={lastIndex} + activeIndex={activeIndex} > {[ // { @@ -348,28 +369,28 @@ function NetworkPanel(props: Props) { label: 'Status', dataKey: 'status', width: 70, - onClick: handleSort, + // onClick: handleSort, }, { label: 'Type', dataKey: 'type', width: 90, render: renderType, - onClick: handleSort, + // onClick: handleSort, }, { label: 'Name', width: 240, dataKey: 'name', render: renderName, - onClick: handleSort, + // onClick: handleSort, }, { label: 'Size', width: 80, dataKey: 'decodedBodySize', render: renderSize, - onClick: handleSort, + // onClick: handleSort, hidden: activeTab === XHR, }, { @@ -377,7 +398,7 @@ function NetworkPanel(props: Props) { width: 80, dataKey: 'duration', render: renderDuration, - onClick: handleSort, + // onClick: handleSort, }, ]} @@ -391,9 +412,12 @@ function NetworkPanel(props: Props) { export default connectPlayer((state: any) => ({ location: state.location, resources: state.resourceList, - fetchList: state.fetchList.map((i: any) => Resource({ ...i.toJS(), type: TYPES.XHR })), + fetchList: state.fetchList.map((i: any) => + Resource({ ...i.toJS(), type: TYPES.XHR, time: i.time < 0 ? 0 : i.time }) + ), domContentLoadedTime: state.domContentLoadedTime, loadTime: state.loadTime, + time: state.time, playing: state.playing, domBuildingTime: state.domBuildingTime, }))(NetworkPanel); diff --git a/frontend/app/components/shared/DevTools/TimeTable/TimeTable.tsx b/frontend/app/components/shared/DevTools/TimeTable/TimeTable.tsx index 2b242f331..1a224d968 100644 --- a/frontend/app/components/shared/DevTools/TimeTable/TimeTable.tsx +++ b/frontend/app/components/shared/DevTools/TimeTable/TimeTable.tsx @@ -145,8 +145,19 @@ export default class TimeTable extends React.PureComponent { scroller = React.createRef(); autoScroll = true; - componentDidMount() { - if (this.scroller.current) { + // componentDidMount() { + // if (this.scroller.current) { + // this.scroller.current.scrollToRow(this.props.activeIndex); + // } + // } + + adjustScroll(prevActiveIndex: number) { + if ( + this.props.activeIndex && + this.props.activeIndex >= 0 && + prevActiveIndex !== this.props.activeIndex && + this.scroller.current + ) { this.scroller.current.scrollToRow(this.props.activeIndex); } } @@ -161,14 +172,8 @@ export default class TimeTable extends React.PureComponent { ...computeTimeLine(this.props.rows, this.state.firstVisibleRowIndex, this.visibleCount), }); } - if ( - this.props.activeIndex && - this.props.activeIndex >= 0 && - prevProps.activeIndex !== this.props.activeIndex && - this.scroller.current - ) { - this.scroller.current.scrollToRow(this.props.activeIndex); - } + + // this.adjustScroll(prevProps.activeIndex); } onScroll = ({ @@ -190,7 +195,7 @@ export default class TimeTable extends React.PureComponent { onJump = (index: any) => { if (this.props.onJump) { - this.props.onJump(this.props.rows[index].time); + this.props.onJump(this.props.rows[index]); } }; @@ -203,23 +208,29 @@ export default class TimeTable extends React.PureComponent {
activeIndex, - })} + className={cn( + 'dev-row border-b border-color-gray-light-shade group items-center', + stl.row, + { + [stl.hoverable]: hoverable, + 'error color-red': !!row.isRed && 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 }) => ( -
- {render - ? render(row) - : row[dataKey || ''] || {'empty'}} -
- ))} + {columns + .filter((i: any) => !i.hidden) + .map(({ dataKey, render, width }) => ( +
+ {render + ? render(row) + : row[dataKey || ''] || {'empty'}} +
+ ))}
@@ -324,10 +335,15 @@ export default class TimeTable extends React.PureComponent { 'cursor-pointer': typeof onClick === 'function', })} style={{ width: `${width}px` }} - onClick={() => this.onColumnClick(dataKey, onClick)} + // onClick={() => this.onColumnClick(dataKey, onClick)} > {label} - {!!sortBy && sortBy === dataKey && } + {!!sortBy && sortBy === dataKey && ( + + )}
))}
@@ -360,6 +376,7 @@ export default class TimeTable extends React.PureComponent { {({ width }: { width: number }) => ( { rowHeight={ROW_HEIGHT} rowRenderer={this.renderRow} onScroll={this.onScroll} - scrollToAlignment="start" + scrollToAlignment="center" forceUpdateProp={timestart | timewidth | (activeIndex || 0)} /> )} diff --git a/frontend/app/mstore/sessionStore.ts b/frontend/app/mstore/sessionStore.ts index 98a7061e6..ec72c19ba 100644 --- a/frontend/app/mstore/sessionStore.ts +++ b/frontend/app/mstore/sessionStore.ts @@ -5,75 +5,97 @@ import Session from './types/session'; import Record, { LAST_7_DAYS } from 'Types/app/period'; class UserFilter { - endDate: number = new Date().getTime(); - startDate: number = new Date().getTime() - 24 * 60 * 60 * 1000; - rangeName: string = LAST_7_DAYS; - filters: any = []; - page: number = 1; - limit: number = 10; - period: any = Record({ rangeName: LAST_7_DAYS }); + endDate: number = new Date().getTime(); + startDate: number = new Date().getTime() - 24 * 60 * 60 * 1000; + rangeName: string = LAST_7_DAYS; + filters: any = []; + page: number = 1; + limit: number = 10; + period: any = Record({ rangeName: LAST_7_DAYS }); - constructor() { - makeAutoObservable(this, { - page: observable, - update: action, - }); + constructor() { + makeAutoObservable(this, { + page: observable, + update: action, + }); + } + + update(key: string, value: any) { + // @ts-ignore + this[key] = value; + + if (key === 'period') { + this.startDate = this.period.start; + this.endDate = this.period.end; } + } - update(key: string, value: any) { - this[key] = value; + setFilters(filters: any[]) { + this.filters = filters; + } - if (key === 'period') { - this.startDate = this.period.start; - this.endDate = this.period.end; - } - } + setPage(page: number) { + this.page = page; + } - setFilters(filters: any[]) { - this.filters = filters; - } + toJson() { + return { + endDate: this.period.end, + startDate: this.period.start, + filters: this.filters.map(filterMap), + page: this.page, + limit: this.limit, + }; + } +} - setPage(page: number) { - this.page = page; - } +class DevTools { + networkIndex: 0; + consoleIndex: 0; + eventsIndex: 0; + networkActive: null; + consoleActive: null; + eventsActive: null; + constructor() { + makeAutoObservable(this, { + update: action, + }); + } - toJson() { - return { - endDate: this.period.end, - startDate: this.period.start, - filters: this.filters.map(filterMap), - page: this.page, - limit: this.limit, - }; - } + update(key: string, value: any) { + // @ts-ignore + this[key] = value; + } } export default class SessionStore { - userFilter: UserFilter = new UserFilter(); + userFilter: UserFilter = new UserFilter(); + devTools: DevTools = new DevTools(); - constructor() { - makeAutoObservable(this, { - userFilter: observable, + constructor() { + makeAutoObservable(this, { + userFilter: observable, + devTools: observable, + }); + } + + resetUserFilter() { + this.userFilter = new UserFilter(); + } + + getSessions(filter: any): Promise { + return new Promise((resolve, reject) => { + sessionService + .getSessions(filter.toJson()) + .then((response: any) => { + resolve({ + sessions: response.sessions.map((session: any) => new Session().fromJson(session)), + total: response.total, + }); + }) + .catch((error: any) => { + reject(error); }); - } - - resetUserFilter() { - this.userFilter = new UserFilter(); - } - - getSessions(filter: any): Promise { - return new Promise((resolve, reject) => { - sessionService - .getSessions(filter.toJson()) - .then((response: any) => { - resolve({ - sessions: response.sessions.map((session: any) => new Session().fromJson(session)), - total: response.total, - }); - }) - .catch((error: any) => { - reject(error); - }); - }); - } + }); + } } diff --git a/frontend/app/player/MessageDistributor/MessageDistributor.ts b/frontend/app/player/MessageDistributor/MessageDistributor.ts index a80676a61..e1b59940a 100644 --- a/frontend/app/player/MessageDistributor/MessageDistributor.ts +++ b/frontend/app/player/MessageDistributor/MessageDistributor.ts @@ -132,7 +132,6 @@ export default class MessageDistributor extends StatedScreen { exceptions: session.errors.toJSON(), }) - /* === */ this.loadMessages(); } diff --git a/frontend/app/styles/general.css b/frontend/app/styles/general.css index cce982514..a21cfe239 100644 --- a/frontend/app/styles/general.css +++ b/frontend/app/styles/general.css @@ -355,4 +355,8 @@ p { width: 80px; height: 80px; transform: rotate(45deg); +} + +.dev-row { + transition: all 0.5s; } \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json index af78fbdaf..c4f0a68de 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -91,6 +91,7 @@ "@types/react-dom": "^18.0.4", "@types/react-redux": "^7.1.24", "@types/react-router-dom": "^5.3.3", + "@types/react-virtualized": "^9.21.21", "@typescript-eslint/eslint-plugin": "^5.24.0", "@typescript-eslint/parser": "^5.24.0", "autoprefixer": "^10.4.7", From 871a9b18266e0d1cb4a37a467389f442cfb9f731 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Wed, 23 Nov 2022 16:31:05 +0100 Subject: [PATCH 2/5] change(ui) - network with state --- .../DevTools/NetworkPanel/NetworkPanel.tsx | 81 +++++++++++++------ .../FetchDetailsModal/FetchDetailsModal.tsx | 6 ++ frontend/app/mstore/sessionStore.ts | 9 ++- 3 files changed, 67 insertions(+), 29 deletions(-) diff --git a/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx b/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx index 8c087d868..6be39a77a 100644 --- a/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx +++ b/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx @@ -15,8 +15,7 @@ import FetchDetailsModal from 'Shared/FetchDetailsModal'; import { useStore } from 'App/mstore'; import { useObserver } from 'mobx-react-lite'; -const INDEX_KEY = 'networkIndex'; -const INDEX_KEY_ACTIVE = 'networkActive'; +const INDEX_KEY = 'network'; const ALL = 'ALL'; const XHR = 'xhr'; @@ -126,6 +125,9 @@ export function renderDuration(r: any) { ); } +let timeOut: any = null; +const TIMEOUT_DURATION = 5000; + interface Props { location: any; resources: any; @@ -139,49 +141,70 @@ interface Props { function NetworkPanel(props: Props) { const { resources, time, domContentLoadedTime, loadTime, domBuildingTime, fetchList } = props; const { showModal } = useModal(); - const [activeTab, setActiveTab] = useState(ALL); + const [sortBy, setSortBy] = useState('time'); const [sortAscending, setSortAscending] = useState(true); - const [filter, setFilter] = useState(''); + const [filteredList, setFilteredList] = useState([]); const [showOnlyErrors, setShowOnlyErrors] = useState(false); - const onTabClick = (activeTab: any) => setActiveTab(activeTab); - const onFilterChange = ({ target: { value } }: any) => setFilter(value); + const [isDetailsModalActive, setIsDetailsModalActive] = useState(false); const additionalHeight = 0; const fetchPresented = fetchList.length > 0; const { sessionStore: { devTools }, } = useStore(); - - const activeIndex = useObserver(() => devTools[INDEX_KEY]); - const activeClick = useObserver(() => devTools[INDEX_KEY_ACTIVE]); - const [pauseSync, setPauseSync] = useState(!!activeClick); + // const [filter, setFilter] = useState(devTools[INDEX_KEY].filter); + // const [activeTab, setActiveTab] = useState(ALL); + 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 onTabClick = (activeTab: any) => devTools.update(INDEX_KEY, { activeTab });; + const onFilterChange = ({ target: { value } }: any) => { + devTools.update(INDEX_KEY, { filter: value }); + }; + synRef.current = { pauseSync, activeIndex, - activeClick, + }; + + const removePause = () => { + clearTimeout(timeOut); + timeOut = setTimeout(() => { + devTools.update(INDEX_KEY, { index: getCurrentIndex() }); + setPauseSync(false); + }, TIMEOUT_DURATION); + }; + + const onMouseLeave = () => { + if (isDetailsModalActive) return; + removePause(); }; useEffect(() => { - if (!!activeClick) { - setPauseSync(true); - devTools.update(INDEX_KEY, activeClick); - console.log('mounting at: ', activeClick); + if (pauseSync) { + removePause(); } + return () => { - if (synRef.current.pauseSync) { - console.log('unmouting at: ', synRef.current.activeIndex); - devTools.update(INDEX_KEY_ACTIVE, synRef.current.activeIndex); + 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 lastIndex = filteredList.filter((item: any) => item.time <= time).length - 1; - if (lastIndex !== activeIndex && !pauseSync) { - devTools.update(INDEX_KEY, lastIndex); + const currentIndex = getCurrentIndex(); + if (currentIndex !== activeIndex && !pauseSync) { + devTools.update(INDEX_KEY, { index: currentIndex }); } }, [time]); @@ -246,14 +269,16 @@ function NetworkPanel(props: Props) { return arr; }, []); - const onRowClick = (row: any) => { + const showDetailsModal = (row: any) => { + setIsDetailsModalActive(true); showModal( , { right: true, + onClose: removePause, } ); - devTools.update(INDEX_KEY, filteredList.indexOf(row)); + devTools.update(INDEX_KEY, { index: filteredList.indexOf(row) }); setPauseSync(true); }; @@ -264,12 +289,17 @@ function NetworkPanel(props: Props) { setSortBy(sortKey); }; + useEffect(() => { + devTools.update(INDEX_KEY, { filter, activeTab }); + }, [filter, activeTab]); + return ( setPauseSync(true)} + onMouseLeave={onMouseLeave} >
@@ -291,6 +321,7 @@ function NetworkPanel(props: Props) { onChange={onFilterChange} height={28} width={230} + value={filter} /> @@ -348,11 +379,11 @@ function NetworkPanel(props: Props) { rows={filteredList} referenceLines={referenceLines} renderPopup - onRowClick={onRowClick} + onRowClick={showDetailsModal} additionalHeight={additionalHeight} onJump={(row: any) => { setPauseSync(true); - devTools.update(INDEX_KEY, filteredList.indexOf(row)); + devTools.update(INDEX_KEY, { index: filteredList.indexOf(row) }); jump(row.time); }} sortBy={sortBy} diff --git a/frontend/app/components/shared/FetchDetailsModal/FetchDetailsModal.tsx b/frontend/app/components/shared/FetchDetailsModal/FetchDetailsModal.tsx index 1ab311bfa..bcee5f5b9 100644 --- a/frontend/app/components/shared/FetchDetailsModal/FetchDetailsModal.tsx +++ b/frontend/app/components/shared/FetchDetailsModal/FetchDetailsModal.tsx @@ -4,6 +4,7 @@ import { Button } from 'UI'; import FetchPluginMessage from './components/FetchPluginMessage'; import { TYPES } from 'Types/session/resource'; import FetchTabs from './components/FetchTabs/FetchTabs'; +import { useStore } from 'App/mstore'; interface Props { resource: any; @@ -16,6 +17,9 @@ function FetchDetailsModal(props: Props) { const [first, setFirst] = useState(false); const [last, setLast] = useState(false); const isXHR = resource.type === TYPES.XHR || resource.type === TYPES.FETCH; + const { + sessionStore: { devTools }, + } = useStore(); useEffect(() => { const index = rows.indexOf(resource); @@ -28,6 +32,7 @@ function FetchDetailsModal(props: Props) { const index = rows.indexOf(resource); if (index > 0) { setResource(rows[index - 1]); + devTools.update('network', { index: index - 1 }) } }; @@ -35,6 +40,7 @@ function FetchDetailsModal(props: Props) { const index = rows.indexOf(resource); if (index < rows.length - 1) { setResource(rows[index + 1]); + devTools.update('network', { index: index + 1 }) } }; diff --git a/frontend/app/mstore/sessionStore.ts b/frontend/app/mstore/sessionStore.ts index ec72c19ba..b947bd01a 100644 --- a/frontend/app/mstore/sessionStore.ts +++ b/frontend/app/mstore/sessionStore.ts @@ -51,12 +51,13 @@ class UserFilter { class DevTools { networkIndex: 0; + network: any; + consoleIndex: 0; eventsIndex: 0; - networkActive: null; - consoleActive: null; - eventsActive: null; + constructor() { + this.network = { index: 0, search: '', activeTab: 'ALL', isError: false }; makeAutoObservable(this, { update: action, }); @@ -64,7 +65,7 @@ class DevTools { update(key: string, value: any) { // @ts-ignore - this[key] = value; + this[key] = Object.assign(this[key], value); } } From 76804f0cd66b076377573b84464188fd99295935 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Wed, 23 Nov 2022 18:35:45 +0100 Subject: [PATCH 3/5] change(ui) - events virutalize and sync --- .../app/components/Session_/Player/Player.js | 4 +- .../DevTools/ConsolePanel/ConsolePanel.tsx | 2 +- .../DevTools/NetworkPanel/NetworkPanel.tsx | 6 +- .../StackEventPanel/StackEventPanel.tsx | 183 ++++++++++++++++++ .../shared/DevTools/StackEventPanel/index.ts | 1 + .../DevTools/StackEventRow/StackEventRow.tsx | 8 +- frontend/app/mstore/sessionStore.ts | 17 +- 7 files changed, 208 insertions(+), 13 deletions(-) create mode 100644 frontend/app/components/shared/DevTools/StackEventPanel/StackEventPanel.tsx create mode 100644 frontend/app/components/shared/DevTools/StackEventPanel/index.ts diff --git a/frontend/app/components/Session_/Player/Player.js b/frontend/app/components/Session_/Player/Player.js index 48d881c29..96a4859cf 100644 --- a/frontend/app/components/Session_/Player/Player.js +++ b/frontend/app/components/Session_/Player/Player.js @@ -42,6 +42,7 @@ import { updateLastPlayedSession } from 'Duck/sessions'; import OverviewPanel from '../OverviewPanel'; import ConsolePanel from 'Shared/DevTools/ConsolePanel'; import ProfilerPanel from 'Shared/DevTools/ProfilerPanel'; +import StackEventPanel from 'Shared/DevTools/StackEventPanel'; @connectPlayer((state) => ({ live: state.live, @@ -115,7 +116,8 @@ export default class Player extends React.PureComponent { // )} - {bottomBlock === STACKEVENTS && } + {/* {bottomBlock === STACKEVENTS && } */} + {bottomBlock === STACKEVENTS && } {bottomBlock === STORAGE && } {bottomBlock === PROFILER && } {bottomBlock === PERFORMANCE && } diff --git a/frontend/app/components/shared/DevTools/ConsolePanel/ConsolePanel.tsx b/frontend/app/components/shared/DevTools/ConsolePanel/ConsolePanel.tsx index 8f5835cfa..efc4f735a 100644 --- a/frontend/app/components/shared/DevTools/ConsolePanel/ConsolePanel.tsx +++ b/frontend/app/components/shared/DevTools/ConsolePanel/ConsolePanel.tsx @@ -95,7 +95,7 @@ function ConsolePanel(props: Props) { ); }; - let filtered = React.useMemo(() => { + const filtered = React.useMemo(() => { const filterRE = getRE(filter, 'i'); let list = logs; diff --git a/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx b/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx index 6be39a77a..ee0ce8a55 100644 --- a/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx +++ b/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx @@ -233,9 +233,9 @@ 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); - }); + // list = list.sort((a: any, b: any) => { + // return compare(a, b, sortBy); + // }); // if (!sortAscending) { // list = list.reverse(); diff --git a/frontend/app/components/shared/DevTools/StackEventPanel/StackEventPanel.tsx b/frontend/app/components/shared/DevTools/StackEventPanel/StackEventPanel.tsx new file mode 100644 index 000000000..57abe1808 --- /dev/null +++ b/frontend/app/components/shared/DevTools/StackEventPanel/StackEventPanel.tsx @@ -0,0 +1,183 @@ +import React, { useEffect, useMemo, useRef, useState } from 'react'; +import { hideHint } from 'Duck/components/player'; +import { Tooltip, Tabs, Input, NoContent, Icon, Toggler } from 'UI'; +import { getRE } from 'App/utils'; +import { List, CellMeasurer, CellMeasurerCache, AutoSizer } from 'react-virtualized'; + +import TimeTable from '../TimeTable'; +import BottomBlock from '../BottomBlock'; +import { connectPlayer, jump } from 'Player'; +import { useModal } from 'App/components/Modal'; +import { useStore } from 'App/mstore'; +import { useObserver } from 'mobx-react-lite'; +import { DATADOG, SENTRY, STACKDRIVER, typeList } from 'Types/session/stackEvent'; +import { connect } from 'react-redux'; +import StackEventRow from 'Shared/DevTools/StackEventRow'; + +let timeOut: any = null; +const TIMEOUT_DURATION = 5000; +const INDEX_KEY = 'stackEvent'; +const ALL = 'ALL'; +const TABS = [ALL, ...typeList].map((tab) => ({ text: tab, key: tab })); + +interface Props { + list: any; + hideHint: any; + time: any; +} +function StackEventPanel(props: Props) { + const { list, time } = props; + const additionalHeight = 0; + 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({}); + synRef.current = { + pauseSync, + activeIndex, + }; + const _list = React.useRef(); + + const onTabClick = (activeTab: any) => devTools.update(INDEX_KEY, { activeTab }); + const onFilterChange = ({ target: { value } }: any) => { + devTools.update(INDEX_KEY, { filter: value }); + }; + + const getCurrentIndex = () => { + return filteredList.filter((item: any) => item.time <= time).length - 1; + }; + + const removePause = () => { + clearTimeout(timeOut); + timeOut = setTimeout(() => { + devTools.update(INDEX_KEY, { index: getCurrentIndex() }); + setPauseSync(false); + }, TIMEOUT_DURATION); + }; + + useEffect(() => { + const currentIndex = getCurrentIndex(); + if (currentIndex !== activeIndex && !pauseSync) { + devTools.update(INDEX_KEY, { index: currentIndex }); + } + }, [time]); + + const onMouseLeave = () => { + if (isDetailsModalActive) return; + removePause(); + }; + + React.useMemo(() => { + const filterRE = getRE(filter, 'i'); + let list = props.list; + + list = list.filter( + ({ name, source }: any) => + (!!filter ? filterRE.test(name) : true) && (activeTab === ALL || activeTab === source) + ); + + setFilteredList(list); + }, [filter, activeTab]); + + const tabs = useMemo(() => { + return TABS.filter(({ key }) => key === ALL || list.some(({ source }: any) => key === source)); + }, []); + + const cache = new CellMeasurerCache({ + fixedWidth: true, + keyMapper: (index: number) => filteredList[index], + }); + + const _rowRenderer = ({ index, key, parent, style }: any) => { + const item = filteredList[index]; + + return ( + // @ts-ignore + + {() => ( + jump(item.time)} + /> + )} + + ); + }; + + return ( + setPauseSync(true)} + onMouseLeave={onMouseLeave} + > + +
+ Stack Events + +
+ +
+ + + + No Data +
+ } + size="small" + show={filteredList.length === 0} + > + + {({ height, width }: any) => ( + + )} + + + +
+ ); +} + +export default connect( + (state: any) => ({ + hintIsHidden: + state.getIn(['components', 'player', 'hiddenHints', 'stack']) || + !state.getIn(['site', 'list']).some((s: any) => s.stackIntegrations), + }), + { hideHint } +)( + connectPlayer((state: any) => ({ + list: state.stackList, + time: state.time, + }))(StackEventPanel) +); diff --git a/frontend/app/components/shared/DevTools/StackEventPanel/index.ts b/frontend/app/components/shared/DevTools/StackEventPanel/index.ts new file mode 100644 index 000000000..bb0ca8cb6 --- /dev/null +++ b/frontend/app/components/shared/DevTools/StackEventPanel/index.ts @@ -0,0 +1 @@ +export { default } from './StackEventPanel'; diff --git a/frontend/app/components/shared/DevTools/StackEventRow/StackEventRow.tsx b/frontend/app/components/shared/DevTools/StackEventRow/StackEventRow.tsx index b6b1a8a6f..e5af72207 100644 --- a/frontend/app/components/shared/DevTools/StackEventRow/StackEventRow.tsx +++ b/frontend/app/components/shared/DevTools/StackEventRow/StackEventRow.tsx @@ -9,9 +9,11 @@ import StackEventModal from '../StackEventModal'; interface Props { event: any; onJump: any; + style?: any; + isActive?: boolean; } function StackEventRow(props: Props) { - const { event, onJump } = props; + const { event, onJump, style, isActive } = props; let message = event.payload[0] || ''; message = typeof message === 'string' ? message : JSON.stringify(message); const onClickDetails = () => { @@ -30,11 +32,13 @@ function StackEventRow(props: Props) { return (
diff --git a/frontend/app/mstore/sessionStore.ts b/frontend/app/mstore/sessionStore.ts index b947bd01a..f19f747fd 100644 --- a/frontend/app/mstore/sessionStore.ts +++ b/frontend/app/mstore/sessionStore.ts @@ -49,15 +49,20 @@ class UserFilter { } } -class DevTools { - networkIndex: 0; - network: any; +interface BaseDevState { + index: number; + filter: string; + activeTab: string; + isError: boolean; +} - consoleIndex: 0; - eventsIndex: 0; +class DevTools { + network: BaseDevState; + stackEvent: BaseDevState; constructor() { - this.network = { index: 0, search: '', activeTab: 'ALL', isError: false }; + this.network = { index: 0, filter: '', activeTab: 'ALL', isError: false }; + this.stackEvent = { index: 0, filter: '', activeTab: 'ALL', isError: false }; makeAutoObservable(this, { update: action, }); From 276d2bd10025cd8205d002952e2b3e11b17cded4 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Wed, 23 Nov 2022 18:51:01 +0100 Subject: [PATCH 4/5] change(ui) - events virutalize and sync --- .../DevTools/NetworkPanel/NetworkPanel.tsx | 5 +++-- .../StackEventPanel/StackEventPanel.tsx | 18 ++++++++++++++++-- .../DevTools/StackEventRow/StackEventRow.tsx | 9 ++------- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx b/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx index ee0ce8a55..1acb51ac2 100644 --- a/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx +++ b/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx @@ -141,7 +141,7 @@ interface Props { 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); @@ -161,7 +161,7 @@ function NetworkPanel(props: Props) { const [pauseSync, setPauseSync] = useState(activeIndex > 0); const synRef: any = useRef({}); - const onTabClick = (activeTab: any) => devTools.update(INDEX_KEY, { activeTab });; + const onTabClick = (activeTab: any) => devTools.update(INDEX_KEY, { activeTab }); const onFilterChange = ({ target: { value } }: any) => { devTools.update(INDEX_KEY, { filter: value }); }; @@ -172,6 +172,7 @@ function NetworkPanel(props: Props) { }; const removePause = () => { + setIsDetailsModalActive(false); clearTimeout(timeOut); timeOut = setTimeout(() => { devTools.update(INDEX_KEY, { index: getCurrentIndex() }); diff --git a/frontend/app/components/shared/DevTools/StackEventPanel/StackEventPanel.tsx b/frontend/app/components/shared/DevTools/StackEventPanel/StackEventPanel.tsx index 57abe1808..929a0e283 100644 --- a/frontend/app/components/shared/DevTools/StackEventPanel/StackEventPanel.tsx +++ b/frontend/app/components/shared/DevTools/StackEventPanel/StackEventPanel.tsx @@ -4,7 +4,6 @@ import { Tooltip, Tabs, Input, NoContent, Icon, Toggler } from 'UI'; import { getRE } from 'App/utils'; import { List, CellMeasurer, CellMeasurerCache, AutoSizer } from 'react-virtualized'; -import TimeTable from '../TimeTable'; import BottomBlock from '../BottomBlock'; import { connectPlayer, jump } from 'Player'; import { useModal } from 'App/components/Modal'; @@ -13,6 +12,7 @@ import { useObserver } from 'mobx-react-lite'; import { DATADOG, SENTRY, STACKDRIVER, typeList } from 'Types/session/stackEvent'; import { connect } from 'react-redux'; import StackEventRow from 'Shared/DevTools/StackEventRow'; +import StackEventModal from '../StackEventModal'; let timeOut: any = null; const TIMEOUT_DURATION = 5000; @@ -31,6 +31,7 @@ function StackEventPanel(props: Props) { const { sessionStore: { devTools }, } = useStore(); + const { showModal } = useModal(); const [isDetailsModalActive, setIsDetailsModalActive] = useState(false); const [filteredList, setFilteredList] = useState([]); const filter = useObserver(() => devTools[INDEX_KEY].filter); @@ -55,6 +56,7 @@ function StackEventPanel(props: Props) { const removePause = () => { clearTimeout(timeOut); + setIsDetailsModalActive(false); timeOut = setTimeout(() => { devTools.update(INDEX_KEY, { index: getCurrentIndex() }); setPauseSync(false); @@ -94,6 +96,13 @@ function StackEventPanel(props: Props) { keyMapper: (index: number) => filteredList[index], }); + const showDetails = (item: any) => { + setIsDetailsModalActive(true); + showModal(, { right: true, onClose: removePause }); + devTools.update(INDEX_KEY, { index: filteredList.indexOf(item) }); + setPauseSync(true); + }; + const _rowRenderer = ({ index, key, parent, style }: any) => { const item = filteredList[index]; @@ -106,7 +115,12 @@ function StackEventPanel(props: Props) { style={style} key={item.key} event={item} - onJump={() => jump(item.time)} + onJump={() => { + setPauseSync(true); + devTools.update(INDEX_KEY, { index: filteredList.indexOf(item) }); + jump(item.time); + }} + onClick={() => showDetails(item)} /> )} diff --git a/frontend/app/components/shared/DevTools/StackEventRow/StackEventRow.tsx b/frontend/app/components/shared/DevTools/StackEventRow/StackEventRow.tsx index e5af72207..0d2eeb554 100644 --- a/frontend/app/components/shared/DevTools/StackEventRow/StackEventRow.tsx +++ b/frontend/app/components/shared/DevTools/StackEventRow/StackEventRow.tsx @@ -3,23 +3,18 @@ import JumpButton from '../JumpButton'; import { Icon } from 'UI'; import cn from 'classnames'; import { OPENREPLAY, SENTRY, DATADOG, STACKDRIVER } from 'Types/session/stackEvent'; -import { useModal } from 'App/components/Modal'; -import StackEventModal from '../StackEventModal'; interface Props { event: any; onJump: any; style?: any; isActive?: boolean; + onClick?: any; } function StackEventRow(props: Props) { const { event, onJump, style, isActive } = props; let message = event.payload[0] || ''; message = typeof message === 'string' ? message : JSON.stringify(message); - const onClickDetails = () => { - showModal(, { right: true }); - }; - const { showModal } = useModal(); const iconProps: any = React.useMemo(() => { const { source } = event; @@ -34,7 +29,7 @@ function StackEventRow(props: Props) {
Date: Wed, 23 Nov 2022 19:47:10 +0100 Subject: [PATCH 5/5] change(ui) - console sync --- .../DevTools/ConsolePanel/ConsolePanel.tsx | 129 +++++++++++++++--- .../shared/DevTools/ConsoleRow/ConsoleRow.tsx | 26 ++-- .../DevTools/NetworkPanel/NetworkPanel.tsx | 26 +--- .../StackEventPanel/StackEventPanel.tsx | 8 +- .../shared/DevTools/TimeTable/TimeTable.tsx | 10 -- frontend/app/mstore/sessionStore.ts | 2 + 6 files changed, 131 insertions(+), 70 deletions(-) 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, });