feat (ui): exec fase 5

This commit is contained in:
kodi
2026-03-06 19:55:31 +01:00
parent 3da82255ff
commit 2c5cb07cdb
+78 -1
View File
@@ -420,6 +420,9 @@ let execTerminalState = {
outputText: '',
outputLineCount: 0,
outputTruncated: false,
sessionInfo: null,
infoPollTimer: null,
infoTickTimer: null,
};
const EXEC_OUTPUT_MAX_CHARS = 200000;
@@ -430,6 +433,8 @@ const EXEC_RECONNECT_BASE_MS = 350;
const EXEC_RECONNECT_MAX_MS = 5000;
const EXEC_RECONNECT_MAX_ATTEMPTS = 8;
const EXEC_PASTE_CHUNK_SIZE = 2048;
const EXEC_SESSION_INFO_POLL_MS = 7000;
const EXEC_IDLE_TTL_SECONDS = 60 * 60;
function _execEls() {
return {
@@ -526,7 +531,73 @@ function _execInitTerminal() {
function _execConnectedStatus() {
const sid = execTerminalState.sessionId || '';
return sid ? `Connected (${sid})` : 'Connected';
if (!sid) return 'Connected';
const info = execTerminalState.sessionInfo;
if (!info) return `Connected (${sid})`;
if (info.closed) return `Session closed: ${info.close_reason || 'closed'}`;
const last = Number(info.last_activity || 0);
if (!Number.isFinite(last) || last <= 0) return `Connected (${sid})`;
const now = Math.floor(Date.now() / 1000);
const idleAge = Math.max(0, now - last);
const idleLeft = Math.max(0, EXEC_IDLE_TTL_SECONDS - idleAge);
const mm = String(Math.floor(idleLeft / 60)).padStart(2, '0');
const ss = String(idleLeft % 60).padStart(2, '0');
return `Connected (${sid}) - idle in ${mm}:${ss}`;
}
function _execStopSessionInfoTimers() {
if (execTerminalState.infoPollTimer) {
clearInterval(execTerminalState.infoPollTimer);
execTerminalState.infoPollTimer = null;
}
if (execTerminalState.infoTickTimer) {
clearInterval(execTerminalState.infoTickTimer);
execTerminalState.infoTickTimer = null;
}
}
function _execCanUpdateConnectedStatus() {
if (!execTerminalState.sessionId) return false;
if (
execTerminalState.reconnectEnabled &&
execTerminalState.reconnectAttempts > 0 &&
!execTerminalState.source
) {
return false;
}
return true;
}
async function _execRefreshSessionInfo() {
const sid = execTerminalState.sessionId;
if (!sid) return;
try {
const info = await api(`/containers/exec/${encodeURIComponent(sid)}`, 'GET');
if (sid !== execTerminalState.sessionId) return;
execTerminalState.sessionInfo = info || null;
if (execTerminalState.sessionInfo?.closed) {
execTerminalState.reconnectEnabled = false;
_execCancelReconnect();
_execCloseEventSource();
_execSetStatus(`Session closed: ${execTerminalState.sessionInfo.close_reason || 'closed'}`);
_execStopSessionInfoTimers();
return;
}
if (_execCanUpdateConnectedStatus()) _execSetStatus(_execConnectedStatus());
} catch (_) {
// stream reconnect status has priority
}
}
function _execStartSessionInfoTimers() {
_execStopSessionInfoTimers();
_execRefreshSessionInfo();
execTerminalState.infoPollTimer = setInterval(_execRefreshSessionInfo, EXEC_SESSION_INFO_POLL_MS);
execTerminalState.infoTickTimer = setInterval(() => {
if (!_execCanUpdateConnectedStatus()) return;
_execSetStatus(_execConnectedStatus());
}, 1000);
}
function _execAppendOutput(txt) {
@@ -888,7 +959,9 @@ async function containerExecOpen(name) {
execTerminalState.sessionId = '';
execTerminalState.lastSeq = 0;
execTerminalState.reconnectEnabled = false;
execTerminalState.sessionInfo = null;
_execCancelReconnect();
_execStopSessionInfoTimers();
execTerminalState.rawMode = true;
_execInitTerminal();
_execUpdateInputModeUi();
@@ -907,8 +980,10 @@ async function containerExecOpen(name) {
execTerminalState.sessionId = sid;
execTerminalState.lastSeq = 0;
execTerminalState.reconnectEnabled = true;
execTerminalState.sessionInfo = null;
_execSetStatus(`Connected (${sid})`);
_execAttachStream(0, false);
_execStartSessionInfoTimers();
_execScheduleResize();
@@ -998,6 +1073,7 @@ async function containerExecClose() {
execTerminalState.reconnectEnabled = false;
_execCancelReconnect();
_execStopSessionInfoTimers();
_execCloseEventSource();
_execDestroyTerminal();
_execSetTerminalUiMode(false);
@@ -1013,6 +1089,7 @@ async function containerExecClose() {
execTerminalState.sessionId = '';
execTerminalState.lastSeq = 0;
execTerminalState.sessionInfo = null;
if (els.back) els.back.style.display = 'none';
if (sid) {