From 0651bfe07a8360428b46737abd62929df01abfc3 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sun, 6 Sep 2026 19:15:55 -0400 Subject: [PATCH] frontend: mint panel shows the full one-shot install command (node-26#4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After a node enrollment token is minted, the panel now renders the paste-ready `curl -fsSL .../install.sh | sudo bash -s -- --token --node-id node-XXX --c2-url --mqtt-broker ` line with a Copy button, alongside the bare token (also kept, also now copyable). - c2-url from NEXT_PUBLIC_C2_URL (same var lib/c2api.ts reads), fallback https://api.example.net - mqtt-broker derived as mqtt. β€” a DNS assumption; the panel text tells the operator to check it - node id is a node-XXX placeholder; the panel collects none Pairs with node-26's install.sh (feat/one-shot-install). The raw/tag/v1/ URL resolves once v1 is re-cut at that PR's merge. NOT typechecked here (no node/npm in this environment); plain React, two useState booleans + one computed string, reviewed by eye. `next build` in the deploy workflow will catch a real type error before it ships. Co-Authored-By: Claude Sonnet 5 --- drb-frontend/app/settings/nodes/page.tsx | 50 +++++++++++++++++++++++- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/drb-frontend/app/settings/nodes/page.tsx b/drb-frontend/app/settings/nodes/page.tsx index dc01f8a..1bebcf0 100644 --- a/drb-frontend/app/settings/nodes/page.tsx +++ b/drb-frontend/app/settings/nodes/page.tsx @@ -39,6 +39,23 @@ function EnrollmentTokensPanel() { const [label, setLabel] = useState(""); const [minting, setMinting] = useState(false); const [justMinted, setJustMinted] = useState(null); + const [cmdCopied, setCmdCopied] = useState(false); + const [tokenCopied, setTokenCopied] = useState(false); + + // The paste-ready one-shot install command for a fresh Pi. node id and the + // MQTT broker host aren't known here β€” left as placeholders the operator + // edits. C2 URL comes from this deployment's own config; the broker is the + // documented mqtt. sibling of the api host (install.sh header). + const c2Url = (process.env.NEXT_PUBLIC_C2_URL ?? "https://api.example.net").replace(/\/$/, ""); + const mqttBroker = (() => { + try { return `mqtt.${new URL(c2Url).hostname.replace(/^api\./, "")}`; } + catch { return "mqtt.example.net"; } + })(); + const installCmd = justMinted + ? `curl -fsSL https://git.vpn.cusano.net/logan/node-26/raw/tag/v1/install.sh \\ + | sudo bash -s -- --token ${justMinted} --node-id node-XXX \\ + --c2-url ${c2Url} --mqtt-broker ${mqttBroker}` + : ""; const load = useCallback(() => { c2api.listEnrollmentTokens() @@ -87,11 +104,40 @@ function EnrollmentTokensPanel() {

New token β€” copy it now, it won't be shown again:

-

{justMinted}

+ +
+

{justMinted}

+ +
+ +

+ …or run this on a fresh Pi (edit node-XXX and the broker host): +

+
+
{installCmd}
+ +
+ -- 2.54.0