making progress
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useState } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { useAuth } from '../contexts/AuthContext'
|
||||
import { useSSHKeys, useAddSSHKey, useDeleteSSHKey } from '../api/queries/sshkeys'
|
||||
|
||||
export default function SettingsPage() {
|
||||
const { user, logout } = useAuth()
|
||||
@@ -58,15 +59,7 @@ export default function SettingsPage() {
|
||||
</form>
|
||||
</section>
|
||||
|
||||
{/* SSH keys placeholder */}
|
||||
<section className="border border-[#DFE1E6] rounded-lg overflow-hidden">
|
||||
<div className="px-5 py-4 border-b border-[#DFE1E6] bg-[#FAFBFC]">
|
||||
<h2 className="text-sm font-semibold text-[#172B4D]">SSH keys</h2>
|
||||
</div>
|
||||
<div className="px-5 py-5 text-sm text-[#5E6C84]">
|
||||
SSH key management coming soon.
|
||||
</div>
|
||||
</section>
|
||||
<SSHKeySection />
|
||||
|
||||
{/* Danger zone */}
|
||||
<section className="border border-[#FFEBE6] rounded-lg overflow-hidden">
|
||||
@@ -100,3 +93,75 @@ function Row({ label, value }: { label: string; value?: string }) {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function SSHKeySection() {
|
||||
const { data: keys } = useSSHKeys()
|
||||
const addKey = useAddSSHKey()
|
||||
const deleteKey = useDeleteSSHKey()
|
||||
const [showAdd, setShowAdd] = useState(false)
|
||||
const [title, setTitle] = useState('')
|
||||
const [publicKey, setPublicKey] = useState('')
|
||||
|
||||
const handleAdd = async (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
await addKey.mutateAsync({ title, publicKey })
|
||||
setTitle(''); setPublicKey(''); setShowAdd(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="border border-[#DFE1E6] rounded-lg overflow-hidden">
|
||||
<div className="px-5 py-4 border-b border-[#DFE1E6] bg-[#FAFBFC] flex items-center justify-between">
|
||||
<h2 className="text-sm font-semibold text-[#172B4D]">SSH keys</h2>
|
||||
<button onClick={() => setShowAdd(s => !s)}
|
||||
className="text-xs text-[#0052CC] hover:underline font-medium">
|
||||
{showAdd ? 'Cancel' : '+ Add key'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{showAdd && (
|
||||
<form onSubmit={handleAdd} className="px-5 py-4 border-b border-[#DFE1E6] space-y-3 bg-[#FAFBFC]">
|
||||
<div>
|
||||
<label className="block text-xs font-semibold text-[#172B4D] mb-1">Title</label>
|
||||
<input value={title} onChange={e => setTitle(e.target.value)} required placeholder="e.g. MacBook Pro"
|
||||
className="w-full border border-[#DFE1E6] rounded px-3 py-2 text-sm focus:outline-none focus:border-[#4C9AFF]" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs font-semibold text-[#172B4D] mb-1">Public key</label>
|
||||
<textarea value={publicKey} onChange={e => setPublicKey(e.target.value)} required rows={3}
|
||||
placeholder="ssh-ed25519 AAAA… or ssh-rsa AAAA…"
|
||||
className="w-full border border-[#DFE1E6] rounded px-3 py-2 text-xs font-mono resize-none focus:outline-none focus:border-[#4C9AFF]" />
|
||||
</div>
|
||||
{addKey.isError && (
|
||||
<p className="text-xs text-[#DE350B]">{addKey.error instanceof Error ? addKey.error.message : 'Error'}</p>
|
||||
)}
|
||||
<button type="submit" disabled={addKey.isPending}
|
||||
className="px-4 py-2 rounded bg-[#0052CC] text-white text-sm font-medium hover:bg-[#0065FF] disabled:opacity-50 min-h-[44px]">
|
||||
{addKey.isPending ? 'Adding…' : 'Add SSH key'}
|
||||
</button>
|
||||
</form>
|
||||
)}
|
||||
|
||||
{!keys?.length ? (
|
||||
<div className="px-5 py-5 text-sm text-[#5E6C84]">No SSH keys added yet.</div>
|
||||
) : (
|
||||
<ul>
|
||||
{keys.map(key => (
|
||||
<li key={key.id} className="flex items-center gap-3 px-5 py-3 border-b border-[#DFE1E6] last:border-0">
|
||||
<svg width="16" height="16" fill="none" stroke="#5E6C84" strokeWidth="1.5" viewBox="0 0 24 24" className="shrink-0">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M15.75 5.25a3 3 0 0 1 3 3m3 0a6 6 0 0 1-7.029 5.912c-.563-.097-1.159.026-1.563.43L10.5 17.25H8.25v2.25H6v2.25H2.25v-2.818c0-.597.237-1.17.659-1.591l6.499-6.499c.404-.404.527-1 .43-1.563A6 6 0 0 1 21.75 8.25Z" />
|
||||
</svg>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-medium text-[#172B4D] truncate">{key.title}</p>
|
||||
<p className="text-xs font-mono text-[#5E6C84] truncate">{key.fingerprint}</p>
|
||||
</div>
|
||||
<button onClick={() => deleteKey.mutate(key.id)}
|
||||
className="text-xs px-3 py-1.5 rounded border border-[#DE350B] text-[#DE350B] hover:bg-[#FFEBE6] shrink-0 min-h-[32px]">
|
||||
Delete
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user