diff --git a/lib/features/settings/settings_account_panel.dart b/lib/features/settings/settings_account_panel.dart index d413ca7a..ad4e9f10 100644 --- a/lib/features/settings/settings_account_panel.dart +++ b/lib/features/settings/settings_account_panel.dart @@ -99,7 +99,7 @@ class _SettingsAccountPanelState extends State controller: _signedOutTabController, tabs: [ Tab(text: appText('svc.plus 云端同步', 'svc.plus Cloud Sync')), - Tab(text: appText('手动 Bridge 配置', 'Manual Bridge Config')), + Tab(text: appText('AI 智能体工作空间', 'AI Agentic Workspace')), ], ), const SizedBox(height: 24), @@ -189,15 +189,15 @@ class _ManualBridgePanel extends StatelessWidget { ), const SizedBox(height: 16), Text( - appText('手动 Bridge 配置', 'Manual Bridge Config'), + appText('AI 智能体工作空间', 'AI Agentic Workspace'), style: theme.textTheme.headlineMedium, textAlign: TextAlign.center, ), const SizedBox(height: 10), Text( appText( - '直接配置本地或私有 xworkmate-bridge 地址与令牌。', - 'Configure local or private xworkmate-bridge address and token directly.', + '直接配置本地或私有 AI 智能体工作空间地址与令牌。', + 'Configure a local or private AI Agentic Workspace address and token directly.', ), style: theme.textTheme.titleMedium?.copyWith( color: theme.textTheme.bodyMedium?.color?.withValues( @@ -799,7 +799,7 @@ String _connectionSourceLabel( ); return mode == _SignedInAccountMode.accountSync ? appText('svc.plus 托管配置', 'svc.plus managed profile') - : appText('手动 Bridge 配置', 'Manual Bridge configuration'); + : appText('AI 智能体工作空间', 'AI Agentic Workspace'); } class _TokenConfiguredSummary extends StatelessWidget { diff --git a/lib/features/workspace_management/workspace_management_result.dart b/lib/features/workspace_management/workspace_management_result.dart index 791c4d9a..b6c0c146 100644 --- a/lib/features/workspace_management/workspace_management_result.dart +++ b/lib/features/workspace_management/workspace_management_result.dart @@ -82,27 +82,34 @@ class WorkspaceManagementResult extends StatelessWidget { label: Text(WorkspaceManagementText.copyAddress), ), OutlinedButton.icon( - onPressed: () => Clipboard.setData(ClipboardData(text: token)), + onPressed: () => + Clipboard.setData(ClipboardData(text: token)), icon: const Icon(Icons.key_outlined), label: Text(appText('复制 Token', 'Copy token')), ), OutlinedButton.icon( onPressed: result == null ? null - : () => _saveAsDefault(result), - icon: const Icon(Icons.bookmark_add_outlined), - label: Text(appText('设为默认', 'Set as default')), - ), - OutlinedButton.icon( - onPressed: result == null ? null : () => _downloadResult(result), + : () => _downloadResult(result), icon: const Icon(Icons.download_outlined), label: Text(appText('下载凭据', 'Download credentials')), ), - FilledButton.tonalIcon( - onPressed: null, + FilledButton.icon( + onPressed: result == null + ? null + : () => _openWorkspace(result), icon: const Icon(Icons.settings_remote_outlined), label: Text(WorkspaceManagementText.connectToWorkspace), ), + FilledButton.icon( + onPressed: result == null + ? null + : () => _saveAsDefault(result), + icon: const Icon(Icons.bookmark_add_outlined), + label: Text( + appText('设为默认保存配置', 'Set as default and save config'), + ), + ), ], ), ], @@ -121,17 +128,41 @@ class WorkspaceManagementResult extends StatelessWidget { await File(location.path).writeAsString(result.downloadText); } + Future _openWorkspace(WorkspaceDeploymentResult result) async { + final url = result.url.trim(); + if (url.isEmpty) { + return; + } + try { + if (Platform.isMacOS) { + await Process.run('open', [url]); + return; + } + if (Platform.isWindows) { + await Process.run('cmd', ['/c', 'start', '', url]); + return; + } + if (Platform.isLinux) { + await Process.run('xdg-open', [url]); + } + } catch (error) { + debugPrint('Open workspace URL failed: $error'); + await Clipboard.setData(ClipboardData(text: url)); + } + } + Future _saveAsDefault(WorkspaceDeploymentResult result) async { final settingsController = appController.settingsController; final currentSettings = appController.settings; - final nextSettings = await settingsController.buildSavedAccountProfileSettings( - settings: currentSettings, - accountBaseUrl: currentSettings.accountBaseUrl, - accountIdentifier: currentSettings.accountUsername, - bridgeServerUrl: result.url, - bridgeToken: result.bridgeToken, - isManualBridge: true, - ); + final nextSettings = await settingsController + .buildSavedAccountProfileSettings( + settings: currentSettings, + accountBaseUrl: currentSettings.accountBaseUrl, + accountIdentifier: currentSettings.accountUsername, + bridgeServerUrl: result.url, + bridgeToken: result.bridgeToken, + isManualBridge: true, + ); await appController.saveSettings(nextSettings, refreshAfterSave: true); } @@ -143,7 +174,9 @@ class WorkspaceManagementResult extends StatelessWidget { decoration: BoxDecoration( color: theme.colorScheme.errorContainer.withValues(alpha: 0.45), borderRadius: BorderRadius.circular(8), - border: Border.all(color: theme.colorScheme.error.withValues(alpha: 0.35)), + border: Border.all( + color: theme.colorScheme.error.withValues(alpha: 0.35), + ), ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, @@ -162,8 +195,7 @@ class WorkspaceManagementResult extends StatelessWidget { ), const SizedBox(height: 4), Text( - controller.errorMessage ?? - appText('请查看日志。', 'Check logs.'), + controller.errorMessage ?? appText('请查看日志。', 'Check logs.'), ), ], ), diff --git a/test/features/settings/settings_account_panel_test.dart b/test/features/settings/settings_account_panel_test.dart index bfca15a0..31c7e7ac 100644 --- a/test/features/settings/settings_account_panel_test.dart +++ b/test/features/settings/settings_account_panel_test.dart @@ -156,7 +156,7 @@ void main() { ), ); - await tester.tap(find.text('手动 Bridge 配置')); + await tester.tap(find.text('AI 智能体工作空间')); await tester.pump(); await tester.enterText( find.byKey(const ValueKey('settings-manual-bridge-url-field')), @@ -211,7 +211,7 @@ void main() { ), ); - await tester.tap(find.text('手动 Bridge 配置')); + await tester.tap(find.text('AI 智能体工作空间')); await tester.pump(); expect(saveCount, 0); @@ -265,7 +265,7 @@ void main() { ), ); - await tester.tap(find.text('手动 Bridge 配置')); + await tester.tap(find.text('AI 智能体工作空间')); await tester.pump(); await tester.enterText( find.byKey(const ValueKey('settings-manual-bridge-url-field')), diff --git a/test/features/workspace_management/workspace_management_widget_test.dart b/test/features/workspace_management/workspace_management_widget_test.dart index d25b7706..d4a13cb5 100644 --- a/test/features/workspace_management/workspace_management_widget_test.dart +++ b/test/features/workspace_management/workspace_management_widget_test.dart @@ -34,7 +34,10 @@ void main() { expect(find.text('创建 / 升级 AI 工作空间'), findsOneWidget); expect(find.text('workspace.example.com'), findsOneWidget); - expect(find.byKey(const Key('workspace-management-upgrade-button')), findsOneWidget); + expect( + find.byKey(const Key('workspace-management-upgrade-button')), + findsOneWidget, + ); expect( tester .widget( @@ -77,7 +80,10 @@ void main() { provisionController.updateForm(logsExpanded: true); await tester.pumpAndSettle(); - expect(find.byKey(const Key('workspace-management-log-content')), findsOneWidget); + expect( + find.byKey(const Key('workspace-management-log-content')), + findsOneWidget, + ); expect(find.textContaining('hello log'), findsOneWidget); }); @@ -108,9 +114,13 @@ void main() { expect(find.text('https://xworkmate-bridge.example.com'), findsOneWidget); expect(find.text('bridge-token-123'), findsOneWidget); expect(find.text('下载凭据'), findsOneWidget); + expect(find.text('连接到该工作空间'), findsOneWidget); + expect(find.text('设为默认保存配置'), findsOneWidget); }); - testWidgets('success result can save deployed bridge as default', (tester) async { + testWidgets('success result can save deployed bridge as default', ( + tester, + ) async { final store = _MemorySecureConfigStore(); final appController = _NoopAppController(store: store); final provisionController = WorkspaceProvisionController( @@ -140,8 +150,8 @@ void main() { ); await tester.pumpAndSettle(); - await tester.ensureVisible(find.text('设为默认')); - await tester.tap(find.text('设为默认')); + await tester.ensureVisible(find.text('设为默认保存配置')); + await tester.tap(find.text('设为默认保存配置')); await tester.pumpAndSettle(); expect( @@ -150,11 +160,7 @@ void main() { ); expect( await appController.settingsController.loadSecretValueByRef( - appController - .settings - .acpBridgeServerModeConfig - .selfHosted - .passwordRef, + appController.settings.acpBridgeServerModeConfig.selfHosted.passwordRef, ), 'save-token-123', );