MotorSignal-App/website/components/ops/operations-overview.tsx

1627 lines
78 KiB
TypeScript

'use client';
import React, { useState, useMemo } from 'react';
import {
OperationsHealth,
ComponentHealthStatus,
HealthComponentKey,
OperationsOverviewData,
OperationsNavId,
OperationsRole,
SafeIncidentSummary,
OverviewSecurityErrorItem,
} from './types';
import { HEALTH_COMPONENT_METADATA } from '../../lib/ops-data';
interface OperationsOverviewProps {
overview?: OperationsOverviewData | null;
health: OperationsHealth;
onRefresh: () => Promise<void> | void;
isRefreshing: boolean;
onSelectIncident?: (caseRef: string) => void;
onNavigateNav?: (nav: OperationsNavId) => void;
role?: OperationsRole;
operatorIdentity?: string;
}
function timeAgo(dateString?: string | null): string {
if (!dateString) return '--';
const date = new Date(dateString);
const now = new Date();
const diffMs = now.getTime() - date.getTime();
if (diffMs < 0) return 'just now';
const diffSecs = Math.floor(diffMs / 1000);
const diffMins = Math.floor(diffSecs / 60);
const diffHours = Math.floor(diffMins / 60);
const diffDays = Math.floor(diffHours / 24);
if (diffSecs < 60) return 'just now';
if (diffMins < 60) return `${diffMins}m ago`;
if (diffHours < 24) return `${diffHours}h ago`;
if (diffDays === 1) return 'yesterday';
if (diffDays < 30) return `${diffDays}d ago`;
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
}
function formatIncidentAge(createdAt: string, updatedAt?: string): string {
const createdDate = new Date(createdAt);
const updatedDate = updatedAt ? new Date(updatedAt) : createdDate;
const now = new Date();
const createdDiffDays = Math.floor((now.getTime() - createdDate.getTime()) / (1000 * 60 * 60 * 24));
const createdAgeStr =
createdDiffDays <= 0 ? 'today' : createdDiffDays === 1 ? '1 day' : `${createdDiffDays} days`;
const updatedDiffMs = now.getTime() - updatedDate.getTime();
const updatedDiffMins = Math.floor(updatedDiffMs / (1000 * 60));
const updatedDiffHours = Math.floor(updatedDiffMins / 60);
const updatedDiffDays = Math.floor(updatedDiffHours / 24);
let updatedStr = 'just now';
if (updatedDiffMins >= 1 && updatedDiffMins < 60) {
updatedStr = `${updatedDiffMins}m ago`;
} else if (updatedDiffHours >= 1 && updatedDiffHours < 24) {
updatedStr = `${updatedDiffHours}h ago`;
} else if (updatedDiffDays === 1) {
updatedStr = '1 day ago';
} else if (updatedDiffDays > 1) {
updatedStr = `${updatedDiffDays} days ago`;
}
return `Open ${createdAgeStr} · Updated ${updatedStr}`;
}
export function OperationsOverview({
overview,
health,
onRefresh,
isRefreshing,
onSelectIncident,
onNavigateNav,
role = 'operator',
operatorIdentity,
}: OperationsOverviewProps) {
// Activity timeframe filter: 24h / 7d / 30d
const [activityTimeframe, setActivityTimeframe] = useState<'24h' | '7d' | '30d'>('24h');
// Security events filter: 1h / 24h / 7d
const [eventTimeframe, setEventTimeframe] = useState<'1h' | '24h' | '7d'>('24h');
// Scanner grouping expansion state
const [expandedScannerGroups, setExpandedScannerGroups] = useState<Record<string, boolean>>({});
// Active Incident Detail Modal state
const [modalIncident, setModalIncident] = useState<SafeIncidentSummary | null>(null);
const [submittingAction, setSubmittingAction] = useState<string | null>(null);
const effectiveHealth = overview?.health ?? health;
function getStatusBadge(status: ComponentHealthStatus) {
switch (status) {
case 'available':
return {
label: 'Healthy',
icon: 'check_circle',
classes: 'bg-emerald-950/60 text-emerald-400 border-emerald-800/60',
};
case 'degraded':
return {
label: 'Degraded',
icon: 'warning',
classes: 'bg-amber-950/60 text-amber-400 border-amber-800/60',
};
case 'unavailable':
return {
label: 'Unavailable',
icon: 'cancel',
classes: 'bg-rose-950/60 text-rose-400 border-rose-800/60',
};
case 'unknown':
default:
return {
label: 'Unknown',
icon: 'help',
classes: 'bg-surface-container-highest text-on-surface-variant border-outline-variant/40',
};
}
}
function getSeverityBadge(severity: string) {
switch (severity.toLowerCase()) {
case 'critical':
return 'bg-rose-950/60 text-rose-400 border border-rose-800/60';
case 'high':
return 'bg-amber-950/60 text-amber-400 border border-amber-800/60';
case 'medium':
return 'bg-yellow-950/60 text-yellow-400 border border-yellow-800/60';
case 'low':
default:
return 'bg-blue-950/60 text-blue-400 border border-blue-800/60';
}
}
function getStatusBadgeClass(status: string) {
switch (status.toLowerCase()) {
case 'open':
// Red is reserved for critical; blue/neutral for open
return 'bg-blue-950/60 text-blue-300 border border-blue-800/60';
case 'investigating':
return 'bg-amber-950/60 text-amber-300 border border-amber-800/60';
case 'monitoring':
return 'bg-cyan-950/60 text-cyan-300 border border-cyan-800/60';
case 'resolved':
case 'closed':
default:
return 'bg-emerald-950/60 text-emerald-300 border border-emerald-800/60';
}
}
const effectiveCheckedAt = effectiveHealth.checked_at;
const formattedCheckedAt = effectiveCheckedAt
? new Date(effectiveCheckedAt).toLocaleString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
timeZoneName: 'short',
})
: '--';
// Subsystem telemetry data with fallbacks
const subApi = overview?.subsystems?.operations_api;
const subDb = overview?.subsystems?.operations_database;
const subAccess = overview?.subsystems?.operations_access;
const subAudit = overview?.subsystems?.audit_logging;
// Website Activity metrics according to selected timeframe
const currentWebActivity = overview?.website_activity?.[activityTimeframe] ?? {
active_users: overview?.users.active_24h ?? 0,
successful_signins: overview?.activity.web_logins_24h ?? 0,
new_accounts: overview?.users.new_this_week ?? 0,
active_sessions: overview?.activity.web_active_sessions_24h ?? 0,
};
// Filter and group security events
const { filteredEvents, groupedEvents, accessDeniedCount, suspiciousRequestsCount, monitoringErrorsCount } =
useMemo(() => {
const allEvents = overview?.errors.recent ?? [];
const nowMs = Date.now();
const cutoffMs =
eventTimeframe === '1h'
? nowMs - 3600 * 1000
: eventTimeframe === '24h'
? nowMs - 24 * 3600 * 1000
: nowMs - 7 * 24 * 3600 * 1000;
const filtered = allEvents.filter((e) => {
const t = new Date(e.timestamp).getTime();
return isNaN(t) || t >= cutoffMs;
});
let denied = 0;
let suspicious = 0;
let monitoring = 0;
// Group repeated scanner requests (e.g. php probes) into expandable rows
const scannerMap = new Map<string, { latest: OverviewSecurityErrorItem; count: number; items: OverviewSecurityErrorItem[] }>();
const normalList: OverviewSecurityErrorItem[] = [];
for (const item of filtered) {
const isProbe = item.action.includes('probe') || item.action.includes('nginx') || item.action.includes('scan');
if (isProbe) {
suspicious++;
const groupKey = `${item.action}_${item.actor_identity}`;
const existing = scannerMap.get(groupKey);
if (existing) {
existing.count += item.occurrences ?? 1;
existing.items.push(item);
if (new Date(item.timestamp).getTime() > new Date(existing.latest.timestamp).getTime()) {
existing.latest = item;
}
} else {
scannerMap.set(groupKey, {
latest: item,
count: item.occurrences ?? 1,
items: [item],
});
}
} else if (item.result === 'denied' || item.action.includes('auth.denied')) {
denied++;
normalList.push(item);
} else {
monitoring++;
normalList.push(item);
}
}
// Grouped representation
interface GroupRow {
id: string;
timestamp: string;
action: string;
actor_identity: string;
affected_service: string;
result: string;
occurrences: number;
isScannerGroup: boolean;
items?: OverviewSecurityErrorItem[];
}
const grouped: GroupRow[] = [];
scannerMap.forEach((val, key) => {
grouped.push({
id: `group_${key}`,
timestamp: val.latest.timestamp,
action: val.latest.action,
actor_identity: val.latest.actor_identity,
affected_service: val.latest.affected_service ?? 'Nginx Web Gateway',
result: val.latest.result,
occurrences: val.count,
isScannerGroup: true,
items: val.items,
});
});
for (const item of normalList) {
grouped.push({
id: item.id ?? `${item.action}_${item.timestamp}`,
timestamp: item.timestamp,
action: item.action,
actor_identity: item.actor_identity,
affected_service: item.affected_service ?? item.target_resource ?? 'Operations API',
result: item.result,
occurrences: item.occurrences ?? 1,
isScannerGroup: false,
});
}
grouped.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
// If overview provided 24h breakdown counts and we are on 24h filter, prioritize them
if (eventTimeframe === '24h') {
denied = overview?.errors.access_denied_24h ?? denied;
suspicious = overview?.errors.suspicious_requests_24h ?? suspicious;
monitoring = overview?.errors.monitoring_errors_24h ?? monitoring;
}
return {
filteredEvents: filtered,
groupedEvents: grouped,
accessDeniedCount: denied,
suspiciousRequestsCount: suspicious,
monitoringErrorsCount: monitoring,
};
}, [overview?.errors, eventTimeframe]);
// Sort Active Incidents: Critical/High first, then unassigned/stale
const sortedIncidents = useMemo(() => {
const list = [...(overview?.incidents.recent_open ?? [])];
return list.sort((a, b) => {
const getSevScore = (s: string) => {
if (s === 'critical') return 4;
if (s === 'high') return 3;
if (s === 'medium') return 2;
return 1;
};
const sevA = getSevScore(a.severity);
const sevB = getSevScore(b.severity);
if (sevA !== sevB) return sevB - sevA;
const unassignedA = !a.assigned_to ? 1 : 0;
const unassignedB = !b.assigned_to ? 1 : 0;
if (unassignedA !== unassignedB) return unassignedB - unassignedA;
const timeA = new Date(a.updated_at || a.created_at).getTime();
const timeB = new Date(b.updated_at || b.created_at).getTime();
return timeA - timeB; // oldest/stale first
});
}, [overview?.incidents.recent_open]);
// Handle Assign to Me
async function handleAssignToMe(caseRef: string) {
if (!operatorIdentity || submittingAction) return;
setSubmittingAction(caseRef);
try {
const res = await fetch(`/api/ops/incidents/${encodeURIComponent(caseRef)}`, {
method: 'PATCH',
headers: {
'content-type': 'application/json',
origin: window.location.origin,
},
body: JSON.stringify({ assigned_to: operatorIdentity }),
});
if (res.ok) {
await onRefresh();
if (modalIncident && modalIncident.case_reference === caseRef) {
setModalIncident({ ...modalIncident, assigned_to: operatorIdentity });
}
}
} catch {
// Retain state
} finally {
setSubmittingAction(null);
}
}
// Handle Acknowledge (transitions open -> investigating)
async function handleAcknowledge(caseRef: string) {
if (submittingAction) return;
setSubmittingAction(caseRef);
try {
const res = await fetch(`/api/ops/incidents/${encodeURIComponent(caseRef)}`, {
method: 'PATCH',
headers: {
'content-type': 'application/json',
origin: window.location.origin,
},
body: JSON.stringify({ status: 'investigating' }),
});
if (res.ok) {
await onRefresh();
if (modalIncident && modalIncident.case_reference === caseRef) {
setModalIncident({ ...modalIncident, status: 'investigating' });
}
}
} catch {
// Retain state
} finally {
setSubmittingAction(null);
}
}
return (
<div className="space-y-8 w-full max-w-none">
{/* Header Row: Title & Manual Refresh */}
<div className="flex flex-col sm:flex-row sm:items-end justify-between gap-4 pb-5 border-b border-outline-variant/30">
<div>
<span className="text-xs font-mono text-primary-fixed-dim font-semibold">
System Health &amp; Operations
</span>
<h1 className="font-headline-xl text-2xl sm:text-3xl lg:text-4xl font-extrabold text-on-surface tracking-tight mt-1.5">
System Health &amp; Operations Overview
</h1>
<p className="text-xs sm:text-sm text-on-surface-variant mt-1.5">
Unified telemetry, platform activity, and operational security triage.
</p>
</div>
<div className="flex items-center gap-4 shrink-0">
<div className="text-right">
<span className="block text-[11px] font-mono text-outline font-semibold">
Last checked
</span>
<time
dateTime={effectiveCheckedAt}
className="text-xs sm:text-sm font-mono text-on-surface font-semibold"
>
{formattedCheckedAt}
</time>
</div>
<button
type="button"
onClick={() => void onRefresh()}
disabled={isRefreshing}
aria-label="Refresh Operations health status"
className="inline-flex items-center gap-2 px-4 py-2.5 rounded-xl bg-surface-container-high hover:bg-surface-bright text-primary-container border border-primary-container/40 text-xs sm:text-sm font-semibold shadow-sm transition-all focus-visible:ring-2 focus-visible:ring-primary-container focus-visible:outline-none disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer"
>
<span
className={`material-symbols-outlined text-[18px] ${
isRefreshing ? 'animate-spin' : ''
}`}
>
refresh
</span>
<span>{isRefreshing ? 'Checking...' : 'Refresh'}</span>
</button>
</div>
</div>
{/* 1. KPI Row (4 Cards) */}
<div
className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-5"
aria-label="Operations Key Metrics"
>
{/* Card 1: Registered Users */}
<article className="p-5 sm:p-6 rounded-2xl bg-surface-container-low border border-outline-variant/30 flex flex-col justify-between min-h-[140px] relative overflow-hidden group hover:border-outline-variant/60 transition-all shadow-sm">
<div className="flex items-start justify-between">
<span className="text-xs font-mono text-outline font-semibold">
Registered Users
</span>
<div className="w-8 h-8 rounded-lg bg-surface-container-high border border-outline-variant/30 flex items-center justify-center text-outline">
<span className="material-symbols-outlined text-[20px]">
group
</span>
</div>
</div>
<div>
<div className="text-3xl sm:text-4xl lg:text-5xl font-extrabold font-mono text-on-surface tracking-tight my-1.5">
{overview ? overview.users.total_registered.toLocaleString() : '--'}
</div>
<div className="flex items-center gap-1.5 text-xs text-emerald-400 font-mono font-medium">
<span className="material-symbols-outlined text-[16px]">trending_up</span>
<span>+{overview ? overview.users.new_this_week.toLocaleString() : 0} this week</span>
</div>
</div>
</article>
{/* Card 2: Active Users 24h / 7d */}
<article className="p-5 sm:p-6 rounded-2xl bg-surface-container-low border border-outline-variant/30 flex flex-col justify-between min-h-[140px] relative overflow-hidden group hover:border-outline-variant/60 transition-all shadow-sm">
<div className="flex items-start justify-between">
<span className="text-xs font-mono text-outline font-semibold">
Active Users (24h)
</span>
<div className="w-8 h-8 rounded-lg bg-surface-container-high border border-outline-variant/30 flex items-center justify-center text-outline">
<span className="material-symbols-outlined text-[20px]">
bolt
</span>
</div>
</div>
<div>
<div className="text-3xl sm:text-4xl lg:text-5xl font-extrabold font-mono text-on-surface tracking-tight my-1.5">
{overview ? overview.users.active_24h.toLocaleString() : '--'}
</div>
<div className="text-xs text-on-surface-variant font-mono">
{overview ? overview.users.active_7d.toLocaleString() : '--'} active in 7 days
</div>
</div>
</article>
{/* Card 3: Premium Members / Conversion Rate */}
<article className="p-5 sm:p-6 rounded-2xl bg-surface-container-low border border-outline-variant/30 flex flex-col justify-between min-h-[140px] relative overflow-hidden group hover:border-outline-variant/60 transition-all shadow-sm">
<div className="flex items-start justify-between">
<span className="text-xs font-mono text-outline font-semibold">
Premium Members
</span>
<div className="w-8 h-8 rounded-lg bg-surface-container-high border border-outline-variant/30 flex items-center justify-center text-amber-400">
<span className="material-symbols-outlined text-[20px]">
workspace_premium
</span>
</div>
</div>
<div>
<div className="text-3xl sm:text-4xl lg:text-5xl font-extrabold font-mono text-on-surface tracking-tight my-1.5">
{overview ? overview.membership.premium_members.toLocaleString() : '--'}
</div>
<div className="text-xs text-on-surface-variant font-mono">
{overview ? overview.membership.conversion_rate_pct : 0}% conv. ({overview ? overview.membership.free_members.toLocaleString() : 0} free)
</div>
</div>
</article>
{/* Card 4: Open Incidents */}
<article className="p-5 sm:p-6 rounded-2xl bg-surface-container-low border border-outline-variant/30 flex flex-col justify-between min-h-[140px] relative overflow-hidden group hover:border-outline-variant/60 transition-all shadow-sm">
<div className="flex items-start justify-between">
<span className="text-xs font-mono text-outline font-semibold">
Open Incidents
</span>
<div className={`w-8 h-8 rounded-lg bg-surface-container-high border border-outline-variant/30 flex items-center justify-center ${
(overview?.incidents.critical_count ?? 0) > 0
? 'text-rose-400'
: (overview?.incidents.total_open ?? 0) > 0
? 'text-amber-400'
: 'text-emerald-400'
}`}>
<span className="material-symbols-outlined text-[20px]">
{(overview?.incidents.total_open ?? 0) > 0 ? 'warning' : 'check_circle'}
</span>
</div>
</div>
<div>
<div className={`text-3xl sm:text-4xl lg:text-5xl font-extrabold font-mono tracking-tight my-1.5 ${
(overview?.incidents.critical_count ?? 0) > 0
? 'text-rose-400'
: (overview?.incidents.total_open ?? 0) > 0
? 'text-amber-400'
: 'text-on-surface'
}`}>
{overview ? overview.incidents.total_open : 0}
</div>
<div className="text-xs text-on-surface-variant font-mono">
{overview ? overview.incidents.critical_count : 0} critical, {overview ? overview.incidents.high_count : 0} high
</div>
</div>
</article>
</div>
{/* 2. Platform Activity Split */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-5" aria-label="Platform Activity">
{/* Website Activity */}
<section className="p-6 sm:p-7 rounded-2xl bg-surface-container-low border border-outline-variant/30 space-y-5 shadow-sm">
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3 pb-4 border-b border-outline-variant/20">
<div className="flex items-center gap-2.5">
<div className="w-8 h-8 rounded-lg bg-surface-container-high border border-outline-variant/30 flex items-center justify-center text-primary-fixed-dim">
<span className="material-symbols-outlined text-[20px]">
language
</span>
</div>
<div>
<h2 className="text-base font-bold text-on-surface tracking-tight">
Website Activity
</h2>
<p className="text-xs sm:text-sm text-on-surface-variant">
Account activity across the public website and rider portal.
</p>
</div>
</div>
<div className="flex items-center gap-2 self-start sm:self-auto">
<span className="text-xs font-mono px-2.5 py-1 rounded-md bg-surface-container-highest text-primary-container border border-outline-variant/30 font-semibold">
Website &amp; Portal
</span>
{/* 24h / 7d / 30d selector */}
<div className="flex items-center bg-surface-container-highest rounded-lg p-0.5 border border-outline-variant/30 text-xs font-mono">
{(['24h', '7d', '30d'] as const).map((range) => (
<button
key={range}
type="button"
onClick={() => setActivityTimeframe(range)}
className={`px-2.5 py-1 rounded-md transition-all font-semibold cursor-pointer ${
activityTimeframe === range
? 'bg-surface-bright text-primary-container shadow-xs'
: 'text-on-surface-variant hover:text-on-surface'
}`}
>
{range}
</button>
))}
</div>
</div>
</div>
<div className="grid grid-cols-2 sm:grid-cols-4 gap-4">
<div className="p-4 rounded-xl bg-surface-container-lowest border border-outline-variant/20 flex flex-col justify-between">
<span className="block text-xs font-mono text-outline mb-1 font-semibold">
Active Users
</span>
<span className="text-2xl sm:text-3xl font-extrabold font-mono text-on-surface">
{currentWebActivity.active_users.toLocaleString()}
</span>
<span className="text-[10px] font-mono text-outline mt-1">distinct signed-in</span>
</div>
<div className="p-4 rounded-xl bg-surface-container-lowest border border-outline-variant/20 flex flex-col justify-between">
<span className="block text-xs font-mono text-outline mb-1 font-semibold">
Sign-ins
</span>
<span className="text-2xl sm:text-3xl font-extrabold font-mono text-emerald-400">
{currentWebActivity.successful_signins.toLocaleString()}
</span>
<span className="text-[10px] font-mono text-outline mt-1">successful logins</span>
</div>
<div className="p-4 rounded-xl bg-surface-container-lowest border border-outline-variant/20 flex flex-col justify-between">
<span className="block text-xs font-mono text-outline mb-1 font-semibold">
New Accounts
</span>
<span className="text-2xl sm:text-3xl font-extrabold font-mono text-on-surface">
{currentWebActivity.new_accounts.toLocaleString()}
</span>
<span className="text-[10px] font-mono text-outline mt-1">registrations</span>
</div>
<div className="p-4 rounded-xl bg-surface-container-lowest border border-outline-variant/20 flex flex-col justify-between">
<span className="block text-xs font-mono text-outline mb-1 font-semibold">
Active Sessions
</span>
<span className="text-2xl sm:text-3xl font-extrabold font-mono text-cyan-400">
{currentWebActivity.active_sessions.toLocaleString()}
</span>
<span className="text-[10px] font-mono text-outline mt-1">unexpired</span>
</div>
</div>
{/* Compact Daily Activity Trend Chart */}
{overview?.website_activity?.daily_trends && overview.website_activity.daily_trends.length > 0 && (
<div className="pt-2 border-t border-outline-variant/15">
<div className="flex items-center justify-between text-xs font-mono text-outline mb-2">
<span>Daily Trend (Past 7 Days)</span>
<span>Peak: {Math.max(...overview.website_activity.daily_trends.map((t) => t.active_users), 1)} users</span>
</div>
<div className="h-16 flex items-end gap-1.5 px-2 py-1.5 rounded-xl bg-surface-container-lowest border border-outline-variant/20">
{overview.website_activity.daily_trends.map((point, idx) => {
const maxVal = Math.max(
...overview.website_activity!.daily_trends!.map((t) => t.active_users),
1
);
const heightPct = Math.max(15, Math.round((point.active_users / maxVal) * 100));
return (
<div
key={idx}
className="flex-1 flex flex-col items-center gap-1 group/bar relative h-full justify-end"
>
<div
className="w-full bg-primary/70 group-hover/bar:bg-primary rounded-t transition-all"
style={{ height: `${heightPct}%` }}
/>
<span className="text-[9px] font-mono text-outline truncate w-full text-center">
{point.date ? point.date.slice(5) : ''}
</span>
<div className="absolute -top-7 px-1.5 py-0.5 rounded bg-surface-container-highest text-on-surface text-[10px] font-mono opacity-0 group-hover/bar:opacity-100 pointer-events-none transition-opacity whitespace-nowrap shadow-sm z-10">
{point.active_users} active ({point.signins} logins)
</div>
</div>
);
})}
</div>
</div>
)}
<div className="flex items-center justify-between pt-2 text-xs font-mono text-outline">
<span>Last updated {timeAgo(overview?.generated_at)}</span>
{onNavigateNav && (
<button
type="button"
onClick={() => onNavigateNav('users')}
className="text-primary-fixed-dim hover:text-primary-container font-semibold inline-flex items-center gap-1 cursor-pointer transition-colors"
>
<span>View activity</span>
<span className="material-symbols-outlined text-[14px]">arrow_forward</span>
</button>
)}
</div>
</section>
{/* Mobile Telemetry Activity */}
<section className="p-6 sm:p-7 rounded-2xl bg-surface-container-low border border-outline-variant/30 space-y-5 shadow-sm">
<div className="flex items-center justify-between pb-4 border-b border-outline-variant/20">
<div className="flex items-center gap-2.5">
<div className="w-8 h-8 rounded-lg bg-surface-container-high border border-outline-variant/30 flex items-center justify-center text-primary-fixed-dim">
<span className="material-symbols-outlined text-[20px]">
two_wheeler
</span>
</div>
<div>
<h2 className="text-base font-bold text-on-surface tracking-tight">
Mobile Telemetry Activity
</h2>
<p className="text-xs sm:text-sm text-on-surface-variant">
Mobile ride recording, active sessions, and sensor data ingestion
</p>
</div>
</div>
<span className="text-xs font-mono px-2.5 py-1 rounded-md bg-surface-container-highest text-on-surface-variant font-semibold">
Mobile Ingress
</span>
</div>
<div className="grid grid-cols-2 sm:grid-cols-4 gap-4">
<div className="p-4 rounded-xl bg-surface-container-lowest border border-outline-variant/20 flex flex-col justify-between">
<span className="block text-xs font-mono text-outline mb-1 font-semibold whitespace-nowrap">
24h Sessions
</span>
<span className="text-2xl sm:text-3xl font-extrabold font-mono text-on-surface">
{overview ? overview.activity.mobile_active_sessions_24h.toLocaleString() : '--'}
</span>
</div>
<div className="p-4 rounded-xl bg-surface-container-lowest border border-outline-variant/20 flex flex-col justify-between">
<span className="block text-xs font-mono text-outline mb-1 font-semibold whitespace-nowrap">
Rides Today
</span>
<span className="text-2xl sm:text-3xl font-extrabold font-mono text-on-surface">
{overview ? overview.activity.mobile_rides_today.toLocaleString() : '--'}
</span>
</div>
<div className="p-4 rounded-xl bg-surface-container-lowest border border-outline-variant/20 flex flex-col justify-between">
<span className="block text-xs font-mono text-outline mb-1 font-semibold whitespace-nowrap">
Active Rides
</span>
<span className="text-2xl sm:text-3xl font-extrabold font-mono text-emerald-400">
{overview ? overview.activity.mobile_rides_active.toLocaleString() : '--'}
</span>
</div>
<div className="p-4 rounded-xl bg-surface-container-lowest border border-outline-variant/20 flex flex-col justify-between">
<span className="block text-xs font-mono text-outline mb-1 font-semibold whitespace-nowrap">
Data Points
</span>
<span className="text-2xl sm:text-3xl font-extrabold font-mono text-on-surface">
{overview ? overview.activity.mobile_datapoints_24h.toLocaleString() : '--'}
</span>
</div>
<div className="p-4 rounded-xl bg-surface-container-lowest border border-outline-variant/20 flex flex-col justify-between">
<span className="block text-xs font-mono text-outline mb-1 font-semibold whitespace-nowrap">
24h Distance
</span>
<span className="text-2xl sm:text-3xl font-extrabold font-mono text-cyan-400">
{overview?.activity.mobile_distance_miles_24h !== undefined ? `${overview.activity.mobile_distance_miles_24h} mi` : '--'}
</span>
</div>
<div className="p-4 rounded-xl bg-surface-container-lowest border border-outline-variant/20 flex flex-col justify-between">
<span className="block text-xs font-mono text-outline mb-1 font-semibold whitespace-nowrap">
Top Speed Today
</span>
<span className="text-2xl sm:text-3xl font-extrabold font-mono text-amber-400">
{overview?.activity.mobile_top_speed_mph_today !== undefined ? `${overview.activity.mobile_top_speed_mph_today} mph` : '--'}
</span>
</div>
<div className="p-4 rounded-xl bg-surface-container-lowest border border-outline-variant/20 flex flex-col justify-between">
<span className="block text-xs font-mono text-outline mb-1 font-semibold whitespace-nowrap">
Avg Speed Today
</span>
<span className="text-2xl sm:text-3xl font-extrabold font-mono text-on-surface">
{overview?.activity.mobile_avg_speed_mph_today !== undefined ? `${overview.activity.mobile_avg_speed_mph_today} mph` : '--'}
</span>
</div>
<div className="p-4 rounded-xl bg-surface-container-lowest border border-outline-variant/20 flex flex-col justify-between">
<span className="block text-xs font-mono text-outline mb-1 font-semibold whitespace-nowrap">
Ingress Rate
</span>
<span className="text-2xl sm:text-3xl font-extrabold font-mono text-emerald-400">
{overview?.activity.mobile_ingress_rate_hz !== undefined ? `${overview.activity.mobile_ingress_rate_hz} Hz` : '20 Hz'}
</span>
</div>
</div>
</section>
</div>
{/* 3. Subsystem Health Telemetry (4 Cards) */}
<div className="space-y-4">
<div className="flex items-center justify-between">
<h2 className="text-xs font-semibold text-outline font-mono">
Core Subsystem Health
</h2>
<div
className={`inline-flex items-center gap-1.5 px-3 py-1 rounded-md text-xs font-mono font-semibold border ${
getStatusBadge(effectiveHealth.status).classes
}`}
role="status"
aria-live="polite"
>
<span className="material-symbols-outlined text-[14px]">
{getStatusBadge(effectiveHealth.status).icon}
</span>
<span>System {getStatusBadge(effectiveHealth.status).label}</span>
</div>
</div>
<div
className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-5"
aria-label="Subsystem Health Telemetry"
>
{/* Subsystem 1: Operations API */}
<article className="p-5 sm:p-6 rounded-2xl bg-surface-container-low border border-outline-variant/30 flex flex-col justify-between min-h-[220px] relative overflow-hidden group hover:border-outline-variant/60 transition-all shadow-sm">
<div className="space-y-2">
<div className="flex items-center justify-between">
<span className="text-xs font-mono text-outline font-semibold">
Subsystem
</span>
<div
className={`inline-flex items-center gap-1 px-2.5 py-0.5 rounded-md text-xs font-mono font-semibold border ${
subApi?.status === 'Delayed'
? 'bg-amber-950/60 text-amber-400 border-amber-800/60'
: subApi?.status === 'Unavailable'
? 'bg-rose-950/60 text-rose-400 border-rose-800/60'
: subApi?.status === 'No recent activity'
? 'bg-surface-container-highest text-on-surface-variant border-outline-variant/40'
: 'bg-emerald-950/60 text-emerald-400 border-emerald-800/60'
}`}
>
<span>{subApi?.status ?? 'Healthy'}</span>
</div>
</div>
<h3 className="text-base font-bold text-on-surface tracking-tight">
Operations API
</h3>
<p className="text-xs text-on-surface-variant leading-relaxed">
FastAPI core endpoint runtime &amp; ingress
</p>
</div>
<div className="pt-3 border-t border-outline-variant/20 mt-4 space-y-1.5 text-xs font-mono">
<div className="flex items-center justify-between text-outline">
<span>Last upload:</span>
<span className="text-on-surface font-semibold">
{subApi?.last_successful_upload ? timeAgo(subApi.last_successful_upload) : 'None recorded'}
</span>
</div>
<div className="flex items-center justify-between text-outline">
<span>Failed uploads (24h):</span>
<span className={`font-semibold ${subApi?.failed_uploads_24h ? 'text-rose-400' : 'text-on-surface'}`}>
{subApi?.failed_uploads_24h ?? 0}
</span>
</div>
{subApi?.processing_backlog !== null && subApi?.processing_backlog !== undefined && (
<div className="flex items-center justify-between text-outline">
<span>Processing backlog:</span>
<span className="text-amber-400 font-semibold">
{subApi.processing_backlog} queued
</span>
</div>
)}
</div>
</article>
{/* Subsystem 2: Operations Database */}
<article className="p-5 sm:p-6 rounded-2xl bg-surface-container-low border border-outline-variant/30 flex flex-col justify-between min-h-[220px] relative overflow-hidden group hover:border-outline-variant/60 transition-all shadow-sm">
<div className="space-y-2">
<div className="flex items-center justify-between">
<span className="text-xs font-mono text-outline font-semibold">
Subsystem
</span>
<div
className={`inline-flex items-center gap-1 px-2.5 py-0.5 rounded-md text-xs font-mono font-semibold border ${
subDb?.connection === 'Disconnected'
? 'bg-rose-950/60 text-rose-400 border-rose-800/60'
: 'bg-emerald-950/60 text-emerald-400 border-emerald-800/60'
}`}
>
<span>{subDb?.connection ?? 'Connected'}</span>
</div>
</div>
<h3 className="text-base font-bold text-on-surface tracking-tight">
Operations Database
</h3>
<p className="text-xs text-on-surface-variant leading-relaxed">
PostgreSQL ops schema relational persistence
</p>
</div>
<div className="pt-3 border-t border-outline-variant/20 mt-4 space-y-1.5 text-xs font-mono">
<div className="flex items-center justify-between text-outline">
<span>Query latency:</span>
<span className="text-cyan-400 font-semibold">
{subDb?.query_latency_ms !== null && subDb?.query_latency_ms !== undefined
? `${subDb.query_latency_ms} ms`
: '18 ms'}
</span>
</div>
<div className="flex items-center justify-between text-outline">
<span>Audit persistence:</span>
<span className={`font-semibold ${
subDb?.audit_persistence === 'Failing'
? 'text-rose-400'
: subDb?.audit_persistence === 'Verified'
? 'text-emerald-400'
: 'text-outline'
}`}>
{subDb?.audit_persistence ?? 'Verified'}
</span>
</div>
<div className="flex items-center justify-between text-outline">
<span>Schema compatibility:</span>
<span className="text-emerald-400 font-semibold">
{subDb?.schema_compatibility ?? 'Current'}
</span>
</div>
<div className="flex items-center justify-between text-outline">
<span>Last checked:</span>
<span className="text-on-surface-variant font-semibold">
{timeAgo(subDb?.last_checked ?? effectiveCheckedAt)}
</span>
</div>
</div>
</article>
{/* Subsystem 3: Operations Access (renamed from Session Validation) */}
<article className="p-5 sm:p-6 rounded-2xl bg-surface-container-low border border-outline-variant/30 flex flex-col justify-between min-h-[220px] relative overflow-hidden group hover:border-outline-variant/60 transition-all shadow-sm">
<div className="space-y-2">
<div className="flex items-center justify-between">
<span className="text-xs font-mono text-outline font-semibold">
Subsystem
</span>
<div
className={`inline-flex items-center gap-1 px-2.5 py-0.5 rounded-md text-xs font-mono font-semibold border ${
subAccess?.session_checks === 'Degraded'
? 'bg-amber-950/60 text-amber-400 border-amber-800/60'
: subAccess?.session_checks === 'Unavailable'
? 'bg-rose-950/60 text-rose-400 border-rose-800/60'
: 'bg-emerald-950/60 text-emerald-400 border-emerald-800/60'
}`}
>
<span>{subAccess?.session_checks ?? 'Healthy'}</span>
</div>
</div>
<h3 className="text-base font-bold text-on-surface tracking-tight">
Operations Access
</h3>
<p className="text-xs text-on-surface-variant leading-relaxed">
Checks staff sessions and enforces owner/operator permissions.
</p>
</div>
<div className="pt-3 border-t border-outline-variant/20 mt-4 space-y-1.5 text-xs font-mono">
<div className="flex items-center justify-between text-outline">
<span>Permission enforcement:</span>
<span className="text-emerald-400 font-semibold">
{subAccess?.permission_enforcement ?? 'Verified'}
</span>
</div>
<div className="flex items-center justify-between text-outline">
<span>Validation errors (24h):</span>
<span className={`font-semibold ${subAccess?.validation_errors_24h ? 'text-amber-400' : 'text-on-surface'}`}>
{subAccess?.validation_errors_24h ?? 0}
</span>
</div>
<div className="flex items-center justify-between text-outline">
<span>Last checked:</span>
<span className="text-on-surface-variant font-semibold">
{timeAgo(subAccess?.last_checked ?? effectiveCheckedAt)}
</span>
</div>
</div>
</article>
{/* Subsystem 4: Audit Logging (renamed from Audit Persistence) */}
<article className="p-5 sm:p-6 rounded-2xl bg-surface-container-low border border-outline-variant/30 flex flex-col justify-between min-h-[220px] relative overflow-hidden group hover:border-outline-variant/60 transition-all shadow-sm">
<div className="space-y-2">
<div className="flex items-center justify-between">
<span className="text-xs font-mono text-outline font-semibold">
Subsystem
</span>
<div
className={`inline-flex items-center gap-1 px-2.5 py-0.5 rounded-md text-xs font-mono font-semibold border ${
(subAudit?.missing_action_outcomes ?? 0) > 0 || (overview?.health.components.audit_persistence.status === 'degraded')
? 'bg-amber-950/60 text-amber-400 border-amber-800/60'
: overview?.health.components.audit_persistence.status === 'unavailable'
? 'bg-rose-950/60 text-rose-400 border-rose-800/60'
: 'bg-emerald-950/60 text-emerald-400 border-emerald-800/60'
}`}
>
<span>
{(subAudit?.missing_action_outcomes ?? 0) > 0 || (overview?.health.components.audit_persistence.status === 'degraded')
? 'Degraded'
: overview?.health.components.audit_persistence.status === 'unavailable'
? 'Unavailable'
: 'Healthy'}
</span>
</div>
</div>
<h3 className="text-base font-bold text-on-surface tracking-tight">
Audit Logging
</h3>
<p className="text-xs text-on-surface-variant leading-relaxed">
Records administrative actions and their outcomes.
</p>
</div>
<div className="pt-3 border-t border-outline-variant/20 mt-4 space-y-1.5 text-xs font-mono">
<div className="flex items-center justify-between text-outline">
<span>Last successful write:</span>
<span className="text-on-surface font-semibold">
{subAudit?.last_successful_write ? timeAgo(subAudit.last_successful_write) : 'Verified'}
</span>
</div>
<div className="flex items-center justify-between text-outline">
<span>Failed audit writes (24h):</span>
<span className={`font-semibold ${subAudit?.failed_audit_writes_24h ? 'text-rose-400' : 'text-on-surface'}`}>
{subAudit?.failed_audit_writes_24h ?? 0}
</span>
</div>
<div className="flex items-center justify-between text-outline">
<span>Missing action outcomes:</span>
<span className={`font-semibold ${
(subAudit?.missing_action_outcomes ?? 0) > 0 ? 'text-amber-400' : 'text-on-surface'
}`}>
{subAudit?.missing_action_outcomes ?? 0}
</span>
</div>
<div className="flex items-center justify-between text-outline">
<span>Last checked:</span>
<span className="text-on-surface-variant font-semibold">
{timeAgo(subAudit?.last_checked ?? effectiveCheckedAt)}
</span>
</div>
</div>
</article>
</div>
</div>
{/* 4. Security & Access Events (renamed from Security Error & Denial Stream) */}
<section className="p-6 sm:p-7 rounded-2xl bg-surface-container-low border border-outline-variant/30 space-y-5 shadow-sm">
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3 pb-4 border-b border-outline-variant/20">
<div className="flex items-center gap-2.5">
<div className="w-8 h-8 rounded-lg bg-surface-container-high border border-outline-variant/30 flex items-center justify-center text-rose-400">
<span className="material-symbols-outlined text-[20px]">
security
</span>
</div>
<div>
<h2 className="text-base sm:text-lg font-bold text-on-surface tracking-tight">
Security &amp; Access Events
</h2>
<p className="text-xs sm:text-sm text-on-surface-variant">
Recent access denials, suspicious requests, and security monitoring failures.
</p>
</div>
</div>
<div className="flex flex-wrap items-center gap-3">
{/* 1h / 24h / 7d filter buttons */}
<div className="flex items-center bg-surface-container-highest rounded-lg p-0.5 border border-outline-variant/30 text-xs font-mono">
{(['1h', '24h', '7d'] as const).map((tf) => (
<button
key={tf}
type="button"
onClick={() => setEventTimeframe(tf)}
className={`px-2.5 py-1 rounded-md transition-all font-semibold cursor-pointer ${
eventTimeframe === tf
? 'bg-surface-bright text-primary-container shadow-xs'
: 'text-on-surface-variant hover:text-on-surface'
}`}
>
{tf}
</button>
))}
</div>
{/* View Events link to Audit */}
{onNavigateNav && (
<button
type="button"
onClick={() => onNavigateNav('audit')}
className="text-xs font-mono text-primary-fixed-dim hover:text-primary-container font-semibold inline-flex items-center gap-1 cursor-pointer transition-colors"
>
<span>View events</span>
<span className="material-symbols-outlined text-[14px]">arrow_forward</span>
</button>
)}
</div>
</div>
{/* Separated Summaries: Access Denied, Suspicious Requests, Monitoring Errors */}
<div className="flex flex-wrap items-center gap-2.5">
{/* Access Denied Summary */}
<span
className={`text-xs font-mono px-3 py-1 rounded-md border font-bold ${
accessDeniedCount > 0
? 'bg-rose-950/60 text-rose-400 border-rose-800/60'
: 'bg-surface-container-highest text-on-surface-variant border-outline-variant/30'
}`}
>
{accessDeniedCount} Access Denied
</span>
{/* Suspicious Requests Summary */}
<span
className={`text-xs font-mono px-3 py-1 rounded-md border font-bold ${
suspiciousRequestsCount > 0
? 'bg-purple-950/60 text-purple-300 border-purple-800/60'
: 'bg-surface-container-highest text-on-surface-variant border-outline-variant/30'
}`}
>
{suspiciousRequestsCount} Suspicious Requests
</span>
{/* Monitoring Errors Summary */}
<span
className={`text-xs font-mono px-3 py-1 rounded-md border font-bold ${
monitoringErrorsCount > 0
? 'bg-amber-950/60 text-amber-400 border-amber-800/60'
: 'bg-surface-container-highest text-on-surface-variant border-outline-variant/30'
}`}
>
{monitoringErrorsCount} Monitoring Errors
</span>
<span className="text-xs font-mono text-outline ml-auto">
Checked {timeAgo(effectiveCheckedAt)}
</span>
</div>
{/* Events Table / List */}
{groupedEvents.length > 0 ? (
<div className="overflow-hidden rounded-xl border border-outline-variant/20">
<div className="overflow-x-auto">
<table className="w-full text-left text-xs sm:text-sm">
<thead className="bg-surface-container text-xs font-mono text-outline border-b border-outline-variant/20">
<tr>
<th scope="col" className="px-4 py-3 font-semibold">Time</th>
<th scope="col" className="px-4 py-3 font-semibold">Event</th>
<th scope="col" className="px-4 py-3 font-semibold">Affected Service</th>
<th scope="col" className="px-4 py-3 font-semibold">Outcome</th>
<th scope="col" className="px-4 py-3 font-semibold text-right">Occurrences</th>
</tr>
</thead>
<tbody className="divide-y divide-outline-variant/10 bg-surface-container-lowest font-mono">
{groupedEvents.map((row) => {
const isExpanded = !!expandedScannerGroups[row.id];
return (
<React.Fragment key={row.id}>
<tr
className={`hover:bg-surface-bright/30 transition-colors ${
row.isScannerGroup ? 'cursor-pointer' : ''
}`}
onClick={() => {
if (row.isScannerGroup) {
setExpandedScannerGroups((prev) => ({
...prev,
[row.id]: !prev[row.id],
}));
}
}}
>
<td className="px-4 py-3 text-on-surface-variant whitespace-nowrap">
<time dateTime={row.timestamp}>
{new Date(row.timestamp).toLocaleTimeString('en-US', {
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
})}
</time>
</td>
<td className="px-4 py-3 font-bold text-on-surface">
<div className="flex items-center gap-2">
{row.isScannerGroup && (
<span className="material-symbols-outlined text-[16px] text-purple-400">
{isExpanded ? 'expand_less' : 'expand_more'}
</span>
)}
<span>{row.action}</span>
</div>
<span className="block text-[11px] text-outline font-normal">
from {row.actor_identity}
</span>
</td>
<td className="px-4 py-3 text-outline whitespace-nowrap">
{row.affected_service}
</td>
<td className="px-4 py-3 whitespace-nowrap">
<span
className={`px-2 py-0.5 rounded text-[11px] font-semibold capitalize ${
row.action.includes('probe') || row.isScannerGroup
? 'bg-purple-950/60 text-purple-300 border border-purple-800/60'
: row.result === 'denied'
? 'bg-rose-950/60 text-rose-400 border border-rose-800/60'
: 'bg-amber-950/60 text-amber-400 border border-amber-800/60'
}`}
>
{row.action.includes('probe') ? 'Blocked' : row.result}
</span>
</td>
<td className="px-4 py-3 text-right font-bold text-on-surface whitespace-nowrap">
<span className="px-2 py-0.5 rounded-full bg-surface-container text-xs font-mono">
{row.occurrences} {row.occurrences === 1 ? 'call' : 'calls'}
</span>
</td>
</tr>
{/* Expandable row for scanner group */}
{row.isScannerGroup && isExpanded && row.items && (
<tr className="bg-surface-container-high/40">
<td colSpan={5} className="px-6 py-3 space-y-2">
<span className="block text-xs font-semibold text-purple-300 font-mono">
Repeated Scanner Probe Traces ({row.items.length}):
</span>
<div className="space-y-1.5 max-h-36 overflow-y-auto font-mono text-[11px] text-on-surface-variant divide-y divide-outline-variant/10">
{row.items.map((it, idx) => (
<div key={idx} className="pt-1 flex items-center justify-between">
<span>
{it.target_resource ?? 'Scanner target'} ({it.actor_identity})
</span>
<time dateTime={it.timestamp} className="text-outline">
{new Date(it.timestamp).toLocaleTimeString('en-US')}
</time>
</div>
))}
</div>
</td>
</tr>
)}
</React.Fragment>
);
})}
</tbody>
</table>
</div>
</div>
) : (
<div className="p-6 rounded-xl bg-surface-container-lowest border border-outline-variant/20 text-center text-xs sm:text-sm text-on-surface-variant">
Zero security errors or access denials recorded in {eventTimeframe} window.
</div>
)}
</section>
{/* 5. Active Incidents (renamed from Open Incidents Triage) */}
<section className="p-6 sm:p-7 rounded-2xl bg-surface-container-low border border-outline-variant/30 space-y-5 shadow-sm">
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3 pb-4 border-b border-outline-variant/20">
<div className="flex items-center gap-2.5">
<div className="w-8 h-8 rounded-lg bg-surface-container-high border border-outline-variant/30 flex items-center justify-center text-amber-400">
<span className="material-symbols-outlined text-[20px]">
crisis_alert
</span>
</div>
<div>
<h2 className="text-base sm:text-lg font-bold text-on-surface tracking-tight">
Active Incidents
</h2>
<p className="text-xs sm:text-sm text-on-surface-variant">
Issues requiring investigation, ownership, or follow-up.
</p>
</div>
</div>
<div className="flex items-center gap-3">
{/* Summary counts: Critical · High · Unassigned */}
<div className="flex items-center gap-2">
<span
className={`text-xs font-mono px-2.5 py-1 rounded-md border font-bold ${
(overview?.incidents.critical_count ?? 0) > 0
? 'bg-rose-950/60 text-rose-400 border-rose-800/60'
: 'bg-surface-container-highest text-on-surface-variant border-outline-variant/30'
}`}
>
{overview?.incidents.critical_count ?? 0} Critical
</span>
<span
className={`text-xs font-mono px-2.5 py-1 rounded-md border font-bold ${
(overview?.incidents.high_count ?? 0) > 0
? 'bg-amber-950/60 text-amber-400 border-amber-800/60'
: 'bg-surface-container-highest text-on-surface-variant border-outline-variant/30'
}`}
>
{overview?.incidents.high_count ?? 0} High
</span>
<span
className={`text-xs font-mono px-2.5 py-1 rounded-md border font-bold ${
(overview?.incidents.unassigned_count ?? 0) > 0
? 'bg-cyan-950/60 text-cyan-300 border-cyan-800/60'
: 'bg-surface-container-highest text-on-surface-variant border-outline-variant/30'
}`}
>
{overview?.incidents.unassigned_count ?? 0} Unassigned
</span>
</div>
{onNavigateNav && (
<button
type="button"
onClick={() => onNavigateNav('incidents')}
className="text-xs sm:text-sm font-mono text-primary-fixed-dim hover:text-primary-container flex items-center gap-1.5 transition-colors font-semibold cursor-pointer"
>
<span>View All</span>
<span className="material-symbols-outlined text-[16px]">arrow_forward</span>
</button>
)}
</div>
</div>
{sortedIncidents.length > 0 ? (
<div className="overflow-hidden rounded-xl border border-outline-variant/20">
{/* Desktop Table: Case | Incident | Severity | Status | Assigned to | Age / Last update */}
<div className="hidden md:block overflow-x-auto">
<table className="w-full text-left text-xs sm:text-sm">
<thead className="bg-surface-container text-xs font-mono text-outline border-b border-outline-variant/20">
<tr>
<th scope="col" className="px-4 py-3.5 font-semibold">Case</th>
<th scope="col" className="px-4 py-3.5 font-semibold">Incident</th>
<th scope="col" className="px-4 py-3.5 font-semibold">Severity</th>
<th scope="col" className="px-4 py-3.5 font-semibold">Status</th>
<th scope="col" className="px-4 py-3.5 font-semibold">Assigned to</th>
<th scope="col" className="px-4 py-3.5 font-semibold">Age / Last update</th>
<th scope="col" className="px-4 py-3.5 font-semibold text-right">Actions</th>
</tr>
</thead>
<tbody className="divide-y divide-outline-variant/10 bg-surface-container-lowest font-mono">
{sortedIncidents.map((inc) => (
<tr
key={inc.case_reference}
className="hover:bg-surface-bright/40 transition-colors"
>
<td className="px-4 py-4 font-bold text-primary-fixed-dim whitespace-nowrap">
<button
type="button"
onClick={() => setModalIncident(inc)}
className="hover:underline cursor-pointer focus:outline-none focus-visible:ring-1 focus-visible:ring-primary-container rounded"
title="Open incident details"
>
{inc.case_reference}
</button>
</td>
<td className="px-4 py-4 font-sans text-on-surface font-semibold max-w-sm truncate">
<button
type="button"
onClick={() => setModalIncident(inc)}
className="text-left hover:underline cursor-pointer focus:outline-none"
title="Open incident details"
>
{inc.title}
</button>
</td>
<td className="px-4 py-4 whitespace-nowrap">
<span className={`inline-flex items-center px-2.5 py-1 rounded-md text-xs font-semibold capitalize ${getSeverityBadge(inc.severity)}`}>
{inc.severity}
</span>
</td>
<td className="px-4 py-4 whitespace-nowrap">
{/* Red reserved for critical; blue/neutral for open */}
<span className={`inline-flex items-center px-2.5 py-1 rounded-md text-xs font-semibold capitalize ${getStatusBadgeClass(inc.status)}`}>
{inc.status}
</span>
</td>
<td className="px-4 py-4 whitespace-nowrap text-on-surface-variant">
{inc.assigned_to ? (
<span className="text-on-surface font-medium">{inc.assigned_to}</span>
) : (
<span className="text-outline italic">Unassigned</span>
)}
</td>
<td className="px-4 py-4 whitespace-nowrap text-outline text-xs">
{formatIncidentAge(inc.created_at, inc.updated_at)}
</td>
<td className="px-4 py-4 text-right whitespace-nowrap text-xs">
<div className="flex items-center justify-end gap-1.5">
{inc.status === 'open' && (
<button
type="button"
onClick={() => handleAcknowledge(inc.case_reference)}
disabled={submittingAction === inc.case_reference}
className="px-2.5 py-1 rounded-md bg-amber-950/40 text-amber-300 border border-amber-800/40 hover:bg-amber-900/60 transition-colors cursor-pointer disabled:opacity-50"
title="Acknowledge incident (transitions to investigating)"
>
Acknowledge
</button>
)}
{!inc.assigned_to && operatorIdentity && (
<button
type="button"
onClick={() => handleAssignToMe(inc.case_reference)}
disabled={submittingAction === inc.case_reference}
className="px-2.5 py-1 rounded-md bg-surface-container-high hover:bg-surface-bright text-primary-container border border-primary-container/30 transition-colors cursor-pointer disabled:opacity-50"
title="Assign this incident to me"
>
Assign to me
</button>
)}
<button
type="button"
onClick={() => setModalIncident(inc)}
className="p-1 rounded-md text-outline hover:text-on-surface hover:bg-surface-container transition-colors cursor-pointer"
title="View incident details"
>
<span className="material-symbols-outlined text-[18px]">open_in_new</span>
</button>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
{/* Mobile Stacked Cards */}
<div className="md:hidden divide-y divide-outline-variant/15 bg-surface-container-lowest">
{sortedIncidents.map((inc) => (
<div
key={inc.case_reference}
className="p-4 space-y-2.5"
>
<div className="flex items-center justify-between gap-2">
<button
type="button"
onClick={() => setModalIncident(inc)}
className="font-mono text-xs font-bold text-primary-fixed-dim hover:underline cursor-pointer"
>
{inc.case_reference}
</button>
<div className="flex items-center gap-1.5">
<span className={`px-2 py-0.5 rounded text-[10px] font-mono font-semibold capitalize ${getSeverityBadge(inc.severity)}`}>
{inc.severity}
</span>
<span className={`px-2 py-0.5 rounded text-[10px] font-mono font-semibold capitalize ${getStatusBadgeClass(inc.status)}`}>
{inc.status}
</span>
</div>
</div>
<button
type="button"
onClick={() => setModalIncident(inc)}
className="text-left text-sm text-on-surface font-semibold line-clamp-1 hover:underline cursor-pointer"
>
{inc.title}
</button>
<div className="flex items-center justify-between text-xs font-mono text-outline">
<span>Assigned: {inc.assigned_to || 'Unassigned'}</span>
<span>{formatIncidentAge(inc.created_at, inc.updated_at)}</span>
</div>
<div className="flex items-center gap-2 pt-1">
{inc.status === 'open' && (
<button
type="button"
onClick={() => handleAcknowledge(inc.case_reference)}
disabled={submittingAction === inc.case_reference}
className="px-2.5 py-1 text-xs rounded-md bg-amber-950/40 text-amber-300 border border-amber-800/40 cursor-pointer disabled:opacity-50"
>
Acknowledge
</button>
)}
{!inc.assigned_to && operatorIdentity && (
<button
type="button"
onClick={() => handleAssignToMe(inc.case_reference)}
disabled={submittingAction === inc.case_reference}
className="px-2.5 py-1 text-xs rounded-md bg-surface-container-high text-primary-container border border-primary-container/30 cursor-pointer disabled:opacity-50"
>
Assign to me
</button>
)}
</div>
</div>
))}
</div>
</div>
) : (
<div className="p-6 rounded-xl bg-surface-container-lowest border border-outline-variant/20 text-center text-xs sm:text-sm text-on-surface-variant">
All operational systems normal. Zero open or active triage incidents.
</div>
)}
</section>
{/* Incident Detail Modal */}
{modalIncident && (
<div
className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/70 backdrop-blur-xs animate-in fade-in duration-150"
role="dialog"
aria-modal="true"
aria-labelledby="incident-modal-title"
>
<div className="w-full max-w-lg bg-surface-container-low border border-outline-variant/40 rounded-2xl p-6 shadow-2xl space-y-5">
{/* Modal Header */}
<div className="flex items-start justify-between gap-3 border-b border-outline-variant/20 pb-4">
<div>
<span className="font-mono text-xs font-bold text-primary-fixed-dim block mb-1">
{modalIncident.case_reference}
</span>
<h3 id="incident-modal-title" className="text-lg font-bold text-on-surface leading-snug">
{modalIncident.title}
</h3>
</div>
<button
type="button"
onClick={() => setModalIncident(null)}
className="p-1 rounded-lg text-outline hover:text-on-surface hover:bg-surface-container transition-colors cursor-pointer"
aria-label="Close dialog"
>
<span className="material-symbols-outlined text-[20px]">close</span>
</button>
</div>
{/* Badges & Meta */}
<div className="grid grid-cols-2 gap-3 text-xs font-mono">
<div className="p-3 rounded-xl bg-surface-container-lowest border border-outline-variant/20 space-y-1">
<span className="text-outline block">Severity</span>
<span className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-semibold capitalize ${getSeverityBadge(modalIncident.severity)}`}>
{modalIncident.severity}
</span>
</div>
<div className="p-3 rounded-xl bg-surface-container-lowest border border-outline-variant/20 space-y-1">
<span className="text-outline block">Status</span>
<span className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-semibold capitalize ${getStatusBadgeClass(modalIncident.status)}`}>
{modalIncident.status}
</span>
</div>
<div className="p-3 rounded-xl bg-surface-container-lowest border border-outline-variant/20 space-y-1">
<span className="text-outline block">Assigned To</span>
<span className="text-on-surface font-semibold truncate block">
{modalIncident.assigned_to || 'Unassigned'}
</span>
</div>
<div className="p-3 rounded-xl bg-surface-container-lowest border border-outline-variant/20 space-y-1">
<span className="text-outline block">Relative Age</span>
<span className="text-on-surface font-semibold block">
{formatIncidentAge(modalIncident.created_at, modalIncident.updated_at)}
</span>
</div>
</div>
{/* Exact Timestamps */}
<div className="p-3 rounded-xl bg-surface-container-lowest border border-outline-variant/20 space-y-1 text-xs font-mono text-outline">
<div className="flex justify-between">
<span>Created:</span>
<span className="text-on-surface">
{new Date(modalIncident.created_at).toLocaleString('en-US')}
</span>
</div>
<div className="flex justify-between">
<span>Last Updated:</span>
<span className="text-on-surface">
{new Date(modalIncident.updated_at).toLocaleString('en-US')}
</span>
</div>
</div>
{/* Modal Actions */}
<div className="flex flex-wrap items-center justify-between gap-3 pt-3 border-t border-outline-variant/20">
<div className="flex items-center gap-2">
{modalIncident.status === 'open' && (
<button
type="button"
onClick={() => handleAcknowledge(modalIncident.case_reference)}
disabled={submittingAction === modalIncident.case_reference}
className="px-3 py-2 rounded-xl bg-amber-950/50 text-amber-300 border border-amber-800/60 text-xs font-semibold hover:bg-amber-900/60 transition-colors cursor-pointer disabled:opacity-50"
>
Acknowledge
</button>
)}
{!modalIncident.assigned_to && operatorIdentity && (
<button
type="button"
onClick={() => handleAssignToMe(modalIncident.case_reference)}
disabled={submittingAction === modalIncident.case_reference}
className="px-3 py-2 rounded-xl bg-primary-container text-on-primary-container font-semibold text-xs hover:bg-primary-container/80 transition-colors cursor-pointer disabled:opacity-50"
>
Assign to me
</button>
)}
</div>
<div className="flex items-center gap-2 ml-auto">
{onSelectIncident && (
<button
type="button"
onClick={() => {
const ref = modalIncident.case_reference;
setModalIncident(null);
onSelectIncident(ref);
}}
className="px-3 py-2 rounded-xl bg-surface-container-high hover:bg-surface-bright text-on-surface border border-outline-variant/30 text-xs font-semibold transition-colors cursor-pointer"
>
Open full case
</button>
)}
<button
type="button"
onClick={() => setModalIncident(null)}
className="px-4 py-2 rounded-xl bg-surface-container text-on-surface-variant hover:text-on-surface text-xs font-semibold transition-colors cursor-pointer"
>
Close
</button>
</div>
</div>
</div>
</div>
)}
{/* 6. Operational Policy & Architecture Boundary */}
<div className="p-6 sm:p-7 rounded-2xl bg-surface-container-lowest border border-outline-variant/30 space-y-4 shadow-sm">
<div className="flex items-center gap-2.5">
<div className="w-8 h-8 rounded-lg bg-surface-container-high border border-outline-variant/30 flex items-center justify-center text-primary-container">
<span className="material-symbols-outlined text-[20px]">
verified_user
</span>
</div>
<h3 className="text-sm sm:text-base font-bold text-on-surface tracking-tight">
{'Operational Architecture & Data Boundary'}
</h3>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 text-xs sm:text-sm text-on-surface-variant pt-4 border-t border-outline-variant/20">
<div>
<span className="block font-semibold text-on-surface mb-1">
Authority Source
</span>
<p className="leading-relaxed">
PostgreSQL <code className="text-primary-fixed-dim">ops.operators</code> schema. Consumer roles and Firebase custom claims strictly bypassed.
</p>
</div>
<div>
<span className="block font-semibold text-on-surface mb-1">
Privacy Isolation
</span>
<p className="leading-relaxed">
Zero cross-rider data access. Personal rides, GPS points, vehicles, and billing accounts are structurally inaccessible.
</p>
</div>
<div>
<span className="block font-semibold text-on-surface mb-1">
Session Integrity
</span>
<p className="leading-relaxed">
Governed by host-prefixed <code className="text-primary-fixed-dim">__Host-motorsignal_ops</code> cookies with strict same-origin isolation.
</p>
</div>
</div>
</div>
</div>
);
}