Default-collapse already-configured SSH hosts on page load (#19)

* Add editable display-name field to generic integrations

Lets users set a custom name for Proxmox, Docker, AWS, Remote Desktop,
Netbird, Cloudflare, Uptime Kuma, and Weather integrations, separate
from the host/IP field, mirroring the SSH host rename pattern.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016kF4hZWEkRCPPvCZTeXxn4

* Surface the new-integration name field as a labeled input

The name field for new generic integrations was a faint header input
with only placeholder text, easy to miss. Move it into the form grid
as a proper labeled "Name" field next to the other connection fields.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016kF4hZWEkRCPPvCZTeXxn4

* Add file upload for SSH private key and certificate fields

Lets users pick a key file from disk (e.g. ~/.ssh) instead of pasting
its contents into the Private Key / OPKSSH Certificate fields.

* Fix SSH private key paste corrupting multi-line PEM format

Private Key and Certificate fields were single-line <input> elements,
which strip newlines on paste and corrupt PEM-formatted keys (causing
'Unsupported key format' errors). Render them as multi-line textareas
instead so pasted keys keep their line breaks.

* Default-collapse already-configured SSH hosts on page load

Previously every SSH host card reset to expanded on each page visit,
showing blank secret fields that looked like saved keys had been
deleted. Hosts with saved secrets now start collapsed on first load.

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Samuel James 2026-06-20 09:00:04 -04:00 committed by GitHub
parent 933845a222
commit ad2cfe808c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -389,6 +389,7 @@ function SshHostsSection() {
const [newDrafts, setNewDrafts] = useState<{ key: number; values: Record<string, string> }[]>([])
const nextNewKey = useRef(-1)
const fileInputRefs = useRef<Record<string, HTMLInputElement | null>>({})
const collapseInitialized = useRef(false)
function toggleCollapsed(id: number) {
setCollapsed((prev) => {
@ -404,7 +405,14 @@ function SshHostsSection() {
}, [])
function refresh() {
api.listIntegrations().then(({ integrations }) => setHosts(integrations.filter((i) => i.type === 'ssh')))
api.listIntegrations().then(({ integrations }) => {
const sshHosts = integrations.filter((i) => i.type === 'ssh')
setHosts(sshHosts)
if (!collapseInitialized.current) {
collapseInitialized.current = true
setCollapsed(new Set(sshHosts.filter((h) => h.secretKeys.length > 0).map((h) => h.id)))
}
})
}
function toggleReveal(key: string) {