mirror of
https://github.com/Eugeny/tabby.git
synced 2025-06-18 18:39:55 +00:00
Merge pull request #8416 from Clem-Fern/connectable-refactoring
Refactoring connectable tab
This commit is contained in:
commit
fac6ec572f
@ -2,9 +2,8 @@
|
|||||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'
|
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'
|
||||||
import colors from 'ansi-colors'
|
import colors from 'ansi-colors'
|
||||||
import { Component, Injector } from '@angular/core'
|
import { Component, Injector } from '@angular/core'
|
||||||
import { first } from 'rxjs'
|
import { Platform, SelectorService } from 'tabby-core'
|
||||||
import { GetRecoveryTokenOptions, Platform, SelectorService } from 'tabby-core'
|
import { BaseTerminalTabComponent, ConnectableTerminalTabComponent } from 'tabby-terminal'
|
||||||
import { BaseTerminalTabComponent, Reconnectable } from 'tabby-terminal'
|
|
||||||
import { SerialSession, BAUD_RATES, SerialProfile } from '../api'
|
import { SerialSession, BAUD_RATES, SerialProfile } from '../api'
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
@ -14,7 +13,7 @@ import { SerialSession, BAUD_RATES, SerialProfile } from '../api'
|
|||||||
styleUrls: ['./serialTab.component.scss', ...BaseTerminalTabComponent.styles],
|
styleUrls: ['./serialTab.component.scss', ...BaseTerminalTabComponent.styles],
|
||||||
animations: BaseTerminalTabComponent.animations,
|
animations: BaseTerminalTabComponent.animations,
|
||||||
})
|
})
|
||||||
export class SerialTabComponent extends BaseTerminalTabComponent<SerialProfile> implements Reconnectable {
|
export class SerialTabComponent extends ConnectableTerminalTabComponent<SerialProfile> {
|
||||||
session: SerialSession|null = null
|
session: SerialSession|null = null
|
||||||
Platform = Platform
|
Platform = Platform
|
||||||
|
|
||||||
@ -28,8 +27,6 @@ export class SerialTabComponent extends BaseTerminalTabComponent<SerialProfile>
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
this.logger = this.log.create('terminalTab')
|
|
||||||
|
|
||||||
this.subscribeUntilDestroyed(this.hotkeys.hotkey$, hotkey => {
|
this.subscribeUntilDestroyed(this.hotkeys.hotkey$, hotkey => {
|
||||||
if (!this.hasFocus) {
|
if (!this.hasFocus) {
|
||||||
return
|
return
|
||||||
@ -54,12 +51,9 @@ export class SerialTabComponent extends BaseTerminalTabComponent<SerialProfile>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
protected onFrontendReady (): void {
|
|
||||||
this.initializeSession()
|
|
||||||
super.onFrontendReady()
|
|
||||||
}
|
|
||||||
|
|
||||||
async initializeSession () {
|
async initializeSession () {
|
||||||
|
super.initializeSession()
|
||||||
|
|
||||||
const session = new SerialSession(this.injector, this.profile)
|
const session = new SerialSession(this.injector, this.profile)
|
||||||
this.setSession(session)
|
this.setSession(session)
|
||||||
|
|
||||||
@ -82,38 +76,16 @@ export class SerialTabComponent extends BaseTerminalTabComponent<SerialProfile>
|
|||||||
this.write(`\r\n${colors.black.bgWhite(' Serial ')} ${msg}\r\n`)
|
this.write(`\r\n${colors.black.bgWhite(' Serial ')} ${msg}\r\n`)
|
||||||
this.session?.resize(this.size.columns, this.size.rows)
|
this.session?.resize(this.size.columns, this.size.rows)
|
||||||
})
|
})
|
||||||
this.attachSessionHandler(this.session!.destroyed$, () => {
|
|
||||||
if (this.frontend) {
|
|
||||||
// Session was closed abruptly
|
|
||||||
this.write('\r\n' + colors.black.bgWhite(' SERIAL ') + ` session closed\r\n`)
|
|
||||||
|
|
||||||
if (this.profile.behaviorOnSessionEnd === 'reconnect') {
|
|
||||||
this.reconnect()
|
|
||||||
} else if (this.profile.behaviorOnSessionEnd === 'keep' || this.profile.behaviorOnSessionEnd === 'auto' && !this.isSessionExplicitlyTerminated()) {
|
|
||||||
this.write(this.translate.instant(_('Press any key to reconnect')) + '\r\n')
|
|
||||||
this.input$.pipe(first()).subscribe(() => {
|
|
||||||
if (!this.session?.open) {
|
|
||||||
this.reconnect()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
super.attachSessionHandlers()
|
super.attachSessionHandlers()
|
||||||
}
|
}
|
||||||
|
|
||||||
async getRecoveryToken (options?: GetRecoveryTokenOptions): Promise<any> {
|
protected onSessionDestroyed (): void {
|
||||||
return {
|
if (this.frontend) {
|
||||||
type: 'app:serial-tab',
|
// Session was closed abruptly
|
||||||
profile: this.profile,
|
this.write('\r\n' + colors.black.bgWhite(' SERIAL ') + ` session closed\r\n`)
|
||||||
savedState: options?.includeState && this.frontend?.saveState(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async reconnect (): Promise<void> {
|
super.onSessionDestroyed()
|
||||||
this.session?.destroy()
|
}
|
||||||
await this.initializeSession()
|
|
||||||
this.session?.releaseInitialDataBuffer()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async changeBaudRate () {
|
async changeBaudRate () {
|
||||||
|
@ -2,9 +2,8 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'
|
|||||||
import colors from 'ansi-colors'
|
import colors from 'ansi-colors'
|
||||||
import { Component, Injector, HostListener } from '@angular/core'
|
import { Component, Injector, HostListener } from '@angular/core'
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { first } from 'rxjs'
|
import { Platform, ProfilesService } from 'tabby-core'
|
||||||
import { GetRecoveryTokenOptions, Platform, ProfilesService, RecoveryToken } from 'tabby-core'
|
import { BaseTerminalTabComponent, ConnectableTerminalTabComponent } from 'tabby-terminal'
|
||||||
import { BaseTerminalTabComponent, Reconnectable } from 'tabby-terminal'
|
|
||||||
import { SSHService } from '../services/ssh.service'
|
import { SSHService } from '../services/ssh.service'
|
||||||
import { KeyboardInteractivePrompt, SSHSession } from '../session/ssh'
|
import { KeyboardInteractivePrompt, SSHSession } from '../session/ssh'
|
||||||
import { SSHPortForwardingModalComponent } from './sshPortForwardingModal.component'
|
import { SSHPortForwardingModalComponent } from './sshPortForwardingModal.component'
|
||||||
@ -22,7 +21,7 @@ import { SSHMultiplexerService } from '../services/sshMultiplexer.service'
|
|||||||
],
|
],
|
||||||
animations: BaseTerminalTabComponent.animations,
|
animations: BaseTerminalTabComponent.animations,
|
||||||
})
|
})
|
||||||
export class SSHTabComponent extends BaseTerminalTabComponent<SSHProfile> implements Reconnectable {
|
export class SSHTabComponent extends ConnectableTerminalTabComponent<SSHProfile> {
|
||||||
Platform = Platform
|
Platform = Platform
|
||||||
sshSession: SSHSession|null = null
|
sshSession: SSHSession|null = null
|
||||||
session: SSHShellSession|null = null
|
session: SSHShellSession|null = null
|
||||||
@ -30,7 +29,6 @@ export class SSHTabComponent extends BaseTerminalTabComponent<SSHProfile> implem
|
|||||||
sftpPath = '/'
|
sftpPath = '/'
|
||||||
enableToolbar = true
|
enableToolbar = true
|
||||||
activeKIPrompt: KeyboardInteractivePrompt|null = null
|
activeKIPrompt: KeyboardInteractivePrompt|null = null
|
||||||
private reconnectOffered = false
|
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
injector: Injector,
|
injector: Injector,
|
||||||
@ -46,8 +44,6 @@ export class SSHTabComponent extends BaseTerminalTabComponent<SSHProfile> implem
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit (): void {
|
ngOnInit (): void {
|
||||||
this.logger = this.log.create('terminalTab')
|
|
||||||
|
|
||||||
this.subscribeUntilDestroyed(this.hotkeys.hotkey$, hotkey => {
|
this.subscribeUntilDestroyed(this.hotkeys.hotkey$, hotkey => {
|
||||||
if (!this.hasFocus) {
|
if (!this.hasFocus) {
|
||||||
return
|
return
|
||||||
@ -73,11 +69,6 @@ export class SSHTabComponent extends BaseTerminalTabComponent<SSHProfile> implem
|
|||||||
super.ngOnInit()
|
super.ngOnInit()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected onFrontendReady (): void {
|
|
||||||
this.initializeSession()
|
|
||||||
super.onFrontendReady()
|
|
||||||
}
|
|
||||||
|
|
||||||
async setupOneSession (injector: Injector, profile: SSHProfile, multiplex = true): Promise<SSHSession> {
|
async setupOneSession (injector: Injector, profile: SSHProfile, multiplex = true): Promise<SSHSession> {
|
||||||
let session = await this.sshMultiplexer.getSession(profile)
|
let session = await this.sshMultiplexer.getSession(profile)
|
||||||
if (!multiplex || !session || !profile.options.reuseSession) {
|
if (!multiplex || !session || !profile.options.reuseSession) {
|
||||||
@ -150,29 +141,13 @@ export class SSHTabComponent extends BaseTerminalTabComponent<SSHProfile> implem
|
|||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
protected attachSessionHandlers (): void {
|
protected onSessionDestroyed (): void {
|
||||||
const session = this.session!
|
if (this.frontend) {
|
||||||
this.attachSessionHandler(session.destroyed$, () => {
|
// Session was closed abruptly
|
||||||
if (this.frontend) {
|
this.write('\r\n' + colors.black.bgWhite(' SSH ') + ` ${this.sshSession?.profile.options.host}: session closed\r\n`)
|
||||||
// Session was closed abruptly
|
|
||||||
this.write('\r\n' + colors.black.bgWhite(' SSH ') + ` ${this.sshSession?.profile.options.host}: session closed\r\n`)
|
|
||||||
|
|
||||||
if (this.profile.behaviorOnSessionEnd === 'reconnect') {
|
super.onSessionDestroyed()
|
||||||
this.reconnect()
|
}
|
||||||
} else if (this.profile.behaviorOnSessionEnd === 'keep' || this.profile.behaviorOnSessionEnd === 'auto' && !this.isSessionExplicitlyTerminated()) {
|
|
||||||
if (!this.reconnectOffered) {
|
|
||||||
this.reconnectOffered = true
|
|
||||||
this.write(this.translate.instant(_('Press any key to reconnect')) + '\r\n')
|
|
||||||
this.input$.pipe(first()).subscribe(() => {
|
|
||||||
if (!this.session?.open && this.reconnectOffered) {
|
|
||||||
this.reconnect()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
super.attachSessionHandlers()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async initializeSessionMaybeMultiplex (multiplex = true): Promise<void> {
|
private async initializeSessionMaybeMultiplex (multiplex = true): Promise<void> {
|
||||||
@ -196,7 +171,7 @@ export class SSHTabComponent extends BaseTerminalTabComponent<SSHProfile> implem
|
|||||||
}
|
}
|
||||||
|
|
||||||
async initializeSession (): Promise<void> {
|
async initializeSession (): Promise<void> {
|
||||||
this.reconnectOffered = false
|
await super.initializeSession()
|
||||||
try {
|
try {
|
||||||
await this.initializeSessionMaybeMultiplex(true)
|
await this.initializeSessionMaybeMultiplex(true)
|
||||||
} catch {
|
} catch {
|
||||||
@ -209,25 +184,11 @@ export class SSHTabComponent extends BaseTerminalTabComponent<SSHProfile> implem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getRecoveryToken (options?: GetRecoveryTokenOptions): Promise<RecoveryToken> {
|
|
||||||
return {
|
|
||||||
type: 'app:ssh-tab',
|
|
||||||
profile: this.profile,
|
|
||||||
savedState: options?.includeState && this.frontend?.saveState(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
showPortForwarding (): void {
|
showPortForwarding (): void {
|
||||||
const modal = this.ngbModal.open(SSHPortForwardingModalComponent).componentInstance as SSHPortForwardingModalComponent
|
const modal = this.ngbModal.open(SSHPortForwardingModalComponent).componentInstance as SSHPortForwardingModalComponent
|
||||||
modal.session = this.sshSession!
|
modal.session = this.sshSession!
|
||||||
}
|
}
|
||||||
|
|
||||||
async reconnect (): Promise<void> {
|
|
||||||
this.session?.destroy()
|
|
||||||
await this.initializeSession()
|
|
||||||
this.session?.releaseInitialDataBuffer()
|
|
||||||
}
|
|
||||||
|
|
||||||
async canClose (): Promise<boolean> {
|
async canClose (): Promise<boolean> {
|
||||||
if (!this.session?.open) {
|
if (!this.session?.open) {
|
||||||
return true
|
return true
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'
|
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'
|
||||||
import colors from 'ansi-colors'
|
import colors from 'ansi-colors'
|
||||||
import { Component, Injector } from '@angular/core'
|
import { Component, Injector } from '@angular/core'
|
||||||
import { first } from 'rxjs'
|
import { Platform } from 'tabby-core'
|
||||||
import { GetRecoveryTokenOptions, Platform, RecoveryToken } from 'tabby-core'
|
import { BaseTerminalTabComponent, ConnectableTerminalTabComponent } from 'tabby-terminal'
|
||||||
import { BaseTerminalTabComponent, Reconnectable } from 'tabby-terminal'
|
|
||||||
import { TelnetProfile, TelnetSession } from '../session'
|
import { TelnetProfile, TelnetSession } from '../session'
|
||||||
|
|
||||||
|
|
||||||
@ -14,10 +13,9 @@ import { TelnetProfile, TelnetSession } from '../session'
|
|||||||
styleUrls: ['./telnetTab.component.scss', ...BaseTerminalTabComponent.styles],
|
styleUrls: ['./telnetTab.component.scss', ...BaseTerminalTabComponent.styles],
|
||||||
animations: BaseTerminalTabComponent.animations,
|
animations: BaseTerminalTabComponent.animations,
|
||||||
})
|
})
|
||||||
export class TelnetTabComponent extends BaseTerminalTabComponent<TelnetProfile> implements Reconnectable {
|
export class TelnetTabComponent extends ConnectableTerminalTabComponent<TelnetProfile> {
|
||||||
Platform = Platform
|
Platform = Platform
|
||||||
session: TelnetSession|null = null
|
session: TelnetSession|null = null
|
||||||
private reconnectOffered = false
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
|
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
|
||||||
constructor (
|
constructor (
|
||||||
@ -28,8 +26,6 @@ export class TelnetTabComponent extends BaseTerminalTabComponent<TelnetProfile>
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit (): void {
|
ngOnInit (): void {
|
||||||
this.logger = this.log.create('telnetTab')
|
|
||||||
|
|
||||||
this.subscribeUntilDestroyed(this.hotkeys.hotkey$, hotkey => {
|
this.subscribeUntilDestroyed(this.hotkeys.hotkey$, hotkey => {
|
||||||
if (this.hasFocus && hotkey === 'restart-telnet-session') {
|
if (this.hasFocus && hotkey === 'restart-telnet-session') {
|
||||||
this.reconnect()
|
this.reconnect()
|
||||||
@ -39,38 +35,17 @@ export class TelnetTabComponent extends BaseTerminalTabComponent<TelnetProfile>
|
|||||||
super.ngOnInit()
|
super.ngOnInit()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected onFrontendReady (): void {
|
protected onSessionDestroyed (): void {
|
||||||
this.initializeSession()
|
if (this.frontend) {
|
||||||
super.onFrontendReady()
|
// Session was closed abruptly
|
||||||
}
|
this.write('\r\n' + colors.black.bgWhite(' TELNET ') + ` ${this.session?.profile.options.host}: session closed\r\n`)
|
||||||
|
|
||||||
protected attachSessionHandlers (): void {
|
super.onSessionDestroyed()
|
||||||
const session = this.session!
|
}
|
||||||
this.attachSessionHandler(session.destroyed$, () => {
|
|
||||||
if (this.frontend) {
|
|
||||||
// Session was closed abruptly
|
|
||||||
this.write('\r\n' + colors.black.bgWhite(' TELNET ') + ` ${this.session?.profile.options.host}: session closed\r\n`)
|
|
||||||
|
|
||||||
if (this.profile.behaviorOnSessionEnd === 'reconnect') {
|
|
||||||
this.reconnect()
|
|
||||||
} else if (this.profile.behaviorOnSessionEnd === 'keep' || this.profile.behaviorOnSessionEnd === 'auto' && !this.isSessionExplicitlyTerminated()) {
|
|
||||||
if (!this.reconnectOffered) {
|
|
||||||
this.reconnectOffered = true
|
|
||||||
this.write(this.translate.instant(_('Press any key to reconnect')) + '\r\n')
|
|
||||||
this.input$.pipe(first()).subscribe(() => {
|
|
||||||
if (!this.session?.open && this.reconnectOffered) {
|
|
||||||
this.reconnect()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
super.attachSessionHandlers()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async initializeSession (): Promise<void> {
|
async initializeSession (): Promise<void> {
|
||||||
this.reconnectOffered = false
|
await super.initializeSession()
|
||||||
|
|
||||||
const session = new TelnetSession(this.injector, this.profile)
|
const session = new TelnetSession(this.injector, this.profile)
|
||||||
this.setSession(session)
|
this.setSession(session)
|
||||||
@ -96,20 +71,6 @@ export class TelnetTabComponent extends BaseTerminalTabComponent<TelnetProfile>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getRecoveryToken (options?: GetRecoveryTokenOptions): Promise<RecoveryToken> {
|
|
||||||
return {
|
|
||||||
type: 'app:telnet-tab',
|
|
||||||
profile: this.profile,
|
|
||||||
savedState: options?.includeState && this.frontend?.saveState(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async reconnect (): Promise<void> {
|
|
||||||
this.session?.destroy()
|
|
||||||
await this.initializeSession()
|
|
||||||
this.session?.releaseInitialDataBuffer()
|
|
||||||
}
|
|
||||||
|
|
||||||
async canClose (): Promise<boolean> {
|
async canClose (): Promise<boolean> {
|
||||||
if (!this.session?.open) {
|
if (!this.session?.open) {
|
||||||
return true
|
return true
|
||||||
|
@ -9,7 +9,7 @@ import { BaseSession } from '../session'
|
|||||||
|
|
||||||
import { Frontend } from '../frontends/frontend'
|
import { Frontend } from '../frontends/frontend'
|
||||||
import { XTermFrontend, XTermWebGLFrontend } from '../frontends/xtermFrontend'
|
import { XTermFrontend, XTermWebGLFrontend } from '../frontends/xtermFrontend'
|
||||||
import { ResizeEvent, BaseTerminalProfile, isReconnectable } from './interfaces'
|
import { ResizeEvent, BaseTerminalProfile } from './interfaces'
|
||||||
import { TerminalDecorator } from './decorator'
|
import { TerminalDecorator } from './decorator'
|
||||||
import { SearchPanelComponent } from '../components/searchPanel.component'
|
import { SearchPanelComponent } from '../components/searchPanel.component'
|
||||||
import { MultifocusService } from '../services/multifocus.service'
|
import { MultifocusService } from '../services/multifocus.service'
|
||||||
@ -312,11 +312,6 @@ export class BaseTerminalTabComponent<P extends BaseTerminalProfile> extends Bas
|
|||||||
case 'scroll-to-bottom':
|
case 'scroll-to-bottom':
|
||||||
this.frontend?.scrollToBottom()
|
this.frontend?.scrollToBottom()
|
||||||
break
|
break
|
||||||
case 'reconnect-tab':
|
|
||||||
if (isReconnectable(this)) {
|
|
||||||
this.reconnect()
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -784,7 +779,7 @@ export class BaseTerminalTabComponent<P extends BaseTerminalProfile> extends Bas
|
|||||||
})
|
})
|
||||||
|
|
||||||
this.attachSessionHandler(this.session.destroyed$, () => {
|
this.attachSessionHandler(this.session.destroyed$, () => {
|
||||||
this.setSession(null)
|
this.onSessionDestroyed()
|
||||||
})
|
})
|
||||||
|
|
||||||
this.attachSessionHandler(this.session.oscProcessor.copyRequested$, content => {
|
this.attachSessionHandler(this.session.oscProcessor.copyRequested$, content => {
|
||||||
@ -793,6 +788,13 @@ export class BaseTerminalTabComponent<P extends BaseTerminalProfile> extends Bas
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method called when session is destroyed. Set the session to null
|
||||||
|
*/
|
||||||
|
protected onSessionDestroyed (): void {
|
||||||
|
this.setSession(null)
|
||||||
|
}
|
||||||
|
|
||||||
protected detachSessionHandlers (): void {
|
protected detachSessionHandlers (): void {
|
||||||
this.sessionHandlers.cancelAll()
|
this.sessionHandlers.cancelAll()
|
||||||
}
|
}
|
||||||
|
94
tabby-terminal/src/api/connectableTerminalTab.component.ts
Normal file
94
tabby-terminal/src/api/connectableTerminalTab.component.ts
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'
|
||||||
|
|
||||||
|
import { Injector, Component } from '@angular/core'
|
||||||
|
|
||||||
|
import { first } from 'rxjs'
|
||||||
|
|
||||||
|
import { BaseTerminalProfile } from './interfaces'
|
||||||
|
import { BaseTerminalTabComponent } from './baseTerminalTab.component'
|
||||||
|
import { GetRecoveryTokenOptions, RecoveryToken } from 'tabby-core'
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class to base your custom connectable terminal tabs on
|
||||||
|
*/
|
||||||
|
@Component({ template: '' })
|
||||||
|
export abstract class ConnectableTerminalTabComponent<P extends BaseTerminalProfile> extends BaseTerminalTabComponent<P> {
|
||||||
|
|
||||||
|
protected reconnectOffered = false
|
||||||
|
|
||||||
|
constructor (protected injector: Injector) {
|
||||||
|
super(injector)
|
||||||
|
|
||||||
|
this.subscribeUntilDestroyed(this.hotkeys.hotkey$, hotkey => {
|
||||||
|
if (this.hasFocus && hotkey === 'reconnect-tab') {
|
||||||
|
this.reconnect()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit (): void {
|
||||||
|
this.logger = this.log.create(`${this.profile.type}Tab`)
|
||||||
|
|
||||||
|
super.ngOnInit()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected onFrontendReady (): void {
|
||||||
|
this.initializeSession()
|
||||||
|
super.onFrontendReady()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize Connectable Session.
|
||||||
|
* Set reconnectOffered to false
|
||||||
|
*/
|
||||||
|
async initializeSession (): Promise<void> {
|
||||||
|
this.reconnectOffered = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method called when session is destroyed. Handle the tab behavior on session end for connectable tab
|
||||||
|
*/
|
||||||
|
protected onSessionDestroyed (): void {
|
||||||
|
super.onSessionDestroyed()
|
||||||
|
|
||||||
|
if (this.frontend) {
|
||||||
|
if (this.profile.behaviorOnSessionEnd === 'reconnect') {
|
||||||
|
this.reconnect()
|
||||||
|
} else if (this.profile.behaviorOnSessionEnd === 'keep' || this.profile.behaviorOnSessionEnd === 'auto' && !this.isSessionExplicitlyTerminated()) {
|
||||||
|
this.offerReconnection()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offering reconnection to the user if it hasn't been done yet.
|
||||||
|
* Set reconnectOffered to true
|
||||||
|
*/
|
||||||
|
offerReconnection (): void {
|
||||||
|
if (!this.reconnectOffered) {
|
||||||
|
this.reconnectOffered = true
|
||||||
|
this.write(this.translate.instant(_('Press any key to reconnect')) + '\r\n')
|
||||||
|
this.input$.pipe(first()).subscribe(() => {
|
||||||
|
if (!this.session?.open && this.reconnectOffered) {
|
||||||
|
this.reconnect()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRecoveryToken (options?: GetRecoveryTokenOptions): Promise<RecoveryToken> {
|
||||||
|
return {
|
||||||
|
type: `app:${this.profile.type}-tab`,
|
||||||
|
profile: this.profile,
|
||||||
|
savedState: options?.includeState && this.frontend?.saveState(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async reconnect (): Promise<void> {
|
||||||
|
this.session?.destroy()
|
||||||
|
await this.initializeSession()
|
||||||
|
this.session?.releaseInitialDataBuffer()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -19,12 +19,3 @@ export interface TerminalColorScheme {
|
|||||||
export interface BaseTerminalProfile extends Profile {
|
export interface BaseTerminalProfile extends Profile {
|
||||||
terminalColorScheme?: TerminalColorScheme
|
terminalColorScheme?: TerminalColorScheme
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Reconnectable {
|
|
||||||
reconnect: () => Promise<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
||||||
export function isReconnectable (object: any): object is Reconnectable {
|
|
||||||
return 'reconnect' in object
|
|
||||||
}
|
|
||||||
|
@ -90,6 +90,7 @@ export default class TerminalModule { } // eslint-disable-line @typescript-eslin
|
|||||||
export { TerminalDecorator, TerminalContextMenuItemProvider, TerminalColorSchemeProvider }
|
export { TerminalDecorator, TerminalContextMenuItemProvider, TerminalColorSchemeProvider }
|
||||||
export { Frontend, XTermFrontend, XTermWebGLFrontend }
|
export { Frontend, XTermFrontend, XTermWebGLFrontend }
|
||||||
export { BaseTerminalTabComponent } from './api/baseTerminalTab.component'
|
export { BaseTerminalTabComponent } from './api/baseTerminalTab.component'
|
||||||
|
export { ConnectableTerminalTabComponent } from './api/connectableTerminalTab.component'
|
||||||
export * from './api/interfaces'
|
export * from './api/interfaces'
|
||||||
export * from './middleware/streamProcessing'
|
export * from './middleware/streamProcessing'
|
||||||
export * from './middleware/loginScriptProcessing'
|
export * from './middleware/loginScriptProcessing'
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { Injectable, Optional, Inject } from '@angular/core'
|
import { Injectable, Optional, Inject } from '@angular/core'
|
||||||
import { BaseTabComponent, TabContextMenuItemProvider, NotificationsService, MenuItemOptions, TranslateService, SplitTabComponent } from 'tabby-core'
|
import { BaseTabComponent, TabContextMenuItemProvider, NotificationsService, MenuItemOptions, TranslateService, SplitTabComponent } from 'tabby-core'
|
||||||
import { BaseTerminalTabComponent } from './api/baseTerminalTab.component'
|
import { BaseTerminalTabComponent } from './api/baseTerminalTab.component'
|
||||||
import { isReconnectable } from './api/interfaces'
|
|
||||||
import { TerminalContextMenuItemProvider } from './api/contextMenuProvider'
|
import { TerminalContextMenuItemProvider } from './api/contextMenuProvider'
|
||||||
import { MultifocusService } from './services/multifocus.service'
|
import { MultifocusService } from './services/multifocus.service'
|
||||||
|
import { ConnectableTerminalTabComponent } from './api/connectableTerminalTab.component'
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -97,7 +97,7 @@ export class ReconnectContextMenu extends TabContextMenuItemProvider {
|
|||||||
) { super() }
|
) { super() }
|
||||||
|
|
||||||
async getItems (tab: BaseTabComponent): Promise<MenuItemOptions[]> {
|
async getItems (tab: BaseTabComponent): Promise<MenuItemOptions[]> {
|
||||||
if (isReconnectable(tab)) {
|
if (tab instanceof ConnectableTerminalTabComponent) {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
label: this.translate.instant('Reconnect'),
|
label: this.translate.instant('Reconnect'),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user