Merge branch 'codex/fix-target-refresh'

This commit is contained in:
Haitao Pan 2026-04-06 15:15:16 +08:00
commit cfc715f321
4 changed files with 76 additions and 18 deletions

View File

@ -48,6 +48,26 @@ import 'app_controller_desktop_runtime_helpers.dart';
// ignore_for_file: invalid_use_of_visible_for_testing_member, invalid_use_of_protected_member
extension AppControllerDesktopSettings on AppController {
SettingsSnapshot _markSavedGatewayTargetsForChangedProfiles(
SettingsSnapshot previous,
SettingsSnapshot snapshot,
) {
var nextSnapshot = snapshot;
if (jsonEncode(previous.primaryLocalGatewayProfile.toJson()) !=
jsonEncode(snapshot.primaryLocalGatewayProfile.toJson())) {
nextSnapshot = nextSnapshot.markGatewayTargetSaved(
AssistantExecutionTarget.local,
);
}
if (jsonEncode(previous.primaryRemoteGatewayProfile.toJson()) !=
jsonEncode(snapshot.primaryRemoteGatewayProfile.toJson())) {
nextSnapshot = nextSnapshot.markGatewayTargetSaved(
AssistantExecutionTarget.remote,
);
}
return nextSnapshot;
}
Future<void> saveSettingsDraft(SettingsSnapshot snapshot) async {
if (disposedInternal) {
return;
@ -173,7 +193,10 @@ extension AppControllerDesktopSettings on AppController {
notifyListeners();
return;
}
final nextSettings = settingsDraft;
final nextSettings = _markSavedGatewayTargetsForChangedProfiles(
settings,
settingsDraft,
);
markPendingApplyDomainsInternal(settings, nextSettings);
await persistDraftSecretsInternal();
if (nextSettings.toJsonString() != settings.toJsonString()) {
@ -237,19 +260,10 @@ extension AppControllerDesktopSettings on AppController {
return;
}
final previous = settings;
var nextSnapshot = snapshot;
if (jsonEncode(previous.primaryLocalGatewayProfile.toJson()) !=
jsonEncode(snapshot.primaryLocalGatewayProfile.toJson())) {
nextSnapshot = nextSnapshot.markGatewayTargetSaved(
AssistantExecutionTarget.local,
);
}
if (jsonEncode(previous.primaryRemoteGatewayProfile.toJson()) !=
jsonEncode(snapshot.primaryRemoteGatewayProfile.toJson())) {
nextSnapshot = nextSnapshot.markGatewayTargetSaved(
AssistantExecutionTarget.remote,
);
}
final nextSnapshot = _markSavedGatewayTargetsForChangedProfiles(
previous,
snapshot,
);
await persistSettingsSnapshotInternal(nextSnapshot);
if (disposedInternal) {
return;

View File

@ -556,10 +556,13 @@ XWorkmate Privacy Policy
SettingsSnapshot settings,
GatewayConnectionProfile profile,
) async {
final nextSettings = settings.copyWithGatewayProfileAt(
selectedGatewayProfileIndexInternal,
profile,
);
final executionTarget =
selectedGatewayProfileIndexInternal == kGatewayLocalProfileIndex
? AssistantExecutionTarget.local
: AssistantExecutionTarget.remote;
final nextSettings = settings
.copyWithGatewayProfileAt(selectedGatewayProfileIndexInternal, profile)
.markGatewayTargetSaved(executionTarget);
await saveSettingsInternal(controller, nextSettings);
if (!mounted) {
return;

View File

@ -767,6 +767,22 @@ paths:
expect(find.byKey(const ValueKey('gateway-host-field')), findsOneWidget);
});
testWidgets(
'SettingsPage gateway save and apply marks the selected gateway target as saved even for default-valued profiles',
(WidgetTester tester) async {
final controller = await createTestController(tester);
await _pumpSettingsPage(tester, controller, tab: SettingsTab.gateway);
await tester.tap(find.byKey(const ValueKey('gateway-profile-chip-0')));
await tester.pumpAndSettle();
await tester.tap(find.byKey(const ValueKey('gateway-apply-button')));
await tester.pumpAndSettle();
expect(controller.settings.savedGatewayTargets, contains('local'));
},
);
testWidgets('SettingsPage diagnostics tab filters and clears runtime logs', (
WidgetTester tester,
) async {

View File

@ -97,6 +97,31 @@ void main() {
},
);
test(
'AppController marks gateway targets as saved when settings drafts are applied',
() async {
final harness = await _DesktopControllerHarness.create();
addTearDown(harness.dispose);
final controller = harness.controller;
final defaults = controller.settings;
final nextSettings = defaults.copyWith(
gatewayProfiles: replaceGatewayProfileAt(
defaults.gatewayProfiles,
kGatewayLocalProfileIndex,
defaults.primaryLocalGatewayProfile.copyWith(
host: '127.0.0.1',
port: 18789,
),
),
);
await controller.saveSettingsDraft(nextSettings);
await controller.applySettingsDraft();
expect(controller.settings.savedGatewayTargets, contains('local'));
},
);
test(
'AppController keeps AI Gateway model choices when single-agent falls back to AI chat',
() async {