Fix Test Connection buttons needing a tab switch to activate

Root cause: on macOS, SecureField's bound value only commits when the
field loses focus (Return, click-away, tab switch) — not on every
keystroke like TextField. Every "Test Connection" button (Sync, Email,
Paperless, Anytype, Jarvis) gated its .disabled(...) on a *Configured
value fed by a SecureField-backed API key/token/password, so typing a
key straight into the field left the button looking permanently disabled
until something else forced a focus change.

Moved the "configured" check from the disabled condition into each test
function's action handler instead — by the time a click fires, the click
itself has already moved focus away and committed the field's value, so
the check now sees it correctly. Buttons stay clickable at all times
(gated only by their own isTesting spinner state) and show a clear
"Enter X first" message if config is actually incomplete.
This commit is contained in:
2026-08-20 08:00:03 +02:00
parent e105aa7378
commit 5787dee018
+32 -5
View File
@@ -2131,7 +2131,7 @@ It's better to admit "I need more information" or "I cannot do that" than to fak
Text("Test Connection")
}
}
.disabled(isTestingSync || !settingsService.syncConfigured)
.disabled(isTestingSync)
if let result = syncTestResult {
Text(result)
.font(.system(size: 13))
@@ -2431,7 +2431,7 @@ It's better to admit "I need more information" or "I cannot do that" than to fak
Text("Test Connection")
}
}
.disabled(isTestingEmailConnection || !settingsService.emailServerConfigured)
.disabled(isTestingEmailConnection)
if let result = emailConnectionTestResult {
Text(result)
.font(.system(size: settingsService.guiTextSize - 1))
@@ -2714,7 +2714,7 @@ It's better to admit "I need more information" or "I cannot do that" than to fak
Text("Test Connection")
}
}
.disabled(isTestingPaperless || !settingsService.paperlessConfigured)
.disabled(isTestingPaperless)
if let result = paperlessTestResult {
Text(result)
.font(.system(size: 13))
@@ -2748,6 +2748,11 @@ It's better to admit "I need more information" or "I cannot do that" than to fak
private func testPaperlessConnection() async {
isTestingPaperless = true
paperlessTestResult = nil
guard settingsService.paperlessConfigured else {
paperlessTestResult = "✗ Enter a base URL and API token first."
isTestingPaperless = false
return
}
let result = await PaperlessService.shared.testConnection()
await MainActor.run {
switch result {
@@ -2825,7 +2830,7 @@ It's better to admit "I need more information" or "I cannot do that" than to fak
Text("Test Connection")
}
}
.disabled(isTestingAnytype || !settingsService.anytypeMcpConfigured)
.disabled(isTestingAnytype)
if let result = anytypeTestResult {
Text(result)
.font(.system(size: 13))
@@ -2920,7 +2925,7 @@ It's better to admit "I need more information" or "I cannot do that" than to fak
Text("Test Connection")
}
}
.disabled(isTestingJarvis || !settingsService.jarvisConfigured)
.disabled(isTestingJarvis)
if let result = jarvisTestResult {
Text(result)
.font(.system(size: 13))
@@ -2951,6 +2956,11 @@ It's better to admit "I need more information" or "I cannot do that" than to fak
private func testJarvisConnection() async {
isTestingJarvis = true
jarvisTestResult = nil
guard settingsService.jarvisConfigured else {
jarvisTestResult = "✗ Enter a URL and API key first."
isTestingJarvis = false
return
}
let ok = await JarvisService.shared.testConnection()
await MainActor.run {
jarvisTestResult = ok ? "✓ Connected" : "✗ Connection failed"
@@ -2961,6 +2971,11 @@ It's better to admit "I need more information" or "I cannot do that" than to fak
private func testAnytypeConnection() async {
isTestingAnytype = true
anytypeTestResult = nil
guard settingsService.anytypeMcpConfigured else {
anytypeTestResult = "✗ Enter an API key first."
isTestingAnytype = false
return
}
let result = await AnytypeMCPService.shared.testConnection()
await MainActor.run {
switch result {
@@ -3389,6 +3404,12 @@ It's better to admit "I need more information" or "I cannot do that" than to fak
isTestingEmailConnection = true
emailConnectionTestResult = nil
guard settingsService.emailServerConfigured else {
emailConnectionTestResult = "✗ Enter your IMAP/SMTP host, username, and password first."
isTestingEmailConnection = false
return
}
do {
let result = try await EmailService.shared.testConnection()
emailConnectionTestResult = "\(result)"
@@ -3405,6 +3426,12 @@ It's better to admit "I need more information" or "I cannot do that" than to fak
isTestingSync = true
syncTestResult = nil
guard settingsService.syncConfigured else {
syncTestResult = "✗ Enter a repository URL and credentials first."
isTestingSync = false
return
}
do {
let result = try await gitSync.testConnection()
syncTestResult = "\(result)"