mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-20 16:43:53 +01:00
fix ws connection state (#175)
Co-authored-by: Gregory Schier <gschier1990@gmail.com>
This commit is contained in:
@@ -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' && (
|
||||
|
||||
@@ -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>•</span>
|
||||
<DurationTag
|
||||
headers={activeResponse.elapsedHeaders}
|
||||
|
||||
@@ -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">→</span>{' '}
|
||||
<span className="font-mono text-sm">{r.elapsed >= 0 ? `${r.elapsed}ms` : 'n/a'}</span>
|
||||
</HStack>
|
||||
|
||||
@@ -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>•</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>
|
||||
) : (
|
||||
|
||||
40
src-web/components/core/HttpStatusTag.tsx
Normal file
40
src-web/components/core/HttpStatusTag.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
31
src-web/components/core/WebsocketStatusTag.tsx
Normal file
31
src-web/components/core/WebsocketStatusTag.tsx
Normal 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>;
|
||||
}
|
||||
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user