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
+16 -3
View File
@@ -1,3 +1,5 @@
import { ArrowRight } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Popover, PopoverAnchor, PopoverContent } from "@/components/ui/popover"
import { ScrollArea } from "@/components/ui/scroll-area"
@@ -15,13 +17,15 @@ function relativeTime(ts: number | null | undefined): string {
export type InspectedEdge = {
message: string
/** Node titles, so the popover names the two ends in the user's own words. */
from: string
to: string
x: number
y: number
}
/**
* What last travelled along an edge. The value is whatever the producing node
* published, shown as it was serialised.
* What last travelled along an edge, and between which two nodes.
*/
export function EdgeInspector({
edge,
@@ -48,7 +52,16 @@ export function EdgeInspector({
className="w-72 p-3"
data-testid="edge-inspector"
>
<p className="font-mono text-xs text-muted-foreground">
<p className="flex items-center gap-1.5 text-sm">
<span className="min-w-0 flex-1 truncate font-medium">
{edge.from}
</span>
<ArrowRight className="size-3.5 shrink-0 text-muted-foreground" />
<span className="min-w-0 flex-1 truncate text-right font-medium">
{edge.to}
</span>
</p>
<p className="mt-1 font-mono text-xs text-muted-foreground">
{displayName(flow, edge.message)}
</p>