mirror of
https://github.com/Eugeny/tabby
synced 2024-12-13 14:52:45 +00:00
added a winscp hotkey - fixes #2938
This commit is contained in:
parent
03bf6e5302
commit
c2ca127574
6 changed files with 79 additions and 77 deletions
|
@ -62,6 +62,11 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
|||
case 'restart-ssh-session':
|
||||
this.reconnect()
|
||||
break
|
||||
case 'launch-winscp':
|
||||
if (this.session) {
|
||||
this.ssh.launchWinSCP(this.session)
|
||||
}
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -13,6 +13,10 @@ export class SSHHotkeyProvider extends HotkeyProvider {
|
|||
id: 'restart-ssh-session',
|
||||
name: 'Restart current SSH session',
|
||||
},
|
||||
{
|
||||
id: 'launch-winscp',
|
||||
name: 'Launch WinSCP for current SSH session',
|
||||
},
|
||||
]
|
||||
|
||||
async provide (): Promise<HotkeyDescription[]> {
|
||||
|
|
|
@ -19,7 +19,7 @@ import { SSHConfigProvider } from './config'
|
|||
import { SSHSettingsTabProvider } from './settings'
|
||||
import { RecoveryProvider } from './recoveryProvider'
|
||||
import { SSHHotkeyProvider } from './hotkeys'
|
||||
import { WinSCPContextMenu } from './winSCPIntegration'
|
||||
import { WinSCPContextMenu } from './tabContextMenu'
|
||||
import { SSHCLIHandler } from './cli'
|
||||
|
||||
/** @hidden */
|
||||
|
|
|
@ -5,7 +5,7 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
|||
import { Client } from 'ssh2'
|
||||
import { exec } from 'child_process'
|
||||
import { Subject, Observable } from 'rxjs'
|
||||
import { Logger, LogService, AppService, SelectorOption, ConfigService, NotificationsService } from 'terminus-core'
|
||||
import { Logger, LogService, AppService, SelectorOption, ConfigService, NotificationsService, HostAppService, Platform, PlatformService } from 'terminus-core'
|
||||
import { SettingsTabComponent } from 'terminus-settings'
|
||||
import { ALGORITHM_BLACKLIST, ForwardedPort, SSHConnection, SSHSession } from '../api'
|
||||
import { PromptModalComponent } from '../components/promptModal.component'
|
||||
|
@ -16,6 +16,7 @@ import { ChildProcess } from 'node:child_process'
|
|||
@Injectable({ providedIn: 'root' })
|
||||
export class SSHService {
|
||||
private logger: Logger
|
||||
private detectedWinSCPPath: string | null
|
||||
|
||||
private constructor (
|
||||
private injector: Injector,
|
||||
|
@ -26,8 +27,13 @@ export class SSHService {
|
|||
private notifications: NotificationsService,
|
||||
private app: AppService,
|
||||
private config: ConfigService,
|
||||
hostApp: HostAppService,
|
||||
private platform: PlatformService,
|
||||
) {
|
||||
this.logger = log.create('ssh')
|
||||
if (hostApp.platform === Platform.Windows) {
|
||||
this.detectedWinSCPPath = platform.getWinSCPPath()
|
||||
}
|
||||
}
|
||||
|
||||
createSession (connection: SSHConnection): SSHSession {
|
||||
|
@ -277,6 +283,33 @@ export class SSHService {
|
|||
this.config.save()
|
||||
return this.connect(connection)
|
||||
}
|
||||
|
||||
getWinSCPPath (): string|undefined {
|
||||
return this.detectedWinSCPPath ?? this.config.store.ssh.winSCPPath
|
||||
}
|
||||
|
||||
async getWinSCPURI (connection: SSHConnection): Promise<string> {
|
||||
let uri = `scp://${connection.user}`
|
||||
const password = await this.passwordStorage.loadPassword(connection)
|
||||
if (password) {
|
||||
uri += ':' + encodeURIComponent(password)
|
||||
}
|
||||
uri += `@${connection.host}:${connection.port}/`
|
||||
return uri
|
||||
}
|
||||
|
||||
async launchWinSCP (session: SSHSession): Promise<void> {
|
||||
const path = this.getWinSCPPath()
|
||||
if (!path) {
|
||||
return
|
||||
}
|
||||
const args = [await this.getWinSCPURI(session.connection)]
|
||||
if (session.activePrivateKey) {
|
||||
args.push('/privatekey')
|
||||
args.push(session.activePrivateKey)
|
||||
}
|
||||
this.platform.exec(path, args)
|
||||
}
|
||||
}
|
||||
|
||||
export class ProxyCommandStream extends Duplex {
|
||||
|
|
35
terminus-ssh/src/tabContextMenu.ts
Normal file
35
terminus-ssh/src/tabContextMenu.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
import { Injectable } from '@angular/core'
|
||||
import { BaseTabComponent, TabContextMenuItemProvider, TabHeaderComponent, HostAppService, Platform, MenuItemOptions } from 'terminus-core'
|
||||
import { SSHTabComponent } from './components/sshTab.component'
|
||||
import { SSHService } from './services/ssh.service'
|
||||
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class WinSCPContextMenu extends TabContextMenuItemProvider {
|
||||
weight = 10
|
||||
|
||||
constructor (
|
||||
private hostApp: HostAppService,
|
||||
private ssh: SSHService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<MenuItemOptions[]> {
|
||||
if (!(tab instanceof SSHTabComponent) || !tab.connection) {
|
||||
return []
|
||||
}
|
||||
if (this.hostApp.platform !== Platform.Windows || tabHeader || !this.ssh.getWinSCPPath()) {
|
||||
return []
|
||||
}
|
||||
return [
|
||||
{
|
||||
label: 'Launch WinSCP',
|
||||
click: (): void => {
|
||||
this.ssh.launchWinSCP(tab.session!)
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
import { Injectable } from '@angular/core'
|
||||
import { ConfigService, BaseTabComponent, TabContextMenuItemProvider, TabHeaderComponent, HostAppService, Platform, PlatformService, MenuItemOptions } from 'terminus-core'
|
||||
import { SSHTabComponent } from './components/sshTab.component'
|
||||
import { PasswordStorageService } from './services/passwordStorage.service'
|
||||
import { SSHConnection, SSHSession } from './api'
|
||||
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class WinSCPContextMenu extends TabContextMenuItemProvider {
|
||||
weight = 10
|
||||
private detectedPath: string | null
|
||||
|
||||
constructor (
|
||||
private hostApp: HostAppService,
|
||||
private config: ConfigService,
|
||||
private platform: PlatformService,
|
||||
private passwordStorage: PasswordStorageService,
|
||||
) {
|
||||
super()
|
||||
|
||||
if (hostApp.platform !== Platform.Windows) {
|
||||
return
|
||||
}
|
||||
|
||||
this.detectedPath = platform.getWinSCPPath()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<MenuItemOptions[]> {
|
||||
if (this.hostApp.platform !== Platform.Windows || tabHeader) {
|
||||
return []
|
||||
}
|
||||
if (!this.getPath()) {
|
||||
return []
|
||||
}
|
||||
if (!(tab instanceof SSHTabComponent) || !tab.connection) {
|
||||
return []
|
||||
}
|
||||
return [
|
||||
{
|
||||
label: 'Launch WinSCP',
|
||||
click: (): void => {
|
||||
this.launchWinSCP(tab.session!)
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
getPath (): string|undefined {
|
||||
return this.detectedPath ?? this.config.store.ssh.winSCPPath
|
||||
}
|
||||
|
||||
async getURI (connection: SSHConnection): Promise<string> {
|
||||
let uri = `scp://${connection.user}`
|
||||
const password = await this.passwordStorage.loadPassword(connection)
|
||||
if (password) {
|
||||
uri += ':' + encodeURIComponent(password)
|
||||
}
|
||||
uri += `@${connection.host}:${connection.port}/`
|
||||
return uri
|
||||
}
|
||||
|
||||
async launchWinSCP (session: SSHSession): Promise<void> {
|
||||
const path = this.getPath()
|
||||
if (!path) {
|
||||
return
|
||||
}
|
||||
const args = [await this.getURI(session.connection)]
|
||||
if (session.activePrivateKey) {
|
||||
args.push('/privatekey')
|
||||
args.push(session.activePrivateKey)
|
||||
}
|
||||
this.platform.exec(path, args)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue