diff --git a/terminus-core/src/tabContextMenu.ts b/terminus-core/src/tabContextMenu.ts index 5e68079b..978e7680 100644 --- a/terminus-core/src/tabContextMenu.ts +++ b/terminus-core/src/tabContextMenu.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import { Injectable, NgZone } from '@angular/core' +import { Injectable } from '@angular/core' import { Subscription } from 'rxjs' import { AppService } from './services/app.service' import { BaseTabComponent } from './components/baseTab.component' @@ -15,7 +15,6 @@ export class TabManagementContextMenu extends TabContextMenuItemProvider { constructor ( private app: AppService, - private zone: NgZone, ) { super() } @@ -24,13 +23,13 @@ export class TabManagementContextMenu extends TabContextMenuItemProvider { let items: MenuItemOptions[] = [ { label: 'Close', - click: () => this.zone.run(() => { + click: () => { if (this.app.tabs.includes(tab)) { this.app.closeTab(tab, true) } else { tab.destroy() } - }), + }, }, ] if (tabHeader) { @@ -38,27 +37,27 @@ export class TabManagementContextMenu extends TabContextMenuItemProvider { ...items, { label: 'Close other tabs', - click: () => this.zone.run(() => { + click: () => { for (const t of this.app.tabs.filter(x => x !== tab)) { this.app.closeTab(t, true) } - }), + }, }, { label: 'Close tabs to the right', - click: () => this.zone.run(() => { + click: () => { for (const t of this.app.tabs.slice(this.app.tabs.indexOf(tab) + 1)) { this.app.closeTab(t, true) } - }), + }, }, { label: 'Close tabs to the left', - click: () => this.zone.run(() => { + click: () => { for (const t of this.app.tabs.slice(0, this.app.tabs.indexOf(tab))) { this.app.closeTab(t, true) } - }), + }, }, ] } else { @@ -73,9 +72,9 @@ export class TabManagementContextMenu extends TabContextMenuItemProvider { l: 'Left', t: 'Up', }[dir], - click: () => this.zone.run(() => { + click: () => { (tab.parent as SplitTabComponent).splitTab(tab, dir) - }), + }, })) as MenuItemOptions[], }) } @@ -100,7 +99,6 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider { weight = -1 constructor ( - private zone: NgZone, private app: AppService, ) { super() @@ -113,11 +111,11 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider { ...items, { label: 'Rename', - click: () => this.zone.run(() => tabHeader.showRenameTabModal()), + click: () => tabHeader.showRenameTabModal(), }, { label: 'Duplicate', - click: () => this.zone.run(() => this.app.duplicateTab(tab)), + click: () => this.app.duplicateTab(tab), }, { label: 'Color', @@ -126,9 +124,9 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider { label: color.name, type: 'radio', checked: tab.color === color.value, - click: () => this.zone.run(() => { + click: () => { tab.color = color.value - }), + }, })) as MenuItemOptions[], }, ] @@ -142,7 +140,6 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider { export class TaskCompletionContextMenu extends TabContextMenuItemProvider { constructor ( private app: AppService, - private zone: NgZone, ) { super() } @@ -162,7 +159,7 @@ export class TaskCompletionContextMenu extends TabContextMenuItemProvider { label: 'Notify when done', type: 'checkbox', checked: extTab.__completionNotificationEnabled, - click: () => this.zone.run(() => { + click: () => { extTab.__completionNotificationEnabled = !extTab.__completionNotificationEnabled if (extTab.__completionNotificationEnabled) { @@ -177,14 +174,14 @@ export class TaskCompletionContextMenu extends TabContextMenuItemProvider { } else { this.app.stopObservingTabCompletion(tab) } - }), + }, }) } items.push({ label: 'Notify on activity', type: 'checkbox', checked: !!extTab.__outputNotificationSubscription, - click: () => this.zone.run(() => { + click: () => { if (extTab.__outputNotificationSubscription) { extTab.__outputNotificationSubscription.unsubscribe() extTab.__outputNotificationSubscription = null @@ -201,7 +198,7 @@ export class TaskCompletionContextMenu extends TabContextMenuItemProvider { } }) } - }), + }, }) return items } diff --git a/terminus-electron/src/services/platform.service.ts b/terminus-electron/src/services/platform.service.ts index 5049fca4..2572d7ec 100644 --- a/terminus-electron/src/services/platform.service.ts +++ b/terminus-electron/src/services/platform.service.ts @@ -147,9 +147,19 @@ export class ElectronPlatformService extends PlatformService { } popupContextMenu (menu: MenuItemOptions[], _event?: MouseEvent): void { - this.electron.Menu.buildFromTemplate(menu.map(item => ({ - ...item, - }))).popup({}) + this.electron.Menu.buildFromTemplate(menu.map(item => this.rewrapMenuItemOptions(item))).popup({}) + } + + rewrapMenuItemOptions (menu: MenuItemOptions): MenuItemOptions { + return { + ...menu, + click: () => { + this.zone.run(() => { + menu.click?.() + }) + }, + submenu: menu.submenu ? menu.submenu.map(x => this.rewrapMenuItemOptions(x)) : undefined, + } } async showMessageBox (options: MessageBoxOptions): Promise { diff --git a/terminus-local/src/tabContextMenu.ts b/terminus-local/src/tabContextMenu.ts index df0cb57b..51708692 100644 --- a/terminus-local/src/tabContextMenu.ts +++ b/terminus-local/src/tabContextMenu.ts @@ -1,4 +1,4 @@ -import { Injectable, NgZone } from '@angular/core' +import { Injectable } from '@angular/core' import { ConfigService, BaseTabComponent, TabContextMenuItemProvider, TabHeaderComponent, SplitTabComponent, NotificationsService, MenuItemOptions } from 'terminus-core' import { TerminalTabComponent } from './components/terminalTab.component' import { UACService } from './services/uac.service' @@ -9,7 +9,6 @@ import { TerminalService } from './services/terminal.service' export class SaveAsProfileContextMenu extends TabContextMenuItemProvider { constructor ( private config: ConfigService, - private zone: NgZone, private notifications: NotificationsService, ) { super() @@ -22,7 +21,7 @@ export class SaveAsProfileContextMenu extends TabContextMenuItemProvider { const items: MenuItemOptions[] = [ { label: 'Save as profile', - click: () => this.zone.run(async () => { + click: async () => { const profile = { sessionOptions: { ...tab.sessionOptions, @@ -36,7 +35,7 @@ export class SaveAsProfileContextMenu extends TabContextMenuItemProvider { ] this.config.save() this.notifications.info('Saved') - }), + }, }, ] @@ -51,7 +50,6 @@ export class NewTabContextMenu extends TabContextMenuItemProvider { constructor ( public config: ConfigService, - private zone: NgZone, private terminalService: TerminalService, private uac: UACService, ) { @@ -64,21 +62,21 @@ export class NewTabContextMenu extends TabContextMenuItemProvider { const items: MenuItemOptions[] = [ { label: 'New terminal', - click: () => this.zone.run(() => { + click: () => { this.terminalService.openTabWithOptions((tab as any).sessionOptions) - }), + }, }, { label: 'New with profile', submenu: profiles.map(profile => ({ label: profile.name, - click: () => this.zone.run(async () => { + click: async () => { let workingDirectory = this.config.store.terminal.workingDirectory if (this.config.store.terminal.alwaysUseWorkingDirectory !== true && tab instanceof TerminalTabComponent) { workingDirectory = await tab.session?.getWorkingDirectory() } await this.terminalService.openTab(profile, workingDirectory) - }), + }, })), }, ] @@ -88,12 +86,12 @@ export class NewTabContextMenu extends TabContextMenuItemProvider { label: 'New admin tab', submenu: profiles.map(profile => ({ label: profile.name, - click: () => this.zone.run(async () => { + click: () => { this.terminalService.openTabWithOptions({ ...profile.sessionOptions, runAsAdministrator: true, }) - }), + }, })), }) } @@ -101,28 +99,28 @@ export class NewTabContextMenu extends TabContextMenuItemProvider { if (tab instanceof TerminalTabComponent && tabHeader && this.uac.isAvailable) { items.push({ label: 'Duplicate as administrator', - click: () => this.zone.run(async () => { + click: () => { this.terminalService.openTabWithOptions({ ...tab.sessionOptions, runAsAdministrator: true, }) - }), + }, }) } if (tab instanceof TerminalTabComponent && tab.parent instanceof SplitTabComponent && tab.parent.getAllTabs().length > 1) { items.push({ label: 'Focus all panes', - click: () => this.zone.run(() => { + click: () => { tab.focusAllPanes() - }), + }, }) } if (tab instanceof TerminalTabComponent && tab.session?.supportsWorkingDirectory()) { items.push({ label: 'Copy current path', - click: () => this.zone.run(() => tab.copyCurrentPath()), + click: () => tab.copyCurrentPath(), }) } diff --git a/terminus-ssh/src/tabContextMenu.ts b/terminus-ssh/src/tabContextMenu.ts index d887dca9..1cbaac5b 100644 --- a/terminus-ssh/src/tabContextMenu.ts +++ b/terminus-ssh/src/tabContextMenu.ts @@ -20,16 +20,18 @@ export class WinSCPContextMenu extends TabContextMenuItemProvider { if (!(tab instanceof SSHTabComponent) || !tab.connection) { return [] } - if (this.hostApp.platform !== Platform.Windows || !this.ssh.getWinSCPPath()) { - return [] - } - return [ - { + const items = [{ + label: 'Open SFTP panel', + click: () => tab.openSFTP(), + }] + if (this.hostApp.platform === Platform.Windows && this.ssh.getWinSCPPath()) { + items.push({ label: 'Launch WinSCP', click: (): void => { this.ssh.launchWinSCP(tab.session!) }, - }, - ] + }) + } + return items } } diff --git a/terminus-terminal/src/tabContextMenu.ts b/terminus-terminal/src/tabContextMenu.ts index 2896cc7d..7c096b2f 100644 --- a/terminus-terminal/src/tabContextMenu.ts +++ b/terminus-terminal/src/tabContextMenu.ts @@ -1,4 +1,4 @@ -import { Injectable, NgZone, Optional, Inject } from '@angular/core' +import { Injectable, Optional, Inject } from '@angular/core' import { BaseTabComponent, TabContextMenuItemProvider, TabHeaderComponent, NotificationsService, MenuItemOptions } from 'terminus-core' import { BaseTerminalTabComponent } from './api/baseTerminalTab.component' import { TerminalContextMenuItemProvider } from './api/contextMenuProvider' @@ -9,7 +9,6 @@ export class CopyPasteContextMenu extends TabContextMenuItemProvider { weight = -10 constructor ( - private zone: NgZone, private notifications: NotificationsService, ) { super() @@ -24,19 +23,15 @@ export class CopyPasteContextMenu extends TabContextMenuItemProvider { { label: 'Copy', click: (): void => { - this.zone.run(() => { - setTimeout(() => { - tab.frontend?.copySelection() - this.notifications.notice('Copied') - }) + setTimeout(() => { + tab.frontend?.copySelection() + this.notifications.notice('Copied') }) }, }, { label: 'Paste', - click: (): void => { - this.zone.run(() => tab.paste()) - }, + click: () => tab.paste(), }, ] }