From e5fd1b235e107a91060898a1e2729255451c28d4 Mon Sep 17 00:00:00 2001 From: nick-delirium Date: Wed, 25 Sep 2024 15:06:11 +0200 Subject: [PATCH] ui: redesigned ws panel --- .../DevTools/NetworkPanel/NetworkPanel.tsx | 22 +-- .../shared/DevTools/NetworkPanel/WSPanel.tsx | 165 ++++++++++++++++++ .../DevTools/TimeTable/timeTable.module.css | 2 +- frontend/app/components/ui/Icon/Icon.tsx | 1 + frontend/app/utils/index.ts | 3 +- 5 files changed, 179 insertions(+), 14 deletions(-) create mode 100644 frontend/app/components/shared/DevTools/NetworkPanel/WSPanel.tsx diff --git a/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx b/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx index 28a638f6f..ee6b26190 100644 --- a/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx +++ b/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx @@ -17,6 +17,7 @@ import { formatBytes } from 'App/utils'; import { Icon, Input, NoContent, Tabs, Toggler, Tooltip } from 'UI'; import FetchDetailsModal from 'Shared/FetchDetailsModal'; +import { WsChannel } from "App/player/web/messages"; import BottomBlock from '../BottomBlock'; import InfoLine from '../BottomBlock/InfoLine'; @@ -24,6 +25,7 @@ import TimeTable from '../TimeTable'; import useAutoscroll, { getLastItemTime } from '../useAutoscroll'; import { useRegExListFilterMemo, useTabListFilterMemo } from '../useListFilter'; import WSModal from './WSModal'; +import WSPanel from './WSPanel'; const INDEX_KEY = 'network'; @@ -191,7 +193,6 @@ function NetworkPanelCont({ zoomEndTs: number; }) { const { player, store } = React.useContext(PlayerContext); - const { domContentLoadedTime, loadTime, @@ -334,9 +335,8 @@ export const NetworkPanelComp = observer( activeOutsideIndex, isSpot, }: Props) => { + const [selectedWsChannel, setSelectedWsChannel] = React.useState(null) const { showModal } = useModal(); - const [sortBy, setSortBy] = useState('time'); - const [sortAscending, setSortAscending] = useState(true); const [showOnlyErrors, setShowOnlyErrors] = useState(false); const [isDetailsModalActive, setIsDetailsModalActive] = useState(false); @@ -491,13 +491,10 @@ export const NetworkPanelComp = observer( const showDetailsModal = (item: any) => { if (item.type === 'websocket') { const socketMsgList = websocketList.filter( - (ws) => ws.channelName === item.channelName - ); + (ws) => ws.channelName === item.channelName + ); - return showModal(, { - right: true, - width: 700, - }); + return setSelectedWsChannel(socketMsgList) } setIsDetailsModalActive(true); showModal( @@ -617,8 +614,8 @@ export const NetworkPanelComp = observer( referenceLines={referenceLines} renderPopup onRowClick={showDetailsModal} - sortBy={sortBy} - sortAscending={sortAscending} + sortBy={'time'} + sortAscending onJump={(row: any) => { devTools.update(INDEX_KEY, { index: filteredList.indexOf(row), @@ -671,6 +668,9 @@ export const NetworkPanelComp = observer( }, ]} + {selectedWsChannel ? ( + setSelectedWsChannel(null)} /> + ) : null} diff --git a/frontend/app/components/shared/DevTools/NetworkPanel/WSPanel.tsx b/frontend/app/components/shared/DevTools/NetworkPanel/WSPanel.tsx new file mode 100644 index 000000000..b17395eab --- /dev/null +++ b/frontend/app/components/shared/DevTools/NetworkPanel/WSPanel.tsx @@ -0,0 +1,165 @@ +import { Timed } from 'Player'; +import React from 'react'; + +import { durationFromMs } from 'App/date'; +import { filterList } from 'App/utils'; +import { CopyButton, Icon, Input } from 'UI'; + +type SocketMsg = Timed & { + channelName: string; + data: string; + timestamp: number; + dir: 'up' | 'down'; + messageType: string; +}; + +interface Props { + socketMsgList: Array; + onClose: () => void; +} + +const lineLength = 40; + +function WSPanel({ socketMsgList, onClose }: Props) { + const [query, setQuery] = React.useState(''); + const [list, setList] = React.useState(socketMsgList); + const [selectedRow, setSelectedRow] = React.useState(null); + + const onQueryChange = (e) => { + setQuery(e.target.value); + const newList = filterList(socketMsgList, e.target.value, [ + 'data', + 'messageType', + ]); + setList(newList); + }; + return ( +
+
+ +
{socketMsgList[0].channelName}
+
+ +
+
+
+
Data
+
Length
+
Time
+
+
+ {list.map((msg) => ( + setSelectedRow(msg)} + /> + ))} + {selectedRow ? ( + setSelectedRow(null)} /> + ) : null} +
+
+ ); +} + +function SelectedRow({ + msg, + onClose, +}: { + msg: SocketMsg; + onClose: () => void; +}) { + const content = React.useMemo(() => { + return JSON.stringify(msg, null, 2); + }, []); + return ( +
+
+ + {msg.messageType} +
+ +
+
+
{msg.data}
+
+ ); +} + +function MsgDirection({ dir }: { dir: 'up' | 'down' }) { + return ( + + ); +} + +function Row({ msg, onSelect }: { msg: SocketMsg; onSelect: () => void }) { + return ( + <> +
+
+ + {msg.messageType} + + {msg.data} + + {msg.data.length > lineLength ? ( +
+ {isOpen ? '-' : '+'} +
+ ) : null} +
+
{msg.data.length}
+
+ {durationFromMs(msg.time, true)} +
+
+ + ); +} + +export default WSPanel; diff --git a/frontend/app/components/shared/DevTools/TimeTable/timeTable.module.css b/frontend/app/components/shared/DevTools/TimeTable/timeTable.module.css index 46c54bc03..0f40d05ec 100644 --- a/frontend/app/components/shared/DevTools/TimeTable/timeTable.module.css +++ b/frontend/app/components/shared/DevTools/TimeTable/timeTable.module.css @@ -40,7 +40,7 @@ $offset: 10px; width: 1px; } scrollbar-width: thin; - font-size: 12px; + font-size: 14px; font-family: 'Menlo', 'monaco', 'consolas', monospace; } diff --git a/frontend/app/components/ui/Icon/Icon.tsx b/frontend/app/components/ui/Icon/Icon.tsx index 74e91e1ed..20354a973 100644 --- a/frontend/app/components/ui/Icon/Icon.tsx +++ b/frontend/app/components/ui/Icon/Icon.tsx @@ -13,6 +13,7 @@ interface IProps { style?: object marginRight?: number inline?: boolean + onClick?: () => void } const Icon: React.FunctionComponent = ({ diff --git a/frontend/app/utils/index.ts b/frontend/app/utils/index.ts index 513bd584d..03419fa72 100644 --- a/frontend/app/utils/index.ts +++ b/frontend/app/utils/index.ts @@ -87,10 +87,9 @@ export const filterList = >( ): T[] => { if (searchQuery === '') return list; const filterRE = getRE(searchQuery, 'i'); - let _list = list.filter((listItem: T) => { + return list.filter((listItem: T) => { return testKeys.some((key) => filterRE.test(listItem[key])) || searchCb?.(listItem, filterRE); }); - return _list; }; export const getStateColor = (state) => {