From 47273a2d417e401ad6a08d44d41736b2ef1dae59 Mon Sep 17 00:00:00 2001 From: Haitao Pan Date: Mon, 23 Mar 2026 17:49:17 +0800 Subject: [PATCH] chore(release): bump to v0.6.2 and gate account access --- config/feature_flags.yaml | 18 ++++ lib/app/ui_feature_manifest.dart | 22 +++++ lib/features/settings/settings_page.dart | 88 ++++++++++--------- pubspec.yaml | 2 +- test/features/settings_page_suite.dart | 42 +++++++++ ...app_controller_desktop_platform_suite.dart | 17 +++- 6 files changed, 146 insertions(+), 43 deletions(-) diff --git a/config/feature_flags.yaml b/config/feature_flags.yaml index 417024e6..3d42ac69 100644 --- a/config/feature_flags.yaml +++ b/config/feature_flags.yaml @@ -134,6 +134,12 @@ mobile: build_modes: [debug, profile, release] description: Mobile settings gateway tab ui_surface: settings_page + account_access: + enabled: false + release_tier: experimental + build_modes: [debug, profile, release] + description: Mobile account access section + ui_surface: settings_page vault_server: enabled: false release_tier: experimental @@ -319,6 +325,12 @@ desktop: build_modes: [debug, profile, release] description: Desktop settings gateway tab ui_surface: settings_page + account_access: + enabled: false + release_tier: experimental + build_modes: [debug, profile, release] + description: Desktop account access section + ui_surface: settings_page vault_server: enabled: false release_tier: experimental @@ -444,6 +456,12 @@ web: build_modes: [debug, profile, release] description: Web settings gateway tab ui_surface: web_settings_page + account_access: + enabled: false + release_tier: experimental + build_modes: [] + description: Web does not expose account access section + ui_surface: web_settings_page vault_server: enabled: false release_tier: experimental diff --git a/lib/app/ui_feature_manifest.dart b/lib/app/ui_feature_manifest.dart index 3015e406..73df8cf1 100644 --- a/lib/app/ui_feature_manifest.dart +++ b/lib/app/ui_feature_manifest.dart @@ -65,6 +65,7 @@ abstract final class UiFeatureKeys { static const settingsGeneral = 'settings.general'; static const settingsWorkspace = 'settings.workspace'; static const settingsGateway = 'settings.gateway'; + static const settingsAccountAccess = 'settings.account_access'; static const settingsVaultServer = 'settings.vault_server'; static const settingsGatewaySetupCode = 'settings.gateway_setup_code'; static const settingsAgents = 'settings.agents'; @@ -256,6 +257,12 @@ mobile: build_modes: [debug, profile, release] description: Mobile settings gateway tab ui_surface: settings_page + account_access: + enabled: false + release_tier: experimental + build_modes: [debug, profile, release] + description: Mobile account access section + ui_surface: settings_page vault_server: enabled: false release_tier: experimental @@ -441,6 +448,12 @@ desktop: build_modes: [debug, profile, release] description: Desktop settings gateway tab ui_surface: settings_page + account_access: + enabled: false + release_tier: experimental + build_modes: [debug, profile, release] + description: Desktop account access section + ui_surface: settings_page vault_server: enabled: false release_tier: experimental @@ -566,6 +579,12 @@ web: build_modes: [debug, profile, release] description: Web settings gateway tab ui_surface: web_settings_page + account_access: + enabled: false + release_tier: experimental + build_modes: [] + description: Web does not expose account access section + ui_surface: web_settings_page vault_server: enabled: false release_tier: experimental @@ -948,6 +967,9 @@ class UiFeatureAccess { bool get supportsDiagnostics => isEnabledPath(UiFeatureKeys.settingsDiagnostics); + bool get supportsAccountAccess => + isEnabledPath(UiFeatureKeys.settingsAccountAccess); + bool get supportsGatewaySetupCode => isEnabledPath(UiFeatureKeys.settingsGatewaySetupCode); diff --git a/lib/features/settings/settings_page.dart b/lib/features/settings/settings_page.dart index 053ab683..dd334d35 100644 --- a/lib/features/settings/settings_page.dart +++ b/lib/features/settings/settings_page.dart @@ -240,7 +240,12 @@ class _SettingsPageState extends State { } return switch (_tab) { - SettingsTab.general => _buildGeneral(context, controller, settings), + SettingsTab.general => _buildGeneral( + context, + controller, + settings, + uiFeatures, + ), SettingsTab.workspace => _buildWorkspace(context, controller, settings), SettingsTab.gateway => _buildGateway( context, @@ -458,6 +463,7 @@ class _SettingsPageState extends State { BuildContext context, AppController controller, SettingsSnapshot settings, + UiFeatureAccess uiFeatures, ) { return [ SurfaceCard( @@ -492,55 +498,57 @@ class _SettingsPageState extends State { settings.copyWith(showDockIcon: value), ), ), - _SwitchRow( - label: appText('账号本地模式', 'Account local mode'), - value: settings.accountLocalMode, - onChanged: (value) => _saveSettings( - controller, - settings.copyWith(accountLocalMode: value), + if (uiFeatures.supportsAccountAccess) + _SwitchRow( + label: appText('账号本地模式', 'Account local mode'), + value: settings.accountLocalMode, + onChanged: (value) => _saveSettings( + controller, + settings.copyWith(accountLocalMode: value), + ), ), - ), ], ), ), if (controller.supportsDesktopIntegration) _buildLinuxDesktopIntegration(context, controller, settings), - SurfaceCard( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - appText('账号访问', 'Account Access'), - style: Theme.of(context).textTheme.titleLarge, - ), - const SizedBox(height: 16), - _EditableField( - label: appText('账号服务地址', 'Account Base URL'), - value: settings.accountBaseUrl, - onSubmitted: (value) => _saveSettings( - controller, - settings.copyWith(accountBaseUrl: value), + if (uiFeatures.supportsAccountAccess) + SurfaceCard( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + appText('账号访问', 'Account Access'), + style: Theme.of(context).textTheme.titleLarge, ), - ), - _EditableField( - label: appText('账号用户名', 'Account Username'), - value: settings.accountUsername, - onSubmitted: (value) => _saveSettings( - controller, - settings.copyWith(accountUsername: value), + const SizedBox(height: 16), + _EditableField( + label: appText('账号服务地址', 'Account Base URL'), + value: settings.accountBaseUrl, + onSubmitted: (value) => _saveSettings( + controller, + settings.copyWith(accountBaseUrl: value), + ), ), - ), - _EditableField( - label: appText('工作区名称', 'Workspace Label'), - value: settings.accountWorkspace, - onSubmitted: (value) => _saveSettings( - controller, - settings.copyWith(accountWorkspace: value), + _EditableField( + label: appText('账号用户名', 'Account Username'), + value: settings.accountUsername, + onSubmitted: (value) => _saveSettings( + controller, + settings.copyWith(accountUsername: value), + ), ), - ), - ], + _EditableField( + label: appText('工作区名称', 'Workspace Label'), + value: settings.accountWorkspace, + onSubmitted: (value) => _saveSettings( + controller, + settings.copyWith(accountWorkspace: value), + ), + ), + ], + ), ), - ), ]; } diff --git a/pubspec.yaml b/pubspec.yaml index 9cf551f9..ccb8a03d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: xworkmate description: "XWorkmate desktop-first AI workspace shell." publish_to: 'none' -version: 0.6.1+1 +version: 0.6.2+1 build-date: 2026-03-20 build-id: 4183a40 diff --git a/test/features/settings_page_suite.dart b/test/features/settings_page_suite.dart index 75a29a1a..c760f25e 100644 --- a/test/features/settings_page_suite.dart +++ b/test/features/settings_page_suite.dart @@ -91,6 +91,48 @@ void main() { expect(controller.themeMode, ThemeMode.light); }); + testWidgets('SettingsPage hides account access controls by default', ( + WidgetTester tester, + ) async { + final controller = await createTestController(tester); + + await pumpPage( + tester, + child: SettingsPage(controller: controller), + platform: TargetPlatform.macOS, + ); + + expect(find.text('账号访问'), findsNothing); + expect(find.text('Account Access'), findsNothing); + expect(find.text('账号本地模式'), findsNothing); + expect(find.text('Account local mode'), findsNothing); + }); + + testWidgets('SettingsPage can expose account access when feature enabled', ( + WidgetTester tester, + ) async { + final manifest = UiFeatureManifest.fallback().copyWithFeature( + platform: UiFeaturePlatform.desktop, + module: 'settings', + feature: 'account_access', + enabled: true, + releaseTier: UiFeatureReleaseTier.experimental, + ); + final controller = await createTestController( + tester, + uiFeatureManifest: manifest, + ); + + await pumpPage( + tester, + child: SettingsPage(controller: controller), + platform: TargetPlatform.macOS, + ); + + expect(find.text('账号访问'), findsOneWidget); + expect(find.text('账号本地模式'), findsOneWidget); + }); + testWidgets('SettingsPage integration tab exposes unified gateway controls', ( WidgetTester tester, ) async { diff --git a/test/runtime/app_controller_desktop_platform_suite.dart b/test/runtime/app_controller_desktop_platform_suite.dart index 46a9edc7..85bda946 100644 --- a/test/runtime/app_controller_desktop_platform_suite.dart +++ b/test/runtime/app_controller_desktop_platform_suite.dart @@ -236,7 +236,7 @@ void main() { final controller = AppController(desktopPlatformService: service); addTearDown(controller.dispose); - await Future.delayed(const Duration(milliseconds: 50)); + await _waitFor(() => !controller.initializing); expect(controller.supportsDesktopIntegration, isTrue); expect( @@ -276,7 +276,7 @@ void main() { addTearDown(server.close); addTearDown(controller.dispose); - await Future.delayed(const Duration(milliseconds: 50)); + await _waitFor(() => !controller.initializing); final result = await controller.testGatewayConnectionDraft( profile: GatewayConnectionProfile.defaults().copyWith( @@ -296,3 +296,16 @@ void main() { }, ); } + +Future _waitFor( + bool Function() condition, { + Duration timeout = const Duration(seconds: 2), +}) async { + final stopwatch = Stopwatch()..start(); + while (!condition()) { + if (stopwatch.elapsed > timeout) { + fail('Condition not met within ${timeout.inMilliseconds}ms'); + } + await Future.delayed(const Duration(milliseconds: 10)); + } +}