feat(notifications): add Open in Anki action and in-place progress updat

- Add openNoteInBrowser to AnkiConnectClient via guiBrowse IPC
- Add Open in Anki action button to mined-card overlay notifications and history entries
- Fall back to a direct AnkiConnectClient when the live integration is unavailable
- Embed notification images as base64 data URIs so history panel shows thumbnails
- Update same-id progress notifications in place to avoid spinner flicker
- Thread noteId through IPC overlay notification action payload
This commit is contained in:
2026-06-08 23:56:04 -07:00
parent a092cbe2da
commit f534938d4b
17 changed files with 640 additions and 65 deletions
+22 -1
View File
@@ -145,6 +145,7 @@ import type {
UpdateChannel,
WindowGeometry,
} from './types';
import { OPEN_ANKI_CARD_ACTION_ID } from './types';
import { AnkiIntegration } from './anki-integration';
import { SubtitleTimingTracker } from './subtitle-timing-tracker';
import { RuntimeOptionsManager } from './runtime-options';
@@ -3480,6 +3481,17 @@ function dismissOverlayNotification(id: string): void {
sendOverlayNotificationEvent({ id, dismiss: true });
}
async function openAnkiCardFromNotification(noteId: number): Promise<void> {
const activeIntegrationOpen = appState.ankiIntegration?.openNoteInAnki(noteId);
if (activeIntegrationOpen) {
await activeIntegrationOpen;
return;
}
const fallbackClient = new AnkiConnectClient(getResolvedConfig().ankiConnect.url);
await fallbackClient.openNoteInBrowser(noteId);
}
function toggleNotificationHistoryPanel(): void {
broadcastToOverlayWindows(IPC_CHANNELS.event.notificationHistoryToggle);
}
@@ -6979,7 +6991,7 @@ const { registerIpcRuntimeHandlers } = composeIpcRuntimeHandlers({
linuxOverlayInteractiveHint = interactive;
applyLinuxOverlayInputShapeFromLatestMeasurement();
},
handleOverlayNotificationAction: (notificationId, actionId) => {
handleOverlayNotificationAction: (notificationId, actionId, noteId) => {
if (
notificationId === UPDATE_AVAILABLE_NOTIFICATION_ID &&
actionId === INSTALL_UPDATE_ACTION_ID
@@ -6993,6 +7005,15 @@ const { registerIpcRuntimeHandlers } = composeIpcRuntimeHandlers({
logger.warn('Failed to install update from overlay notification action:', error);
});
}
if (actionId === OPEN_ANKI_CARD_ACTION_ID && noteId !== undefined) {
void openAnkiCardFromNotification(noteId).catch((error) => {
logger.warn('Failed to open Anki card from overlay notification action:', error);
showConfiguredStatusNotification('Failed to open Anki card in Anki.', {
id: 'open-anki-card-failed',
variant: 'error',
});
});
}
},
onYoutubePickerResolve: (request) => youtubeFlowRuntime.resolveActivePicker(request),
openYomitanSettings: () => openYomitanSettings(),