diff --git a/lib/features/workspace_management/workspace_management_panel.dart b/lib/features/workspace_management/workspace_management_panel.dart index 2c7e6fc2..b5540a25 100644 --- a/lib/features/workspace_management/workspace_management_panel.dart +++ b/lib/features/workspace_management/workspace_management_panel.dart @@ -242,7 +242,10 @@ class _WorkspaceManagementPanelState extends State { const SizedBox(height: 12), _LogPanel(controller: _controller), const SizedBox(height: 12), - WorkspaceManagementResult(controller: _controller), + WorkspaceManagementResult( + controller: _controller, + appController: widget.appController, + ), ], ), ), diff --git a/lib/features/workspace_management/workspace_management_result.dart b/lib/features/workspace_management/workspace_management_result.dart index 4e5b9a7a..791c4d9a 100644 --- a/lib/features/workspace_management/workspace_management_result.dart +++ b/lib/features/workspace_management/workspace_management_result.dart @@ -4,15 +4,22 @@ import 'package:file_selector/file_selector.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import '../../app/app_controller.dart'; import '../../i18n/app_language.dart'; +import '../../runtime/runtime_controllers.dart'; import 'workspace_management_i18n.dart'; import 'workspace_provision_controller.dart'; import 'workspace_provision_models.dart'; class WorkspaceManagementResult extends StatelessWidget { - const WorkspaceManagementResult({super.key, required this.controller}); + const WorkspaceManagementResult({ + super.key, + required this.controller, + required this.appController, + }); final WorkspaceProvisionController controller; + final AppController appController; @override Widget build(BuildContext context) { @@ -79,6 +86,13 @@ class WorkspaceManagementResult extends StatelessWidget { 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), icon: const Icon(Icons.download_outlined), @@ -107,6 +121,20 @@ class WorkspaceManagementResult extends StatelessWidget { await File(location.path).writeAsString(result.downloadText); } + 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, + ); + await appController.saveSettings(nextSettings, refreshAfterSave: true); + } + Widget _failure(BuildContext context) { final theme = Theme.of(context); return Container( diff --git a/test/features/workspace_management/workspace_management_widget_test.dart b/test/features/workspace_management/workspace_management_widget_test.dart index 225203d6..d25b7706 100644 --- a/test/features/workspace_management/workspace_management_widget_test.dart +++ b/test/features/workspace_management/workspace_management_widget_test.dart @@ -109,6 +109,56 @@ void main() { expect(find.text('bridge-token-123'), findsOneWidget); expect(find.text('下载凭据'), findsOneWidget); }); + + testWidgets('success result can save deployed bridge as default', (tester) async { + final store = _MemorySecureConfigStore(); + final appController = _NoopAppController(store: store); + final provisionController = WorkspaceProvisionController( + executor: _FakeSshExecutor(), + ); + await tester.binding.setSurfaceSize(const Size(1200, 1400)); + addTearDown(() async { + await tester.binding.setSurfaceSize(null); + }); + addTearDown(() { + provisionController.dispose(); + appController.dispose(); + }); + provisionController.deploymentResult = const WorkspaceDeploymentResult( + url: 'https://acp-bridge.onwalk.net', + bridgeToken: 'save-token-123', + ); + provisionController.phase = ProvisionPhase.success; + + await tester.pumpWidget( + _buildApp( + WorkspaceManagementPanel( + appController: appController, + provisionController: provisionController, + ), + ), + ); + await tester.pumpAndSettle(); + + await tester.ensureVisible(find.text('设为默认')); + await tester.tap(find.text('设为默认')); + await tester.pumpAndSettle(); + + expect( + appController.settings.acpBridgeServerModeConfig.selfHosted.serverUrl, + 'https://acp-bridge.onwalk.net', + ); + expect( + await appController.settingsController.loadSecretValueByRef( + appController + .settings + .acpBridgeServerModeConfig + .selfHosted + .passwordRef, + ), + 'save-token-123', + ); + }); } Widget _buildApp(Widget child) {