fix: cap request bodies, link login error, add book-form retry, guard double add
Limit request bodies to 1 MiB (413 JSON), wire aria-describedby on the login form, add Retry and cancellation to the book form load, disable Add entry while a note POST is in flight, and poll pg_isready in README. Claude-Session: https://claude.ai/code/session_01M9MLit5Ko3X4s7rzC5Kv7X
This commit is contained in:
+21
-9
@@ -19,11 +19,16 @@ export function BookForm() {
|
||||
const [loadError, setLoadError] = useState<string | null>(null)
|
||||
const [error, setError] = useState<FormError | null>(null)
|
||||
const [busy, setBusy] = useState(false)
|
||||
const [attempt, setAttempt] = useState(0)
|
||||
|
||||
useEffect(() => {
|
||||
if (!editing) return
|
||||
let cancelled = false
|
||||
setLoadError(null)
|
||||
setLoading(true)
|
||||
api<Book>('GET', `/books/${id}`).then(
|
||||
(book) => {
|
||||
if (cancelled) return
|
||||
setFields({
|
||||
title: book.title,
|
||||
author: book.author,
|
||||
@@ -34,11 +39,15 @@ export function BookForm() {
|
||||
setLoading(false)
|
||||
},
|
||||
(err) => {
|
||||
if (cancelled) return
|
||||
setLoadError(errorMessage(err))
|
||||
setLoading(false)
|
||||
},
|
||||
)
|
||||
}, [editing, id])
|
||||
return () => {
|
||||
cancelled = true
|
||||
}
|
||||
}, [editing, id, attempt])
|
||||
|
||||
function set(name: keyof Fields) {
|
||||
return (event: { target: { value: string } }) => setFields((prev) => ({ ...prev, [name]: event.target.value }))
|
||||
@@ -72,13 +81,16 @@ export function BookForm() {
|
||||
|
||||
if (loadError) {
|
||||
return (
|
||||
<div className={card}>
|
||||
<p role="alert" className="text-red-700">
|
||||
{loadError}
|
||||
</p>
|
||||
<Link to="/books" className="mt-2 inline-block text-indigo-700 underline">
|
||||
← Back to library
|
||||
</Link>
|
||||
<div role="alert" className={card}>
|
||||
<p className="text-red-700">{loadError}</p>
|
||||
<div className="mt-2 flex items-center gap-3">
|
||||
<button type="button" className={secondaryButton} onClick={() => setAttempt((n) => n + 1)}>
|
||||
Retry
|
||||
</button>
|
||||
<Link to="/books" className="text-indigo-700 underline">
|
||||
← Back to library
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -106,7 +118,7 @@ export function BookForm() {
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
{genresError && <p className="text-sm text-red-700">{`Could not load genres: ${genresError}`}</p>}
|
||||
{genresError && <p role="alert" className="text-sm text-red-700">{`Could not load genres: ${genresError}`}</p>}
|
||||
<div className="flex gap-4">
|
||||
<label className="block">
|
||||
<span className={labelText}>Total pages</span>
|
||||
|
||||
Reference in New Issue
Block a user