feat(studio): live step-progress in flow-run dialog
Some checks are pending
Security / Security check (push) Waiting to run
Some checks are pending
Security / Security check (push) Waiting to run
The flow-run dialog showed a single spinner + "running…" label
for the whole run. For multi-step flows the operator had no
way to see *which* step was busy or how close the run was to
finishing.
Replace the spinner with a live step list driven by a
StreamEvents subscription:
✔ extract 0.41s
⏳ summarize
◻ notify
━━━━━━━━━━──── 35%
Mirrors the `fai run` CLI rendering — one shared visual
language across both surfaces. Steps appear in execution
order as the hub emits step.started events; check + duration
on completion; cross + first-line error on failure; pause
icon on approval gates.
Implementation:
- HubService.streamEvents(backfill, types) — new public
stream-facade method that wraps HubClient.streamEvents and
maps proto LoggedEvent → AuditEvent for the rest of Studio.
Subscribed with backfill=0 so the dialog only sees events
from this very run.
- _FlowRunDialogState.initState subscribes BEFORE submitting
the run, so the first step.started never gets lost in the
gRPC handshake gap.
- Two-layer filter on incoming events: same flow name AND
timestamp >= dialog open time. The timestamp gate is what
stops a previous run's tail-end from painting stale rows
if the user re-runs the same saved flow.
- _LiveStep + _LiveStepList — insertion-ordered map renders
rows in runtime execution order (not alphabetical), so
what the operator sees matches what the hub did.
Version 0.51.5 → 0.51.6.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
parent
2b65cd771f
commit
ba1a1a4f06
4 changed files with 249 additions and 15 deletions
|
|
@ -729,6 +729,37 @@ class HubService {
|
|||
};
|
||||
}
|
||||
|
||||
/// Live audit-event stream. The hub's StreamEvents RPC
|
||||
/// optionally replays [backfill] historical events first, then
|
||||
/// keeps the channel open and forwards every new event as soon
|
||||
/// as it lands. Filtering by [types] is applied on the hub
|
||||
/// side so this surface stays lean even when the log is busy.
|
||||
///
|
||||
/// Subscribe **before** triggering the work whose progress you
|
||||
/// want to follow — otherwise the earliest `*.started` events
|
||||
/// can arrive before the subscriber is ready and slip past.
|
||||
Stream<AuditEvent> streamEvents({
|
||||
int backfill = 0,
|
||||
List<String> types = const [],
|
||||
}) {
|
||||
return _client.streamEvents(backfill: backfill, types: types).map(
|
||||
(e) => AuditEvent(
|
||||
eventId: e.eventId,
|
||||
timestamp: DateTime.tryParse(e.timestamp) ?? DateTime.now(),
|
||||
type: e.eventType,
|
||||
flowName: e.flowName.isEmpty ? null : e.flowName,
|
||||
stepId: e.stepId.isEmpty ? null : e.stepId,
|
||||
moduleName: e.moduleName.isEmpty ? null : e.moduleName,
|
||||
moduleVersion: e.moduleVersion.isEmpty ? null : e.moduleVersion,
|
||||
invocationId: e.invocationId.isEmpty ? null : e.invocationId,
|
||||
flowExecution: e.flowExecution.isEmpty ? null : e.flowExecution,
|
||||
durationMs: e.durationMs == 0 ? null : e.durationMs.toInt(),
|
||||
error: e.error.isEmpty ? null : e.error,
|
||||
detail: e.detail.isEmpty ? null : e.detail,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<List<AuditEvent>> recentEvents({
|
||||
int limit = 50,
|
||||
List<String> types = const [],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue