Commit graph

6 commits

Author SHA1 Message Date
flemming-it
28f6fe1a9a feat(approvals,runs): explain approvals in place + one-click hub update (0.81.0)
Approvals: the pending card now shows its full origin — flow, step,
run id (previously dropped at the Dart mapping layer), project, and
requested-at — under an ORIGIN heading, led by a one-line intro strip
that says what the inbox is and what Approve/Reject do. Approve/Reject
buttons carry tooltips; the history dialog gains project + run id.
Fixes the approvals doc drift (title/details/reviewer ->
prompt/show/timeout_seconds). Guard: approvals_origin_test renders the
card via the hermetic fake hub and pins every origin fact.

Runs: the "hub too old" state now leads with an in-place update button
(same `chain update apply` path as the Diagnose page), the Diagnose
deeplink demoted to secondary, with a CLI-absent fallback. Guard: two
new RunsLoadErrorView widget tests.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-07-26 15:50:41 +02:00
flemming-it
66b26304fd feat(test): hermetic hub fake + state-matrix sweep across all pages
The widget suites used to talk to whatever listens on the real
endpoint — results depended on the operator's machine (a running
hub fed real data into a11y/responsive runs and its gRPC channel
timers caused the historic flake). Hardening round:

- HubService.instance is now injectable (debugSetInstance);
  FakeHubService (test/support/fake_hub.dart) answers every member
  the pages touch with healthy-empty defaults and scripts per-RPC
  failures (UNIMPLEMENTED / UNAVAILABLE / detached gate) through a
  GrpcError-shaped fake. Unimplemented members are recorded and
  fail the sweep with the exact list.
- state_matrix_test.dart pins the app-wide invariants for every
  sidebar page x hub condition: healthy => no unreachable claims
  and no raw error text; hub gone => honest unreachable states;
  UNIMPLEMENTED => never 'not reachable' while the sidebar shows
  connected; detached gate => plain-language feature-off state.
- a11y + responsive sweeps now inject the fake (hermetic); the
  6-minute idle-timer drain workaround is gone with the cause.

Real bugs the new sweep caught immediately:
- every data page (store, doctor, audit, approvals, federation)
  folded ANY load failure into 'hub not reachable' — the runs-page
  bug class; they now share HubLoadErrorView, which classifies
  into unreachable / needs-newer-hub / load-failed-with-copyable-
  detail (new generic DE+EN strings)
- the approvals page's hidden tab had no future listener: a load
  failure there surfaced as an uncaught async error
- the audit status bar rendered the raw gRPC error wall verbatim;
  it now shows the classified friendly headline (still selectable)

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-07-19 01:02:51 +02:00
flemming-it
ea2cd87b5e 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>
2026-07-18 17:33:11 +02:00
flemming-it
ae97b88257 fix(runs): honest empty state — feature off vs. no runs yet
Some checks are pending
Security / Security check (push) Waiting to run
The empty state unconditionally claimed background runs were
switched off, even on hubs where the operator had enabled them.
The hub now reports the flag on the list RPC (detached_enabled);
the hint picks the truthful variant.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-07-18 00:20:43 +02:00
flemming-it
cc1618f512 fix(runs): plain-language empty state with a guide button
Some checks are pending
Security / Security check (push) Waiting to run
The empty state explained itself in operator jargon (detach,
detached.enabled, operator config) and offered no way forward.
Now it says what background runs are in everyday language and
opens the built-in guide — which carries the exact activation
steps — via a real button. DE and EN.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-07-17 23:23:15 +02:00
flemming-it
54ccd3936a feat: detached-runs monitor page (T3 parity)
Some checks failed
Security / Security check (push) Failing after 1s
New Runs sidebar destination listing detached invocations (detach:true)
with phase, current step, project and a Cancel button while
pending/running. Workspace-scoped like Audit/Approvals, polls every 2s.
Detached runs are opt-in (detached.enabled) — the empty state explains
how to enable them. Inline help doc DE+EN. DetachedRun model +
listDetachedRuns/cancelDetachedRun in HubService, backed by the SDK's
listInvocations()/cancelInvocation(). flutter analyze clean; 29 tests
green (sidebar Y-stability updated for the new destination, model
mapping unit-tested).

Screenshot verification (light+dark) deferred — shared desktop in use.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
2026-07-12 14:43:37 +02:00