mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-25 00:22:09 +03:00
Beginner UX: purpose-first Traffic Inspector header (#11283)
Validated on a 3-PR combined board: traffic-inspector-beginner-header suite green within the board's 30/30, typecheck:core + dashboard-typecheck clean, gates within baseline. Purpose-first orientation header for Traffic Inspector, existing inspection UI untouched. Thank you @ignamiranda!
This commit is contained in:
@@ -0,0 +1 @@
|
||||
- **feat(dashboard):** lead Traffic Inspector with a purpose-first header that separates "what happened" from "how it happened", so beginners can read request outcomes without drowning in protocol detail ([#11283](https://github.com/diegosouzapw/OmniRoute/pull/11283))
|
||||
@@ -15,7 +15,15 @@ import { HistoricSessionBanner } from "./components/session/HistoricSessionBanne
|
||||
|
||||
const BUFFER_MAX = 1000;
|
||||
|
||||
export function TrafficInspectorPageClient() {
|
||||
export function TrafficInspectorPageClient({
|
||||
title,
|
||||
subtitle,
|
||||
purpose,
|
||||
}: {
|
||||
title?: string;
|
||||
subtitle?: string;
|
||||
purpose?: string;
|
||||
} = {}) {
|
||||
const [containerHeight, setContainerHeight] = useState(600);
|
||||
const listContainerRef = useRef<HTMLDivElement | null>(null);
|
||||
const [selectedRequest, setSelectedRequest] = useState<InterceptedRequest | null>(null);
|
||||
@@ -91,6 +99,18 @@ export function TrafficInspectorPageClient() {
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full overflow-hidden">
|
||||
{title && (
|
||||
<div className="shrink-0 px-4 pt-4 pb-2">
|
||||
<h1 className="text-2xl font-bold text-text-main">{title}</h1>
|
||||
{subtitle && (
|
||||
<p className="text-sm text-text-muted mt-1 max-w-2xl">{subtitle}</p>
|
||||
)}
|
||||
{purpose && (
|
||||
<p className="text-xs text-text-muted mt-2 max-w-2xl italic">{purpose}</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Capture modes toolbar */}
|
||||
<div className="shrink-0 px-4 pt-4 pb-2">
|
||||
<CaptureModesToolbar customHostCount={0} />
|
||||
|
||||
@@ -9,6 +9,7 @@ export async function generateMetadata() {
|
||||
};
|
||||
}
|
||||
|
||||
export default function TrafficInspectorPage() {
|
||||
return <TrafficInspectorPageClient />;
|
||||
export default async function TrafficInspectorPage() {
|
||||
const t = await getTranslations("sidebar");
|
||||
return <TrafficInspectorPageClient title={t("trafficInspector")} subtitle={t("trafficInspectorSubtitle")} purpose={t("trafficInspectorPurpose")} />;
|
||||
}
|
||||
|
||||
@@ -1272,7 +1272,8 @@
|
||||
"agentBridge": "Agent Bridge",
|
||||
"agentBridgeSubtitle": "Intercept IDE agent traffic",
|
||||
"trafficInspector": "Traffic Inspector",
|
||||
"trafficInspectorSubtitle": "Monitor LLM calls + debug any HTTPS traffic",
|
||||
"trafficInspectorSubtitle": "Inspect request and response traffic from your apps",
|
||||
"trafficInspectorPurpose": "See exactly what your application sends to and receives from AI providers. Works with any OpenAI-compatible client.",
|
||||
"cliCode": "CLI Code",
|
||||
"cliCodeSubtitle": "Code tools pointing to OmniRoute",
|
||||
"cliAgents": "CLI Agents",
|
||||
|
||||
44
tests/unit/traffic-inspector-beginner-header.test.ts
Normal file
44
tests/unit/traffic-inspector-beginner-header.test.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
||||
const pagePath = path.join(
|
||||
repoRoot,
|
||||
"src/app/(dashboard)/dashboard/tools/traffic-inspector/page.tsx"
|
||||
);
|
||||
const clientPath = path.join(
|
||||
repoRoot,
|
||||
"src/app/(dashboard)/dashboard/tools/traffic-inspector/TrafficInspectorPageClient.tsx"
|
||||
);
|
||||
const enPath = path.join(repoRoot, "src/i18n/messages/en.json");
|
||||
|
||||
test("Traffic Inspector page passes translated title, subtitle, and purpose", () => {
|
||||
const pageSource = fs.readFileSync(pagePath, "utf8");
|
||||
assert.match(pageSource, /title=\{t\("trafficInspector"\)\}/);
|
||||
assert.match(pageSource, /subtitle=\{t\("trafficInspectorSubtitle"\)\}/);
|
||||
assert.match(pageSource, /purpose=\{t\("trafficInspectorPurpose"\)\}/);
|
||||
});
|
||||
|
||||
test("Traffic Inspector client renders purpose-first header when props are provided", () => {
|
||||
const clientSource = fs.readFileSync(clientPath, "utf8");
|
||||
assert.match(clientSource, /title\s*&&/);
|
||||
assert.match(clientSource, /subtitle\s*&&/);
|
||||
assert.match(clientSource, /purpose\s*&&/);
|
||||
});
|
||||
|
||||
test("Traffic Inspector beginner i18n keys exist in en.json", () => {
|
||||
const en = JSON.parse(fs.readFileSync(enPath, "utf8"));
|
||||
assert.equal(en.sidebar.trafficInspector, "Traffic Inspector");
|
||||
assert.equal(
|
||||
en.sidebar.trafficInspectorSubtitle,
|
||||
"Inspect request and response traffic from your apps"
|
||||
);
|
||||
assert.equal(
|
||||
typeof en.sidebar.trafficInspectorPurpose,
|
||||
"string"
|
||||
);
|
||||
assert.ok(en.sidebar.trafficInspectorPurpose.length > 20);
|
||||
});
|
||||
Reference in New Issue
Block a user