feat: move terminal settings, look and ssh tools into ssh-terminal plugin

This commit is contained in:
LukeGus committed 2026-09-29 02:38:37 -05:00
1 parent ffa872ebd3
commit d9bba10612
242 files changed
+25071 -7207

No files matched your search

+6
View File
@@ -21,6 +21,12 @@
"scpLegacy": {
"label": "SCP Legacy Mode"
}
},
"user": {
"transferConcurrency": {
"label": "Simultaneous File Transfers",
"description": "How many files the side by side local/remote manager uploads or downloads at the same time. Lower this if your server limits SFTP channels."
}
}
},
"hostCapability": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "SCP Legacy-modus"
}
},
"user": {
"transferConcurrency": {
"label": "Gelyktydige lêeroordragte",
"description": "Hoeveel lêers die sy-aan-sy plaaslike/afgeleë bestuurder gelyktydig oplaai of aflaai. Verlaag dit as jou bediener SFTP-kanale beperk."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "وضع SCP القديم"
}
},
"user": {
"transferConcurrency": {
"label": "نقل الملفات المتزامن",
"description": "كم عدد الملفات التي يقوم مدير الملفات المحلي/البعيد بتحميلها أو تنزيلها في نفس الوقت؟ قلل هذا العدد إذا كان خادمك يحد من قنوات SFTP."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "SCP Legacy режим"
}
},
"user": {
"transferConcurrency": {
"label": "Едновременно прехвърляне на файлове",
"description": "Колко файла едновременно качва или изтегля локалният/отдалечен мениджър. Намалете това, ако вашият сървър ограничава SFTP каналите."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "SCP লিগ্যাসি মোড"
}
},
"user": {
"transferConcurrency": {
"label": "একযোগে ফাইল স্থানান্তর",
"description": "সাইড বাই সাইড লোকাল/রিমোট ম্যানেজার একই সময়ে কতগুলো ফাইল আপলোড বা ডাউনলোড করে। আপনার সার্ভার যদি SFTP চ্যানেল সীমিত করে, তবে এই সংখ্যাটি কমিয়ে দিন।"
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "Mode Llegat de SCP"
}
},
"user": {
"transferConcurrency": {
"label": "Transferències simultànies de fitxers",
"description": "Quants fitxers puja o descarrega el gestor local/remot en paral·lel alhora. Redueix aquest valor si el teu servidor limita els canals SFTP."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "Starší režim SCP"
}
},
"user": {
"transferConcurrency": {
"label": "Současné přenosy souborů",
"description": "Kolik souborů souběžně nahrává nebo stahuje lokální/vzdálený správce. Snižte tuto hodnotu, pokud váš server omezuje SFTP kanály."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "SCP Legacy-tilstand"
}
},
"user": {
"transferConcurrency": {
"label": "Samtidige filoverførsler",
"description": "Hvor mange filer den side om side lokale/fjernstyrede administrator uploader eller downloader på samme tid. Sænk dette, hvis din server begrænser SFTP-kanaler."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "SCP-Legacy-Modus"
}
},
"user": {
"transferConcurrency": {
"label": "Gleichzeitige Dateiübertragungen",
"description": "Wie viele Dateien der lokale/Remote-Manager gleichzeitig hoch- oder herunterlädt. Verringern Sie diesen Wert, wenn Ihr Server die Anzahl der SFTP-Kanäle begrenzt."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "Λειτουργία παλαιού τύπου SCP"
}
},
"user": {
"transferConcurrency": {
"label": "Ταυτόχρονες μεταφορές αρχείων",
"description": "Πόσα αρχεία ανεβάζει ή κατεβάζει ο τοπικός/απομακρυσμένος διαχειριστής παράλληλων λήψεων ταυτόχρονα. Μειώστε αυτό το ποσό εάν ο διακομιστής σας περιορίζει τα κανάλια SFTP."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "Modo SCP heredado"
}
},
"user": {
"transferConcurrency": {
"label": "Transferencias simultáneas de archivos",
"description": "¿Cuántos archivos sube o descarga simultáneamente el gestor local/remoto? Reduzca este valor si su servidor limita los canales SFTP."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "SCP:n vanha tila"
}
},
"user": {
"transferConcurrency": {
"label": "Samanaikaiset tiedostonsiirrot",
"description": "Kuinka monta tiedostoa rinnakkainen paikallinen/etähallinta lataa tai lataa samanaikaisesti. Laske tätä arvoa, jos palvelimesi rajoittaa SFTP-kanavia."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "Mode SCP hérité"
}
},
"user": {
"transferConcurrency": {
"label": "Transferts de fichiers simultanés",
"description": "Nombre de fichiers que le gestionnaire local/distant côte à côte télécharge ou charge simultanément. Réduisez cette valeur si votre serveur limite le nombre de canaux SFTP."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "מצב SCP Legacy"
}
},
"user": {
"transferConcurrency": {
"label": "העברות קבצים בו זמנית",
"description": "כמה קבצים מעלה או מוריד המנהל המקומי/מרחוק בו זמנית. יש להוריד ערך זה אם השרת שלך מגביל ערוצי SFTP."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "SCP लीगेसी मोड"
}
},
"user": {
"transferConcurrency": {
"label": "एक साथ फ़ाइल स्थानांतरण",
"description": "साइड-बाय-साइड लोकल/रिमोट मैनेजर एक ही समय में कितनी फाइलें अपलोड या डाउनलोड कर सकता है। यदि आपका सर्वर SFTP चैनलों को सीमित करता है तो इसे कम करें।"
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "SCP örökölt mód"
}
},
"user": {
"transferConcurrency": {
"label": "Egyidejű fájlátvitel",
"description": "Hány fájlt tölt fel vagy tölt le egyszerre az egymás melletti helyi/távoli kezelő. Csökkentse ezt az értéket, ha a szerver korlátozza az SFTP csatornákat."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "Mode Warisan SCP"
}
},
"user": {
"transferConcurrency": {
"label": "Transfer File Serentak",
"description": "Jumlah file yang diunggah atau diunduh oleh pengelola file lokal/jarak jauh secara bersamaan. Kurangi nilai ini jika server Anda membatasi saluran SFTP."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "Modalità SCP legacy"
}
},
"user": {
"transferConcurrency": {
"label": "Trasferimenti simultanei di file",
"description": "Quanti file il gestore locale/remoto affiancato carica o scarica contemporaneamente. Riduci questo valore se il tuo server limita i canali SFTP."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "SCP レガシーモード"
}
},
"user": {
"transferConcurrency": {
"label": "同時ファイル転送",
"description": "ローカル/リモートマネージャーが同時にアップロードまたはダウンロードできるファイルの数を指定します。サーバーがSFTPチャネルを制限している場合は、この値を小さくしてください。"
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "SCP 레거시 모드"
}
},
"user": {
"transferConcurrency": {
"label": "동시 파일 전송",
"description": "로컬/원격 파일 관리자가 동시에 업로드 또는 다운로드할 수 있는 파일 수를 지정합니다. 서버에서 SFTP 채널 수를 제한하는 경우 이 값을 낮추십시오."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "SCP Legacy-modus"
}
},
"user": {
"transferConcurrency": {
"label": "Gelijktijdige bestandsoverdracht",
"description": "Hoeveel bestanden de lokale/externe manager naast elkaar tegelijkertijd uploadt of downloadt. Verlaag deze waarde als uw server het aantal SFTP-kanalen beperkt."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "SCP Legacy-modus"
}
},
"user": {
"transferConcurrency": {
"label": "Samtidige filoverføringer",
"description": "Hvor mange filer den side om side lokale/fjernstyrte administratoren laster opp eller ned samtidig. Reduser dette hvis serveren din begrenser SFTP-kanaler."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "Tryb SCP Legacy"
}
},
"user": {
"transferConcurrency": {
"label": "Jednoczesne przesyłanie plików",
"description": "Ile plików lokalny/zdalny menedżer obok siebie przesyła lub pobiera jednocześnie? Zmniejsz tę wartość, jeśli Twój serwer ogranicza kanały SFTP."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "Modo Legado SCP"
}
},
"user": {
"transferConcurrency": {
"label": "Transferências simultâneas de arquivos",
"description": "Quantos arquivos o gerenciador local/remoto lado a lado carrega ou baixa simultaneamente? Diminua esse valor se o seu servidor limitar os canais SFTP."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "Modo SCP Legado"
}
},
"user": {
"transferConcurrency": {
"label": "Transferências simultâneas de ficheiros",
"description": "Quantos ficheiros o gestor local/remoto lado a lado carrega ou descarrega simultaneamente? Diminua este valor se o seu servidor limitar os canais SFTP."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "Modul SCP Legacy"
}
},
"user": {
"transferConcurrency": {
"label": "Transferuri simultane de fișiere",
"description": "Câte fișiere încarcă sau descarcă simultan managerul local/la distanță. Reduceți această valoare dacă serverul dvs. limitează canalele SFTP."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "Устаревший режим SCP"
}
},
"user": {
"transferConcurrency": {
"label": "Одновременная передача файлов",
"description": "Сколько файлов менеджер, работающий в режиме локального/удалённого доступа, может загружать или скачивать одновременно. Уменьшите это значение, если ваш сервер ограничивает количество SFTP-каналов."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "SCP Legacy Mode"
}
},
"user": {
"transferConcurrency": {
"label": "Истовремени пренос датотека",
"description": "Колико датотека локални/удаљени менаџер истовремено отпрема или преузима. Смањите ово ако ваш сервер ограничава SFTP канале."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "SCP Legacy-läge"
}
},
"user": {
"transferConcurrency": {
"label": "Samtidiga filöverföringar",
"description": "Hur många filer den sida vid sida lokala/fjärrstyrda hanteraren laddar upp eller laddar ner samtidigt. Sänk detta om din server begränsar SFTP-kanaler."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "โหมด SCP ดั้งเดิม"
}
},
"user": {
"transferConcurrency": {
"label": "การโอนไฟล์พร้อมกัน",
"description": "ตัวจัดการไฟล์แบบโลคอล/รีโมตที่ทำงานควบคู่กันไป สามารถอัปโหลดหรือดาวน์โหลดไฟล์ได้พร้อมกันกี่ไฟล์ ลดจำนวนไฟล์นี้ลงหากเซิร์ฟเวอร์ของคุณจำกัดจำนวนช่อง SFTP"
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "SCP Eski Modu"
}
},
"user": {
"transferConcurrency": {
"label": "Eşzamanlı Dosya Aktarımları",
"description": "Yan yana yerel/uzaktan yönetici tarafından aynı anda yüklenen veya indirilen dosya sayısı. Sunucunuz SFTP kanallarını sınırlandırıyorsa bu değeri düşürün."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "Застарілий режим SCP"
}
},
"user": {
"transferConcurrency": {
"label": "Одночасна передача файлів",
"description": "Скільки файлів одночасно завантажує або вивантажує локальний/віддалений менеджер. Зменште це значення, якщо ваш сервер обмежує кількість каналів SFTP."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "Chế độ SCP cũ"
}
},
"user": {
"transferConcurrency": {
"label": "Truyền tệp đồng thời",
"description": "Số lượng tệp mà trình quản lý cục bộ/từ xa song song tải lên hoặc tải xuống cùng lúc. Giảm giá trị này nếu máy chủ của bạn giới hạn số kênh SFTP."
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "SCP 传统模式"
}
},
"user": {
"transferConcurrency": {
"label": "同时文件传输",
"description": "本地/远程并排管理器同时上传或下载的文件数量。如果您的服务器限制 SFTP 通道,请降低此值。"
}
}
},
"nav": {
@@ -395,6 +395,12 @@
"scpLegacy": {
"label": "SCP 舊版模式"
}
},
"user": {
"transferConcurrency": {
"label": "同時文件傳輸",
"description": "本機/遠端並排管理器同時上傳或下載的檔案數量。如果您的伺服器限制 SFTP 通道,請降低此值。"
}
}
},
"nav": {
+11
View File
@@ -70,6 +70,17 @@
}
],
"settings": {
"user": [
{
"key": "transferConcurrency",
"type": "number",
"labelKey": "settings.user.transferConcurrency.label",
"descriptionKey": "settings.user.transferConcurrency.description",
"min": 1,
"max": 8,
"default": 4
}
],
"host": {
"editorGroup": "ssh",
"editorOrder": 60,
+4 -4
View File
@@ -584,7 +584,7 @@ export async function activate(ctx: PluginContext) {
let resolvedIp = ip;
let resolvedPort = port;
let resolvedUsername = username;
let resolvedTerminalConfig: Record<string, unknown> | undefined;
let resolvedSshOptions: PluginSshHost["sshOptions"];
let resolvedJumpHosts = jumpHosts;
let resolvedScpLegacy = false;
let resolvedUseSocks5 = useSocks5;
@@ -612,8 +612,8 @@ export async function activate(ctx: PluginContext) {
certPublicKey: (resolvedHost as { certPublicKey?: string })
.certPublicKey,
};
resolvedTerminalConfig = resolvedHost.terminalConfig as unknown as
Record<string, unknown> | undefined;
resolvedSshOptions =
resolvedHost.sshOptions as PluginSshHost["sshOptions"];
resolvedScpLegacy =
(await ctx.settings.getHost<boolean>(
Number(resolvedHost.id),
@@ -728,7 +728,7 @@ export async function activate(ctx: PluginContext) {
key: resolvedCredentials.sshKey,
keyPassword: resolvedCredentials.keyPassword,
certPublicKey: resolvedCredentials.certPublicKey,
terminalConfig: resolvedTerminalConfig ?? null,
sshOptions: resolvedSshOptions ?? null,
jumpHosts: resolvedJumpHosts,
useSocks5: resolvedUseSocks5,
socks5Host: resolvedSocks5Host,
@@ -1,9 +1,10 @@
import { useCallback, useRef } from "react";
import { useCallback, useEffect, useRef } from "react";
import { createElement } from "react";
import { toast } from "sonner";
import { useTranslation } from "react-i18next";
import type { FileItem } from "../host-types";
import type { LocalWalkResult } from "@termix/plugin-sdk/ui";
import { useSettings } from "@termix/plugin-sdk/frontend";
import {
cancelLocalTransfer,
createLocalTransferId,
@@ -20,8 +21,10 @@ import {
import {
UnsafeLocalNameError,
buildLocalDestination,
getTransferConcurrency,
clampTransferConcurrency,
DEFAULT_TRANSFER_CONCURRENCY,
runWithConcurrency,
takeLegacyTransferConcurrency,
joinRemotePath,
planRemoteDirectories,
remoteBaseName,
@@ -130,6 +133,27 @@ export function useLocalTransfers({
const { t } = useTranslation();
const batchCounter = useRef(0);
// "Simultaneous file transfers", the transferConcurrency user setting.
const userSettings = useSettings("user");
const concurrencyRef = useRef(DEFAULT_TRANSFER_CONCURRENCY);
concurrencyRef.current = clampTransferConcurrency(
userSettings.values.transferConcurrency ?? DEFAULT_TRANSFER_CONCURRENCY,
);
const { loaded: settingsLoaded, save: saveUserSettings } = userSettings;
useEffect(() => {
if (!settingsLoaded) return;
// A value this browser kept before 2.9.0 fills a setting still at its default.
const legacy = takeLegacyTransferConcurrency();
if (
legacy !== null &&
legacy !== concurrencyRef.current &&
concurrencyRef.current === DEFAULT_TRANSFER_CONCURRENCY
) {
concurrencyRef.current = legacy;
void saveUserSettings({ transferConcurrency: legacy }).catch(() => {});
}
}, [settingsLoaded, saveUserSettings]);
const runBatch = useCallback(
async (
direction: "upload" | "download",
@@ -316,7 +340,7 @@ export function useLocalTransfers({
let reason: string | undefined;
await runWithConcurrency(
plan.files,
getTransferConcurrency(),
concurrencyRef.current,
async (file) => {
const fileName = file.relativePath.split("/").pop()!;
const targetDir = remoteDirForRelativePath(
@@ -520,7 +544,7 @@ export function useLocalTransfers({
let reason: string | undefined;
await runWithConcurrency(
work,
getTransferConcurrency(),
concurrencyRef.current,
async ({ entry, dest }) => {
const fileName = entry.relativePath.split("/").pop()!;
const transferId = createLocalTransferId("local-download");
@@ -1,3 +1,5 @@
import type { HostSshOptions } from "@termix/plugin-sdk/frontend";
/** A host as the shell hands it to the file manager. */
export interface SSHHost {
id: number;
@@ -19,7 +21,7 @@ export interface SSHHost {
overrideCredentialUsername?: boolean;
userId?: string;
jumpHosts?: Array<{ hostId: number }>;
terminalConfig?: Record<string, unknown>;
sshOptions?: HostSshOptions | null;
notes?: string;
useSocks5?: boolean;
socks5Host?: string;
@@ -355,6 +355,7 @@ export function formatLocalModified(
// ---------------------------------------------------------------------------
// Parallel transfers
/** Where a browser kept the preference before it became a user setting. */
export const TRANSFER_CONCURRENCY_STORAGE_KEY =
"termix:file-manager:transfer-concurrency";
export const DEFAULT_TRANSFER_CONCURRENCY = 4;
@@ -366,28 +367,21 @@ export function clampTransferConcurrency(value: unknown): number {
return Math.min(MAX_TRANSFER_CONCURRENCY, Math.max(1, n));
}
/** How many files are transferred at the same time (1 = one after another). */
export function getTransferConcurrency(): number {
/**
* The value this browser kept before 2.9.0, removed as it is read so it only
* moves into the transferConcurrency user setting once. Null when none.
*/
export function takeLegacyTransferConcurrency(): number | null {
try {
const raw = localStorage.getItem(TRANSFER_CONCURRENCY_STORAGE_KEY);
return raw === null
? DEFAULT_TRANSFER_CONCURRENCY
: clampTransferConcurrency(raw);
if (raw === null) return null;
localStorage.removeItem(TRANSFER_CONCURRENCY_STORAGE_KEY);
return clampTransferConcurrency(raw);
} catch {
return DEFAULT_TRANSFER_CONCURRENCY;
return null;
}
}
export function setTransferConcurrency(value: number): number {
const clamped = clampTransferConcurrency(value);
try {
localStorage.setItem(TRANSFER_CONCURRENCY_STORAGE_KEY, String(clamped));
} catch {
// storage unavailable
}
return clamped;
}
/**
* Runs `worker` over `items` with at most `limit` in flight, preserving the
* original order of dispatch. Stops dispatching new items once `shouldStop()`
@@ -8,9 +8,8 @@ import {
buildLocalDestination,
clampTransferConcurrency,
describeLocalKind,
getTransferConcurrency,
runWithConcurrency,
setTransferConcurrency,
takeLegacyTransferConcurrency,
DEFAULT_TRANSFER_CONCURRENCY,
TRANSFER_CONCURRENCY_STORAGE_KEY,
formatLocalModified,
@@ -300,15 +299,19 @@ describe("local entry presentation", () => {
describe("parallel transfers", () => {
beforeEach(() => localStorage.clear());
it("clamps and persists the concurrency preference", () => {
expect(getTransferConcurrency()).toBe(DEFAULT_TRANSFER_CONCURRENCY);
it("clamps the concurrency preference", () => {
expect(clampTransferConcurrency(0)).toBe(1);
expect(clampTransferConcurrency(99)).toBe(8);
expect(clampTransferConcurrency("3.7")).toBe(3);
expect(clampTransferConcurrency("nope")).toBe(DEFAULT_TRANSFER_CONCURRENCY);
expect(setTransferConcurrency(6)).toBe(6);
expect(localStorage.getItem(TRANSFER_CONCURRENCY_STORAGE_KEY)).toBe("6");
expect(getTransferConcurrency()).toBe(6);
});
it("reads the value a browser kept before 2.9.0 once, then forgets it", () => {
expect(takeLegacyTransferConcurrency()).toBeNull();
localStorage.setItem(TRANSFER_CONCURRENCY_STORAGE_KEY, "12");
expect(takeLegacyTransferConcurrency()).toBe(8);
expect(localStorage.getItem(TRANSFER_CONCURRENCY_STORAGE_KEY)).toBeNull();
expect(takeLegacyTransferConcurrency()).toBeNull();
});
const deferred = () => {