Initial commit — DRB server stack

Includes c2-core (FastAPI/MQTT/Firestore), discord-bot (slash commands),
frontend (Next.js admin UI), and mosquitto config.
This commit is contained in:
Logan
2026-04-05 19:01:39 -04:00
commit 2f0597c81b
77 changed files with 4126 additions and 0 deletions
+63
View File
@@ -0,0 +1,63 @@
"use client";
import { useState } from "react";
import { useNodes } from "@/lib/useNodes";
import { useSystems } from "@/lib/useSystems";
import { NodeCard } from "@/components/NodeCard";
import { NodeConfigModal } from "@/components/NodeConfigModal";
import type { NodeRecord } from "@/lib/types";
export default function NodesPage() {
const { nodes, loading } = useNodes();
const { systems } = useSystems();
const [configNode, setConfigNode] = useState<NodeRecord | null>(null);
const systemMap = Object.fromEntries(systems.map((s) => [s.system_id, s]));
const pending = nodes.filter((n) => !n.configured);
return (
<div className="space-y-6">
<h1 className="text-xl font-bold text-white font-mono">Nodes</h1>
{pending.length > 0 && (
<div className="space-y-2">
<h2 className="text-sm font-semibold text-indigo-400 uppercase tracking-wider">
Needs Configuration ({pending.length})
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{pending.map((n) => (
<div key={n.node_id} onClick={() => setConfigNode(n)} className="cursor-pointer">
<NodeCard node={n} system={systemMap[n.assigned_system_id ?? ""]} />
</div>
))}
</div>
</div>
)}
<div className="space-y-2">
<h2 className="text-sm font-semibold text-gray-400 uppercase tracking-wider">
All Nodes ({nodes.length})
</h2>
{loading ? (
<p className="text-gray-600 text-sm font-mono">Loading</p>
) : nodes.length === 0 ? (
<p className="text-gray-600 text-sm font-mono">No nodes registered yet. Boot a Pi to get started.</p>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{nodes.map((n) => (
<NodeCard key={n.node_id} node={n} system={systemMap[n.assigned_system_id ?? ""]} />
))}
</div>
)}
</div>
{configNode && (
<NodeConfigModal
node={configNode}
systems={systems}
onClose={() => setConfigNode(null)}
/>
)}
</div>
);
}