From 4ceb5bb56725f324327da12417dfb1a3b9386a82 Mon Sep 17 00:00:00 2001 From: flemming-it Date: Mon, 13 Jul 2026 14:15:17 +0200 Subject: [PATCH] fix(settings): reveal System-AI test result + refresh onboarding checklist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two settings bugs the operator hit: 1. 'Test connection' appeared to do nothing. The result/error panel renders at the bottom of the System-AI editor's scrollable, 600px-capped form, so on a tall dialog it lands below the fold — the footer button flickers 'Testing…' and nothing visible changes. The editor now holds a ScrollController and animates the content to reveal the outcome whenever a test result or error appears. 2. The welcome onboarding checklist kept 'connect System-AI' unchecked right after saving a working config. The checklist row opens the Settings dialog (an overlay, not a navigation), and on close the checklist never re-probed — so it showed the stale pre-config state. Both settings-opening rows (System-AI, MCP) now re-probe when the dialog closes; navigation-based rows already self-heal on return. Studio suite green; flutter analyze clean. Signed-off-by: flemming-it --- lib/pages/welcome.dart | 16 ++++++++++++++-- lib/widgets/chain_system_ai_editor.dart | 22 ++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/lib/pages/welcome.dart b/lib/pages/welcome.dart index 985f665..301a5c4 100644 --- a/lib/pages/welcome.dart +++ b/lib/pages/welcome.dart @@ -641,6 +641,18 @@ class _OnboardingChecklistState extends State<_OnboardingChecklist> { setState(() => _dismissed = true); } + /// Open Settings (where System-AI + MCP are configured) and + /// re-probe when it closes. The Settings dialog overlays the + /// welcome page rather than navigating, so without this the + /// checklist kept showing the pre-config state (e.g. "connect + /// System-AI" stayed unchecked right after saving a working + /// config). Navigation-based rows self-heal on return; these + /// dialog-based ones did not. + Future _openSettingsThenRefresh() async { + await ChainSettingsDialog.show(context); + if (mounted) await _refresh(); + } + /// Localized plain-language label for the applied setup profile. String _profileLabel(AppLocalizations l) => switch (_setupProfile) { 'enterprise' => l.setupProfileEnterprise, @@ -664,13 +676,13 @@ class _OnboardingChecklistState extends State<_OnboardingChecklist> { _aiOk, l.welcomeChecklistAi, l.welcomeChecklistAiHint, - () => ChainSettingsDialog.show(context), + _openSettingsThenRefresh, ), ( _mcpOk, l.welcomeChecklistMcp, l.welcomeChecklistMcpHint, - () => ChainSettingsDialog.show(context), + _openSettingsThenRefresh, ), ( _moduleOk, diff --git a/lib/widgets/chain_system_ai_editor.dart b/lib/widgets/chain_system_ai_editor.dart index c22129d..154ce2e 100644 --- a/lib/widgets/chain_system_ai_editor.dart +++ b/lib/widgets/chain_system_ai_editor.dart @@ -144,6 +144,7 @@ class _FaiSystemAiEditorState extends State { String? _modelsError; AskAiResult? _testResult; String? _error; + final _scrollController = ScrollController(); HardwareSnapshot? _hw; CuratedSnapshot? _curated; Map _curatedById = const {}; @@ -200,9 +201,26 @@ class _FaiSystemAiEditorState extends State { _endpoint.dispose(); _model.dispose(); _apiKeyEnv.dispose(); + _scrollController.dispose(); super.dispose(); } + /// Reveal the test-result / error panel. It renders at the bottom + /// of a scrollable, height-capped form, so on a tall dialog it + /// lands below the fold — the operator taps "Test connection", + /// the footer button flickers, and nothing *visible* changes. + /// Scroll it into view so the outcome is never missed. + void _revealBottom() { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (!_scrollController.hasClients) return; + _scrollController.animateTo( + _scrollController.position.maxScrollExtent, + duration: const Duration(milliseconds: 250), + curve: Curves.easeOut, + ); + }); + } + void _onProviderChanged(_ProviderPreset p) { setState(() { _preset = p; @@ -255,6 +273,7 @@ class _FaiSystemAiEditorState extends State { _saving = false; _error = e.toString(); }); + _revealBottom(); } } @@ -297,11 +316,13 @@ class _FaiSystemAiEditorState extends State { _testing = false; _testResult = r; }); + _revealBottom(); } catch (e) { setState(() { _testing = false; _error = e.toString(); }); + _revealBottom(); } } @@ -375,6 +396,7 @@ class _FaiSystemAiEditorState extends State { content: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 520, maxHeight: 600), child: SingleChildScrollView( + controller: _scrollController, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start,