fix(runs): stop claiming the hub is unreachable on RPC-level errors

The runs monitor folded every load failure into 'hub not reachable',
contradicting the sidebar's green connected dot whenever the hub
answered but the RPC failed — most visibly against a pre-0.22 hub
whose version predates the ListInvocations RPC (UNIMPLEMENTED).

Classify the failure instead (top-level, unit-tested):
- UNIMPLEMENTED -> 'this view needs a newer hub version' with a
  doctor-page link (the update banner lives there)
- FAILED_PRECONDITION from the detached gate -> the regular
  feature-off empty state with the guide button
- UNAVAILABLE / DEADLINE_EXCEEDED / socket-level failures -> the
  honest 'hub not reachable' state (unchanged)
- everything else -> a load-failed state with the friendly error
  and a copyable detail box

The error view is a public callback-driven widget so the tests pump
each variant without a live hub. New DE+EN strings for the too-old
and load-failed states; grpcCodeOf/grpcMessageOf exposed from the
friendly-error mapper instead of duplicating the duck-typing.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
flemming-it 2026-07-18 17:33:11 +02:00
parent b47d8c4646
commit ea2cd87b5e
8 changed files with 380 additions and 7 deletions

View file

@ -1812,6 +1812,10 @@
"runsEmptyHint": "Runs that keep working in the background while you do something else appear here. The feature is optional and off by default — the guide shows step by step how to turn it on.",
"runsEmptyEnabledHint": "Background runs are switched on — none has been started yet. Start a flow with the \"run in background\" option and it will appear here.",
"runsEmptyGuideButton": "Open the guide",
"runsHubTooOldTitle": "This view needs a newer hub version",
"runsHubTooOldHint": "The hub is connected, but its version does not know the runs monitor yet. Update the hub and the runs will appear here.",
"runsHubTooOldButton": "Open Doctor",
"runsLoadFailedTitle": "Runs could not be loaded",
"runsCancelButton": "Cancel",
"runsCancelSignalled": "Cancel signalled for {flow}.",
"@runsCancelSignalled": {"placeholders": {"flow": {"type": "String"}}},