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:
2026-07-13 18:28:30 +02:00
co-authored by Claude Fable 5
parent 9a4420fdc2
commit e2f3737656
13 changed files with 533 additions and 125 deletions
+4 -4
View File
@@ -95,10 +95,10 @@
}
</button>
@if (connections.grouped().root.length || connections.grouped().folders.length) {
@if (connections.grouped().loose.length || connections.grouped().stacks.length) {
<div class="my-1 border-t border-border"></div>
}
@for (connection of connections.grouped().root; track connection.id) {
@for (connection of connections.grouped().loose; track connection.id) {
<button
(click)="pickConnection(connection)"
class="flex w-full items-center gap-2 px-3 py-1.5 text-left text-(length:--path-font) hover:bg-accent"
@@ -107,9 +107,9 @@
<span class="flex-1 truncate">{{ connection.name }}</span>
</button>
}
@for (group of connections.grouped().folders; track group.folder.id) {
@for (group of connections.grouped().stacks; track group.stack.id) {
<div class="px-3 pt-1.5 pb-0.5 text-[10px] font-medium tracking-wide text-muted-foreground uppercase">
{{ group.folder.name }}
{{ group.stack.name }}
</div>
@for (connection of group.connections; track connection.id) {
<button
+1 -1
View File
@@ -89,7 +89,7 @@ export class FilePanel {
pickConnection(connection: SavedConnection): void {
this.menuOpen.set(false);
this.activate();
void this.panels.connectPanel(this.side(), connection, connection.name);
void this.panels.connectPanel(this.side(), connection, connection.name, connection.localDir);
}
toggleMenu(): void {