mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-01-11 20:00:29 +01:00
Response info in new tab
This commit is contained in:
@@ -1,8 +1,5 @@
|
||||
import { open } from '@tauri-apps/plugin-shell';
|
||||
import type { HttpResponse } from '../lib/models';
|
||||
import { IconButton } from './core/IconButton';
|
||||
import { KeyValueRow, KeyValueRows } from './core/KeyValueRow';
|
||||
import { Separator } from './core/Separator';
|
||||
|
||||
interface Props {
|
||||
response: HttpResponse;
|
||||
@@ -13,33 +10,9 @@ export function ResponseHeaders({ response }: Props) {
|
||||
<div className="overflow-auto h-full pb-4">
|
||||
<KeyValueRows>
|
||||
{response.headers.map((h, i) => (
|
||||
<KeyValueRow key={i} label={h.name} value={h.value} labelClassName="!text-violet-600" />
|
||||
<KeyValueRow labelColor="primary" key={i} label={h.name} value={h.value} />
|
||||
))}
|
||||
</KeyValueRows>
|
||||
<Separator className="my-4">Other Info</Separator>
|
||||
<KeyValueRows>
|
||||
<KeyValueRow label="Version" value={response.version} />
|
||||
<KeyValueRow label="Remote Address" value={response.remoteAddr} />
|
||||
<KeyValueRow
|
||||
label={
|
||||
<div className="flex items-center">
|
||||
URL
|
||||
<IconButton
|
||||
iconSize="sm"
|
||||
className="inline-block w-auto ml-1 !h-auto opacity-50 hover:opacity-100"
|
||||
icon="externalLink"
|
||||
onClick={() => open(response.url)}
|
||||
title="Open in browser"
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
value={
|
||||
<div className="flex">
|
||||
<span className="select-text cursor-text">{response.url}</span>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</KeyValueRows>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
39
src-web/components/ResponseInfo.tsx
Normal file
39
src-web/components/ResponseInfo.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import { open } from '@tauri-apps/plugin-shell';
|
||||
import type { HttpResponse } from '../lib/models';
|
||||
import { IconButton } from './core/IconButton';
|
||||
import { KeyValueRow, KeyValueRows } from './core/KeyValueRow';
|
||||
|
||||
interface Props {
|
||||
response: HttpResponse;
|
||||
}
|
||||
|
||||
export function ResponseInfo({ response }: Props) {
|
||||
return (
|
||||
<div className="overflow-auto h-full pb-4">
|
||||
<KeyValueRows>
|
||||
<KeyValueRow labelColor="info" label="Version" value={response.version} />
|
||||
<KeyValueRow labelColor="info" label="Remote Address" value={response.remoteAddr} />
|
||||
<KeyValueRow
|
||||
labelColor="info"
|
||||
label={
|
||||
<div className="flex items-center">
|
||||
URL
|
||||
<IconButton
|
||||
iconSize="sm"
|
||||
className="inline-block w-auto ml-1 !h-auto opacity-50 hover:opacity-100"
|
||||
icon="externalLink"
|
||||
onClick={() => open(response.url)}
|
||||
title="Open in browser"
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
value={
|
||||
<div className="flex">
|
||||
<span className="select-text cursor-text">{response.url}</span>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</KeyValueRows>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import { TabContent, Tabs } from './core/Tabs/Tabs';
|
||||
import { EmptyStateText } from './EmptyStateText';
|
||||
import { RecentResponsesDropdown } from './RecentResponsesDropdown';
|
||||
import { ResponseHeaders } from './ResponseHeaders';
|
||||
import { ResponseInfo } from './ResponseInfo';
|
||||
import { AudioViewer } from './responseViewers/AudioViewer';
|
||||
import { CsvViewer } from './responseViewers/CsvViewer';
|
||||
import { ImageViewer } from './responseViewers/ImageViewer';
|
||||
@@ -46,7 +47,7 @@ export const ResponsePane = memo(function ResponsePane({ style, className, activ
|
||||
() => [
|
||||
{
|
||||
value: 'body',
|
||||
label: 'Preview',
|
||||
label: 'Preview Mode',
|
||||
options: {
|
||||
value: viewMode,
|
||||
onChange: setViewMode,
|
||||
@@ -67,6 +68,10 @@ export const ResponsePane = memo(function ResponsePane({ style, className, activ
|
||||
),
|
||||
value: 'headers',
|
||||
},
|
||||
{
|
||||
label: 'Info',
|
||||
value: 'info',
|
||||
},
|
||||
],
|
||||
[activeResponse?.headers, contentType, setViewMode, viewMode],
|
||||
);
|
||||
@@ -148,6 +153,9 @@ export const ResponsePane = memo(function ResponsePane({ style, className, activ
|
||||
<TabContent value="headers">
|
||||
<ResponseHeaders response={activeResponse} />
|
||||
</TabContent>
|
||||
<TabContent value="info">
|
||||
<ResponseInfo response={activeResponse} />
|
||||
</TabContent>
|
||||
<TabContent value="body">
|
||||
{!activeResponse.contentLength ? (
|
||||
<div className="pb-2 h-full">
|
||||
@@ -166,6 +174,8 @@ export const ResponsePane = memo(function ResponsePane({ style, className, activ
|
||||
) : viewMode === 'pretty' && contentType?.includes('html') ? (
|
||||
<WebPageViewer response={activeResponse} />
|
||||
) : (
|
||||
// ) : viewMode === 'pretty' && contentType?.includes('json') ? (
|
||||
// <JsonAttributeTree attrValue={activeResponse} />
|
||||
<TextViewer
|
||||
className="-mr-2" // Pull to the right
|
||||
response={activeResponse}
|
||||
|
||||
@@ -9,9 +9,16 @@ interface Props {
|
||||
attrValue: any;
|
||||
attrKey?: string | number;
|
||||
attrKeyJsonPath?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const JsonAttributeTree = ({ depth = 0, attrKey, attrValue, attrKeyJsonPath }: Props) => {
|
||||
export const JsonAttributeTree = ({
|
||||
depth = 0,
|
||||
attrKey,
|
||||
attrValue,
|
||||
attrKeyJsonPath,
|
||||
className,
|
||||
}: Props) => {
|
||||
attrKeyJsonPath = attrKeyJsonPath ?? `${attrKey}`;
|
||||
|
||||
const [isExpanded, setIsExpanded] = useState(true);
|
||||
@@ -59,7 +66,7 @@ export const JsonAttributeTree = ({ depth = 0, attrKey, attrValue, attrKeyJsonPa
|
||||
: null,
|
||||
isExpandable: attrValue.length > 0,
|
||||
label: isExpanded ? `[${attrValue.length || ' '}]` : `[⋯]`,
|
||||
labelClassName: 'text-subtler',
|
||||
labelClassName: 'text-fg-subtler',
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
@@ -77,10 +84,18 @@ export const JsonAttributeTree = ({ depth = 0, attrKey, attrValue, attrKeyJsonPa
|
||||
}, [attrValue, attrKeyJsonPath, isExpanded, depth]);
|
||||
|
||||
const labelEl = (
|
||||
<span className={classNames(labelClassName, 'select-text group-hover:text-fg')}>{label}</span>
|
||||
<span className={classNames(labelClassName, 'select-text group-hover:text-fg-subtle')}>
|
||||
{label}
|
||||
</span>
|
||||
);
|
||||
return (
|
||||
<div className={classNames(/*depth === 0 && '-ml-4',*/ 'font-mono text-xs')}>
|
||||
<div
|
||||
className={classNames(
|
||||
className,
|
||||
/*depth === 0 && '-ml-4',*/ 'font-mono text-xs',
|
||||
depth === 0 && 'h-full overflow-y-auto pb-2',
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
{isExpandable ? (
|
||||
<button className="group relative flex items-center pl-4 w-full" onClick={toggleExpanded}>
|
||||
|
||||
@@ -24,13 +24,20 @@ interface Props {
|
||||
label: ReactNode;
|
||||
value: ReactNode;
|
||||
labelClassName?: string;
|
||||
labelColor?: 'secondary' | 'primary' | 'info';
|
||||
}
|
||||
|
||||
export function KeyValueRow({ label, value, labelClassName }: Props) {
|
||||
export function KeyValueRow({ label, value, labelColor = 'secondary', labelClassName }: Props) {
|
||||
return (
|
||||
<>
|
||||
<td
|
||||
className={classNames('py-0.5 pr-2 text-fg-subtle select-text cursor-text', labelClassName)}
|
||||
className={classNames(
|
||||
'py-0.5 pr-2 select-text cursor-text',
|
||||
labelClassName,
|
||||
labelColor === 'primary' && 'text-fg-primary',
|
||||
labelColor === 'secondary' && 'text-fg-subtle',
|
||||
labelColor === 'info' && 'text-fg-info',
|
||||
)}
|
||||
>
|
||||
{label}
|
||||
</td>
|
||||
|
||||
Reference in New Issue
Block a user