feat(frontend/request_logs): raw json view

This commit is contained in:
2025-12-13 22:18:48 +08:00
parent 982a9e5457
commit adf11ced6d

View File

@@ -24,7 +24,7 @@ const TreeView: Component<TreeViewProps> = (props) => {
return <span class="text-purple-600">{String(value)}</span>; return <span class="text-purple-600">{String(value)}</span>;
case "object": case "object":
if (value === null) return <span class="text-gray-500">null</span>; if (value === null) return <span class="text-gray-500">null</span>;
// This case is handled by recursive TreeView return <span class="text-gray-500">{String(value)}</span>;
default: default:
return <span class="text-gray-500">{String(value)}</span>; return <span class="text-gray-500">{String(value)}</span>;
} }
@@ -36,7 +36,9 @@ const TreeView: Component<TreeViewProps> = (props) => {
class="flex items-center cursor-pointer hover:bg-gray-100 rounded px-1" class="flex items-center cursor-pointer hover:bg-gray-100 rounded px-1"
onClick={() => setIsOpen(!isOpen())} onClick={() => setIsOpen(!isOpen())}
> >
<span class="w-4 inline-block text-gray-500">{isObject ? (isOpen() ? "▼" : "►") : ""}</span> <span class="w-4 inline-block text-gray-500">
{isObject ? (isOpen() ? "▼" : "►") : ""}
</span>
<span class="font-semibold text-gray-800">{props.name}:</span> <span class="font-semibold text-gray-800">{props.name}:</span>
<Show when={!isObject}> <Show when={!isObject}>
<span class="ml-2">{renderValue(props.data)}</span> <span class="ml-2">{renderValue(props.data)}</span>
@@ -53,6 +55,70 @@ const TreeView: Component<TreeViewProps> = (props) => {
); );
}; };
interface DataSectionProps {
title: string;
data: any;
badge?: string;
}
const DataSection: Component<DataSectionProps> = (props) => {
const [viewMode, setViewMode] = createSignal<"tree" | "raw">("tree");
return (
<div>
<div class="flex items-center justify-between mb-2">
<h4 class="font-semibold flex items-center">
{props.title}
<Show when={props.badge}>
<span class="ml-2 inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
{props.badge}
</span>
</Show>
</h4>
{/* View Toggle Buttons */}
<div class="flex text-xs rounded-md border border-gray-300 overflow-hidden">
<button
type="button"
class={`px-2 py-1 ${
viewMode() === "tree"
? "bg-gray-200 text-gray-900 font-medium"
: "bg-white text-gray-600 hover:bg-gray-50"
}`}
onClick={() => setViewMode("tree")}
>
Tree
</button>
<button
type="button"
class={`px-2 py-1 border-l border-gray-300 ${
viewMode() === "raw"
? "bg-gray-200 text-gray-900 font-medium"
: "bg-white text-gray-600 hover:bg-gray-50"
}`}
onClick={() => setViewMode("raw")}
>
Raw
</button>
</div>
</div>
<div class="bg-gray-50 p-3 rounded overflow-x-auto border border-gray-200">
<Show
when={viewMode() === "tree"}
fallback={
<pre class="font-mono text-xs text-gray-800 whitespace-pre-wrap break-words">
{JSON.stringify(props.data, null, 2)}
</pre>
}
>
<TreeView name="body" data={props.data} isRoot={true} />
</Show>
</div>
</div>
);
};
interface RequestDetailsProps { interface RequestDetailsProps {
log: RequestLog; log: RequestLog;
onClose: () => void; onClose: () => void;
@@ -70,50 +136,35 @@ const RequestDetails: Component<RequestDetailsProps> = (props) => {
</CardHeader> </CardHeader>
<CardContent class="flex-1 overflow-y-auto min-h-0"> <CardContent class="flex-1 overflow-y-auto min-h-0">
<div class="grid grid-cols-1 gap-4"> <div class="grid grid-cols-1 gap-6">
<div> {/* Original Request */}
<h4 class="font-semibold mb-2">Request</h4> <DataSection
<div class="bg-gray-50 p-3 rounded overflow-x-auto"> title="Request"
<TreeView name="body" data={props.log.request_body} isRoot={true} /> data={props.log.request_body}
</div> />
</div>
<div>
<h4 class="font-semibold mb-2">Response</h4>
<div class="bg-gray-50 p-3 rounded overflow-x-auto">
<TreeView name="body" data={props.log.response_body} isRoot={true} />
</div>
</div>
{/* Original Response */}
<DataSection
title="Response"
data={props.log.response_body}
/>
{/* Intercepted Request */}
<Show when={props.log.intercepted_request}> <Show when={props.log.intercepted_request}>
<div> <DataSection
<h4 class="font-semibold mb-2 flex items-center"> title="Intercepted Request"
Intercepted Request data={props.log.intercepted_request}
<Show when={props.log.request_interception_action}> badge={props.log.request_interception_action}
<span class="ml-2 inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800"> />
{props.log.request_interception_action}
</span>
</Show>
</h4>
<div class="bg-gray-50 p-3 rounded overflow-x-auto">
<TreeView name="body" data={props.log.intercepted_request} isRoot={true} />
</div>
</div>
</Show> </Show>
{/* Intercepted Response */}
<Show when={props.log.intercepted_response}> <Show when={props.log.intercepted_response}>
<div> <DataSection
<h4 class="font-semibold mb-2 flex items-center"> title="Intercepted Response"
Intercepted Response data={props.log.intercepted_response}
<Show when={props.log.response_interception_action}> badge={props.log.response_interception_action}
<span class="ml-2 inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800"> />
{props.log.response_interception_action}
</span>
</Show>
</h4>
<div class="bg-gray-50 p-3 rounded overflow-x-auto">
<TreeView name="body" data={props.log.intercepted_response} isRoot={true} />
</div>
</div>
</Show> </Show>
</div> </div>
</CardContent> </CardContent>