Skip to content

Commit

Permalink
Basic folder upload for sftp electron.
Browse files Browse the repository at this point in the history
  • Loading branch information
marko1616 committed Aug 21, 2024
1 parent 3f0b78e commit deaa529
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 11 deletions.
6 changes: 6 additions & 0 deletions tabby-core/src/api/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -84,6 +85,7 @@ export abstract class FileUpload extends FileTransfer {

export interface FileUploadOptions {
multiple: boolean
directory: boolean
}

export type PlatformTheme = 'light'|'dark'
Expand Down Expand Up @@ -202,6 +204,10 @@ export class HTMLFileUpload extends FileUpload {
return this.file.name
}

getRelativePath (): string {
return ""

Check failure on line 208 in tabby-core/src/api/platform.ts

View workflow job for this annotation

GitHub Actions / Lint

Strings must use singlequote
}

getMode (): number {
return 0o644
}
Expand Down
58 changes: 50 additions & 8 deletions tabby-electron/src/services/platform.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,20 @@ export class ElectronPlatformService extends PlatformService {
})
}

async getAllFiles(dir: string) {

Check failure on line 51 in tabby-electron/src/services/platform.service.ts

View workflow job for this annotation

GitHub Actions / Lint

Missing return type on function

Check failure on line 51 in tabby-electron/src/services/platform.service.ts

View workflow job for this annotation

GitHub Actions / Lint

Missing space before function parentheses
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()
}
Expand Down Expand Up @@ -187,12 +201,15 @@ export class ElectronPlatformService extends PlatformService {
}

async startUpload (options?: FileUploadOptions, paths?: string[]): Promise<FileUpload[]> {
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(
Expand All @@ -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)

Check failure on line 232 in tabby-electron/src/services/platform.service.ts

View workflow job for this annotation

GitHub Actions / Lint

'files' is never reassigned. Use 'const' instead
allFiles = allFiles.concat(files)
relativePaths = relativePaths.concat(files.map(file => path.posix.join(path.basename(folderPath),path.posix.relative(folderPath, file))))

Check failure on line 234 in tabby-electron/src/services/platform.service.ts

View workflow job for this annotation

GitHub Actions / Lint

A space is required after ','
}

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<FileDownload|null> {
Expand Down Expand Up @@ -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="") {

Check failure on line 303 in tabby-electron/src/services/platform.service.ts

View workflow job for this annotation

GitHub Actions / Lint

Type string trivially inferred from a string literal, remove type annotation

Check failure on line 303 in tabby-electron/src/services/platform.service.ts

View workflow job for this annotation

GitHub Actions / Lint

Strings must use singlequote
super()
this.buffer = Buffer.alloc(256 * 1024)
this.powerSaveBlocker = electron.powerSaveBlocker.start('prevent-app-suspension')
Expand All @@ -282,6 +316,10 @@ class ElectronFileUpload extends FileUpload {
getName (): string {
return path.basename(this.filePath)
}

Check failure on line 319 in tabby-electron/src/services/platform.service.ts

View workflow job for this annotation

GitHub Actions / Lint

Trailing spaces not allowed
getRelativePath (): string {
return this.relativePath
}

getMode (): number {
return this.mode
Expand Down Expand Up @@ -325,6 +363,10 @@ class ElectronFileDownload extends FileDownload {
return path.basename(this.filePath)
}

getRelativePath (): string {
return ""

Check failure on line 367 in tabby-electron/src/services/platform.service.ts

View workflow job for this annotation

GitHub Actions / Lint

Strings must use singlequote
}

getMode (): number {
return this.mode
}
Expand Down
2 changes: 1 addition & 1 deletion tabby-electron/src/sftpContextMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
4 changes: 4 additions & 0 deletions tabby-ssh/src/components/sftpPanel.component.pug
Original file line number Diff line number Diff line change
Expand Up @@ -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)')
Expand Down
32 changes: 31 additions & 1 deletion tabby-ssh/src/components/sftpPanel.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,40 @@ export class SFTPPanelComponent {
}

async upload (): Promise<void> {
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<void> {
const transfers = await this.platform.startUpload({ multiple: true, directory: true })
await Promise.all(transfers.map(t => this.uploadOneWithFolder(t)))
}

async uploadOneWithFolder (transfer: FileUpload): Promise<void> {
const savedPath = this.path

Check failure on line 190 in tabby-ssh/src/components/sftpPanel.component.ts

View workflow job for this annotation

GitHub Actions / Lint

Trailing spaces not allowed
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<void> {
const savedPath = this.path
await this.sftp.upload(path.join(this.path, transfer.getName()), transfer)
Expand Down
2 changes: 1 addition & 1 deletion tabby-terminal/src/features/zmodem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
4 changes: 4 additions & 0 deletions tabby-web/src/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ class HTMLFileDownload extends FileDownload {
return this.name
}

getRelativePath (): string {
return ""
}

getMode (): number {
return this.mode
}
Expand Down

0 comments on commit deaa529

Please sign in to comment.