Connect-host wizard: delete the minted pending node on cancel (no orphan 'waiting for daemon' card)
The wizard mints a pending node on open (POST /api/nodes/pair). Cancelling left it behind as a 'waiting for daemon to dial home' card. handleClose now DELETEs the node on close unless it actually connected (everConnected) — so cancel leaves no card, while a node that already dialed home is kept. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
fadb1a084c
commit
447bf04932
@@ -37,6 +37,8 @@ export function ConnectHostWizard({ onClose }: { onClose: () => void }) {
|
|||||||
const [node, setNode] = useState<FleetNode | null>(null);
|
const [node, setNode] = useState<FleetNode | null>(null);
|
||||||
const [exec, setExec] = useState<{ ok: boolean; output: string } | null>(null);
|
const [exec, setExec] = useState<{ ok: boolean; output: string } | null>(null);
|
||||||
const [execing, setExecing] = useState(false);
|
const [execing, setExecing] = useState(false);
|
||||||
|
// Once the daemon has dialed home, the node is real — keep it even on cancel.
|
||||||
|
const [everConnected, setEverConnected] = useState(false);
|
||||||
|
|
||||||
const origin = typeof window !== "undefined" ? window.location.origin : "";
|
const origin = typeof window !== "undefined" ? window.location.origin : "";
|
||||||
|
|
||||||
@@ -82,6 +84,19 @@ export function ConnectHostWizard({ onClose }: { onClose: () => void }) {
|
|||||||
};
|
};
|
||||||
}, [step, nodeId]);
|
}, [step, nodeId]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (node?.status === "online") setEverConnected(true);
|
||||||
|
}, [node]);
|
||||||
|
|
||||||
|
// Cancelling before the daemon ever connected → drop the orphan pending node so
|
||||||
|
// we don't leave a "waiting for daemon" card behind.
|
||||||
|
const handleClose = useCallback(() => {
|
||||||
|
if (nodeId && !everConnected) {
|
||||||
|
fetch(`/api/nodes/${nodeId}`, { method: "DELETE" }).catch(() => {});
|
||||||
|
}
|
||||||
|
onClose();
|
||||||
|
}, [nodeId, everConnected, onClose]);
|
||||||
|
|
||||||
const runExec = useCallback(() => {
|
const runExec = useCallback(() => {
|
||||||
if (!nodeId) return;
|
if (!nodeId) return;
|
||||||
setExecing(true);
|
setExecing(true);
|
||||||
@@ -105,7 +120,7 @@ export function ConnectHostWizard({ onClose }: { onClose: () => void }) {
|
|||||||
const idx = STEPS.findIndex((s) => s.key === step);
|
const idx = STEPS.findIndex((s) => s.key === step);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ position: "fixed", inset: 0, zIndex: 300, background: "rgba(0,0,0,.6)", display: "flex", alignItems: "center", justifyContent: "center", padding: 20 }} onClick={onClose}>
|
<div style={{ position: "fixed", inset: 0, zIndex: 300, background: "rgba(0,0,0,.6)", display: "flex", alignItems: "center", justifyContent: "center", padding: 20 }} onClick={handleClose}>
|
||||||
<div onClick={(e) => e.stopPropagation()} style={{ width: 560, maxWidth: "100%", maxHeight: "90vh", overflow: "auto", borderRadius: 18, background: "#141417", border: "1px solid rgba(255,255,255,.1)", boxShadow: "0 24px 70px rgba(0,0,0,.6)" }}>
|
<div onClick={(e) => e.stopPropagation()} style={{ width: 560, maxWidth: "100%", maxHeight: "90vh", overflow: "auto", borderRadius: 18, background: "#141417", border: "1px solid rgba(255,255,255,.1)", boxShadow: "0 24px 70px rgba(0,0,0,.6)" }}>
|
||||||
<div style={{ display: "flex", alignItems: "center", gap: 12, padding: "18px 20px 14px", borderBottom: "1px solid rgba(255,255,255,.07)" }}>
|
<div style={{ display: "flex", alignItems: "center", gap: 12, padding: "18px 20px 14px", borderBottom: "1px solid rgba(255,255,255,.07)" }}>
|
||||||
<span style={{ width: 34, height: 34, borderRadius: 9, background: "rgba(94,200,216,.12)", border: "1px solid rgba(94,200,216,.3)", display: "flex", alignItems: "center", justifyContent: "center", color: "#5ec8d8" }}><Terminal size={17} /></span>
|
<span style={{ width: 34, height: 34, borderRadius: 9, background: "rgba(94,200,216,.12)", border: "1px solid rgba(94,200,216,.3)", display: "flex", alignItems: "center", justifyContent: "center", color: "#5ec8d8" }}><Terminal size={17} /></span>
|
||||||
@@ -117,7 +132,7 @@ export function ConnectHostWizard({ onClose }: { onClose: () => void }) {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" onClick={onClose} aria-label="Close" style={{ width: 30, height: 30, borderRadius: 8, border: "1px solid rgba(255,255,255,.12)", background: "transparent", color: "#9a9aa2", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center" }}><X size={16} /></button>
|
<button type="button" onClick={handleClose} aria-label="Close" style={{ width: 30, height: 30, borderRadius: 8, border: "1px solid rgba(255,255,255,.12)", background: "transparent", color: "#9a9aa2", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center" }}><X size={16} /></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ padding: 20 }}>
|
<div style={{ padding: 20 }}>
|
||||||
@@ -165,13 +180,13 @@ export function ConnectHostWizard({ onClose }: { onClose: () => void }) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ display: "flex", justifyContent: "space-between", gap: 10, padding: "14px 20px", borderTop: "1px solid rgba(255,255,255,.07)" }}>
|
<div style={{ display: "flex", justifyContent: "space-between", gap: 10, padding: "14px 20px", borderTop: "1px solid rgba(255,255,255,.07)" }}>
|
||||||
<button type="button" onClick={onClose} style={{ padding: "9px 16px", borderRadius: 9, border: "1px solid rgba(255,255,255,.14)", background: "transparent", color: "#9a9aa2", fontSize: 13, fontWeight: 600, cursor: "pointer" }}>{step === "exec" ? "Done" : "Cancel"}</button>
|
<button type="button" onClick={handleClose} style={{ padding: "9px 16px", borderRadius: 9, border: "1px solid rgba(255,255,255,.14)", background: "transparent", color: "#9a9aa2", fontSize: 13, fontWeight: 600, cursor: "pointer" }}>{step === "exec" ? "Done" : "Cancel"}</button>
|
||||||
{step === "install" ? (
|
{step === "install" ? (
|
||||||
<button type="button" disabled={!token} onClick={() => setStep("verify")} style={{ padding: "9px 18px", borderRadius: 9, border: 0, background: token ? "#5ec8d8" : "rgba(94,200,216,.3)", color: "#04222a", fontSize: 13, fontWeight: 700, cursor: token ? "pointer" : "default" }}>I’ve run it →</button>
|
<button type="button" disabled={!token} onClick={() => setStep("verify")} style={{ padding: "9px 18px", borderRadius: 9, border: 0, background: token ? "#5ec8d8" : "rgba(94,200,216,.3)", color: "#04222a", fontSize: 13, fontWeight: 700, cursor: token ? "pointer" : "default" }}>I’ve run it →</button>
|
||||||
) : step === "verify" ? (
|
) : step === "verify" ? (
|
||||||
<button type="button" disabled={!online} onClick={() => setStep("exec")} style={{ padding: "9px 18px", borderRadius: 9, border: 0, background: online ? "#5ec8d8" : "rgba(94,200,216,.3)", color: "#04222a", fontSize: 13, fontWeight: 700, cursor: online ? "pointer" : "default" }}>Next →</button>
|
<button type="button" disabled={!online} onClick={() => setStep("exec")} style={{ padding: "9px 18px", borderRadius: 9, border: 0, background: online ? "#5ec8d8" : "rgba(94,200,216,.3)", color: "#04222a", fontSize: 13, fontWeight: 700, cursor: online ? "pointer" : "default" }}>Next →</button>
|
||||||
) : (
|
) : (
|
||||||
<button type="button" onClick={onClose} style={{ padding: "9px 18px", borderRadius: 9, border: 0, background: "#5fd08a", color: "#04220f", fontSize: 13, fontWeight: 700, cursor: "pointer" }}>Finish</button>
|
<button type="button" onClick={handleClose} style={{ padding: "9px 18px", borderRadius: 9, border: 0, background: "#5fd08a", color: "#04220f", fontSize: 13, fontWeight: 700, cursor: "pointer" }}>Finish</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user