diff --git a/firmware/config/device.json b/firmware/config/device.json index b303545..6136790 100644 --- a/firmware/config/device.json +++ b/firmware/config/device.json @@ -3,5 +3,5 @@ "mode": "DEV", "active_slot": "A", "status": "OFFLINE", - "name": "Unnamed Device" + "name": "Unnamed Device0" } \ No newline at end of file diff --git a/firmware/simulator.py b/firmware/simulator.py index b38c108..a8af0c5 100644 --- a/firmware/simulator.py +++ b/firmware/simulator.py @@ -143,12 +143,13 @@ if __name__ == "__main__": print(" 4. Switch to PROD Mode") print(" 5. Swap Active Slot (A/B)") print(" 6. Start Automated Loop") + print(" 7. Request Re-enlistment") print(" 0. Exit Orchestrator") print("-" * 45) while True: print_menu() - choice = input("Select operation [0-6] >> ").strip() + choice = input("Select operation [0-7] >> ").strip() if choice == "1": hu.register() @@ -177,6 +178,9 @@ if __name__ == "__main__": break except KeyboardInterrupt: print("\n[!] Loop interrupted by user.") + elif choice == "7": + hu.status = "PENDING" + hu.register() elif choice == "0": print("[*] Powering down head unit...") break diff --git a/prisma/dev.db b/prisma/dev.db index 58b8b6f..19709b5 100644 Binary files a/prisma/dev.db and b/prisma/dev.db differ diff --git a/src/app/admin/devices/[id]/page.tsx b/src/app/admin/devices/[id]/page.tsx index 41ffa6e..903affc 100644 --- a/src/app/admin/devices/[id]/page.tsx +++ b/src/app/admin/devices/[id]/page.tsx @@ -155,20 +155,42 @@ export default function DeviceConfigPage({ params }: { params: Promise<{ id: str
- - + {device.status === "OFFLINE" ? ( + + ) : ( + <> + + + + )}
diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index b8c2cab..163e051 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -1,7 +1,7 @@ "use client"; import { useState, useEffect } from "react"; -import { Shield, ArrowRight, Settings2, PlusCircle, CheckCircle2, XCircle, Clock, ChevronRight } from "lucide-react"; +import { Shield, ArrowRight, Settings2, PlusCircle, CheckCircle2, XCircle, Clock, ChevronRight, RefreshCw } from "lucide-react"; import Link from "next/link"; interface Device { @@ -27,7 +27,8 @@ export default function AdminPage() { }); }, []); - const handleEnroll = async (id: string) => { + const handleEnroll = async (id: string, currentStatus: string) => { + const nextStatus = currentStatus === "OFFLINE" ? "ENROLLED" : "ENROLLED"; const res = await fetch(`/api/devices/${id}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, @@ -38,6 +39,19 @@ export default function AdminPage() { } }; + const handleDecommission = async (id: string) => { + if (!confirm("Are you sure you want to decommission this hardware node? It will be disconnected from the active mesh.")) return; + + const res = await fetch(`/api/devices/${id}`, { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ status: "OFFLINE" }), + }); + if (res.ok) { + setDevices(devices.map(d => d.id === id ? { ...d, status: "OFFLINE" } : d)); + } + }; + const handleUpdateName = async (id: string, name: string) => { await fetch(`/api/devices/${id}`, { method: "PATCH", @@ -145,14 +159,22 @@ export default function AdminPage() { {device.status === "PENDING" ? ( + ) : device.status === "OFFLINE" ? ( + ) : ( + + + +
+
+

REBOOT

+ +
+ +
+

ENTER

+ +
+
+ + + + + {/* Virtual Logs Panel */} +
+
+
+ + Node System Logs +
+
+
+
+
+
+
+
+ {logs.map((log, i) => ( +
+ {log} +
+ ))} +
+
+
+ + {/* User Instructions */} +
+ {[ + { key: "R", action: "Sync with Mesh" }, + { key: "T", action: "Run Test Sweep" }, + { key: "S", action: "Switch Slot" }, + { key: "B", action: "Soft Reboot" } + ].map((item) => ( +
+ {item.key} + {item.action} +
+ ))} +
+
+ ); +}