fix: new session poll-until-ready before auto-opening
This commit is contained in:
+30
-6
@@ -1402,8 +1402,10 @@ function showFabSessionInput() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new tmux session via POST /api/sessions.
|
* Create a new tmux session via POST /api/sessions.
|
||||||
* Shows a toast with the created session name, calls pollSessions() to refresh,
|
* Shows a toast, then polls _currentSessions until the session name appears
|
||||||
* and if ss.auto_open_created !== false, calls openSession(data.name) after 500ms.
|
* (or times out after 30s) before calling openSession — this handles commands
|
||||||
|
* that take time to create the tmux session (e.g. cloning repos, setup scripts).
|
||||||
|
* If auto_open_created is false in server settings, skips the auto-open.
|
||||||
* @param {string} name - The session name to create.
|
* @param {string} name - The session name to create.
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
@@ -1411,12 +1413,34 @@ async function createNewSession(name) {
|
|||||||
try {
|
try {
|
||||||
const res = await api('POST', '/api/sessions', { name });
|
const res = await api('POST', '/api/sessions', { name });
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
showToast('Created: ' + (data.name || name));
|
const sessionName = data.name || name;
|
||||||
await pollSessions();
|
showToast('Creating session \'' + sessionName + '\'…');
|
||||||
|
|
||||||
const ss = _serverSettings || {};
|
const ss = _serverSettings || {};
|
||||||
if (ss.auto_open_created !== false) {
|
if (ss.auto_open_created === false) {
|
||||||
setTimeout(() => openSession(data.name || name), 500);
|
// Auto-open disabled — just do one refresh
|
||||||
|
await pollSessions();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Poll until the session appears in _currentSessions (max 30s, every 2s)
|
||||||
|
var attempts = 0;
|
||||||
|
var maxAttempts = 15;
|
||||||
|
var pollForSession = setInterval(async function() {
|
||||||
|
attempts++;
|
||||||
|
await pollSessions();
|
||||||
|
var found = _currentSessions && _currentSessions.find(function(s) {
|
||||||
|
return s.name === sessionName;
|
||||||
|
});
|
||||||
|
if (found) {
|
||||||
|
clearInterval(pollForSession);
|
||||||
|
showToast('Session \'' + sessionName + '\' ready');
|
||||||
|
openSession(sessionName);
|
||||||
|
} else if (attempts >= maxAttempts) {
|
||||||
|
clearInterval(pollForSession);
|
||||||
|
showToast('Session \'' + sessionName + '\' is taking longer than expected');
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showToast(err.message || 'Failed to create session');
|
showToast(err.message || 'Failed to create session');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2382,4 +2382,28 @@ test('app.js source uses 500ms debounce for template input and references new_se
|
|||||||
assert.ok(source.includes('new_session_template'), 'must reference new_session_template setting key');
|
assert.ok(source.includes('new_session_template'), 'must reference new_session_template setting key');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('createNewSession polls for session before auto-opening (not immediate setTimeout openSession)', () => {
|
||||||
|
// The old behavior was: setTimeout(() => openSession(...), 500) immediately after POST.
|
||||||
|
// The new behavior must use a polling interval to wait for the session to appear in
|
||||||
|
// _currentSessions before calling openSession — so the immediate pattern must be gone.
|
||||||
|
const source = fs.readFileSync(
|
||||||
|
new URL('../app.js', import.meta.url), 'utf8'
|
||||||
|
);
|
||||||
|
// Extract the createNewSession function body
|
||||||
|
const start = source.indexOf('async function createNewSession(');
|
||||||
|
assert.ok(start !== -1, 'createNewSession function must exist');
|
||||||
|
// Find the end of the function (next function declaration at same indent level)
|
||||||
|
const snippet = source.slice(start, start + 2000);
|
||||||
|
// Must NOT contain the old immediate-open pattern inside createNewSession
|
||||||
|
assert.ok(
|
||||||
|
!snippet.includes("setTimeout(() => openSession"),
|
||||||
|
'createNewSession must not use immediate setTimeout(() => openSession) — should poll instead'
|
||||||
|
);
|
||||||
|
// Must contain a polling mechanism (setInterval)
|
||||||
|
assert.ok(
|
||||||
|
snippet.includes('setInterval'),
|
||||||
|
'createNewSession must use setInterval to poll for session readiness'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1721,8 +1721,8 @@ def test_create_new_session_auto_opens_session() -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_create_new_session_auto_open_delay() -> None:
|
def test_create_new_session_polls_before_open() -> None:
|
||||||
"""createNewSession must use a 500ms delay before calling openSession."""
|
"""createNewSession must poll for the session to appear before calling openSession (not immediate setTimeout)."""
|
||||||
match = re.search(
|
match = re.search(
|
||||||
r"async function createNewSession\s*\(\w+\)\s*\{(.*?)(?=\nasync function |\nfunction |\n// )",
|
r"async function createNewSession\s*\(\w+\)\s*\{(.*?)(?=\nasync function |\nfunction |\n// )",
|
||||||
_JS,
|
_JS,
|
||||||
@@ -1730,7 +1730,14 @@ def test_create_new_session_auto_open_delay() -> None:
|
|||||||
)
|
)
|
||||||
assert match, "createNewSession function not found"
|
assert match, "createNewSession function not found"
|
||||||
body = match.group(1)
|
body = match.group(1)
|
||||||
assert "500" in body, "createNewSession must use 500ms delay before openSession"
|
# Old immediate pattern must be gone
|
||||||
|
assert "setTimeout(() => openSession" not in body, (
|
||||||
|
"createNewSession must not use immediate setTimeout(() => openSession) — should poll instead"
|
||||||
|
)
|
||||||
|
# New polling pattern must be present
|
||||||
|
assert "setInterval" in body, (
|
||||||
|
"createNewSession must use setInterval to poll for session readiness"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_bind_static_event_listeners_binds_new_session_btn() -> None:
|
def test_bind_static_event_listeners_binds_new_session_btn() -> None:
|
||||||
|
|||||||
Reference in New Issue
Block a user