mirror of
https://github.com/Eugeny/tabby.git
synced 2025-07-04 18:39:54 +00:00
WinSCP integration
This commit is contained in:
parent
32b29a91e9
commit
62b53575ac
@ -36,3 +36,14 @@ h3.mt-5 Options
|
|||||||
[(ngModel)]='config.store.ssh.warnOnClose',
|
[(ngModel)]='config.store.ssh.warnOnClose',
|
||||||
(ngModelChange)='config.save()',
|
(ngModelChange)='config.save()',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
.form-line
|
||||||
|
.header
|
||||||
|
.title WinSCP path
|
||||||
|
.descriptions When WinSCP is detected, you can launch an SCP session from the context menu.
|
||||||
|
input.form-control(
|
||||||
|
type='text',
|
||||||
|
placeholder='Auto-detect',
|
||||||
|
[(ngModel)]='config.store.ssh.winSCPPath',
|
||||||
|
(ngModelChange)='config.save()',
|
||||||
|
)
|
||||||
|
@ -7,6 +7,7 @@ export class SSHConfigProvider extends ConfigProvider {
|
|||||||
connections: [],
|
connections: [],
|
||||||
recentConnections: [],
|
recentConnections: [],
|
||||||
warnOnClose: false,
|
warnOnClose: false,
|
||||||
|
winSCPPath: null,
|
||||||
},
|
},
|
||||||
hotkeys: {
|
hotkeys: {
|
||||||
ssh: [
|
ssh: [
|
||||||
|
@ -3,7 +3,7 @@ import { CommonModule } from '@angular/common'
|
|||||||
import { FormsModule } from '@angular/forms'
|
import { FormsModule } from '@angular/forms'
|
||||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { ToastrModule } from 'ngx-toastr'
|
import { ToastrModule } from 'ngx-toastr'
|
||||||
import TerminusCoreModule, { ToolbarButtonProvider, ConfigProvider, TabRecoveryProvider, HotkeyProvider } from 'terminus-core'
|
import TerminusCoreModule, { ToolbarButtonProvider, ConfigProvider, TabRecoveryProvider, HotkeyProvider, TabContextMenuItemProvider } from 'terminus-core'
|
||||||
import { SettingsTabProvider } from 'terminus-settings'
|
import { SettingsTabProvider } from 'terminus-settings'
|
||||||
import TerminusTerminalModule from 'terminus-terminal'
|
import TerminusTerminalModule from 'terminus-terminal'
|
||||||
|
|
||||||
@ -18,6 +18,7 @@ import { SSHConfigProvider } from './config'
|
|||||||
import { SSHSettingsTabProvider } from './settings'
|
import { SSHSettingsTabProvider } from './settings'
|
||||||
import { RecoveryProvider } from './recoveryProvider'
|
import { RecoveryProvider } from './recoveryProvider'
|
||||||
import { SSHHotkeyProvider } from './hotkeys'
|
import { SSHHotkeyProvider } from './hotkeys'
|
||||||
|
import { WinSCPContextMenu } from './winSCPIntegration'
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@ -35,6 +36,7 @@ import { SSHHotkeyProvider } from './hotkeys'
|
|||||||
{ provide: SettingsTabProvider, useClass: SSHSettingsTabProvider, multi: true },
|
{ provide: SettingsTabProvider, useClass: SSHSettingsTabProvider, multi: true },
|
||||||
{ provide: TabRecoveryProvider, useClass: RecoveryProvider, multi: true },
|
{ provide: TabRecoveryProvider, useClass: RecoveryProvider, multi: true },
|
||||||
{ provide: HotkeyProvider, useClass: SSHHotkeyProvider, multi: true },
|
{ provide: HotkeyProvider, useClass: SSHHotkeyProvider, multi: true },
|
||||||
|
{ provide: TabContextMenuItemProvider, useClass: WinSCPContextMenu, multi: true },
|
||||||
],
|
],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
EditConnectionModalComponent,
|
EditConnectionModalComponent,
|
||||||
|
85
terminus-ssh/src/winSCPIntegration.ts
Normal file
85
terminus-ssh/src/winSCPIntegration.ts
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import { execFile } from 'child_process'
|
||||||
|
import { Injectable } from '@angular/core'
|
||||||
|
import { ConfigService, BaseTabComponent, TabContextMenuItemProvider, TabHeaderComponent, HostAppService, Platform } from 'terminus-core'
|
||||||
|
import { SSHTabComponent } from './components/sshTab.component'
|
||||||
|
import { PasswordStorageService } from './services/passwordStorage.service'
|
||||||
|
import { SSHConnection } from './api'
|
||||||
|
|
||||||
|
|
||||||
|
/* eslint-disable block-scoped-var */
|
||||||
|
try {
|
||||||
|
var wnr = require('windows-native-registry') // eslint-disable-line @typescript-eslint/no-var-requires, no-var
|
||||||
|
} catch { }
|
||||||
|
|
||||||
|
|
||||||
|
/** @hidden */
|
||||||
|
@Injectable()
|
||||||
|
export class WinSCPContextMenu extends TabContextMenuItemProvider {
|
||||||
|
weight = 10
|
||||||
|
private detectedPath?: string
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
private hostApp: HostAppService,
|
||||||
|
private config: ConfigService,
|
||||||
|
private passwordStorage: PasswordStorageService,
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
|
||||||
|
if (hostApp.platform !== Platform.Windows) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = wnr.getRegistryKey(wnr.HK.CR, 'WinSCP.Url\\DefaultIcon')
|
||||||
|
if (key?.['']) {
|
||||||
|
this.detectedPath = key[''].value?.split(',')[0]
|
||||||
|
this.detectedPath = this.detectedPath?.substring(1, this.detectedPath.length - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]> {
|
||||||
|
if (this.hostApp.platform !== Platform.Windows || tabHeader) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
if (!this.getPath()) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
if (!(tab instanceof SSHTabComponent)) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: 'Launch WinSCP',
|
||||||
|
click: (): void => {
|
||||||
|
this.launchWinSCP(tab.connection)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (connection: SSHConnection): Promise<void> {
|
||||||
|
const path = this.getPath()
|
||||||
|
if (!path) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let args = [await this.getURI(connection)]
|
||||||
|
if ((!connection.auth || connection.auth === 'publicKey') && connection.privateKey) {
|
||||||
|
args.push('/privatekey')
|
||||||
|
args.push(connection.privateKey)
|
||||||
|
}
|
||||||
|
execFile(path, args)
|
||||||
|
}
|
||||||
|
}
|
@ -45,10 +45,12 @@ module.exports = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
externals: [
|
externals: [
|
||||||
|
'child_process',
|
||||||
'fs',
|
'fs',
|
||||||
'keytar',
|
'keytar',
|
||||||
'path',
|
'path',
|
||||||
'ngx-toastr',
|
'ngx-toastr',
|
||||||
|
'windows-native-registry',
|
||||||
'windows-process-tree/build/Release/windows_process_tree.node',
|
'windows-process-tree/build/Release/windows_process_tree.node',
|
||||||
/^rxjs/,
|
/^rxjs/,
|
||||||
/^@angular/,
|
/^@angular/,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user