diff --git a/tabby-core/src/api/index.ts b/tabby-core/src/api/index.ts index 5c9c0ce6..5ca9b636 100644 --- a/tabby-core/src/api/index.ts +++ b/tabby-core/src/api/index.ts @@ -16,7 +16,7 @@ export { BootstrapData, PluginInfo, BOOTSTRAP_DATA } from './mainProcess' export { HostWindowService } from './hostWindow' export { HostAppService, Platform } from './hostApp' export { FileProvider } from './fileProvider' -export { ProfileProvider, Profile, PartialProfile, ProfileSettingsComponent, ProfileGroup, PartialProfileGroup } from './profileProvider' +export { ProfileProvider, ConnectableProfileProvider, Profile, ConnectableProfile, PartialProfile, ProfileSettingsComponent, ProfileGroup, PartialProfileGroup } from './profileProvider' export { PromptModalComponent } from '../components/promptModal.component' export * from './commands' diff --git a/tabby-core/src/api/profileProvider.ts b/tabby-core/src/api/profileProvider.ts index fbbf1f5d..01c7b759 100644 --- a/tabby-core/src/api/profileProvider.ts +++ b/tabby-core/src/api/profileProvider.ts @@ -21,6 +21,10 @@ export interface Profile { isTemplate: boolean } +export interface ConnectableProfile extends Profile { + clearServiceMessagesOnConnect: boolean +} + export type PartialProfile = Omit, 'type'>, 'name'> & { @@ -54,7 +58,6 @@ export interface ProfileSettingsComponent

{ export abstract class ProfileProvider

{ id: string name: string - supportsQuickConnect = false settingsComponent?: new (...args: any[]) => ProfileSettingsComponent

configDefaults = {} @@ -68,6 +71,11 @@ export abstract class ProfileProvider

{ abstract getDescription (profile: PartialProfile

): string + deleteProfile (profile: P): void { } +} + +export abstract class ConnectableProfileProvider

extends ProfileProvider

{ + quickConnect (query: string): PartialProfile

|null { return null } @@ -76,5 +84,4 @@ export abstract class ProfileProvider

{ return null } - deleteProfile (profile: P): void { } } diff --git a/tabby-core/src/index.ts b/tabby-core/src/index.ts index fc08aea4..ebe1fc44 100644 --- a/tabby-core/src/index.ts +++ b/tabby-core/src/index.ts @@ -37,7 +37,7 @@ import { FastHtmlBindDirective } from './directives/fastHtmlBind.directive' import { DropZoneDirective } from './directives/dropZone.directive' import { CdkAutoDropGroup } from './directives/cdkAutoDropGroup.directive' -import { Theme, CLIHandler, TabContextMenuItemProvider, TabRecoveryProvider, HotkeyProvider, ConfigProvider, PlatformService, FileProvider, ProfilesService, ProfileProvider, SelectorOption, Profile, SelectorService, CommandProvider } from './api' +import { Theme, CLIHandler, TabContextMenuItemProvider, TabRecoveryProvider, HotkeyProvider, ConfigProvider, PlatformService, FileProvider, ProfilesService, ProfileProvider, ConnectableProfileProvider, SelectorOption, Profile, SelectorService, CommandProvider } from './api' import { AppService } from './services/app.service' import { ConfigService } from './services/config.service' @@ -214,7 +214,7 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex callback: () => this.profilesService.openNewTabForProfile(p), })) - if (provider.supportsQuickConnect) { + if (provider instanceof ConnectableProfileProvider) { options.push({ name: this.translate.instant('Quick connect'), freeInputPattern: this.translate.instant('Connect to "%s"...'), diff --git a/tabby-core/src/services/config.service.ts b/tabby-core/src/services/config.service.ts index 1bc60a46..4b91fefa 100644 --- a/tabby-core/src/services/config.service.ts +++ b/tabby-core/src/services/config.service.ts @@ -397,6 +397,13 @@ export class ConfigService { config.groups = groups config.version = 5 } + if (config.version < 6) { + if (config.ssh.clearServiceMessagesOnConnect === false) { + config.profileDefaults.ssh.clearServiceMessagesOnConnect = false + delete config.ssh?.clearServiceMessagesOnConnect + } + config.version = 6 + } } private async maybeDecryptConfig (store) { diff --git a/tabby-core/src/services/profiles.service.ts b/tabby-core/src/services/profiles.service.ts index 329fc4fe..f0616a26 100644 --- a/tabby-core/src/services/profiles.service.ts +++ b/tabby-core/src/services/profiles.service.ts @@ -2,7 +2,7 @@ import { Injectable, Inject } from '@angular/core' import { TranslateService } from '@ngx-translate/core' import { NewTabParameters } from './tabs.service' import { BaseTabComponent } from '../components/baseTab.component' -import { PartialProfile, PartialProfileGroup, Profile, ProfileGroup, ProfileProvider } from '../api/profileProvider' +import { ConnectableProfileProvider, PartialProfile, PartialProfileGroup, Profile, ProfileGroup, ProfileProvider } from '../api/profileProvider' import { SelectorOption } from '../api/selector' import { AppService } from './app.service' import { configMerge, ConfigProxy, ConfigService } from './config.service' @@ -230,7 +230,7 @@ export class ProfilesService { selectorOptionForProfile

(profile: PartialProfile

): SelectorOption { const fullProfile = this.getConfigProxyForProfile(profile) const provider = this.providerForProfile(fullProfile) - const freeInputEquivalent = provider?.intoQuickConnectString(fullProfile) ?? undefined + const freeInputEquivalent = provider instanceof ConnectableProfileProvider ? provider.intoQuickConnectString(fullProfile) ?? undefined : undefined return { ...profile, group: this.resolveProfileGroupName(profile.group ?? ''), @@ -307,18 +307,20 @@ export class ProfilesService { }) } catch { } - this.getProviders().filter(x => x.supportsQuickConnect).forEach(provider => { - options.push({ - name: this.translate.instant('Quick connect'), - freeInputPattern: this.translate.instant('Connect to "%s"...'), - description: `(${provider.name.toUpperCase()})`, - icon: 'fas fa-arrow-right', - weight: provider.id !== this.config.store.defaultQuickConnectProvider ? 1 : 0, - callback: query => { - const profile = provider.quickConnect(query) - resolve(profile) - }, - }) + this.getProviders().forEach(provider => { + if (provider instanceof ConnectableProfileProvider) { + options.push({ + name: this.translate.instant('Quick connect'), + freeInputPattern: this.translate.instant('Connect to "%s"...'), + description: `(${provider.name.toUpperCase()})`, + icon: 'fas fa-arrow-right', + weight: provider.id !== this.config.store.defaultQuickConnectProvider ? 1 : 0, + callback: query => { + const profile = provider.quickConnect(query) + resolve(profile) + }, + }) + } }) await this.selector.show(this.translate.instant('Select profile or enter an address'), options) @@ -336,7 +338,7 @@ export class ProfilesService { async quickConnect (query: string): Promise|null> { for (const provider of this.getProviders()) { - if (provider.supportsQuickConnect) { + if (provider instanceof ConnectableProfileProvider) { const profile = provider.quickConnect(query) if (profile) { return profile diff --git a/tabby-serial/src/api.ts b/tabby-serial/src/api.ts index 64d46e68..bc9d741c 100644 --- a/tabby-serial/src/api.ts +++ b/tabby-serial/src/api.ts @@ -3,10 +3,10 @@ import { SerialPortStream } from '@serialport/stream' import { LogService, NotificationsService } from 'tabby-core' import { Subject, Observable } from 'rxjs' import { Injector, NgZone } from '@angular/core' -import { BaseSession, BaseTerminalProfile, InputProcessingOptions, InputProcessor, LoginScriptsOptions, SessionMiddleware, StreamProcessingOptions, TerminalStreamProcessor, UTF8SplitterMiddleware } from 'tabby-terminal' +import { BaseSession, ConnectableTerminalProfile, InputProcessingOptions, InputProcessor, LoginScriptsOptions, SessionMiddleware, StreamProcessingOptions, TerminalStreamProcessor, UTF8SplitterMiddleware } from 'tabby-terminal' import { SerialService } from './services/serial.service' -export interface SerialProfile extends BaseTerminalProfile { +export interface SerialProfile extends ConnectableTerminalProfile { options: SerialProfileOptions } diff --git a/tabby-serial/src/profiles.ts b/tabby-serial/src/profiles.ts index c6c5d5bf..36f975fc 100644 --- a/tabby-serial/src/profiles.ts +++ b/tabby-serial/src/profiles.ts @@ -2,14 +2,14 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker' import slugify from 'slugify' import deepClone from 'clone-deep' import { Injectable } from '@angular/core' -import { ProfileProvider, NewTabParameters, SelectorService, HostAppService, Platform, TranslateService } from 'tabby-core' +import { NewTabParameters, SelectorService, HostAppService, Platform, TranslateService, ConnectableProfileProvider } from 'tabby-core' import { SerialProfileSettingsComponent } from './components/serialProfileSettings.component' import { SerialTabComponent } from './components/serialTab.component' import { SerialService } from './services/serial.service' import { BAUD_RATES, SerialProfile } from './api' @Injectable({ providedIn: 'root' }) -export class SerialProfilesService extends ProfileProvider { +export class SerialProfilesService extends ConnectableProfileProvider { id = 'serial' name = _('Serial') settingsComponent = SerialProfileSettingsComponent @@ -32,6 +32,7 @@ export class SerialProfilesService extends ProfileProvider { slowSend: false, input: { backspace: 'backspace' }, }, + clearServiceMessagesOnConnect: false, } constructor ( diff --git a/tabby-settings/src/components/editProfileModal.component.pug b/tabby-settings/src/components/editProfileModal.component.pug index 10d7fea2..7b971bcd 100644 --- a/tabby-settings/src/components/editProfileModal.component.pug +++ b/tabby-settings/src/components/editProfileModal.component.pug @@ -77,9 +77,15 @@ ) option(ngValue='auto', translate) Auto option(ngValue='keep', translate) Keep - option(*ngIf='profile.type == "serial" || profile.type == "telnet" || profile.type == "ssh"', ngValue='reconnect', translate) Reconnect + option(*ngIf='isConnectable()', ngValue='reconnect', translate) Reconnect option(ngValue='close', translate) Close - + + .form-line(*ngIf='isConnectable()') + .header + .title(translate) Clear terminal after connection + toggle( + [(ngModel)]='profile.clearServiceMessagesOnConnect', + ) .mb-4 .col-12.col-lg-8(*ngIf='this.profileProvider.settingsComponent') diff --git a/tabby-settings/src/components/editProfileModal.component.ts b/tabby-settings/src/components/editProfileModal.component.ts index a3dea3a0..f1ac1c1e 100644 --- a/tabby-settings/src/components/editProfileModal.component.ts +++ b/tabby-settings/src/components/editProfileModal.component.ts @@ -2,7 +2,7 @@ import { Observable, OperatorFunction, debounceTime, map, distinctUntilChanged } from 'rxjs' import { Component, Input, ViewChild, ViewContainerRef, ComponentFactoryResolver, Injector } from '@angular/core' import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' -import { ConfigProxy, PartialProfileGroup, Profile, ProfileProvider, ProfileSettingsComponent, ProfilesService, TAB_COLORS, ProfileGroup } from 'tabby-core' +import { ConfigProxy, PartialProfileGroup, Profile, ProfileProvider, ProfileSettingsComponent, ProfilesService, TAB_COLORS, ProfileGroup, ConnectableProfileProvider } from 'tabby-core' const iconsData = require('../../../tabby-core/src/icons.json') const iconsClassList = Object.keys(iconsData).map( @@ -103,4 +103,9 @@ export class EditProfileModalComponent

{ cancel () { this.modalInstance.dismiss() } + + isConnectable (): boolean { + return this.profileProvider instanceof ConnectableProfileProvider + } + } diff --git a/tabby-settings/src/components/profilesSettingsTab.component.ts b/tabby-settings/src/components/profilesSettingsTab.component.ts index 7a0b537d..41fb3e27 100644 --- a/tabby-settings/src/components/profilesSettingsTab.component.ts +++ b/tabby-settings/src/components/profilesSettingsTab.component.ts @@ -2,7 +2,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker' import deepClone from 'clone-deep' import { Component, Inject } from '@angular/core' import { NgbModal } from '@ng-bootstrap/ng-bootstrap' -import { ConfigService, HostAppService, Profile, SelectorService, ProfilesService, PromptModalComponent, PlatformService, BaseComponent, PartialProfile, ProfileProvider, TranslateService, Platform, ProfileGroup, PartialProfileGroup } from 'tabby-core' +import { ConfigService, HostAppService, Profile, SelectorService, ProfilesService, PromptModalComponent, PlatformService, BaseComponent, PartialProfile, ProfileProvider, TranslateService, Platform, ProfileGroup, PartialProfileGroup, ConnectableProfileProvider } from 'tabby-core' import { EditProfileModalComponent } from './editProfileModal.component' import { EditProfileGroupModalComponent, EditProfileGroupModalComponentResult } from './editProfileGroupModal.component' @@ -341,7 +341,7 @@ export class ProfilesSettingsTabComponent extends BaseComponent { } getQuickConnectProviders (): ProfileProvider[] { - return this.profileProviders.filter(x => x.supportsQuickConnect) + return this.profileProviders.filter(x => x instanceof ConnectableProfileProvider) } /** diff --git a/tabby-ssh/src/api/interfaces.ts b/tabby-ssh/src/api/interfaces.ts index 901d5dd1..07a77a5c 100644 --- a/tabby-ssh/src/api/interfaces.ts +++ b/tabby-ssh/src/api/interfaces.ts @@ -1,4 +1,4 @@ -import { BaseTerminalProfile, InputProcessingOptions, LoginScriptsOptions } from 'tabby-terminal' +import { ConnectableTerminalProfile, InputProcessingOptions, LoginScriptsOptions } from 'tabby-terminal' export enum SSHAlgorithmType { HMAC = 'hmac', @@ -7,7 +7,7 @@ export enum SSHAlgorithmType { HOSTKEY = 'serverHostKey', } -export interface SSHProfile extends BaseTerminalProfile { +export interface SSHProfile extends ConnectableTerminalProfile { options: SSHProfileOptions } diff --git a/tabby-ssh/src/components/sshSettingsTab.component.pug b/tabby-ssh/src/components/sshSettingsTab.component.pug index 2ff88f71..fd50f44f 100644 --- a/tabby-ssh/src/components/sshSettingsTab.component.pug +++ b/tabby-ssh/src/components/sshSettingsTab.component.pug @@ -61,12 +61,4 @@ h3 SSH (ngModelChange)='config.save()' ) -.form-line - .header - .title(translate) Clear terminal after connection - toggle( - [(ngModel)]='config.store.ssh.clearServiceMessagesOnConnect', - (ngModelChange)='config.save()', - ) - .alert.alert-info(translate) SSH connection management is now done through the "Profiles & connections" tab diff --git a/tabby-ssh/src/components/sshTab.component.ts b/tabby-ssh/src/components/sshTab.component.ts index b6c6d3eb..738862dd 100644 --- a/tabby-ssh/src/components/sshTab.component.ts +++ b/tabby-ssh/src/components/sshTab.component.ts @@ -83,7 +83,7 @@ export class SSHTabComponent extends ConnectableTerminalTabComponent const jumpSession = await this.setupOneSession( this.injector, - this.profilesService.getConfigProxyForProfile(jumpConnection), + this.profilesService.getConfigProxyForProfile(jumpConnection), ) jumpSession.ref() @@ -163,10 +163,6 @@ export class SSHTabComponent extends ConnectableTerminalTabComponent await session.start() - if (this.config.store.ssh.clearServiceMessagesOnConnect) { - this.frontend?.clear() - } - this.session?.resize(this.size.columns, this.size.rows) } diff --git a/tabby-ssh/src/config.ts b/tabby-ssh/src/config.ts index 82a35cdc..8c32ba89 100644 --- a/tabby-ssh/src/config.ts +++ b/tabby-ssh/src/config.ts @@ -11,7 +11,6 @@ export class SSHConfigProvider extends ConfigProvider { x11Display: null, knownHosts: [], verifyHostKeys: true, - clearServiceMessagesOnConnect: true, }, hotkeys: { 'restart-ssh-session': [], diff --git a/tabby-ssh/src/profiles.ts b/tabby-ssh/src/profiles.ts index 0952e713..64610e03 100644 --- a/tabby-ssh/src/profiles.ts +++ b/tabby-ssh/src/profiles.ts @@ -1,5 +1,5 @@ import { Injectable, InjectFlags, Injector } from '@angular/core' -import { ProfileProvider, NewTabParameters, PartialProfile, TranslateService } from 'tabby-core' +import { NewTabParameters, PartialProfile, TranslateService, ConnectableProfileProvider } from 'tabby-core' import * as ALGORITHMS from 'ssh2/lib/protocol/constants' import { SSHProfileSettingsComponent } from './components/sshProfileSettings.component' import { SSHTabComponent } from './components/sshTab.component' @@ -8,10 +8,9 @@ import { ALGORITHM_BLACKLIST, SSHAlgorithmType, SSHProfile } from './api' import { SSHProfileImporter } from './api/importer' @Injectable({ providedIn: 'root' }) -export class SSHProfilesService extends ProfileProvider { +export class SSHProfilesService extends ConnectableProfileProvider { id = 'ssh' name = 'SSH' - supportsQuickConnect = true settingsComponent = SSHProfileSettingsComponent configDefaults = { options: { @@ -45,6 +44,7 @@ export class SSHProfilesService extends ProfileProvider { reuseSession: true, input: { backspace: 'backspace' }, }, + clearServiceMessagesOnConnect: true, } constructor ( diff --git a/tabby-ssh/src/services/sshMultiplexer.service.ts b/tabby-ssh/src/services/sshMultiplexer.service.ts index 2665187e..775e20fa 100644 --- a/tabby-ssh/src/services/sshMultiplexer.service.ts +++ b/tabby-ssh/src/services/sshMultiplexer.service.ts @@ -34,7 +34,7 @@ export class SSHMultiplexerService { if (!jumpConnection) { return key } - const jumpProfile = this.profilesService.getConfigProxyForProfile(jumpConnection) + const jumpProfile = this.profilesService.getConfigProxyForProfile(jumpConnection) key += '$' + await this.getMultiplexerKey(jumpProfile) } return key diff --git a/tabby-telnet/src/profiles.ts b/tabby-telnet/src/profiles.ts index fad4f8ce..0c247e8a 100644 --- a/tabby-telnet/src/profiles.ts +++ b/tabby-telnet/src/profiles.ts @@ -1,11 +1,11 @@ import { Injectable } from '@angular/core' -import { ProfileProvider, NewTabParameters, PartialProfile, TranslateService } from 'tabby-core' +import { NewTabParameters, PartialProfile, TranslateService, ConnectableProfileProvider } from 'tabby-core' import { TelnetProfileSettingsComponent } from './components/telnetProfileSettings.component' import { TelnetTabComponent } from './components/telnetTab.component' import { TelnetProfile } from './session' @Injectable({ providedIn: 'root' }) -export class TelnetProfilesService extends ProfileProvider { +export class TelnetProfilesService extends ConnectableProfileProvider { id = 'telnet' name = 'Telnet' supportsQuickConnect = true @@ -21,6 +21,7 @@ export class TelnetProfilesService extends ProfileProvider { scripts: [], input: { backspace: 'backspace' }, }, + clearServiceMessagesOnConnect: false, } constructor (private translate: TranslateService) { super() } diff --git a/tabby-telnet/src/session.ts b/tabby-telnet/src/session.ts index 27c2cc27..1200d1c3 100644 --- a/tabby-telnet/src/session.ts +++ b/tabby-telnet/src/session.ts @@ -3,11 +3,11 @@ import colors from 'ansi-colors' import stripAnsi from 'strip-ansi' import { Injector } from '@angular/core' import { LogService } from 'tabby-core' -import { BaseSession, BaseTerminalProfile, InputProcessingOptions, InputProcessor, LoginScriptsOptions, SessionMiddleware, StreamProcessingOptions, TerminalStreamProcessor } from 'tabby-terminal' +import { BaseSession, ConnectableTerminalProfile, InputProcessingOptions, InputProcessor, LoginScriptsOptions, SessionMiddleware, StreamProcessingOptions, TerminalStreamProcessor } from 'tabby-terminal' import { Subject, Observable } from 'rxjs' -export interface TelnetProfile extends BaseTerminalProfile { +export interface TelnetProfile extends ConnectableTerminalProfile { options: TelnetProfileOptions } diff --git a/tabby-terminal/src/api/connectableTerminalTab.component.ts b/tabby-terminal/src/api/connectableTerminalTab.component.ts index 97560ec1..cefd3e71 100644 --- a/tabby-terminal/src/api/connectableTerminalTab.component.ts +++ b/tabby-terminal/src/api/connectableTerminalTab.component.ts @@ -4,7 +4,7 @@ import { Injector, Component } from '@angular/core' import { first } from 'rxjs' -import { BaseTerminalProfile } from './interfaces' +import { ConnectableTerminalProfile } from './interfaces' import { BaseTerminalTabComponent } from './baseTerminalTab.component' import { GetRecoveryTokenOptions, RecoveryToken } from 'tabby-core' @@ -13,7 +13,7 @@ import { GetRecoveryTokenOptions, RecoveryToken } from 'tabby-core' * A class to base your custom connectable terminal tabs on */ @Component({ template: '' }) -export abstract class ConnectableTerminalTabComponent

extends BaseTerminalTabComponent

{ +export abstract class ConnectableTerminalTabComponent

extends BaseTerminalTabComponent

{ protected reconnectOffered = false protected isDisconnectedByHand = false @@ -57,6 +57,9 @@ export abstract class ConnectableTerminalTabComponent

{ this.reconnectOffered = false this.isDisconnectedByHand = false + if (this.profile.clearServiceMessagesOnConnect) { + this.frontend?.clear() + } } /** diff --git a/tabby-terminal/src/api/interfaces.ts b/tabby-terminal/src/api/interfaces.ts index 74143339..eb61a8f1 100644 --- a/tabby-terminal/src/api/interfaces.ts +++ b/tabby-terminal/src/api/interfaces.ts @@ -1,4 +1,4 @@ -import { Profile } from 'tabby-core' +import { ConnectableProfile, Profile } from 'tabby-core' export interface ResizeEvent { columns: number @@ -19,3 +19,5 @@ export interface TerminalColorScheme { export interface BaseTerminalProfile extends Profile { terminalColorScheme?: TerminalColorScheme } + +export interface ConnectableTerminalProfile extends BaseTerminalProfile, ConnectableProfile {}