Files
threshold-ui/ui/desktop/app/controllers/application.js
T
Priya Patel f48e6dc049 Refactor: Load terminal using web contents view (#3190)
* chore: 🤖 create terminal preload

* chore: 🤖 created terminal-manager service and updated handlers

* chore: 🤖 adds terminal view and bundling script

* chore: 🤖 addede terminal service, updated tabs component

* chore: 🤖 hides terminal on signout modal

* test: 💍 added terminal service tests

* chore: 🤖 removed debug file

* chore: 🤖 adds windows event handler

* docs: ✏️ adds jsdoc for terminal view

* chore: 🤖 removed xterm dependency from desktop package.json

* chore: 🤖 updated sessionId check

* chore: 🤖 fixed zoom sync with main window

* chore: 🤖 adds CSP for terminal view

* chore: 🤖 hides terminal on error

* chore: 🤖 cleamup listener, fixed failing tests

* chore: 🤖 fixed terminal view cleanup

* chore: 🤖 addressed feedback

* fix: 🐛 adds null check for destroy, hdie terminal view

* fix: 🐛 fixed terminal view on logout/app quit modal

* fix: 🐛 fixed hidding modal on app quit

* chore: 🤖 addressed feedback

* chore: 🤖 hides terminal view when sidenav is expanded

* chore: 🤖 removed canDisplayExistingTerminal
2026-03-30 10:08:55 -07:00

221 lines
5.7 KiB
JavaScript

/**
* Copyright IBM Corp. 2021, 2026
* SPDX-License-Identifier: BUSL-1.1
*/
import Controller from '@ember/controller';
import { service } from '@ember/service';
import { getOwner } from '@ember/application';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
import { defaultValidator } from 'ember-a11y-refocus';
import { paramValueFinder } from 'core/utils/param-value-finder';
export default class ApplicationController extends Controller {
// =services
@service clusterUrl;
@service flashMessages;
@service session;
@service('browser/window') window;
@service router;
@service scope;
@service intl;
@service terminal;
// =attributes
@tracked isLoggingOut = false;
@tracked isAppQuitting = false;
removeOnAppQuitListener;
constructor() {
super(...arguments);
// Listen for when user attempts to quit app
// Setup removeOnAppQuitListener to destroy the listener afterwards
this.removeOnAppQuitListener = this.window.desktop?.app.onAppQuit(() => {
this.isAppQuitting = true;
this.hideTerminalViewForModal();
});
}
/**
* Returns display name and icon for current scope.
* @type {object}
*/
get currentScope() {
if (this.scope.org.isOrg) {
return { name: this.scope.org.displayName, icon: 'org' };
} else {
return { name: this.intl.t('titles.global'), icon: 'globe' };
}
}
/**
* Shows side navigation only for routes nested under a scope
* and if user has been authenticated.
* @type {boolean}
*/
get showSideNav() {
return (
this.router.currentRouteName.startsWith('scopes.scope') &&
this.session.isAuthenticated
);
}
// =actions
/**
* Stop all active/pending target sessions
* Logout or close app
*/
@action
async confirmCloseSessions() {
await window.desktop.session.stopAllSessions();
if (this.isAppQuitting) {
this.isAppQuitting = false;
this.close();
} else {
// this.session.invalidate() comes from Ember Simple Auth BaseSessionService
this.session.invalidate();
}
this.isLoggingOut = false;
}
/**
* Only renders the signout modal if target sessions are running
*/
@action
async showModalOrLogout() {
const hasRunningSessions =
await window.desktop.session.hasRunningSessions();
if (hasRunningSessions) {
this.isLoggingOut = true;
this.hideTerminalViewForModal();
} else {
this.session.invalidate();
}
}
/**
* Disconnects from clusterUrl and invalidates session, thereby resetting
* the client and reloading to the onboarding clusterUrl screen.
*/
@action
disconnect() {
this.clusterUrl.resetClusterUrl();
this.session.invalidate();
}
@action
minimize() {
window.desktop.windowAction.minimizeWindow();
}
@action
toggleFullScreen() {
window.desktop.windowAction.toggleFullscreenWindow();
}
@action
close() {
window.desktop.windowAction.closeWindow();
}
/**
* Applies the specified color theme to the root ember element.
* @param {string} theme - "light", "dark", or nullish (system default)
*/
@action
toggleTheme(theme) {
const rootElementSelector = getOwner(this).rootElement;
const rootEl = getOwner(this)
.lookup('service:-document')
.querySelector(rootElementSelector);
this.session.set('data.theme', theme);
switch (theme) {
case 'light':
rootEl.classList.add('rose-theme-light');
rootEl.classList.remove('rose-theme-dark');
break;
case 'dark':
rootEl.classList.add('rose-theme-dark');
rootEl.classList.remove('rose-theme-light');
break;
default:
rootEl.classList.remove('rose-theme-dark');
rootEl.classList.remove('rose-theme-light');
}
}
@action
cancel() {
this.isLoggingOut = false;
this.isAppQuitting = false;
if (this.terminal.isTerminalTabActive) {
this.terminal.displayTerminalView();
}
}
willDestroy() {
super.willDestroy(...arguments);
this.removeOnAppQuitListener?.();
}
/**
* Add custom route change validation to prevent refocus when
* user is attempting to search, filter, or sort.
* @param {object} transition
* @returns {boolean}
*/
customRouteChangeValidator(transition) {
if (!transition.to || !transition.from) {
return true;
}
if (transition.to.name === transition.from.name) {
const toParams = paramValueFinder(
transition.to.localName,
transition.to.parent,
);
const fromParams = paramValueFinder(
transition.from.localName,
transition.from.parent,
);
// Return false to prevent refocus when routes have equivalent dynamic segments (params).
return JSON.stringify(toParams) !== JSON.stringify(fromParams);
}
return defaultValidator(transition);
}
/**
* Hides terminal if open and on terminal tab of Session details page for logout/app quit modal
*/
hideTerminalViewForModal() {
if (this.terminal.isTerminalTabActive) {
this.terminal.hideTerminalView();
}
}
/**
* Handles side nav toggle to hide/show terminal based on side nav state
* @param {boolean} isMinimized - Whether the side nav is minimized i.e. collapsed
*/
@action
handleSideNavToggle(isMinimized) {
this.terminal.setSideNavMinimized(isMinimized);
// update terminal view if we're on the terminal tab
if (this.terminal.isTerminalTabActive) {
if (isMinimized) {
// Side nav is collapsed, display terminal view
this.terminal.displayTerminalView();
} else {
// Side nav is expanded, hide terminal view
this.terminal.hideTerminalView();
}
}
}
}