fix ws connection state (#175)

Co-authored-by: Gregory Schier <gschier1990@gmail.com>
This commit is contained in:
Hao Xiang
2025-03-09 00:03:16 +08:00
committed by GitHub
parent f4d0371060
commit cdce2ac53a
17 changed files with 260 additions and 184 deletions

View File

@@ -67,7 +67,7 @@ export function GrpcConnectionMessagesPane({ style, methodType, activeRequest }:
firstSlot={() =>
activeConnection && (
<div className="w-full grid grid-rows-[auto_minmax(0,1fr)] items-center">
<HStack className="pl-3 mb-1 font-mono text-sm">
<HStack className="pl-3 mb-1 font-mono text-sm text-text-subtle">
<HStack space={2}>
<span>{events.length} Messages</span>
{activeConnection.state !== 'closed' && (

View File

@@ -14,7 +14,7 @@ import { HotKeyList } from './core/HotKeyList';
import { LoadingIcon } from './core/LoadingIcon';
import { SizeTag } from './core/SizeTag';
import { HStack } from './core/Stacks';
import { StatusTag } from './core/StatusTag';
import { HttpStatusTag } from './core/HttpStatusTag';
import type { TabItem } from './core/Tabs/Tabs';
import { TabContent, Tabs } from './core/Tabs/Tabs';
import { EmptyStateText } from './EmptyStateText';
@@ -121,7 +121,7 @@ export function HttpResponsePane({ style, className, activeRequestId }: Props) {
)}
>
{activeResponse.state !== 'closed' && <LoadingIcon size="sm" />}
<StatusTag showReason response={activeResponse} />
<HttpStatusTag showReason response={activeResponse} />
<span>&bull;</span>
<DurationTag
headers={activeResponse.elapsedHeaders}

View File

@@ -8,7 +8,7 @@ import { Dropdown } from './core/Dropdown';
import { Icon } from './core/Icon';
import { IconButton } from './core/IconButton';
import { HStack } from './core/Stacks';
import { StatusTag } from './core/StatusTag';
import { HttpStatusTag } from './core/HttpStatusTag';
interface Props {
responses: HttpResponse[];
@@ -68,7 +68,7 @@ export const RecentHttpResponsesDropdown = function ResponsePane({
...responses.map((r: HttpResponse) => ({
label: (
<HStack space={2}>
<StatusTag className="text-sm" response={r} />
<HttpStatusTag className="text-sm" response={r} />
<span className="text-text-subtle">&rarr;</span>{' '}
<span className="font-mono text-sm">{r.elapsed >= 0 ? `${r.elapsed}ms` : 'n/a'}</span>
</HStack>

View File

@@ -19,7 +19,7 @@ import { LoadingIcon } from './core/LoadingIcon';
import { Separator } from './core/Separator';
import { SplitLayout } from './core/SplitLayout';
import { HStack, VStack } from './core/Stacks';
import { StatusTag } from './core/StatusTag';
import { WebsocketStatusTag } from './core/WebsocketStatusTag';
import { EmptyStateText } from './EmptyStateText';
import { RecentWebsocketConnectionsDropdown } from './RecentWebsocketConnectionsDropdown';
@@ -69,12 +69,12 @@ export function WebsocketResponsePane({ activeRequest }: Props) {
firstSlot={() =>
activeConnection && (
<div className="w-full grid grid-rows-[auto_minmax(0,1fr)] items-center">
<HStack className="pl-3 mb-1 font-mono text-sm">
<HStack className="pl-3 mb-1 font-mono text-sm text-text-subtle">
<HStack space={2}>
{activeConnection.state !== 'closed' && (
<LoadingIcon size="sm" className="text-text-subtlest" />
)}
<StatusTag showReason response={activeConnection} />
<WebsocketStatusTag connection={activeConnection} />
<span>&bull;</span>
<span>{events.length} Messages</span>
</HStack>
@@ -122,7 +122,9 @@ export function WebsocketResponsePane({ activeRequest }: Props) {
<div className="font-semibold">
{activeEvent.messageType === 'close'
? 'Connection Closed'
: `Message ${activeEvent.isServer ? 'Received' : 'Sent'}`}
: activeEvent.messageType === 'open'
? 'Connection open'
: `Message ${activeEvent.isServer ? 'Received' : 'Sent'}`}
</div>
{message != '' && (
<HStack space={1}>
@@ -212,9 +214,15 @@ function EventRow({
)}
>
<Icon
color={messageType === 'close' ? 'secondary' : isServer ? 'info' : 'primary'}
color={
messageType === 'close' || messageType === 'open'
? 'secondary'
: isServer
? 'info'
: 'primary'
}
icon={
messageType === 'close'
messageType === 'close' || messageType === 'open'
? 'info'
: isServer
? 'arrow_big_down_dash'
@@ -223,7 +231,9 @@ function EventRow({
/>
<div className={classNames('w-full truncate text-xs')}>
{messageType === 'close' ? (
'Connection closed by ' + (isServer ? 'server' : 'client')
'Disconnected from server'
) : messageType === 'open' ? (
'Connected to server'
) : message === '' ? (
<em className="italic text-text-subtlest">No content</em>
) : (

View File

@@ -0,0 +1,40 @@
import type { HttpResponse } from '@yaakapp-internal/models';
import classNames from 'classnames';
interface Props {
response: HttpResponse;
className?: string;
showReason?: boolean;
}
export function HttpStatusTag({ response, className, showReason }: Props) {
const { status, state } = response;
let colorClass;
let label = `${status}`;
if (state === 'initialized') {
label = 'CONNECTING';
colorClass = 'text-text-subtle';
} else if (status < 100) {
label = 'ERROR';
colorClass = 'text-danger';
} else if (status < 200) {
colorClass = 'text-info';
} else if (status < 300) {
colorClass = 'text-success';
} else if (status < 400) {
colorClass = 'text-primary';
} else if (status < 500) {
colorClass = 'text-warning';
} else {
colorClass = 'text-danger';
}
return (
<span className={classNames(className, 'font-mono', colorClass)}>
{label}{' '}
{showReason && 'statusReason' in response ? response.statusReason : null}
</span>
);
}

View File

@@ -1,34 +0,0 @@
import type {HttpResponse, WebsocketConnection} from '@yaakapp-internal/models';
import classNames from 'classnames';
interface Props {
response: HttpResponse | WebsocketConnection;
className?: string;
showReason?: boolean;
}
export function StatusTag({ response, className, showReason }: Props) {
const { status, state } = response;
const label = status < 100 ? 'ERROR' : status;
const category = `${status}`[0];
const isInitializing = state === 'initialized';
return (
<span
className={classNames(
className,
'font-mono',
!isInitializing && category === '0' && 'text-danger',
!isInitializing && category === '1' && 'text-info',
!isInitializing && category === '2' && 'text-success',
!isInitializing && category === '3' && 'text-primary',
!isInitializing && category === '4' && 'text-warning',
!isInitializing && category === '5' && 'text-danger',
isInitializing && 'text-text-subtle',
)}
>
{isInitializing ? 'CONNECTING' : label}{' '}
{showReason && 'statusReason' in response ? response.statusReason : null}
</span>
);
}

View File

@@ -0,0 +1,31 @@
import type { WebsocketConnection } from '@yaakapp-internal/models';
import classNames from 'classnames';
interface Props {
connection: WebsocketConnection;
className?: string;
}
export function WebsocketStatusTag({ connection, className }: Props) {
const { state, error } = connection;
let label;
let colorClass = 'text-text-subtle';
if (error) {
label = 'ERROR';
colorClass = 'text-danger';
} else if (state === 'connected') {
label = 'CONNECTED';
colorClass = 'text-success';
} else if (state === 'closing') {
label = 'CLOSING';
} else if (state === 'closed') {
label = 'CLOSED';
colorClass = 'text-warning';
} else {
label = 'CONNECTING';
}
return <span className={classNames(className, 'font-mono', colorClass)}>{label}</span>;
}

View File

@@ -23,7 +23,7 @@ import { jotaiStore } from '../../lib/jotai';
import { HttpMethodTag } from '../core/HttpMethodTag';
import { Icon } from '../core/Icon';
import { LoadingIcon } from '../core/LoadingIcon';
import { StatusTag } from '../core/StatusTag';
import { HttpStatusTag } from '../core/HttpStatusTag';
import type { SidebarTreeNode } from './Sidebar';
import { sidebarSelectedIdAtom } from './SidebarAtoms';
import { SidebarItemContextMenu } from './SidebarItemContextMenu';
@@ -305,7 +305,7 @@ export const SidebarItem = memo(function SidebarItem({
{latestHttpResponse.state !== 'closed' ? (
<LoadingIcon size="sm" className="text-text-subtlest" />
) : (
<StatusTag className="text-xs" response={latestHttpResponse} />
<HttpStatusTag className="text-xs" response={latestHttpResponse} />
)}
</div>
) : null}