Redo connection manager: Stacks, More options, drag & drop, WinSCP import
Folders become Stacks (connections.json v2, no v1 migration): collapsible stack-first list, open-stack-in-tabs (first reuses a pristine tab), drag connections between stacks. More... reveals a per-connection Local directory applied to the other panel when local and untouched. Import reads a WinSCP.ini export incl. deobfuscated passwords. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+24
-4
@@ -8,6 +8,7 @@ import { SftpProvider } from "./fs/sftp";
|
||||
import type { ConnectionStore } from "./store/connections";
|
||||
import type { SettingsStore } from "./store/settings";
|
||||
import { loadSshConfigHosts } from "./store/ssh-config";
|
||||
import { importWinScpIni } from "./store/winscp-import";
|
||||
import type { TransferEngine } from "./transfers/engine";
|
||||
import { removeRecursive } from "./transfers/walk";
|
||||
|
||||
@@ -152,20 +153,39 @@ export function createAppRPC({
|
||||
return {};
|
||||
}),
|
||||
|
||||
upsertFolder: ({ folder }) =>
|
||||
upsertStack: ({ stack }) =>
|
||||
wrap(async () => {
|
||||
const id = await store.upsertFolder(folder);
|
||||
const id = await store.upsertStack(stack);
|
||||
events.connectionsChanged();
|
||||
return { id };
|
||||
}),
|
||||
|
||||
deleteFolder: ({ id }) =>
|
||||
deleteStack: ({ id }) =>
|
||||
wrap(async () => {
|
||||
await store.deleteFolder(id);
|
||||
await store.deleteStack(id);
|
||||
events.connectionsChanged();
|
||||
return {};
|
||||
}),
|
||||
|
||||
importWinScp: () =>
|
||||
wrap(async () => {
|
||||
const { homedir } = await import("node:os");
|
||||
const picked = await Utils.openFileDialog({
|
||||
startingFolder: homedir(),
|
||||
allowedFileTypes: "*",
|
||||
canChooseFiles: true,
|
||||
canChooseDirectory: false,
|
||||
allowsMultipleSelection: false,
|
||||
});
|
||||
const file = picked.find((p) => p.trim().length > 0);
|
||||
// dialog cancelled — all-zero result, UI shows nothing
|
||||
if (!file) return { connections: 0, stacks: 0, skipped: 0 };
|
||||
const text = await (await import("node:fs/promises")).readFile(file, "utf8");
|
||||
const result = await importWinScpIni(text, store);
|
||||
events.connectionsChanged();
|
||||
return result;
|
||||
}),
|
||||
|
||||
getSshConfigHosts: () => wrap(async () => ({ hosts: loadSshConfigHosts() })),
|
||||
|
||||
// ---- settings ----
|
||||
|
||||
Reference in New Issue
Block a user