feat: add inline kill confirmation in flyout, remove old confirm() dialog
This commit is contained in:
+79
-1
@@ -1890,6 +1890,85 @@ function _doRemoveFromView() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show inline kill confirmation inside the flyout menu.
|
||||||
|
* Replaces the "Kill Session" item with "Kill? [Yes] [No]".
|
||||||
|
* No timeout — stays until click-outside closes the menu.
|
||||||
|
* On error: "Failed" for 2 seconds then reverts.
|
||||||
|
* @param {HTMLElement} killItem - The "Kill Session" menu item element
|
||||||
|
*/
|
||||||
|
function _doKillSessionInline(killItem) {
|
||||||
|
var sessionName = _flyoutSessionName;
|
||||||
|
var remoteId = _flyoutRemoteId;
|
||||||
|
|
||||||
|
// Replace the kill item with confirmation UI
|
||||||
|
var confirmHtml =
|
||||||
|
'<div class="flyout-menu__confirm">' +
|
||||||
|
'<span>Kill?</span>' +
|
||||||
|
'<button class="flyout-menu__confirm-btn flyout-menu__confirm-btn--yes" data-action="confirm-kill">Yes</button>' +
|
||||||
|
'<button class="flyout-menu__confirm-btn" data-action="cancel-kill">No</button>' +
|
||||||
|
'</div>';
|
||||||
|
|
||||||
|
killItem.outerHTML = confirmHtml;
|
||||||
|
|
||||||
|
// Re-attach handlers on the confirm/cancel buttons
|
||||||
|
if (!_flyoutMenuEl) return;
|
||||||
|
|
||||||
|
var confirmBtn = _flyoutMenuEl.querySelector('[data-action="confirm-kill"]');
|
||||||
|
var cancelBtn = _flyoutMenuEl.querySelector('[data-action="cancel-kill"]');
|
||||||
|
|
||||||
|
if (confirmBtn) {
|
||||||
|
confirmBtn.addEventListener('click', function(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
_executeKill(sessionName, remoteId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cancelBtn) {
|
||||||
|
cancelBtn.addEventListener('click', function(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
closeFlyoutMenu();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the kill session API call from the flyout inline confirmation.
|
||||||
|
* On success: closes flyout, shows toast, refreshes sessions.
|
||||||
|
* On error: shows "Failed" for 2s in the confirm area, then reverts.
|
||||||
|
* @param {string} name
|
||||||
|
* @param {string} remoteId
|
||||||
|
*/
|
||||||
|
function _executeKill(name, remoteId) {
|
||||||
|
var endpoint = remoteId
|
||||||
|
? '/api/federation/' + encodeURIComponent(remoteId) + '/sessions/' + encodeURIComponent(name)
|
||||||
|
: '/api/sessions/' + encodeURIComponent(name);
|
||||||
|
|
||||||
|
api('DELETE', endpoint)
|
||||||
|
.then(function() {
|
||||||
|
closeFlyoutMenu();
|
||||||
|
showToast('Session \'' + name + '\' killed');
|
||||||
|
if (_viewingSession === name) {
|
||||||
|
closeSession();
|
||||||
|
}
|
||||||
|
pollSessions();
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
// Show "Failed" for 2 seconds
|
||||||
|
var confirmDiv = _flyoutMenuEl && _flyoutMenuEl.querySelector('.flyout-menu__confirm');
|
||||||
|
if (confirmDiv) {
|
||||||
|
confirmDiv.innerHTML = '<span style="color:var(--err)">Failed</span>';
|
||||||
|
setTimeout(function() {
|
||||||
|
// Revert to original kill button if menu is still open
|
||||||
|
if (_flyoutMenuEl && confirmDiv.parentNode) {
|
||||||
|
confirmDiv.outerHTML =
|
||||||
|
'<button class="flyout-menu__item flyout-menu__item--danger" role="menuitem" data-action="kill">Kill Session</button>';
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// ─── Notification permission ────────────────────────────────────────────────
|
// ─── Notification permission ────────────────────────────────────────────────
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -3190,7 +3269,6 @@ async function createNewSession(name, remoteId) {
|
|||||||
* @param {string} [remoteId] - Remote instance index (empty or absent for local).
|
* @param {string} [remoteId] - Remote instance index (empty or absent for local).
|
||||||
*/
|
*/
|
||||||
function killSession(name, remoteId) {
|
function killSession(name, remoteId) {
|
||||||
if (!confirm('Kill session "' + name + '"?')) return;
|
|
||||||
var endpoint = remoteId
|
var endpoint = remoteId
|
||||||
? '/api/federation/' + encodeURIComponent(remoteId) + '/sessions/' + encodeURIComponent(name)
|
? '/api/federation/' + encodeURIComponent(remoteId) + '/sessions/' + encodeURIComponent(name)
|
||||||
: '/api/sessions/' + encodeURIComponent(name);
|
: '/api/sessions/' + encodeURIComponent(name);
|
||||||
|
|||||||
@@ -3856,3 +3856,29 @@ def test_hide_session_removes_from_all_views() -> None:
|
|||||||
assert "views" in fn_body, (
|
assert "views" in fn_body, (
|
||||||
"_doHideSession must remove session from all views (mutual exclusion)"
|
"_doHideSession must remove session from all views (mutual exclusion)"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# ─── Task 7: Kill session inline confirmation ─────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
|
def test_do_kill_session_inline_function_exists() -> None:
|
||||||
|
"""app.js must define a _doKillSessionInline function."""
|
||||||
|
assert "function _doKillSessionInline" in _JS, (
|
||||||
|
"app.js must contain a _doKillSessionInline function"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_kill_session_no_confirm_dialog() -> None:
|
||||||
|
"""killSession must NOT use window.confirm() (replaced by inline confirmation)."""
|
||||||
|
fn_body = _JS.split("function killSession")[1].split("\nfunction ")[0]
|
||||||
|
assert "confirm(" not in fn_body, (
|
||||||
|
"killSession must not use confirm() — replaced by inline flyout confirmation"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_do_kill_inline_shows_confirmation_buttons() -> None:
|
||||||
|
"""_doKillSessionInline must render Yes/No confirmation buttons."""
|
||||||
|
fn_body = _JS.split("function _doKillSessionInline")[1].split("\nfunction ")[0]
|
||||||
|
assert "Yes" in fn_body and "No" in fn_body, (
|
||||||
|
"_doKillSessionInline must show 'Kill? [Yes] [No]' inline"
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user