From 266f10d1eb28b6d830d26021ba7078064764995c Mon Sep 17 00:00:00 2001 From: Priya Patel Date: Fri, 3 Apr 2026 12:11:46 -0700 Subject: [PATCH] Fix terminal view lag while route changes (#3228) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 🐛 fixed terminal view being visible after route change * test: 💍 fixed tests * chore: 🤖 used willTransition hook * chore: 🤖 hides terminal view on willtransition * fix: 🐛 removed unneccessary await from hideTerminalView * chore: 🤖 removed extra hideterminalview call * chore: 🤖 removed settabactive on failure --- .../scopes/scope/projects/sessions/session.js | 21 +++++++++++++++++++ ui/desktop/app/services/terminal.js | 4 ++-- ui/desktop/electron-app/src/ipc/handlers.js | 4 +--- ui/desktop/electron-app/src/preload.js | 2 +- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/ui/desktop/app/routes/scopes/scope/projects/sessions/session.js b/ui/desktop/app/routes/scopes/scope/projects/sessions/session.js index bc0049d79..30b7d77de 100644 --- a/ui/desktop/app/routes/scopes/scope/projects/sessions/session.js +++ b/ui/desktop/app/routes/scopes/scope/projects/sessions/session.js @@ -5,7 +5,9 @@ import Route from '@ember/routing/route'; import { service } from '@ember/service'; +import { action } from '@ember/object'; import { TYPE_TARGET_RDP } from 'api/models/target'; + const { __electronLog } = globalThis; export default class ScopesScopeProjectsSessionsSessionRoute extends Route { @@ -16,6 +18,7 @@ export default class ScopesScopeProjectsSessionsSessionRoute extends Route { @service flashMessages; @service intl; @service storage; + @service terminal; // =methods @@ -97,4 +100,22 @@ export default class ScopesScopeProjectsSessionsSessionRoute extends Route { return session; } + + @action + async willTransition(transition) { + // If the terminal tab is active, we want to hide it before transitioning to prevent the terminal from briefly remaining visible after route transition. + if (this.terminal.isTerminalTabActive) { + transition.abort(); + try { + // wait for terminal to hide + await this.terminal.setTerminalTabActive(false); + // retry the transition after hiding + transition.retry(); + } catch (error) { + __electronLog?.error('Terminal hide failed', error.message); + // let transition proceed + transition.retry(); + } + } + } } diff --git a/ui/desktop/app/services/terminal.js b/ui/desktop/app/services/terminal.js index e1add4577..5eaf73fa0 100644 --- a/ui/desktop/app/services/terminal.js +++ b/ui/desktop/app/services/terminal.js @@ -53,7 +53,7 @@ export default class TerminalService extends Service { this.isTerminalTabActive = isActive; if (!isActive) { - this.hideTerminalView(); + return this.hideTerminalView(); } } @@ -72,7 +72,7 @@ export default class TerminalService extends Service { * Hides the terminal view. We do this instead of destroying the view because we want to preserve the state of the terminal session. */ hideTerminalView() { - window.webContentView?.hideTerminalView(); + return window.webContentView?.hideTerminalView(); } createTerminalView(payload) { diff --git a/ui/desktop/electron-app/src/ipc/handlers.js b/ui/desktop/electron-app/src/ipc/handlers.js index c09618f76..493516010 100644 --- a/ui/desktop/electron-app/src/ipc/handlers.js +++ b/ui/desktop/electron-app/src/ipc/handlers.js @@ -320,9 +320,7 @@ ipcMain.on('destroyTerminalView', () => { /** * Hides the terminal view from the main window */ -ipcMain.on('hideTerminalView', () => { - terminalManager.hideTerminalView(); -}); +handle('hideTerminalView', () => terminalManager.hideTerminalView()); /** * Positions the terminal view within the main window based on the provided position diff --git a/ui/desktop/electron-app/src/preload.js b/ui/desktop/electron-app/src/preload.js index c79ecc882..793de495a 100644 --- a/ui/desktop/electron-app/src/preload.js +++ b/ui/desktop/electron-app/src/preload.js @@ -104,7 +104,7 @@ contextBridge.exposeInMainWorld('webContentView', { ipcRenderer.send('destroyTerminalView'); }, hideTerminalView: () => { - ipcRenderer.send('hideTerminalView'); + return invoke('hideTerminalView'); }, positionTerminalView: (position) => { ipcRenderer.send('positionTerminalView', position);