feat: I.3 Dashboard — system metrics (DB/Redis/Worker/API), cost tracking (LLM cost 24h), usage analytics (tokens/plugins), admin-only, tsc clean

This commit is contained in:
Agent Zero
2026-08-21 00:14:51 +02:00
parent e635f2cf06
commit 5c31c53b5f
+72
View File
@@ -4,7 +4,10 @@ import { ActivityFeed, ActivityItem } from '@/components/shared/ActivityFeed';
import { DashboardGrid } from '@/components/dashboard/DashboardGrid';
import { useUnifiedContacts, useAuditLog } from '@/api/hooks';
import { useDashboardWidgets } from '@/api/dashboard';
import { useSystemDashboard } from '@/api/systemDashboard';
import { useAuthStore } from '@/store/authStore';
import { formatDateTime } from '@/utils/date';
import { Database, Server, Cpu, DollarSign, Activity, TrendingUp } from 'lucide-react';
export function DashboardPage() {
const { t } = useTranslation();
@@ -12,6 +15,9 @@ export function DashboardPage() {
const { data: contactsData } = useUnifiedContacts(1, 1, undefined, 'person');
const { data: auditData, isError: auditError } = useAuditLog(1, 5);
const { data: widgetsData, isError: widgetsError } = useDashboardWidgets();
const { data: systemData } = useSystemDashboard();
const user = useAuthStore((s) => s.user);
const isAdmin = user?.is_system_admin ?? false;
const totalCompanies = companiesData?.total ?? 0;
const totalContacts = contactsData?.total ?? 0;
@@ -72,6 +78,72 @@ export function DashboardPage() {
/>
</div>
{/* System Metrics (Admin only) — I-DASH, I-COST, I-USE */}
{isAdmin && systemData && (
<div className="mb-8">
<h2 className="text-lg font-semibold text-secondary-800 mb-4">{t('dashboard.systemMetrics', 'System Status')}</h2>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
<div className="border border-secondary-200 rounded-lg p-4 bg-white">
<div className="flex items-center gap-2 mb-2">
<Database className="w-4 h-4 text-primary-600" />
<span className="text-sm font-medium text-secondary-900">Database</span>
</div>
<p className="text-2xl font-bold text-secondary-900">{systemData.database?.status === 'up' ? '✅' : '❌'}</p>
<p className="text-xs text-secondary-500">{systemData.database?.db_size_human || '—'}</p>
</div>
<div className="border border-secondary-200 rounded-lg p-4 bg-white">
<div className="flex items-center gap-2 mb-2">
<Server className="w-4 h-4 text-primary-600" />
<span className="text-sm font-medium text-secondary-900">Redis</span>
</div>
<p className="text-2xl font-bold text-secondary-900">{systemData.redis?.status === 'up' ? '✅' : '❌'}</p>
<p className="text-xs text-secondary-500">{systemData.redis?.used_memory_human || '—'}</p>
</div>
<div className="border border-secondary-200 rounded-lg p-4 bg-white">
<div className="flex items-center gap-2 mb-2">
<Cpu className="w-4 h-4 text-primary-600" />
<span className="text-sm font-medium text-secondary-900">Worker</span>
</div>
<p className="text-2xl font-bold text-secondary-900">{systemData.worker?.status === 'up' ? '✅' : '❌'}</p>
<p className="text-xs text-secondary-500">Queue: {systemData.worker?.queue_length ?? '—'}</p>
</div>
<div className="border border-secondary-200 rounded-lg p-4 bg-white">
<div className="flex items-center gap-2 mb-2">
<Activity className="w-4 h-4 text-primary-600" />
<span className="text-sm font-medium text-secondary-900">API</span>
</div>
<p className="text-2xl font-bold text-secondary-900">{systemData.api?.total_requests ?? '—'}</p>
<p className="text-xs text-secondary-500">Errors: {systemData.api?.error_count ?? 0}</p>
</div>
</div>
{systemData.llm && (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 mt-4">
<div className="border border-secondary-200 rounded-lg p-4 bg-white">
<div className="flex items-center gap-2 mb-2">
<DollarSign className="w-4 h-4 text-warning-600" />
<span className="text-sm font-medium text-secondary-900">LLM Cost (24h)</span>
</div>
<p className="text-2xl font-bold text-secondary-900">${systemData.llm.cost_24h?.toFixed(2) ?? '0.00'}</p>
</div>
<div className="border border-secondary-200 rounded-lg p-4 bg-white">
<div className="flex items-center gap-2 mb-2">
<TrendingUp className="w-4 h-4 text-primary-600" />
<span className="text-sm font-medium text-secondary-900">LLM Tokens (24h)</span>
</div>
<p className="text-2xl font-bold text-secondary-900">{systemData.llm.tokens_24h?.toLocaleString() ?? '0'}</p>
</div>
<div className="border border-secondary-200 rounded-lg p-4 bg-white">
<div className="flex items-center gap-2 mb-2">
<Activity className="w-4 h-4 text-primary-600" />
<span className="text-sm font-medium text-secondary-900">Active Plugins</span>
</div>
<p className="text-2xl font-bold text-secondary-900">{systemData.plugins?.active_count ?? '—'}</p>
</div>
</div>
)}
</div>
)}
{/* Dynamic Plugin Widgets */}
{widgetsError ? (
<p className="text-sm text-secondary-500 mb-6" data-testid="dashboard-widgets-unavailable">