Files
weircon-front/templates/admin_claude_login.html
T
agw 58471b1a4d
CD / deploy (push) Successful in 20s
CI / check (push) Successful in 27s
fix(claude-login): siden opgiver ikke mens serveren starter login
Efter et tryk på Start kunne siden nå at læse den gamle hvile-status (fx
"Logget ind"), før serveren havde skrevet "starter". Så sprang den tilbage
til knappen og målte først igen efter 30 sekunder, og login-knappen kom
aldrig frem. Nu venter siden i op til et minut på en status, serveren har
skrevet efter trykket, og måler hvert 2. sekund imens.

Claude-Session: https://claude.ai/code/session_012LCTmU2ewo8tnM1dByYAoG
2026-10-03 09:03:48 +02:00

121 lines
5.1 KiB
HTML

{% extends "base.html" %}
{% block title %}Admin — Claude-login{% endblock %}
{% block body %}
<p><a href="/admin" class="wt-muted">← Admin</a></p>
<h1>Claude-login</h1>
<p class="wt-lead">Claude på serveren skal logges ind igen hver 4. uge. Det kan gøres herfra: start et login, log ind hos Claude i en ny fane, og indsæt koden du får her. Du får en påmindelse på ntfy tre dage før.</p>
<section class="wt-card" id="cl" style="margin:1rem 0;padding:1rem 1.2rem;max-width:40rem">
<p id="cl-status" style="margin:0 0 .6rem;font-weight:600">…</p>
<p id="cl-besked" class="wt-flash" hidden></p>
<div id="cl-start" hidden>
<button class="wt-btn wt-btn--primary" type="button" id="cl-start-btn">Start login</button>
</div>
<div id="cl-vent" hidden>
<p class="wt-muted" style="margin:.2rem 0">Serveren starter login-processen…</p>
</div>
<ol id="cl-trin" hidden style="padding-left:1.2rem;margin:.4rem 0">
<li style="margin:.4rem 0">
<a class="wt-btn wt-btn--primary" id="cl-url" href="#" target="_blank" rel="noopener noreferrer">Log ind hos Claude</a>
<div class="wt-muted" style="font-size:.9em;margin-top:.3rem">Åbner i en ny fane. Til sidst viser Claude en kode; kopiér den.</div>
</li>
<li style="margin:.8rem 0 .4rem">
<form id="cl-form" autocomplete="off" style="margin:0">
<label style="display:block">Indsæt koden
<input class="wt-input" name="kode" id="cl-kode" required autocomplete="one-time-code" autocapitalize="off"
autocorrect="off" spellcheck="false" style="font-family:ui-monospace,monospace" placeholder="kode#…"></label>
<button class="wt-btn wt-btn--primary" type="submit" style="margin-top:.5rem">Send til serveren</button>
</form>
</li>
</ol>
<p id="cl-tjek" class="wt-muted" hidden>Serveren logger ind…</p>
</section>
<script>
(function () {
var TEKST = {
ok: "✅ Logget ind",
snart: "⏳ Login udløber snart",
udloebet: "⚠️ Claude er logget ud",
ukendt: "Status ukendt",
starter: "Starter login…",
venter: "Venter på din kode",
tjekker: "Logger ind…"
};
var $ = function (id) { return document.getElementById(id); };
var timer = null;
// Efter et tryk på Start venter vi i op til et minut på en status, serveren har
// skrevet EFTER trykket; en ældre hvile-status betyder bare, at den ikke er nået dertil.
var klik = 0;
function dato(t) {
var d = new Date(t * 1000);
return d.toLocaleString("da-DK", { day: "numeric", month: "numeric", hour: "2-digit", minute: "2-digit" });
}
function vis(st) {
var s = st.status || "ukendt";
var hvile = s === "ok" || s === "snart" || s === "udloebet" || s === "ukendt";
if (hvile && klik && Date.now() - klik < 60000 && (st.updated || 0) * 1000 < klik) s = "starter";
var linje = TEKST[s] || s;
if (st.expires && (s === "ok" || s === "snart")) {
var dage = Math.floor((st.expires * 1000 - Date.now()) / 86400000);
linje += " · udløber " + dato(st.expires) + " (om " + dage + " " + (dage === 1 ? "dag" : "dage") + ")";
} else if (st.expires && s === "udloebet") {
linje += " siden " + dato(st.expires);
}
$("cl-status").textContent = linje;
var besked = st.error || st.message;
if (st.stale) besked = "Agenten på serveren svarer ikke (claude-login-agent). Så sker der ikke noget, når du trykker.";
$("cl-besked").hidden = !besked;
$("cl-besked").textContent = besked || "";
$("cl-start").hidden = !(s === "ok" || s === "snart" || s === "udloebet" || s === "ukendt");
$("cl-start-btn").textContent = s === "ok" ? "Forny login nu" : "Start login";
$("cl-vent").hidden = s !== "starter";
$("cl-trin").hidden = s !== "venter";
$("cl-tjek").hidden = s !== "tjekker";
if (s === "venter" && st.url && $("cl-url").getAttribute("href") !== st.url) {
$("cl-url").setAttribute("href", st.url);
}
planlaeg(s === "starter" || s === "venter" || s === "tjekker" ? 2000 : 30000);
}
function planlaeg(ms) {
clearTimeout(timer);
timer = setTimeout(hent, ms);
}
function hent() {
fetch("/admin/claude-login/status", { credentials: "same-origin", cache: "no-store" })
.then(function (r) { return r.json(); }).then(vis)
.catch(function () { planlaeg(5000); });
}
$("cl-start-btn").addEventListener("click", function () {
$("cl-start-btn").disabled = true;
klik = Date.now();
fetch("/admin/claude-login/start", { method: "POST", credentials: "same-origin" })
.then(function (r) { return r.json(); }).then(vis)
.finally(function () { $("cl-start-btn").disabled = false; });
});
$("cl-form").addEventListener("submit", function (e) {
e.preventDefault();
var data = new FormData($("cl-form"));
fetch("/admin/claude-login/kode", { method: "POST", credentials: "same-origin", body: data })
.then(function (r) { return r.json(); })
.then(function (st) { if (!st.error) $("cl-kode").value = ""; vis(st); })
.catch(function () { planlaeg(2000); });
});
document.addEventListener("visibilitychange", function () { if (!document.hidden) hent(); });
vis({{ st | tojson }});
})();
</script>
{% endblock %}