diff --git a/changelog.d/features/11283-traffic-inspector-purpose-header.md b/changelog.d/features/11283-traffic-inspector-purpose-header.md new file mode 100644 index 0000000000..4faaf5bc57 --- /dev/null +++ b/changelog.d/features/11283-traffic-inspector-purpose-header.md @@ -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)) diff --git a/src/app/(dashboard)/dashboard/tools/traffic-inspector/TrafficInspectorPageClient.tsx b/src/app/(dashboard)/dashboard/tools/traffic-inspector/TrafficInspectorPageClient.tsx index a1537f236d..cd3a33372a 100644 --- a/src/app/(dashboard)/dashboard/tools/traffic-inspector/TrafficInspectorPageClient.tsx +++ b/src/app/(dashboard)/dashboard/tools/traffic-inspector/TrafficInspectorPageClient.tsx @@ -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(null); const [selectedRequest, setSelectedRequest] = useState(null); @@ -91,6 +99,18 @@ export function TrafficInspectorPageClient() { return (
+ {title && ( +
+

{title}

+ {subtitle && ( +

{subtitle}

+ )} + {purpose && ( +

{purpose}

+ )} +
+ )} + {/* Capture modes toolbar */}
diff --git a/src/app/(dashboard)/dashboard/tools/traffic-inspector/page.tsx b/src/app/(dashboard)/dashboard/tools/traffic-inspector/page.tsx index fb3f9ddc3d..ba2f691a2f 100644 --- a/src/app/(dashboard)/dashboard/tools/traffic-inspector/page.tsx +++ b/src/app/(dashboard)/dashboard/tools/traffic-inspector/page.tsx @@ -9,6 +9,7 @@ export async function generateMetadata() { }; } -export default function TrafficInspectorPage() { - return ; +export default async function TrafficInspectorPage() { + const t = await getTranslations("sidebar"); + return ; } diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json index 6a6ec59863..e45ebbd04f 100644 --- a/src/i18n/messages/en.json +++ b/src/i18n/messages/en.json @@ -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", diff --git a/tests/unit/traffic-inspector-beginner-header.test.ts b/tests/unit/traffic-inspector-beginner-header.test.ts new file mode 100644 index 0000000000..693597fbfc --- /dev/null +++ b/tests/unit/traffic-inspector-beginner-header.test.ts @@ -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); +});