Compare commits
3 Commits
b17608c3c5
...
0fa98a5955
| Author | SHA1 | Date | |
|---|---|---|---|
| 0fa98a5955 | |||
| 25ba0f5cff | |||
| 2a2237bd6e |
@ -1 +1 @@
|
|||||||
v20260113-01-changelog-markdown-render
|
v20260113-02-edge-mail-lightmode
|
||||||
|
|||||||
@ -290,10 +290,33 @@
|
|||||||
container.innerHTML = tableHtml;
|
container.innerHTML = tableHtml;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function wrapMailHtml(html) {
|
||||||
|
html = html || "";
|
||||||
|
var trimmed = (typeof html === "string") ? html.trim() : "";
|
||||||
|
var injection = '<meta charset="utf-8"><meta name="color-scheme" content="light"><meta name="supported-color-schemes" content="light"><meta name="viewport" content="width=device-width, initial-scale=1"><base target="_blank"><style>:root{color-scheme:light;}html{color-scheme:light;}body{margin:0;padding:8px;background:#fff;forced-color-adjust:none;-ms-high-contrast-adjust:none;}</style>';
|
||||||
|
|
||||||
|
function injectIntoFullDoc(doc) {
|
||||||
|
var d = doc || "";
|
||||||
|
if (/<head[^>]*>/i.test(d)) {
|
||||||
|
return d.replace(/<head[^>]*>/i, function (m) { return m + injection; });
|
||||||
|
}
|
||||||
|
if (/<html[^>]*>/i.test(d)) {
|
||||||
|
return d.replace(/<html[^>]*>/i, function (m) { return m + "<head>" + injection + "</head>"; });
|
||||||
|
}
|
||||||
|
return "<!doctype html><html><head>" + injection + "</head><body>" + d + "</body></html>";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trimmed.toLowerCase().indexOf("<!doctype") === 0 || trimmed.toLowerCase().indexOf("<html") === 0) {
|
||||||
|
return injectIntoFullDoc(trimmed);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "<!doctype html><html><head>" + injection + "</head><body>" + html + "</body></html>";
|
||||||
|
}
|
||||||
|
|
||||||
function setIframeHtml(html) {
|
function setIframeHtml(html) {
|
||||||
var iframe = document.getElementById('msg_body_container_iframe');
|
var iframe = document.getElementById('msg_body_container_iframe');
|
||||||
if (!iframe) return;
|
if (!iframe) return;
|
||||||
iframe.srcdoc = html || '<p>No message content stored.</p>';
|
iframe.srcdoc = wrapMailHtml(html || '<p>No message content stored.</p>');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function openMessage(messageId) {
|
async function openMessage(messageId) {
|
||||||
@ -314,7 +337,7 @@
|
|||||||
setText('msg_parsed', meta.parsed_at);
|
setText('msg_parsed', meta.parsed_at);
|
||||||
setText('msg_overall_message', meta.overall_message);
|
setText('msg_overall_message', meta.overall_message);
|
||||||
|
|
||||||
setIframeHtml(data.body_html);
|
setIframeHtml(data.body_html || "");
|
||||||
renderObjects(data.objects);
|
renderObjects(data.objects);
|
||||||
|
|
||||||
modal.show();
|
modal.show();
|
||||||
|
|||||||
@ -323,18 +323,26 @@
|
|||||||
|
|
||||||
function wrapMailHtml(html) {
|
function wrapMailHtml(html) {
|
||||||
html = html || "";
|
html = html || "";
|
||||||
// Ensure we render the mail HTML with its own CSS, isolated from the site styling.
|
var trimmed = (typeof html === "string") ? html.trim() : "";
|
||||||
return (
|
var injection = '<meta charset="utf-8"><meta name="color-scheme" content="light"><meta name="supported-color-schemes" content="light"><meta name="viewport" content="width=device-width, initial-scale=1"><base target="_blank"><style>:root{color-scheme:light;}html{color-scheme:light;}body{margin:0;padding:8px;background:#fff;forced-color-adjust:none;-ms-high-contrast-adjust:none;}</style>';
|
||||||
"<!doctype html><html><head><meta charset=\"utf-8\">" +
|
|
||||||
"<base target=\"_blank\">" +
|
function injectIntoFullDoc(doc) {
|
||||||
"</head><body style=\"margin:0; padding:8px;\">" +
|
var d = doc || "";
|
||||||
html +
|
if (/<head[^>]*>/i.test(d)) {
|
||||||
"</body></html>"
|
return d.replace(/<head[^>]*>/i, function (m) { return m + injection; });
|
||||||
);
|
}
|
||||||
|
if (/<html[^>]*>/i.test(d)) {
|
||||||
|
return d.replace(/<html[^>]*>/i, function (m) { return m + "<head>" + injection + "</head>"; });
|
||||||
|
}
|
||||||
|
return "<!doctype html><html><head>" + injection + "</head><body>" + d + "</body></html>";
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentJobId = null;
|
if (trimmed.toLowerCase().indexOf("<!doctype") === 0 || trimmed.toLowerCase().indexOf("<html") === 0) {
|
||||||
var currentRunId = null;
|
return injectIntoFullDoc(trimmed);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "<!doctype html><html><head>" + injection + "</head><body>" + html + "</body></html>";
|
||||||
|
}
|
||||||
|
|
||||||
function escapeHtml(s) {
|
function escapeHtml(s) {
|
||||||
return (s || "").toString()
|
return (s || "").toString()
|
||||||
|
|||||||
@ -380,22 +380,26 @@
|
|||||||
function wrapMailHtml(html) {
|
function wrapMailHtml(html) {
|
||||||
html = html || "";
|
html = html || "";
|
||||||
var trimmed = (typeof html === "string") ? html.trim() : "";
|
var trimmed = (typeof html === "string") ? html.trim() : "";
|
||||||
|
var injection = '<meta charset="utf-8"><meta name="color-scheme" content="light"><meta name="supported-color-schemes" content="light"><meta name="viewport" content="width=device-width, initial-scale=1"><base target="_blank"><style>:root{color-scheme:light;}html{color-scheme:light;}body{margin:0;padding:8px;background:#fff;forced-color-adjust:none;-ms-high-contrast-adjust:none;}</style>';
|
||||||
|
|
||||||
|
function injectIntoFullDoc(doc) {
|
||||||
|
var d = doc || "";
|
||||||
|
if (/<head[^>]*>/i.test(d)) {
|
||||||
|
return d.replace(/<head[^>]*>/i, function (m) { return m + injection; });
|
||||||
|
}
|
||||||
|
if (/<html[^>]*>/i.test(d)) {
|
||||||
|
return d.replace(/<html[^>]*>/i, function (m) { return m + "<head>" + injection + "</head>"; });
|
||||||
|
}
|
||||||
|
return "<!doctype html><html><head>" + injection + "</head><body>" + d + "</body></html>";
|
||||||
|
}
|
||||||
|
|
||||||
// If the content already looks like a full HTML document (common for report attachments),
|
|
||||||
// do not wrap it again.
|
|
||||||
if (trimmed.toLowerCase().indexOf("<!doctype") === 0 || trimmed.toLowerCase().indexOf("<html") === 0) {
|
if (trimmed.toLowerCase().indexOf("<!doctype") === 0 || trimmed.toLowerCase().indexOf("<html") === 0) {
|
||||||
return trimmed;
|
return injectIntoFullDoc(trimmed);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure we render the mail HTML with its own CSS, isolated from the site styling.
|
return "<!doctype html><html><head>" + injection + "</head><body>" + html + "</body></html>";
|
||||||
return (
|
|
||||||
"<!doctype html><html><head><meta charset=\"utf-8\">" +
|
|
||||||
"<base target=\"_blank\">" +
|
|
||||||
"</head><body style=\"margin:0; padding:8px;\">" +
|
|
||||||
html +
|
|
||||||
"</body></html>"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function findCustomerIdByName(name) {
|
function findCustomerIdByName(name) {
|
||||||
if (!name) return null;
|
if (!name) return null;
|
||||||
for (var i = 0; i < customers.length; i++) {
|
for (var i = 0; i < customers.length; i++) {
|
||||||
|
|||||||
@ -132,13 +132,25 @@
|
|||||||
(function () {
|
(function () {
|
||||||
function wrapMailHtml(html) {
|
function wrapMailHtml(html) {
|
||||||
html = html || "";
|
html = html || "";
|
||||||
return (
|
var trimmed = (typeof html === "string") ? html.trim() : "";
|
||||||
"<!doctype html><html><head><meta charset=\"utf-8\">" +
|
var injection = '<meta charset="utf-8"><meta name="color-scheme" content="light"><meta name="supported-color-schemes" content="light"><meta name="viewport" content="width=device-width, initial-scale=1"><base target="_blank"><style>:root{color-scheme:light;}html{color-scheme:light;}body{margin:0;padding:8px;background:#fff;forced-color-adjust:none;-ms-high-contrast-adjust:none;}</style>';
|
||||||
"<base target=\"_blank\">" +
|
|
||||||
"</head><body style=\"margin:0; padding:8px;\">" +
|
function injectIntoFullDoc(doc) {
|
||||||
html +
|
var d = doc || "";
|
||||||
"</body></html>"
|
if (/<head[^>]*>/i.test(d)) {
|
||||||
);
|
return d.replace(/<head[^>]*>/i, function (m) { return m + injection; });
|
||||||
|
}
|
||||||
|
if (/<html[^>]*>/i.test(d)) {
|
||||||
|
return d.replace(/<html[^>]*>/i, function (m) { return m + "<head>" + injection + "</head>"; });
|
||||||
|
}
|
||||||
|
return "<!doctype html><html><head>" + injection + "</head><body>" + d + "</body></html>";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trimmed.toLowerCase().indexOf("<!doctype") === 0 || trimmed.toLowerCase().indexOf("<html") === 0) {
|
||||||
|
return injectIntoFullDoc(trimmed);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "<!doctype html><html><head>" + injection + "</head><body>" + html + "</body></html>";
|
||||||
}
|
}
|
||||||
|
|
||||||
function attachHandlers() {
|
function attachHandlers() {
|
||||||
|
|||||||
@ -478,15 +478,27 @@
|
|||||||
|
|
||||||
function wrapMailHtml(html) {
|
function wrapMailHtml(html) {
|
||||||
html = html || "";
|
html = html || "";
|
||||||
// Ensure we render the mail HTML with its own CSS, isolated from the site styling.
|
var trimmed = (typeof html === "string") ? html.trim() : "";
|
||||||
return (
|
var injection = '<meta charset="utf-8"><meta name="color-scheme" content="light"><meta name="supported-color-schemes" content="light"><meta name="viewport" content="width=device-width, initial-scale=1"><base target="_blank"><style>:root{color-scheme:light;}html{color-scheme:light;}body{margin:0;padding:8px;background:#fff;forced-color-adjust:none;-ms-high-contrast-adjust:none;}</style>';
|
||||||
"<!doctype html><html><head><meta charset=\"utf-8\">" +
|
|
||||||
"<base target=\"_blank\">" +
|
function injectIntoFullDoc(doc) {
|
||||||
"</head><body style=\"margin:0; padding:8px;\">" +
|
var d = doc || "";
|
||||||
html +
|
if (/<head[^>]*>/i.test(d)) {
|
||||||
"</body></html>"
|
return d.replace(/<head[^>]*>/i, function (m) { return m + injection; });
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
if (/<html[^>]*>/i.test(d)) {
|
||||||
|
return d.replace(/<html[^>]*>/i, function (m) { return m + "<head>" + injection + "</head>"; });
|
||||||
|
}
|
||||||
|
return "<!doctype html><html><head>" + injection + "</head><body>" + d + "</body></html>";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trimmed.toLowerCase().indexOf("<!doctype") === 0 || trimmed.toLowerCase().indexOf("<html") === 0) {
|
||||||
|
return injectIntoFullDoc(trimmed);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "<!doctype html><html><head>" + injection + "</head><body>" + html + "</body></html>";
|
||||||
|
}
|
||||||
|
|
||||||
function renderObjects(objects) {
|
function renderObjects(objects) {
|
||||||
var container = document.getElementById("run_msg_objects_container");
|
var container = document.getElementById("run_msg_objects_container");
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|||||||
@ -364,13 +364,25 @@ function statusClass(status) {
|
|||||||
|
|
||||||
function wrapMailHtml(html) {
|
function wrapMailHtml(html) {
|
||||||
html = html || "";
|
html = html || "";
|
||||||
return (
|
var trimmed = (typeof html === "string") ? html.trim() : "";
|
||||||
"<!doctype html><html><head><meta charset=\"utf-8\">" +
|
var injection = '<meta charset="utf-8"><meta name="color-scheme" content="light"><meta name="supported-color-schemes" content="light"><meta name="viewport" content="width=device-width, initial-scale=1"><base target="_blank"><style>:root{color-scheme:light;}html{color-scheme:light;}body{margin:0;padding:8px;background:#fff;forced-color-adjust:none;-ms-high-contrast-adjust:none;}</style>';
|
||||||
"<base target=\"_blank\">" +
|
|
||||||
"</head><body style=\"margin:0; padding:8px;\">" +
|
function injectIntoFullDoc(doc) {
|
||||||
html +
|
var d = doc || "";
|
||||||
"</body></html>"
|
if (/<head[^>]*>/i.test(d)) {
|
||||||
);
|
return d.replace(/<head[^>]*>/i, function (m) { return m + injection; });
|
||||||
|
}
|
||||||
|
if (/<html[^>]*>/i.test(d)) {
|
||||||
|
return d.replace(/<html[^>]*>/i, function (m) { return m + "<head>" + injection + "</head>"; });
|
||||||
|
}
|
||||||
|
return "<!doctype html><html><head>" + injection + "</head><body>" + d + "</body></html>";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trimmed.toLowerCase().indexOf("<!doctype") === 0 || trimmed.toLowerCase().indexOf("<html") === 0) {
|
||||||
|
return injectIntoFullDoc(trimmed);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "<!doctype html><html><head>" + injection + "</head><body>" + html + "</body></html>";
|
||||||
}
|
}
|
||||||
|
|
||||||
function escapeHtml(s) {
|
function escapeHtml(s) {
|
||||||
|
|||||||
@ -5,6 +5,14 @@
|
|||||||
- Ensured the changelog always fetches the latest version from the source repository at request time.
|
- Ensured the changelog always fetches the latest version from the source repository at request time.
|
||||||
- Removed plain-text rendering to prevent loss of Markdown structure.
|
- Removed plain-text rendering to prevent loss of Markdown structure.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## v20260113-02-edge-mail-lightmode
|
||||||
|
|
||||||
|
- Forced light color-scheme for embedded mail content to prevent Edge auto dark mode rendering.
|
||||||
|
- Added explicit color-scheme and forced-color-adjust rules so original mail CSS is respected.
|
||||||
|
- Ensured consistent mail readability across Edge and Firefox in Inbox, Deleted Inbox, Job Detail, Run Checks, Daily Jobs, and Admin All Mail views.
|
||||||
|
|
||||||
================================================================================================================================================
|
================================================================================================================================================
|
||||||
## v0.1.20
|
## v0.1.20
|
||||||
|
|
||||||
@ -97,13 +105,13 @@ This release delivers a comprehensive set of improvements focused on parser corr
|
|||||||
## v0.1.19
|
## v0.1.19
|
||||||
This release delivers a broad set of improvements focused on reliability, transparency, and operational control across mail processing, administrative auditing, and Run Checks workflows. The changes aim to make message handling more robust, provide better insight for administrators, and give operators clearer and more flexible control when reviewing backup runs.
|
This release delivers a broad set of improvements focused on reliability, transparency, and operational control across mail processing, administrative auditing, and Run Checks workflows. The changes aim to make message handling more robust, provide better insight for administrators, and give operators clearer and more flexible control when reviewing backup runs.
|
||||||
|
|
||||||
Mail Import Reliability and Data Integrity
|
### Mail Import Reliability and Data Integrity
|
||||||
- Updated the mail import flow so messages are only moved to the processed folder after a successful database store and commit.
|
- Updated the mail import flow so messages are only moved to the processed folder after a successful database store and commit.
|
||||||
- Prevented Graph emails from being moved when parsing, storing, or committing data fails, ensuring no messages are lost due to partial failures.
|
- Prevented Graph emails from being moved when parsing, storing, or committing data fails, ensuring no messages are lost due to partial failures.
|
||||||
- Added explicit commit and rollback handling to guarantee database consistency before any mail state changes occur.
|
- Added explicit commit and rollback handling to guarantee database consistency before any mail state changes occur.
|
||||||
- Improved logging around import, commit, and rollback failures to make skipped or retried mails easier to trace and troubleshoot.
|
- Improved logging around import, commit, and rollback failures to make skipped or retried mails easier to trace and troubleshoot.
|
||||||
|
|
||||||
Administrative Mail Auditing and Visibility
|
### Administrative Mail Auditing and Visibility
|
||||||
- Introduced an admin-only “All Mail” audit page that provides a complete overview of all received mail messages.
|
- Introduced an admin-only “All Mail” audit page that provides a complete overview of all received mail messages.
|
||||||
- Implemented pagination with a fixed page size of 50 items to ensure consistent performance and predictable navigation.
|
- Implemented pagination with a fixed page size of 50 items to ensure consistent performance and predictable navigation.
|
||||||
- Added always-visible search filters that can be combined using AND logic, including From, Subject, Backup, Type, Job name, and a received date/time range.
|
- Added always-visible search filters that can be combined using AND logic, including From, Subject, Backup, Type, Job name, and a received date/time range.
|
||||||
@ -112,14 +120,14 @@ Administrative Mail Auditing and Visibility
|
|||||||
- Added a dedicated navigation entry so administrators can easily access the All Mail audit view.
|
- Added a dedicated navigation entry so administrators can easily access the All Mail audit view.
|
||||||
- Fixed modal opening behavior in the All Mail page to fully align click handling and popups with the Inbox implementation.
|
- Fixed modal opening behavior in the All Mail page to fully align click handling and popups with the Inbox implementation.
|
||||||
|
|
||||||
Inbox and Mail Body Rendering Improvements
|
### Inbox and Mail Body Rendering Improvements
|
||||||
- Treated whitespace-only email bodies as empty during import so HTML report attachments can be extracted and displayed correctly.
|
- Treated whitespace-only email bodies as empty during import so HTML report attachments can be extracted and displayed correctly.
|
||||||
- Added legacy fallback logic in the Inbox message detail API to extract the first HTML attachment from stored EML files when bodies are empty or invalid.
|
- Added legacy fallback logic in the Inbox message detail API to extract the first HTML attachment from stored EML files when bodies are empty or invalid.
|
||||||
- Improved iframe rendering in the Inbox so full HTML documents (commonly used for report attachments) are rendered directly instead of being wrapped.
|
- Improved iframe rendering in the Inbox so full HTML documents (commonly used for report attachments) are rendered directly instead of being wrapped.
|
||||||
- Added detection for “effectively empty” HTML bodies, such as empty Graph-generated HTML skeletons.
|
- Added detection for “effectively empty” HTML bodies, such as empty Graph-generated HTML skeletons.
|
||||||
- Ensured that both newly imported and already-stored messages can dynamically fall back to EML attachment extraction without requiring a reset.
|
- Ensured that both newly imported and already-stored messages can dynamically fall back to EML attachment extraction without requiring a reset.
|
||||||
|
|
||||||
Run Checks Usability and Control
|
### Run Checks Usability and Control
|
||||||
- Added a copy-to-clipboard icon next to ticket numbers in the Run Checks popup to quickly copy only the ticket code.
|
- Added a copy-to-clipboard icon next to ticket numbers in the Run Checks popup to quickly copy only the ticket code.
|
||||||
- Prevented accidental selection of appended status text when copying ticket numbers.
|
- Prevented accidental selection of appended status text when copying ticket numbers.
|
||||||
- Introduced a manual “Success (override)” action that allows Operators and Admins to mark a run as successful even if it originally failed or produced warnings.
|
- Introduced a manual “Success (override)” action that allows Operators and Admins to mark a run as successful even if it originally failed or produced warnings.
|
||||||
@ -130,13 +138,13 @@ Run Checks Usability and Control
|
|||||||
- Added support for extracting HTML content from stored EML files when both HTML and text bodies are unavailable.
|
- Added support for extracting HTML content from stored EML files when both HTML and text bodies are unavailable.
|
||||||
- Ensured plain-text emails are safely rendered using preformatted HTML to preserve readability.
|
- Ensured plain-text emails are safely rendered using preformatted HTML to preserve readability.
|
||||||
|
|
||||||
Customer, Ticket, and Scope Cleanup
|
### Customer, Ticket, and Scope Cleanup
|
||||||
- Updated customer deletion logic to allow removal of customers even when tickets or remarks are linked.
|
- Updated customer deletion logic to allow removal of customers even when tickets or remarks are linked.
|
||||||
- Added explicit cleanup of related TicketScope and RemarkScope records prior to customer deletion.
|
- Added explicit cleanup of related TicketScope and RemarkScope records prior to customer deletion.
|
||||||
- Ensured jobs linked to a deleted customer are safely unassigned to prevent foreign key constraint errors.
|
- Ensured jobs linked to a deleted customer are safely unassigned to prevent foreign key constraint errors.
|
||||||
- Eliminated deletion failures caused by lingering ticket or remark relationships.
|
- Eliminated deletion failures caused by lingering ticket or remark relationships.
|
||||||
|
|
||||||
Parser Enhancements and Informational Messages
|
### Parser Enhancements and Informational Messages
|
||||||
- Added parser support for 3CX SSL Certificate notification emails.
|
- Added parser support for 3CX SSL Certificate notification emails.
|
||||||
- Classified these messages as Backup: 3CX with Type: SSL Certificate.
|
- Classified these messages as Backup: 3CX with Type: SSL Certificate.
|
||||||
- Parsed and displayed certificate information in the Run Checks popup.
|
- Parsed and displayed certificate information in the Run Checks popup.
|
||||||
@ -145,7 +153,7 @@ Parser Enhancements and Informational Messages
|
|||||||
- Classified Synology Updates messages as informational and set their overall status to Warning.
|
- Classified Synology Updates messages as informational and set their overall status to Warning.
|
||||||
- Excluded Synology Updates informational messages from scheduling logic and reporting output.
|
- Excluded Synology Updates informational messages from scheduling logic and reporting output.
|
||||||
|
|
||||||
UI Layout and Status Accuracy Improvements
|
### UI Layout and Status Accuracy Improvements
|
||||||
- Moved the Details section above the email body in both Inbox and Job Details popups to improve readability.
|
- Moved the Details section above the email body in both Inbox and Job Details popups to improve readability.
|
||||||
- Avoided long detail texts being constrained to narrow side columns.
|
- Avoided long detail texts being constrained to narrow side columns.
|
||||||
- Adjusted missed run detection to include a ±1 hour grace window around scheduled run times.
|
- Adjusted missed run detection to include a ±1 hour grace window around scheduled run times.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user