Skip to content

Commit

Permalink
Merge pull request #151 from jizhang27/subscription_enhancements
Browse files Browse the repository at this point in the history
subscription: allow websocket url filter & toggle full message rendering
  • Loading branch information
warrenday authored Oct 14, 2024
2 parents 7457217 + 41179e7 commit baef1c5
Show file tree
Hide file tree
Showing 12 changed files with 333 additions and 180 deletions.
5 changes: 5 additions & 0 deletions src/containers/Main/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,19 @@ import { NetworkPanel } from '../NetworkPanel'
import { SearchPanel } from '../SearchPanel'
import { useWebSocketNetworkMonitor } from '../../hooks/useWebSocketNetworkMonitor'
import { useOperationFilters } from '../../hooks/useOperationFilters'
import useUserSettings from '../../hooks/useUserSettings'

export const Main = () => {
const [selectedRowId, setSelectedRowId] = useState<string | number | null>(
null
)
const { operationFilters } = useOperationFilters()
const [userSettings, setUserSettings] = useUserSettings()
const [networkRequests, clearWebRequests] = useNetworkMonitor()
const [webSocketNetworkRequests, clearWebSocketNetworkRequests] =
useWebSocketNetworkMonitor({
isEnabled: operationFilters.subscription,
urlFilter: userSettings.websocketUrlFilter
})
const { isSearchOpen } = useSearch()
const { setActiveTab } = useNetworkTabs()
Expand Down Expand Up @@ -54,6 +57,8 @@ export const Main = () => {
clearWebRequests={clearRequests}
selectedRowId={selectedRowId}
setSelectedRowId={setSelectedRowId}
userSettings={userSettings}
setUserSettings={setUserSettings}
/>
}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import * as safeJson from "@/helpers/safeJson"

interface IMessageViewProps {
messages: IWebSocketMessage[]
showFullMessage: boolean
}

/**
Expand All @@ -21,12 +22,12 @@ const getReadableTime = (time: number): string => {
}

const MessageView = React.memo((props: IMessageViewProps) => {
const { messages } = props
const { messages, showFullMessage } = props

return (
<Panels>
{messages.map((message, i) => {
const payload = JSON.stringify(message.data, null, 2)
const payload = JSON.stringify(showFullMessage ? message.data : message.data.payload, null, 2)
const isGraphQLQuery = message.type === "send" && message.data?.query

return (
Expand Down
5 changes: 3 additions & 2 deletions src/containers/NetworkPanel/WebSocketNetworkDetails/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import MessageView from "./MessageView"
interface WebSocketNetworkDetailsProps {
data: IWebSocketNetworkRequest
onClose: () => void
showFullMessage: boolean
}

const WebSocketNetworkDetails = (props: WebSocketNetworkDetailsProps) => {
const { data, onClose } = props
const { data, onClose, showFullMessage } = props
const { activeTab, setActiveTab } = useNetworkTabs()
const requestHeaders = data.request.headers
const responseHeaders = data.response?.headers || []
Expand Down Expand Up @@ -49,7 +50,7 @@ const WebSocketNetworkDetails = (props: WebSocketNetworkDetailsProps) => {
{
id: "messages",
title: "Messages",
component: <MessageView messages={data.messages} />,
component: <MessageView showFullMessage={showFullMessage} messages={data.messages} />,
},
]}
/>
Expand Down
31 changes: 17 additions & 14 deletions src/containers/NetworkPanel/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { fireEvent } from '@testing-library/react'
import { NetworkPanel } from './index'
import { render } from '../../test-utils'
import useUserSettings from '@/hooks/useUserSettings'

jest.mock('@/hooks/useHighlight', () => ({
useHighlight: () => ({
Expand All @@ -14,16 +15,24 @@ jest.mock('@/services/userSettingsService', () => ({
setUserSettings: jest.fn(),
}))

const NetworkPanelContainer = () => {
const [userSettings, setUserSettings] = useUserSettings();

return <NetworkPanel
userSettings={userSettings}
setUserSettings={setUserSettings}
selectedRowId={null}
setSelectedRowId={() => { }}
networkRequests={[]}
webSocketNetworkRequests={[]}
clearWebRequests={() => { }}
/>
}

describe('NetworkPanel', () => {
it('invalid regex is provided, regex mode is on - error message is rendered', () => {
const { getByTestId, getByText } = render(
<NetworkPanel
selectedRowId={null}
setSelectedRowId={() => {}}
networkRequests={[]}
webSocketNetworkRequests={[]}
clearWebRequests={() => {}}
/>
<NetworkPanelContainer />
)
const filterInput = getByTestId('filter-input')
const regexCheckbox = getByTestId('regex-checkbox')
Expand All @@ -42,13 +51,7 @@ describe('NetworkPanel', () => {

it('invalid regex is provided, regex mode is off - error message is not rendered', () => {
const { getByTestId, queryByText } = render(
<NetworkPanel
selectedRowId={null}
setSelectedRowId={() => {}}
networkRequests={[]}
webSocketNetworkRequests={[]}
clearWebRequests={() => {}}
/>
<NetworkPanelContainer />
)
const filterInput = getByTestId('filter-input')

Expand Down
18 changes: 15 additions & 3 deletions src/containers/NetworkPanel/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState, useEffect, useMemo } from 'react'
import { useState, useEffect, useMemo, SetStateAction, Dispatch } from 'react'
import RegexParser from 'regex-parser'
import { SplitPaneLayout } from '@/components/Layout'
import { onNavigate } from '@/services/networkMonitor'
Expand All @@ -12,15 +12,17 @@ import {
IOperationFilters,
useOperationFilters,
} from '../../hooks/useOperationFilters'
import useUserSettings from '../../hooks/useUserSettings'
import { IClearWebRequestsOptions } from '../../hooks/useNetworkMonitor'
import { IUserSettings } from '@/services/userSettingsService'

interface NetworkPanelProps {
selectedRowId: string | number | null
setSelectedRowId: (selectedRowId: string | number | null) => void
networkRequests: ICompleteNetworkRequest[]
webSocketNetworkRequests: IWebSocketNetworkRequest[]
clearWebRequests: (opts?: IClearWebRequestsOptions) => void
userSettings: IUserSettings
setUserSettings: (userSettings: Partial<IUserSettings>) => void
}

const getRegex = (str: string) => {
Expand Down Expand Up @@ -74,9 +76,10 @@ export const NetworkPanel = (props: NetworkPanelProps) => {
clearWebRequests,
selectedRowId,
setSelectedRowId,
userSettings,
setUserSettings,
} = props

const [userSettings, setUserSettings] = useUserSettings()
const { operationFilters } = useOperationFilters()

const { results: filteredNetworkRequests, errorMessage: filterError } =
Expand Down Expand Up @@ -177,6 +180,14 @@ export const NetworkPanel = (props: NetworkPanelProps) => {
onRegexActiveChange={(isRegexActive) => {
setUserSettings({ isRegexActive })
}}
websocketUrlFilter={userSettings.websocketUrlFilter}
onWebsocketUrlFilterChange={(websocketUrlFilter) => {
setUserSettings({ websocketUrlFilter })
}}
showFullWebsocketMessage={userSettings.shouldShowFullWebsocketMessage}
onShowFullWebsocketMessageChange={(shouldShowFullWebsocketMessage) => {
setUserSettings({ shouldShowFullWebsocketMessage })
}}
onClear={() => {
setSelectedRowId(null)
clearWebRequests()
Expand Down Expand Up @@ -208,6 +219,7 @@ export const NetworkPanel = (props: NetworkPanelProps) => {
)}
{selectedWebSocketRequest && (
<WebSocketNetworkDetails
showFullMessage={userSettings.shouldShowFullWebsocketMessage}
data={selectedWebSocketRequest}
onClose={() => {
setSelectedRowId(null)
Expand Down
173 changes: 103 additions & 70 deletions src/containers/Toolbar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { Checkbox } from "../../components/Checkbox"
import { Button } from "../../components/Button"
import { BinIcon } from "../../components/Icons/BinIcon"
import { SearchIcon } from "../../components/Icons/SearchIcon"
import { useSearch } from "../../hooks/useSearch"
import { Textfield } from "@/components/Textfield"
import { OverflowPopover } from "../../components/OverflowPopover"
import { Bar } from "../../components/Bar"
import { DocsIcon } from "../../components/Icons/DocsIcon"
import { Checkbox } from '../../components/Checkbox'
import { Button } from '../../components/Button'
import { BinIcon } from '../../components/Icons/BinIcon'
import { SearchIcon } from '../../components/Icons/SearchIcon'
import { useSearch } from '../../hooks/useSearch'
import { Textfield } from '@/components/Textfield'
import { OverflowPopover } from '../../components/OverflowPopover'
import { Bar } from '../../components/Bar'
import { DocsIcon } from '../../components/Icons/DocsIcon'
import { useOperationFilters } from '@/hooks/useOperationFilters'

interface IToolbarProps {
filterValue: string
Expand All @@ -17,6 +18,10 @@ interface IToolbarProps {
onInvertedChange: (inverted: boolean) => void
regexActive: boolean
onRegexActiveChange: (regexActive: boolean) => void
websocketUrlFilter: string
onWebsocketUrlFilterChange: (websocketUrlFilter: string) => void
showFullWebsocketMessage: boolean
onShowFullWebsocketMessageChange: (showFullWebsocketMessage: boolean) => void
onClear: () => void
}

Expand All @@ -30,74 +35,102 @@ export const Toolbar = (props: IToolbarProps) => {
onInvertedChange,
regexActive,
onRegexActiveChange,
websocketUrlFilter,
onWebsocketUrlFilterChange,
showFullWebsocketMessage,
onShowFullWebsocketMessageChange,
onClear,
} = props
const { setIsSearchOpen } = useSearch()
const { operationFilters } = useOperationFilters()

return (
<Bar testId="toolbar" className="border-b">
<Button
icon={<BinIcon />}
onClick={onClear}
testId="clear-network-table"
className="-mr-3 dark:text-gray-400 dark:hover:text-white"
variant="ghost"
/>
<Textfield
className="w-80"
value={filterValue}
onChange={(event) => onFilterValueChange(event.currentTarget.value)}
placeholder={regexActive ? "/ab+c/" : "Filter"}
testId="filter-input"
/>
<OverflowPopover
className="flex-1 space-x-6"
items={[
<Checkbox
id="invert"
label="Invert"
checked={inverted}
onChange={onInvertedChange}
testId="inverted-checkbox"
/>,
<Checkbox
id="regex"
label="Regex"
checked={regexActive}
onChange={onRegexActiveChange}
testId="regex-checkbox"
/>,
<Checkbox
id="preserveLog"
label="Preserve Log"
checked={preserveLogs}
onChange={onPreserveLogsChange}
testId="preserve-log-checkbox"
/>,
<Button
icon={<SearchIcon />}
onClick={() => setIsSearchOpen(true)}
testId="search-button"
variant="ghost"
className="text-gray-500 dark:text-gray-400 -ml-2"
>
Search
</Button>,
<a
href="https://www.overstacked.io/docs/graphql-network-inspector"
target="_blank"
>
<div>
<Bar testId="toolbar" className="border-b">
<Button
icon={<BinIcon />}
onClick={onClear}
testId="clear-network-table"
className="-mr-3 dark:text-gray-400 dark:hover:text-white"
variant="ghost"
/>
<Textfield
className="w-80"
value={filterValue}
onChange={(event) => onFilterValueChange(event.currentTarget.value)}
placeholder={regexActive ? '/ab+c/' : 'Filter'}
testId="filter-input"
/>
<OverflowPopover
className="flex-1 space-x-6"
items={[
<Checkbox
id="invert"
label="Invert"
checked={inverted}
onChange={onInvertedChange}
testId="inverted-checkbox"
/>,
<Checkbox
id="regex"
label="Regex"
checked={regexActive}
onChange={onRegexActiveChange}
testId="regex-checkbox"
/>,
<Checkbox
id="preserveLog"
label="Preserve Log"
checked={preserveLogs}
onChange={onPreserveLogsChange}
testId="preserve-log-checkbox"
/>,
<Button
icon={<DocsIcon />}
testId="docs-button"
icon={<SearchIcon />}
onClick={() => setIsSearchOpen(true)}
testId="search-button"
variant="ghost"
className="text-gray-500 dark:text-gray-400 -ml-2 whitespace-nowrap"
className="text-gray-500 dark:text-gray-400 -ml-2"
>
View Docs
</Button>
</a>,
]}
/>
</Bar>
Search
</Button>,
<a
href="https://www.overstacked.io/docs/graphql-network-inspector"
target="_blank"
>
<Button
icon={<DocsIcon />}
testId="docs-button"
variant="ghost"
className="text-gray-500 dark:text-gray-400 -ml-2 whitespace-nowrap"
>
View Docs
</Button>
</a>,
]}
/>
</Bar>
{operationFilters.subscription &&
<Bar testId="toolbar-websocket" className="border-b">
<span className="pl-3 font-bold">Websocket</span>
<Textfield
className="w-40"
value={websocketUrlFilter}
onChange={(event) =>
onWebsocketUrlFilterChange(event.currentTarget.value)
}
placeholder={'URL Filter'}
testId="websocket-url-filter-input"
/>
<Checkbox
id="showFullWebsocketMessage"
label="Show Full Message"
checked={showFullWebsocketMessage}
onChange={onShowFullWebsocketMessageChange}
testId="show-full-websocket-message-checkbox"
/>
</Bar>
}
</div>
)
}
Loading

0 comments on commit baef1c5

Please sign in to comment.