Rebranded to console tester.

This commit is contained in:
2025-12-23 11:21:02 -05:00
parent a0403eef57
commit 7d8c835fee
7 changed files with 309 additions and 207 deletions

View File

@@ -1,11 +1,12 @@
# HDMI Tester Enterprise # HDMI Console Diagnostics (Enterprise)
A high-performance orchestration and telemetry platform designed for real-time monitoring and lifecycle management of HDMI testing hardware. This platform provides a "single pane of glass" view for large fleets of test nodes, offering sub-ms edge latency tracking and remote hardware orchestration. A high-performance orchestration platform designed for real-time monitoring and repair diagnostics of **Console HDMI Ports** (PS5, Xbox, Switch). This platform provides a "single pane of glass" view for large fleets of test nodes, offering sub-ms edge latency tracking and remote hardware orchestration for front-desk and technical staff.
## 🚀 Key Features ## 🚀 Key Features
- **Operational Telemetry**: Real-time monitoring of active nodes, test results, and system health. - **Port Telemetry**: Real-time monitoring of active nodes, port diagnostic results, and system health.
- **Node Insights**: Tactical spectral analysis of HDMI bus metrics including DDC, CEC, and TMDS voltage verification. - **Port Insights**: Tactical spectral analysis of HDMI pins (DDC, CEC, TMDS) for board-level repair verification.
- **Retail & Enterprise Views**: Simplified "Good/Bad" UI for front-desk staff and detailed telemetry for technicians.
- **Command Center**: Enterprise-grade fleet management for device enrollment and environment orchestration. - **Command Center**: Enterprise-grade fleet management for device enrollment and environment orchestration.
- **Device Configuration**: - **Device Configuration**:
- Remote renaming and identification. - Remote renaming and identification.
@@ -15,6 +16,7 @@ A high-performance orchestration and telemetry platform designed for real-time m
- **Premium UI/UX**: - **Premium UI/UX**:
- High-contrast Light and Dark modes. - High-contrast Light and Dark modes.
- Safari-optimized rendering and backdrop filters. - Safari-optimized rendering and backdrop filters.
- **Virtual Hardware Simulator**: A web-based tactile OLED emulator for immediate testing.
- Fluid micro-animations and responsive layouts. - Fluid micro-animations and responsive layouts.
## 🛠 Tech Stack ## 🛠 Tech Stack
@@ -53,8 +55,13 @@ Open [http://localhost:3000](http://localhost:3000) to access the dashboard.
## 🤖 Hardware Simulation ## 🤖 Hardware Simulation
To test the platform without physical hardware, use the provided simulator. It mimics a head unit with active mesh capabilities. To test the platform without physical hardware, you can use either the interactive web emulator or the Python-based CLI simulator.
### Web Simulator (Recommended)
Access the tactile OLED emulator directly in your browser: [http://localhost:3000/simulator](http://localhost:3000/simulator)
- **Features**: Real-time OLED display, keyboard shortcuts (R/T/S/B), and live system logs.
### Python CLI Simulator
```bash ```bash
# Register a simulated device # Register a simulated device
python3 firmware/simulator.py register python3 firmware/simulator.py register

View File

@@ -5,7 +5,7 @@ import requests
import uuid import uuid
import socket import socket
class HeadUnit: class PortTester:
def __init__(self, server_url="http://localhost:3000", config_path="firmware/config/device.json"): def __init__(self, server_url="http://localhost:3000", config_path="firmware/config/device.json"):
self.server_url = server_url self.server_url = server_url
self.config_path = config_path self.config_path = config_path
@@ -109,42 +109,39 @@ class HeadUnit:
self.save_config() self.save_config()
print(f"[*] Switched to Slot {self.active_slot}.") print(f"[*] Switched to Slot {self.active_slot}.")
def generate_mock_hdmi_test(): def generate_console_port_test():
"""Generates mock spectral data for a console HDMI port."""
pins = ["DDC_SCL", "DDC_SDA", "CEC", "HPD", "TMDS_CLK+", "TMDS_CLK-"]
results = {pin: round(0.400 + (random.random() * 0.2), 3) for pin in pins}
return { return {
"type": "HDMI_OFFLINE", "type": "PORT_DIAGNOSTIC",
"status": "PASS", "status": "PASS",
"hdmi5v": False, "hdmi5v": True,
"summary": "Offline diode check completed. All lines within tolerance.", "summary": "Port handshake confirmed. Pin continuity within spec.",
"diodeResults": { "diodeResults": results
"DDC_SCL": 0.542,
"DDC_SDA": 0.544,
"CEC": 0.612,
"HPD": 0.589,
"TMDS_CLK+": 0.498,
"TMDS_CLK-": 0.497
}
} }
if __name__ == "__main__": if __name__ == "__main__":
hu = HeadUnit() hu = PortTester()
def print_menu(): def print_menu():
print("\n" + "="*45) print("\n" + "="*45)
print(f" HDMI TESTER - HARDWARE SIMULATOR (v1.2.0)") print(f" HDMI PORT DIAGNOSTICS - HARDWARE SIMULATOR")
print("="*45) print("="*45)
print(f" Status: [{hu.status}]") print(f" Status: [{hu.status}]")
print(f" Mode: [{hu.mode}]") print(f" Mode: [{hu.mode}]")
print(f" Active: [Slot {hu.active_slot}]") print(f" Active: [Slot {hu.active_slot}]")
print(f" Serial: [{hu.serial_number}]") print(f" Node: [{hu.serial_number}]")
print("-" * 45) print("-" * 45)
print(" 1. Register / Sync Device") print(" 1. Register / Sync Port Diagnostics")
print(" 2. Report Mock HDMI Test") print(" 2. Run Console Port Sweep")
print(" 3. Switch to DEV Mode") print(" 3. Switch to DEV Mode")
print(" 4. Switch to PROD Mode") print(" 4. Switch to PROD Mode")
print(" 5. Swap Active Slot (A/B)") print(" 5. Swap Active Slot (A/B)")
print(" 6. Start Automated Loop") print(" 6. Start Automated Loop")
print(" 7. Request Re-enlistment") print(" 7. Request Re-enlistment")
print(" 0. Exit Orchestrator") print(" 0. Power Down Node")
print("-" * 45) print("-" * 45)
while True: while True:
@@ -154,7 +151,7 @@ if __name__ == "__main__":
if choice == "1": if choice == "1":
hu.register() hu.register()
elif choice == "2": elif choice == "2":
hu.report_test(generate_mock_hdmi_test()) hu.report_test(generate_console_port_test())
elif choice == "3": elif choice == "3":
hu.switch_mode("DEV") hu.switch_mode("DEV")
elif choice == "4": elif choice == "4":
@@ -171,7 +168,7 @@ if __name__ == "__main__":
break break
if hu.status == "ENROLLED": if hu.status == "ENROLLED":
hu.report_test(generate_mock_hdmi_test()) hu.report_test(generate_console_port_test())
time.sleep(5) time.sleep(5)
if hu.status == "OFFLINE": if hu.status == "OFFLINE":

Binary file not shown.

View File

@@ -1,7 +1,7 @@
"use client"; "use client";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { Shield, ArrowRight, Settings2, PlusCircle, CheckCircle2, XCircle, Clock, ChevronRight, RefreshCw } from "lucide-react"; import { Shield, ArrowRight, Settings2, PlusCircle, CheckCircle2, XCircle, Clock, ChevronRight, RefreshCw, Activity } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
interface Device { interface Device {
@@ -73,10 +73,24 @@ export default function AdminPage() {
</h1> </h1>
<p className="text-secondary font-medium text-sm tracking-wide">Manage device fleet, enrollment, and firmware orchestration.</p> <p className="text-secondary font-medium text-sm tracking-wide">Manage device fleet, enrollment, and firmware orchestration.</p>
</div> </div>
<button className="bg-sky-500 hover:bg-sky-400 text-white px-6 py-2.5 rounded-2xl text-[10px] font-black uppercase tracking-widest flex items-center gap-3 transition-all shadow-[0_0_25px_rgba(56,189,248,0.2)] hover:scale-105 active:scale-95"> <div className="flex items-center gap-4">
<PlusCircle className="w-4 h-4" /> <Link
Proactive Provisioning href="/simulator"
</button> className="group flex items-center gap-3 bg-secondary/5 border border-border px-5 py-2.5 rounded-2xl hover:bg-sky-500/10 hover:border-sky-500/30 transition-all active:scale-95"
>
<div className="w-8 h-8 rounded-lg bg-sky-500/10 flex items-center justify-center text-sky-500 group-hover:bg-sky-500 group-hover:text-white transition-all">
<Activity className="w-4 h-4" />
</div>
<div className="text-left">
<p className="text-[10px] font-black uppercase tracking-widest text-foreground">Launch Virtual Node</p>
<p className="text-[8px] font-bold text-secondary uppercase tracking-tight">OLED Hardware Emulator</p>
</div>
</Link>
<button className="bg-sky-500 hover:bg-sky-400 text-white px-6 py-2.5 rounded-2xl text-[10px] font-black uppercase tracking-widest flex items-center gap-3 transition-all shadow-[0_0_25px_rgba(56,189,248,0.2)] hover:scale-105 active:scale-95">
<PlusCircle className="w-4 h-4" />
Proactive Provisioning
</button>
</div>
</div> </div>
<div className="grid grid-cols-1 gap-6"> <div className="grid grid-cols-1 gap-6">

View File

@@ -1,7 +1,7 @@
"use client"; "use client";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { Activity, Cpu, CheckCircle2, AlertCircle, Clock, Zap } from "lucide-react"; import { Activity, Cpu, CheckCircle2, AlertCircle, Clock, Zap, RefreshCw } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { clsx, type ClassValue } from "clsx"; import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
@@ -41,6 +41,7 @@ export default function DashboardPage() {
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [lastUpdate, setLastUpdate] = useState<Date | null>(null); const [lastUpdate, setLastUpdate] = useState<Date | null>(null);
const [isUpdating, setIsUpdating] = useState(false); const [isUpdating, setIsUpdating] = useState(false);
const [viewMode, setViewMode] = useState<"ENTERPRISE" | "RETAIL">("ENTERPRISE");
const fetchData = async () => { const fetchData = async () => {
try { try {
@@ -97,194 +98,277 @@ export default function DashboardPage() {
Operational Telemetry Operational Telemetry
</h1> </h1>
</div> </div>
<div className="flex items-center gap-3"> <div className="flex items-center gap-4">
<div className="text-[10px] font-mono text-secondary uppercase tracking-tighter"> <div className="flex items-center gap-2 bg-secondary/5 p-1 rounded-xl border border-border">
Last sync: <span className="text-foreground">{lastUpdate ? lastUpdate.toLocaleTimeString() : "--:--:--"}</span> <button
onClick={() => setViewMode("RETAIL")}
className={cn(
"px-4 py-1.5 rounded-lg text-[9px] font-black uppercase tracking-widest transition-all",
viewMode === "RETAIL" ? "bg-background text-foreground shadow-sm" : "text-secondary hover:text-foreground"
)}
>
Retail
</button>
<button
onClick={() => setViewMode("ENTERPRISE")}
className={cn(
"px-4 py-1.5 rounded-lg text-[9px] font-black uppercase tracking-widest transition-all",
viewMode === "ENTERPRISE" ? "bg-background text-foreground shadow-sm" : "text-secondary hover:text-foreground"
)}
>
Enterprise
</button>
</div>
<div className="flex items-center gap-3">
<div className="text-[10px] font-mono text-secondary uppercase tracking-tighter">
Last sync: <span className="text-foreground">{lastUpdate ? lastUpdate.toLocaleTimeString() : "--:--:--"}</span>
</div>
<div className={cn(
"w-2 h-2 rounded-full transition-all duration-500",
isUpdating ? "bg-sky-400 shadow-[0_0_8px_rgba(56,189,248,0.8)]" : "bg-secondary/20"
)} />
</div> </div>
<div className={cn(
"w-2 h-2 rounded-full transition-all duration-500",
isUpdating ? "bg-sky-400 shadow-[0_0_8px_rgba(56,189,248,0.8)]" : "bg-secondary/20"
)} />
</div> </div>
</div> </div>
{/* Hero Stats */} {viewMode === "RETAIL" ? (
<div className="grid grid-cols-1 md:grid-cols-3 gap-6"> /* Retail Mode UI - Ultra Simplified */
{[ <div className="flex flex-col items-center justify-center py-20 animate-in zoom-in-95 duration-700">
{ label: "Active Nodes", value: data.stats.onlineCount, icon: Activity, color: "text-sky-400", glow: "shadow-sky-500/10" }, <div className={cn(
{ label: "Tests Conducted", value: data.stats.testCount, icon: Zap, color: "text-amber-400", glow: "shadow-amber-500/10" }, "w-full max-w-2xl overflow-hidden rounded-[3rem] p-16 text-center border-2 transition-all duration-1000",
{ label: "Registered Hardware", value: data.stats.deviceCount, icon: Cpu, color: "text-purple-400", glow: "shadow-purple-500/10" }, data.recentTests[0]?.status === "PASS"
].map((stat, i) => ( ? "bg-emerald-500/5 border-emerald-500/20 text-emerald-500 shadow-[0_20px_100px_rgba(16,185,129,0.1)]"
<div : "bg-rose-500/5 border-rose-500/20 text-rose-500 shadow-[0_20px_100px_rgba(244,63,94,0.1)]"
key={i} )}>
className={cn( <div className="space-y-8">
"bg-background border border-border rounded-2xl p-6 backdrop-blur-sm relative overflow-hidden group transition-all duration-700", <div className="flex justify-center">
stat.glow <div className={cn(
)} "w-32 h-32 rounded-full flex items-center justify-center border-8 transition-all duration-1000 shadow-xl",
> data.recentTests[0]?.status === "PASS" ? "bg-emerald-500/10 border-emerald-500" : "bg-rose-500/10 border-rose-500"
<div className="absolute inset-0 bg-gradient-to-br from-white/[0.02] to-transparent pointer-events-none" /> )}>
<div className="flex items-center justify-between relative z-10"> {data.recentTests[0]?.status === "PASS" ? (
<div> <CheckCircle2 className="w-16 h-16" />
<p className="text-slate-500 text-[10px] font-black uppercase tracking-[0.2em] mb-2">{stat.label}</p> ) : (
<h3 className={cn("text-4xl font-black tracking-tighter transition-all duration-500 font-mono", stat.color)}> <AlertCircle className="w-16 h-16" />
{stat.value.toString().padStart(2, '0')} )}
</h3> </div>
</div> </div>
<div className="w-12 h-12 rounded-xl bg-secondary/5 flex items-center justify-center transition-all duration-700 group-hover:bg-secondary/10 group-hover:scale-110">
<stat.icon className={cn( <div className="space-y-4">
"w-6 h-6 transition-all duration-700 opacity-60 group-hover:opacity-100", <h2 className="text-8xl font-black tracking-tighter uppercase">
stat.color {data.recentTests[0]?.status === "PASS" ? "Port OK" : "Port Fail"}
)} /> </h2>
<div className="h-px w-24 bg-current/20 mx-auto" />
<p className="text-foreground/70 font-bold text-2xl uppercase tracking-widest italic">
{data.recentTests[0]?.status === "PASS" ? "HDMI Port is Functional" : "Console Port Requires Repair"}
</p>
</div>
<div className="pt-10 flex flex-col items-center gap-4">
<div className="px-6 py-2 bg-foreground/5 border border-foreground/10 rounded-full flex items-center gap-3">
<div className="w-2 h-2 rounded-full bg-foreground animate-pulse" />
<span className="text-[10px] font-black uppercase tracking-[0.2em] text-foreground">Waiting for Next Console</span>
</div>
<p className="text-secondary font-medium text-sm">
Last test: {data.recentTests[0]?.summary}
</p>
</div> </div>
</div> </div>
</div> </div>
))}
</div>
{/* Main Content Grid */} <div className="mt-12 flex items-center gap-8">
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8"> <div className="text-center">
{/* Recent Activity Feed */} <p className="text-[10px] font-black text-secondary uppercase tracking-widest mb-1">Active Station</p>
<div className="lg:col-span-2 space-y-4"> <p className="text-sm font-black text-foreground">{data.enrolledDevices[0]?.name || "Front Desk 01"}</p>
<div className="flex items-center justify-between mb-2"> </div>
<h2 className="text-sm font-black uppercase tracking-[0.2em] flex items-center gap-3 text-slate-300"> <div className="w-px h-8 bg-border" />
<Clock className="w-4 h-4 text-sky-400" /> <div className="text-center">
Live Sequence Stream <p className="text-[10px] font-black text-secondary uppercase tracking-widest mb-1">Today's Volume</p>
</h2> <p className="text-sm font-black text-foreground">{data.stats.testCount} Tests</p>
<div className="h-px flex-1 mx-6 bg-gradient-to-r from-white/5 to-transparent" /> </div>
</div>
</div>
) : (
<div className="space-y-10">
{/* Hero Stats */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{[
{ label: "Active Nodes", value: data.stats.onlineCount, icon: Activity, color: "text-sky-400", glow: "shadow-sky-500/10" },
{ label: "Tests Conducted", value: data.stats.testCount, icon: Zap, color: "text-amber-400", glow: "shadow-amber-500/10" },
{ label: "Registered Hardware", value: data.stats.deviceCount, icon: Cpu, color: "text-purple-400", glow: "shadow-purple-500/10" },
].map((stat, i) => (
<div
key={i}
className={cn(
"bg-background border border-border rounded-2xl p-6 backdrop-blur-sm relative overflow-hidden group transition-all duration-700",
stat.glow
)}
>
<div className="absolute inset-0 bg-gradient-to-br from-white/[0.02] to-transparent pointer-events-none" />
<div className="flex items-center justify-between relative z-10">
<div>
<p className="text-slate-500 text-[10px] font-black uppercase tracking-[0.2em] mb-2">{stat.label}</p>
<h3 className={cn("text-4xl font-black tracking-tighter transition-all duration-500 font-mono", stat.color)}>
{stat.value.toString().padStart(2, '0')}
</h3>
</div>
<div className="w-12 h-12 rounded-xl bg-secondary/5 flex items-center justify-center transition-all duration-700 group-hover:bg-secondary/10 group-hover:scale-110">
<stat.icon className={cn(
"w-6 h-6 transition-all duration-700 opacity-60 group-hover:opacity-100",
stat.color
)} />
</div>
</div>
</div>
))}
</div> </div>
<div className="bg-background border border-border rounded-2xl overflow-hidden backdrop-blur-md"> {/* Main Content Grid */}
<table className="w-full text-left border-collapse"> <div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
<thead> {/* Recent Activity Feed */}
<tr className="border-b border-border bg-background/30"> <div className="lg:col-span-2 space-y-4">
<th className="px-6 py-4 text-[10px] font-black uppercase tracking-[0.2em] text-secondary">Node</th> <div className="flex items-center justify-between mb-2">
<th className="px-6 py-4 text-[10px] font-black uppercase tracking-[0.2em] text-secondary">Operation</th> <h2 className="text-sm font-black uppercase tracking-[0.2em] flex items-center gap-3 text-slate-300">
<th className="px-6 py-4 text-[10px] font-black uppercase tracking-[0.2em] text-secondary">Status</th> <Clock className="w-4 h-4 text-sky-400" />
<th className="px-6 py-4 text-[10px] font-black uppercase tracking-[0.2em] text-secondary">Execution</th> Live Sequence Stream
<th className="px-6 py-4 text-[10px] font-black uppercase tracking-[0.2em] text-secondary"></th> </h2>
</tr> <div className="h-px flex-1 mx-6 bg-gradient-to-r from-white/5 to-transparent" />
</thead> </div>
<tbody className="divide-y divide-white/[0.02]">
{data.recentTests.length === 0 ? ( <div className="bg-background border border-border rounded-2xl overflow-hidden backdrop-blur-md">
<tr> <table className="w-full text-left border-collapse">
<td colSpan={5} className="px-6 py-16 text-center text-slate-500 italic font-medium">No telemetry data reported yet.</td> <thead>
</tr> <tr className="border-b border-border bg-background/30">
) : ( <th className="px-6 py-4 text-[10px] font-black uppercase tracking-[0.2em] text-secondary">Node</th>
data.recentTests.map((test) => ( <th className="px-6 py-4 text-[10px] font-black uppercase tracking-[0.2em] text-secondary">Operation</th>
<tr key={test.id} className="hover:bg-secondary/5 transition-all group animate-in fade-in slide-in-from-left-2 duration-500"> <th className="px-6 py-4 text-[10px] font-black uppercase tracking-[0.2em] text-secondary">Status</th>
<td className="px-6 py-4"> <th className="px-6 py-4 text-[10px] font-black uppercase tracking-[0.2em] text-secondary">Execution</th>
<th className="px-6 py-4 text-[10px] font-black uppercase tracking-[0.2em] text-secondary"></th>
</tr>
</thead>
<tbody className="divide-y divide-white/[0.02]">
{data.recentTests.length === 0 ? (
<tr>
<td colSpan={5} className="px-6 py-16 text-center text-slate-500 italic font-medium">No telemetry data reported yet.</td>
</tr>
) : (
data.recentTests.map((test) => (
<tr key={test.id} className="hover:bg-secondary/5 transition-all group animate-in fade-in slide-in-from-left-2 duration-500">
<td className="px-6 py-4">
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded-lg bg-background border border-border flex items-center justify-center font-mono text-[10px] font-bold text-sky-400 shadow-sm">
HU
</div>
<div className="flex flex-col">
<span className="font-bold text-foreground text-xs">
{test.device.name && test.device.name !== "Unnamed Device" ? test.device.name : test.device.serialNumber}
</span>
<span className="text-[9px] text-secondary font-mono tracking-tighter uppercase whitespace-nowrap">
ID: {test.device.serialNumber}
</span>
</div>
</div>
</td>
<td className="px-6 py-4">
<span className="text-[10px] px-2 py-0.5 rounded bg-secondary/5 border border-border text-secondary font-black uppercase tracking-widest whitespace-nowrap">
{test.type.replace("_", " ")}
</span>
</td>
<td className="px-6 py-4">
{test.status === "PASS" ? (
<div className="flex items-center gap-2 text-emerald-400 text-[10px] font-black uppercase tracking-widest">
<span className="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse shadow-[0_0_8px_rgba(16,185,129,0.5)]" />
Nominal
</div>
) : (
<div className="flex items-center gap-2 text-rose-400 text-[10px] font-black uppercase tracking-widest">
<span className="w-1.5 h-1.5 rounded-full bg-rose-500 shadow-[0_0_8px_rgba(244,63,94,0.5)]" />
Fault
</div>
)}
</td>
<td className="px-6 py-4">
<div className="flex flex-col">
<span className="text-[10px] font-bold text-foreground font-mono">
{new Date(test.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false })}
</span>
<span className="text-[8px] text-secondary font-black uppercase tracking-widest">
{new Date(test.timestamp).toLocaleDateString([], { month: 'short', day: 'numeric' })}
</span>
</div>
</td>
<td className="px-6 py-4 text-right">
<Link
href={`/tests/${test.id}`}
className="px-3 py-1 bg-sky-500/10 hover:bg-sky-500/20 border border-sky-500/20 rounded-lg text-[9px] font-black text-sky-400 uppercase tracking-widest transition-all hover:scale-105 active:scale-95"
>
Insights
</Link>
</td>
</tr>
))
)}
</tbody>
</table>
</div>
</div>
{/* Sidebar */}
<div className="space-y-6">
<div className="bg-gradient-to-br from-sky-500/10 to-transparent border border-sky-500/20 rounded-2xl p-6 relative overflow-hidden">
<div className="absolute top-0 right-0 p-4 opacity-5">
<Zap className="w-20 h-20 text-sky-400" />
</div>
<h4 className="font-black text-sky-400 text-[10px] uppercase tracking-[0.3em] mb-4 flex items-center gap-2 relative z-10">
<Activity className="w-3 h-3" />
Intelligence Engine
</h4>
<div className="space-y-3 relative z-10">
<p className="text-xs text-secondary leading-relaxed font-medium">
Real-time spectral analysis of <span className="text-foreground">Console HDMI Ports</span>. Processing orchestrated with <span className="text-sky-400 font-bold">sub-ms</span> edge latency.
</p>
<div className="flex items-center gap-2 py-3 border-t border-sky-500/10">
<span className="relative flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-green-500"></span>
</span>
<span className="text-[9px] font-black uppercase tracking-[0.15em] text-foreground">Neural Engine Online</span>
</div>
</div>
</div>
<div className="bg-background border border-border rounded-2xl p-6">
<div className="flex items-center justify-between mb-6">
<h4 className="font-black text-secondary text-[10px] uppercase tracking-[0.3em]">Fleet Nodes</h4>
<Link href="/admin" className="text-[9px] text-sky-400 hover:text-sky-300 uppercase font-black tracking-widest">Manage All</Link>
</div>
<div className="space-y-3">
{data.enrolledDevices.length === 0 ? (
<p className="text-[10px] text-secondary italic text-center py-4 border border-dashed border-border rounded-xl">No active nodes in mesh.</p>
) : (
data.enrolledDevices.map((device) => (
<div key={device.id} className="p-3 bg-secondary/5 hover:bg-secondary/10 transition-colors rounded-xl border border-border flex items-center justify-between group cursor-default">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="w-8 h-8 rounded-lg bg-background border border-border flex items-center justify-center font-mono text-[10px] font-bold text-sky-400 shadow-sm"> <div className="w-8 h-8 rounded-lg bg-sky-500/10 flex items-center justify-center group-hover:bg-sky-500/20 transition-colors">
HU <Cpu className="w-4 h-4 text-sky-400" />
</div> </div>
<div className="flex flex-col"> <div className="flex flex-col">
<span className="font-bold text-foreground text-xs"> <span className="text-[10px] font-black text-foreground uppercase tracking-wider">
{test.device.name && test.device.name !== "Unnamed Device" ? test.device.name : test.device.serialNumber} {device.name && device.name !== "Unnamed Device" ? device.name : device.serialNumber}
</span>
<span className="text-[9px] text-secondary font-mono tracking-tighter uppercase whitespace-nowrap">
ID: {test.device.serialNumber}
</span> </span>
<span className="text-[8px] text-secondary font-mono uppercase tracking-tighter">System Health: Optimal</span>
</div> </div>
</div> </div>
</td> <div className="w-1.5 h-1.5 rounded-full bg-emerald-500 shadow-[0_0_6px_rgba(16,185,129,0.5)]" />
<td className="px-6 py-4"> </div>
<span className="text-[10px] px-2 py-0.5 rounded bg-secondary/5 border border-border text-secondary font-black uppercase tracking-widest whitespace-nowrap"> ))
{test.type.replace("_", " ")} )}
</span> </div>
</td>
<td className="px-6 py-4">
{test.status === "PASS" ? (
<div className="flex items-center gap-2 text-emerald-400 text-[10px] font-black uppercase tracking-widest">
<span className="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse shadow-[0_0_8px_rgba(16,185,129,0.5)]" />
Nominal
</div>
) : (
<div className="flex items-center gap-2 text-rose-400 text-[10px] font-black uppercase tracking-widest">
<span className="w-1.5 h-1.5 rounded-full bg-rose-500 shadow-[0_0_8px_rgba(244,63,94,0.5)]" />
Fault
</div>
)}
</td>
<td className="px-6 py-4">
<div className="flex flex-col">
<span className="text-[10px] font-bold text-foreground font-mono">
{new Date(test.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false })}
</span>
<span className="text-[8px] text-secondary font-black uppercase tracking-widest">
{new Date(test.timestamp).toLocaleDateString([], { month: 'short', day: 'numeric' })}
</span>
</div>
</td>
<td className="px-6 py-4 text-right">
<Link
href={`/tests/${test.id}`}
className="px-3 py-1 bg-sky-500/10 hover:bg-sky-500/20 border border-sky-500/20 rounded-lg text-[9px] font-black text-sky-400 uppercase tracking-widest transition-all hover:scale-105 active:scale-95"
>
Insights
</Link>
</td>
</tr>
))
)}
</tbody>
</table>
</div>
</div>
{/* Sidebar */}
<div className="space-y-6">
<div className="bg-gradient-to-br from-sky-500/10 to-transparent border border-sky-500/20 rounded-2xl p-6 relative overflow-hidden">
<div className="absolute top-0 right-0 p-4 opacity-5">
<Zap className="w-20 h-20 text-sky-400" />
</div>
<h4 className="font-black text-sky-400 text-[10px] uppercase tracking-[0.3em] mb-4 flex items-center gap-2 relative z-10">
<Activity className="w-3 h-3" />
Intelligence Engine
</h4>
<div className="space-y-3 relative z-10">
<p className="text-xs text-secondary leading-relaxed font-medium">
Real-time spectral analysis of HDMI bus metrics. Processing orchestrated with <span className="text-sky-400 font-bold">sub-ms</span> edge latency.
</p>
<div className="flex items-center gap-2 py-3 border-t border-sky-500/10">
<span className="relative flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-green-500"></span>
</span>
<span className="text-[9px] font-black uppercase tracking-[0.15em] text-foreground">Neural Engine Online</span>
</div> </div>
</div> </div>
</div> </div>
<div className="bg-background border border-border rounded-2xl p-6">
<div className="flex items-center justify-between mb-6">
<h4 className="font-black text-secondary text-[10px] uppercase tracking-[0.3em]">Fleet Nodes</h4>
<Link href="/admin" className="text-[9px] text-sky-400 hover:text-sky-300 uppercase font-black tracking-widest">Manage All</Link>
</div>
<div className="space-y-3">
{data.enrolledDevices.length === 0 ? (
<p className="text-[10px] text-secondary italic text-center py-4 border border-dashed border-border rounded-xl">No active nodes in mesh.</p>
) : (
data.enrolledDevices.map((device) => (
<div key={device.id} className="p-3 bg-secondary/5 hover:bg-secondary/10 transition-colors rounded-xl border border-border flex items-center justify-between group cursor-default">
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded-lg bg-sky-500/10 flex items-center justify-center group-hover:bg-sky-500/20 transition-colors">
<Cpu className="w-4 h-4 text-sky-400" />
</div>
<div className="flex flex-col">
<span className="text-[10px] font-black text-foreground uppercase tracking-wider">
{device.name && device.name !== "Unnamed Device" ? device.name : device.serialNumber}
</span>
<span className="text-[8px] text-secondary font-mono uppercase tracking-tighter">System Health: Optimal</span>
</div>
</div>
<div className="w-1.5 h-1.5 rounded-full bg-emerald-500 shadow-[0_0_6px_rgba(16,185,129,0.5)]" />
</div>
))
)}
</div>
</div>
</div> </div>
</div> )}
</div> </div>
); );
} }

View File

@@ -102,7 +102,7 @@ export default function WebSimulatorPage() {
return; return;
} }
setState(s => ({ ...s, isTesting: true })); setState(s => ({ ...s, isTesting: true }));
addLog("[OP] Initiating HDMI spectral sweep..."); addLog("[OP] Initiating HDMI Port Diagnostic sweep...");
await new Promise(r => setTimeout(r, 1500)); await new Promise(r => setTimeout(r, 1500));
@@ -111,10 +111,10 @@ export default function WebSimulatorPage() {
method: "POST", method: "POST",
body: JSON.stringify({ body: JSON.stringify({
serialNumber: state.serialNumber, serialNumber: state.serialNumber,
type: "HDMI_OFFLINE", type: "PORT_DIAGNOSTIC",
status: "PASS", status: "PASS",
hdmi5v: false, hdmi5v: true,
summary: "Virtual sweep completed within threshold.", summary: "Port handshake confirmed. Pin continuity within spec.",
diodeResults: { diodeResults: {
"DDC_SCL": 0.500 + Math.random() * 0.1, "DDC_SCL": 0.500 + Math.random() * 0.1,
"DDC_SDA": 0.500 + Math.random() * 0.1, "DDC_SDA": 0.500 + Math.random() * 0.1,
@@ -215,9 +215,9 @@ export default function WebSimulatorPage() {
{/* Main Content */} {/* Main Content */}
<div className="flex flex-col items-center justify-center flex-1"> <div className="flex flex-col items-center justify-center flex-1">
<div className="text-white text-lg font-black tracking-tighter leading-none mb-1"> <div className="text-white text-lg font-black tracking-tighter leading-none mb-1">
{state.isTesting ? "RUNNING SWEEP" : state.serialNumber} {state.isTesting ? "PORT SWEEP" : state.serialNumber}
</div> </div>
<div className="text-[8px] text-sky-400/60 font-black uppercase tracking-[0.2em]">Validated Path v1.0</div> <div className="text-[8px] text-sky-400/60 font-black uppercase tracking-[0.2em]">Console Interface v1.0</div>
</div> </div>
{/* Bottom Console */} {/* Bottom Console */}

View File

@@ -28,7 +28,7 @@ export default async function TestDetailsPage({ params }: { params: Promise<{ id
<Activity className="w-3 h-3" /> Dashboard <Activity className="w-3 h-3" /> Dashboard
</Link> </Link>
<span className="opacity-20">/</span> <span className="opacity-20">/</span>
<span className="text-secondary/70">Node Insights</span> <span className="text-secondary/70">Port Diagnostic Insights</span>
</div> </div>
<div className="flex flex-col md:flex-row md:items-end justify-between gap-8 pb-8 border-b border-border"> <div className="flex flex-col md:flex-row md:items-end justify-between gap-8 pb-8 border-b border-border">
@@ -85,7 +85,7 @@ export default async function TestDetailsPage({ params }: { params: Promise<{ id
<div className="w-10 h-10 rounded-xl bg-sky-500/10 flex items-center justify-center"> <div className="w-10 h-10 rounded-xl bg-sky-500/10 flex items-center justify-center">
<Info className="w-5 h-5 text-sky-400" /> <Info className="w-5 h-5 text-sky-400" />
</div> </div>
<h2 className="text-[10px] font-black uppercase tracking-[0.3em] text-secondary">Response Spectrum Analysis</h2> <h2 className="text-[10px] font-black uppercase tracking-[0.3em] text-secondary">HDMI Port Pinout Analysis</h2>
</div> </div>
<div className="px-4 py-1.5 bg-sky-500/10 border border-sky-500/20 rounded-full text-[9px] font-black text-sky-400 uppercase tracking-widest"> <div className="px-4 py-1.5 bg-sky-500/10 border border-sky-500/20 rounded-full text-[9px] font-black text-sky-400 uppercase tracking-widest">
Calibration: 0.8V VDD Calibration: 0.8V VDD