mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-07 15:52:52 +03:00
feat: sidebar reorganization + CLI fingerprint to Agents page
- New CLI sidebar section: Tools + Agents - Move Media to Debug section - Move Health + Logs to System section - Move CLI Fingerprint card from Settings > Security to Agents page - Add cliToolsShort i18n key to all 30 languages
This commit is contained in:
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "omniroute",
|
||||
"version": "2.0.10",
|
||||
"version": "2.0.11",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "omniroute",
|
||||
"version": "2.0.10",
|
||||
"version": "2.0.11",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "omniroute",
|
||||
"version": "2.0.11",
|
||||
"version": "2.0.12",
|
||||
"description": "Smart AI Router with auto fallback — route to FREE & cheap models, zero downtime. Works with Cursor, Cline, Claude Desktop, Codex, and any OpenAI-compatible tool.",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import { Card, Button, Input } from "@/shared/components";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { AI_PROVIDERS } from "@/shared/constants/config";
|
||||
|
||||
interface AgentInfo {
|
||||
id: string;
|
||||
@@ -29,6 +30,7 @@ export default function AgentsPage() {
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const [showAddForm, setShowAddForm] = useState(false);
|
||||
const [addLoading, setAddLoading] = useState(false);
|
||||
const [settings, setSettings] = useState<Record<string, any>>({});
|
||||
const [newAgent, setNewAgent] = useState({
|
||||
name: "",
|
||||
binary: "",
|
||||
@@ -36,6 +38,7 @@ export default function AgentsPage() {
|
||||
spawnArgs: "",
|
||||
});
|
||||
const t = useTranslations("agents");
|
||||
const ts = useTranslations("settings");
|
||||
|
||||
const fetchAgents = useCallback(async () => {
|
||||
try {
|
||||
@@ -52,8 +55,26 @@ export default function AgentsPage() {
|
||||
|
||||
useEffect(() => {
|
||||
fetchAgents();
|
||||
// Also fetch settings for CLI fingerprint
|
||||
fetch("/api/settings")
|
||||
.then((r) => r.json())
|
||||
.then((d) => setSettings(d))
|
||||
.catch(() => {});
|
||||
}, [fetchAgents]);
|
||||
|
||||
const updateSetting = async (key: string, value: any) => {
|
||||
try {
|
||||
const res = await fetch("/api/settings", {
|
||||
method: "PATCH",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ [key]: value }),
|
||||
});
|
||||
if (res.ok) setSettings((prev) => ({ ...prev, [key]: value }));
|
||||
} catch (err) {
|
||||
console.error("Failed to update setting:", err);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRefresh = async () => {
|
||||
setRefreshing(true);
|
||||
try {
|
||||
@@ -64,7 +85,7 @@ export default function AgentsPage() {
|
||||
});
|
||||
const data = await res.json();
|
||||
setAgents(data.agents || []);
|
||||
await fetchAgents(); // Re-fetch for summary
|
||||
await fetchAgents();
|
||||
} catch (err) {
|
||||
console.error("Failed to refresh:", err);
|
||||
} finally {
|
||||
@@ -156,6 +177,70 @@ export default function AgentsPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* CLI Fingerprint Matching */}
|
||||
<Card>
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<div className="p-2 rounded-lg bg-emerald-500/10 text-emerald-600 dark:text-emerald-400">
|
||||
<span className="material-symbols-outlined text-[20px]" aria-hidden="true">
|
||||
fingerprint
|
||||
</span>
|
||||
</div>
|
||||
<h3 className="text-lg font-semibold">{ts("cliFingerprint")}</h3>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<p className="text-sm text-text-muted">{ts("cliFingerprintDesc")}</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{(["codex", "claude", "github", "antigravity"] as const).map((providerId) => {
|
||||
const providerMeta = Object.values(AI_PROVIDERS).find(
|
||||
(p: any) => p.id === providerId
|
||||
) as any;
|
||||
const isEnabled = (settings.cliCompatProviders || []).includes(providerId);
|
||||
const displayName = providerMeta?.name || providerId;
|
||||
const icon = providerMeta?.icon || "terminal";
|
||||
const color = providerMeta?.color || "#888";
|
||||
return (
|
||||
<button
|
||||
key={providerId}
|
||||
onClick={() => {
|
||||
const current: string[] = settings.cliCompatProviders || [];
|
||||
const updated = current.includes(providerId)
|
||||
? current.filter((p) => p !== providerId)
|
||||
: [...current, providerId];
|
||||
updateSetting("cliCompatProviders", updated);
|
||||
}}
|
||||
className={`inline-flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg text-xs font-medium transition-all border ${
|
||||
isEnabled
|
||||
? "bg-emerald-500/10 border-emerald-500/30 text-emerald-600 dark:text-emerald-400"
|
||||
: "bg-black/[0.02] dark:bg-white/[0.02] border-transparent text-text-muted hover:bg-black/[0.05] dark:hover:bg-white/[0.05]"
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
className="material-symbols-outlined text-[14px]"
|
||||
style={{ color: isEnabled ? undefined : color }}
|
||||
>
|
||||
{isEnabled ? "fingerprint" : icon}
|
||||
</span>
|
||||
{displayName}
|
||||
{isEnabled && (
|
||||
<span className="material-symbols-outlined text-[12px] text-emerald-500">
|
||||
check
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{(settings.cliCompatProviders || []).length > 0 && (
|
||||
<p className="text-xs text-emerald-600 dark:text-emerald-400 mt-1 flex items-center gap-1">
|
||||
<span className="material-symbols-outlined text-[14px]">verified</span>
|
||||
{ts("cliFingerprintEnabled", {
|
||||
count: (settings.cliCompatProviders || []).length,
|
||||
})}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* Agent Grid */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{agents.map((agent) => (
|
||||
|
||||
@@ -248,76 +248,6 @@ export default function SecurityTab() {
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* CLI Fingerprint Matching */}
|
||||
<Card>
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<div className="p-2 rounded-lg bg-emerald-500/10 text-emerald-600 dark:text-emerald-400">
|
||||
<span className="material-symbols-outlined text-[20px]" aria-hidden="true">
|
||||
fingerprint
|
||||
</span>
|
||||
</div>
|
||||
<h3 className="text-lg font-semibold">{t("cliFingerprint")}</h3>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<p className="text-sm text-text-muted">{t("cliFingerprintDesc")}</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{(["codex", "claude", "github", "antigravity"] as const).map((providerId) => {
|
||||
const providerMeta = Object.values(AI_PROVIDERS).find(
|
||||
(p: any) => p.id === providerId
|
||||
) as any;
|
||||
const isEnabled = (settings.cliCompatProviders || []).includes(providerId);
|
||||
const displayName = providerMeta?.name || providerId;
|
||||
const icon = providerMeta?.icon || "terminal";
|
||||
const color = providerMeta?.color || "#888";
|
||||
return (
|
||||
<button
|
||||
key={providerId}
|
||||
onClick={() => {
|
||||
const current: string[] = settings.cliCompatProviders || [];
|
||||
const updated = current.includes(providerId)
|
||||
? current.filter((p) => p !== providerId)
|
||||
: [...current, providerId];
|
||||
updateSetting("cliCompatProviders", updated);
|
||||
}}
|
||||
disabled={loading}
|
||||
className={`inline-flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg text-xs font-medium transition-all border ${
|
||||
isEnabled
|
||||
? "bg-emerald-500/10 border-emerald-500/30 text-emerald-600 dark:text-emerald-400"
|
||||
: "bg-black/[0.02] dark:bg-white/[0.02] border-transparent text-text-muted hover:bg-black/[0.05] dark:hover:bg-white/[0.05]"
|
||||
}`}
|
||||
title={
|
||||
isEnabled
|
||||
? t("disableFingerprintTitle", { provider: displayName })
|
||||
: t("enableFingerprintTitle", { provider: displayName })
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="material-symbols-outlined text-[14px]"
|
||||
style={{ color: isEnabled ? undefined : color }}
|
||||
>
|
||||
{isEnabled ? "fingerprint" : icon}
|
||||
</span>
|
||||
{displayName}
|
||||
{isEnabled && (
|
||||
<span className="material-symbols-outlined text-[12px] text-emerald-500">
|
||||
check
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{(settings.cliCompatProviders || []).length > 0 && (
|
||||
<p className="text-xs text-emerald-600 dark:text-emerald-400 mt-1 flex items-center gap-1">
|
||||
<span className="material-symbols-outlined text-[14px]">verified</span>
|
||||
{t("cliFingerprintEnabled", {
|
||||
count: (settings.cliCompatProviders || []).length,
|
||||
})}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<SessionInfoCard />
|
||||
<IPFilterSection />
|
||||
</div>
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "كيان",
|
||||
"endpoints": "نقاط النهاية",
|
||||
"playground": "ملعب النماذج",
|
||||
"agents": "وكلاء"
|
||||
"agents": "وكلاء",
|
||||
"cliToolsShort": "أدوات"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "المواضيع",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Циан",
|
||||
"endpoints": "Крайни точки",
|
||||
"playground": "Площадка",
|
||||
"agents": "Агенти"
|
||||
"agents": "Агенти",
|
||||
"cliToolsShort": "Инструменти"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Теми",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Turkis",
|
||||
"endpoints": "Endpoints",
|
||||
"playground": "Legeplads",
|
||||
"agents": "Agenter"
|
||||
"agents": "Agenter",
|
||||
"cliToolsShort": "Værktøjer"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Temaer",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Cyan",
|
||||
"endpoints": "Endpunkte",
|
||||
"playground": "Spielwiese",
|
||||
"agents": "Agenten"
|
||||
"agents": "Agenten",
|
||||
"cliToolsShort": "Werkzeuge"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Themen",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeGreen": "Green",
|
||||
"themeViolet": "Violet",
|
||||
"themeOrange": "Orange",
|
||||
"themeCyan": "Cyan"
|
||||
"themeCyan": "Cyan",
|
||||
"cliToolsShort": "Tools"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Themes",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "cian",
|
||||
"endpoints": "Endpoints",
|
||||
"playground": "Playground",
|
||||
"agents": "Agentes"
|
||||
"agents": "Agentes",
|
||||
"cliToolsShort": "Herramientas"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Temas",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Syaani",
|
||||
"endpoints": "Päätepisteet",
|
||||
"playground": "Leikkipaikka",
|
||||
"agents": "Agentit"
|
||||
"agents": "Agentit",
|
||||
"cliToolsShort": "Työkalut"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Teemat",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Cyan",
|
||||
"endpoints": "Points d'accès",
|
||||
"playground": "Playground",
|
||||
"agents": "Agents"
|
||||
"agents": "Agents",
|
||||
"cliToolsShort": "Outils"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Thèmes",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Cyan",
|
||||
"endpoints": "נקודות קצה",
|
||||
"playground": "Playground",
|
||||
"agents": "סוכנים"
|
||||
"agents": "סוכנים",
|
||||
"cliToolsShort": "כלים"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Themes",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Cián",
|
||||
"endpoints": "Végpontok",
|
||||
"playground": "Játszótér",
|
||||
"agents": "Ügynökök"
|
||||
"agents": "Ügynökök",
|
||||
"cliToolsShort": "Eszközök"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Témák",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Cyan",
|
||||
"endpoints": "Endpoint",
|
||||
"playground": "Playground",
|
||||
"agents": "Agen"
|
||||
"agents": "Agen",
|
||||
"cliToolsShort": "Alat"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Themes",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Cyan",
|
||||
"endpoints": "Endpoint",
|
||||
"playground": "Playground",
|
||||
"agents": "एजेंट"
|
||||
"agents": "एजेंट",
|
||||
"cliToolsShort": "उपकरण"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Themes",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Cyan",
|
||||
"endpoints": "Endpoint",
|
||||
"playground": "Playground",
|
||||
"agents": "Agenti"
|
||||
"agents": "Agenti",
|
||||
"cliToolsShort": "Strumenti"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Themes",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Cyan",
|
||||
"endpoints": "エンドポイント",
|
||||
"playground": "プレイグラウンド",
|
||||
"agents": "エージェント"
|
||||
"agents": "エージェント",
|
||||
"cliToolsShort": "ツール"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Themes",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Cyan",
|
||||
"endpoints": "엔드포인트",
|
||||
"playground": "플레이그라운드",
|
||||
"agents": "에이전트"
|
||||
"agents": "에이전트",
|
||||
"cliToolsShort": "도구"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Themes",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Cyan",
|
||||
"endpoints": "Titik Akhir",
|
||||
"playground": "Playground",
|
||||
"agents": "Ejen"
|
||||
"agents": "Ejen",
|
||||
"cliToolsShort": "Alat"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Themes",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Cyan",
|
||||
"endpoints": "Eindpunten",
|
||||
"playground": "Speeltuin",
|
||||
"agents": "Agenten"
|
||||
"agents": "Agenten",
|
||||
"cliToolsShort": "Gereedschap"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Themes",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Cyan",
|
||||
"endpoints": "Endepunkter",
|
||||
"playground": "Lekeplass",
|
||||
"agents": "Agenter"
|
||||
"agents": "Agenter",
|
||||
"cliToolsShort": "Verktøy"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Themes",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Cyan",
|
||||
"endpoints": "Mga Endpoint",
|
||||
"playground": "Playground",
|
||||
"agents": "Mga Agent"
|
||||
"agents": "Mga Agent",
|
||||
"cliToolsShort": "Mga Tool"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Themes",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Cyan",
|
||||
"endpoints": "Punkty końcowe",
|
||||
"playground": "Plac zabaw",
|
||||
"agents": "Agenci"
|
||||
"agents": "Agenci",
|
||||
"cliToolsShort": "Narzędzia"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Themes",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Cyan",
|
||||
"endpoints": "Endpoints",
|
||||
"playground": "Playground",
|
||||
"agents": "Agentes"
|
||||
"agents": "Agentes",
|
||||
"cliToolsShort": "Ferramentas"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Themes",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeOrange": "Laranja",
|
||||
"themeCyan": "Ciano",
|
||||
"playground": "Playground",
|
||||
"agents": "Agentes"
|
||||
"agents": "Agentes",
|
||||
"cliToolsShort": "Ferramentas"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Themes",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Cyan",
|
||||
"endpoints": "Puncte finale",
|
||||
"playground": "Playground",
|
||||
"agents": "Agenți"
|
||||
"agents": "Agenți",
|
||||
"cliToolsShort": "Instrumente"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Themes",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Голубой",
|
||||
"endpoints": "Конечные точки",
|
||||
"playground": "Площадка",
|
||||
"agents": "Агенты"
|
||||
"agents": "Агенты",
|
||||
"cliToolsShort": "Инструменты"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Темы",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Cyan",
|
||||
"endpoints": "Koncové body",
|
||||
"playground": "Ihrisko",
|
||||
"agents": "Agenti"
|
||||
"agents": "Agenti",
|
||||
"cliToolsShort": "Nástroje"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Themes",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Cyan",
|
||||
"endpoints": "Ändpunkter",
|
||||
"playground": "Lekplats",
|
||||
"agents": "Agenter"
|
||||
"agents": "Agenter",
|
||||
"cliToolsShort": "Verktyg"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Themes",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Cyan",
|
||||
"endpoints": "จุดปลายทาง",
|
||||
"playground": "Playground",
|
||||
"agents": "เอเจนต์"
|
||||
"agents": "เอเจนต์",
|
||||
"cliToolsShort": "เครื่องมือ"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "ธีมส์",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Cyan",
|
||||
"endpoints": "Кінцеві точки",
|
||||
"playground": "Playground",
|
||||
"agents": "Агенти"
|
||||
"agents": "Агенти",
|
||||
"cliToolsShort": "Інструменти"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Themes",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Cyan",
|
||||
"endpoints": "Điểm cuối",
|
||||
"playground": "Playground",
|
||||
"agents": "Tác nhân"
|
||||
"agents": "Tác nhân",
|
||||
"cliToolsShort": "Công cụ"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Themes",
|
||||
|
||||
@@ -102,7 +102,8 @@
|
||||
"themeCyan": "Cyan",
|
||||
"endpoints": "端点",
|
||||
"playground": "模型试验场",
|
||||
"agents": "代理"
|
||||
"agents": "代理",
|
||||
"cliToolsShort": "工具"
|
||||
},
|
||||
"themesPage": {
|
||||
"title": "Themes",
|
||||
|
||||
@@ -18,22 +18,27 @@ const navItemDefs = [
|
||||
{ href: "/dashboard/api-manager", i18nKey: "apiManager", icon: "vpn_key" },
|
||||
{ href: "/dashboard/providers", i18nKey: "providers", icon: "dns" },
|
||||
{ href: "/dashboard/combos", i18nKey: "combos", icon: "layers" },
|
||||
{ href: "/dashboard/logs", i18nKey: "logs", icon: "description" },
|
||||
{ href: "/dashboard/costs", i18nKey: "costs", icon: "account_balance_wallet" },
|
||||
{ href: "/dashboard/analytics", i18nKey: "analytics", icon: "analytics" },
|
||||
{ href: "/dashboard/limits", i18nKey: "limits", icon: "tune" },
|
||||
{ href: "/dashboard/health", i18nKey: "health", icon: "health_and_safety" },
|
||||
{ href: "/dashboard/cli-tools", i18nKey: "cliTools", icon: "terminal" },
|
||||
{ href: "/dashboard/media", i18nKey: "media", icon: "auto_awesome" },
|
||||
];
|
||||
|
||||
const cliItemDefs = [
|
||||
{ href: "/dashboard/cli-tools", i18nKey: "cliToolsShort", icon: "terminal" },
|
||||
{ href: "/dashboard/agents", i18nKey: "agents", icon: "smart_toy" },
|
||||
];
|
||||
|
||||
const debugItemDefs = [
|
||||
{ href: "/dashboard/translator", i18nKey: "translator", icon: "translate" },
|
||||
{ href: "/dashboard/playground", i18nKey: "playground", icon: "science" },
|
||||
{ href: "/dashboard/agents", i18nKey: "agents", icon: "smart_toy" },
|
||||
{ href: "/dashboard/media", i18nKey: "media", icon: "auto_awesome" },
|
||||
];
|
||||
|
||||
const systemItemDefs = [{ href: "/dashboard/settings", i18nKey: "settings", icon: "settings" }];
|
||||
const systemItemDefs = [
|
||||
{ href: "/dashboard/health", i18nKey: "health", icon: "health_and_safety" },
|
||||
{ href: "/dashboard/logs", i18nKey: "logs", icon: "description" },
|
||||
{ href: "/dashboard/settings", i18nKey: "settings", icon: "settings" },
|
||||
];
|
||||
|
||||
const helpItemDefs = [
|
||||
{ href: "/docs", i18nKey: "docs", icon: "menu_book" },
|
||||
@@ -110,6 +115,7 @@ export default function Sidebar({
|
||||
// Resolve i18n keys → labels
|
||||
const resolveItems = (defs) => defs.map((d) => ({ ...d, label: t(d.i18nKey) }));
|
||||
const navItems = resolveItems(navItemDefs);
|
||||
const cliItems = resolveItems(cliItemDefs);
|
||||
const debugItems = resolveItems(debugItemDefs);
|
||||
const systemItems = resolveItems(systemItemDefs);
|
||||
const helpItems = resolveItems(helpItemDefs);
|
||||
@@ -238,6 +244,17 @@ export default function Sidebar({
|
||||
>
|
||||
{navItems.map(renderNavLink)}
|
||||
|
||||
{/* CLI section */}
|
||||
<div className="pt-4 mt-2">
|
||||
{!collapsed && (
|
||||
<p className="px-4 text-xs font-semibold text-text-muted/60 uppercase tracking-wider mb-2">
|
||||
CLI
|
||||
</p>
|
||||
)}
|
||||
{collapsed && <div className="border-t border-black/5 dark:border-white/5 mb-2" />}
|
||||
{cliItems.map(renderNavLink)}
|
||||
</div>
|
||||
|
||||
{/* Debug section */}
|
||||
{showDebug && (
|
||||
<div className="pt-4 mt-2">
|
||||
|
||||
Reference in New Issue
Block a user