mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-23 01:08:28 +02:00
Better response headers
This commit is contained in:
@@ -5,5 +5,9 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function EmptyStateText({ children }: Props) {
|
export function EmptyStateText({ children }: Props) {
|
||||||
return <div className="h-full text-gray-400 flex items-center justify-center">{children}</div>;
|
return (
|
||||||
|
<div className="rounded-lg border border-dashed border-highlight h-full text-gray-400 flex items-center justify-center">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,9 +96,7 @@ export const RequestPane = memo(function RequestPane({ style, fullHeight, classN
|
|||||||
label: (
|
label: (
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
Headers
|
Headers
|
||||||
<CountBadge
|
<CountBadge count={activeRequest.headers.filter((h) => h.name).length} />
|
||||||
count={activeRequest.headers.filter((h) => h.name && h.value).length}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@@ -164,7 +162,7 @@ export const RequestPane = memo(function RequestPane({ style, fullHeight, classN
|
|||||||
label="Request"
|
label="Request"
|
||||||
onChangeValue={setActiveTab}
|
onChangeValue={setActiveTab}
|
||||||
tabs={tabs}
|
tabs={tabs}
|
||||||
className="mt-1"
|
tabListClassName="mt-2"
|
||||||
>
|
>
|
||||||
<TabContent value="auth">
|
<TabContent value="auth">
|
||||||
{activeRequest.authenticationType === AUTH_TYPE_BASIC ? (
|
{activeRequest.authenticationType === AUTH_TYPE_BASIC ? (
|
||||||
@@ -199,7 +197,7 @@ export const RequestPane = memo(function RequestPane({ style, fullHeight, classN
|
|||||||
onChange={() => null}
|
onChange={() => null}
|
||||||
/>
|
/>
|
||||||
</TabContent>
|
</TabContent>
|
||||||
<TabContent value="body" className="mt-1">
|
<TabContent value="body">
|
||||||
{activeRequest.bodyType === BODY_TYPE_JSON ? (
|
{activeRequest.bodyType === BODY_TYPE_JSON ? (
|
||||||
<Editor
|
<Editor
|
||||||
forceUpdateKey={forceUpdateKey}
|
forceUpdateKey={forceUpdateKey}
|
||||||
|
|||||||
26
src-web/components/ResponseHeaders.tsx
Normal file
26
src-web/components/ResponseHeaders.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import classnames from 'classnames';
|
||||||
|
import type { HttpResponse } from '../lib/models';
|
||||||
|
import { HStack } from './core/Stacks';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
headers: HttpResponse['headers'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ResponseHeaders({ headers }: Props) {
|
||||||
|
return (
|
||||||
|
<dl className="font-mono text-xs table-fixed w-full">
|
||||||
|
{headers.map((h, i) => {
|
||||||
|
return (
|
||||||
|
<HStack
|
||||||
|
space={3}
|
||||||
|
key={i}
|
||||||
|
className={classnames(i > 0 && 'border-t border-highlightSecondary', 'py-1')}
|
||||||
|
>
|
||||||
|
<dd className="w-1/3 text-violet-600 select-text cursor-text">{h.name}</dd>
|
||||||
|
<dt className="w-2/3 text-blue-600 select-text cursor-text break-all">{h.value}</dt>
|
||||||
|
</HStack>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</dl>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ import { StatusColor } from './core/StatusColor';
|
|||||||
import { TabContent, Tabs } from './core/Tabs/Tabs';
|
import { TabContent, Tabs } from './core/Tabs/Tabs';
|
||||||
import { Webview } from './core/Webview';
|
import { Webview } from './core/Webview';
|
||||||
import { EmptyStateText } from './EmptyStateText';
|
import { EmptyStateText } from './EmptyStateText';
|
||||||
|
import { ResponseHeaders } from './ResponseHeaders';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
style?: CSSProperties;
|
style?: CSSProperties;
|
||||||
@@ -81,7 +82,11 @@ export const ResponsePane = memo(function ResponsePane({ style, className }: Pro
|
|||||||
>
|
>
|
||||||
<HStack
|
<HStack
|
||||||
alignItems="center"
|
alignItems="center"
|
||||||
className="italic text-gray-700 text-sm w-full flex-shrink-0 -mb-1"
|
className={classnames(
|
||||||
|
'italic text-gray-700 text-sm w-full flex-shrink-0',
|
||||||
|
// Remove a bit of space because the tabs have lots too
|
||||||
|
'-mb-1.5',
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{activeResponse && (
|
{activeResponse && (
|
||||||
<>
|
<>
|
||||||
@@ -171,14 +176,7 @@ export const ResponsePane = memo(function ResponsePane({ style, className }: Pro
|
|||||||
) : null}
|
) : null}
|
||||||
</TabContent>
|
</TabContent>
|
||||||
<TabContent value="headers">
|
<TabContent value="headers">
|
||||||
<ul>
|
<ResponseHeaders headers={activeResponse?.headers ?? []} />
|
||||||
{activeResponse?.headers.map((h) => (
|
|
||||||
<li key={h.name} className="font-mono text-xs">
|
|
||||||
<span className="text-violet-600 select-text cursor-text">{h.name}</span>:{' '}
|
|
||||||
<span className="text-blue-600 select-text cursor-text">{h.value}</span>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</TabContent>
|
</TabContent>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ interface Props {
|
|||||||
export function CountBadge({ count }: Props) {
|
export function CountBadge({ count }: Props) {
|
||||||
if (count === 0) return null;
|
if (count === 0) return null;
|
||||||
return (
|
return (
|
||||||
<div aria-hidden className="opacity-80 text-2xs border rounded px-1 mb-0.5 ml-1 h-4">
|
<>
|
||||||
{count}
|
<div aria-hidden className="opacity-70 text-3xs rounded mb-0.5 ml-1 h-4 font-mono">
|
||||||
</div>
|
{count}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,13 +117,12 @@ export const PairEditor = memo(function PairEditor({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleFocus = useCallback(
|
const handleFocus = useCallback(
|
||||||
(pair: PairContainer) => {
|
(pair: PairContainer) =>
|
||||||
const isLast = pair.id === pairs[pairs.length - 1]?.id;
|
setPairs((pairs) => {
|
||||||
if (isLast) {
|
const isLast = pair.id === pairs[pairs.length - 1]?.id;
|
||||||
setPairs((pairs) => [...pairs, newPairContainer()]);
|
return isLast ? [...pairs, newPairContainer()] : pairs;
|
||||||
}
|
}),
|
||||||
},
|
[],
|
||||||
[pairs],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Ensure there's always at least one pair
|
// Ensure there's always at least one pair
|
||||||
@@ -138,7 +137,7 @@ export const PairEditor = memo(function PairEditor({
|
|||||||
className={classnames(
|
className={classnames(
|
||||||
className,
|
className,
|
||||||
'@container',
|
'@container',
|
||||||
'overflow-auto max-h-full pb-2 grid',
|
'pb-2 grid',
|
||||||
// Move over the width of the drag handle
|
// Move over the width of the drag handle
|
||||||
'-ml-3',
|
'-ml-3',
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -73,18 +73,15 @@ export function Tabs({
|
|||||||
aria-label={label}
|
aria-label={label}
|
||||||
className={classnames(
|
className={classnames(
|
||||||
tabListClassName,
|
tabListClassName,
|
||||||
'h-md flex items-center overflow-x-auto hide-scrollbars',
|
'flex items-center overflow-x-auto hide-scrollbars mt-1 mb-2',
|
||||||
// Give space for button focus states within overflow boundary
|
// Give space for button focus states within overflow boundary.
|
||||||
'px-2 -mx-2',
|
'px-2 -mx-2',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<HStack space={3} className="-ml-1 flex-shrink-0">
|
<HStack space={1} className="flex-shrink-0">
|
||||||
{tabs.map((t) => {
|
{tabs.map((t) => {
|
||||||
const isActive = t.value === value;
|
const isActive = t.value === value;
|
||||||
const btnClassName = classnames(
|
const btnClassName = classnames(isActive ? 'bg-highlightSecondary' : 'text-gray-600');
|
||||||
'!px-1',
|
|
||||||
isActive ? 'text-gray-900' : 'text-gray-600 hover:text-gray-800',
|
|
||||||
);
|
|
||||||
if ('options' in t) {
|
if ('options' in t) {
|
||||||
const option = t.options.items.find(
|
const option = t.options.items.find(
|
||||||
(i) => 'value' in i && i.value === t.options?.value,
|
(i) => 'value' in i && i.value === t.options?.value,
|
||||||
@@ -148,7 +145,7 @@ export const TabContent = memo(function TabContent({
|
|||||||
<div
|
<div
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
data-tab={value}
|
data-tab={value}
|
||||||
className={classnames(className, 'tab-content', 'hidden w-full h-full')}
|
className={classnames(className, 'tab-content', 'overflow-auto hidden w-full h-full')}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ module.exports = {
|
|||||||
"sans": ["Inter", "sans-serif"]
|
"sans": ["Inter", "sans-serif"]
|
||||||
},
|
},
|
||||||
fontSize: {
|
fontSize: {
|
||||||
|
'3xs': "0.6rem",
|
||||||
'2xs': "0.7rem",
|
'2xs': "0.7rem",
|
||||||
xs: "0.8rem",
|
xs: "0.8rem",
|
||||||
sm: "0.9rem",
|
sm: "0.9rem",
|
||||||
|
|||||||
Reference in New Issue
Block a user