From deaa529c07f21f4913d5eaa5b17d3668b6db2614 Mon Sep 17 00:00:00 2001 From: marko1616 Date: Wed, 21 Aug 2024 13:50:25 +0800 Subject: [PATCH 01/12] Basic folder upload for sftp electron. --- tabby-core/src/api/platform.ts | 6 ++ .../src/services/platform.service.ts | 58 ++++++++++++++++--- tabby-electron/src/sftpContextMenu.ts | 2 +- .../src/components/sftpPanel.component.pug | 4 ++ .../src/components/sftpPanel.component.ts | 32 +++++++++- tabby-terminal/src/features/zmodem.ts | 2 +- tabby-web/src/platform.ts | 4 ++ 7 files changed, 97 insertions(+), 11 deletions(-) diff --git a/tabby-core/src/api/platform.ts b/tabby-core/src/api/platform.ts index 9a87dc1834..1c4c9cd48d 100644 --- a/tabby-core/src/api/platform.ts +++ b/tabby-core/src/api/platform.ts @@ -22,6 +22,7 @@ export interface MessageBoxResult { export abstract class FileTransfer { abstract getName (): string + abstract getRelativePath (): string abstract getMode (): number abstract getSize (): number abstract close (): void @@ -84,6 +85,7 @@ export abstract class FileUpload extends FileTransfer { export interface FileUploadOptions { multiple: boolean + directory: boolean } export type PlatformTheme = 'light'|'dark' @@ -202,6 +204,10 @@ export class HTMLFileUpload extends FileUpload { return this.file.name } + getRelativePath (): string { + return "" + } + getMode (): number { return 0o644 } diff --git a/tabby-electron/src/services/platform.service.ts b/tabby-electron/src/services/platform.service.ts index 85ff48f69d..9172bc3144 100644 --- a/tabby-electron/src/services/platform.service.ts +++ b/tabby-electron/src/services/platform.service.ts @@ -48,6 +48,20 @@ export class ElectronPlatformService extends PlatformService { }) } + async getAllFiles(dir: string) { + let files: string[] = [] + const items = await fs.readdir(dir, { withFileTypes: true }) + for (const item of items) { + const fullPath = path.posix.join(dir, item.name) + if (item.isDirectory()) { + files = files.concat(await this.getAllFiles(fullPath)) + } else { + files.push(fullPath) + } + } + return files + } + readClipboard (): string { return this.electron.clipboard.readText() } @@ -187,12 +201,15 @@ export class ElectronPlatformService extends PlatformService { } async startUpload (options?: FileUploadOptions, paths?: string[]): Promise { - options ??= { multiple: false } + options ??= { multiple: false, directory: false } const properties: any[] = ['openFile', 'treatPackageAsDirectory'] if (options.multiple) { properties.push('multiSelections') } + if (options.directory) { + properties.push('openDirectory') + } if (!paths) { const result = await this.electron.dialog.showOpenDialog( @@ -208,12 +225,29 @@ export class ElectronPlatformService extends PlatformService { paths = result.filePaths } - return Promise.all(paths.map(async p => { - const transfer = new ElectronFileUpload(p, this.electron) - await wrapPromise(this.zone, transfer.open()) - this.fileTransferStarted.next(transfer) - return transfer - })) + if(options.directory) { + let allFiles: string[] = [] + let relativePaths: string[] = [] + for (const folderPath of paths) { + let files = await this.getAllFiles(folderPath) + allFiles = allFiles.concat(files) + relativePaths = relativePaths.concat(files.map(file => path.posix.join(path.basename(folderPath),path.posix.relative(folderPath, file)))) + } + + return Promise.all(allFiles.map(async (p, index) => { + const transfer = new ElectronFileUpload(p, this.electron, relativePaths[index]) + await wrapPromise(this.zone, transfer.open()) + this.fileTransferStarted.next(transfer) + return transfer + })) + } else { + return Promise.all(paths.map(async p => { + const transfer = new ElectronFileUpload(p, this.electron) + await wrapPromise(this.zone, transfer.open()) + this.fileTransferStarted.next(transfer) + return transfer + })) + } } async startDownload (name: string, mode: number, size: number, filePath?: string): Promise { @@ -266,7 +300,7 @@ class ElectronFileUpload extends FileUpload { private buffer: Buffer private powerSaveBlocker = 0 - constructor (private filePath: string, private electron: ElectronService) { + constructor (private filePath: string, private electron: ElectronService, private relativePath: string="") { super() this.buffer = Buffer.alloc(256 * 1024) this.powerSaveBlocker = electron.powerSaveBlocker.start('prevent-app-suspension') @@ -282,6 +316,10 @@ class ElectronFileUpload extends FileUpload { getName (): string { return path.basename(this.filePath) } + + getRelativePath (): string { + return this.relativePath + } getMode (): number { return this.mode @@ -325,6 +363,10 @@ class ElectronFileDownload extends FileDownload { return path.basename(this.filePath) } + getRelativePath (): string { + return "" + } + getMode (): number { return this.mode } diff --git a/tabby-electron/src/sftpContextMenu.ts b/tabby-electron/src/sftpContextMenu.ts index 2443aad65e..9ec30a6102 100644 --- a/tabby-electron/src/sftpContextMenu.ts +++ b/tabby-electron/src/sftpContextMenu.ts @@ -54,7 +54,7 @@ export class EditSFTPContextMenu extends SFTPContextMenuItemProvider { if (event === 'rename') { watcher.close() } - const upload = await this.platform.startUpload({ multiple: false }, [tempPath]) + const upload = await this.platform.startUpload({ multiple: false, directory: false }, [tempPath]) if (!upload.length) { return } diff --git a/tabby-ssh/src/components/sftpPanel.component.pug b/tabby-ssh/src/components/sftpPanel.component.pug index 57e9694194..36376f87f6 100644 --- a/tabby-ssh/src/components/sftpPanel.component.pug +++ b/tabby-ssh/src/components/sftpPanel.component.pug @@ -25,6 +25,10 @@ i.fas.fa-upload.me-1 div(translate) Upload + button.btn.btn-link.btn-sm.flex-shrink-0.d-flex((click)='uploadFolder()') + i.fas.fa-upload.me-1 + div(translate) Upload Folder + button.btn.btn-link.text-decoration-none((click)='close()') !{require('../../../tabby-core/src/icons/times.svg')} .body(dropZone, (transfer)='uploadOne($event)') diff --git a/tabby-ssh/src/components/sftpPanel.component.ts b/tabby-ssh/src/components/sftpPanel.component.ts index e966244379..3a22f92461 100644 --- a/tabby-ssh/src/components/sftpPanel.component.ts +++ b/tabby-ssh/src/components/sftpPanel.component.ts @@ -176,10 +176,40 @@ export class SFTPPanelComponent { } async upload (): Promise { - const transfers = await this.platform.startUpload({ multiple: true }) + const transfers = await this.platform.startUpload({ multiple: true, directory: false }) await Promise.all(transfers.map(t => this.uploadOne(t))) } + async uploadFolder (): Promise { + const transfers = await this.platform.startUpload({ multiple: true, directory: true }) + await Promise.all(transfers.map(t => this.uploadOneWithFolder(t))) + } + + async uploadOneWithFolder (transfer: FileUpload): Promise { + const savedPath = this.path + + try { + await this.sftp.stat(path.join(this.path, transfer.getRelativePath())) + } catch (e) { + if (e instanceof Error && e.message.includes('No such file')) { + let accumPath = "" + for (const pathParts of path.posix.dirname(transfer.getRelativePath()).split(path.posix.sep)) { + accumPath = path.posix.join(accumPath,pathParts) + this.sftp.mkdir(path.join(this.path, accumPath)).then(() => { + this.notifications.notice('The directory was created successfully') + }).catch(() => {}) + } + } else { + console.log("THROW HERE") + throw e; + } + } + await this.sftp.upload(path.join(this.path, transfer.getRelativePath()), transfer) + if (this.path === savedPath) { + await this.navigate(this.path) + } + } + async uploadOne (transfer: FileUpload): Promise { const savedPath = this.path await this.sftp.upload(path.join(this.path, transfer.getName()), transfer) diff --git a/tabby-terminal/src/features/zmodem.ts b/tabby-terminal/src/features/zmodem.ts index ed45e6769a..414846e2b3 100644 --- a/tabby-terminal/src/features/zmodem.ts +++ b/tabby-terminal/src/features/zmodem.ts @@ -74,7 +74,7 @@ class ZModemMiddleware extends SessionMiddleware { this.logger.info('new session', zsession) if (zsession.type === 'send') { - const transfers = await this.platform.startUpload({ multiple: true }) + const transfers = await this.platform.startUpload({ multiple: true, directory: false }) let filesRemaining = transfers.length let sizeRemaining = transfers.reduce((a, b) => a + b.getSize(), 0) for (const transfer of transfers) { diff --git a/tabby-web/src/platform.ts b/tabby-web/src/platform.ts index 035e2b6bb1..ddab757d2c 100644 --- a/tabby-web/src/platform.ts +++ b/tabby-web/src/platform.ts @@ -159,6 +159,10 @@ class HTMLFileDownload extends FileDownload { return this.name } + getRelativePath (): string { + return "" + } + getMode (): number { return this.mode } From 89dd0773eed8f6a4398160eecd4786f21ce9750b Mon Sep 17 00:00:00 2001 From: marko1616 Date: Wed, 21 Aug 2024 14:24:19 +0800 Subject: [PATCH 02/12] Lint pass. --- tabby-core/src/api/platform.ts | 2 +- tabby-electron/src/services/platform.service.ts | 12 ++++++------ tabby-ssh/src/components/sftpPanel.component.ts | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tabby-core/src/api/platform.ts b/tabby-core/src/api/platform.ts index 1c4c9cd48d..bf72880a3f 100644 --- a/tabby-core/src/api/platform.ts +++ b/tabby-core/src/api/platform.ts @@ -205,7 +205,7 @@ export class HTMLFileUpload extends FileUpload { } getRelativePath (): string { - return "" + return '' } getMode (): number { diff --git a/tabby-electron/src/services/platform.service.ts b/tabby-electron/src/services/platform.service.ts index 9172bc3144..63e28f89e6 100644 --- a/tabby-electron/src/services/platform.service.ts +++ b/tabby-electron/src/services/platform.service.ts @@ -48,7 +48,7 @@ export class ElectronPlatformService extends PlatformService { }) } - async getAllFiles(dir: string) { + async getAllFiles (dir: string): string[] { let files: string[] = [] const items = await fs.readdir(dir, { withFileTypes: true }) for (const item of items) { @@ -229,9 +229,9 @@ export class ElectronPlatformService extends PlatformService { let allFiles: string[] = [] let relativePaths: string[] = [] for (const folderPath of paths) { - let files = await this.getAllFiles(folderPath) + const files = await this.getAllFiles(folderPath) allFiles = allFiles.concat(files) - relativePaths = relativePaths.concat(files.map(file => path.posix.join(path.basename(folderPath),path.posix.relative(folderPath, file)))) + relativePaths = relativePaths.concat(files.map(file => path.posix.join(path.basename(folderPath), path.posix.relative(folderPath, file)))) } return Promise.all(allFiles.map(async (p, index) => { @@ -300,7 +300,7 @@ class ElectronFileUpload extends FileUpload { private buffer: Buffer private powerSaveBlocker = 0 - constructor (private filePath: string, private electron: ElectronService, private relativePath: string="") { + constructor (private filePath: string, private electron: ElectronService, private relativePath = '') { super() this.buffer = Buffer.alloc(256 * 1024) this.powerSaveBlocker = electron.powerSaveBlocker.start('prevent-app-suspension') @@ -316,7 +316,7 @@ class ElectronFileUpload extends FileUpload { getName (): string { return path.basename(this.filePath) } - + getRelativePath (): string { return this.relativePath } @@ -364,7 +364,7 @@ class ElectronFileDownload extends FileDownload { } getRelativePath (): string { - return "" + return '' } getMode (): number { diff --git a/tabby-ssh/src/components/sftpPanel.component.ts b/tabby-ssh/src/components/sftpPanel.component.ts index 3a22f92461..1f524bba08 100644 --- a/tabby-ssh/src/components/sftpPanel.component.ts +++ b/tabby-ssh/src/components/sftpPanel.component.ts @@ -187,7 +187,7 @@ export class SFTPPanelComponent { async uploadOneWithFolder (transfer: FileUpload): Promise { const savedPath = this.path - + try { await this.sftp.stat(path.join(this.path, transfer.getRelativePath())) } catch (e) { From f630b53e0a9bfe0e504427e75b513187f291e1ae Mon Sep 17 00:00:00 2001 From: marko1616 Date: Wed, 21 Aug 2024 14:33:11 +0800 Subject: [PATCH 03/12] Tiny fix. --- tabby-electron/src/services/platform.service.ts | 2 +- tabby-ssh/src/components/sftpPanel.component.ts | 11 ++++++----- tabby-web/src/platform.ts | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/tabby-electron/src/services/platform.service.ts b/tabby-electron/src/services/platform.service.ts index 63e28f89e6..87d5fca54f 100644 --- a/tabby-electron/src/services/platform.service.ts +++ b/tabby-electron/src/services/platform.service.ts @@ -48,7 +48,7 @@ export class ElectronPlatformService extends PlatformService { }) } - async getAllFiles (dir: string): string[] { + async getAllFiles (dir: string): Promise { let files: string[] = [] const items = await fs.readdir(dir, { withFileTypes: true }) for (const item of items) { diff --git a/tabby-ssh/src/components/sftpPanel.component.ts b/tabby-ssh/src/components/sftpPanel.component.ts index 1f524bba08..773e34c03d 100644 --- a/tabby-ssh/src/components/sftpPanel.component.ts +++ b/tabby-ssh/src/components/sftpPanel.component.ts @@ -192,16 +192,17 @@ export class SFTPPanelComponent { await this.sftp.stat(path.join(this.path, transfer.getRelativePath())) } catch (e) { if (e instanceof Error && e.message.includes('No such file')) { - let accumPath = "" + let accumPath = '' for (const pathParts of path.posix.dirname(transfer.getRelativePath()).split(path.posix.sep)) { - accumPath = path.posix.join(accumPath,pathParts) + accumPath = path.posix.join(accumPath, pathParts) this.sftp.mkdir(path.join(this.path, accumPath)).then(() => { this.notifications.notice('The directory was created successfully') - }).catch(() => {}) + }).catch(() => { + // Intentionally ignoring errors from making duplicate dirs. + }) } } else { - console.log("THROW HERE") - throw e; + throw e } } await this.sftp.upload(path.join(this.path, transfer.getRelativePath()), transfer) diff --git a/tabby-web/src/platform.ts b/tabby-web/src/platform.ts index ddab757d2c..aa1d504561 100644 --- a/tabby-web/src/platform.ts +++ b/tabby-web/src/platform.ts @@ -160,7 +160,7 @@ class HTMLFileDownload extends FileDownload { } getRelativePath (): string { - return "" + return '' } getMode (): number { From fdda602a76b058c3ba5eedd0cf4bfb2b6150a8d0 Mon Sep 17 00:00:00 2001 From: marko1616 <45327989+marko1616@users.noreply.github.com> Date: Wed, 21 Aug 2024 17:25:21 +0800 Subject: [PATCH 04/12] Apply suggestions from code review. Co-authored-by: Eugene --- tabby-ssh/src/components/sftpPanel.component.pug | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tabby-ssh/src/components/sftpPanel.component.pug b/tabby-ssh/src/components/sftpPanel.component.pug index 36376f87f6..95be8cb6ab 100644 --- a/tabby-ssh/src/components/sftpPanel.component.pug +++ b/tabby-ssh/src/components/sftpPanel.component.pug @@ -23,11 +23,11 @@ button.btn.btn-link.btn-sm.flex-shrink-0.d-flex((click)='upload()') i.fas.fa-upload.me-1 - div(translate) Upload + div(translate) Upload files button.btn.btn-link.btn-sm.flex-shrink-0.d-flex((click)='uploadFolder()') i.fas.fa-upload.me-1 - div(translate) Upload Folder + div(translate) Upload folder button.btn.btn-link.text-decoration-none((click)='close()') !{require('../../../tabby-core/src/icons/times.svg')} From b0dcc5f9df2e3392682e55ec55bf63dab0d53c42 Mon Sep 17 00:00:00 2001 From: marko1616 Date: Thu, 22 Aug 2024 05:42:00 +0800 Subject: [PATCH 05/12] Style fix. --- tabby-core/src/api/platform.ts | 6 +++--- .../src/services/platform.service.ts | 17 +++++++++-------- .../src/components/sftpPanel.component.ts | 18 +++++++++++------- tabby-web/src/platform.ts | 4 ++-- 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/tabby-core/src/api/platform.ts b/tabby-core/src/api/platform.ts index bf72880a3f..f6f9044c43 100644 --- a/tabby-core/src/api/platform.ts +++ b/tabby-core/src/api/platform.ts @@ -22,7 +22,7 @@ export interface MessageBoxResult { export abstract class FileTransfer { abstract getName (): string - abstract getRelativePath (): string + abstract getRelativePath (): string | null abstract getMode (): number abstract getSize (): number abstract close (): void @@ -204,8 +204,8 @@ export class HTMLFileUpload extends FileUpload { return this.file.name } - getRelativePath (): string { - return '' + getRelativePath (): null { + return null } getMode (): number { diff --git a/tabby-electron/src/services/platform.service.ts b/tabby-electron/src/services/platform.service.ts index 87d5fca54f..e8d20a0b3b 100644 --- a/tabby-electron/src/services/platform.service.ts +++ b/tabby-electron/src/services/platform.service.ts @@ -226,16 +226,17 @@ export class ElectronPlatformService extends PlatformService { } if(options.directory) { - let allFiles: string[] = [] - let relativePaths: string[] = [] + let fileInfos: { fullPath: string, relativePath: string }[] = [] for (const folderPath of paths) { const files = await this.getAllFiles(folderPath) - allFiles = allFiles.concat(files) - relativePaths = relativePaths.concat(files.map(file => path.posix.join(path.basename(folderPath), path.posix.relative(folderPath, file)))) + fileInfos = fileInfos.concat(files.map(file => ({ + fullPath: file, + relativePath: path.posix.join(path.basename(folderPath), path.posix.relative(folderPath, file)) + }))) } - return Promise.all(allFiles.map(async (p, index) => { - const transfer = new ElectronFileUpload(p, this.electron, relativePaths[index]) + return Promise.all(fileInfos.map(async (fileInfo) => { + const transfer = new ElectronFileUpload(fileInfo.fullPath, this.electron, fileInfo.relativePath) await wrapPromise(this.zone, transfer.open()) this.fileTransferStarted.next(transfer) return transfer @@ -363,8 +364,8 @@ class ElectronFileDownload extends FileDownload { return path.basename(this.filePath) } - getRelativePath (): string { - return '' + getRelativePath (): null { + return null } getMode (): number { diff --git a/tabby-ssh/src/components/sftpPanel.component.ts b/tabby-ssh/src/components/sftpPanel.component.ts index 773e34c03d..bee3a38bdd 100644 --- a/tabby-ssh/src/components/sftpPanel.component.ts +++ b/tabby-ssh/src/components/sftpPanel.component.ts @@ -187,25 +187,29 @@ export class SFTPPanelComponent { async uploadOneWithFolder (transfer: FileUpload): Promise { const savedPath = this.path + const RelativePath = transfer.getRelativePath() + if (RelativePath == null){ + return + } try { - await this.sftp.stat(path.join(this.path, transfer.getRelativePath())) + await this.sftp.stat(path.join(this.path, RelativePath)) } catch (e) { if (e instanceof Error && e.message.includes('No such file')) { let accumPath = '' - for (const pathParts of path.posix.dirname(transfer.getRelativePath()).split(path.posix.sep)) { + for (const pathParts of path.posix.dirname(RelativePath).split(path.posix.sep)) { accumPath = path.posix.join(accumPath, pathParts) - this.sftp.mkdir(path.join(this.path, accumPath)).then(() => { - this.notifications.notice('The directory was created successfully') - }).catch(() => { + try { + await this.sftp.mkdir(path.join(this.path, accumPath)) + } catch (e) { // Intentionally ignoring errors from making duplicate dirs. - }) + } } } else { throw e } } - await this.sftp.upload(path.join(this.path, transfer.getRelativePath()), transfer) + await this.sftp.upload(path.join(this.path, RelativePath), transfer) if (this.path === savedPath) { await this.navigate(this.path) } diff --git a/tabby-web/src/platform.ts b/tabby-web/src/platform.ts index aa1d504561..d95d4f73c0 100644 --- a/tabby-web/src/platform.ts +++ b/tabby-web/src/platform.ts @@ -159,8 +159,8 @@ class HTMLFileDownload extends FileDownload { return this.name } - getRelativePath (): string { - return '' + getRelativePath (): null { + return null } getMode (): number { From aa105bdf4da58def20faa3d5064acb33b3d7247f Mon Sep 17 00:00:00 2001 From: marko1616 Date: Thu, 22 Aug 2024 05:49:43 +0800 Subject: [PATCH 06/12] Lint pass. --- tabby-electron/src/services/platform.service.ts | 2 +- tabby-ssh/src/components/sftpPanel.component.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tabby-electron/src/services/platform.service.ts b/tabby-electron/src/services/platform.service.ts index e8d20a0b3b..701136ec19 100644 --- a/tabby-electron/src/services/platform.service.ts +++ b/tabby-electron/src/services/platform.service.ts @@ -231,7 +231,7 @@ export class ElectronPlatformService extends PlatformService { const files = await this.getAllFiles(folderPath) fileInfos = fileInfos.concat(files.map(file => ({ fullPath: file, - relativePath: path.posix.join(path.basename(folderPath), path.posix.relative(folderPath, file)) + relativePath: path.posix.join(path.basename(folderPath), path.posix.relative(folderPath, file)), }))) } diff --git a/tabby-ssh/src/components/sftpPanel.component.ts b/tabby-ssh/src/components/sftpPanel.component.ts index bee3a38bdd..129db3b434 100644 --- a/tabby-ssh/src/components/sftpPanel.component.ts +++ b/tabby-ssh/src/components/sftpPanel.component.ts @@ -188,7 +188,7 @@ export class SFTPPanelComponent { async uploadOneWithFolder (transfer: FileUpload): Promise { const savedPath = this.path const RelativePath = transfer.getRelativePath() - if (RelativePath == null){ + if (RelativePath == null) { return } @@ -201,7 +201,7 @@ export class SFTPPanelComponent { accumPath = path.posix.join(accumPath, pathParts) try { await this.sftp.mkdir(path.join(this.path, accumPath)) - } catch (e) { + } catch { // Intentionally ignoring errors from making duplicate dirs. } } From 3c5f2ba28c92ab1785c7243f5e9c14bcb81c2616 Mon Sep 17 00:00:00 2001 From: marko1616 Date: Thu, 22 Aug 2024 08:05:37 +0800 Subject: [PATCH 07/12] Drag upload support. --- tabby-core/src/api/platform.ts | 56 ++++++++++++++----- .../src/directives/dropZone.directive.ts | 4 +- .../src/services/platform.service.ts | 4 +- .../src/components/sftpPanel.component.pug | 2 +- tabby-web/src/platform.ts | 5 +- 5 files changed, 50 insertions(+), 21 deletions(-) diff --git a/tabby-core/src/api/platform.ts b/tabby-core/src/api/platform.ts index f6f9044c43..de8389d84d 100644 --- a/tabby-core/src/api/platform.ts +++ b/tabby-core/src/api/platform.ts @@ -109,22 +109,50 @@ export abstract class PlatformService { abstract startDownload (name: string, mode: number, size: number): Promise abstract startUpload (options?: FileUploadOptions): Promise - startUploadFromDragEvent (event: DragEvent, multiple = false): FileUpload[] { + async startUploadFromDragEvent(event: DragEvent, multiple = false): Promise { const result: FileUpload[] = [] + if (!event.dataTransfer) { - return [] + return Promise.resolve([]) } - // eslint-disable-next-line @typescript-eslint/prefer-for-of - for (let i = 0; i < event.dataTransfer.files.length; i++) { - const file = event.dataTransfer.files[i] - const transfer = new HTMLFileUpload(file) - this.fileTransferStarted.next(transfer) - result.push(transfer) - if (!multiple) { - break + + const traverseFileTree = (item: any, path = ''): Promise => { + return new Promise((resolve) => { + if (item.isFile) { + item.file((file: File) => { + const transfer = new HTMLFileUpload(file, `${path}/${item.name}`) + this.fileTransferStarted.next(transfer) + result.push(transfer) + resolve() + }); + } else if (item.isDirectory) { + const dirReader = item.createReader() + dirReader.readEntries(async (entries: any[]) => { + for (const entry of entries) { + await traverseFileTree(entry, `${path}${item.name}/`) + } + resolve() + }) + } else { + resolve() + } + }) + } + + const promises: Promise[] = [] + + const items = event.dataTransfer.items + for (let i = 0; i < items.length; i++) { + const item = items[i].webkitGetAsEntry() + if (item) { + promises.push(traverseFileTree(item)) + if (!multiple) { + break + } } } - return result + + return Promise.all(promises).then(() => result) } getConfigPath (): string|null { @@ -194,7 +222,7 @@ export class HTMLFileUpload extends FileUpload { private stream: ReadableStream private reader: ReadableStreamDefaultReader - constructor (private file: File) { + constructor (private file: File, private relativePath: string|null = null) { super() this.stream = this.file.stream() this.reader = this.stream.getReader() @@ -204,8 +232,8 @@ export class HTMLFileUpload extends FileUpload { return this.file.name } - getRelativePath (): null { - return null + getRelativePath (): string|null { + return this.relativePath } getMode (): number { diff --git a/tabby-core/src/directives/dropZone.directive.ts b/tabby-core/src/directives/dropZone.directive.ts index 1da823eb1c..55e6544963 100644 --- a/tabby-core/src/directives/dropZone.directive.ts +++ b/tabby-core/src/directives/dropZone.directive.ts @@ -27,9 +27,9 @@ export class DropZoneDirective implements AfterViewInit { }) } }) - this.el.nativeElement.addEventListener('drop', (event: DragEvent) => { + this.el.nativeElement.addEventListener('drop', async (event: DragEvent) => { this.removeHint() - for (const transfer of this.platform.startUploadFromDragEvent(event, true)) { + for (const transfer of await this.platform.startUploadFromDragEvent(event, true)) { this.transfer.emit(transfer) } }) diff --git a/tabby-electron/src/services/platform.service.ts b/tabby-electron/src/services/platform.service.ts index 701136ec19..a330713b3d 100644 --- a/tabby-electron/src/services/platform.service.ts +++ b/tabby-electron/src/services/platform.service.ts @@ -301,7 +301,7 @@ class ElectronFileUpload extends FileUpload { private buffer: Buffer private powerSaveBlocker = 0 - constructor (private filePath: string, private electron: ElectronService, private relativePath = '') { + constructor (private filePath: string, private electron: ElectronService, private relativePath: string|null = null ) { super() this.buffer = Buffer.alloc(256 * 1024) this.powerSaveBlocker = electron.powerSaveBlocker.start('prevent-app-suspension') @@ -318,7 +318,7 @@ class ElectronFileUpload extends FileUpload { return path.basename(this.filePath) } - getRelativePath (): string { + getRelativePath (): string|null { return this.relativePath } diff --git a/tabby-ssh/src/components/sftpPanel.component.pug b/tabby-ssh/src/components/sftpPanel.component.pug index 95be8cb6ab..8e5716f9cc 100644 --- a/tabby-ssh/src/components/sftpPanel.component.pug +++ b/tabby-ssh/src/components/sftpPanel.component.pug @@ -31,7 +31,7 @@ button.btn.btn-link.text-decoration-none((click)='close()') !{require('../../../tabby-core/src/icons/times.svg')} -.body(dropZone, (transfer)='uploadOne($event)') +.body(dropZone, (transfer)='uploadOneWithFolder($event)') a.alert.alert-info.d-flex.align-items-center( *ngIf='shouldShowCWDTip && !cwdDetectionAvailable', (click)='platform.openExternal("https://tabby.sh/go/cwd-detection")' diff --git a/tabby-web/src/platform.ts b/tabby-web/src/platform.ts index d95d4f73c0..9a57e020a4 100644 --- a/tabby-web/src/platform.ts +++ b/tabby-web/src/platform.ts @@ -151,6 +151,7 @@ class HTMLFileDownload extends FileDownload { private name: string, private mode: number, private size: number, + private relativePath: string|null = null, ) { super() } @@ -159,8 +160,8 @@ class HTMLFileDownload extends FileDownload { return this.name } - getRelativePath (): null { - return null + getRelativePath (): string|null { + return this.relativePath } getMode (): number { From 856a800cb29385ade0371d60864dacbcefaf1090 Mon Sep 17 00:00:00 2001 From: marko1616 Date: Thu, 22 Aug 2024 08:11:36 +0800 Subject: [PATCH 08/12] lint pass. --- tabby-core/src/api/platform.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tabby-core/src/api/platform.ts b/tabby-core/src/api/platform.ts index de8389d84d..1c1c3e9aed 100644 --- a/tabby-core/src/api/platform.ts +++ b/tabby-core/src/api/platform.ts @@ -109,13 +109,13 @@ export abstract class PlatformService { abstract startDownload (name: string, mode: number, size: number): Promise abstract startUpload (options?: FileUploadOptions): Promise - async startUploadFromDragEvent(event: DragEvent, multiple = false): Promise { + async startUploadFromDragEvent (event: DragEvent, multiple = false): Promise { const result: FileUpload[] = [] - + if (!event.dataTransfer) { return Promise.resolve([]) } - + const traverseFileTree = (item: any, path = ''): Promise => { return new Promise((resolve) => { if (item.isFile) { @@ -124,7 +124,7 @@ export abstract class PlatformService { this.fileTransferStarted.next(transfer) result.push(transfer) resolve() - }); + }) } else if (item.isDirectory) { const dirReader = item.createReader() dirReader.readEntries(async (entries: any[]) => { @@ -138,10 +138,11 @@ export abstract class PlatformService { } }) } - + const promises: Promise[] = [] - + const items = event.dataTransfer.items + // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let i = 0; i < items.length; i++) { const item = items[i].webkitGetAsEntry() if (item) { @@ -151,7 +152,6 @@ export abstract class PlatformService { } } } - return Promise.all(promises).then(() => result) } From d6c2c5de31c87842f0411022e92bd774bedac30e Mon Sep 17 00:00:00 2001 From: marko1616 Date: Fri, 23 Aug 2024 11:32:10 +0800 Subject: [PATCH 09/12] Support empty directory. --- tabby-core/src/api/index.ts | 2 +- tabby-core/src/api/platform.ts | 38 ++++++++--- .../src/directives/dropZone.directive.ts | 8 +-- .../src/services/platform.service.ts | 68 ++++++++++--------- tabby-electron/src/sftpContextMenu.ts | 2 +- .../src/components/sftpPanel.component.pug | 2 +- .../src/components/sftpPanel.component.ts | 37 ++++------ tabby-terminal/src/features/zmodem.ts | 2 +- tabby-web/src/platform.ts | 6 +- 9 files changed, 90 insertions(+), 75 deletions(-) diff --git a/tabby-core/src/api/index.ts b/tabby-core/src/api/index.ts index cc467f96ca..b55f7e764b 100644 --- a/tabby-core/src/api/index.ts +++ b/tabby-core/src/api/index.ts @@ -10,7 +10,7 @@ export { Theme } from './theme' export { TabContextMenuItemProvider } from './tabContextMenuProvider' export { SelectorOption } from './selector' export { CLIHandler, CLIEvent } from './cli' -export { PlatformService, ClipboardContent, MessageBoxResult, MessageBoxOptions, FileDownload, FileUpload, FileTransfer, HTMLFileUpload, FileUploadOptions } from './platform' +export { PlatformService, ClipboardContent, MessageBoxResult, MessageBoxOptions, FileDownload, FileUpload, FileTransfer, HTMLFileUpload, FileUploadOptions, DirectoryUpload } from './platform' export { MenuItemOptions } from './menu' export { BootstrapData, PluginInfo, BOOTSTRAP_DATA } from './mainProcess' export { HostWindowService } from './hostWindow' diff --git a/tabby-core/src/api/platform.ts b/tabby-core/src/api/platform.ts index 1c1c3e9aed..2b8944665b 100644 --- a/tabby-core/src/api/platform.ts +++ b/tabby-core/src/api/platform.ts @@ -85,7 +85,26 @@ export abstract class FileUpload extends FileTransfer { export interface FileUploadOptions { multiple: boolean - directory: boolean +} + +export class DirectoryUpload { + private childrens: (FileUpload|DirectoryUpload)[] = [] + + constructor(private name = '') { + // Just set name for now. + } + + getName () { + return this.name + } + + getChildrens () { + return this.childrens + } + + pushChildren (item: FileUpload|DirectoryUpload) { + this.childrens.push(item) + } } export type PlatformTheme = 'light'|'dark' @@ -108,31 +127,34 @@ export abstract class PlatformService { abstract startDownload (name: string, mode: number, size: number): Promise abstract startUpload (options?: FileUploadOptions): Promise + abstract startUploadDirectory (paths?: string[]): Promise - async startUploadFromDragEvent (event: DragEvent, multiple = false): Promise { - const result: FileUpload[] = [] + async startUploadFromDragEvent (event: DragEvent, multiple = false): Promise { + const result = new DirectoryUpload() if (!event.dataTransfer) { - return Promise.resolve([]) + return Promise.resolve(result) } - const traverseFileTree = (item: any, path = ''): Promise => { + const traverseFileTree = (item: any, root: DirectoryUpload = result): Promise => { return new Promise((resolve) => { if (item.isFile) { item.file((file: File) => { - const transfer = new HTMLFileUpload(file, `${path}/${item.name}`) + const transfer = new HTMLFileUpload(file) this.fileTransferStarted.next(transfer) - result.push(transfer) + root.pushChildren(transfer) resolve() }) } else if (item.isDirectory) { const dirReader = item.createReader() + const childrenFolder = new DirectoryUpload(item.name) dirReader.readEntries(async (entries: any[]) => { for (const entry of entries) { - await traverseFileTree(entry, `${path}${item.name}/`) + await traverseFileTree(entry, childrenFolder) } resolve() }) + root.pushChildren(childrenFolder) } else { resolve() } diff --git a/tabby-core/src/directives/dropZone.directive.ts b/tabby-core/src/directives/dropZone.directive.ts index 55e6544963..11afeea80e 100644 --- a/tabby-core/src/directives/dropZone.directive.ts +++ b/tabby-core/src/directives/dropZone.directive.ts @@ -1,5 +1,5 @@ import { Directive, Output, ElementRef, EventEmitter, AfterViewInit } from '@angular/core' -import { FileUpload, PlatformService } from '../api/platform' +import { DirectoryUpload, PlatformService } from '../api/platform' import './dropZone.directive.scss' /** @hidden */ @@ -7,7 +7,7 @@ import './dropZone.directive.scss' selector: '[dropZone]', }) export class DropZoneDirective implements AfterViewInit { - @Output() transfer = new EventEmitter() + @Output() transfer = new EventEmitter() private dropHint?: HTMLElement constructor ( @@ -29,9 +29,7 @@ export class DropZoneDirective implements AfterViewInit { }) this.el.nativeElement.addEventListener('drop', async (event: DragEvent) => { this.removeHint() - for (const transfer of await this.platform.startUploadFromDragEvent(event, true)) { - this.transfer.emit(transfer) - } + this.transfer.emit(await this.platform.startUploadFromDragEvent(event, true)) }) this.el.nativeElement.addEventListener('dragleave', () => { this.removeHint() diff --git a/tabby-electron/src/services/platform.service.ts b/tabby-electron/src/services/platform.service.ts index a330713b3d..78d5173d6d 100644 --- a/tabby-electron/src/services/platform.service.ts +++ b/tabby-electron/src/services/platform.service.ts @@ -5,7 +5,7 @@ import * as os from 'os' import promiseIpc, { RendererProcessType } from 'electron-promise-ipc' import { execFile } from 'mz/child_process' import { Injectable, NgZone } from '@angular/core' -import { PlatformService, ClipboardContent, Platform, MenuItemOptions, MessageBoxOptions, MessageBoxResult, FileUpload, FileDownload, FileUploadOptions, wrapPromise, TranslateService } from 'tabby-core' +import { PlatformService, ClipboardContent, Platform, MenuItemOptions, MessageBoxOptions, MessageBoxResult, DirectoryUpload, FileUpload, FileDownload, FileUploadOptions, wrapPromise, TranslateService } from 'tabby-core' import { ElectronService } from '../services/electron.service' import { ElectronHostWindow } from './hostWindow.service' import { ShellIntegrationService } from './shellIntegration.service' @@ -48,18 +48,19 @@ export class ElectronPlatformService extends PlatformService { }) } - async getAllFiles (dir: string): Promise { - let files: string[] = [] + async getAllFiles (dir: string, root: DirectoryUpload): Promise { const items = await fs.readdir(dir, { withFileTypes: true }) for (const item of items) { - const fullPath = path.posix.join(dir, item.name) if (item.isDirectory()) { - files = files.concat(await this.getAllFiles(fullPath)) + root.pushChildren(await this.getAllFiles(path.join(dir, item.name), new DirectoryUpload(item.name))) } else { - files.push(fullPath) + let file = new ElectronFileUpload(path.join(dir, item.name), this.electron) + root.pushChildren(file) + await wrapPromise(this.zone, file.open()) + this.fileTransferStarted.next(file) } } - return files + return root } readClipboard (): string { @@ -201,15 +202,12 @@ export class ElectronPlatformService extends PlatformService { } async startUpload (options?: FileUploadOptions, paths?: string[]): Promise { - options ??= { multiple: false, directory: false } + options ??= { multiple: false } const properties: any[] = ['openFile', 'treatPackageAsDirectory'] if (options.multiple) { properties.push('multiSelections') } - if (options.directory) { - properties.push('openDirectory') - } if (!paths) { const result = await this.electron.dialog.showOpenDialog( @@ -225,30 +223,34 @@ export class ElectronPlatformService extends PlatformService { paths = result.filePaths } - if(options.directory) { - let fileInfos: { fullPath: string, relativePath: string }[] = [] - for (const folderPath of paths) { - const files = await this.getAllFiles(folderPath) - fileInfos = fileInfos.concat(files.map(file => ({ - fullPath: file, - relativePath: path.posix.join(path.basename(folderPath), path.posix.relative(folderPath, file)), - }))) - } + return Promise.all(paths.map(async p => { + const transfer = new ElectronFileUpload(p, this.electron) + await wrapPromise(this.zone, transfer.open()) + this.fileTransferStarted.next(transfer) + return transfer + })) + } - return Promise.all(fileInfos.map(async (fileInfo) => { - const transfer = new ElectronFileUpload(fileInfo.fullPath, this.electron, fileInfo.relativePath) - await wrapPromise(this.zone, transfer.open()) - this.fileTransferStarted.next(transfer) - return transfer - })) - } else { - return Promise.all(paths.map(async p => { - const transfer = new ElectronFileUpload(p, this.electron) - await wrapPromise(this.zone, transfer.open()) - this.fileTransferStarted.next(transfer) - return transfer - })) + async startUploadDirectory (paths?: string[]): Promise { + const properties: any[] = ['openFile', 'treatPackageAsDirectory', 'openDirectory'] + + if (!paths) { + const result = await this.electron.dialog.showOpenDialog( + this.hostWindow.getWindow(), + { + buttonLabel: this.translate.instant('Select'), + properties, + }, + ) + if (result.canceled) { + return new DirectoryUpload() + } + paths = result.filePaths } + + let root = new DirectoryUpload() + root.pushChildren(await this.getAllFiles(paths[0].split(path.sep).join(path.posix.sep),new DirectoryUpload(path.basename(paths[0])))) + return root } async startDownload (name: string, mode: number, size: number, filePath?: string): Promise { diff --git a/tabby-electron/src/sftpContextMenu.ts b/tabby-electron/src/sftpContextMenu.ts index 9ec30a6102..2443aad65e 100644 --- a/tabby-electron/src/sftpContextMenu.ts +++ b/tabby-electron/src/sftpContextMenu.ts @@ -54,7 +54,7 @@ export class EditSFTPContextMenu extends SFTPContextMenuItemProvider { if (event === 'rename') { watcher.close() } - const upload = await this.platform.startUpload({ multiple: false, directory: false }, [tempPath]) + const upload = await this.platform.startUpload({ multiple: false }, [tempPath]) if (!upload.length) { return } diff --git a/tabby-ssh/src/components/sftpPanel.component.pug b/tabby-ssh/src/components/sftpPanel.component.pug index 8e5716f9cc..67e4f20227 100644 --- a/tabby-ssh/src/components/sftpPanel.component.pug +++ b/tabby-ssh/src/components/sftpPanel.component.pug @@ -31,7 +31,7 @@ button.btn.btn-link.text-decoration-none((click)='close()') !{require('../../../tabby-core/src/icons/times.svg')} -.body(dropZone, (transfer)='uploadOneWithFolder($event)') +.body(dropZone, (transfer)='uploadOneFolder($event)') a.alert.alert-info.d-flex.align-items-center( *ngIf='shouldShowCWDTip && !cwdDetectionAvailable', (click)='platform.openExternal("https://tabby.sh/go/cwd-detection")' diff --git a/tabby-ssh/src/components/sftpPanel.component.ts b/tabby-ssh/src/components/sftpPanel.component.ts index 129db3b434..336ab0d20e 100644 --- a/tabby-ssh/src/components/sftpPanel.component.ts +++ b/tabby-ssh/src/components/sftpPanel.component.ts @@ -1,7 +1,7 @@ import * as C from 'constants' import { posix as path } from 'path' import { Component, Input, Output, EventEmitter, Inject, Optional } from '@angular/core' -import { FileUpload, MenuItemOptions, NotificationsService, PlatformService } from 'tabby-core' +import { FileUpload, DirectoryUpload, MenuItemOptions, NotificationsService, PlatformService } from 'tabby-core' import { SFTPSession, SFTPFile } from '../session/sftp' import { SSHSession } from '../session/ssh' import { SFTPContextMenuItemProvider } from '../api' @@ -176,40 +176,29 @@ export class SFTPPanelComponent { } async upload (): Promise { - const transfers = await this.platform.startUpload({ multiple: true, directory: false }) + const transfers = await this.platform.startUpload({ multiple: true }) await Promise.all(transfers.map(t => this.uploadOne(t))) } async uploadFolder (): Promise { - const transfers = await this.platform.startUpload({ multiple: true, directory: true }) - await Promise.all(transfers.map(t => this.uploadOneWithFolder(t))) + const transfer = await this.platform.startUploadDirectory() + await this.uploadOneFolder(transfer) } - async uploadOneWithFolder (transfer: FileUpload): Promise { + async uploadOneFolder (transfer: DirectoryUpload, accumPath = ''): Promise { const savedPath = this.path - const RelativePath = transfer.getRelativePath() - if (RelativePath == null) { - return - } - - try { - await this.sftp.stat(path.join(this.path, RelativePath)) - } catch (e) { - if (e instanceof Error && e.message.includes('No such file')) { - let accumPath = '' - for (const pathParts of path.posix.dirname(RelativePath).split(path.posix.sep)) { - accumPath = path.posix.join(accumPath, pathParts) - try { - await this.sftp.mkdir(path.join(this.path, accumPath)) - } catch { - // Intentionally ignoring errors from making duplicate dirs. - } + for(const t of transfer.getChildrens()) { + if (t instanceof DirectoryUpload) { + try { + await this.sftp.mkdir(path.posix.join(this.path, accumPath, t.getName())) + } catch { + // Intentionally ignoring errors from making duplicate dirs. } + await this.uploadOneFolder(t, path.posix.join(accumPath,t.getName())) } else { - throw e + await this.sftp.upload(path.posix.join(this.path, accumPath, t.getName()), t) } } - await this.sftp.upload(path.join(this.path, RelativePath), transfer) if (this.path === savedPath) { await this.navigate(this.path) } diff --git a/tabby-terminal/src/features/zmodem.ts b/tabby-terminal/src/features/zmodem.ts index 414846e2b3..ed45e6769a 100644 --- a/tabby-terminal/src/features/zmodem.ts +++ b/tabby-terminal/src/features/zmodem.ts @@ -74,7 +74,7 @@ class ZModemMiddleware extends SessionMiddleware { this.logger.info('new session', zsession) if (zsession.type === 'send') { - const transfers = await this.platform.startUpload({ multiple: true, directory: false }) + const transfers = await this.platform.startUpload({ multiple: true }) let filesRemaining = transfers.length let sizeRemaining = transfers.reduce((a, b) => a + b.getSize(), 0) for (const transfer of transfers) { diff --git a/tabby-web/src/platform.ts b/tabby-web/src/platform.ts index 9a57e020a4..aa4c46b5a0 100644 --- a/tabby-web/src/platform.ts +++ b/tabby-web/src/platform.ts @@ -2,7 +2,7 @@ import '@vaadin/vaadin-context-menu' import copyToClipboard from 'copy-text-to-clipboard' import { Injectable, Inject } from '@angular/core' import { NgbModal } from '@ng-bootstrap/ng-bootstrap' -import { PlatformService, ClipboardContent, MenuItemOptions, MessageBoxOptions, MessageBoxResult, FileUpload, FileUploadOptions, FileDownload, HTMLFileUpload } from 'tabby-core' +import { PlatformService, ClipboardContent, MenuItemOptions, MessageBoxOptions, MessageBoxResult, FileUpload, FileUploadOptions, FileDownload, HTMLFileUpload, DirectoryUpload } from 'tabby-core' // eslint-disable-next-line no-duplicate-imports import type { ContextMenuElement, ContextMenuItem } from '@vaadin/vaadin-context-menu' @@ -135,6 +135,10 @@ export class WebPlatformService extends PlatformService { }) } + async startUploadDirectory (paths?: string[]): Promise { + return new DirectoryUpload() + } + setErrorHandler (handler: (_: any) => void): void { window.addEventListener('error', handler) } From 4d60ae2e902061f33fc1c1b721677e790f945e71 Mon Sep 17 00:00:00 2001 From: marko1616 Date: Fri, 23 Aug 2024 11:42:53 +0800 Subject: [PATCH 10/12] Lint pass --- tabby-core/src/api/platform.ts | 8 ++++---- tabby-core/src/directives/dropZone.directive.ts | 2 +- tabby-electron/src/services/platform.service.ts | 6 +++--- tabby-ssh/src/components/sftpPanel.component.ts | 2 +- tabby-web/src/platform.ts | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tabby-core/src/api/platform.ts b/tabby-core/src/api/platform.ts index 2b8944665b..834f362219 100644 --- a/tabby-core/src/api/platform.ts +++ b/tabby-core/src/api/platform.ts @@ -90,19 +90,19 @@ export interface FileUploadOptions { export class DirectoryUpload { private childrens: (FileUpload|DirectoryUpload)[] = [] - constructor(private name = '') { + constructor (private name = '') { // Just set name for now. } - getName () { + getName (): string { return this.name } - getChildrens () { + getChildrens (): (FileUpload|DirectoryUpload)[] { return this.childrens } - pushChildren (item: FileUpload|DirectoryUpload) { + pushChildren (item: FileUpload|DirectoryUpload): void { this.childrens.push(item) } } diff --git a/tabby-core/src/directives/dropZone.directive.ts b/tabby-core/src/directives/dropZone.directive.ts index 11afeea80e..64632fbc98 100644 --- a/tabby-core/src/directives/dropZone.directive.ts +++ b/tabby-core/src/directives/dropZone.directive.ts @@ -29,7 +29,7 @@ export class DropZoneDirective implements AfterViewInit { }) this.el.nativeElement.addEventListener('drop', async (event: DragEvent) => { this.removeHint() - this.transfer.emit(await this.platform.startUploadFromDragEvent(event, true)) + this.transfer.emit(await this.platform.startUploadFromDragEvent(event, true)) }) this.el.nativeElement.addEventListener('dragleave', () => { this.removeHint() diff --git a/tabby-electron/src/services/platform.service.ts b/tabby-electron/src/services/platform.service.ts index 78d5173d6d..26668392fc 100644 --- a/tabby-electron/src/services/platform.service.ts +++ b/tabby-electron/src/services/platform.service.ts @@ -54,7 +54,7 @@ export class ElectronPlatformService extends PlatformService { if (item.isDirectory()) { root.pushChildren(await this.getAllFiles(path.join(dir, item.name), new DirectoryUpload(item.name))) } else { - let file = new ElectronFileUpload(path.join(dir, item.name), this.electron) + const file = new ElectronFileUpload(path.join(dir, item.name), this.electron) root.pushChildren(file) await wrapPromise(this.zone, file.open()) this.fileTransferStarted.next(file) @@ -248,8 +248,8 @@ export class ElectronPlatformService extends PlatformService { paths = result.filePaths } - let root = new DirectoryUpload() - root.pushChildren(await this.getAllFiles(paths[0].split(path.sep).join(path.posix.sep),new DirectoryUpload(path.basename(paths[0])))) + const root = new DirectoryUpload() + root.pushChildren(await this.getAllFiles(paths[0].split(path.sep).join(path.posix.sep), new DirectoryUpload(path.basename(paths[0])))) return root } diff --git a/tabby-ssh/src/components/sftpPanel.component.ts b/tabby-ssh/src/components/sftpPanel.component.ts index 336ab0d20e..38625c0fca 100644 --- a/tabby-ssh/src/components/sftpPanel.component.ts +++ b/tabby-ssh/src/components/sftpPanel.component.ts @@ -194,7 +194,7 @@ export class SFTPPanelComponent { } catch { // Intentionally ignoring errors from making duplicate dirs. } - await this.uploadOneFolder(t, path.posix.join(accumPath,t.getName())) + await this.uploadOneFolder(t, path.posix.join(accumPath, t.getName())) } else { await this.sftp.upload(path.posix.join(this.path, accumPath, t.getName()), t) } diff --git a/tabby-web/src/platform.ts b/tabby-web/src/platform.ts index aa4c46b5a0..b64388f961 100644 --- a/tabby-web/src/platform.ts +++ b/tabby-web/src/platform.ts @@ -135,7 +135,7 @@ export class WebPlatformService extends PlatformService { }) } - async startUploadDirectory (paths?: string[]): Promise { + async startUploadDirectory (_paths?: string[]): Promise { return new DirectoryUpload() } From 82013e31393da8b261f44aa6827b2ac0aca83bc4 Mon Sep 17 00:00:00 2001 From: marko1616 Date: Fri, 23 Aug 2024 12:43:21 +0800 Subject: [PATCH 11/12] Trigger CI From f0d228bb60dcb7888c60b92827365faf998aacb6 Mon Sep 17 00:00:00 2001 From: Eugene Date: Sat, 24 Aug 2024 23:49:16 +0200 Subject: [PATCH 12/12] cleanup --- tabby-core/src/api/platform.ts | 7 +------ tabby-electron/src/services/platform.service.ts | 10 +--------- tabby-web/src/platform.ts | 5 ----- 3 files changed, 2 insertions(+), 20 deletions(-) diff --git a/tabby-core/src/api/platform.ts b/tabby-core/src/api/platform.ts index 834f362219..6f63154fc4 100644 --- a/tabby-core/src/api/platform.ts +++ b/tabby-core/src/api/platform.ts @@ -22,7 +22,6 @@ export interface MessageBoxResult { export abstract class FileTransfer { abstract getName (): string - abstract getRelativePath (): string | null abstract getMode (): number abstract getSize (): number abstract close (): void @@ -244,7 +243,7 @@ export class HTMLFileUpload extends FileUpload { private stream: ReadableStream private reader: ReadableStreamDefaultReader - constructor (private file: File, private relativePath: string|null = null) { + constructor (private file: File) { super() this.stream = this.file.stream() this.reader = this.stream.getReader() @@ -254,10 +253,6 @@ export class HTMLFileUpload extends FileUpload { return this.file.name } - getRelativePath (): string|null { - return this.relativePath - } - getMode (): number { return 0o644 } diff --git a/tabby-electron/src/services/platform.service.ts b/tabby-electron/src/services/platform.service.ts index 26668392fc..52fcf9fc44 100644 --- a/tabby-electron/src/services/platform.service.ts +++ b/tabby-electron/src/services/platform.service.ts @@ -303,7 +303,7 @@ class ElectronFileUpload extends FileUpload { private buffer: Buffer private powerSaveBlocker = 0 - constructor (private filePath: string, private electron: ElectronService, private relativePath: string|null = null ) { + constructor (private filePath: string, private electron: ElectronService) { super() this.buffer = Buffer.alloc(256 * 1024) this.powerSaveBlocker = electron.powerSaveBlocker.start('prevent-app-suspension') @@ -320,10 +320,6 @@ class ElectronFileUpload extends FileUpload { return path.basename(this.filePath) } - getRelativePath (): string|null { - return this.relativePath - } - getMode (): number { return this.mode } @@ -366,10 +362,6 @@ class ElectronFileDownload extends FileDownload { return path.basename(this.filePath) } - getRelativePath (): null { - return null - } - getMode (): number { return this.mode } diff --git a/tabby-web/src/platform.ts b/tabby-web/src/platform.ts index b64388f961..50958dae17 100644 --- a/tabby-web/src/platform.ts +++ b/tabby-web/src/platform.ts @@ -155,7 +155,6 @@ class HTMLFileDownload extends FileDownload { private name: string, private mode: number, private size: number, - private relativePath: string|null = null, ) { super() } @@ -164,10 +163,6 @@ class HTMLFileDownload extends FileDownload { return this.name } - getRelativePath (): string|null { - return this.relativePath - } - getMode (): number { return this.mode }