Recover from a dead session, and report a node problem once

An expired or orphaned session left the app on a half-rendered page instead of
the login screen: a properly signed token naming a user who no longer exists
answered 404, which the client does not treat as an authentication failure. All
failures in get_current_user are 401 now, and the client stops retrying them,
so a dead session goes straight back to the login screen.

- Clicking an edge names the two nodes it runs between, not just the message.
- A node with a problem shows one badge carrying the whole explanation, rather
  than a corner badge and a status dot saying the same thing twice. The dot is
  back to what it is good at: whether the node ran.
- The sidebar's collapse control sits in the sidebar, where a phone still finds
  one in the chrome because there is no sidebar on screen to hold it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016WzrvW7rjQbynnhF6pxh6i
This commit is contained in:
Melvin Strobl
2026-08-15 19:19:57 +02:00
co-authored by Claude Fable 5
parent 6fb42bb3ef
commit c254d487ba
9 changed files with 128 additions and 24 deletions
+15 -1
View File
@@ -19,12 +19,17 @@ OpenAPI.TOKEN = async () => {
return localStorage.getItem("access_token") || ""
}
/** A session the server will not accept, whatever we do next. */
const isAuthFailure = (error: unknown) =>
error instanceof ApiError && [401, 403].includes(error.status)
const handleApiError = (error: Error) => {
if (error instanceof ApiError && [401, 403].includes(error.status)) {
if (isAuthFailure(error)) {
localStorage.removeItem("access_token")
window.location.href = "/login"
}
}
const queryClient = new QueryClient({
queryCache: new QueryCache({
onError: handleApiError,
@@ -32,6 +37,15 @@ const queryClient = new QueryClient({
mutationCache: new MutationCache({
onError: handleApiError,
}),
defaultOptions: {
queries: {
// Retrying an expired session only delays the trip to the login screen.
retry: (count, error) => !isAuthFailure(error) && count < 3,
},
mutations: {
retry: false,
},
},
})
const router = createRouter({ routeTree })