diff --git a/lib/data/hub.dart b/lib/data/hub.dart index f51dc49..1939e6e 100644 --- a/lib/data/hub.dart +++ b/lib/data/hub.dart @@ -1136,16 +1136,19 @@ class HubService { Future reject(String id, String reviewer, String reason) => _client.reject(approvalId: id, reviewer: reviewer, reason: reason); - /// Every tracked detached invocation (newest-first). Optionally - /// scoped to one [project]. Empty when detached invocations are - /// disabled or none have run this process. - Future> listDetachedRuns({String project = ''}) async { - final entries = await _client.listInvocations(); - final runs = entries + /// Detached-runs monitor snapshot: every tracked invocation + /// (newest-first, optionally scoped to one [project]) plus whether + /// the operator enabled the feature at all — so the empty state + /// can say "switched off" vs. "on, but no runs yet" truthfully. + Future<({List runs, bool enabled})> listDetachedRuns({ + String project = '', + }) async { + final r = await _client.listInvocationsFull(); + final runs = r.invocations .where((e) => project.isEmpty || e.project == project) .map(DetachedRun.fromEntry) .toList(); - return runs; + return (runs: runs, enabled: r.detachedEnabled); } /// Cancel a running/pending detached invocation. Returns true when diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 049af98..cb4587a 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -1744,6 +1744,7 @@ "runsReloadTooltip": "Lauf-Liste neu laden", "runsEmptyTitle": "Keine Läufe im Hintergrund", "runsEmptyHint": "Hier erscheinen Läufe, die im Hintergrund weiterlaufen, während Sie anderes tun. Diese Funktion ist optional und standardmäßig ausgeschaltet — die Anleitung zeigt Schritt für Schritt, wie sie eingeschaltet wird.", + "runsEmptyEnabledHint": "Läufe im Hintergrund sind eingeschaltet — es wurde nur noch keiner gestartet. Starten Sie einen Flow mit der Option „im Hintergrund ausführen“, dann erscheint er hier.", "runsEmptyGuideButton": "Anleitung öffnen", "runsCancelButton": "Abbrechen", "runsCancelSignalled": "Abbruch für {flow} ausgelöst.", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index a655ae0..9cd599b 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1783,6 +1783,7 @@ "runsReloadTooltip": "Reload the runs list", "runsEmptyTitle": "No background runs", "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", "runsCancelButton": "Cancel", "runsCancelSignalled": "Cancel signalled for {flow}.", diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 1c18855..8e25421 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -5299,6 +5299,12 @@ abstract class AppLocalizations { /// **'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.'** String get runsEmptyHint; + /// No description provided for @runsEmptyEnabledHint. + /// + /// In en, this message translates to: + /// **'Background runs are switched on — none has been started yet. Start a flow with the \"run in background\" option and it will appear here.'** + String get runsEmptyEnabledHint; + /// No description provided for @runsEmptyGuideButton. /// /// In en, this message translates to: diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index e286065..1933b5b 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -3135,6 +3135,10 @@ class AppLocalizationsDe extends AppLocalizations { String get runsEmptyHint => 'Hier erscheinen Läufe, die im Hintergrund weiterlaufen, während Sie anderes tun. Diese Funktion ist optional und standardmäßig ausgeschaltet — die Anleitung zeigt Schritt für Schritt, wie sie eingeschaltet wird.'; + @override + String get runsEmptyEnabledHint => + 'Läufe im Hintergrund sind eingeschaltet — es wurde nur noch keiner gestartet. Starten Sie einen Flow mit der Option „im Hintergrund ausführen“, dann erscheint er hier.'; + @override String get runsEmptyGuideButton => 'Anleitung öffnen'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 6073599..781d566 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -3136,6 +3136,10 @@ class AppLocalizationsEn extends AppLocalizations { String get 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.'; + @override + String get 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.'; + @override String get runsEmptyGuideButton => 'Open the guide'; diff --git a/lib/pages/runs.dart b/lib/pages/runs.dart index 89f4207..6f458c0 100644 --- a/lib/pages/runs.dart +++ b/lib/pages/runs.dart @@ -24,6 +24,7 @@ class RunsPage extends StatefulWidget { class _RunsPageState extends State { List _runs = const []; + bool _detachedEnabled = false; String? _error; bool _loaded = false; Timer? _poll; @@ -49,12 +50,13 @@ class _RunsPageState extends State { Future _refresh() async { try { - final runs = await HubService.instance.listDetachedRuns( + final snapshot = await HubService.instance.listDetachedRuns( project: Workspace.instance.activeSlug, ); if (!mounted) return; setState(() { - _runs = runs; + _runs = snapshot.runs; + _detachedEnabled = snapshot.enabled; _error = null; _loaded = true; }); @@ -126,7 +128,10 @@ class _RunsPageState extends State { ? ChainEmptyState( icon: Icons.rocket_launch_outlined, title: l.runsEmptyTitle, - hint: l.runsEmptyHint, + // The hub reports whether the operator enabled the + // feature — never claim "switched off" while it is on + // and there simply are no runs yet (usertest finding). + hint: _detachedEnabled ? l.runsEmptyEnabledHint : l.runsEmptyHint, // The guide carries the plain-language explanation plus // the exact operator steps (config snippet) — a click // target instead of a raw config key in the hint.