/* init.js — инициализация namespace, утилиты таймера и статуса */ var _initPolling = false; var _initTickBusy = false; var _initStartedAt = 0; 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 formatSeconds(totalSeconds) { totalSeconds = Math.max(0, Number(totalSeconds) || 0); var minutes = Math.floor(totalSeconds / 60); var seconds = totalSeconds % 60; if (minutes <= 0) return seconds + 'с'; return minutes + 'м ' + seconds + 'с'; } function setInitElapsed(seconds) { document.getElementById('init-elapsed').textContent = formatSeconds(seconds); } function setInitCurrentStage(text) { document.getElementById('init-current-stage').textContent = text || 'Ожидание старта'; } function setBox(id, text) { var el = document.getElementById(id); if (!el) return; if (!text) { el.style.display = 'none'; el.textContent = ''; return; } el.style.display = 'block'; el.textContent = text; } function missingKeys(obj) { return Object.keys(obj || {}).filter(function (key) { return !obj[key]; }); } function firstPendingStage(stages) { var list = stages || []; for (var i = 0; i < list.length; i++) { if (!list[i].done) return list[i].name; } return list.length ? list[list.length - 1].name : 'Ожидание старта'; } function describeInitReason(debug) { if (!debug) return 'Собираем диагностические данные по namespace и control-plane...'; if (!debug.exists) return 'Ещё не создан Kubernetes namespace пользователя.'; if (!debug.active) return 'Namespace создан, но Kubernetes ещё не перевёл его в состояние Active.'; var preparation = debug.preparation || {}; if (!preparation.managedByConsole) return 'Namespace существует, но ещё не помечен как managed-by=fission-console.'; if (!preparation.watcherLabel) return 'Namespace ещё не помечен label fission.io/managed=true для NSWatcher.'; var missingSAs = missingKeys(preparation.serviceAccounts); if (missingSAs.length) return 'Не готовы bootstrap service accounts: ' + missingSAs.join(', ') + '.'; var missingRBs = missingKeys(preparation.roleBindings); if (missingRBs.length) return 'Не готовы bootstrap role bindings: ' + missingRBs.join(', ') + '.'; var control = debug.controlPlane || {}; if (!control.executor || !control.executor.ready) { return 'Executor ещё не ready. Возможна задержка из-за cold start, image pull или specialization.'; } if (!control.router || !control.router.ready) { return 'Router ещё не ready. HTTP маршрутизация пока не активна.'; } return 'Ожидаем финальное подтверждение готовности control-plane.'; } function summarizeInit(status, debug) { var done = status && status.stages ? status.stages.filter(function (s) { return s.done; }).length : 0; var namespace = debug && debug.namespace ? debug.namespace : 'не определён'; return 'Namespace: ' + namespace + '. Завершено шагов: ' + done + '/3.'; } function explainDelay(seconds) { if (seconds < 5) return 'Обычная операция без заметной задержки.'; if (seconds < 10) return 'Вероятен cold start: прогрев пула, image pull или ожидание specialization.'; return 'Задержка выше нормы: возможны cold start, specialization или ожидание готовности control-plane.'; } function startTimedStatus(startText, waitingPrefix, waitingHint) { var startedAt = Date.now(); showStatus(startText, ''); var timer = setInterval(function () { var elapsed = Math.max(1, Math.floor((Date.now() - startedAt) / 1000)); var text = waitingPrefix + ' ' + formatSeconds(elapsed); if (waitingHint) text += ' · ' + waitingHint(elapsed); showStatus(text, ''); }, 1000); return { stop: function (message, kind) { clearInterval(timer); var elapsed = Math.max(0, Math.round((Date.now() - startedAt) / 1000)); var text = message; if (message) text += ' за ' + formatSeconds(elapsed); showStatus(text, kind || ''); } }; } 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 '