feat(settings): gate vault server behind experimental flag

This commit is contained in:
Haitao Pan 2026-03-23 14:40:07 +08:00
parent ded87aa63f
commit 196f0a96af
4 changed files with 110 additions and 16 deletions

View File

@ -134,6 +134,12 @@ mobile:
build_modes: [debug, profile, release]
description: Mobile settings gateway tab
ui_surface: settings_page
vault_server:
enabled: false
release_tier: experimental
build_modes: [debug, profile, release]
description: Mobile Vault server integration section
ui_surface: settings_page
gateway_setup_code:
enabled: false
release_tier: experimental
@ -313,6 +319,12 @@ desktop:
build_modes: [debug, profile, release]
description: Desktop settings gateway tab
ui_surface: settings_page
vault_server:
enabled: false
release_tier: experimental
build_modes: [debug, profile, release]
description: Desktop Vault server integration section
ui_surface: settings_page
gateway_setup_code:
enabled: false
release_tier: experimental
@ -432,6 +444,12 @@ web:
build_modes: [debug, profile, release]
description: Web settings gateway tab
ui_surface: web_settings_page
vault_server:
enabled: false
release_tier: experimental
build_modes: []
description: Web does not expose vault server integration
ui_surface: web_settings_page
gateway_setup_code:
enabled: false
release_tier: experimental

View File

@ -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 settingsVaultServer = 'settings.vault_server';
static const settingsGatewaySetupCode = 'settings.gateway_setup_code';
static const settingsAgents = 'settings.agents';
static const settingsAppearance = 'settings.appearance';
@ -255,6 +256,12 @@ mobile:
build_modes: [debug, profile, release]
description: Mobile settings gateway tab
ui_surface: settings_page
vault_server:
enabled: false
release_tier: experimental
build_modes: [debug, profile, release]
description: Mobile Vault server integration section
ui_surface: settings_page
gateway_setup_code:
enabled: false
release_tier: experimental
@ -434,6 +441,12 @@ desktop:
build_modes: [debug, profile, release]
description: Desktop settings gateway tab
ui_surface: settings_page
vault_server:
enabled: false
release_tier: experimental
build_modes: [debug, profile, release]
description: Desktop Vault server integration section
ui_surface: settings_page
gateway_setup_code:
enabled: false
release_tier: experimental
@ -553,6 +566,12 @@ web:
build_modes: [debug, profile, release]
description: Web settings gateway tab
ui_surface: web_settings_page
vault_server:
enabled: false
release_tier: experimental
build_modes: []
description: Web does not expose vault server integration
ui_surface: web_settings_page
gateway_setup_code:
enabled: false
release_tier: experimental
@ -932,6 +951,9 @@ class UiFeatureAccess {
bool get supportsGatewaySetupCode =>
isEnabledPath(UiFeatureKeys.settingsGatewaySetupCode);
bool get supportsVaultServer =>
isEnabledPath(UiFeatureKeys.settingsVaultServer);
List<SettingsTab> get availableSettingsTabs {
return SettingsTab.values
.where(

View File

@ -229,13 +229,24 @@ class _SettingsPageState extends State<SettingsPage> {
UiFeatureAccess uiFeatures,
) {
if (_detail != null) {
return _buildDetailContent(context, controller, settings, _detail!);
return _buildDetailContent(
context,
controller,
settings,
uiFeatures,
_detail!,
);
}
return switch (_tab) {
SettingsTab.general => _buildGeneral(context, controller, settings),
SettingsTab.workspace => _buildWorkspace(context, controller, settings),
SettingsTab.gateway => _buildGateway(context, controller, settings),
SettingsTab.gateway => _buildGateway(
context,
controller,
settings,
uiFeatures,
),
SettingsTab.agents => _buildAgents(context, controller, settings),
SettingsTab.appearance => _buildAppearance(context, controller),
SettingsTab.diagnostics => _buildDiagnostics(context, controller),
@ -253,6 +264,7 @@ class _SettingsPageState extends State<SettingsPage> {
BuildContext context,
AppController controller,
SettingsSnapshot settings,
UiFeatureAccess uiFeatures,
SettingsDetailPage detail,
) {
final workspaceSections = _buildWorkspace(context, controller, settings);
@ -268,8 +280,10 @@ class _SettingsPageState extends State<SettingsPage> {
),
const SizedBox(height: 16),
_buildOpenClawGatewayCard(context, controller, settings),
const SizedBox(height: 16),
_buildVaultProviderCard(context, controller, settings),
if (uiFeatures.supportsVaultServer) ...[
const SizedBox(height: 16),
_buildVaultProviderCard(context, controller, settings),
],
const SizedBox(height: 16),
_buildAiGatewayCard(context, controller, settings),
],
@ -295,7 +309,17 @@ class _SettingsPageState extends State<SettingsPage> {
),
),
const SizedBox(height: 16),
_buildVaultProviderCard(context, controller, settings),
if (uiFeatures.supportsVaultServer)
_buildVaultProviderCard(context, controller, settings)
else
SurfaceCard(
child: Text(
appText(
'当前发布配置未开放 Vault Server 参数。',
'Vault Server settings are disabled in this release configuration.',
),
),
),
],
SettingsDetailPage.ollamaProvider => <Widget>[
_buildDetailIntro(
@ -891,6 +915,7 @@ class _SettingsPageState extends State<SettingsPage> {
BuildContext context,
AppController controller,
SettingsSnapshot settings,
UiFeatureAccess uiFeatures,
) {
return [
_buildCollapsibleGatewaySection(
@ -902,16 +927,18 @@ class _SettingsPageState extends State<SettingsPage> {
}),
child: _buildOpenClawGatewayCard(context, controller, settings),
),
const SizedBox(height: 16),
_buildCollapsibleGatewaySection(
context: context,
title: appText('Vault Server', 'Vault Server'),
expanded: _vaultServerExpanded,
onChanged: (value) => setState(() {
_vaultServerExpanded = value;
}),
child: _buildVaultProviderCard(context, controller, settings),
),
if (uiFeatures.supportsVaultServer) ...[
const SizedBox(height: 16),
_buildCollapsibleGatewaySection(
context: context,
title: appText('Vault Server', 'Vault Server'),
expanded: _vaultServerExpanded,
onChanged: (value) => setState(() {
_vaultServerExpanded = value;
}),
child: _buildVaultProviderCard(context, controller, settings),
),
],
const SizedBox(height: 16),
_buildCollapsibleGatewaySection(
context: context,

View File

@ -106,7 +106,7 @@ void main() {
await tester.pumpAndSettle();
expect(find.text('OpenClaw Gateway'), findsOneWidget);
expect(find.text('Vault Server'), findsOneWidget);
expect(find.text('Vault Server'), findsNothing);
expect(find.byKey(const ValueKey('ai-gateway-url-field')), findsOneWidget);
expect(find.byKey(const ValueKey('gateway-mode-field')), findsNothing);
expect(find.text('认证诊断'), findsNothing);
@ -139,6 +139,33 @@ void main() {
);
});
testWidgets('SettingsPage can expose vault section when feature enabled', (
WidgetTester tester,
) async {
final manifest = UiFeatureManifest.fallback().copyWithFeature(
platform: UiFeaturePlatform.desktop,
module: 'settings',
feature: 'vault_server',
enabled: true,
releaseTier: UiFeatureReleaseTier.experimental,
);
final controller = await createTestController(
tester,
uiFeatureManifest: manifest,
);
await pumpPage(
tester,
child: SettingsPage(controller: controller),
platform: TargetPlatform.macOS,
);
await tester.tap(find.text('集成'));
await tester.pumpAndSettle();
expect(find.text('Vault Server'), findsOneWidget);
});
testWidgets('SettingsPage gateway sections can collapse individually', (
WidgetTester tester,
) async {