List ~/.ssh/config hosts in the panel source dropdown

Read-only group below saved connections; hosts resolve HostName/User/
Port/IdentityFile (Include, wildcards, %-tokens) and connect on click.
New ssh-agent auth kind covers hosts without a usable identity file;
ProxyJump/ProxyCommand hosts are shown disabled.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-13 14:10:52 +02:00
co-authored by Claude Fable 5
parent fdf65766b5
commit f4819a58fe
11 changed files with 240 additions and 18 deletions
+19 -1
View File
@@ -1,7 +1,7 @@
<!-- session strip -->
<div class="relative flex items-center gap-1.5 border-b border-border px-2 py-1">
<button
(click)="menuOpen.set(!menuOpen())"
(click)="toggleMenu()"
class="flex min-w-0 items-center gap-1.5 rounded-md px-2 py-1 text-xs font-medium hover:bg-accent"
title="Choose what this panel shows"
>
@@ -128,6 +128,24 @@
}
}
@if (connections.sshHosts().length) {
<div class="my-1 border-t border-border"></div>
<div class="px-3 pt-1.5 pb-0.5 text-[10px] font-medium tracking-wide text-muted-foreground uppercase">
~/.ssh/config
</div>
@for (host of connections.sshHosts(); track host.name) {
<button
(click)="pickSshHost(host)"
[disabled]="host.unsupported"
[title]="sshHostTitle(host)"
class="flex w-full items-center gap-2 py-1.5 pr-3 pl-5 text-left text-xs hover:bg-accent disabled:opacity-60 disabled:hover:bg-transparent"
>
<ng-icon name="mynaServers" size="0.9rem" class="shrink-0 text-muted-foreground" />
<span class="flex-1 truncate">{{ host.name }}</span>
</button>
}
}
<div class="my-1 border-t border-border"></div>
<button
(click)="openManager()"
+30 -1
View File
@@ -9,7 +9,7 @@ import {
viewChild,
} from '@angular/core';
import { NgIcon } from '@ng-icons/core';
import type { FileEntry, SavedConnection } from '@shared/types';
import type { FileEntry, SavedConnection, SshConfigHost } from '@shared/types';
import { ConnectionsService } from '../connections.service';
import { DialogsService } from '../dialogs.service';
import { FileActionsService } from '../file-actions.service';
@@ -84,6 +84,35 @@ export class FilePanel {
void this.panels.connectPanel(this.side(), connection, connection.name);
}
toggleMenu(): void {
this.menuOpen.set(!this.menuOpen());
// re-read ~/.ssh/config on each open so external edits show up
if (this.menuOpen()) void this.connections.reloadSshHosts();
}
pickSshHost(host: SshConfigHost): void {
this.menuOpen.set(false);
this.activate();
void this.panels.connectPanel(
this.side(),
{
host: host.hostname,
port: host.port,
username: host.username,
auth: host.identityFile
? { kind: 'key', privateKeyPath: host.identityFile }
: { kind: 'agent' },
initialPath: null,
},
host.name,
);
}
sshHostTitle(host: SshConfigHost): string {
if (host.unsupported === 'proxy') return 'Uses ProxyJump/ProxyCommand — not supported';
return `${host.username}@${host.hostname}:${host.port}`;
}
openManager(): void {
this.menuOpen.set(false);
this.activate();