feat: v0.8.14 — init overlay, /ns/status endpoint, token hint

This commit is contained in:
Naeel
2026-04-25 16:40:27 +03:00
parent b46921708c
commit 7fccd39a73
3 changed files with 171 additions and 2 deletions
+76 -1
View File
@@ -307,13 +307,26 @@
<div class="row" style="flex-direction:column; gap:6px; margin-bottom:12px;">
<label style="font-size:12px; color:#999;">Токен</label>
<textarea id="l-token" rows="5" style="background:var(--bg-base); border:1px solid var(--border); color:var(--fg); padding:8px 10px; border-radius:6px; font-family:monospace; font-size:12px; resize:vertical; width:100%; box-sizing:border-box;" placeholder="Введите токен..."></textarea>
<div style="font-size:11px; color:var(--text-secondary); margin-top:4px;">Токен: <strong style="color:#8bc7ff;">Личный кабинет → Профиль пользователя → Токены</strong></div>
</div>
<div id="l-error" style="display:none; color:#ff6b6b; font-size:13px; margin-bottom:10px;"></div>
<button id="l-btn" class="btn" style="width:100%;" onclick="doLogin()">Войти</button>
</div>
</div>
<!-- Overlay: инициализация нового окружения -->
<div id="init-overlay" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,.88); z-index:1000; align-items:center; justify-content:center; padding:16px;">
<div class="panel" style="width:min(520px,100%);">
<div style="margin-bottom:16px;">
<div style="font-size:16px; font-weight:700; margin-bottom:6px;">⚙️ Инициализация окружения</div>
<div style="font-size:13px; color:var(--text-secondary);">Первый вход. Настраиваем ваше окружение — это займёт ~5 минут.</div>
</div>
<div id="init-log" style="background:#000d1a; border:1px solid var(--border); border-radius:6px; padding:12px; font-family:monospace; font-size:12px; height:160px; overflow-y:auto; color:#4fc3f7; white-space:pre-wrap; line-height:1.6;"></div>
<div id="init-stages" style="margin-top:14px; display:flex; flex-direction:column; gap:8px;"></div>
<div style="margin-top:14px; font-size:12px; color:var(--text-secondary);">Страница обновится автоматически когда всё будет готово.</div>
</div>
</div>
<div class="navbar">
<div class="brand">
<div class="brand-mark">N</div>
<div class="brand-text">
<div class="nubes">NUBES</div>
@@ -826,6 +839,15 @@
localStorage.setItem('auth_token', token);
localStorage.setItem('auth_env', env);
hideLoginOverlay();
// Проверяем статус NS — если не ready, показываем init overlay
try {
var sr = await fetch(API_BASE + '/ns/status', {headers: {'X-Auth-Token': token, 'X-Auth-Env': env}});
var sd = await sr.json();
if (!sd.ready) {
pollNSStatus();
return;
}
} catch(_) {}
reloadAll();
} catch(e) {
errEl.textContent = e.message;
@@ -870,6 +892,59 @@
}
}
var _initPolling = false;
function initLog(msg) {
var el = document.getElementById('init-log');
var ts = new Date().toLocaleTimeString('ru-RU');
el.textContent += '[' + ts + '] ' + msg + '\n';
el.scrollTop = el.scrollHeight;
}
function renderInitStages(stages) {
var el = document.getElementById('init-stages');
el.innerHTML = stages.map(function(s) {
var icon = s.done ? '✅' : '⏳';
var color = s.done ? '#4caf50' : '#8bc7ff';
return '<div style="font-size:13px; color:' + color + ';">' + icon + '&nbsp;' + s.name + '</div>';
}).join('');
}
async function pollNSStatus() {
if (_initPolling) return;
_initPolling = true;
var overlay = document.getElementById('init-overlay');
overlay.style.display = 'flex';
initLog('Запуск инициализации...');
var attempt = 0;
var maxAttempts = 60; // 5 минут
var interval = setInterval(async function() {
attempt++;
try {
var r = await fetch(API_BASE + '/ns/status', {headers: authHeaders()});
var d = await r.json();
if (d.stages) renderInitStages(d.stages);
var done = d.stages ? d.stages.filter(function(s){return s.done;}).length : 0;
initLog('Шагов завершено: ' + done + '/3');
if (d.ready) {
initLog('✅ Готово! Загружаем консоль...');
clearInterval(interval);
_initPolling = false;
overlay.style.display = 'none';
reloadAll();
return;
}
} catch(e) {
initLog('Ошибка опроса: ' + e.message);
}
if (attempt >= maxAttempts) {
clearInterval(interval);
_initPolling = false;
initLog('⚠️ Превышено время ожидания. Попробуйте обновить страницу.');
}
}, 5000);
}
function checkAuth() {
if (!localStorage.getItem('auth_token')) {
showLoginOverlay();