feat: show incomplete Magic Notes todo counts

Magic Notes can now show a default-on incomplete todo badge in the primary
navigation. The badge hides at zero, caps its visual label at 99+ while
retaining the exact accessible count, and refreshes after user or Agent/MCP
note changes.

Platform Features > Magic Notes includes a persistent switch that hides only
the count without changing notes or the Magic Notes entry. Existing settings
migrate with the count enabled.

Release note: 左侧“魔法笔记”入口现在可显示未完成待办数量;可在“平台功能 → 魔法笔记”中关闭,超过 99 项显示“99+”。
This commit is contained in:
mesalogo
2026-08-22 08:32:57 +08:00
parent fee4686750
commit fb51793595
25 changed files with 538 additions and 25 deletions
+50 -6
View File
@@ -58,13 +58,15 @@ describe('ApplicationSettingsStore', () => {
await expect(
store.update({
checkUpdatesOnStartup: false,
magicNotesEnabled: false
magicNotesEnabled: false,
magicNotesShowIncompleteTodoCount: false
})
).resolves.toEqual({
checkUpdatesOnStartup: false,
updateSource: 'github',
modelDownloadSource: 'modelscope',
magicNotesEnabled: false,
magicNotesShowIncompleteTodoCount: false,
magicNoteCommentMode: 'immediate',
magicNoteCommentFormat: 'combined'
})
@@ -73,15 +75,17 @@ describe('ApplicationSettingsStore', () => {
updateSource: 'github',
modelDownloadSource: 'modelscope',
magicNotesEnabled: false,
magicNotesShowIncompleteTodoCount: false,
magicNoteCommentMode: 'immediate',
magicNoteCommentFormat: 'combined'
})
expect(JSON.parse(await readFile(filePath, 'utf8'))).toEqual({
version: 7,
version: 8,
checkUpdatesOnStartup: false,
updateSource: 'github',
modelDownloadSource: 'modelscope',
magicNotesEnabled: false,
magicNotesShowIncompleteTodoCount: false,
magicNoteCommentMode: 'immediate',
magicNoteCommentFormat: 'combined',
lastSeenReleaseNotesVersion: null
@@ -107,6 +111,7 @@ describe('ApplicationSettingsStore', () => {
updateSource: 'github',
modelDownloadSource: 'modelscope',
magicNotesEnabled: false,
magicNotesShowIncompleteTodoCount: true,
magicNoteCommentMode: 'immediate',
magicNoteCommentFormat: 'combined'
})
@@ -130,6 +135,7 @@ describe('ApplicationSettingsStore', () => {
updateSource: 'github',
modelDownloadSource: 'modelscope',
magicNotesEnabled: false,
magicNotesShowIncompleteTodoCount: true,
magicNoteCommentMode: 'immediate',
magicNoteCommentFormat: 'combined'
})
@@ -153,6 +159,7 @@ describe('ApplicationSettingsStore', () => {
updateSource: 'github',
modelDownloadSource: 'modelscope',
magicNotesEnabled: true,
magicNotesShowIncompleteTodoCount: true,
magicNoteCommentMode: 'immediate',
magicNoteCommentFormat: 'combined'
})
@@ -176,6 +183,7 @@ describe('ApplicationSettingsStore', () => {
updateSource: 'github',
modelDownloadSource: 'modelscope',
magicNotesEnabled: true,
magicNotesShowIncompleteTodoCount: true,
magicNoteCommentMode: 'after-save-manual',
magicNoteCommentFormat: 'combined'
})
@@ -201,11 +209,12 @@ describe('ApplicationSettingsStore', () => {
new ApplicationSettingsStore(filePath).getLastSeenReleaseNotesVersion()
).resolves.toBe('0.8.18')
expect(JSON.parse(await readFile(filePath, 'utf8'))).toEqual({
version: 7,
version: 8,
checkUpdatesOnStartup: false,
updateSource: 'github',
modelDownloadSource: 'modelscope',
magicNotesEnabled: true,
magicNotesShowIncompleteTodoCount: true,
magicNoteCommentMode: 'after-save-manual',
magicNoteCommentFormat: 'narrative',
lastSeenReleaseNotesVersion: '0.8.18'
@@ -232,6 +241,7 @@ describe('ApplicationSettingsStore', () => {
updateSource: 'github',
modelDownloadSource: 'modelscope',
magicNotesEnabled: true,
magicNotesShowIncompleteTodoCount: true,
magicNoteCommentMode: 'after-save-auto',
magicNoteCommentFormat: 'structured'
})
@@ -258,6 +268,7 @@ describe('ApplicationSettingsStore', () => {
updateSource: 'mirror',
modelDownloadSource: 'modelscope',
magicNotesEnabled: true,
magicNotesShowIncompleteTodoCount: true,
magicNoteCommentMode: 'after-save-auto',
magicNoteCommentFormat: 'structured'
})
@@ -268,11 +279,40 @@ describe('ApplicationSettingsStore', () => {
await store.update({ modelDownloadSource: 'hugging-face' })
expect(JSON.parse(await readFile(filePath, 'utf8'))).toEqual({
...versionSix,
version: 7,
modelDownloadSource: 'hugging-face'
version: 8,
modelDownloadSource: 'hugging-face',
magicNotesShowIncompleteTodoCount: true
})
})
it('migrates version 7 to show incomplete todo counts', async () => {
const { filePath, store } = await createStore()
const versionSeven = {
version: 7,
checkUpdatesOnStartup: false,
updateSource: 'github',
modelDownloadSource: 'modelscope',
magicNotesEnabled: true,
magicNoteCommentMode: 'immediate',
magicNoteCommentFormat: 'combined',
lastSeenReleaseNotesVersion: null
}
await writeFile(filePath, JSON.stringify(versionSeven), 'utf8')
await expect(store.get()).resolves.toEqual({
checkUpdatesOnStartup: false,
updateSource: 'github',
modelDownloadSource: 'modelscope',
magicNotesEnabled: true,
magicNotesShowIncompleteTodoCount: true,
magicNoteCommentMode: 'immediate',
magicNoteCommentFormat: 'combined'
})
expect(JSON.parse(await readFile(filePath, 'utf8'))).toEqual(
versionSeven
)
})
it('strictly rejects incomplete full settings', () => {
for (const input of [
{},
@@ -319,6 +359,7 @@ describe('ApplicationSettingsStore', () => {
updateSource: 'github',
modelDownloadSource: 'modelscope',
magicNotesEnabled: true,
magicNotesShowIncompleteTodoCount: true,
magicNoteCommentMode: 'immediate',
magicNoteCommentFormat: 'combined'
})
@@ -433,15 +474,17 @@ describe('ApplicationSettingsStore', () => {
updateSource: 'github',
modelDownloadSource: 'modelscope',
magicNotesEnabled: false,
magicNotesShowIncompleteTodoCount: true,
magicNoteCommentMode: 'immediate',
magicNoteCommentFormat: 'combined'
})
expect(JSON.parse(await readFile(filePath, 'utf8'))).toEqual({
version: 7,
version: 8,
checkUpdatesOnStartup: false,
updateSource: 'github',
modelDownloadSource: 'modelscope',
magicNotesEnabled: false,
magicNotesShowIncompleteTodoCount: true,
magicNoteCommentMode: 'immediate',
magicNoteCommentFormat: 'combined',
lastSeenReleaseNotesVersion: null
@@ -467,6 +510,7 @@ describe('ApplicationSettingsStore', () => {
updateSource: 'github',
modelDownloadSource: 'modelscope',
magicNotesEnabled: true,
magicNotesShowIncompleteTodoCount: true,
magicNoteCommentMode: 'immediate',
magicNoteCommentFormat: 'combined'
})