A bit better handling of responses

This commit is contained in:
Gregory Schier
2024-02-02 13:32:06 -08:00
parent d8948bb061
commit 6c69fff27d
7 changed files with 168 additions and 120 deletions

View File

@@ -3,6 +3,7 @@ import classNames from 'classnames';
import { format } from 'date-fns';
import type { CSSProperties, FormEvent } from 'react';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useActiveRequestId } from '../hooks/useActiveRequestId';
import { useAlert } from '../hooks/useAlert';
import type { GrpcMessage } from '../hooks/useGrpc';
import { useGrpc } from '../hooks/useGrpc';
@@ -26,26 +27,31 @@ interface Props {
}
export function GrpcConnectionLayout({ style }: Props) {
const url = useKeyValue<string>({ namespace: 'debug', key: 'grpc_url', defaultValue: '' });
const activeRequestId = useActiveRequestId();
const url = useKeyValue<string>({
namespace: 'debug',
key: ['grpc_url', activeRequestId ?? ''],
defaultValue: '',
});
const alert = useAlert();
const service = useKeyValue<string | null>({
namespace: 'debug',
key: 'grpc_service',
key: ['grpc_service', activeRequestId ?? ''],
defaultValue: null,
});
const method = useKeyValue<string | null>({
namespace: 'debug',
key: 'grpc_method',
key: ['grpc_method', activeRequestId ?? ''],
defaultValue: null,
});
const message = useKeyValue<string>({
namespace: 'debug',
key: 'grpc_message',
key: ['grpc_message', activeRequestId ?? ''],
defaultValue: '',
});
const [activeMessage, setActiveMessage] = useState<GrpcMessage | null>(null);
const [resp, setResp] = useState<string>('');
const grpc = useGrpc(url.value ?? null);
const grpc = useGrpc(url.value ?? null, activeRequestId);
const activeMethod = useMemo(() => {
if (grpc.schema == null) return null;
@@ -105,6 +111,7 @@ export function GrpcConnectionLayout({ style }: Props) {
);
useEffect(() => {
console.log('GrpcConnectionLayout');
if (grpc.schema == null) return;
const s = grpc.schema.find((s) => s.name === service.value);
if (s == null) {
@@ -167,11 +174,10 @@ export function GrpcConnectionLayout({ style }: Props) {
)}
>
<UrlBar
id="foo"
url={url.value ?? ''}
method={null}
submitIcon={null}
forceUpdateKey="to-do"
forceUpdateKey={activeRequestId ?? ''}
placeholder="localhost:50051"
onSubmit={handleConnect}
isLoading={grpc.unary.isLoading}
@@ -231,7 +237,7 @@ export function GrpcConnectionLayout({ style }: Props) {
</div>
{!service.isLoading && !method.isLoading && (
<GrpcEditor
forceUpdateKey={[service, method].join('::')}
forceUpdateKey={activeRequestId ?? ''}
url={url.value ?? ''}
defaultValue={message.value}
onChange={message.set}
@@ -255,16 +261,16 @@ export function GrpcConnectionLayout({ style }: Props) {
<Banner color="danger" className="m-2">
{grpc.unary.error}
</Banner>
) : grpc.messages.length > 0 ? (
) : (grpc.messages.value ?? []).length > 0 ? (
<SplitLayout
name="grpc_messages2"
minHeightPx={20}
defaultRatio={0.25}
leftSlot={() => (
<div className="overflow-y-auto">
{...grpc.messages.map((m, i) => (
{...(grpc.messages.value ?? []).map((m, i) => (
<HStack
key={`${m.time.getTime()}::${m.message}::${i}`}
key={`${m.timestamp}::${m.message}::${i}`}
space={2}
onClick={() => {
if (m === activeMessage) setActiveMessage(null);
@@ -292,25 +298,29 @@ export function GrpcConnectionLayout({ style }: Props) {
: 'info'
}
/>
<div className="w-full truncate text-gray-800 text-xs">{m.message}</div>
<div className="text-gray-600 text-2xs" title={m.time.toISOString()}>
{format(m.time, 'HH:mm:ss')}
<div className="w-full truncate text-gray-800 text-2xs">{m.message}</div>
<div className="text-gray-600 text-2xs">
{format(m.timestamp, 'HH:mm:ss')}
</div>
</HStack>
))}
</div>
)}
rightSlot={() =>
activeMessage && (
<div className="grid grid-rows-[auto_minmax(0,1fr)]">
<div className="pb-3 px-2">
<Separator />
</div>
<div className="pl-2 overflow-y-auto">
<JsonAttributeTree attrValue={JSON.parse(activeMessage?.message ?? '{}')} />
</div>
</div>
)
rightSlot={
!activeMessage
? null
: () => (
<div className="grid grid-rows-[auto_minmax(0,1fr)]">
<div className="pb-3 px-2">
<Separator />
</div>
<div className="pl-2 overflow-y-auto">
<JsonAttributeTree
attrValue={JSON.parse(activeMessage?.message ?? '{}')}
/>
</div>
</div>
)
}
/>
) : resp ? (

View File

@@ -209,8 +209,6 @@ export const RequestPane = memo(function RequestPane({ style, fullHeight, classN
{activeRequest && (
<>
<UrlBar
key={activeRequest.id} // Force-reset the url bar when the active request changes
id={activeRequest.id}
url={activeRequest.url}
method={activeRequest.method}
placeholder="https://example.com"

View File

@@ -8,7 +8,7 @@ import { IconButton } from './core/IconButton';
import { Input } from './core/Input';
import { RequestMethodDropdown } from './RequestMethodDropdown';
type Props = Pick<HttpRequest, 'id' | 'url'> & {
type Props = Pick<HttpRequest, 'url'> & {
className?: string;
method: HttpRequest['method'] | null;
placeholder: string;

View File

@@ -17,7 +17,7 @@ interface SlotProps {
interface Props {
name: string;
leftSlot: (props: SlotProps) => ReactNode;
rightSlot: (props: SlotProps) => ReactNode;
rightSlot: null | ((props: SlotProps) => ReactNode);
style?: CSSProperties;
className?: string;
defaultRatio?: number;
@@ -48,33 +48,37 @@ export function SplitLayout({
`${name}_height::${useActiveWorkspaceId()}`,
);
const width = widthRaw ?? defaultRatio;
const height = heightRaw ?? defaultRatio;
let height = heightRaw ?? defaultRatio;
const [isResizing, setIsResizing] = useState<boolean>(false);
const moveState = useRef<{ move: (e: MouseEvent) => void; up: (e: MouseEvent) => void } | null>(
null,
);
if (!rightSlot) {
height = 0;
minHeightPx = 0;
}
useResizeObserver(containerRef.current, ({ contentRect }) => {
setVertical(contentRect.width < STACK_VERTICAL_WIDTH);
});
const styles = useMemo<CSSProperties>(
() => ({
const styles = useMemo<CSSProperties>(() => {
return {
...style,
gridTemplate: vertical
? `
' ${areaL.gridArea}' minmax(0,${1 - height}fr)
' ${areaD.gridArea}' 0
' ${areaR.gridArea}' minmax(${minHeightPx}px,${height}fr)
/ 1fr
`
' ${areaL.gridArea}' minmax(0,${1 - height}fr)
' ${areaD.gridArea}' 0
' ${areaR.gridArea}' minmax(${minHeightPx}px,${height}fr)
/ 1fr
`
: `
' ${areaL.gridArea} ${areaD.gridArea} ${areaR.gridArea}' minmax(0,1fr)
/ ${1 - width}fr 0 ${width}fr
`,
}),
[vertical, width, height, style],
);
' ${areaL.gridArea} ${areaD.gridArea} ${areaR.gridArea}' minmax(0,1fr)
/ ${1 - width}fr 0 ${width}fr
`,
};
}, [style, vertical, height, minHeightPx, width]);
const unsub = () => {
if (moveState.current !== null) {
@@ -142,17 +146,21 @@ export function SplitLayout({
return (
<div ref={containerRef} className={classNames(className, 'grid w-full h-full')} style={styles}>
{leftSlot({ style: areaL, orientation: vertical ? 'vertical' : 'horizontal' })}
<ResizeHandle
style={areaD}
isResizing={isResizing}
barClassName={'bg-red-300'}
className={classNames(vertical ? 'translate-y-0.5' : 'translate-x-0.5')}
onResizeStart={handleResizeStart}
onReset={handleReset}
side={vertical ? 'top' : 'left'}
justify="center"
/>
{rightSlot({ style: areaR, orientation: vertical ? 'vertical' : 'horizontal' })}
{rightSlot && (
<>
<ResizeHandle
style={areaD}
isResizing={isResizing}
barClassName={'bg-red-300'}
className={classNames(vertical ? 'translate-y-0.5' : 'translate-x-0.5')}
onResizeStart={handleResizeStart}
onReset={handleReset}
side={vertical ? 'top' : 'left'}
justify="center"
/>
{rightSlot({ style: areaR, orientation: vertical ? 'vertical' : 'horizontal' })}
</>
)}
</div>
);
}