fix: Projekt-Anlegen robuster — klare Netzwerkfehler und gezielter Listen-Refresh.
Some checks failed
Deploy Development / deploy (push) Successful in 50s
Test Suite / pytest-backend (push) Failing after 1m45s
Test Suite / k6 /api/health Baseline (push) Has been skipped
Test Suite / playwright-smoke (push) Has been skipped
Test Suite / lint-backend (push) Successful in 8s
Test Suite / compose-smoke (push) Has been skipped

Vermeidet irreführendes Fail to fetch nach erfolgreichem POST und hält das Formular bei Fehlern offen.
This commit is contained in:
Lars 2026-07-08 10:54:58 +02:00
parent bff1248e32
commit 94e815e88a
3 changed files with 28 additions and 6 deletions

View File

@ -28,10 +28,21 @@ export function parseError(body, fallback) {
export async function apiFetch(path, options = {}) { export async function apiFetch(path, options = {}) {
const token = options.token ?? getToken() const token = options.token ?? getToken()
const res = await fetch(path, { let res
...options, try {
headers: { ...apiHeaders(token), ...options.headers }, res = await fetch(path, {
}) ...options,
headers: { ...apiHeaders(token), ...options.headers },
})
} catch (err) {
const message =
err instanceof TypeError
? 'Netzwerkfehler — Server nicht erreichbar. Bitte Verbindung prüfen oder Seite neu laden.'
: err.message || 'Netzwerkfehler bei der Anfrage'
const networkErr = new Error(message)
networkErr.cause = err
throw networkErr
}
const body = await res.json().catch(() => null) const body = await res.json().catch(() => null)
if (!res.ok) { if (!res.ok) {
const message = parseError(body, `Anfrage fehlgeschlagen (${res.status})`) const message = parseError(body, `Anfrage fehlgeschlagen (${res.status})`)

View File

@ -109,13 +109,14 @@ export function ProjectsSection({
async function handleSubmit(e) { async function handleSubmit(e) {
e.preventDefault() e.preventDefault()
if (!title.trim()) return if (!title.trim()) return
await onCreate({ const ok = await onCreate({
title: title.trim(), title: title.trim(),
description: description.trim(), description: description.trim(),
parent_project_id: parentProjectId || undefined, parent_project_id: parentProjectId || undefined,
container_kind: containerKind || undefined, container_kind: containerKind || undefined,
roadmap_item_id: gateId || undefined, roadmap_item_id: gateId || undefined,
}) })
if (!ok) return
setTitle('') setTitle('')
setDescription('') setDescription('')
setParentProjectId('') setParentProjectId('')

View File

@ -430,11 +430,21 @@ export function InitiativeOperationsProvider({ children }) {
async function handleCreateProject(body) { async function handleCreateProject(body) {
setFormBusy(true) setFormBusy(true)
setError(null)
try { try {
await createInitiativeProject(id, body) await createInitiativeProject(id, body)
await load() try {
setProjects(await listInitiativeProjects(id))
} catch (refreshErr) {
setError(
`Projekt angelegt, aber die Liste konnte nicht aktualisiert werden: ${refreshErr.message}`,
)
return false
}
return true
} catch (err) { } catch (err) {
setError(err.message) setError(err.message)
return false
} finally { } finally {
setFormBusy(false) setFormBusy(false)
} }