Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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))
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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")} />;
}
3 changes: 2 additions & 1 deletion src/i18n/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1259,7 +1259,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",
Expand Down
44 changes: 44 additions & 0 deletions tests/unit/traffic-inspector-beginner-header.test.ts
Original file line number Diff line number Diff line change
@@ -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);
});
Loading