#794: Telegram-Client-Anmeldung ueber die WebUI
Code und 2FA-Passwort wurden nur im Desktop-Dialog abgefragt; eine Instanz ohne Fenster liess die Anmeldung aus. Jetzt haelt die Instanz die Frage (TelegramLoginBroker), die Einstellungsseite beantwortet sie. Die Anmeldung laeuft im Hintergrund, damit die HTTP-Flaeche, ueber die der Code kommt, nicht auf ihn wartet. Eine offene Frage verfaellt nach 15 Minuten. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
93395c9e01
commit
4e41fc12d7
@@ -669,6 +669,16 @@
|
||||
"logs.empty": "Noch keine Protokolleinträge vorhanden.",
|
||||
|
||||
"settings.title": "Einstellungen & Systemarchitektur",
|
||||
"settings.telegramCard": "Telegram-Client",
|
||||
"settings.telegramState.Connecting": "Verbindet",
|
||||
"settings.telegramState.NeedsCode": "Code nötig",
|
||||
"settings.telegramState.NeedsPassword": "Passwort nötig",
|
||||
"settings.telegramState.Connected": "Angemeldet",
|
||||
"settings.telegramState.Failed": "Nicht angemeldet",
|
||||
"settings.telegramCode": "Anmeldecode von Telegram",
|
||||
"settings.telegramPassword": "Passwort der zweistufigen Bestätigung",
|
||||
"settings.telegramSend": "Senden",
|
||||
"settings.telegramRetry": "Erneut anmelden",
|
||||
"settings.license": "Lizenz",
|
||||
"settings.licenseState": "Zustand",
|
||||
"settings.licenseValid": "Gültig",
|
||||
|
||||
@@ -669,6 +669,16 @@
|
||||
"logs.empty": "No log messages yet.",
|
||||
|
||||
"settings.title": "Settings & System Architecture",
|
||||
"settings.telegramCard": "Telegram client",
|
||||
"settings.telegramState.Connecting": "Connecting",
|
||||
"settings.telegramState.NeedsCode": "Code needed",
|
||||
"settings.telegramState.NeedsPassword": "Password needed",
|
||||
"settings.telegramState.Connected": "Logged in",
|
||||
"settings.telegramState.Failed": "Not logged in",
|
||||
"settings.telegramCode": "Login code from Telegram",
|
||||
"settings.telegramPassword": "Two-step verification password",
|
||||
"settings.telegramSend": "Send",
|
||||
"settings.telegramRetry": "Log in again",
|
||||
"settings.license": "License",
|
||||
"settings.licenseState": "State",
|
||||
"settings.licenseValid": "Valid",
|
||||
|
||||
@@ -214,10 +214,11 @@ async function instanceSection() {
|
||||
return el;
|
||||
}
|
||||
|
||||
const [settings, status, info] = await Promise.all([
|
||||
const [settings, status, info, telegram] = await Promise.all([
|
||||
api("/settings").catch(() => null),
|
||||
api("/status").catch(() => null),
|
||||
api("/info").catch(() => null)
|
||||
api("/info").catch(() => null),
|
||||
api("/telegram-client").catch(() => null)
|
||||
]);
|
||||
|
||||
// The instance file belongs to the instance process: it is only written while it runs.
|
||||
@@ -230,6 +231,7 @@ async function instanceSection() {
|
||||
|
||||
const grid = erstelleElement("div", { klasse: "settings-grid" });
|
||||
grid.append(instanceCard(settings), openRouterCard(settings, status), applicationCard(settings));
|
||||
if (telegram && telegram.state !== "NotConfigured") grid.append(telegramCard(telegram));
|
||||
if (info) grid.append(subsystemsCard(info));
|
||||
el.append(grid);
|
||||
|
||||
@@ -332,3 +334,89 @@ function subsystemsCard(info) {
|
||||
[t("settings.dcSubToken"), badge(info.deploymentcenterActive)]
|
||||
])]);
|
||||
}
|
||||
|
||||
// ─── Telegram client login (#794) ───
|
||||
//
|
||||
// The login code and the two-step password used to be asked in a desktop dialog. Now the
|
||||
// instance holds the question and this card answers it. While a login is under way the card
|
||||
// asks again every few seconds — Telegram's code arrives on the account's other devices, not
|
||||
// here, so there is no event to wait for. While a question is open it does not ask: the
|
||||
// answer itself moves the state on.
|
||||
|
||||
const TELEGRAM_BADGE = {
|
||||
Connected: "erfolg", Failed: "gefahr", NeedsCode: "warnung", NeedsPassword: "warnung", Connecting: "neutral"
|
||||
};
|
||||
|
||||
function telegramCard(initial) {
|
||||
const body = erstelleElement("div", { klasse: "formular-raster" });
|
||||
const card = erstelleKarte(t("settings.telegramCard"), [body]);
|
||||
let timer = null;
|
||||
|
||||
function render(state) {
|
||||
body.replaceChildren(
|
||||
erstelleElement("div", { klasse: "gruppe-horizontal" },
|
||||
erstellePlakette(t(`settings.telegramState.${state.state}`), TELEGRAM_BADGE[state.state] ?? "neutral")),
|
||||
erstelleElement("p", { klasse: "gedaempft text-klein", text: state.message }));
|
||||
|
||||
if (state.state === "NeedsCode" || state.state === "NeedsPassword") {
|
||||
const input = erstelleElement("input", {
|
||||
type: state.state === "NeedsPassword" ? "password" : "text",
|
||||
autocomplete: "one-time-code",
|
||||
inputmode: state.state === "NeedsCode" ? "numeric" : null
|
||||
});
|
||||
const send = erstelleElement("button", { type: "submit", klasse: "schaltflaeche primaer klein", text: t("settings.telegramSend") });
|
||||
const form = erstelleElement("form", { klasse: "formular-raster" },
|
||||
erstelleElement("label", { text: state.state === "NeedsCode" ? t("settings.telegramCode") : t("settings.telegramPassword") }),
|
||||
input, erstelleElement("div", {}, send));
|
||||
form.addEventListener("submit", async (e) => {
|
||||
e.preventDefault();
|
||||
send.disabled = true;
|
||||
try {
|
||||
await api("/telegram-client/answer", { method: "POST", body: { value: input.value } });
|
||||
input.value = "";
|
||||
await refreshTelegram();
|
||||
} catch (err) {
|
||||
zeigeMeldung(err.message, "gefahr");
|
||||
send.disabled = false;
|
||||
}
|
||||
});
|
||||
body.append(form);
|
||||
}
|
||||
|
||||
if (state.state === "Failed") {
|
||||
body.append(erstelleElement("div", {}, erstelleElement("button", {
|
||||
type: "button",
|
||||
klasse: "schaltflaeche klein",
|
||||
text: t("settings.telegramRetry"),
|
||||
onclick: async () => {
|
||||
try {
|
||||
await api("/telegram-client/connect", { method: "POST" });
|
||||
await refreshTelegram();
|
||||
} catch (err) {
|
||||
zeigeMeldung(err.message, "gefahr");
|
||||
}
|
||||
}
|
||||
})));
|
||||
}
|
||||
|
||||
clearTimeout(timer);
|
||||
// Only while connecting: re-rendering during a question would wipe what is being typed.
|
||||
if (state.state === "Connecting") {
|
||||
timer = setTimeout(() => {
|
||||
// Stop asking once the card is gone (another view, or the page was rebuilt).
|
||||
if (card.isConnected) refreshTelegram();
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshTelegram() {
|
||||
try {
|
||||
render(await api("/telegram-client"));
|
||||
} catch {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
}
|
||||
|
||||
render(initial);
|
||||
return card;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user