feat: align workspace ready actions and naming

This commit is contained in:
Haitao Pan 2026-06-09 10:58:15 +08:00
parent 27fd3a3286
commit a8cce8e32c
4 changed files with 76 additions and 38 deletions

View File

@ -99,7 +99,7 @@ class _SettingsAccountPanelState extends State<SettingsAccountPanel>
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 {

View File

@ -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<void> _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<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,
);
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.'),
),
],
),

View File

@ -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')),

View File

@ -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<FilledButton>(
@ -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',
);