0.2.29
RustBox CI / rustbox (push) Canceled after 0s

This commit is contained in:
Mateusz Gruszczyński committed 2026-11-07 10:27:26 +01:00
1 parent 065fc87306
commit 1b12899ff6
8 files changed
+38 -13

No files matched your search

+4
View File
@@ -2,6 +2,10 @@
What changed in each RustBox release, written for the people who use and run it. Technical details are in the [documentation](docs/). What changed in each RustBox release, written for the people who use and run it. Technical details are in the [documentation](docs/).
## 0.2.29
- An open message thread now updates automatically when a new message for that thread arrives via realtime events; reopening the thread is no longer required.
## 0.2.28 ## 0.2.28
- Replying to a message you sent no longer addresses the reply back to yourself; RustBox chooses the other thread participant(s), including when aliases/identities are used. - Replying to a message you sent no longer addresses the reply back to yourself; RustBox chooses the other thread participant(s), including when aliases/identities are used.
Generated
+1 -1
View File
@@ -3506,7 +3506,7 @@ dependencies = [
[[package]] [[package]]
name = "rustbox" name = "rustbox"
version = "0.2.28" version = "0.2.29"
dependencies = [ dependencies = [
"aes-gcm", "aes-gcm",
"async-imap", "async-imap",
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "rustbox" name = "rustbox"
version = "0.2.28" version = "0.2.29"
edition = "2024" edition = "2024"
rust-version = "1.99.1" rust-version = "1.99.1"
license = "AGPL-3.0-only" license = "AGPL-3.0-only"
+1 -1
View File
@@ -1,4 +1,4 @@
# RustBox 0.2.28 # RustBox 0.2.29
**Fast, self-hosted webmail written in Rust.** RustBox connects to any IMAP/SMTP server and ships as one executable with the whole interface built in, so there is no Node.js, PHP or separate frontend to deploy. **Fast, self-hosted webmail written in Rust.** RustBox connects to any IMAP/SMTP server and ships as one executable with the whole interface built in, so there is no Node.js, PHP or separate frontend to deploy.
+5 -4
View File
@@ -1,6 +1,7 @@
RustBox 0.2.28 release manifest RustBox 0.2.29 release manifest
0.2.28 release changes: 0.2.29 release changes:
- open message thread refreshes automatically after realtime NewMessages events, without requiring the user to reopen it
- replies to own sent messages target the other participant(s), with account aliases/identities treated as own addresses - replies to own sent messages target the other participant(s), with account aliases/identities treated as own addresses
- mailbox toolbar toggles between grouped threads and individual messages using the persisted mailbox `thread_mode` preference; thread rows expand/collapse and use Message-ID/In-Reply-To/References metadata - mailbox toolbar toggles between grouped threads and individual messages using the persisted mailbox `thread_mode` preference; thread rows expand/collapse and use Message-ID/In-Reply-To/References metadata
- legacy Polish text repair covers common UTF-8/Windows-1252 and ISO-8859-2/Western-Latin mojibake in headers, bodies and cached summaries/details; exact ISO-8859-2 folded-subject coverage added - legacy Polish text repair covers common UTF-8/Windows-1252 and ISO-8859-2/Western-Latin mojibake in headers, bodies and cached summaries/details; exact ISO-8859-2 folded-subject coverage added
@@ -131,14 +132,14 @@ Docker examples:
Operations/docs: Operations/docs:
- standalone `scripts/migrate_roundcube.py` imports Roundcube contacts/identities using RustBox config.toml and supports SQLite/MySQL/PostgreSQL targets - standalone `scripts/migrate_roundcube.py` imports Roundcube contacts/identities using RustBox config.toml and supports SQLite/MySQL/PostgreSQL targets
- README.md documents 0.2.28 configuration - README.md documents 0.2.29 configuration
- docker/README.md documents Compose variants - docker/README.md documents Compose variants
- docs/STORAGE_SEARCH_OPERATIONS.md documents failure modes, shared-storage requirements and migration behavior - 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 - TODO.md leaves live SILO/MinIO/AWS/Ceph and real multi-node acceptance validation explicitly pending
Build/release metadata: Build/release metadata:
- `scripts/package-release.sh` runs the full Rust release gate before creating ZIP/SHA256 artifacts - `scripts/package-release.sh` runs the full Rust release gate before creating ZIP/SHA256 artifacts
- Cargo.toml version = 0.2.28 - Cargo.toml version = 0.2.29
- rust-toolchain.toml pins Rust 1.99.1 - rust-toolchain.toml pins Rust 1.99.1
- Cargo.lock is retained for reproducible application builds; the release gate generates it only when missing - 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 - CI and scripts/build-release.sh use the retained Cargo.lock (generating it only if missing), then run locked tests/Clippy/release build
+5 -4
View File
@@ -1,6 +1,7 @@
RustBox 0.2.28 - final source validation RustBox 0.2.29 - final source validation
0.2.28 scope: 0.2.29 scope:
- realtime refresh of the currently open message thread when NewMessages arrives
- correct reply recipients for own sent messages in threads, Roundcube-style mailbox thread/flat list toggle (compact icon-button matching Select messages, with an icon reflecting the active mode), and stronger Polish legacy-encoding/mojibake repair, plus the 0.2.27 mail-list and appearance baseline - correct reply recipients for own sent messages in threads, Roundcube-style mailbox thread/flat list toggle (compact icon-button matching Select messages, with an icon reflecting the active mode), and stronger Polish legacy-encoding/mojibake repair, plus the 0.2.27 mail-list and appearance baseline
0.2.25 scope: 0.2.25 scope:
@@ -67,7 +68,7 @@ RustBox 0.2.28 - final source validation
- Composing shows only compact attachment/message size-limit values on one line - 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 - 0.2.9 realtime notification gating, browser shortcut preservation and 300-message defaults remain intact
- V047-V052 are consolidated into compatibility baseline V052; V053 adds `skin_depth` and `skin_gradients`; V054 adds the theme schedule and account colour; V055 is next - V047-V052 are consolidated into compatibility baseline V052; V053 adds `skin_depth` and `skin_gradients`; V054 adds the theme schedule and account colour; V055 is next
- version metadata identifies 0.2.28 - version metadata identifies 0.2.29
Completed in this environment: Completed in this environment:
- offline release validator: scripts/validate-release-static.py (458/458 checks passed) - offline release validator: scripts/validate-release-static.py (458/458 checks passed)
@@ -78,7 +79,7 @@ Completed in this environment:
- all JSON files parse successfully - all JSON files parse successfully
- Python helper scripts compile successfully - Python helper scripts compile successfully
- shell scripts pass `bash -n` - shell scripts pass `bash -n`
- release metadata consistently identifies 0.2.28 - release metadata consistently identifies 0.2.29
- V052 baseline consolidation plus the V053 skin-depth migration are validated offline - V052 baseline consolidation plus the V053 skin-depth migration are validated offline
- 0.2.25 filter UI (apply now, run now, always move from sender), context submenus and preset editing exercised in Playwright against a mocked API; the 0.2.24 styles rendered at standard and immersive depth with gradients on and off; earlier: all 37 interface styles rendered in light and dark at the immersive depth against a mocked API (Playwright), with no page errors - 0.2.25 filter UI (apply now, run now, always move from sender), context submenus and preset editing exercised in Playwright against a mocked API; the 0.2.24 styles rendered at standard and immersive depth with gradients on and off; earlier: all 37 interface styles rendered in light and dark at the immersive depth against a mocked API (Playwright), with no page errors
+6 -2
View File
@@ -1,7 +1,11 @@
# RustBox 0.2.28 - implementation status # RustBox 0.2.29 - implementation status
- Draft saves are realtime-silent: Drafts folder/list updates continue, but saving a draft does not surface as a new-mail notification. - 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.28` 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.29` 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.29 realtime open-thread refresh
- When realtime reports `NewMessages`, the currently open message detail is re-fetched and its thread is re-rendered if the user is still viewing the same message.
## 0.2.28 thread replies and legacy Polish mail decoding ## 0.2.28 thread replies and legacy Polish mail decoding
+15
View File
@@ -662,6 +662,19 @@ async function resyncRealtimeState() {
return state.realtimeSyncPromise; return state.realtimeSyncPromise;
} }
async function refreshOpenThread() {
const current = state.currentDetail;
if (!current) return;
const folder = current.folder;
const uid = current.uid;
try {
const fresh = await request(`/messages/${encodeURIComponent(folder)}/${uid}`, { method: "GET" });
if (!state.currentDetail || state.currentDetail.folder !== folder || Number(state.currentDetail.uid) !== Number(uid)) return;
state.currentDetail.thread = fresh.thread || [];
renderThread(state.currentDetail);
} catch (_) { }
}
function scheduleRealtimeRefresh(event, accountId) { function scheduleRealtimeRefresh(event, accountId) {
if (accountId !== state.accountId) return; if (accountId !== state.accountId) return;
state.realtimeRefreshEvents.push(event); state.realtimeRefreshEvents.push(event);
@@ -669,6 +682,7 @@ function scheduleRealtimeRefresh(event, accountId) {
state.realtimeRefreshTimer = setTimeout(async () => { state.realtimeRefreshTimer = setTimeout(async () => {
const events = state.realtimeRefreshEvents.splice(0); const events = state.realtimeRefreshEvents.splice(0);
const folderTreeChanged = events.some((item) => item.type === "FolderUpdated"); const folderTreeChanged = events.some((item) => item.type === "FolderUpdated");
const hasNewMessages = events.some((item) => item.type === "NewMessages");
const newInCurrent = events.some((item) => item.type === "NewMessages" && item.data?.folder === state.folder); const newInCurrent = events.some((item) => item.type === "NewMessages" && item.data?.folder === state.folder);
const structuralFlagsInCurrent = events.some((item) => item.type === "FlagsChanged" && item.data?.folder === state.folder && !(item.data?.changes || []).length); const structuralFlagsInCurrent = events.some((item) => item.type === "FlagsChanged" && item.data?.folder === state.folder && !(item.data?.changes || []).length);
const tasks = []; const tasks = [];
@@ -678,6 +692,7 @@ function scheduleRealtimeRefresh(event, accountId) {
else tasks.push(loadMessages(true, { background: true })); else tasks.push(loadMessages(true, { background: true }));
} }
if (tasks.length) await Promise.all(tasks); if (tasks.length) await Promise.all(tasks);
if (hasNewMessages && state.currentDetail) await refreshOpenThread();
}, 80); }, 80);
} }