1 parent
065fc87306
commit
1b12899ff6
8 files changed
+38
-13
No files matched your search
@@ -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
@@ -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
@@ -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,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.
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user