From f8873e8eb6fbecfde5cf661c23470c9eca04a68d Mon Sep 17 00:00:00 2001 From: Haitao Pan Date: Tue, 24 Mar 2026 21:14:04 +0800 Subject: [PATCH] refactor(web): compact header connection status --- lib/web/web_assistant_page.dart | 95 +++++++++++++++++++++++-------- test/web/web_ui_browser_test.dart | 4 ++ 2 files changed, 76 insertions(+), 23 deletions(-) diff --git a/lib/web/web_assistant_page.dart b/lib/web/web_assistant_page.dart index 2055870c..8cb0a6e1 100644 --- a/lib/web/web_assistant_page.dart +++ b/lib/web/web_assistant_page.dart @@ -12,7 +12,6 @@ import '../runtime/runtime_models.dart'; import '../theme/app_palette.dart'; import '../widgets/desktop_workspace_scaffold.dart'; import '../widgets/pane_resize_handle.dart'; -import '../widgets/status_badge.dart'; import '../widgets/surface_card.dart'; import 'web_focus_panel.dart'; @@ -450,6 +449,7 @@ class _AssistantWorkspaceChrome extends StatelessWidget { @override Widget build(BuildContext context) { + final connectionState = controller.currentAssistantConnectionState; return SurfaceCard( tone: SurfaceCardTone.chrome, borderRadius: 10, @@ -463,15 +463,8 @@ class _AssistantWorkspaceChrome extends StatelessWidget { controller: controller, compact: true, ), - const SizedBox(width: 8), - StatusBadge( - status: StatusInfo( - controller.assistantConnectionStatusLabel, - controller.currentAssistantConnectionState.ready - ? StatusTone.success - : StatusTone.warning, - ), - ), + const Spacer(), + _ChromeConnectionChip(state: connectionState, compact: true), const SizedBox(width: 8), IconButton( key: const Key('assistant-workspace-chrome-toggle'), @@ -503,11 +496,11 @@ class _AssistantWorkspaceChrome extends StatelessWidget { ], ), ), - Wrap( - spacing: 8, - runSpacing: 8, - crossAxisAlignment: WrapCrossAlignment.center, + Row( + mainAxisSize: MainAxisSize.min, children: [ + _ChromeConnectionChip(state: connectionState), + const SizedBox(width: 8), IconButton( key: const Key('assistant-workspace-chrome-toggle'), tooltip: appText( @@ -529,15 +522,6 @@ class _AssistantWorkspaceChrome extends StatelessWidget { controller: controller, ), ), - const SizedBox(width: 8), - StatusBadge( - status: StatusInfo( - controller.assistantConnectionStatusLabel, - controller.currentAssistantConnectionState.ready - ? StatusTone.success - : StatusTone.warning, - ), - ), ], ), ], @@ -547,6 +531,71 @@ class _AssistantWorkspaceChrome extends StatelessWidget { } } +class _ChromeConnectionChip extends StatelessWidget { + const _ChromeConnectionChip({required this.state, this.compact = false}); + + final AssistantThreadConnectionState state; + final bool compact; + + @override + Widget build(BuildContext context) { + final palette = context.palette; + final theme = Theme.of(context); + final tone = switch (state.status) { + RuntimeConnectionStatus.connected => ( + palette.success.withValues(alpha: 0.14), + palette.success.withValues(alpha: 0.22), + palette.success, + ), + RuntimeConnectionStatus.connecting => ( + palette.accentMuted.withValues(alpha: 0.86), + palette.accent.withValues(alpha: 0.18), + palette.accent, + ), + RuntimeConnectionStatus.error => ( + palette.danger.withValues(alpha: 0.12), + palette.danger.withValues(alpha: 0.18), + palette.textSecondary, + ), + RuntimeConnectionStatus.offline => ( + palette.warning.withValues(alpha: 0.12), + palette.warning.withValues(alpha: 0.18), + palette.textSecondary, + ), + }; + final text = [ + state.primaryLabel.trim(), + state.detailLabel.trim(), + ].where((item) => item.isNotEmpty).join(' ยท '); + + return ConstrainedBox( + constraints: BoxConstraints(maxWidth: compact ? 280 : 360), + child: Container( + key: const Key('assistant-workspace-status-chip'), + padding: EdgeInsets.symmetric( + horizontal: compact ? 10 : 12, + vertical: compact ? 6 : 7, + ), + decoration: BoxDecoration( + color: tone.$1, + borderRadius: BorderRadius.circular(999), + border: Border.all(color: tone.$2), + ), + child: Text( + text, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: theme.textTheme.labelLarge?.copyWith( + color: tone.$3, + fontWeight: FontWeight.w600, + letterSpacing: 0.02, + ), + ), + ), + ); + } +} + class _AssistantSidePane extends StatelessWidget { const _AssistantSidePane({ required this.collapsed, diff --git a/test/web/web_ui_browser_test.dart b/test/web/web_ui_browser_test.dart index 1218c6c7..44a9d7be 100644 --- a/test/web/web_ui_browser_test.dart +++ b/test/web/web_ui_browser_test.dart @@ -31,6 +31,10 @@ void main() { find.byKey(const Key('assistant-session-settings-button')), findsOneWidget, ); + expect( + find.byKey(const Key('assistant-workspace-status-chip')), + findsOneWidget, + ); expect(find.byKey(const Key('assistant-top-target-button')), findsNothing); expect(find.byKey(const Key('assistant-target-button')), findsNothing); expect(