admin / Synapse-Cortex
publicSelf Hosted ITSM Tool with RBAC/Tenanting and MFA
Synapse-Cortex / Synapse-Cortexv2 / frontend / src / pages / Setup.tsx
4827 B · main
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | import { useState, type FormEvent } from 'react' import { setupApi } from '../api/setup' import { ApiError } from '../api/client' export function Setup() { const [tenantName, setTenantName] = useState('') const [fullName, setFullName] = useState('') const [email, setEmail] = useState('') const [password, setPassword] = useState('') const [error, setError] = useState<string | null>(null) const [submitting, setSubmitting] = useState(false) const onSubmit = async (e: FormEvent) => { e.preventDefault() setError(null) if (password.length < 8) { setError('Password must be at least 8 characters.') return } setSubmitting(true) try { await setupApi.submit({ tenant_name: tenantName, admin_full_name: fullName, admin_email: email, admin_password: password, }) // Full page navigation (not client-side) so SetupGate re-fetches setup // status fresh on load - it only checks once per mount, and this is // the one moment in the app's life where that status actually flips. window.location.href = '/' } catch (err) { setError(err instanceof ApiError ? err.message : 'Setup failed.') } finally { setSubmitting(false) } } return ( <div className="min-h-screen flex items-center justify-center bg-cortex-bg px-4"> <div className="w-full max-w-md border border-cortex-border bg-cortex-panel rounded-md p-8 glow-blue"> <div className="flex flex-col items-center mb-6"> <img src="/img/cortex-logo.webp" alt="Synapse-Cortex" className="h-24 mb-3" /> <div className="text-[10px] text-accent-blue tracking-widest uppercase font-display"> Initial System Configuration </div> <div className="mt-3 flex items-center gap-2 text-[10px] text-accent-orange uppercase tracking-wider"> <span className="h-1.5 w-1.5 rounded-full bg-accent-orange animate-pulse" /> No global admin detected </div> </div> {error && ( <div className="mb-4 text-xs border border-accent-red/40 bg-accent-red/10 text-accent-red px-3 py-2 rounded"> {error} </div> )} <form onSubmit={onSubmit} className="space-y-3 text-sm"> <div> <label className="block text-xs text-cortex-muted mb-1 uppercase tracking-wider">Tenant Name</label> <input required value={tenantName} onChange={(e) => setTenantName(e.target.value)} placeholder="Acme Corporation" className="w-full bg-cortex-panel2 border border-cortex-border rounded px-3 py-2 focus:outline-none focus:border-accent-blue" /> </div> <div> <label className="block text-xs text-cortex-muted mb-1 uppercase tracking-wider">Global Admin Name</label> <input required value={fullName} onChange={(e) => setFullName(e.target.value)} placeholder="Jane Operator" className="w-full bg-cortex-panel2 border border-cortex-border rounded px-3 py-2 focus:outline-none focus:border-accent-blue" /> </div> <div> <label className="block text-xs text-cortex-muted mb-1 uppercase tracking-wider">Admin Email</label> <input required type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="[email protected]" className="w-full bg-cortex-panel2 border border-cortex-border rounded px-3 py-2 focus:outline-none focus:border-accent-blue" /> </div> <div> <label className="block text-xs text-cortex-muted mb-1 uppercase tracking-wider">Admin Password</label> <input required type="password" minLength={8} value={password} onChange={(e) => setPassword(e.target.value)} className="w-full bg-cortex-panel2 border border-cortex-border rounded px-3 py-2 focus:outline-none focus:border-accent-blue" /> </div> <button type="submit" disabled={submitting} className="w-full bg-accent-blue text-cortex-bg font-display font-bold uppercase tracking-wider text-xs py-2.5 rounded hover:bg-accent-blue-bright transition disabled:opacity-50" > {submitting ? 'Initializing…' : 'Initialize System'} </button> </form> <div className="mt-6 text-center text-[10px] text-cortex-muted tracking-wider"> SYNAPSE SUITE // CORTEX ITSM MODULE // v2.0.0 </div> </div> </div> ) } |