Merge pull request #96 from wagesj45/codex/add-enabled-checkbox-to-rules-ui
Add enabled toggle for rules
This commit is contained in:
commit
39ffa288fa
3 changed files with 25 additions and 5 deletions
|
@ -19,6 +19,7 @@ message meets a specified criterion.
|
||||||
- **Light/Dark themes** – automatically match Thunderbird's appearance with optional manual override.
|
- **Light/Dark themes** – automatically match Thunderbird's appearance with optional manual override.
|
||||||
- **Automatic rules** – create rules that tag, move, copy, forward, reply, delete, archive, mark read/unread or flag/unflag messages based on AI classification. Rules can optionally apply only to unread messages and can ignore messages outside a chosen age range.
|
- **Automatic rules** – create rules that tag, move, copy, forward, reply, delete, archive, mark read/unread or flag/unflag messages based on AI classification. Rules can optionally apply only to unread messages and can ignore messages outside a chosen age range.
|
||||||
- **Rule ordering** – drag rules to prioritize them and optionally stop processing after a match.
|
- **Rule ordering** – drag rules to prioritize them and optionally stop processing after a match.
|
||||||
|
- **Rule enable/disable** – temporarily turn a rule off without removing it.
|
||||||
- **Account & folder filters** – limit rules to specific accounts or folders.
|
- **Account & folder filters** – limit rules to specific accounts or folders.
|
||||||
- **Context menu** – apply AI rules from the message list or the message display action button.
|
- **Context menu** – apply AI rules from the message list or the message display action button.
|
||||||
- **Status icons** – toolbar icons show when classification is in progress and briefly display success or error states.
|
- **Status icons** – toolbar icons show when classification is in progress and briefly display success or error states.
|
||||||
|
@ -75,7 +76,7 @@ Sortana is implemented entirely with standard WebExtension scripts—no custom e
|
||||||
deleting or archiving a message when it matches. Drag rules to
|
deleting or archiving a message when it matches. Drag rules to
|
||||||
reorder them, check *Only apply to unread messages* to skip read mail,
|
reorder them, check *Only apply to unread messages* to skip read mail,
|
||||||
set optional minimum or maximum message age limits, select the accounts or
|
set optional minimum or maximum message age limits, select the accounts or
|
||||||
folders a rule should apply to, and
|
folders a rule should apply to, uncheck *Enabled* to temporarily disable a rule, and
|
||||||
check *Stop after match* to halt further processing. Forward and reply actions
|
check *Stop after match* to halt further processing. Forward and reply actions
|
||||||
open a compose window using the account that received the message.
|
open a compose window using the account that received the message.
|
||||||
3. Save your settings. New mail will be evaluated automatically using the
|
3. Save your settings. New mail will be evaluated automatically using the
|
||||||
|
|
|
@ -36,6 +36,7 @@ function normalizeRules(rules) {
|
||||||
if (r.actions) {
|
if (r.actions) {
|
||||||
if (!Array.isArray(r.accounts)) r.accounts = [];
|
if (!Array.isArray(r.accounts)) r.accounts = [];
|
||||||
if (!Array.isArray(r.folders)) r.folders = [];
|
if (!Array.isArray(r.folders)) r.folders = [];
|
||||||
|
r.enabled = r.enabled !== false;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
const actions = [];
|
const actions = [];
|
||||||
|
@ -49,6 +50,7 @@ function normalizeRules(rules) {
|
||||||
if (typeof r.maxAgeDays === 'number') rule.maxAgeDays = r.maxAgeDays;
|
if (typeof r.maxAgeDays === 'number') rule.maxAgeDays = r.maxAgeDays;
|
||||||
if (Array.isArray(r.accounts)) rule.accounts = r.accounts;
|
if (Array.isArray(r.accounts)) rule.accounts = r.accounts;
|
||||||
if (Array.isArray(r.folders)) rule.folders = r.folders;
|
if (Array.isArray(r.folders)) rule.folders = r.folders;
|
||||||
|
rule.enabled = r.enabled !== false;
|
||||||
return rule;
|
return rule;
|
||||||
}) : [];
|
}) : [];
|
||||||
}
|
}
|
||||||
|
@ -234,6 +236,9 @@ async function processMessage(id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const rule of aiRules) {
|
for (const rule of aiRules) {
|
||||||
|
if (rule.enabled === false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (hdr && Array.isArray(rule.accounts) && rule.accounts.length &&
|
if (hdr && Array.isArray(rule.accounts) && rule.accounts.length &&
|
||||||
!rule.accounts.includes(hdr.folder.accountId)) {
|
!rule.accounts.includes(hdr.folder.accountId)) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -326,6 +326,16 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
});
|
});
|
||||||
header.appendChild(delBtn);
|
header.appendChild(delBtn);
|
||||||
|
|
||||||
|
const enabledLabel = document.createElement('label');
|
||||||
|
enabledLabel.className = 'checkbox ml-2';
|
||||||
|
const enabledCheck = document.createElement('input');
|
||||||
|
enabledCheck.type = 'checkbox';
|
||||||
|
enabledCheck.className = 'rule-enabled';
|
||||||
|
enabledCheck.checked = rule.enabled !== false;
|
||||||
|
enabledLabel.appendChild(enabledCheck);
|
||||||
|
enabledLabel.append(' Enabled');
|
||||||
|
header.appendChild(enabledLabel);
|
||||||
|
|
||||||
const actionsContainer = document.createElement('div');
|
const actionsContainer = document.createElement('div');
|
||||||
actionsContainer.className = 'rule-actions mb-2';
|
actionsContainer.className = 'rule-actions mb-2';
|
||||||
|
|
||||||
|
@ -469,18 +479,19 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
});
|
});
|
||||||
const stopProcessing = ruleEl.querySelector('.stop-processing')?.checked;
|
const stopProcessing = ruleEl.querySelector('.stop-processing')?.checked;
|
||||||
const unreadOnly = ruleEl.querySelector('.unread-only')?.checked;
|
const unreadOnly = ruleEl.querySelector('.unread-only')?.checked;
|
||||||
|
const enabled = ruleEl.querySelector('.rule-enabled')?.checked !== false;
|
||||||
const minAgeDays = parseFloat(ruleEl.querySelector('.min-age')?.value);
|
const minAgeDays = parseFloat(ruleEl.querySelector('.min-age')?.value);
|
||||||
const maxAgeDays = parseFloat(ruleEl.querySelector('.max-age')?.value);
|
const maxAgeDays = parseFloat(ruleEl.querySelector('.max-age')?.value);
|
||||||
const accounts = [...(ruleEl.querySelector('.account-select')?.selectedOptions || [])].map(o => o.value);
|
const accounts = [...(ruleEl.querySelector('.account-select')?.selectedOptions || [])].map(o => o.value);
|
||||||
const folders = [...(ruleEl.querySelector('.folder-filter-select')?.selectedOptions || [])].map(o => o.value);
|
const folders = [...(ruleEl.querySelector('.folder-filter-select')?.selectedOptions || [])].map(o => o.value);
|
||||||
const rule = { criterion, actions, unreadOnly, stopProcessing };
|
const rule = { criterion, actions, unreadOnly, stopProcessing, enabled };
|
||||||
if (!isNaN(minAgeDays)) rule.minAgeDays = minAgeDays;
|
if (!isNaN(minAgeDays)) rule.minAgeDays = minAgeDays;
|
||||||
if (!isNaN(maxAgeDays)) rule.maxAgeDays = maxAgeDays;
|
if (!isNaN(maxAgeDays)) rule.maxAgeDays = maxAgeDays;
|
||||||
if (accounts.length) rule.accounts = accounts;
|
if (accounts.length) rule.accounts = accounts;
|
||||||
if (folders.length) rule.folders = folders;
|
if (folders.length) rule.folders = folders;
|
||||||
return rule;
|
return rule;
|
||||||
});
|
});
|
||||||
data.push({ criterion: '', actions: [], unreadOnly: false, stopProcessing: false, accounts: [], folders: [] });
|
data.push({ criterion: '', actions: [], unreadOnly: false, stopProcessing: false, enabled: true, accounts: [], folders: [] });
|
||||||
renderRules(data);
|
renderRules(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -488,6 +499,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
if (r.actions) {
|
if (r.actions) {
|
||||||
if (!Array.isArray(r.accounts)) r.accounts = [];
|
if (!Array.isArray(r.accounts)) r.accounts = [];
|
||||||
if (!Array.isArray(r.folders)) r.folders = [];
|
if (!Array.isArray(r.folders)) r.folders = [];
|
||||||
|
if (r.enabled !== false) r.enabled = true; else r.enabled = false;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
const actions = [];
|
const actions = [];
|
||||||
|
@ -501,6 +513,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
if (typeof r.maxAgeDays === 'number') rule.maxAgeDays = r.maxAgeDays;
|
if (typeof r.maxAgeDays === 'number') rule.maxAgeDays = r.maxAgeDays;
|
||||||
if (Array.isArray(r.accounts)) rule.accounts = r.accounts;
|
if (Array.isArray(r.accounts)) rule.accounts = r.accounts;
|
||||||
if (Array.isArray(r.folders)) rule.folders = r.folders;
|
if (Array.isArray(r.folders)) rule.folders = r.folders;
|
||||||
|
rule.enabled = r.enabled !== false;
|
||||||
return rule;
|
return rule;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -644,11 +657,12 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
});
|
});
|
||||||
const stopProcessing = ruleEl.querySelector('.stop-processing')?.checked;
|
const stopProcessing = ruleEl.querySelector('.stop-processing')?.checked;
|
||||||
const unreadOnly = ruleEl.querySelector('.unread-only')?.checked;
|
const unreadOnly = ruleEl.querySelector('.unread-only')?.checked;
|
||||||
|
const enabled = ruleEl.querySelector('.rule-enabled')?.checked !== false;
|
||||||
const minAgeDays = parseFloat(ruleEl.querySelector('.min-age')?.value);
|
const minAgeDays = parseFloat(ruleEl.querySelector('.min-age')?.value);
|
||||||
const maxAgeDays = parseFloat(ruleEl.querySelector('.max-age')?.value);
|
const maxAgeDays = parseFloat(ruleEl.querySelector('.max-age')?.value);
|
||||||
const accounts = [...(ruleEl.querySelector('.account-select')?.selectedOptions || [])].map(o => o.value);
|
const accounts = [...(ruleEl.querySelector('.account-select')?.selectedOptions || [])].map(o => o.value);
|
||||||
const folders = [...(ruleEl.querySelector('.folder-filter-select')?.selectedOptions || [])].map(o => o.value);
|
const folders = [...(ruleEl.querySelector('.folder-filter-select')?.selectedOptions || [])].map(o => o.value);
|
||||||
const rule = { criterion, actions, unreadOnly, stopProcessing };
|
const rule = { criterion, actions, unreadOnly, stopProcessing, enabled };
|
||||||
if (!isNaN(minAgeDays)) rule.minAgeDays = minAgeDays;
|
if (!isNaN(minAgeDays)) rule.minAgeDays = minAgeDays;
|
||||||
if (!isNaN(maxAgeDays)) rule.maxAgeDays = maxAgeDays;
|
if (!isNaN(maxAgeDays)) rule.maxAgeDays = maxAgeDays;
|
||||||
if (accounts.length) rule.accounts = accounts;
|
if (accounts.length) rule.accounts = accounts;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue