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
121 lines
5.1 KiB
HTML
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 %}
|