fix: make dashboard login responsive

This commit is contained in:
Курнат Андрей
2026-07-19 22:56:19 +03:00
parent 393454c9e0
commit 3ce92b6428
3 changed files with 50 additions and 24 deletions
+43 -19
View File
@@ -2,7 +2,7 @@
const state = {
snapshot: null,
authorization: "",
token: "",
loading: false,
timer: null,
marketFilter: "",
@@ -78,30 +78,49 @@ function bindControls() {
event.preventDefault();
const username = $("#usernameInput").value.trim();
const password = $("#passwordInput").value;
const submitButton = $("#authSubmitButton");
setText("authError", "");
if (!username || !password) return;
state.authorization = basicAuthorization(username, password);
await loadSnapshot(true, true);
if (username !== "sevenhill") {
setText("authError", "Неверный логин или пароль.");
return;
}
state.token = password.trim();
submitButton.disabled = true;
submitButton.setAttribute("aria-busy", "true");
setText("authSubmitButton", "Входим…");
setText("authError", "Проверяем доступ…");
try {
await loadSnapshot(true, true);
} finally {
submitButton.disabled = false;
submitButton.removeAttribute("aria-busy");
setText("authSubmitButton", "Войти");
}
});
}
function basicAuthorization(username, password) {
const bytes = new TextEncoder().encode(`${username}:${password}`);
let binary = "";
bytes.forEach((byte) => { binary += String.fromCharCode(byte); });
return `Basic ${btoa(binary)}`;
}
async function api(path, options = {}) {
const headers = { Accept: "application/json", ...(options.headers || {}) };
if (options.body) headers["Content-Type"] = "application/json";
if (state.authorization) headers.Authorization = state.authorization;
const response = await fetch(path, {
...options,
headers,
credentials: "same-origin",
cache: "no-store",
});
if (state.token) headers["X-TradeBot-Token"] = state.token;
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 30000);
let response;
try {
response = await fetch(path, {
...options,
headers,
signal: controller.signal,
credentials: "omit",
cache: "no-store",
});
} catch (error) {
if (error?.name === "AbortError") throw new Error("Сервер не ответил за 30 секунд.");
throw error;
} finally {
clearTimeout(timeout);
}
if (response.status === 401) throw new AuthRequiredError("Требуется авторизация");
let payload = null;
try { payload = await response.json(); } catch (_) { payload = null; }
@@ -113,7 +132,7 @@ async function api(path, options = {}) {
}
async function loadSnapshot(manual = false, fromAuth = false) {
if (state.loading) return;
if (state.loading) return false;
state.loading = true;
clearTimeout(state.timer);
$("#refreshButton").classList.add("is-spinning");
@@ -127,15 +146,20 @@ async function loadSnapshot(manual = false, fromAuth = false) {
$("#passwordInput").value = "";
setText("authError", "");
scheduleRefresh(10000);
return true;
} catch (error) {
if (error instanceof AuthRequiredError) {
if (fromAuth) setText("authError", "Неверный логин или пароль.");
state.authorization = "";
state.token = "";
showAuthDialog();
} else if (fromAuth) {
setText("authError", `Ошибка подключения: ${error.message}`);
showAuthDialog();
} else {
setOffline(true, error.message);
scheduleRefresh(12000);
}
return false;
} finally {
state.loading = false;
$("#refreshButton").classList.remove("is-spinning");
+3 -3
View File
@@ -195,7 +195,7 @@
<div class="dialog-icon">T</div>
<p class="eyebrow">Защищённый доступ</p>
<h2>Вход в TradeBot</h2>
<p>Введите логин и пароль панели управления. Данные используются только для запросов из этой вкладки и не сохраняются в браузере.</p>
<p>Введите логин и пароль панели управления TradeBot. Данные используются только для запросов из этой вкладки и не сохраняются в браузере.</p>
<div class="auth-fields">
<div>
<label for="usernameInput">Логин</label>
@@ -207,7 +207,7 @@
</div>
</div>
<p class="form-error" id="authError" role="alert"></p>
<button class="button button-primary button-wide" type="submit">Войти</button>
<button class="button button-primary button-wide" id="authSubmitButton" type="submit">Войти</button>
</form>
</dialog>
@@ -221,6 +221,6 @@
</dialog>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="/assets/dashboard.js?v=4" defer></script>
<script src="/assets/dashboard.js?v=5" defer></script>
</body>
</html>