Add default bridge save action

This commit is contained in:
Haitao Pan 2026-06-08 18:35:08 +08:00
parent 23d8dd741a
commit b222434a9d
3 changed files with 83 additions and 2 deletions

View File

@ -242,7 +242,10 @@ class _WorkspaceManagementPanelState extends State<WorkspaceManagementPanel> {
const SizedBox(height: 12),
_LogPanel(controller: _controller),
const SizedBox(height: 12),
WorkspaceManagementResult(controller: _controller),
WorkspaceManagementResult(
controller: _controller,
appController: widget.appController,
),
],
),
),

View File

@ -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<void> _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(

View File

@ -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) {