From 16e918e9b47faf0b75c929fee595e967431807e1 Mon Sep 17 00:00:00 2001 From: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com> Date: Fri, 17 Oct 2025 13:44:15 +0200 Subject: [PATCH] fix: improve SSH key handling and public key modal UX (#178) * fix: increase IP input box width in installedScripts table - Changed IP input field width from w-32 (128px) to w-40 (160px) - Fixes truncation issue for IP addresses in format 123.123.123.123 - Affects Web UI column in desktop table view when editing scripts * fix: improve SSH key handling and public key modal UX - Fix SSH key import to automatically trim trailing whitespace and empty lines - Add 'View Public Key' button in ServerForm for generated key pairs - Reduce public key textarea size from 120px to 60px min-height - Add quick command section with pre-filled echo command for authorized_keys - Improve user experience with one-click copy functionality for both key and command --- src/app/_components/InstalledScriptsTab.tsx | 2 +- src/app/_components/PublicKeyModal.tsx | 72 ++++++++++++++++++++- src/app/_components/SSHKeyInput.tsx | 13 +++- src/app/_components/ServerForm.tsx | 26 ++++++-- 4 files changed, 102 insertions(+), 11 deletions(-) diff --git a/src/app/_components/InstalledScriptsTab.tsx b/src/app/_components/InstalledScriptsTab.tsx index 05a40bf..cb1cd5e 100644 --- a/src/app/_components/InstalledScriptsTab.tsx +++ b/src/app/_components/InstalledScriptsTab.tsx @@ -1376,7 +1376,7 @@ export function InstalledScriptsTab() { type="text" value={editFormData.web_ui_ip} onChange={(e) => handleInputChange('web_ui_ip', e.target.value)} - className="w-32 px-3 py-2 text-sm font-mono border border-input rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:border-ring" + className="w-40 px-3 py-2 text-sm font-mono border border-input rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:border-ring" placeholder="IP" /> : diff --git a/src/app/_components/PublicKeyModal.tsx b/src/app/_components/PublicKeyModal.tsx index ac6d461..2afc80d 100644 --- a/src/app/_components/PublicKeyModal.tsx +++ b/src/app/_components/PublicKeyModal.tsx @@ -14,6 +14,7 @@ interface PublicKeyModalProps { export function PublicKeyModal({ isOpen, onClose, publicKey, serverName, serverIp }: PublicKeyModalProps) { const [copied, setCopied] = useState(false); + const [commandCopied, setCommandCopied] = useState(false); if (!isOpen) return null; @@ -54,6 +55,42 @@ export function PublicKeyModal({ isOpen, onClose, publicKey, serverName, serverI } }; + const handleCopyCommand = async () => { + const command = `echo "${publicKey}" >> ~/.ssh/authorized_keys`; + try { + // Try modern clipboard API first + if (navigator.clipboard && window.isSecureContext) { + await navigator.clipboard.writeText(command); + setCommandCopied(true); + setTimeout(() => setCommandCopied(false), 2000); + } else { + // Fallback for older browsers or non-HTTPS + const textArea = document.createElement('textarea'); + textArea.value = command; + textArea.style.position = 'fixed'; + textArea.style.left = '-999999px'; + textArea.style.top = '-999999px'; + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + + try { + document.execCommand('copy'); + setCommandCopied(true); + setTimeout(() => setCommandCopied(false), 2000); + } catch (fallbackError) { + console.error('Fallback copy failed:', fallbackError); + alert('Please manually copy this command:\n\n' + command); + } + + document.body.removeChild(textArea); + } + } catch (error) { + console.error('Failed to copy command to clipboard:', error); + alert('Please manually copy this command:\n\n' + command); + } + }; + return (
+ echo "{publicKey}" >> ~/.ssh/authorized_keys
+
+ + Copy and paste this command directly into your server terminal to add the key to authorized_keys +
+