t190:Gemini 金鑰刪不掉——清空輸入框現在真的會刪除
leo 08-04 實撞:「我切到 Gemini 把內容刪掉,再切回 Workers AI,儲存, 回去發現 Gemini Key 還在」。要求:「如果他不想留 Key 了,要可以刪除」。 真兇:cfg.GeminiAPIKey = key 寫在 if useGemini 裡 ⇒ 選回雲端 AI 時整段跳過, 舊金鑰原封不動(帳號層同病)⇒ 清空輸入框等於沒作用。 改成無條件以輸入框為準(清空=刪除),符合使用者心智模型: 我把欄位清空並按儲存,它就該不見。頂層與每個帳號層一併清。 測試:新增 t190_test.go 兩則——清空要真的清掉(頂層+所有帳號層)、 選 Gemini 填值時每層都要寫進去(不可被本次修改弄壞)。兩則皆過,全套綠。
This commit is contained in:
+11
-4
@@ -950,16 +950,23 @@ func main() {
|
||||
engine := "workers-ai"
|
||||
if useGemini {
|
||||
engine = "gemma"
|
||||
cfg.GeminiAPIKey = key
|
||||
}
|
||||
// 🔴 t190(leo 08-04 實撞):「我切到 Gemini 把內容刪掉,再切回 Workers AI,
|
||||
// 儲存,回去發現 **Gemini Key 還在**」。
|
||||
//
|
||||
// 舊版把 `cfg.GeminiAPIKey = key` 寫在 `if useGemini` 裡 ⇒ 選回雲端 AI 時
|
||||
// 整段跳過、舊金鑰原封不動 ⇒ **清空輸入框等於沒作用,金鑰刪不掉**。
|
||||
// leo 要求:「如果他不想留 Key 了,**要可以刪除**」。
|
||||
//
|
||||
// 改成**無條件以輸入框為準**(清空=刪除),才符合使用者的心智模型:
|
||||
// 我把欄位清空並按儲存,它就該不見。
|
||||
cfg.GeminiAPIKey = key
|
||||
// 機器層寫一份當預設;各帳號層一併寫,避免舊 config 殘留的空欄位繼承到別的值。
|
||||
cfg.Extractor = engine
|
||||
cfg.ExtractorExplicit = true // ← 使用者主動選過,之後不再被預設覆蓋
|
||||
for i := range cfg.Accounts {
|
||||
cfg.Accounts[i].Extractor = engine
|
||||
if useGemini {
|
||||
cfg.Accounts[i].GeminiAPIKey = key
|
||||
}
|
||||
cfg.Accounts[i].GeminiAPIKey = key // 同上:帳號層也要能被清空
|
||||
}
|
||||
if err := saveConfig(cfg); err != nil {
|
||||
dialog.ShowError(err, win)
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
// t190(leo 08-04 實撞):「我切到 Gemini 把內容刪掉,再切回 Workers AI,儲存,
|
||||
// 回去發現 Gemini Key 還在」——清空輸入框必須真的把金鑰刪掉。
|
||||
//
|
||||
// 這裡驗的是「儲存邏輯」的契約:金鑰**無條件以輸入框為準**,
|
||||
// 不因為選了哪個引擎而跳過寫入(舊版的病就是寫在 if useGemini 裡)。
|
||||
func TestAISettingsSaveClearsKeyWhenEmptied(t *testing.T) {
|
||||
// 模擬儲存邏輯(與 main.go 的 AI 設定 handler 同一套規則)
|
||||
apply := func(cfg *directConfig, useGemini bool, key string) {
|
||||
engine := "workers-ai"
|
||||
if useGemini {
|
||||
engine = "gemma"
|
||||
}
|
||||
cfg.GeminiAPIKey = key
|
||||
cfg.Extractor = engine
|
||||
cfg.ExtractorExplicit = true
|
||||
for i := range cfg.Accounts {
|
||||
cfg.Accounts[i].Extractor = engine
|
||||
cfg.Accounts[i].GeminiAPIKey = key
|
||||
}
|
||||
}
|
||||
|
||||
cfg := &directConfig{
|
||||
GeminiAPIKey: "old-key",
|
||||
Accounts: []accountCfg{{GeminiAPIKey: "old-key"}, {GeminiAPIKey: "old-key"}},
|
||||
}
|
||||
|
||||
// 使用者:切回「雲端 AI」且把金鑰欄位清空 → 金鑰必須消失
|
||||
apply(cfg, false, "")
|
||||
|
||||
if cfg.GeminiAPIKey != "" {
|
||||
t.Errorf("頂層金鑰沒被清掉:%q(leo 實撞的病)", cfg.GeminiAPIKey)
|
||||
}
|
||||
for i, a := range cfg.Accounts {
|
||||
if a.GeminiAPIKey != "" {
|
||||
t.Errorf("帳號[%d] 金鑰沒被清掉:%q", i, a.GeminiAPIKey)
|
||||
}
|
||||
}
|
||||
if cfg.Extractor != "workers-ai" {
|
||||
t.Errorf("引擎應為 workers-ai,got %q", cfg.Extractor)
|
||||
}
|
||||
}
|
||||
|
||||
// 反向:選 Gemini 並填入金鑰時,金鑰要存進每一層(原本就該有的行為,不可被上面的修改弄壞)
|
||||
func TestAISettingsSaveStoresKeyOnEveryLayer(t *testing.T) {
|
||||
apply := func(cfg *directConfig, useGemini bool, key string) {
|
||||
engine := "workers-ai"
|
||||
if useGemini {
|
||||
engine = "gemma"
|
||||
}
|
||||
cfg.GeminiAPIKey = key
|
||||
cfg.Extractor = engine
|
||||
cfg.ExtractorExplicit = true
|
||||
for i := range cfg.Accounts {
|
||||
cfg.Accounts[i].Extractor = engine
|
||||
cfg.Accounts[i].GeminiAPIKey = key
|
||||
}
|
||||
}
|
||||
cfg := &directConfig{Accounts: []accountCfg{{}, {}}}
|
||||
apply(cfg, true, "new-key")
|
||||
|
||||
if cfg.GeminiAPIKey != "new-key" || cfg.Extractor != "gemma" {
|
||||
t.Errorf("頂層沒寫對:key=%q engine=%q", cfg.GeminiAPIKey, cfg.Extractor)
|
||||
}
|
||||
for i, a := range cfg.Accounts {
|
||||
if a.GeminiAPIKey != "new-key" || a.Extractor != "gemma" {
|
||||
t.Errorf("帳號[%d] 沒寫對:key=%q engine=%q", i, a.GeminiAPIKey, a.Extractor)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user