1 parent
1309358b68
commit
9003a50eb4
11 files changed
+83
-17
No files matched your search
@@ -1,5 +1,11 @@
|
||||
# RustBox changelog
|
||||
|
||||
### 0.2.19
|
||||
|
||||
- Improved vertical space management in the HTML message reader: the sandboxed message iframe now expands to the actual space remaining below the reader toolbar, message header and auxiliary bars instead of stopping at a fixed `68vh`.
|
||||
- Recalculate the HTML message viewport when the reader, header, attachments, security bars, window size or fullscreen state changes, avoiding an unnecessary short inner scrollbar while preserving the existing iframe sandbox.
|
||||
- Bumped the application/source release to 0.2.19.
|
||||
|
||||
### 0.2.18
|
||||
|
||||
- Fixed new-message sender selection so the composer prefers the configured default identity, then the identity matching the active account address, then the first available identity; the visible From field now shows the active account address instead of an ambiguous `Account default` label when no identity is selected.
|
||||
|
||||
Generated
+1
-1
@@ -3506,7 +3506,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustbox"
|
||||
version = "0.2.18"
|
||||
version = "0.2.19"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"async-imap",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rustbox"
|
||||
version = "0.2.18"
|
||||
version = "0.2.19"
|
||||
edition = "2024"
|
||||
rust-version = "1.99.1"
|
||||
default-run = "rustbox"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# RustBox attribution / notice
|
||||
|
||||
RustBox 0.2.18 is derived from the Oxi webmail project:
|
||||
RustBox 0.2.19 is derived from the Oxi webmail project:
|
||||
|
||||
- Upstream: `c0h1b4/oxi`
|
||||
- Base snapshot: `7f1507c486b78cf33e54beb701dd460d3bd2bd5d`
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# RustBox 0.2.18
|
||||
# RustBox 0.2.19
|
||||
|
||||
RustBox is a webmail derived from `c0h1b4/oxi`. The consumed Oxi revision is recorded in `UPSTREAM_BASE`.
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
RustBox 0.2.18 release manifest
|
||||
RustBox 0.2.19 release manifest
|
||||
|
||||
0.2.18 release changes and retained feature set:
|
||||
0.2.19 release changes and retained feature set:
|
||||
- expands sandboxed HTML message previews to the real remaining reader height and keeps that height synchronized across layout/fullscreen changes
|
||||
- adds equal-height text/HTML signature fields and a dedicated raw-HTML + visual signature editor with image insertion
|
||||
- keeps synchronization activity visible during page/progressive/all mailbox loads and individual message retrieval
|
||||
- adds Shift-click contiguous message selection and direct first/last pagination controls
|
||||
@@ -70,14 +71,14 @@ Docker examples:
|
||||
|
||||
Operations/docs:
|
||||
- standalone `scripts/migrate_roundcube.py` imports Roundcube contacts/identities using RustBox config.toml and supports SQLite/MySQL/PostgreSQL targets
|
||||
- README.md documents 0.2.18 configuration
|
||||
- README.md documents 0.2.19 configuration
|
||||
- docker/README.md documents Compose variants
|
||||
- docs/STORAGE_SEARCH_OPERATIONS.md documents failure modes, shared-storage requirements and migration behavior
|
||||
- TODO.md leaves live SILO/MinIO/AWS/Ceph and real multi-node acceptance validation explicitly pending
|
||||
|
||||
Build/release metadata:
|
||||
- `scripts/package-release.sh` runs the full Rust release gate before creating ZIP/SHA256 artifacts
|
||||
- Cargo.toml version = 0.2.18
|
||||
- Cargo.toml version = 0.2.19
|
||||
- rust-toolchain.toml pins Rust 1.99.1
|
||||
- Cargo.lock is retained for reproducible application builds; the release gate generates it only when missing
|
||||
- CI and scripts/build-release.sh use the retained Cargo.lock (generating it only if missing), then run locked tests/Clippy/release build
|
||||
@@ -1,6 +1,7 @@
|
||||
RustBox 0.2.18 - final source validation
|
||||
RustBox 0.2.19 - final source validation
|
||||
|
||||
0.2.18 scope:
|
||||
0.2.19 scope:
|
||||
- HTML message reader iframe height follows the actual remaining reader viewport rather than a fixed 68vh, with resize/fullscreen recalculation
|
||||
- multi-account sessions expose a top-bar quick switcher, per-browser combined notification selection, per-account notification preferences and the administrator `multi_account_enabled` feature gate
|
||||
- plain-text and HTML signature controls have aligned heights; raw HTML can be pasted into a modal, previewed/edited visually and extended with inline images
|
||||
- synchronization spinner covers mailbox pagination, progressive/full-folder loading and message/draft body retrieval
|
||||
@@ -32,15 +33,15 @@ RustBox 0.2.18 - final source validation
|
||||
- Composing shows only compact attachment/message size-limit values on one line
|
||||
- 0.2.9 realtime notification gating, browser shortcut preservation and 300-message defaults remain intact
|
||||
- V047-V050 are consolidated into compatibility baseline V050; V051 migrates existing tenants with adaptive HTML-mail colors and mailbox loading mode; V052 is next
|
||||
- version metadata remains at 0.2.18
|
||||
- version metadata identifies 0.2.19
|
||||
|
||||
Completed in this environment:
|
||||
- offline release validator: scripts/validate-release-static.py (413/413 checks passed)
|
||||
- offline release validator: scripts/validate-release-static.py (420/420 checks passed)
|
||||
- browser JavaScript assembled in manifest order passes `node --check`
|
||||
- all JSON files parse successfully
|
||||
- Python helper scripts compile successfully
|
||||
- shell scripts pass `bash -n`
|
||||
- release metadata consistently identifies 0.2.18
|
||||
- release metadata consistently identifies 0.2.19
|
||||
- V050 baseline consolidation plus the V051 adaptive-colors/mailbox-loading migration are validated offline
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
# RustBox 0.2.18 - implementation status
|
||||
# RustBox 0.2.19 - implementation status
|
||||
|
||||
- Draft saves are realtime-silent: Drafts folder/list updates continue, but saving a draft does not surface as a new-mail notification.
|
||||
This file tracks the `0.2.18` source snapshot. Storage/search scope and outstanding acceptance work are tracked in `TODO.md`. A feature is only listed as implemented when working code exists in this source tree; partial items are called out explicitly.
|
||||
This file tracks the `0.2.19` source snapshot. Storage/search scope and outstanding acceptance work are tracked in `TODO.md`. A feature is only listed as implemented when working code exists in this source tree; partial items are called out explicitly.
|
||||
|
||||
## 0.2.18 browser mail UX
|
||||
## 0.2.19 browser mail UX
|
||||
|
||||
- HTML message previews use the full remaining vertical reader area and recompute their iframe height as reader chrome/layout changes.
|
||||
- Signature management uses equal-height text and HTML fields and includes a raw-HTML modal with a sanitized visual editor and inline image import.
|
||||
- Mail loading activity is represented by the app-bar spinner for pagination, progressive/full-folder retrieval and individual message/draft loading.
|
||||
- Shift-click selects a contiguous range in the visible message list, and pagination includes direct first/last page navigation.
|
||||
|
||||
@@ -152,6 +152,7 @@ require('suppressRealtimeNotificationsForFolder(notificationDestination)' in mai
|
||||
require('realtimeNotificationSuppressedMessages: new Map()' in bootstrap_js and 'suppressRealtimeNotificationForMessage' in realtime_js and 'consumeRealtimeMessageNotificationSuppression' in realtime_js and 'suppressIntentionalMoveNotification' in mail_actions_js, "intentional message moves suppress the matching realtime new-mail event by destination UID")
|
||||
require('finishAuthenticatedStartup({ showLoginToast = false } = {})' in auth_js and 'finishAuthenticatedStartup({ showLoginToast: true })' in auth_js and bindings_js.count('finishAuthenticatedStartup();') >= 1, "login success toast is limited to real login, not refresh/session restoration")
|
||||
require('<meta charset="utf-8">${csp}' in reader_js, "message preview srcdoc explicitly declares UTF-8")
|
||||
require('function resizeReaderMessageFrame()' in reader_js and 'new ResizeObserver(scheduleReaderMessageFrameResize)' in reader_js and '--reader-message-frame-height' in mail_css and 'min-height: 68vh' not in mail_css, "HTML message preview uses the full remaining reader height instead of fixed 68vh")
|
||||
require('function sanitizeMessagePreviewHtml(html)' in bootstrap_js and 'if (!node.hasAttribute("target")) node.setAttribute("target", "_blank");' in bootstrap_js and '!["_self", "_parent", "_top"].includes(target)' in bootstrap_js and 'rel.add("noopener");' in bootstrap_js and 'rel.add("noreferrer");' in bootstrap_js and 'sanitizeMessagePreviewHtml(detail.html)' in reader_js, "message preview links default to safe new-window navigation without overriding explicit targets")
|
||||
require('sourceDoc.head.querySelectorAll("style")' in bootstrap_js and 'messagePreviewBodyPresentation' in reader_js and 'iframe.style.background = previewTheme.surface;' in reader_js and 'background: var(--reader-bg);' in mail_css, "adaptive HTML-mail preview preserves head CSS/body presentation and never exposes a hard-coded white iframe canvas")
|
||||
require('attachmentContentUrl(folder, uid, attachment)' in reader_js and 'frame.src = attachmentContentUrl(folder, uid, attachment);' in reader_js and 'URL.createObjectURL(blob)' in reader_js, "PDF preview uses authenticated inline URL while other attachment previews retain blob handling")
|
||||
|
||||
@@ -593,7 +593,8 @@
|
||||
.message-body iframe {
|
||||
display: block;
|
||||
width: 100%;
|
||||
min-height: 68vh;
|
||||
height: var(--reader-message-frame-height, 260px);
|
||||
min-height: 260px;
|
||||
border: 0;
|
||||
background: var(--reader-bg);
|
||||
}
|
||||
|
||||
@@ -503,6 +503,7 @@ function setReaderFullscreen(enabled, options = {}) {
|
||||
}
|
||||
restoreReaderScroll();
|
||||
}
|
||||
scheduleReaderMessageFrameResize();
|
||||
}
|
||||
|
||||
function enterReaderFullscreen() {
|
||||
@@ -1164,10 +1165,62 @@ function adaptMessagePreviewColors(html, detail, body) {
|
||||
return { html: doc.body.innerHTML, targetTheme, surface: adaptiveEmailRgbCss(messageSurface), text: adaptiveEmailRgbCss(messageText) };
|
||||
}
|
||||
|
||||
let readerMessageFrameObserver = null;
|
||||
let readerMessageFrameResizeRaf = 0;
|
||||
let readerMessageFrameWindowResizeBound = false;
|
||||
|
||||
function resizeReaderMessageFrame() {
|
||||
readerMessageFrameResizeRaf = 0;
|
||||
const reader = $("#reader-content");
|
||||
const body = $("#message-body");
|
||||
const iframe = body?.querySelector(":scope > iframe");
|
||||
if (!reader || !body || !iframe || reader.classList.contains("hidden")) return;
|
||||
|
||||
let occupiedHeight = 0;
|
||||
for (const child of reader.children) {
|
||||
if (child === body) break;
|
||||
const style = getComputedStyle(child);
|
||||
if (style.display === "none" || style.position === "absolute" || style.position === "fixed") continue;
|
||||
const rect = child.getBoundingClientRect();
|
||||
occupiedHeight += rect.height;
|
||||
occupiedHeight += Number.parseFloat(style.marginTop) || 0;
|
||||
occupiedHeight += Number.parseFloat(style.marginBottom) || 0;
|
||||
}
|
||||
|
||||
const availableHeight = Math.max(260, Math.floor(reader.clientHeight - occupiedHeight));
|
||||
body.style.setProperty("--reader-message-frame-height", `${availableHeight}px`);
|
||||
}
|
||||
|
||||
function scheduleReaderMessageFrameResize() {
|
||||
if (readerMessageFrameResizeRaf) cancelAnimationFrame(readerMessageFrameResizeRaf);
|
||||
readerMessageFrameResizeRaf = requestAnimationFrame(resizeReaderMessageFrame);
|
||||
}
|
||||
|
||||
function observeReaderMessageFrameLayout() {
|
||||
const reader = $("#reader-content");
|
||||
const body = $("#message-body");
|
||||
if (!reader || !body) return;
|
||||
|
||||
if (typeof ResizeObserver === "function") {
|
||||
if (!readerMessageFrameObserver) readerMessageFrameObserver = new ResizeObserver(scheduleReaderMessageFrameResize);
|
||||
readerMessageFrameObserver.disconnect();
|
||||
readerMessageFrameObserver.observe(reader);
|
||||
for (const child of reader.children) {
|
||||
if (child !== body) readerMessageFrameObserver.observe(child);
|
||||
}
|
||||
}
|
||||
|
||||
if (!readerMessageFrameWindowResizeBound) {
|
||||
window.addEventListener("resize", scheduleReaderMessageFrameResize, { passive: true });
|
||||
readerMessageFrameWindowResizeBound = true;
|
||||
}
|
||||
}
|
||||
|
||||
function renderMessageBody(detail, forceRemote = false) {
|
||||
const body = $("#message-body");
|
||||
const remoteBar = $("#remote-image-bar");
|
||||
body.replaceChildren();
|
||||
body.style.removeProperty("--reader-message-frame-height");
|
||||
remoteBar.classList.add("hidden");
|
||||
const preferredBody = state.mailPrefs.preferred_body || "auto";
|
||||
if (preferredBody === "text" || !detail?.html) {
|
||||
@@ -1208,6 +1261,8 @@ function renderMessageBody(detail, forceRemote = false) {
|
||||
].filter(Boolean).join(" ");
|
||||
iframe.srcdoc = `<!doctype html><html><head><meta charset="utf-8">${csp}<meta name="color-scheme" content="${previewTheme.targetTheme}"><style>${previewStyle}</style></head><body${bodyAttributes ? ` ${bodyAttributes}` : ""}>${safeHtml}</body></html>`;
|
||||
body.append(iframe);
|
||||
observeReaderMessageFrameLayout();
|
||||
resizeReaderMessageFrame();
|
||||
}
|
||||
|
||||
async function downloadAttachment(folder, uid, attachment) {
|
||||
|
||||
Reference in new issue
Block a user