fix(web): окно аккаунта не обновлялось и застревало на заглушке
Владелец открыл карточку Grok и увидел «Grok 2h — Н/Д» и статус «Не проверялся» — хотя сервер в этот момент уже отдавал настоящие данные: подписка 14%, GrokChat 13%, GrokBuild 1%. Проверено на живом сервере: и /api/snapshot, и quota_snapshot внутри профиля содержали правильные корзины. Дефект целиком в клиенте — окно рисовалось ОДИН РАЗ при открытии и на опрос не реагировало. Открытое до завершения прогрева квот, оно навсегда оставалось с заглушкой _generate_baseline_snapshot, а после успешной проверки подключения по-прежнему показывало «Не проверялся». Теперь открытый профиль отслеживается и перерисовывается при каждом применении снапшота. Объявление переменной поднято выше первого использования: let не поднимается, и обращение раньше объявления роняло бы обработчик снапшота целиком. При закрытии окна сбрасывается отслеживание и останавливается опрос кода устройства — раньше он продолжал работать после закрытия мастера. Тесты: 431 passed, ruff чисто. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
0df7dba2ce
commit
c49e6eac31
2 changed files with 55 additions and 0 deletions
|
|
@ -8,6 +8,9 @@
|
|||
const USE_MOCK_FIXTURE = false;
|
||||
|
||||
let lastAppliedSeq = -1;
|
||||
// Какой профиль сейчас открыт в окне аккаунта: нужно, чтобы перерисовывать
|
||||
// его по свежему снапшоту, а не оставлять с заглушкой.
|
||||
let _openAccountModalProfile = null;
|
||||
let currentSnapshot = null;
|
||||
let activeView = 'overview';
|
||||
let pollTimer = null;
|
||||
|
|
@ -226,6 +229,18 @@ function applySnapshot(snapshot) {
|
|||
currentSnapshot = snapshot;
|
||||
updateGlobalHeader();
|
||||
|
||||
// Открытое окно аккаунта рисовалось один раз и на опрос не реагировало.
|
||||
// Если его открыть до того, как придут живые квоты, оно навсегда
|
||||
// оставалось с заглушкой («Grok 2h — Н/Д») и со статусом «Не проверялся»
|
||||
// даже после успешной проверки. Перерисовываем по свежему снапшоту.
|
||||
if (_openAccountModalProfile) {
|
||||
try {
|
||||
openAccountDetailsModal(_openAccountModalProfile, true);
|
||||
} catch (e) {
|
||||
console.warn('[Hub] Не удалось обновить окно аккаунта:', e);
|
||||
}
|
||||
}
|
||||
|
||||
if (isFirstLoad) {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const targetView = params.get('view');
|
||||
|
|
@ -1296,6 +1311,7 @@ async function saveHubServerSettings() {
|
|||
|
||||
// ── MODALS (Account Details, Model Choice, Routing, Wizard) ──
|
||||
function openAccountDetailsModal(profileId) {
|
||||
_openAccountModalProfile = profileId;
|
||||
if (!currentSnapshot) return;
|
||||
const profile = (currentSnapshot.all_profiles || {})[profileId];
|
||||
if (!profile) return;
|
||||
|
|
@ -1939,6 +1955,8 @@ function showModal() {
|
|||
}
|
||||
|
||||
function closeModal() {
|
||||
_openAccountModalProfile = null;
|
||||
stopDeviceAuthPolling();
|
||||
if (elements.modalBackdrop) elements.modalBackdrop.classList.add('hidden');
|
||||
}
|
||||
|
||||
|
|
|
|||
37
tests/test_account_modal_refresh.py
Normal file
37
tests/test_account_modal_refresh.py
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
"""Открытое окно аккаунта обязано обновляться по свежему снапшоту.
|
||||
|
||||
Владелец открыл карточку Grok сразу после запуска — до того, как пришли
|
||||
живые квоты, — и она навсегда осталась с заглушкой «Grok 2h — Н/Д» и
|
||||
статусом «Не проверялся», хотя сервер уже отдавал 14% расхода подписки и
|
||||
проверка подключения прошла успешно.
|
||||
|
||||
Окно рисовалось один раз при открытии и на опрос не реагировало.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pathlib
|
||||
|
||||
APP_JS = pathlib.Path("src/antigravity_provider/router/web/static/app.js").read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def test_open_modal_is_tracked_and_redrawn():
|
||||
assert "_openAccountModalProfile" in APP_JS, "открытое окно не отслеживается"
|
||||
|
||||
# Объявление обязано идти ДО использования: let не поднимается, и
|
||||
# обращение к нему раньше объявления роняет обработчик снапшота.
|
||||
declaration = APP_JS.index("let _openAccountModalProfile")
|
||||
first_use = APP_JS.index("if (_openAccountModalProfile)")
|
||||
assert declaration < first_use, "переменная используется раньше объявления"
|
||||
|
||||
|
||||
def test_modal_redraw_happens_on_snapshot_apply():
|
||||
"""Перерисовка должна быть привязана к применению снапшота."""
|
||||
head = APP_JS[: APP_JS.index("if (_openAccountModalProfile)")]
|
||||
assert "currentSnapshot = snapshot" in head, "перерисовка не там, где применяется снапшот"
|
||||
|
||||
|
||||
def test_closing_modal_stops_tracking_and_polling():
|
||||
block = APP_JS.split("function closeModal()", 1)[1][:300]
|
||||
assert "_openAccountModalProfile = null" in block, "после закрытия окно продолжает перерисовываться"
|
||||
assert "stopDeviceAuthPolling" in block, "опрос кода устройства не останавливается при закрытии"
|
||||
Loading…
Reference in a new issue