From 9dbfb93e62e30ca60a3fc1d2b3ed63a86408dbed Mon Sep 17 00:00:00 2001 From: mic Date: Mon, 20 Apr 2026 22:06:18 +0200 Subject: [PATCH] added a generic error panel. see #766 --- _locales/en/messages.json | 4 +++ claude-spec/01-architecture.md | 2 +- claude-spec/04-api-integrations.md | 5 ++++ js/mzta-compose-script.js | 48 ++++++++++++++++++++++++++++++ mzta-background.js | 36 +++++++++++++++++----- 5 files changed, 87 insertions(+), 8 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index cb1b54d3..2dcf1779 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -2103,6 +2103,10 @@ "message": "Delete summary", "description": "" }, + "generic_error_dismiss": { + "message": "Dismiss", + "description": "Menu item to dismiss a generic error panel shown in the message display." + }, "prefs_OptionText_translate": { "message": "Translate email", "description": "" diff --git a/claude-spec/01-architecture.md b/claude-spec/01-architecture.md index 082f7b8c..51cc992d 100644 --- a/claude-spec/01-architecture.md +++ b/claude-spec/01-architecture.md @@ -160,7 +160,7 @@ taTranslationStore.saveTranslation() | `js/mzta-placeholders.js` | Placeholder definitions and resolution logic | | `js/mzta-utils.js` | General utilities (email parsing, storage helpers, etc.) | | `js/mzta-utils-prompt.js` | Prompt-specific utilities (text truncation, lang injection, `buildSummaryPrompt()` for unified summary prompt assembly, `buildTranslationPrompt()` for translation prompt assembly) | -| `js/mzta-compose-script.js` | Content script for compose and message display: injects AI response into compose window, renders unified toolbar (spam badge, summary/translation trigger buttons) and content panels (spam explanation, summary, translation) in message display via `#mzta-container` | +| `js/mzta-compose-script.js` | Content script for compose and message display: injects AI response into compose window, renders unified toolbar (spam badge, summary/translation trigger buttons) and content panels (generic error, spam explanation, summary, translation) in message display via `#mzta-container` | | `js/mzta-chatgpt.js` | ChatGPT Web integration (opens browser window, reads DOM) | | `js/mzta-special-commands.js` | Handles special prompt actions (add_tags, calendar, task) | | `js/mzta-spamreport.js` | Spam filter logic | diff --git a/claude-spec/04-api-integrations.md b/claude-spec/04-api-integrations.md index 5139e4f5..2c72142c 100644 --- a/claude-spec/04-api-integrations.md +++ b/claude-spec/04-api-integrations.md @@ -67,6 +67,11 @@ Validation is skipped when `use_specific_api = true` (i.e., the prompt's own `ap The `isConfigError` flag on the thrown error tells callers in `mzta-background.js` to display the error in the panel **without saving it to storage** — so the user can fix settings and retry cleanly. +Feature-specific routing of `isConfigError`: + +- `summarize` / `translate` / `spamfilter`: the error is shown in their dedicated panel (summary / translation / spam panel) and **not** persisted to storage. +- `add_tags`: it has **no dedicated panel**, so the error is routed to the **generic error panel** via `showGenericError(errMsg, source)` in `mzta-background.js`, which broadcasts a `showGenericError` message to all tabs. The content script `js/mzta-compose-script.js` renders it as `#mzta-generic-error` inside `#mzta-container`. The panel is dismissible and reusable by any future feature without its own UI. + For regular prompts (`openChatGPT()`), validation still happens inside the listener callback after the API webchat window is created (unchanged behavior). ## Web Worker Pattern diff --git a/js/mzta-compose-script.js b/js/mzta-compose-script.js index 78fdc3bf..28be6795 100644 --- a/js/mzta-compose-script.js +++ b/js/mzta-compose-script.js @@ -131,6 +131,7 @@ function _removeToolbarItem(id) { } const _PANEL_ORDER = [ + 'mzta-generic-error', 'mzta-spam-check-progress', 'mzta-spam-report-banner', 'mzta-translation-generating', 'mzta-translation-banner', 'mzta-summary-generating', 'mzta-summary-banner' @@ -866,6 +867,53 @@ switch (message.command) { break; + case "showGenericError": { + const { message: errMsg, source } = message.data || {}; + const colors = _getThemeColors(); + const ec = colors.summaryErr; + + const panel = document.createElement('div'); + panel.style.cssText = `background-color: ${ec.bg}; color: ${ec.text}; padding: 0.5rem; border-radius: 4px; border: 1px solid ${ec.border}; font-size: 14px; display: flex; align-items: flex-start; gap: 8px;`; + + const icon = document.createElement('span'); + icon.textContent = '\u26A0'; + icon.style.cssText = 'font-size: 16px; flex-shrink: 0; line-height: 1.4;'; + + const textWrap = document.createElement('div'); + textWrap.style.cssText = 'flex: 1; min-width: 0; line-height: 1.4;'; + + const prefix = document.createElement('strong'); + prefix.textContent = `[ThunderAI${source ? ' | ' + source : ''}] `; + const body = document.createElement('span'); + body.textContent = errMsg || ''; + textWrap.appendChild(prefix); + textWrap.appendChild(body); + + const rightGroup = document.createElement('span'); + rightGroup.style.cssText = 'display: flex; align-items: center; gap: 5px; margin-left: auto;'; + const dismissMenu = createThreeDotsMenu(colors.isDark, [ + { + icon: '\u00D7', + label: browser.i18n.getMessage("generic_error_dismiss") || 'Dismiss', + hoverColor: '#cc0000', + onClick: () => { _removePanel('mzta-generic-error'); } + } + ], { bg: ec.bg, border: ec.border, text: ec.text }); + rightGroup.appendChild(dismissMenu); + + panel.appendChild(icon); + panel.appendChild(textWrap); + panel.appendChild(rightGroup); + + _addPanel('mzta-generic-error', panel); + return Promise.resolve(true); + } + + case "clearGenericError": { + _removePanel('mzta-generic-error'); + return Promise.resolve(true); + } + case "showSpamCheckInProgress": { _removePanel('mzta-spam-report-banner'); _removeToolbarItem('mzta-toolbar-spam'); diff --git a/mzta-background.js b/mzta-background.js index 30c68eca..f6ee06a9 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -1727,6 +1727,16 @@ const newEmailListener = (folder, messagesList) => { return _newEmailListener(); } +async function showGenericError(errMsg, source) { + let tabs = await browser.tabs.query({}); + for (const tab of tabs) { + browser.tabs.sendMessage(tab.id, { + command: "showGenericError", + data: { message: errMsg, source: source } + }).catch(() => {}); + } +} + async function updateSpamPanel(messageId, command, data = null) { if (prefs_init.spamfilter_show_msg_panel) { let tabs = await browser.tabs.query({ active: true, currentWindow: true }); @@ -1833,16 +1843,28 @@ async function processEmails(args) { do_debug: prefs_aats.do_debug, config: curr_prompt_add_tags }); - await cmd_addTags.initWorker(); - let tags_current_email = []; + let addTagsInitFailed = false; try { - tags_current_email = taPromptUtils.getTagsFromResponse(await cmd_addTags.sendPrompt(), prefs_aats.add_tags_auto_uselist, prefs_aats.add_tags_auto_uselist_list); + await cmd_addTags.initWorker(); } catch (err) { - console.error("[ThunderAI | Auto add_tags] Error getting tags: ", err); + addTagsInitFailed = true; + if (err.isConfigError) { + await showGenericError(err.message, browser.i18n.getMessage('prompt_add_tags') || 'Add tags'); + } else { + console.error("[ThunderAI | Auto add_tags] initWorker error: ", err); + } + } + if (!addTagsInitFailed) { + let tags_current_email = []; + try { + tags_current_email = taPromptUtils.getTagsFromResponse(await cmd_addTags.sendPrompt(), prefs_aats.add_tags_auto_uselist, prefs_aats.add_tags_auto_uselist_list); + } catch (err) { + console.error("[ThunderAI | Auto add_tags] Error getting tags: ", err); + } + taLog.log("tags_current_email: " + JSON.stringify(tags_current_email)); + let _data = { messageId: message.id, tags: tags_current_email }; + _assign_tags(_data, !prefs_aats.add_tags_auto_force_existing, prefs_aats.add_tags_exclusions_exact_match); } - taLog.log("tags_current_email: " + JSON.stringify(tags_current_email)); - let _data = { messageId: message.id, tags: tags_current_email }; - _assign_tags(_data, !prefs_aats.add_tags_auto_force_existing, prefs_aats.add_tags_exclusions_exact_match); } }