From e223effe9857b2046039502da3d020721d5c0f57 Mon Sep 17 00:00:00 2001 From: Thomas Peterson Date: Tue, 29 Mar 2022 18:26:57 +0200 Subject: [PATCH 1/7] SFTP Feature: implement Create Folder --- .../sftpCreateDirectoryModal.component.pug | 13 ++++++ .../sftpCreateDirectoryModal.component.ts | 42 +++++++++++++++++++ tabby-ssh/src/index.ts | 3 ++ tabby-ssh/src/session/sftp.ts | 8 ++++ tabby-ssh/src/sftpContextMenu.ts | 15 +++++++ 5 files changed, 81 insertions(+) create mode 100644 tabby-ssh/src/components/sftpCreateDirectoryModal.component.pug create mode 100644 tabby-ssh/src/components/sftpCreateDirectoryModal.component.ts diff --git a/tabby-ssh/src/components/sftpCreateDirectoryModal.component.pug b/tabby-ssh/src/components/sftpCreateDirectoryModal.component.pug new file mode 100644 index 00000000..e320ca54 --- /dev/null +++ b/tabby-ssh/src/components/sftpCreateDirectoryModal.component.pug @@ -0,0 +1,13 @@ +.modal-body + label(translate) Create Directory + .form-group.w-100.mr-2 + label(translate) Name + input.form-control( + type='text', + [(ngModel)]='directoryName', + ) + + +.modal-footer + button.btn.btn-success((click)='create()', translate) Create + button.btn.btn-danger((click)='cancel()', translate) Cancel diff --git a/tabby-ssh/src/components/sftpCreateDirectoryModal.component.ts b/tabby-ssh/src/components/sftpCreateDirectoryModal.component.ts new file mode 100644 index 00000000..2f2a543c --- /dev/null +++ b/tabby-ssh/src/components/sftpCreateDirectoryModal.component.ts @@ -0,0 +1,42 @@ +import { Component } from '@angular/core' +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' +import path from 'path' +import { BaseComponent } from 'tabby-core' +import { SFTPFile, SFTPSession } from '../session/sftp' +import { SFTPPanelComponent } from './sftpPanel.component' + +/** @hidden */ +@Component({ + template: require('./sftpCreateDirectoryModal.component.pug'), +}) +export class SFTPCreateDirectoryModalComponent extends BaseComponent { + sftp: SFTPSession + item: SFTPFile + panel: SFTPPanelComponent + directoryName: string + + constructor ( + private modalInstance: NgbActiveModal, + ) { + super() + } + + async ngOnInit (): Promise { + + } + + create (): void { + this.createDirectory(this.item.directory); + } + cancel (): void { + this.modalInstance.close() + } + + async createDirectory (currentDirectory: string): Promise { + this.sftp.mkdir(path.join(currentDirectory, this.directoryName)).finally(() => { + this.panel.navigate(path.join(currentDirectory, this.directoryName)); + this.cancel(); + }); + + } +} diff --git a/tabby-ssh/src/index.ts b/tabby-ssh/src/index.ts index 750838e5..e970b8f3 100644 --- a/tabby-ssh/src/index.ts +++ b/tabby-ssh/src/index.ts @@ -26,6 +26,7 @@ import { SFTPContextMenu } from './tabContextMenu' import { SSHProfilesService } from './profiles' import { SFTPContextMenuItemProvider } from './api/contextMenu' import { CommonSFTPContextMenu } from './sftpContextMenu' +import { SFTPCreateDirectoryModalComponent } from './components/sftpCreateDirectoryModal.component' /** @hidden */ @NgModule({ @@ -50,6 +51,7 @@ import { CommonSFTPContextMenu } from './sftpContextMenu' entryComponents: [ SSHProfileSettingsComponent, SFTPDeleteModalComponent, + SFTPCreateDirectoryModalComponent, SSHPortForwardingModalComponent, SSHSettingsTabComponent, SSHTabComponent, @@ -58,6 +60,7 @@ import { CommonSFTPContextMenu } from './sftpContextMenu' declarations: [ SSHProfileSettingsComponent, SFTPDeleteModalComponent, + SFTPCreateDirectoryModalComponent, SSHPortForwardingModalComponent, SSHPortForwardingConfigComponent, SSHSettingsTabComponent, diff --git a/tabby-ssh/src/session/sftp.ts b/tabby-ssh/src/session/sftp.ts index 4c85e70c..1e60ad8b 100644 --- a/tabby-ssh/src/session/sftp.ts +++ b/tabby-ssh/src/session/sftp.ts @@ -12,6 +12,7 @@ import type { FileEntry, Stats } from 'ssh2-streams' export interface SFTPFile { name: string fullPath: string + directory: string isDirectory: boolean isSymlink: boolean mode: number @@ -103,6 +104,7 @@ export class SFTPSession { const stats = await wrapPromise(this.zone, promisify(f => this.sftp.stat(p, f))()) return { name: posixPath.basename(p), + directory: posixPath.dirname(p), fullPath: p, isDirectory: stats.isDirectory(), isSymlink: stats.isSymbolicLink(), @@ -123,6 +125,11 @@ export class SFTPSession { await promisify((f: any) => this.sftp.rmdir(p, f))() } + async mkdir (p: string): Promise { + this.logger.debug('mkdir', p) + await promisify((f: any) => this.sftp.mkdir(p, f))() + } + async rename (oldPath: string, newPath: string): Promise { this.logger.debug('rename', oldPath, newPath) await promisify((f: any) => this.sftp.rename(oldPath, newPath, f))() @@ -181,6 +188,7 @@ export class SFTPSession { return { fullPath: p, name: posixPath.basename(p), + directory: posixPath.dirname(p), isDirectory: (entry.attrs.mode & C.S_IFDIR) === C.S_IFDIR, isSymlink: (entry.attrs.mode & C.S_IFLNK) === C.S_IFLNK, mode: entry.attrs.mode, diff --git a/tabby-ssh/src/sftpContextMenu.ts b/tabby-ssh/src/sftpContextMenu.ts index b1e0cff9..05b1c95b 100644 --- a/tabby-ssh/src/sftpContextMenu.ts +++ b/tabby-ssh/src/sftpContextMenu.ts @@ -5,6 +5,7 @@ import { SFTPSession, SFTPFile } from './session/sftp' import { SFTPContextMenuItemProvider } from './api' import { SFTPDeleteModalComponent } from './components/sftpDeleteModal.component' import { SFTPPanelComponent } from './components/sftpPanel.component' +import { SFTPCreateDirectoryModalComponent } from './components/sftpCreateDirectoryModal.component' /** @hidden */ @@ -22,6 +23,12 @@ export class CommonSFTPContextMenu extends SFTPContextMenuItemProvider { async getItems (item: SFTPFile, panel: SFTPPanelComponent): Promise { return [ + { + click: async () => { + await this.createDirectory(item, panel); + }, + label: this.translate.instant('Create Directory'), + }, { click: async () => { if ((await this.platform.showMessageBox({ @@ -49,4 +56,12 @@ export class CommonSFTPContextMenu extends SFTPContextMenuItemProvider { modal.componentInstance.sftp = session await modal.result } + + async createDirectory (item: SFTPFile, panel: SFTPPanelComponent): Promise { + const modal = this.ngbModal.open(SFTPCreateDirectoryModalComponent) + modal.componentInstance.item = item + modal.componentInstance.sftp = panel.sftp + modal.componentInstance.panel = panel + await modal.result + } } From e2a74a2f6e7edb37f86498eda27023fcbf8d93de Mon Sep 17 00:00:00 2001 From: Thomas Peterson Date: Tue, 29 Mar 2022 18:43:32 +0200 Subject: [PATCH 2/7] Fix Typings --- .../sftpCreateDirectoryModal.component.ts | 14 +++++--------- tabby-ssh/src/sftpContextMenu.ts | 2 +- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/tabby-ssh/src/components/sftpCreateDirectoryModal.component.ts b/tabby-ssh/src/components/sftpCreateDirectoryModal.component.ts index 2f2a543c..64b27829 100644 --- a/tabby-ssh/src/components/sftpCreateDirectoryModal.component.ts +++ b/tabby-ssh/src/components/sftpCreateDirectoryModal.component.ts @@ -14,19 +14,15 @@ export class SFTPCreateDirectoryModalComponent extends BaseComponent { item: SFTPFile panel: SFTPPanelComponent directoryName: string - + constructor ( private modalInstance: NgbActiveModal, ) { super() } - async ngOnInit (): Promise { - - } - create (): void { - this.createDirectory(this.item.directory); + this.createDirectory(this.item.directory) } cancel (): void { this.modalInstance.close() @@ -34,9 +30,9 @@ export class SFTPCreateDirectoryModalComponent extends BaseComponent { async createDirectory (currentDirectory: string): Promise { this.sftp.mkdir(path.join(currentDirectory, this.directoryName)).finally(() => { - this.panel.navigate(path.join(currentDirectory, this.directoryName)); - this.cancel(); - }); + this.panel.navigate(path.join(currentDirectory, this.directoryName)) + this.cancel() + }) } } diff --git a/tabby-ssh/src/sftpContextMenu.ts b/tabby-ssh/src/sftpContextMenu.ts index 05b1c95b..8e8b5f9c 100644 --- a/tabby-ssh/src/sftpContextMenu.ts +++ b/tabby-ssh/src/sftpContextMenu.ts @@ -25,7 +25,7 @@ export class CommonSFTPContextMenu extends SFTPContextMenuItemProvider { return [ { click: async () => { - await this.createDirectory(item, panel); + await this.createDirectory(item, panel) }, label: this.translate.instant('Create Directory'), }, From d710c5d3fae371e98b0f91fd32c899a4af2df426 Mon Sep 17 00:00:00 2001 From: boonkerz Date: Wed, 30 Mar 2022 09:10:16 +0200 Subject: [PATCH 3/7] Update tabby-ssh/src/sftpContextMenu.ts Co-authored-by: Eugeny --- tabby-ssh/src/sftpContextMenu.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tabby-ssh/src/sftpContextMenu.ts b/tabby-ssh/src/sftpContextMenu.ts index 8e8b5f9c..afdbe96f 100644 --- a/tabby-ssh/src/sftpContextMenu.ts +++ b/tabby-ssh/src/sftpContextMenu.ts @@ -27,7 +27,7 @@ export class CommonSFTPContextMenu extends SFTPContextMenuItemProvider { click: async () => { await this.createDirectory(item, panel) }, - label: this.translate.instant('Create Directory'), + label: this.translate.instant('Create directory'), }, { click: async () => { From 8904209bb53aea4c295f63cb2fbccc9832f2d1e1 Mon Sep 17 00:00:00 2001 From: boonkerz Date: Wed, 30 Mar 2022 09:10:22 +0200 Subject: [PATCH 4/7] Update tabby-ssh/src/components/sftpCreateDirectoryModal.component.pug Co-authored-by: Eugeny --- tabby-ssh/src/components/sftpCreateDirectoryModal.component.pug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tabby-ssh/src/components/sftpCreateDirectoryModal.component.pug b/tabby-ssh/src/components/sftpCreateDirectoryModal.component.pug index e320ca54..4d7bc337 100644 --- a/tabby-ssh/src/components/sftpCreateDirectoryModal.component.pug +++ b/tabby-ssh/src/components/sftpCreateDirectoryModal.component.pug @@ -1,5 +1,5 @@ .modal-body - label(translate) Create Directory + label(translate) Name for the new directory .form-group.w-100.mr-2 label(translate) Name input.form-control( From 54aa027764349038a6b0ee85f463c68313445a8b Mon Sep 17 00:00:00 2001 From: Thomas Peterson Date: Wed, 30 Mar 2022 13:57:54 +0200 Subject: [PATCH 5/7] Fixing the modal dialog and some architecture issues :) --- .../sftpCreateDirectoryModal.component.pug | 1 - .../sftpCreateDirectoryModal.component.ts | 18 ++---------------- .../src/components/sftpPanel.component.pug | 4 ++++ .../src/components/sftpPanel.component.ts | 17 +++++++++++++---- tabby-ssh/src/sftpContextMenu.ts | 11 +---------- 5 files changed, 20 insertions(+), 31 deletions(-) diff --git a/tabby-ssh/src/components/sftpCreateDirectoryModal.component.pug b/tabby-ssh/src/components/sftpCreateDirectoryModal.component.pug index 4d7bc337..a559641c 100644 --- a/tabby-ssh/src/components/sftpCreateDirectoryModal.component.pug +++ b/tabby-ssh/src/components/sftpCreateDirectoryModal.component.pug @@ -1,7 +1,6 @@ .modal-body label(translate) Name for the new directory .form-group.w-100.mr-2 - label(translate) Name input.form-control( type='text', [(ngModel)]='directoryName', diff --git a/tabby-ssh/src/components/sftpCreateDirectoryModal.component.ts b/tabby-ssh/src/components/sftpCreateDirectoryModal.component.ts index 64b27829..85b02b0b 100644 --- a/tabby-ssh/src/components/sftpCreateDirectoryModal.component.ts +++ b/tabby-ssh/src/components/sftpCreateDirectoryModal.component.ts @@ -1,18 +1,12 @@ import { Component } from '@angular/core' import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' -import path from 'path' import { BaseComponent } from 'tabby-core' -import { SFTPFile, SFTPSession } from '../session/sftp' -import { SFTPPanelComponent } from './sftpPanel.component' /** @hidden */ @Component({ template: require('./sftpCreateDirectoryModal.component.pug'), }) export class SFTPCreateDirectoryModalComponent extends BaseComponent { - sftp: SFTPSession - item: SFTPFile - panel: SFTPPanelComponent directoryName: string constructor ( @@ -22,17 +16,9 @@ export class SFTPCreateDirectoryModalComponent extends BaseComponent { } create (): void { - this.createDirectory(this.item.directory) + this.modalInstance.close(this.directoryName) } cancel (): void { - this.modalInstance.close() - } - - async createDirectory (currentDirectory: string): Promise { - this.sftp.mkdir(path.join(currentDirectory, this.directoryName)).finally(() => { - this.panel.navigate(path.join(currentDirectory, this.directoryName)) - this.cancel() - }) - + this.modalInstance.close('') } } diff --git a/tabby-ssh/src/components/sftpPanel.component.pug b/tabby-ssh/src/components/sftpPanel.component.pug index 7007b5f5..b4e9dfc1 100644 --- a/tabby-ssh/src/components/sftpPanel.component.pug +++ b/tabby-ssh/src/components/sftpPanel.component.pug @@ -6,6 +6,10 @@ (click)='navigate(segment.path)' ) {{segment.name}} + button.btn.btn-link.btn-sm.d-flex((click)='openCreateDirectoryModal()') + i.fas.fa-plus.mr-1 + div(translate) Create Directory + button.btn.btn-link.btn-sm.d-flex((click)='upload()') i.fas.fa-upload.mr-1 div(translate) Upload diff --git a/tabby-ssh/src/components/sftpPanel.component.ts b/tabby-ssh/src/components/sftpPanel.component.ts index 599e841f..f9591686 100644 --- a/tabby-ssh/src/components/sftpPanel.component.ts +++ b/tabby-ssh/src/components/sftpPanel.component.ts @@ -5,6 +5,8 @@ import { FileUpload, MenuItemOptions, NotificationsService, PlatformService } fr import { SFTPSession, SFTPFile } from '../session/sftp' import { SSHSession } from '../session/ssh' import { SFTPContextMenuItemProvider } from '../api' +import { NgbModal } from '@ng-bootstrap/ng-bootstrap' +import { SFTPCreateDirectoryModalComponent } from './sftpCreateDirectoryModal.component' interface PathSegment { name: string @@ -26,6 +28,7 @@ export class SFTPPanelComponent { pathSegments: PathSegment[] = [] constructor ( + private ngbModal: NgbModal, private platform: PlatformService, private notifications: NotificationsService, @Optional() @Inject(SFTPContextMenuItemProvider) protected contextMenuProviders: SFTPContextMenuItemProvider[], @@ -106,6 +109,16 @@ export class SFTPPanelComponent { } } + async openCreateDirectoryModal (): Promise { + const modal = this.ngbModal.open(SFTPCreateDirectoryModalComponent) + const directoryName = await modal.result + if (directoryName !== '') { + this.sftp.mkdir(path.join(this.path, directoryName)).finally(() => { + this.navigate(path.join(this.path, directoryName)) + }) + } + } + async upload (): Promise { const transfers = await this.platform.startUpload({ multiple: true }) await Promise.all(transfers.map(t => this.uploadOne(t))) @@ -113,10 +126,6 @@ export class SFTPPanelComponent { async uploadOne (transfer: FileUpload): Promise { await this.sftp.upload(path.join(this.path, transfer.getName()), transfer) - const savedPath = this.path - if (this.path === savedPath) { - await this.navigate(this.path) - } } async download (itemPath: string, mode: number, size: number): Promise { diff --git a/tabby-ssh/src/sftpContextMenu.ts b/tabby-ssh/src/sftpContextMenu.ts index afdbe96f..5a3a8213 100644 --- a/tabby-ssh/src/sftpContextMenu.ts +++ b/tabby-ssh/src/sftpContextMenu.ts @@ -5,7 +5,6 @@ import { SFTPSession, SFTPFile } from './session/sftp' import { SFTPContextMenuItemProvider } from './api' import { SFTPDeleteModalComponent } from './components/sftpDeleteModal.component' import { SFTPPanelComponent } from './components/sftpPanel.component' -import { SFTPCreateDirectoryModalComponent } from './components/sftpCreateDirectoryModal.component' /** @hidden */ @@ -25,7 +24,7 @@ export class CommonSFTPContextMenu extends SFTPContextMenuItemProvider { return [ { click: async () => { - await this.createDirectory(item, panel) + await panel.openCreateDirectoryModal() }, label: this.translate.instant('Create directory'), }, @@ -56,12 +55,4 @@ export class CommonSFTPContextMenu extends SFTPContextMenuItemProvider { modal.componentInstance.sftp = session await modal.result } - - async createDirectory (item: SFTPFile, panel: SFTPPanelComponent): Promise { - const modal = this.ngbModal.open(SFTPCreateDirectoryModalComponent) - modal.componentInstance.item = item - modal.componentInstance.sftp = panel.sftp - modal.componentInstance.panel = panel - await modal.result - } } From a4600890c3e9b4edcf6165ef82c67e245fc130d3 Mon Sep 17 00:00:00 2001 From: Thomas Peterson Date: Wed, 30 Mar 2022 13:59:56 +0200 Subject: [PATCH 6/7] Fixing Lang Typo --- tabby-ssh/src/sftpContextMenu.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tabby-ssh/src/sftpContextMenu.ts b/tabby-ssh/src/sftpContextMenu.ts index 5a3a8213..6208b0e0 100644 --- a/tabby-ssh/src/sftpContextMenu.ts +++ b/tabby-ssh/src/sftpContextMenu.ts @@ -26,7 +26,7 @@ export class CommonSFTPContextMenu extends SFTPContextMenuItemProvider { click: async () => { await panel.openCreateDirectoryModal() }, - label: this.translate.instant('Create directory'), + label: this.translate.instant('Create Directory'), }, { click: async () => { From 45eebf47f3733043f761a1678c29895cd3c8d4fd Mon Sep 17 00:00:00 2001 From: Thomas Peterson Date: Wed, 30 Mar 2022 14:01:01 +0200 Subject: [PATCH 7/7] Fixing Lang Typo --- tabby-ssh/src/components/sftpPanel.component.pug | 2 +- tabby-ssh/src/sftpContextMenu.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tabby-ssh/src/components/sftpPanel.component.pug b/tabby-ssh/src/components/sftpPanel.component.pug index b4e9dfc1..cbfa705d 100644 --- a/tabby-ssh/src/components/sftpPanel.component.pug +++ b/tabby-ssh/src/components/sftpPanel.component.pug @@ -8,7 +8,7 @@ button.btn.btn-link.btn-sm.d-flex((click)='openCreateDirectoryModal()') i.fas.fa-plus.mr-1 - div(translate) Create Directory + div(translate) Create directory button.btn.btn-link.btn-sm.d-flex((click)='upload()') i.fas.fa-upload.mr-1 diff --git a/tabby-ssh/src/sftpContextMenu.ts b/tabby-ssh/src/sftpContextMenu.ts index 6208b0e0..5a3a8213 100644 --- a/tabby-ssh/src/sftpContextMenu.ts +++ b/tabby-ssh/src/sftpContextMenu.ts @@ -26,7 +26,7 @@ export class CommonSFTPContextMenu extends SFTPContextMenuItemProvider { click: async () => { await panel.openCreateDirectoryModal() }, - label: this.translate.instant('Create Directory'), + label: this.translate.instant('Create directory'), }, { click: async () => {