feat: detached-runs monitor page (T3 parity)
Some checks failed
Security / Security check (push) Failing after 1s
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>
This commit is contained in:
parent
984c91f91d
commit
54ccd3936a
13 changed files with 764 additions and 2 deletions
96
test/detached_run_test.dart
Normal file
96
test/detached_run_test.dart
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
// DetachedRun model — the phase mapping + cancellable predicate that
|
||||
// drive the runs monitor's chip tone and the cancel-button visibility.
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'package:chain_studio/data/hub.dart';
|
||||
// The generated enum type isn't re-exported by the SDK's public
|
||||
// surface (only the message typedefs are), so build fixtures against
|
||||
// the generated file directly — test-only.
|
||||
import 'package:chain_client_sdk/src/generated/chain/v1/hub.pb.dart';
|
||||
|
||||
InvocationEntry _entry({
|
||||
required String id,
|
||||
required int phaseValue,
|
||||
String flow = 'demo',
|
||||
String project = 'general',
|
||||
String step = '',
|
||||
String error = '',
|
||||
}) {
|
||||
final status = InvocationStatus()
|
||||
..phase = InvocationStatus_Phase.valueOf(phaseValue)!
|
||||
..currentStep = step
|
||||
..startedAt = '2026-07-12T10:00:00Z'
|
||||
..error = error;
|
||||
return InvocationEntry()
|
||||
..invocationId = id
|
||||
..flowName = flow
|
||||
..project = project
|
||||
..status = status;
|
||||
}
|
||||
|
||||
void main() {
|
||||
test('maps each wire phase to the model phase', () {
|
||||
expect(
|
||||
DetachedRun.fromEntry(_entry(id: 'a', phaseValue: 1)).phase,
|
||||
DetachedPhase.pending,
|
||||
);
|
||||
expect(
|
||||
DetachedRun.fromEntry(_entry(id: 'b', phaseValue: 2)).phase,
|
||||
DetachedPhase.running,
|
||||
);
|
||||
expect(
|
||||
DetachedRun.fromEntry(_entry(id: 'c', phaseValue: 3)).phase,
|
||||
DetachedPhase.succeeded,
|
||||
);
|
||||
expect(
|
||||
DetachedRun.fromEntry(_entry(id: 'd', phaseValue: 4)).phase,
|
||||
DetachedPhase.failed,
|
||||
);
|
||||
expect(
|
||||
DetachedRun.fromEntry(_entry(id: 'e', phaseValue: 5)).phase,
|
||||
DetachedPhase.cancelled,
|
||||
);
|
||||
expect(
|
||||
DetachedRun.fromEntry(_entry(id: 'f', phaseValue: 0)).phase,
|
||||
DetachedPhase.unknown,
|
||||
);
|
||||
});
|
||||
|
||||
test('only pending and running runs are cancellable', () {
|
||||
expect(
|
||||
DetachedRun.fromEntry(_entry(id: 'a', phaseValue: 1)).isCancellable,
|
||||
isTrue,
|
||||
);
|
||||
expect(
|
||||
DetachedRun.fromEntry(_entry(id: 'b', phaseValue: 2)).isCancellable,
|
||||
isTrue,
|
||||
);
|
||||
for (final terminal in [3, 4, 5]) {
|
||||
expect(
|
||||
DetachedRun.fromEntry(_entry(id: 'x', phaseValue: terminal))
|
||||
.isCancellable,
|
||||
isFalse,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('carries flow name, project, step and error through', () {
|
||||
final run = DetachedRun.fromEntry(
|
||||
_entry(
|
||||
id: 'inv-1',
|
||||
phaseValue: 4,
|
||||
flow: 'intake',
|
||||
project: 'client-a',
|
||||
step: 'extract',
|
||||
error: 'boom',
|
||||
),
|
||||
);
|
||||
expect(run.id, 'inv-1');
|
||||
expect(run.flowName, 'intake');
|
||||
expect(run.project, 'client-a');
|
||||
expect(run.currentStep, 'extract');
|
||||
expect(run.error, 'boom');
|
||||
expect(run.startedAt, isNotNull);
|
||||
});
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@ const _destinations = <String>[
|
|||
'flows',
|
||||
'audit',
|
||||
'approvals',
|
||||
'runs',
|
||||
'federation',
|
||||
];
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue