From 93123c5c601a947a774ef2cf047c600b252e91a1 Mon Sep 17 00:00:00 2001 From: Louis Date: Wed, 14 Oct 2026 21:29:49 +0200 Subject: [PATCH] SFTP: upload button on the server pane (desktop: system file dialog with multi-select, uploads into the current folder); fix the backend switch (UFW/iptables) sitting too high in the firewall tab bar (.seg bottom margin was only reset for Docker) Co-Authored-By: Claude Opus 5.5 --- src/i18n.js | 1 + src/main/main.js | 5 +++++ src/renderer/app.js | 11 +++++++++-- src/renderer/styles.css | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/i18n.js b/src/i18n.js index 4ef388d..73cc011 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -151,6 +151,7 @@ 'Send Enter automatically': 'Enter automatisch senden', 'Command is missing.': 'Befehl fehlt.', 'No open terminal': 'Kein offenes Terminal', + 'Upload files …': 'Dateien hochladen …', // Support-Assistent 'Delete chat': 'Chat löschen', 'Delete chat?': 'Chat löschen?', diff --git a/src/main/main.js b/src/main/main.js index 3f5f4a0..cab4df8 100644 --- a/src/main/main.js +++ b/src/main/main.js @@ -408,6 +408,11 @@ handle('sftp:open', async (sessionId, hostRef) => { }); handle('sftp:list', (id, dir) => ssh.sftpList(id, dir)); handle('sftp:op', (id, op, a, b) => ssh.sftpOp(id, op, a, b)); +// Dateien für den SFTP-Upload auswählen (Mehrfachauswahl) +handle('sftp:pickUpload', async () => { + const r = await dialog.showOpenDialog(win, { title: i18n.t('Upload'), properties: ['openFile', 'multiSelections', 'showHiddenFiles'] }); + return r.canceled ? [] : r.filePaths.map((p) => ({ path: p, name: path.basename(p) })); +}); handle('sftp:transfer', async (id, dir, localPath, remotePath, transferId) => { let last = 0; await ssh.transfer(id, dir, localPath, remotePath, (done, total) => { diff --git a/src/renderer/app.js b/src/renderer/app.js index a1f1134..90d6817 100644 --- a/src/renderer/app.js +++ b/src/renderer/app.js @@ -2042,7 +2042,7 @@ class FilePane { - ${WEB ? `` : ``} + ${WEB ? `` : `${side === 'remote' ? `` : ''}`}
`); this.el.addEventListener('click', (e) => { const p = e.target.closest('[data-p]')?.dataset.p; @@ -2069,7 +2069,14 @@ class FilePane { }); } get other() { return this.side === 'local' ? this.sftp.remote : this.sftp.local; } - pickUpload() { + async pickUpload() { + if (!WEB) { + // Desktop: Dateiauswahl des Systems, Upload in den aktuellen Server-Ordner + const files = await call('sftp:pickUpload'); + for (const f of files) await this.sftp.transfer('upload', f.path, await this.join(this.cwd, f.name), f.name); + if (files.length) this.go(this.cwd); + return; + } const inp = h(''); inp.onchange = () => { this.uploadFiles([...inp.files]); inp.remove(); }; document.body.append(inp); diff --git a/src/renderer/styles.css b/src/renderer/styles.css index 8d70006..8ad1fc6 100644 --- a/src/renderer/styles.css +++ b/src/renderer/styles.css @@ -361,7 +361,7 @@ kbd { background: var(--card); border: 1px solid var(--border); border-bottom-wi /* Firewall */ .seg.sm button { padding: 4px 10px; font-size: 12px; } -.session.docker .sbar .seg { margin: 0 6px 0 0; flex: none; } +.session .sbar .seg { margin: 0 6px 0 0; flex: none; } .docker-table .dot.none { background: transparent; border: 1px solid var(--faint); } .docker-table .badge, .tpl-it .badge { font-size: 10px; font-weight: 600; padding: 1px 6px; border-radius: 6px; background: var(--icon-bg); color: var(--muted); margin-left: 4px; vertical-align: middle; } .stack-bar { display: flex; align-items: center; gap: 6px; padding: 8px 10px; border-bottom: 1px solid var(--border); flex-wrap: wrap; position: sticky; top: 0; background: var(--bg); z-index: 2; }