Merge pull request #50 from wagesj45/codex/refactor-messagedisplayaction-button-to-popup
Add popup details view
This commit is contained in:
commit
05176ab30e
7 changed files with 66 additions and 116 deletions
|
@ -13,8 +13,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||
logger.js = logger.js
|
||||
manifest.json = manifest.json
|
||||
README.md = README.md
|
||||
reasoning.html = reasoning.html
|
||||
reasoning.js = reasoning.js
|
||||
EndProjectSection
|
||||
ProjectSection(FolderGlobals) = preProject
|
||||
Q_5_4Users_4Jordan_4Documents_4Gitea_4thunderbird-ai-filter_4src_4manifest_1json__JsonSchema =
|
||||
|
@ -54,8 +52,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "prompt_templates", "prompt_
|
|||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "resources", "resources", "{68A87938-5C2B-49F5-8AAA-8A34FBBFD854}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
resources\clearCacheButton.js = resources\clearCacheButton.js
|
||||
resources\reasonButton.js = resources\reasonButton.js
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "img", "img", "{F266602F-1755-4A95-A11B-6C90C701C5BF}"
|
||||
|
|
|
@ -30,7 +30,7 @@ function setIcon(path) {
|
|||
}
|
||||
|
||||
function updateActionIcon() {
|
||||
let path = "resources/img/logo32.png";
|
||||
let path = "resources/img/brain.png";
|
||||
if (processing || queuedCount > 0) {
|
||||
path = "resources/img/busy.png";
|
||||
}
|
||||
|
@ -223,40 +223,9 @@ async function clearCacheForMessages(idsInput) {
|
|||
|
||||
logger.aiLog("background.js loaded – ready to classify", {debug: true});
|
||||
if (browser.messageDisplayAction) {
|
||||
browser.messageDisplayAction.setTitle({ title: "Classify" });
|
||||
browser.messageDisplayAction.setTitle({ title: "Details" });
|
||||
if (browser.messageDisplayAction.setLabel) {
|
||||
browser.messageDisplayAction.setLabel({ label: "Classify" });
|
||||
}
|
||||
}
|
||||
if (browser.scripting && browser.scripting.messageDisplay) {
|
||||
try {
|
||||
const scripts = [
|
||||
{
|
||||
id: "clear-cache-button",
|
||||
js: ["resources/clearCacheButton.js"],
|
||||
},
|
||||
{
|
||||
id: "reason-button",
|
||||
js: ["resources/reasonButton.js"],
|
||||
},
|
||||
];
|
||||
await browser.scripting.messageDisplay.registerScripts(scripts);
|
||||
} catch (e) {
|
||||
logger.aiLog("failed to register message display script", { level: 'warn' }, e);
|
||||
}
|
||||
} else if (browser.messageDisplayScripts) {
|
||||
try {
|
||||
const scripts = [
|
||||
{ js: ["resources/clearCacheButton.js"] },
|
||||
{ js: ["resources/reasonButton.js"] },
|
||||
];
|
||||
if (browser.messageDisplayScripts.registerScripts) {
|
||||
await browser.messageDisplayScripts.registerScripts(scripts);
|
||||
} else if (browser.messageDisplayScripts.register) {
|
||||
await browser.messageDisplayScripts.register(scripts);
|
||||
}
|
||||
} catch (e) {
|
||||
logger.aiLog("failed to register message display script", { level: 'warn' }, e);
|
||||
browser.messageDisplayAction.setLabel({ label: "Details" });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -293,17 +262,7 @@ async function clearCacheForMessages(idsInput) {
|
|||
icons: { "16": "resources/img/brain.png" }
|
||||
});
|
||||
|
||||
if (browser.messageDisplayAction) {
|
||||
browser.messageDisplayAction.onClicked.addListener(async (tab) => {
|
||||
try {
|
||||
const msgs = await browser.messageDisplay.getDisplayedMessages(tab.id);
|
||||
const ids = msgs.map(m => m.id);
|
||||
await applyAiRules(ids);
|
||||
} catch (e) {
|
||||
logger.aiLog("failed to apply AI rules from action", { level: 'error' }, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
browser.menus.onClicked.addListener(async info => {
|
||||
if (info.menuItemId === "apply-ai-rules-list" || info.menuItemId === "apply-ai-rules-display") {
|
||||
|
@ -317,7 +276,7 @@ async function clearCacheForMessages(idsInput) {
|
|||
} else if (info.menuItemId === "view-ai-reason-list" || info.menuItemId === "view-ai-reason-display") {
|
||||
const id = info.messageId || info.selectedMessages?.messages?.[0]?.id;
|
||||
if (id) {
|
||||
const url = browser.runtime.getURL(`reasoning.html?mid=${id}`);
|
||||
const url = browser.runtime.getURL(`details.html?mid=${id}`);
|
||||
browser.tabs.create({ url });
|
||||
}
|
||||
}
|
||||
|
@ -383,6 +342,45 @@ async function clearCacheForMessages(idsInput) {
|
|||
logger.aiLog("failed to collect reasons", { level: 'error' }, e);
|
||||
return { subject: '', reasons: [] };
|
||||
}
|
||||
} else if (msg?.type === "sortana:getDetails") {
|
||||
try {
|
||||
const id = msg.id;
|
||||
const hdr = await messenger.messages.get(id);
|
||||
const subject = hdr?.subject || "";
|
||||
if (!aiRules.length) {
|
||||
const { aiRules: stored } = await storage.local.get("aiRules");
|
||||
aiRules = Array.isArray(stored) ? stored.map(r => {
|
||||
if (r.actions) return r;
|
||||
const actions = [];
|
||||
if (r.tag) actions.push({ type: 'tag', tagKey: r.tag });
|
||||
if (r.moveTo) actions.push({ type: 'move', folder: r.moveTo });
|
||||
const rule = { criterion: r.criterion, actions };
|
||||
if (r.stopProcessing) rule.stopProcessing = true;
|
||||
return rule;
|
||||
}) : [];
|
||||
}
|
||||
const results = [];
|
||||
for (const rule of aiRules) {
|
||||
const key = await sha256Hex(`${id}|${rule.criterion}`);
|
||||
const matched = AiClassifier.getCachedResult(key);
|
||||
const reason = AiClassifier.getReason(key);
|
||||
if (matched !== null || reason) {
|
||||
results.push({ criterion: rule.criterion, matched, reason });
|
||||
}
|
||||
}
|
||||
return { subject, results };
|
||||
} catch (e) {
|
||||
logger.aiLog("failed to collect details", { level: 'error' }, e);
|
||||
return { subject: '', results: [] };
|
||||
}
|
||||
} else if (msg?.type === "sortana:clearCacheForMessage") {
|
||||
try {
|
||||
await clearCacheForMessages([msg.id]);
|
||||
return { ok: true };
|
||||
} catch (e) {
|
||||
logger.aiLog("failed to clear cache for message", { level: 'error' }, e);
|
||||
return { ok: false };
|
||||
}
|
||||
} else {
|
||||
logger.aiLog("Unknown message type, ignoring", {level: 'warn'}, msg?.type);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>AI Reasoning</title>
|
||||
<title>AI Details</title>
|
||||
<link rel="stylesheet" href="options/bulma.css">
|
||||
</head>
|
||||
<body>
|
||||
|
@ -10,8 +10,11 @@
|
|||
<div class="container">
|
||||
<h1 class="title" id="subject"></h1>
|
||||
<div id="rules"></div>
|
||||
<div class="buttons mt-4">
|
||||
<button class="button is-danger" id="clear">Clear Cache</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<script src="reasoning.js"></script>
|
||||
<script src="details.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -3,25 +3,33 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
const id = parseInt(params.get('mid'), 10);
|
||||
if (!id) return;
|
||||
try {
|
||||
const { subject, reasons } = await browser.runtime.sendMessage({ type: 'sortana:getReasons', id });
|
||||
const { subject, results } = await browser.runtime.sendMessage({ type: 'sortana:getDetails', id });
|
||||
document.getElementById('subject').textContent = subject;
|
||||
const container = document.getElementById('rules');
|
||||
for (const r of reasons) {
|
||||
for (const r of results) {
|
||||
const article = document.createElement('article');
|
||||
article.className = 'message mb-4';
|
||||
const color = r.matched === true ? 'is-success' : 'is-danger';
|
||||
article.className = `message ${color} mb-4`;
|
||||
const header = document.createElement('div');
|
||||
header.className = 'message-header';
|
||||
header.innerHTML = `<p>${r.criterion}</p>`;
|
||||
const body = document.createElement('div');
|
||||
body.className = 'message-body';
|
||||
const status = document.createElement('p');
|
||||
status.textContent = r.matched ? 'Matched' : 'Did not match';
|
||||
const pre = document.createElement('pre');
|
||||
pre.textContent = r.reason;
|
||||
pre.textContent = r.reason || '';
|
||||
body.appendChild(status);
|
||||
body.appendChild(pre);
|
||||
article.appendChild(header);
|
||||
article.appendChild(body);
|
||||
container.appendChild(article);
|
||||
}
|
||||
document.getElementById('clear').addEventListener('click', async () => {
|
||||
await browser.runtime.sendMessage({ type: 'sortana:clearCacheForMessage', id });
|
||||
window.close();
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('failed to load reasons', e);
|
||||
console.error('failed to load details', e);
|
||||
}
|
||||
});
|
|
@ -22,9 +22,10 @@
|
|||
"default_icon": "resources/img/logo32.png"
|
||||
},
|
||||
"message_display_action": {
|
||||
"default_icon": "resources/img/logo32.png",
|
||||
"default_title": "Classify",
|
||||
"default_label": "Classify"
|
||||
"default_icon": "resources/img/brain.png",
|
||||
"default_title": "Details",
|
||||
"default_label": "Details",
|
||||
"default_popup": "details.html"
|
||||
},
|
||||
"background": { "scripts": [ "background.js" ] },
|
||||
"options_ui": {
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
(function() {
|
||||
function addButton() {
|
||||
const toolbar = document.querySelector("#header-view-toolbar") ||
|
||||
document.querySelector("#mail-toolbox toolbar");
|
||||
if (!toolbar || document.getElementById('sortana-clear-cache-button')) return;
|
||||
const button = document.createXULElement ?
|
||||
document.createXULElement('toolbarbutton') :
|
||||
document.createElement('button');
|
||||
button.id = 'sortana-clear-cache-button';
|
||||
button.setAttribute('label', 'Clear Cache');
|
||||
button.className = 'toolbarbutton-1';
|
||||
button.addEventListener('command', () => {
|
||||
browser.runtime.sendMessage({ type: 'sortana:clearCacheForDisplayed' });
|
||||
});
|
||||
toolbar.appendChild(button);
|
||||
}
|
||||
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
||||
addButton();
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', addButton, { once: true });
|
||||
}
|
||||
})();
|
|
@ -1,34 +0,0 @@
|
|||
(function() {
|
||||
function addButton() {
|
||||
const toolbar = document.querySelector("#header-view-toolbar") ||
|
||||
document.querySelector("#mail-toolbox toolbar");
|
||||
if (!toolbar || document.getElementById('sortana-reason-button')) return;
|
||||
const button = document.createXULElement ?
|
||||
document.createXULElement('toolbarbutton') :
|
||||
document.createElement('button');
|
||||
button.id = 'sortana-reason-button';
|
||||
button.setAttribute('label', 'View Reasoning');
|
||||
button.className = 'toolbarbutton-1';
|
||||
const icon = browser.runtime.getURL('resources/img/brain.png');
|
||||
if (button.setAttribute) {
|
||||
button.setAttribute('image', icon);
|
||||
} else {
|
||||
button.style.backgroundImage = `url(${icon})`;
|
||||
button.style.backgroundSize = 'contain';
|
||||
}
|
||||
button.addEventListener('command', async () => {
|
||||
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
|
||||
const tabId = tabs[0]?.id;
|
||||
const msgs = tabId ? await browser.messageDisplay.getDisplayedMessages(tabId) : [];
|
||||
if (!msgs.length) return;
|
||||
const url = browser.runtime.getURL(`reasoning.html?mid=${msgs[0].id}`);
|
||||
browser.tabs.create({ url });
|
||||
});
|
||||
toolbar.appendChild(button);
|
||||
}
|
||||
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
||||
addButton();
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', addButton, { once: true });
|
||||
}
|
||||
})();
|
Loading…
Add table
Add a link
Reference in a new issue