From cb2873e379eed5c7a6beb2d2610af6217b5b6300 Mon Sep 17 00:00:00 2001 From: Dusk Date: Sat, 25 Apr 2026 23:51:05 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E8=B0=83=E6=95=B4=E5=8D=A1=E7=89=87?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E8=AE=BE=E7=BD=AE=E6=96=87=E6=A1=88=E4=B8=8E?= =?UTF-8?q?=E5=90=AF=E7=94=A8=E8=AE=A1=E6=95=B0=20/=20fix=20card-types=20c?= =?UTF-8?q?opy=20and=20enabled=20count?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../settings/PluginSettingTab.test.ts | 108 ++++++++++++++++++ src/presentation/settings/PluginSettingTab.ts | 9 +- 2 files changed, 114 insertions(+), 3 deletions(-) diff --git a/src/presentation/settings/PluginSettingTab.test.ts b/src/presentation/settings/PluginSettingTab.test.ts index aa74420..0b32a53 100644 --- a/src/presentation/settings/PluginSettingTab.test.ts +++ b/src/presentation/settings/PluginSettingTab.test.ts @@ -725,6 +725,16 @@ describe("PluginSettingTab", () => { expect(() => queryByDataset(tab.containerEl, "cardTypeMarker", "semantic-qa")).toThrow("Element not found"); }); + it("does not render the legacy card-types description copy", async () => { + const plugin = new FakePlugin(); + const tab = new AnkiHeadingSyncSettingTab(plugin as never); + + tab.display(); + await expandCard(tab, "card-types"); + + expect(collectTexts(tab.containerEl)).not.toContain("直接编辑识别规则,修改后自动保存。"); + }); + it("auto saves toggle, heading, note type and field mapping edits", async () => { const plugin = new FakePlugin(); const tab = new AnkiHeadingSyncSettingTab(plugin as never); @@ -1049,6 +1059,104 @@ describe("PluginSettingTab", () => { expect(collectTexts(tab.containerEl).some((text) => text.includes("和本页缓存的 2 个模板不一致"))).toBe(false); }); + it("counts only enabled visible card types with cached fields in the status summary", async () => { + const plugin = new FakePlugin(); + plugin.settings = normalizePluginSettings({ + ...plugin.settings, + ankiNoteTypeCache: ["Basic", "Custom Cloze", QA_GROUP_USER_MODEL_NAME], + ankiModelFieldCache: { + Basic: { + fieldNames: ["Front", "Back", "Extra"], + loadedAt: 100, + }, + "Custom Cloze": { + fieldNames: ["Text", "Extra", "Hint"], + loadedAt: 100, + }, + [QA_GROUP_USER_MODEL_NAME]: { + fieldNames: ["题目", "标题", "问题01", "答案01"], + loadedAt: 100, + }, + }, + cardTypeConfigs: { + ...plugin.settings.cardTypeConfigs, + basic: { + ...plugin.settings.cardTypeConfigs.basic, + enabled: true, + noteType: "Basic", + }, + "qa-group": { + ...plugin.settings.cardTypeConfigs["qa-group"], + enabled: true, + noteType: QA_GROUP_USER_MODEL_NAME, + }, + cloze: { + ...plugin.settings.cardTypeConfigs.cloze, + enabled: false, + noteType: "Custom Cloze", + }, + }, + }); + plugin.noteModels = ["Basic", "Custom Cloze", QA_GROUP_USER_MODEL_NAME]; + const tab = new AnkiHeadingSyncSettingTab(plugin as never); + + tab.display(); + await expandCard(tab, "card-types"); + await flushPromises(); + + expect(collectTexts(tab.containerEl).some((text) => text.includes("当前使用缓存的 3 个笔记模板,已选择并配置 2 个卡片模式。"))).toBe(true); + + const clozeToggle = queryByDataset(tab.containerEl, "cardTypeEnabled", "cloze"); + clozeToggle.checked = true; + await clozeToggle.trigger("change"); + + expect(collectTexts(tab.containerEl).some((text) => text.includes("当前使用缓存的 3 个笔记模板,已选择并配置 3 个卡片模式。"))).toBe(true); + }); + + it("excludes enabled card types without cached fields from the configured count", async () => { + const plugin = new FakePlugin(); + plugin.settings = normalizePluginSettings({ + ...plugin.settings, + ankiNoteTypeCache: ["Basic", "Custom Cloze", QA_GROUP_USER_MODEL_NAME], + ankiModelFieldCache: { + Basic: { + fieldNames: ["Front", "Back", "Extra"], + loadedAt: 100, + }, + [QA_GROUP_USER_MODEL_NAME]: { + fieldNames: ["题目", "标题", "问题01", "答案01"], + loadedAt: 100, + }, + }, + cardTypeConfigs: { + ...plugin.settings.cardTypeConfigs, + basic: { + ...plugin.settings.cardTypeConfigs.basic, + enabled: true, + noteType: "Basic", + }, + "qa-group": { + ...plugin.settings.cardTypeConfigs["qa-group"], + enabled: true, + noteType: QA_GROUP_USER_MODEL_NAME, + }, + cloze: { + ...plugin.settings.cardTypeConfigs.cloze, + enabled: true, + noteType: "Custom Cloze", + }, + }, + }); + plugin.noteModels = ["Basic", "Custom Cloze", QA_GROUP_USER_MODEL_NAME]; + const tab = new AnkiHeadingSyncSettingTab(plugin as never); + + tab.display(); + await expandCard(tab, "card-types"); + await flushPromises(); + + expect(collectTexts(tab.containerEl).some((text) => text.includes("当前使用缓存的 3 个笔记模板,已选择并配置 2 个卡片模式。"))).toBe(true); + }); + it("switching note type immediately reuses cached field names", async () => { const plugin = new FakePlugin(); plugin.settings = normalizePluginSettings({ diff --git a/src/presentation/settings/PluginSettingTab.ts b/src/presentation/settings/PluginSettingTab.ts index 6e76223..c29a4b5 100644 --- a/src/presentation/settings/PluginSettingTab.ts +++ b/src/presentation/settings/PluginSettingTab.ts @@ -283,7 +283,6 @@ export class AnkiHeadingSyncSettingTab extends PluginSettingTab { private renderCardTypesCard(containerEl: HTMLElement): void { this.hydrateVisibleCardTypeCaches(); this.maybeStartNoteTypeCacheCheck(); - containerEl.createEl("p", { text: t("settings.cards.cardTypes.desc") }); const actionRow = containerEl.createDiv(); actionRow.style.display = "flex"; @@ -1012,8 +1011,12 @@ export class AnkiHeadingSyncSettingTab extends PluginSettingTab { private countConfiguredCardTypes(ankiModelFieldCache: AnkiHeadingSyncPlugin["settings"]["ankiModelFieldCache"]): number { return VISIBLE_CARD_TYPE_CONFIG_IDS.reduce((configuredCount, configId) => { - const selectedModelName = this.plugin.settings.cardTypeConfigs[configId].noteType; - return configuredCount + (ankiModelFieldCache[selectedModelName] ? 1 : 0); + const config = this.plugin.settings.cardTypeConfigs[configId]; + if (!config.enabled) { + return configuredCount; + } + + return configuredCount + (ankiModelFieldCache[config.noteType] ? 1 : 0); }, 0); }