Files
research-workbench/frontend/src/components/LoginPage.tsx
T
Ken 8e69ac185e fix: address code review findings from Phase 2 final review
- ChatPanel: add 'chat-message ${role}' CSS classes to message wrappers
  so .chat-message.user and .chat-message.assistant rules apply correctly
- LoginPage: rename className 'login-error' -> 'error' to match the
  .login-card .error selector in globals.css
- MCPAppRenderer: verify event.source matches iframe contentWindow before
  processing postMessage to close cross-window injection vector
- App: remove redundant await refresh() after createNew() since
  createNew() already calls refresh() internally
- useArtifacts: wrap listArtifacts call in try/catch with console.error,
  matching the error-handling pattern already used in useSessions
2026-05-26 19:46:38 +00:00

56 lines
1.4 KiB
TypeScript

import { useState } from 'react'
import type { FormEvent } from 'react'
interface LoginPageProps {
onLogin: (email: string, password: string) => Promise<void>
}
export function LoginPage({ onLogin }: LoginPageProps) {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [error, setError] = useState('')
const [loading, setLoading] = useState(false)
async function handleSubmit(e: FormEvent) {
e.preventDefault()
setError('')
setLoading(true)
try {
await onLogin(email, password)
} catch {
setError('Invalid credentials')
} finally {
setLoading(false)
}
}
return (
<div className="login-page">
<form className="login-card" onSubmit={handleSubmit}>
<h2>Research Workbench</h2>
{error && <div className="error">{error}</div>}
<label htmlFor="email">Email</label>
<input
id="email"
type="email"
value={email}
onChange={e => setEmail(e.target.value)}
autoFocus
required
/>
<label htmlFor="password">Password</label>
<input
id="password"
type="password"
value={password}
onChange={e => setPassword(e.target.value)}
required
/>
<button type="submit" disabled={loading}>
{loading ? 'Signing in...' : 'Sign In'}
</button>
</form>
</div>
)
}