zeroclaw/web/src/components/layout/Header.tsx
Zeki Kocabıyık 79337c76e8 feat(gateway): add embedded web dashboard with React frontend
Add a complete web management panel for ZeroClaw, served directly from
the binary via rust-embed. The dashboard provides real-time monitoring,
agent chat, configuration editing, and system diagnostics — all
accessible at http://localhost:5555/ after pairing.

Backend (Rust):
- Add 15+ REST API endpoints under /api/* with bearer token auth
- Add WebSocket agent chat at /ws/chat with query param auth
- Add SSE event stream at /api/events via BroadcastObserver
- Add rust-embed static file serving at /_app/* with SPA fallback
- Extend AppState with tools_registry, cost_tracker, event_tx
- Extract doctor::diagnose() for structured diagnostic results
- Add Serialize derives to IntegrationStatus, CliCategory, DiscoveredCli

Frontend (React + Vite + Tailwind CSS):
- 10 dashboard pages: Dashboard, AgentChat, Tools, Cron, Integrations,
  Memory, Config, Cost, Logs, Doctor
- WebSocket client with auto-reconnect for agent chat
- SSE client (fetch-based, supports auth headers) for live events
- Full EN/TR internationalization (~190 translation keys)
- Dark theme with responsive layouts
- Auth flow via 6-digit pairing code, token stored in localStorage

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 16:14:01 +08:00

60 lines
1.8 KiB
TypeScript

import { useLocation } from 'react-router-dom';
import { LogOut } from 'lucide-react';
import { t } from '@/lib/i18n';
import { useAuth, useLocaleContext } from '@/App';
const routeTitles: Record<string, string> = {
'/': 'nav.dashboard',
'/agent': 'nav.agent',
'/tools': 'nav.tools',
'/cron': 'nav.cron',
'/integrations': 'nav.integrations',
'/memory': 'nav.memory',
'/config': 'nav.config',
'/cost': 'nav.cost',
'/logs': 'nav.logs',
'/doctor': 'nav.doctor',
};
export default function Header() {
const location = useLocation();
const { logout } = useAuth();
const { locale, setAppLocale } = useLocaleContext();
const titleKey = routeTitles[location.pathname] ?? 'nav.dashboard';
const pageTitle = t(titleKey);
const toggleLanguage = () => {
setAppLocale(locale === 'en' ? 'tr' : 'en');
};
return (
<header className="h-14 bg-gray-800 border-b border-gray-700 flex items-center justify-between px-6">
{/* Page title */}
<h1 className="text-lg font-semibold text-white">{pageTitle}</h1>
{/* Right-side controls */}
<div className="flex items-center gap-4">
{/* Language switcher */}
<button
type="button"
onClick={toggleLanguage}
className="px-3 py-1 rounded-md text-sm font-medium border border-gray-600 text-gray-300 hover:bg-gray-700 hover:text-white transition-colors"
>
{locale === 'en' ? 'EN' : 'TR'}
</button>
{/* Logout */}
<button
type="button"
onClick={logout}
className="flex items-center gap-1.5 px-3 py-1.5 rounded-md text-sm text-gray-300 hover:bg-gray-700 hover:text-white transition-colors"
>
<LogOut className="h-4 w-4" />
<span>{t('auth.logout')}</span>
</button>
</div>
</header>
);
}