mirror of
https://github.com/andrey271192/amnezia_web-PRO.git
synced 2026-09-20 14:42:00 +00:00
fix(ui): separate server vs browser TZ; highlight sync from device
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -8,6 +8,7 @@ const logoutBtn = document.querySelector("#logout");
|
||||
const refreshBtn = document.querySelector("#refresh");
|
||||
const clockServerEl = document.querySelector("#clock-server");
|
||||
const clockLocalEl = document.querySelector("#clock-local");
|
||||
const clockZoneDiffEl = document.querySelector("#clock-zone-diff");
|
||||
const clockSyncBtn = document.querySelector("#clock-sync");
|
||||
const rowsEl = document.querySelector("#rows");
|
||||
const statusEl = document.querySelector("#status");
|
||||
@@ -320,7 +321,9 @@ function tickServerClockDisplay() {
|
||||
|
||||
async function refreshServerClock() {
|
||||
try {
|
||||
const t = await api("/api/server-time");
|
||||
const tz = browserTimeZoneLabel();
|
||||
const q = tz ? `?browserTz=${encodeURIComponent(tz)}` : "";
|
||||
const t = await api(`/api/server-time${q}`);
|
||||
const iso = typeof t.iso === "string" ? t.iso : "";
|
||||
const parsed = new Date(iso).getTime();
|
||||
if (!iso || Number.isNaN(parsed)) {
|
||||
@@ -332,11 +335,28 @@ async function refreshServerClock() {
|
||||
typeof t.timeZone === "string" && t.timeZone.trim() ? t.timeZone.trim() : "UTC";
|
||||
serverTzFmtCached = buildServerTzFmt(serverDisplayTz);
|
||||
tickServerClockDisplay();
|
||||
if (clockZoneDiffEl) {
|
||||
const hint = typeof t.zoneCompareHint === "string" ? t.zoneCompareHint.trim() : "";
|
||||
if (hint) {
|
||||
clockZoneDiffEl.textContent = hint;
|
||||
clockZoneDiffEl.classList.remove("hidden");
|
||||
clockZoneDiffEl.classList.toggle("clock-zone-diff--accent", t.zoneSame === false);
|
||||
} else {
|
||||
clockZoneDiffEl.textContent = "";
|
||||
clockZoneDiffEl.classList.add("hidden");
|
||||
clockZoneDiffEl.classList.remove("clock-zone-diff--accent");
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
serverAnchorUtcMs = null;
|
||||
serverTzFmtCached = null;
|
||||
clockServerEl.dateTime = "";
|
||||
clockServerEl.textContent = "—";
|
||||
if (clockZoneDiffEl) {
|
||||
clockZoneDiffEl.textContent = "";
|
||||
clockZoneDiffEl.classList.add("hidden");
|
||||
clockZoneDiffEl.classList.remove("clock-zone-diff--accent");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,6 +389,11 @@ function stopClocks() {
|
||||
clockLocalEl.dateTime = "";
|
||||
clockServerEl.textContent = "—";
|
||||
clockLocalEl.textContent = "—";
|
||||
if (clockZoneDiffEl) {
|
||||
clockZoneDiffEl.textContent = "";
|
||||
clockZoneDiffEl.classList.add("hidden");
|
||||
clockZoneDiffEl.classList.remove("clock-zone-diff--accent");
|
||||
}
|
||||
}
|
||||
|
||||
function startClocks() {
|
||||
@@ -386,8 +411,8 @@ async function loadTimeSyncCaps() {
|
||||
const c = await api("/api/time-sync-capabilities");
|
||||
if (hint) {
|
||||
hint.textContent = c.hostTimeSync
|
||||
? `Через SSH на root@${c.sshHost}. Часовой пояс строки «Сервер»: ${c.serverClockTimeZone}. Пароль не сохраняется.`
|
||||
: `Авто-синхронизация по SSH недоступна (или TIME_SYNC_DISABLED). Пояс «Сервер»: ${c.serverClockTimeZone}. Задайте DISPLAY_TZ или TZ для контейнера панели — см. README.`;
|
||||
? `Записывается UTC-момент с этого устройства на хост по SSH (root@${c.sshHost}). Пояс строки «Сервер»: ${c.serverClockTimeZone}. Пароль не сохраняется.`
|
||||
: `Авто-синхронизация по SSH недоступна (или TIME_SYNC_DISABLED). Пояс «Сервер»: ${c.serverClockTimeZone}. Задайте TZ контейнера панели при необходимости — см. README.`;
|
||||
}
|
||||
if (btn) btn.disabled = !c.hostTimeSync;
|
||||
} catch {
|
||||
@@ -404,13 +429,13 @@ document.querySelector("#sync-host-time")?.addEventListener("click", async () =>
|
||||
return;
|
||||
}
|
||||
try {
|
||||
setStatus("Синхронизация времени хоста…", false);
|
||||
setStatus("Беру время с этого устройства и отправляю на хост…", false);
|
||||
await api("/api/sync-host-time", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ rootPassword: pw, unixMs: Date.now() }),
|
||||
});
|
||||
inp.value = "";
|
||||
setStatus("Запрос выполнен. Проверьте строку «Сервер».", false);
|
||||
setStatus("Готово: часы хоста выставлены по вашему устройству (UTC). Проверьте строки времени.", false);
|
||||
void refreshServerClock();
|
||||
} catch (e) {
|
||||
setStatus(String(e.message || e), true);
|
||||
|
||||
@@ -58,27 +58,28 @@
|
||||
<select id="proto-select" class="proto-select" aria-label="Инстанс AmneziaWG"></select>
|
||||
</div>
|
||||
<div class="clock-strip" role="status" aria-live="polite">
|
||||
<div class="clock-row">
|
||||
<span class="muted clock-kind">Сервер</span>
|
||||
<div class="clock-row clock-row--server">
|
||||
<span class="muted clock-kind">Сервер <span class="clock-kind-sub">(часы VPS / контейнера)</span></span>
|
||||
<time id="clock-server" class="clock-time">—</time>
|
||||
</div>
|
||||
<div class="clock-row">
|
||||
<span class="muted clock-kind">Браузер</span>
|
||||
<div class="clock-row clock-row--your-place">
|
||||
<span class="muted clock-kind">Ваше место <span class="clock-kind-sub">(браузер)</span></span>
|
||||
<time id="clock-local" class="clock-time">—</time>
|
||||
</div>
|
||||
<p id="clock-zone-diff" class="clock-zone-diff muted hidden" role="note"></p>
|
||||
<p class="clock-hint muted">
|
||||
«Сервер» — время в часовом поясе VPS (подпись справа). «Браузер» — ваш компьютер. «Сверить» — заново запросить момент с сервера.
|
||||
Цифры разнятся, если пояса разные — это нормально для одного момента UTC. «Сверить» подтягивает время с VPS.
|
||||
</p>
|
||||
<button type="button" id="clock-sync" class="btn small ghost clock-sync-btn">
|
||||
Сверить время
|
||||
</button>
|
||||
<details class="clock-host-sync">
|
||||
<summary>Синхронизировать часы VPS с этим компьютером</summary>
|
||||
<summary class="clock-sync-summary">Синхронизация: выставить часы <strong>хоста VPS</strong> под <strong>ваше устройство</strong></summary>
|
||||
<p id="sync-host-hint" class="muted clock-sync-hint"></p>
|
||||
<label for="sync-root-pw">Пароль root на хосте (не сохраняется)</label>
|
||||
<input id="sync-root-pw" type="password" autocomplete="off" class="clock-sync-input">
|
||||
<button type="button" id="sync-host-time" class="btn small primary clock-sync-submit">
|
||||
Выставить время хоста как у браузера
|
||||
Взять время с этого устройства и записать на хост VPS
|
||||
</button>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
@@ -227,6 +227,42 @@ h1 {
|
||||
max-width: 22rem;
|
||||
}
|
||||
|
||||
.clock-row--server .clock-kind-sub,
|
||||
.clock-row--your-place .clock-kind-sub {
|
||||
font-weight: 400;
|
||||
opacity: 0.82;
|
||||
font-size: 0.72rem;
|
||||
}
|
||||
|
||||
.clock-row--your-place {
|
||||
padding: 0.35rem 0.55rem;
|
||||
margin: 0.15rem -0.35rem 0;
|
||||
border-radius: 10px;
|
||||
border-left: 3px solid #22d3ee;
|
||||
background: rgba(56, 189, 248, 0.07);
|
||||
}
|
||||
|
||||
.clock-zone-diff {
|
||||
margin: 0.5rem 0 0;
|
||||
font-size: 0.78rem;
|
||||
line-height: 1.45;
|
||||
max-width: 26rem;
|
||||
}
|
||||
|
||||
.clock-zone-diff--accent {
|
||||
color: #a5f3fc;
|
||||
padding: 0.45rem 0.55rem;
|
||||
margin-top: 0.45rem;
|
||||
border-radius: 8px;
|
||||
border: 1px solid rgba(34, 211, 238, 0.35);
|
||||
background: rgba(56, 189, 248, 0.08);
|
||||
}
|
||||
|
||||
.clock-sync-summary strong {
|
||||
color: var(--text);
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
.clock-strip {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -247,7 +283,9 @@ h1 {
|
||||
}
|
||||
|
||||
.clock-kind {
|
||||
flex: 0 0 4.25rem;
|
||||
flex: 0 0 auto;
|
||||
min-width: 7rem;
|
||||
max-width: 11rem;
|
||||
}
|
||||
|
||||
.clock-time {
|
||||
|
||||
Reference in New Issue
Block a user