feat(frontend/request_logs): raw json view
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user