From e188fbef3626bcaee1411a7f9952571e405f76d1 Mon Sep 17 00:00:00 2001 From: loki5512344 Date: Sat, 11 Jul 2026 00:04:13 +0200 Subject: [PATCH] feat: FTPS, AppError, Site Manager, tests, multi-window, auto-clear, CI/CD, virtual scroll MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - FTPS: реализован FtpsClient через suppaftp + async-native-tls - AppError: кастомный enum с Serialize вместо Result - Site Manager UI: создание/редактирование/удаление сайтов - Тесты: 53 тестов (domain, storage, transfer, fs, remote) - Multi-window: новое окно + сохранение геометрии - Auto-clear: воркер чистит завершённые задачи по таймеру - CI/CD: 3-ступенчатый пайплайн (lint→build→test) с кэшированием - Virtual scroll: fileTable с рендером только видимых строк - UI: исправлены close-кнопки, color-scheme для select, скриншоты в README --- .cargo/config.toml | 2 + .github/workflows/rust.yml | 77 +- README.md | 17 +- docs/img/connect_screen.png | Bin 0 -> 25927 bytes docs/img/settings_screen.png | Bin 0 -> 32102 bytes docs/img/start_screen.png | Bin 0 -> 46674 bytes frontend/css/components.css | 8 +- frontend/css/layout.css | 16 +- frontend/js/components/connectDialog.js | 2 +- frontend/js/components/fileTable.js | 271 ++- frontend/js/components/paneLayout.js | 2 +- frontend/js/components/settingsDialog.js | 9 +- frontend/js/components/siteManager.js | 374 ++++ frontend/js/components/tabs.js | 2 +- frontend/js/components/toolbar.js | 5 + frontend/js/components/welcome.js | 5 + frontend/js/i18n/en.js | 16 + frontend/js/ipc.js | 1 + frontend/js/main.js | 5 + frontend/js/settingsActions.js | 3 + frontend/js/store.js | 1 + src/commands.rs | 363 +++- src/domain/connection.rs | 50 + src/domain/error.rs | 105 + src/domain/file_entry.rs | 46 + src/domain/mod.rs | 2 + src/domain/site.rs | 53 + src/domain/transfer.rs | 85 + src/domain/window_state.rs | 12 + src/fs/local.rs | 114 ++ src/fs/remote.rs | 78 + src/gen/schemas/linux-schema.json | 2358 ++++++++++++++++++++++ src/i18n/strings/common.rs | 236 ++- src/i18n/strings/dialogs.rs | 14 +- src/i18n/strings/panels.rs | 154 +- src/i18n/strings/settings.rs | 181 +- src/i18n/strings/toolbar.rs | 84 +- src/lib.rs | 55 +- src/protocols/ftp/mod.rs | 75 +- src/protocols/ftp/ops.rs | 225 ++- src/protocols/ftp/transfer.rs | 150 +- src/protocols/mod.rs | 1 + src/storage/db/bookmarks.rs | 2 +- src/storage/db/history.rs | 2 +- src/storage/db/mod.rs | 157 +- src/storage/db/settings.rs | 2 +- src/storage/db/sites.rs | 2 +- src/tauri.conf.json | 1 + src/tests/commands_test.rs | 110 + src/transfer/progress.rs | 35 + src/transfer/queue.rs | 112 + src/transfer/worker.rs | 31 +- 52 files changed, 5188 insertions(+), 523 deletions(-) create mode 100644 .cargo/config.toml create mode 100644 docs/img/connect_screen.png create mode 100644 docs/img/settings_screen.png create mode 100644 docs/img/start_screen.png create mode 100644 frontend/js/components/siteManager.js create mode 100644 src/domain/error.rs create mode 100644 src/domain/window_state.rs create mode 100644 src/gen/schemas/linux-schema.json create mode 100644 src/tests/commands_test.rs diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..39dc687 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +jobs = 6 diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 9fd45e0..64560bb 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -10,13 +10,74 @@ env: CARGO_TERM_COLOR: always jobs: - build: - + lint: runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Build - run: cargo build --verbose - - name: Run tests - run: cargo test --verbose + - uses: actions/checkout@v4 + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + libwebkit2gtk-4.1-dev \ + libjavascriptcoregtk-4.1-dev \ + libsoup-3.0-dev \ + libgtk-3-dev \ + libappindicator3-dev \ + librsvg2-dev \ + patchelf \ + libssl-dev \ + libdbus-1-dev + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy, rustfmt + - uses: Swatinem/rust-cache@v2 + - name: Check formatting + run: cargo fmt --check + - name: Lint with clippy + run: cargo clippy -- -D warnings + + build: + runs-on: ubuntu-latest + needs: [lint] + steps: + - uses: actions/checkout@v4 + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + libwebkit2gtk-4.1-dev \ + libjavascriptcoregtk-4.1-dev \ + libsoup-3.0-dev \ + libgtk-3-dev \ + libappindicator3-dev \ + librsvg2-dev \ + patchelf \ + libssl-dev \ + libdbus-1-dev + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - name: Build (release) + run: cargo build --release + + test: + runs-on: ubuntu-latest + needs: [build] + steps: + - uses: actions/checkout@v4 + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + libwebkit2gtk-4.1-dev \ + libjavascriptcoregtk-4.1-dev \ + libsoup-3.0-dev \ + libgtk-3-dev \ + libappindicator3-dev \ + librsvg2-dev \ + patchelf \ + libssl-dev \ + libdbus-1-dev + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - name: Run tests + run: cargo test diff --git a/README.md b/README.md index 5eab2fc..bf7eb70 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,11 @@ FTP/SFTP клиент на Tauri 2: бэкенд на Rust, фронтенд — vanilla HTML/CSS/JS. +

+ Wherry main screen +
Welcome-экран с сохранёнными сайтами и историей подключений +

+ ## Стек - **Tauri 2** — нативная оболочка (Rust-бэкенд + WebView-фронтенд) @@ -23,7 +28,15 @@ FTP/SFTP клиент на Tauri 2: бэкенд на Rust, фронтенд — |----------|--------------| | SFTP | реализован | | FTP | реализован | -| FTPS | заглушка | +| FTPS | реализован | + +## Скриншоты + +

+ Connect dialog + Settings screen +
Диалог подключения (слева) и окно настроек (справа) +

## Возможности @@ -34,8 +47,6 @@ FTP/SFTP клиент на Tauri 2: бэкенд на Rust, фронтенд — - Welcome-экран: сохранённые сайты, недавние подключения, шорткаты - Settings: General / Appearance / Connections / History / Security / Transfers / About -В разработке: полноценная реализация FTPS, Site Manager UI (создание/редактирование сайтов). - ## Разработка ```bash diff --git a/docs/img/connect_screen.png b/docs/img/connect_screen.png new file mode 100644 index 0000000000000000000000000000000000000000..e375e16edfa24050b52b350f095f33c19c42979f GIT binary patch literal 25927 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%0D^ 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 bIi6wD+tNpp?VT}vpXk{WS!CYhS0DZl5YW}f literal 0 HcmV?d00001 diff --git a/docs/img/start_screen.png b/docs/img/start_screen.png new file mode 100644 index 0000000000000000000000000000000000000000..d4828fc49b7c2b727200c4b069ebdee332bbc13e GIT binary patch literal 46674 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
diff --git a/frontend/js/components/fileTable.js b/frontend/js/components/fileTable.js index d5c738c..3e89668 100644 --- a/frontend/js/components/fileTable.js +++ b/frontend/js/components/fileTable.js @@ -1,6 +1,3 @@ -// Reusable file listing table shared by the Local and Remote panes — mirrors -// the old src/ui/panels/file_pane module (table.rs/row.rs/sort.rs collapsed -// into one file since there's no split-module pressure in JS). import { t } from "../i18n.js"; import { iconMarkup, fileIconFor } from "../icons.js"; import { formatSize, formatTime } from "../format.js"; @@ -8,6 +5,11 @@ import { makeDraggable, makeDropTarget } from "../dnd.js"; import { showContextMenu } from "./contextMenu.js"; import { escapeHtml } from "../dom.js"; +const ROW_HEIGHT = 32; +const OVERSCAN = 10; + +let rafId = null; + function sortEntries(entries, sort) { const dotdotIdx = entries.findIndex((e) => e.name === ".."); const dotdot = dotdotIdx >= 0 ? entries[dotdotIdx] : null; @@ -57,29 +59,64 @@ function sortHeaderHtml(label, col, sort) { return ``; } -/** - * opts: - * - entries: FileEntry[] - * - selected: string[] (names of selected entries) - * - anchor: string|null (name shift-click range selection extends from) - * - sort: { col, dir } - * - onSort(nextSort) - * - onSelect(names, anchor) - * - onOpen(name) - * - dragPayload(entry) => payload|null - * - onDropOnEntry(entry, payload) only called for dir/".." rows - * - onHoverOpen(entry) spring-loaded open: fires after a drag lingers on - * a dir/".." row for HOVER_OPEN_DELAY, without - * ending the drag -- only called for dir/".." rows - * - contextMenuItems(entry, selectedEntries) => menu items for showContextMenu, or null to skip - */ -export function renderFileTable(container, opts) { - const scrollPos = container.querySelector(".file-table-body")?.scrollTop ?? 0; +function computeVisibleRange(scrollTop, viewportHeight, totalItems) { + const start = Math.max(0, Math.floor(scrollTop / ROW_HEIGHT) - OVERSCAN); + const end = Math.min(totalItems, Math.ceil((scrollTop + viewportHeight) / ROW_HEIGHT) + OVERSCAN); + return { start, end }; +} + +function getSignature(sorted, sort) { + const len = sorted.length; + if (len === 0) return `0:${sort.col}:${sort.dir}`; + const mid = Math.min(len >> 1, len - 1); + return `${len}:${sort.col}:${sort.dir}:${sorted[0].name}:${sorted[mid].name}:${sorted[len - 1].name}`; +} + +function initStructure(container) { + let cache = container._fileTableCache; + if (cache) return cache; + container.innerHTML = ""; container.classList.add("file-table-wrap"); const header = document.createElement("div"); header.className = "file-table-header"; + container.appendChild(header); + + const body = document.createElement("div"); + body.className = "file-table-body"; + container.appendChild(body); + + const spacer = document.createElement("div"); + spacer.style.position = "relative"; + body.appendChild(spacer); + + cache = { + header, + body, + spacer, + lastSignature: null, + sorted: [], + selectableNames: [], + opts: null, + }; + container._fileTableCache = cache; + + body.addEventListener("scroll", () => { + if (rafId) return; + rafId = requestAnimationFrame(() => { + rafId = null; + const c = container._fileTableCache; + if (c && c.sorted.length > 0) { + updateVisibleRows(c); + } + }); + }); + + return cache; +} + +function updateHeader(header, opts) { header.innerHTML = ` ${sortHeaderHtml(t("panels.colName"), "name", opts.sort)} ${sortHeaderHtml(t("panels.colModified"), "modified", opts.sort)} @@ -96,81 +133,141 @@ export function renderFileTable(container, opts) { opts.onSort(next); }); }); - container.appendChild(header); +} - const body = document.createElement("div"); - body.className = "file-table-body"; - container.appendChild(body); +function createRowElement(entry, index, cache) { + const row = document.createElement("div"); + row.className = "file-row"; + row.dataset.index = index; - const sorted = sortEntries(opts.entries, opts.sort); - const selectableNames = sorted.filter((e) => e.name !== "..").map((e) => e.name); + const current = cache.opts; + if (current.selected.includes(entry.name)) row.classList.add("selected"); - for (const entry of sorted) { - const row = document.createElement("div"); - row.className = "file-row"; - if (opts.selected.includes(entry.name)) row.classList.add("selected"); + row.style.position = "absolute"; + row.style.top = index * ROW_HEIGHT + "px"; + row.style.left = "0"; + row.style.right = "0"; + row.style.height = ROW_HEIGHT + "px"; - const [iconName, iconColor] = rowIcon(entry); - const nameCol = entry.name === ".." ? "text-hint" : "text-primary"; + const [iconName, iconColor] = rowIcon(entry); + const nameCol = entry.name === ".." ? "text-hint" : "text-primary"; - row.innerHTML = ` -
- ${iconMarkup(iconName, 15)} - ${escapeHtml(entry.name)} -
-
${formatTime(entry.modified)}
-
${typeLabel(entry)}
-
${formatSize(entry.size)}
- `; + row.innerHTML = ` +
+ ${iconMarkup(iconName, 15)} + ${escapeHtml(entry.name)} +
+
${formatTime(entry.modified)}
+
${typeLabel(entry)}
+
${formatSize(entry.size)}
+ `; - row.addEventListener("click", (e) => { - if (entry.name === "..") { - opts.onSelect([], null); - return; - } - const idx = selectableNames.indexOf(entry.name); - if (e.shiftKey && opts.anchor && selectableNames.includes(opts.anchor)) { - const anchorIdx = selectableNames.indexOf(opts.anchor); - const [lo, hi] = anchorIdx < idx ? [anchorIdx, idx] : [idx, anchorIdx]; - opts.onSelect(selectableNames.slice(lo, hi + 1), opts.anchor); - } else if (e.ctrlKey || e.metaKey) { - const next = new Set(opts.selected); - if (next.has(entry.name)) next.delete(entry.name); - else next.add(entry.name); - opts.onSelect(selectableNames.filter((n) => next.has(n)), entry.name); - } else { - opts.onSelect([entry.name], entry.name); + row.addEventListener("click", (e) => { + const opts = cache.opts; + if (entry.name === "..") { + opts.onSelect([], null); + return; + } + const idx = cache.selectableNames.indexOf(entry.name); + if (e.shiftKey && opts.anchor && cache.selectableNames.includes(opts.anchor)) { + const anchorIdx = cache.selectableNames.indexOf(opts.anchor); + const [lo, hi] = anchorIdx < idx ? [anchorIdx, idx] : [idx, anchorIdx]; + opts.onSelect(cache.selectableNames.slice(lo, hi + 1), opts.anchor); + } else if (e.ctrlKey || e.metaKey) { + const next = new Set(opts.selected); + if (next.has(entry.name)) next.delete(entry.name); + else next.add(entry.name); + opts.onSelect(cache.selectableNames.filter((n) => next.has(n)), entry.name); + } else { + opts.onSelect([entry.name], entry.name); + } + }); + row.addEventListener("dblclick", () => cache.opts.onOpen(entry.name)); + + if (entry.name !== "..") { + row.addEventListener("contextmenu", (e) => { + e.preventDefault(); + const opts = cache.opts; + let selection = opts.selected; + if (!selection.includes(entry.name)) { + selection = [entry.name]; + opts.onSelect(selection, entry.name); } + const selectedEntries = cache.sorted.filter((en) => selection.includes(en.name)); + const items = opts.contextMenuItems?.(entry, selectedEntries); + if (items) showContextMenu(e.clientX, e.clientY, items); }); - row.addEventListener("dblclick", () => opts.onOpen(entry.name)); - if (entry.name !== "..") { - row.addEventListener("contextmenu", (e) => { - e.preventDefault(); - let selection = opts.selected; - if (!selection.includes(entry.name)) { - selection = [entry.name]; - opts.onSelect(selection, entry.name); - } - const selectedEntries = sorted.filter((en) => selection.includes(en.name)); - const items = opts.contextMenuItems?.(entry, selectedEntries); - if (items) showContextMenu(e.clientX, e.clientY, items); - }); - - const payload = opts.dragPayload?.(entry); - if (payload) makeDraggable(row.querySelector(".file-row-name"), entry, payload); - } - - if (entry.kind === "dir" || entry.name === "..") { - makeDropTarget(row, { - onDrop: (payload) => opts.onDropOnEntry?.(entry, payload), - onHoverChange: (hover) => row.classList.toggle("drag-hover", hover), - onHoverHold: () => opts.onHoverOpen?.(entry), - }); - } - - body.appendChild(row); + const payload = current.dragPayload?.(entry); + if (payload) makeDraggable(row.querySelector(".file-row-name"), entry, payload); } - body.scrollTop = scrollPos; + if (entry.kind === "dir" || entry.name === "..") { + makeDropTarget(row, { + onDrop: (payload) => cache.opts.onDropOnEntry?.(entry, payload), + onHoverChange: (hover) => row.classList.toggle("drag-hover", hover), + onHoverHold: () => cache.opts.onHoverOpen?.(entry), + }); + } + + return row; +} + +function updateVisibleRows(cache) { + const sorted = cache.sorted; + if (sorted.length === 0) return; + + const { start, end } = computeVisibleRange( + cache.body.scrollTop, + cache.body.clientHeight, + sorted.length, + ); + + const existing = cache.spacer.querySelectorAll(".file-row"); + for (const row of existing) { + const idx = parseInt(row.dataset.index, 10); + if (idx < start || idx >= end) { + row.remove(); + } + } + + for (let i = start; i < end; i++) { + if (!cache.spacer.querySelector(`.file-row[data-index="${i}"]`)) { + const row = createRowElement(sorted[i], i, cache); + cache.spacer.appendChild(row); + } + } +} + +function updateSelection(cache, selected) { + const rows = cache.spacer.querySelectorAll(".file-row"); + for (const row of rows) { + const idx = parseInt(row.dataset.index, 10); + const entry = cache.sorted[idx]; + if (entry) { + row.classList.toggle("selected", selected.includes(entry.name)); + } + } +} + +export function renderFileTable(container, opts) { + const cache = initStructure(container); + cache.opts = opts; + + updateHeader(cache.header, opts); + + const sorted = sortEntries(opts.entries, opts.sort); + const sig = getSignature(sorted, opts.sort); + + if (sig !== cache.lastSignature) { + cache.lastSignature = sig; + cache.sorted = sorted; + cache.selectableNames = sorted.filter((e) => e.name !== "..").map((e) => e.name); + cache.spacer.style.height = sorted.length * ROW_HEIGHT + "px"; + cache.body.scrollTop = 0; + cache.spacer.innerHTML = ""; + updateVisibleRows(cache); + } else { + updateSelection(cache, opts.selected); + } } diff --git a/frontend/js/components/paneLayout.js b/frontend/js/components/paneLayout.js index 2e959b9..5fb5fb5 100644 --- a/frontend/js/components/paneLayout.js +++ b/frontend/js/components/paneLayout.js @@ -64,7 +64,7 @@ function createPaneCell(pane) { const closeBtn = document.createElement("button"); closeBtn.className = "pane-close-btn"; closeBtn.title = "Close"; - closeBtn.innerHTML = iconMarkup("close", 10); + closeBtn.innerHTML = iconMarkup("close", 13); closeBtn.addEventListener("click", (e) => { e.stopPropagation(); closePane(pane.id); }); header.appendChild(closeBtn); } diff --git a/frontend/js/components/settingsDialog.js b/frontend/js/components/settingsDialog.js index 4d90902..e82a970 100644 --- a/frontend/js/components/settingsDialog.js +++ b/frontend/js/components/settingsDialog.js @@ -22,6 +22,7 @@ import { setLanguage, setTheme, } from "../settingsActions.js"; +import { openSiteManager } from "./siteManager.js"; const LANG_OPTIONS = [ ["en", "English"], @@ -176,6 +177,7 @@ function sectionConnections() {
${escapeHtml(s.name)}
${escapeHtml(s.username)}@${escapeHtml(s.host)}:${s.port}
+
`, ) @@ -348,7 +350,7 @@ function build() {
${iconMarkup("settings", 16)} ${t("settings.title")} - +
@@ -408,6 +410,11 @@ function wireContentActions(root) { }); }); + root.querySelectorAll("[data-action='edit-site']").forEach((btn) => { + btn.addEventListener("click", () => { + openSiteManager(btn.dataset.id); + }); + }); root.querySelectorAll("[data-action='delete-site']").forEach((btn) => { btn.addEventListener("click", async () => { await deleteSite(btn.dataset.id); diff --git a/frontend/js/components/siteManager.js b/frontend/js/components/siteManager.js new file mode 100644 index 0000000..258e45a --- /dev/null +++ b/frontend/js/components/siteManager.js @@ -0,0 +1,374 @@ +import { state, notify } from "../store.js"; +import { t } from "../i18n.js"; +import { iconMarkup } from "../icons.js"; +import { escapeHtml } from "../dom.js"; +import { connectFromSite, PROTOCOL_LABELS } from "../connectActions.js"; +import * as ipc from "../ipc.js"; + +const PROTOCOLS = ["sftp", "ftp", "ftps"]; +const DEFAULT_PORTS = { sftp: 22, ftp: 21, ftps: 990 }; + +let overlayEl = null; +let viewMode = "list"; +let form = emptyForm(); +let editingId = null; +let saving = false; +let deleteConfirmId = null; + +function emptyForm() { + return { + name: "", + protocol: "sftp", + host: "", + port: "", + username: "", + password: "", + keyPath: "", + folder: "", + note: "", + }; +} + +export function openSiteManager(siteId) { + const site = state.sites.find((s) => s.id === siteId); + if (!site) return; + editingId = siteId; + form = { + name: site.name, + protocol: site.protocol, + host: site.host, + port: String(site.port), + username: site.username, + password: site.password ?? "", + keyPath: site.keyPath ?? "", + folder: site.folder ?? "", + note: site.note ?? "", + }; + viewMode = "form"; + saving = false; + deleteConfirmId = null; + state.showSettingsDialog = false; + state.showSiteManager = true; + notify(); +} + +export function openSiteManagerNew() { + editingId = null; + form = emptyForm(); + viewMode = "list"; + saving = false; + deleteConfirmId = null; + state.showSiteManager = true; + notify(); +} + +function close() { + state.showSiteManager = false; + overlayEl?.remove(); + overlayEl = null; + notify(); +} + +function switchToList() { + viewMode = "list"; + deleteConfirmId = null; + notify(); +} + +async function saveCurrent() { + if (saving) return; + const name = form.name.trim(); + const host = form.host.trim(); + const username = form.username.trim(); + if (!name || !host || !username) return; + + let port = DEFAULT_PORTS[form.protocol]; + if (form.port.trim()) { + const parsed = Number(form.port); + if (!Number.isInteger(parsed) || parsed < 1 || parsed > 65535) return; + port = parsed; + } + + saving = true; + notify(); + + const site = { + id: editingId || crypto.randomUUID(), + name, + protocol: form.protocol, + host, + port, + username, + password: form.password || null, + keyPath: form.keyPath || null, + folder: form.folder || null, + note: form.note || null, + }; + + try { + await ipc.saveSite(site); + state.sites = await ipc.listSites(); + state.statusMessage = t("siteManager.saved"); + viewMode = "list"; + saving = false; + notify(); + } catch { + saving = false; + notify(); + } +} + +async function deleteSiteAction(id) { + const site = state.sites.find((s) => s.id === id); + await ipc.deleteSite(id); + await ipc.deletePassword(id); + state.sites = state.sites.filter((s) => s.id !== id); + if (site) state.statusMessage = `Removed ${site.name}`; + notify(); +} + +async function browseKeyFile() { + try { + const dialog = window.__TAURI__.dialog; + const path = await dialog.open({ title: "Choose SSH key", multiple: false, directory: false }); + if (typeof path === "string") { + form.keyPath = path; + const input = overlayEl?.querySelector("[data-field=keyPath]"); + if (input) input.value = path; + } + } catch { + /* dialog plugin unavailable / user cancelled */ + } +} + +function build() { + const overlay = document.createElement("div"); + overlay.className = "overlay"; + overlay.addEventListener("mousedown", (e) => { + if (e.target === overlay) close(); + }); + + const dialog = document.createElement("div"); + dialog.className = "dialog"; + dialog.style.width = "440px"; + dialog.addEventListener("mousedown", (e) => e.stopPropagation()); + dialog.addEventListener("keydown", (e) => { + if (e.key === "Enter" && viewMode === "form") saveCurrent(); + }); + + dialog.innerHTML = ` +
+ ${iconMarkup("serverSquare", 16)} + ${t("siteManager.title")} + +
+
+ `; + + dialog.querySelector('[data-action="close"]').addEventListener("click", close); + + overlay.appendChild(dialog); + return overlay; +} + +function renderList() { + const title = overlayEl.querySelector('[data-role="title"]'); + title.textContent = t("siteManager.title"); + + const body = overlayEl.querySelector('[data-role="body"]'); + + let html = ""; + if (!state.sites.length) { + html += `
${t("siteManager.noSites")}
`; + } else { + html += state.sites.map( + (s) => ` +
+
+
+ ${PROTOCOL_LABELS[s.protocol] ?? s.protocol} + ${escapeHtml(s.name)} +
+
${escapeHtml(s.username)}@${escapeHtml(s.host)}:${s.port}
+
+
+ + + +
+
`, + ).join(""); + } + + html += ` +
+ +
+ `; + + body.innerHTML = html; + + body.querySelectorAll("[data-action='sm-connect']").forEach((btn) => { + btn.addEventListener("click", async () => { + const site = state.sites.find((s) => s.id === btn.dataset.id); + if (site) { + close(); + await connectFromSite(site); + } + }); + }); + + body.querySelectorAll("[data-action='sm-edit']").forEach((btn) => { + btn.addEventListener("click", () => openSiteManager(btn.dataset.id)); + }); + + body.querySelectorAll("[data-action='sm-delete']").forEach((btn) => { + btn.addEventListener("click", async () => { + await deleteSiteAction(btn.dataset.id); + if (overlayEl) renderList(); + }); + }); + + body.querySelector("[data-action='sm-add']").addEventListener("click", () => { + editingId = null; + form = emptyForm(); + viewMode = "form"; + notify(); + }); +} + +function renderForm() { + const title = overlayEl.querySelector('[data-role="title"]'); + title.textContent = editingId ? t("siteManager.editSite") : t("siteManager.addSite"); + + const body = overlayEl.querySelector('[data-role="body"]'); + + body.innerHTML = ` +
+ ${t("siteManager.name")} + +
+ +
+ ${t("siteManager.protocol")} +
+ ${PROTOCOLS.map((p) => ``).join("")} +
+
+ +
+ ${t("connect.host")} + +
+ +
+
+ ${t("connect.username")} + +
+
+ ${t("connect.port")} + +
+
+ +
+ ${t("connect.password")} +
+ + +
+
+ +
+

${t("siteManager.keyHint")}

+
+ ${t("connect.keyFile")} +
+ + +
+
+
+ +
+ ${t("siteManager.folder")} + +
+ +
+ ${t("siteManager.note")} + +
+ + + `; + + body.querySelector('[data-action="cancel"]').addEventListener("click", switchToList); + body.querySelector('[data-action="save"]').addEventListener("click", saveCurrent); + + body.querySelectorAll("[data-field]").forEach((input) => { + input.addEventListener("input", () => { + form[input.dataset.field] = input.value; + }); + }); + + const passInput = body.querySelector('[data-field="password"]'); + const toggleBtn = body.querySelector('[data-action="toggle-pass"]'); + if (toggleBtn && passInput) { + toggleBtn.addEventListener("click", () => { + const showing = passInput.type === "text"; + passInput.type = showing ? "password" : "text"; + toggleBtn.innerHTML = iconMarkup(showing ? "eye" : "eyeClosed", 15); + }); + } + + const browseBtn = body.querySelector('[data-action="browse"]'); + if (browseBtn) browseBtn.addEventListener("click", browseKeyFile); + + body.querySelectorAll("[data-protocol]").forEach((btn) => { + btn.addEventListener("click", () => { + const proto = btn.dataset.protocol; + form.protocol = proto; + const portInput = body.querySelector('[data-field="port"]'); + if (!form.port) { + portInput.placeholder = String(DEFAULT_PORTS[proto]); + } + body.querySelectorAll("[data-protocol]").forEach((b) => b.classList.toggle("active", b === btn)); + const keySection = body.querySelector('[data-role="key-section"]'); + if (keySection) keySection.style.display = proto === "sftp" ? "block" : "none"; + }); + }); + + setTimeout(() => body.querySelector('[data-field="name"]')?.focus(), 0); +} + +export function renderSiteManager() { + if (!state.showSiteManager) { + if (overlayEl) { + overlayEl.remove(); + overlayEl = null; + } + return; + } + + if (!overlayEl) { + overlayEl = build(); + document.body.appendChild(overlayEl); + } + + if (viewMode === "list") { + renderList(); + } else { + renderForm(); + } +} diff --git a/frontend/js/components/tabs.js b/frontend/js/components/tabs.js index 07ff07a..07d1ee3 100644 --- a/frontend/js/components/tabs.js +++ b/frontend/js/components/tabs.js @@ -65,7 +65,7 @@ function createTab(id, label, status, closable) { const close = document.createElement("button"); close.type = "button"; close.className = "tab-close"; - close.innerHTML = iconMarkup("close", 10); + close.innerHTML = iconMarkup("close", 13); close.title = "Close"; close.addEventListener("click", (e) => { e.stopPropagation(); diff --git a/frontend/js/components/toolbar.js b/frontend/js/components/toolbar.js index 5dade7a..4cbb010 100644 --- a/frontend/js/components/toolbar.js +++ b/frontend/js/components/toolbar.js @@ -1,6 +1,7 @@ import { state, notify, activeTab } from "../store.js"; import { t } from "../i18n.js"; import { iconMarkup } from "../icons.js"; +import * as ipc from "../ipc.js"; import { openNew } from "./connectDialog.js"; import { toggle as toggleHistory } from "./historyPopup.js"; import { openMkdir, openDelete, openRename } from "./opDialogs.js"; @@ -49,6 +50,7 @@ export function renderToolbar(container) { +
@@ -90,6 +92,9 @@ export function renderToolbar(container) { state.opTarget = state.activePane; openRename(names[0]); }); + container.querySelector('[data-action="new-window"]').addEventListener("click", () => { + ipc.newWindow(); + }); container.querySelector('[data-action="history"]').addEventListener("click", (e) => { toggleHistory(e.currentTarget); }); diff --git a/frontend/js/components/welcome.js b/frontend/js/components/welcome.js index e8aa64f..60c5185 100644 --- a/frontend/js/components/welcome.js +++ b/frontend/js/components/welcome.js @@ -4,6 +4,7 @@ import { iconMarkup } from "../icons.js"; import { renderHistoryRows } from "./historyList.js"; import { openNew } from "./connectDialog.js"; import { openSettings } from "./settingsDialog.js"; +import { openSiteManagerNew } from "./siteManager.js"; import { connectFromSite, PROTOCOL_LABELS } from "../connectActions.js"; import { escapeHtml } from "../dom.js"; import { shortcutLabel } from "../platform.js"; @@ -31,6 +32,9 @@ export function renderWelcome(container) {

cZP26B~3_Bqo_`|e;zQ~QVzP-Y`?XRRCaAB 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 literal 0 HcmV?d00001 diff --git a/frontend/css/components.css b/frontend/css/components.css index 44cf84f..ea1086b 100644 --- a/frontend/css/components.css +++ b/frontend/css/components.css @@ -414,8 +414,8 @@ flex: 1; } .dialog-close { - width: 24px; - height: 24px; + width: 28px; + height: 28px; border-radius: var(--radius-sm); border: none; background: transparent; @@ -541,6 +541,10 @@ cursor: pointer; min-width: 180px; } +.settings-select option { + background: var(--bg-panel); + color: var(--text-primary); +} .settings-select:hover { border-color: var(--accent); } diff --git a/frontend/css/layout.css b/frontend/css/layout.css index d49b920..d2d47c2 100644 --- a/frontend/css/layout.css +++ b/frontend/css/layout.css @@ -305,8 +305,8 @@ color: var(--text-primary); } .tab-close { - width: 16px; - height: 16px; + width: 22px; + height: 22px; border-radius: 4px; border: none; background: transparent; @@ -314,13 +314,15 @@ display: flex; align-items: center; justify-content: center; - font-size: 12px; + font-size: 13px; line-height: 1; cursor: pointer; + opacity: 0.7; } .tab-close:hover { background: rgba(255, 255, 255, 0.12); color: var(--text-primary); + opacity: 1; } /* localPane.js/remotePane.js render straight into this element (there's no @@ -708,17 +710,17 @@ html[data-platform="linux"] ::-webkit-scrollbar { } .pane-split-btn, .pane-close-btn { - width: 18px; - height: 18px; + width: 24px; + height: 24px; border: none; - border-radius: 3px; + border-radius: 4px; background: transparent; color: var(--text-hint); display: flex; align-items: center; justify-content: center; cursor: pointer; - font-size: 10px; + font-size: 13px; padding: 0; } .pane-split-btn:hover, diff --git a/frontend/js/components/connectDialog.js b/frontend/js/components/connectDialog.js index a0a5fef..b578126 100644 --- a/frontend/js/components/connectDialog.js +++ b/frontend/js/components/connectDialog.js @@ -94,7 +94,7 @@ function build() {