Adjusting the ui

This commit is contained in:
Owen
2026-05-29 10:57:28 -07:00
parent 76cd716caa
commit 71756812b6
2 changed files with 130 additions and 89 deletions

View File

@@ -16,6 +16,10 @@ import {
CardDescription CardDescription
} from "@app/components/ui/card"; } from "@app/components/ui/card";
import Link from "next/link"; import Link from "next/link";
import { ExternalLink } from "lucide-react";
import { cn } from "@app/lib/cn";
type AuthTab = "password" | "privateKey";
type FormState = { type FormState = {
username: string; username: string;
@@ -53,7 +57,7 @@ export default function SshClient({
return { username: "", password: "", privateKey: "" }; return { username: "", password: "", privateKey: "" };
}); });
const fileInputRef = useRef<HTMLInputElement>(null); const [authTab, setAuthTab] = useState<AuthTab>("password");
function handleKeyFile(e: React.ChangeEvent<HTMLInputElement>) { function handleKeyFile(e: React.ChangeEvent<HTMLInputElement>) {
const file = e.target.files?.[0]; const file = e.target.files?.[0];
@@ -186,8 +190,11 @@ export default function SshClient({
} }
const username = override?.username ?? form.username; const username = override?.username ?? form.username;
const password = override?.password ?? form.password; const password =
const privateKey = override?.privateKey ?? form.privateKey; override?.password ?? (authTab === "password" ? form.password : "");
const privateKey =
override?.privateKey ??
(authTab === "privateKey" ? form.privateKey : "");
const certificate = override?.certificate; const certificate = override?.certificate;
const proxyAddress = `${window.location.protocol === "https:" ? "wss" : "ws"}://${window.location.host}/gateway/ssh`; const proxyAddress = `${window.location.protocol === "https:" ? "wss" : "ws"}://${window.location.host}/gateway/ssh`;
@@ -353,95 +360,125 @@ export default function SshClient({
<CardHeader> <CardHeader>
<CardTitle>Sign in to SSH</CardTitle> <CardTitle>Sign in to SSH</CardTitle>
<CardDescription> <CardDescription>
Enter your credentials to access xxxx Enter credentials to access xxxx
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="space-y-4"> {/* Tab row */}
<Field label="Username" id="username"> <div className="flex space-x-4 border-b mb-4">
<Input {(["password", "privateKey"] as const).map(
id="username" (tab) => (
value={form.username} <button
onChange={(e) => key={tab}
setForm({
...form,
username: e.target.value
})
}
placeholder="root"
/>
</Field>
<Field label="Password" id="password">
<Input
id="password"
type="password"
value={form.password}
onChange={(e) =>
setForm({
...form,
password: e.target.value
})
}
placeholder={
form.privateKey
? "Optional with key auth"
: ""
}
/>
</Field>
<Field
label="Private Key (optional)"
id="privateKey"
>
<Textarea
id="privateKey"
value={form.privateKey}
onChange={(e) =>
setForm({
...form,
privateKey: e.target.value
})
}
placeholder="Paste your private key here (PEM format)…"
rows={5}
className="font-mono text-xs"
/>
<div className="mt-1.5 flex items-center gap-2">
<Button
type="button" type="button"
variant="outline" onClick={() => setAuthTab(tab)}
size="sm" className={cn(
onClick={() => "px-4 py-2 text-sm font-medium transition-colors whitespace-nowrap relative",
fileInputRef.current?.click() authTab === tab
} ? "text-primary after:absolute after:bottom-0 after:left-0 after:right-0 after:h-0.5 after:bg-primary after:rounded-full"
: "text-muted-foreground hover:text-foreground"
)}
> >
Upload key file {tab === "password"
</Button> ? "Password"
{form.privateKey && ( : "Private Key"}
<button </button>
type="button" )
className="text-xs text-muted-foreground underline" )}
onClick={() => </div>
setForm((prev) => ({
...prev,
privateKey: ""
}))
}
>
Clear
</button>
)}
</div>
<input
ref={fileInputRef}
type="file"
className="hidden"
accept=".pem,.key,.pub,*"
onChange={handleKeyFile}
/>
</Field>
{authTab === "password" && (
<div className="space-y-4">
<Field label="Username" id="username-pw">
<Input
id="username-pw"
value={form.username}
onChange={(e) =>
setForm({
...form,
username: e.target.value
})
}
placeholder="root"
/>
</Field>
<Field label="Password" id="password">
<Input
id="password"
type="password"
value={form.password}
onChange={(e) =>
setForm({
...form,
password: e.target.value
})
}
/>
</Field>
</div>
)}
{authTab === "privateKey" && (
<div className="space-y-4">
<p className="text-sm text-muted-foreground">
Your private key is not stored or
visible to Pangolin. Alternatively, you
can use short-lived certificates for
seamless authentication using your
existing Pangolin identity.{" "}
<Link
href="https://docs.pangolin.net/"
target="_blank"
rel="noopener noreferrer"
className="underline inline-flex items-center gap-1"
>
Learn more
<ExternalLink className="h-3 w-3" />
</Link>
</p>
<Field label="Username" id="username-key">
<Input
id="username-key"
value={form.username}
onChange={(e) =>
setForm({
...form,
username: e.target.value
})
}
placeholder="root"
/>
</Field>
<Field label="Private Key" id="privateKey">
<Textarea
id="privateKey"
value={form.privateKey}
onChange={(e) =>
setForm({
...form,
privateKey: e.target.value
})
}
placeholder="-----BEGIN OPENSSH PRIVATE KEY-----"
rows={5}
className="font-mono text-xs"
/>
</Field>
<Field
label="Private Key File"
id="privateKeyFile"
>
<Input
id="privateKeyFile"
type="file"
accept=".pem,.key,.pub,*"
onChange={handleKeyFile}
/>
</Field>
</div>
)}
<div className="mt-4 space-y-3">
{connectError && ( {connectError && (
<p className="text-destructive text-sm"> <p className="text-destructive text-sm">
{connectError} {connectError}
@@ -453,11 +490,15 @@ export default function SshClient({
loading={connecting} loading={connecting}
disabled={ disabled={
!form.username || !form.username ||
(!form.password && !form.privateKey) (authTab === "password"
? !form.password
: !form.privateKey)
} }
className="w-full" className="w-full"
> >
{connecting ? "Connecting..." : "Connect"} {connecting
? "Connecting..."
: "Authenticate"}
</Button> </Button>
</div> </div>
</CardContent> </CardContent>

View File

@@ -201,7 +201,7 @@ export default function VncClient({
<CardHeader> <CardHeader>
<CardTitle>VNC</CardTitle> <CardTitle>VNC</CardTitle>
<CardDescription> <CardDescription>
Enter your credentials to connect Enter your credentials to access xxxx
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>