added a generic error panel. see #766

This commit is contained in:
mic 2026-04-20 22:06:18 +02:00
parent 80f8bc1019
commit 9dbfb93e62
5 changed files with 87 additions and 8 deletions

View file

@ -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": ""

View file

@ -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 |

View file

@ -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

View file

@ -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');

View file

@ -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);
}
}