From beae94e9320f1c5f84ae7a22c57252a39285945d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Gruszczy=C5=84ski?= Date: Wed, 4 Nov 2026 20:44:31 +0100 Subject: [PATCH] v0.2.23 --- CHANGELOG.md | 11 + Cargo.lock | 2 +- Cargo.toml | 2 +- NOTICE.md | 2 +- README.md | 6 +- RELEASE-MANIFEST.txt | 24 +- RELEASE-VALIDATION.txt | 20 +- config.example.toml | 9 +- docs/IMPLEMENTATION_STATUS.md | 15 +- migrations/README.md | 29 +- ..._email_colors_and_message_loading_mode.sql | 5 - migrations/mysql/V052__snooze.sql | 9 - .../mysql/V053__skin_depth_and_gradients.sql | 3 + migrations/mysql/schema.sql | 10 +- ..._email_colors_and_message_loading_mode.sql | 5 - migrations/pgsql/V052__snooze.sql | 10 - .../pgsql/V053__skin_depth_and_gradients.sql | 3 + migrations/pgsql/schema.sql | 8 +- ..._email_colors_and_message_loading_mode.sql | 5 - migrations/sqlite/V052__snooze.sql | 10 - .../sqlite/V053__skin_depth_and_gradients.sql | 5 + migrations/sqlite/schema.sql | 6 +- packaging/rustbox.toml | 8 +- scripts/migrate_roundcube.py | 2 +- scripts/validate-release-static.py | 72 ++ src/config.rs | 34 +- src/db/display_preferences.rs | 164 ++-- src/db/pool.rs | 91 +- src/queries/mysql/queries.rs | 2 +- src/queries/pgsql/queries.rs | 2 +- src/queries/sqlite/queries.rs | 2 +- src/web/css/55-roundcube-skins.css | 47 +- src/web/css/56-interface-styles.css | 759 +++++++++++++++ src/web/css/57-skin-tokens.css | 896 ++++++++++++++++++ src/web/css/58-skin-immersive.css | 307 ++++++ src/web/css/manifest.txt | 2 + src/web/i18n/en.json | 11 +- src/web/i18n/pl.json | 20 +- src/web/index.html | 24 + src/web/js/00-bootstrap.js | 2 +- src/web/js/20-preferences-auth.js | 146 ++- src/web/js/95-bindings-boot.js | 2 + 42 files changed, 2518 insertions(+), 274 deletions(-) delete mode 100644 migrations/mysql/V051__adaptive_email_colors_and_message_loading_mode.sql delete mode 100644 migrations/mysql/V052__snooze.sql create mode 100644 migrations/mysql/V053__skin_depth_and_gradients.sql delete mode 100644 migrations/pgsql/V051__adaptive_email_colors_and_message_loading_mode.sql delete mode 100644 migrations/pgsql/V052__snooze.sql create mode 100644 migrations/pgsql/V053__skin_depth_and_gradients.sql delete mode 100644 migrations/sqlite/V051__adaptive_email_colors_and_message_loading_mode.sql delete mode 100644 migrations/sqlite/V052__snooze.sql create mode 100644 migrations/sqlite/V053__skin_depth_and_gradients.sql mode change 100755 => 100644 scripts/migrate_roundcube.py mode change 100755 => 100644 scripts/validate-release-static.py create mode 100644 src/web/css/57-skin-tokens.css create mode 100644 src/web/css/58-skin-immersive.css diff --git a/CHANGELOG.md b/CHANGELOG.md index fc74b1d..44e1d32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # RustBox changelog +### 0.2.23 + +- Added **Style depth** to Appearance (`skin_depth`, migration `V053`). *Colors only* applies just a predefined style's palette and keeps every layout control editable; *Standard* (default) is the previous behavior — palette plus the style's fixed layout profile; *Immersive* additionally reshapes the interface with the style's own typography, control/button/avatar shapes, floating or flush panes, app bar and search field, sidebar colors, selection markers, card-style rows, primary/compose buttons and backdrop (gradients, glass blur, bevels). Floating-pane geometry applies only to the desktop three-pane layout; phones and tablets keep the drawer layout. +- Added a separate **Style gradients** switch to Appearance (`skin_gradients`, part of migration `V053`, default off). All gradients used by styles — immersive backdrops, app bars, primary buttons, the Synthwave logo and the Roundcube Classic bevelled toolbars/buttons — are applied only when it is on; otherwise each style uses flat colors. Note: Roundcube Classic is therefore flat by default until the switch is enabled. +- Introduced a common interface-style standard. Every predefined style now ships light and dark palettes, a fixed layout profile and a structural token block (`57-skin-tokens.css`, consumed by `58-skin-immersive.css`). All 23 existing styles were adapted to it — for example GitHub gets its dark header and green primary button, Slack its aubergine sidebar, Gmail its pill navigation and light-blue compose button, Outlook its accent app bar and selection bar, Apple Mail its filled selection. +- Added 14 predefined styles: Dracula, Catppuccin, Solarized, Gruvbox, Tokyo Night, Rosé Pine, Everforest, Synthwave, Paper, Terminal, Aqua Glass, Linear inspired, Material You inspired and Retro 95. +- The interface-style catalog is defined once (`display_preferences::INTERFACE_SKINS`) and shared by the user preference and `default_interface_skin` validation. The release validator now checks that every style is present in the catalog, the settings selector, the layout profiles, both palettes and the token table. +- Consolidated migrations V051 and V052 into the fresh schemas; the compatibility baseline is now V052. Databases below V052 must be opened once with 0.2.22 before upgrading. +- Fixed the fresh MySQL schema: `mail_preferences.message_loading_mode` used a literal `DEFAULT` on a `TEXT` column, which MySQL rejects; it now uses an expression default. +- Bumped the application/source release to 0.2.23. + ### 0.2.22 - Added message snooze. A new `snoozed_messages` table (migration `V052`) records a wake time for a message; snoozing it (via the new "Snooze…" context-menu entry or the `b` shortcut while a message is open) hides it client-side from its folder's current view until that time, using `GET /folders/{name}/snoozed-uids` to know which UIDs are currently asleep. `POST /messages/{folder}/{uid}/snooze` and `DELETE /messages/{folder}/{uid}/snooze` set/clear a snooze; `GET /messages/snoozed` lists everything currently sleeping, shown in the new "View snoozed messages…" dialog (`Shift+B`). This is purely a local cache: it has no IMAP side effects and does not change server-side folder pagination/count queries. diff --git a/Cargo.lock b/Cargo.lock index 521b557..0f72a0f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3506,7 +3506,7 @@ dependencies = [ [[package]] name = "rustbox" -version = "0.2.22" +version = "0.2.23" dependencies = [ "aes-gcm", "async-imap", diff --git a/Cargo.toml b/Cargo.toml index 80f0fdb..55785d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustbox" -version = "0.2.22" +version = "0.2.23" edition = "2024" rust-version = "1.99.1" default-run = "rustbox" diff --git a/NOTICE.md b/NOTICE.md index 3f209bf..9d10622 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -1,6 +1,6 @@ # RustBox attribution / notice -RustBox 0.2.22 is derived from the Oxi webmail project: +RustBox 0.2.23 is derived from the Oxi webmail project: - Upstream: `c0h1b4/oxi` - Base snapshot: `7f1507c486b78cf33e54beb701dd460d3bd2bd5d` diff --git a/README.md b/README.md index d555a02..6a86106 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# RustBox 0.2.22 +# RustBox 0.2.23 RustBox is a webmail derived from `c0h1b4/oxi`. The consumed Oxi revision is recorded in `UPSTREAM_BASE`. @@ -67,7 +67,7 @@ Edit `config.dev.toml` before the first run: ```toml default_theme = "system" # system | dark | light -default_interface_skin = "rustbox" # rustbox | gmail | proton | zoho | outlook | fastmail | apple-mail | yahoo | hey | nord | github | gitlab | discord | slack | reddit | notion | ... +default_interface_skin = "rustbox" # rustbox | gmail | outlook | apple-mail | github | slack | dracula | catppuccin | tokyo-night | paper | terminal | aqua | material | retro | ... (full list in config.example.toml) log_level = "info" # RustBox app level; dependencies default to WARN. RUST_LOG can override the full filter. # Recommended dev filter: warn,rustbox=debug,tower_http=info # Avoid a global RUST_LOG=debug/info unless diagnosing a dependency: third-party @@ -183,7 +183,7 @@ rustbox search reindex Ready Docker examples are in `docker/`: standalone SQLite, PostgreSQL + SILO (S3-compatible) + OpenSearch, and MySQL + NFS + OpenSearch. -All executable application SQL is centralized by dialect under `src/queries/{sqlite,mysql,pgsql}/queries.rs`. Migrations V047-V050 are consolidated into the V050 compatibility baseline; databases older than V050 must first be upgraded with a release that can reach that baseline. RustBox 0.2.16 adds V051 for adaptive HTML-mail colors and mailbox loading mode; fresh schemas already contain those columns, while existing V050 tenants migrate automatically to V051. V052 is the next migration number. See `migrations/README.md`. +All executable application SQL is centralized by dialect under `src/queries/{sqlite,mysql,pgsql}/queries.rs`. Migrations V047-V052 are consolidated into the V052 compatibility baseline; databases older than V052 must first be upgraded with a release that can reach that baseline (0.2.22). RustBox 0.2.23 adds V053 for the appearance `skin_depth` and `skin_gradients` settings; fresh schemas already contain the column, while existing V052 tenants migrate automatically. V054 is the next migration number. See `migrations/README.md`. ## Development diff --git a/RELEASE-MANIFEST.txt b/RELEASE-MANIFEST.txt index 09cb17f..ab7a4b6 100644 --- a/RELEASE-MANIFEST.txt +++ b/RELEASE-MANIFEST.txt @@ -1,4 +1,13 @@ -RustBox 0.2.22 release manifest +RustBox 0.2.23 release manifest + +0.2.23 release changes: +- adds a "Style depth" appearance setting (`skin_depth`, migration V053): `colors` applies only a predefined style's palette, `standard` (default, previous behavior) adds its fixed layout profile, `immersive` additionally applies its structural design tokens — typography, control/button/avatar shapes, floating or flush panes, app-bar and search treatment, selection markers, row cards and backdrop +- adds a separate "Style gradients" switch (`skin_gradients`, default off, same V053 migration): every gradient used by a style — backdrops, app bars, primary buttons, Roundcube Classic bevels — is applied only when it is on; otherwise each style uses its flat fallback colors +- introduces the interface-style standard: every predefined style now ships light + dark palettes, a fixed layout profile and a structural token block (`57-skin-tokens.css`, consumed by `58-skin-immersive.css`); all 23 existing styles were adapted to it +- adds 14 predefined styles: Dracula, Catppuccin, Solarized, Gruvbox, Tokyo Night, Rosé Pine, Everforest, Synthwave, Paper, Terminal, Aqua Glass, Linear inspired, Material You inspired and Retro 95 +- the interface-style catalog is defined once in Rust (`INTERFACE_SKINS`) and shared by preference and `default_interface_skin` validation; the release validator enforces catalog/selector/profile/palette/token parity +- consolidates V051 and V052 into the fresh schemas; the compatibility baseline is now V052 +- fixes the fresh MySQL schema: `mail_preferences.message_loading_mode` now uses an expression default (MySQL rejects literal defaults on TEXT) 0.2.22 release changes: - adds message snooze: snoozing a message hides it client-side from its folder's current view until the chosen wake time, without touching server-side folder pagination/count SQL; `snoozed_messages` is a local-only cache table with no IMAP side effects, so a snoozed message is unaffected on any other client @@ -71,11 +80,10 @@ Search: Database/schema: - migrations/{sqlite,mysql,pgsql}/schema.sql contain the current fresh schema -- compatibility baseline is V050; former V047-V050 changes are consolidated into `schema.sql` and their standalone migrations are removed -- databases older than V050 must be upgraded with a V050-capable RustBox release before using this build -- V051 adds `display_preferences.adaptive_email_colors` and `mail_preferences.message_loading_mode` to existing V050 tenants -- V052 adds `snoozed_messages` (local-only cache state, no IMAP side effects) to existing V051 tenants -- next migration number: V053 +- compatibility baseline is V052; former V047-V052 changes are consolidated into `schema.sql` and their standalone migrations are removed +- databases older than V052 must be upgraded with a V052-capable RustBox release (0.2.22) before using this build +- V053 adds `display_preferences.skin_depth` (default `standard`) and `display_preferences.skin_gradients` (default off) to existing V052 tenants +- next migration number: V054 Docker examples: - docker/compose-single-sqlite.yml @@ -85,14 +93,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.22 configuration +- README.md documents 0.2.23 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.22 +- Cargo.toml version = 0.2.23 - 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 diff --git a/RELEASE-VALIDATION.txt b/RELEASE-VALIDATION.txt index 298d84f..2b3cec8 100644 --- a/RELEASE-VALIDATION.txt +++ b/RELEASE-VALIDATION.txt @@ -1,4 +1,11 @@ -RustBox 0.2.22 - final source validation +RustBox 0.2.23 - final source validation + +0.2.23 scope: +- adds Appearance "Style depth" (`skin_depth`, V053): colors only / standard (default) / immersive +- adds a separate "Style gradients" switch (`skin_gradients`, V053, default off); every stylesheet gradient is gated by it +- interface-style standard: every predefined style ships light+dark palettes, a fixed layout profile and structural design tokens; 23 existing styles adapted, 14 new styles added (Dracula, Catppuccin, Solarized, Gruvbox, Tokyo Night, Rosé Pine, Everforest, Synthwave, Paper, Terminal, Aqua Glass, Linear, Material You, Retro 95) +- V051/V052 consolidated into the fresh schemas; compatibility baseline V052 +- fresh MySQL schema: `message_loading_mode` uses an expression default 0.2.22 scope: - adds message snooze (`snoozed_messages`, V052): hides a message client-side from its current folder view until a chosen wake time; purely client-side hiding, no server-side pagination/count SQL changes, no IMAP side effects @@ -45,17 +52,18 @@ RustBox 0.2.22 - final source validation - PDF attachment preview uses the authenticated inline URL for Safari/iPhone compatibility - 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 adds `snoozed_messages` to existing V051 tenants; V053 is next -- version metadata identifies 0.2.22 +- V047-V052 are consolidated into compatibility baseline V052; V053 adds `skin_depth` and `skin_gradients` to existing V052 tenants; V054 is next +- version metadata identifies 0.2.23 Completed in this environment: -- offline release validator: scripts/validate-release-static.py (424/424 checks passed) +- offline release validator: scripts/validate-release-static.py (432/432 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.22 -- V050 baseline consolidation plus the V051 adaptive-colors/mailbox-loading migration are validated offline +- release metadata consistently identifies 0.2.23 +- V052 baseline consolidation plus the V053 skin-depth migration are validated offline +- all 37 interface styles rendered in light and dark at the immersive depth against a mocked API (Playwright), with no page errors Not executable in this packaging environment: diff --git a/config.example.toml b/config.example.toml index d74268e..3763128 100644 --- a/config.example.toml +++ b/config.example.toml @@ -11,8 +11,13 @@ cookie_secure = "auto" # Global light/dark theme: system | dark | light default_theme = "system" # Global interface style used by the login screen and by accounts set to -# "Global default". Presets include gmail, proton, zoho, outlook, fastmail, -# apple-mail, yahoo, hey, nord, github, gitlab, discord, slack, reddit, notion, minimal and Roundcube variants. +# "Global default". Each user can additionally choose a style depth (colors only, +# standard or immersive) in Appearance. Available styles: +# rustbox, roundcube-classic, roundcube-larry, roundcube-elastic, clean, gmail, +# proton, zoho, outlook, minimal, graphite, high-contrast, fastmail, apple-mail, +# yahoo, hey, nord, github, gitlab, discord, slack, reddit, notion, dracula, +# catppuccin, solarized, gruvbox, tokyo-night, rose-pine, everforest, synthwave, +# paper, terminal, aqua, linear, material, retro default_interface_skin = "gmail" data_dir = "/var/lib/rustbox" log_dir = "/var/log/rustbox" diff --git a/docs/IMPLEMENTATION_STATUS.md b/docs/IMPLEMENTATION_STATUS.md index 3db2f35..733a731 100644 --- a/docs/IMPLEMENTATION_STATUS.md +++ b/docs/IMPLEMENTATION_STATUS.md @@ -1,7 +1,16 @@ -# RustBox 0.2.22 - implementation status +# RustBox 0.2.23 - 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.22` 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.23` 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.23 interface styles + +- Adds Appearance → **Style depth** (`display_preferences.skin_depth`, migration V053): `colors` applies only a predefined style's palette and leaves layout controls editable; `standard` (default) keeps the previous palette + fixed layout behavior; `immersive` additionally applies the style's structural tokens. +- Adds Appearance → **Style gradients** (`display_preferences.skin_gradients`, same V053 migration, default off). Every gradient a style uses (immersive backdrops, app bars, primary buttons, the Synthwave logo, Roundcube Classic bevels in any depth) is scoped to `html[data-skin-gradients="true"]`; with the switch off the style uses flat fallback colors. The release validator rejects ungated gradients. +- Interface-style standard: each predefined style has light and dark palettes (`55-roundcube-skins.css`, `56-interface-styles.css`), a fixed layout profile (`interfaceStyleProfiles`) and a structural token block in `57-skin-tokens.css` (fonts, heading treatment, control/button/compose/avatar radii, floating vs. flush panes, pane borders/shadows/glass, app bar and search field, sidebar colors, selection background/marker, row cards, primary/compose buttons, focus ring, bevels). `58-skin-immersive.css` consumes the tokens only at the immersive depth; floating-pane geometry is limited to the desktop three-pane layout (>820px). +- All 23 existing styles were adapted to the standard; 14 styles were added: Dracula, Catppuccin, Solarized, Gruvbox, Tokyo Night, Rosé Pine, Everforest, Synthwave, Paper, Terminal, Aqua Glass, Linear inspired, Material You inspired, Retro 95. +- The style catalog lives in `display_preferences::INTERFACE_SKINS` and is shared by preference and `default_interface_skin` validation; `scripts/validate-release-static.py` checks catalog/selector/profile/palette/token parity. +- V051 and V052 are consolidated into the fresh schemas (baseline V052). The fresh MySQL schema now uses an expression default for `mail_preferences.message_loading_mode`. ## 0.2.22 snooze and undo send @@ -50,7 +59,7 @@ This file tracks the `0.2.22` source snapshot. Storage/search scope and outstand - Initial synchronization remains silent for new-mail notifications; bulk operations retain one summary toast; browser/system modifier shortcuts remain preserved. - Mailbox pagination is enabled by default at 300 messages per page; the API/preferences accept page sizes up to 300, with progressive and load-all alternatives. - Blob deletion uses a durable SQL outbox for filesystem/shared POSIX/NFS and S3 backends; attachment/draft metadata deletion is transactionally paired with cleanup enqueue and failed deletes retry in the background. -- V047-V050 are consolidated into the V050 compatibility baseline. RustBox 0.2.16 uses V051 to add adaptive HTML-mail colors and mailbox loading mode to existing V050 tenants; V052 is next. +- V047-V052 are consolidated into the V052 compatibility baseline (0.2.23). V053 adds `skin_depth` and `skin_gradients` to existing V052 tenants; V054 is next. ## 0.2.8 browser security headers diff --git a/migrations/README.md b/migrations/README.md index 87a18b6..4a02d26 100644 --- a/migrations/README.md +++ b/migrations/README.md @@ -8,28 +8,31 @@ RustBox keeps one complete fresh-install schema per supported SQL backend: ## Compatibility baseline -The consolidated compatibility baseline is **V050**. Historical migrations V047-V050 are already represented by the complete `schema.sql` files and are intentionally not shipped as standalone runtime migrations in this source tree. +The consolidated compatibility baseline is **V052** (RustBox 0.2.23). Historical migrations up to and including V052 are already represented by the complete `schema.sql` files and are intentionally not shipped as standalone runtime migrations in this source tree: -Databases older than V050 must first be upgraded with a RustBox release that can reach V050. RustBox 0.2.16 accepts V050 databases and migrates them forward normally. +- V047-V050 — attachment/search-outbox changes, folder counter generation, blob deletion outbox, compact-row and signature preferences (consolidated in 0.2.16); +- V051 — `display_preferences.adaptive_email_colors` (default `0`) and `mail_preferences.message_loading_mode` (default `pagination`); +- V052 — the `snoozed_messages` table used by Snooze (local cache state only, no IMAP side effects, no foreign keys). -## V051 — RustBox 0.2.16 +Databases older than V052 must first be upgraded with a RustBox release that can reach V052. RustBox 0.2.22 accepts V050 and V051 databases and migrates them to V052, so a tenant that has not logged in since an older release should be opened once with 0.2.22 before upgrading. Tenants below the baseline are refused with an explicit error instead of being partially migrated. -V051 adds the preferences introduced in 0.2.16: +The MySQL fresh schema now declares `mail_preferences.message_loading_mode` with an expression default (`DEFAULT ('pagination')`); MySQL rejects literal defaults on `TEXT` columns. -- `display_preferences.adaptive_email_colors`, default `0` / disabled; -- `mail_preferences.message_loading_mode`, default `pagination`. +## V053 — RustBox 0.2.23 -`mail_preferences.messages_per_page` remains `300` by default. Supported message loading modes are `pagination`, `progressive` and `all`. +V053 adds two appearance columns to `display_preferences`. -Fresh installations already contain the V051 columns in `schema.sql` and are registered at the latest schema version. Existing V050 tenants execute `V051__adaptive_email_colors_and_message_loading_mode.sql` before application queries use the new columns. +`skin_depth`, default `standard`, controls how far a predefined interface style may reshape the interface: -## V052 — RustBox 0.2.22 +- `colors` — only the style's palette is applied; layout, shapes and typography come from your own appearance settings; +- `standard` — palette plus the style's fixed layout preferences (the behavior of earlier releases); +- `immersive` — additionally applies the style's structural design tokens: typography, control and avatar shapes, floating panes, app-bar treatment, selection markers and backdrop. -V052 adds the `snoozed_messages` table used by the Snooze feature introduced in 0.2.22: a message can be hidden from its folder listing in the client until a chosen wake time, without being moved on the real IMAP server. The table is local cache state only (no IMAP side effects) and has no foreign keys, matching `message_tags`' existing exemption from forward-referencing foreign keys in the MySQL/PostgreSQL schemas. +`skin_gradients`, default `0` / off, is a separate switch for every gradient a style uses (backdrops, app bars, buttons, Roundcube Classic bevels). When off, each style falls back to flat colors defined next to its gradient. -Fresh installations already contain `snoozed_messages` in `schema.sql` and are registered at the latest schema version. Existing V051 tenants execute `V052__snooze.sql`. +Fresh installations already contain both columns in `schema.sql` and are registered at the latest schema version. Existing V052 tenants execute `V053__skin_depth_and_gradients.sql`. -The next migration number is **V053**. +The next migration number is **V054**. ## Migration rules @@ -39,3 +42,5 @@ Any future schema-changing release must: 2. add the same logical numbered migration for SQLite, MySQL and PostgreSQL; 3. register that migration in `src/db/pool.rs`; 4. extend the offline migration tests in `scripts/validate-release-static.py`. + +On MySQL, `TEXT` columns must use expression defaults such as `DEFAULT ('value')`. diff --git a/migrations/mysql/V051__adaptive_email_colors_and_message_loading_mode.sql b/migrations/mysql/V051__adaptive_email_colors_and_message_loading_mode.sql deleted file mode 100644 index 7e975c4..0000000 --- a/migrations/mysql/V051__adaptive_email_colors_and_message_loading_mode.sql +++ /dev/null @@ -1,5 +0,0 @@ -ALTER TABLE {{p}}display_preferences - ADD COLUMN adaptive_email_colors BIGINT NOT NULL DEFAULT 0; - -ALTER TABLE {{p}}mail_preferences - ADD COLUMN message_loading_mode TEXT NOT NULL DEFAULT 'pagination'; diff --git a/migrations/mysql/V052__snooze.sql b/migrations/mysql/V052__snooze.sql deleted file mode 100644 index ba5c8b8..0000000 --- a/migrations/mysql/V052__snooze.sql +++ /dev/null @@ -1,9 +0,0 @@ -CREATE TABLE {{p}}snoozed_messages ( - id VARCHAR(64) PRIMARY KEY, - message_uid BIGINT NOT NULL, - message_folder VARCHAR(512) NOT NULL, - wake_at BIGINT NOT NULL, - created_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)), - UNIQUE KEY idx_snoozed_messages_unique (message_uid, message_folder), - INDEX idx_snoozed_messages_wake (wake_at) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/migrations/mysql/V053__skin_depth_and_gradients.sql b/migrations/mysql/V053__skin_depth_and_gradients.sql new file mode 100644 index 0000000..ae8f5a5 --- /dev/null +++ b/migrations/mysql/V053__skin_depth_and_gradients.sql @@ -0,0 +1,3 @@ +ALTER TABLE {{p}}display_preferences + ADD COLUMN skin_depth TEXT NOT NULL DEFAULT ('standard'), + ADD COLUMN skin_gradients BIGINT NOT NULL DEFAULT 0; diff --git a/migrations/mysql/schema.sql b/migrations/mysql/schema.sql index d260d5c..0e6d817 100644 --- a/migrations/mysql/schema.sql +++ b/migrations/mysql/schema.sql @@ -1,13 +1,13 @@ -- RustBox 0.2.0 MySQL schema. -- One physical database contains global sessions plus isolated per-account tables. -- Application tables are materialized by replacing {{p}} with a collision-checked prefix. --- Squashed compatibility baseline: V050; current schema: V052. +-- Squashed compatibility baseline: V052; current schema: V053. -- RUSTBOX:GLOBAL-BEGIN CREATE TABLE IF NOT EXISTS rustbox_accounts ( user_hash VARCHAR(128) PRIMARY KEY, table_prefix VARCHAR(64) NOT NULL UNIQUE, - schema_version BIGINT NOT NULL DEFAULT 50, + schema_version BIGINT NOT NULL DEFAULT 52, created_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)), updated_at VARCHAR(64) NOT NULL DEFAULT (CAST(CURRENT_TIMESTAMP AS CHAR)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; @@ -177,7 +177,9 @@ CREATE TABLE {{p}}display_preferences ( spellcheck_enabled BIGINT NOT NULL DEFAULT 1, interface_skin TEXT NOT NULL DEFAULT ('rustbox'), preset_scale_unlocked BIGINT NOT NULL DEFAULT 0, - adaptive_email_colors BIGINT NOT NULL DEFAULT 0 + adaptive_email_colors BIGINT NOT NULL DEFAULT 0, + skin_depth TEXT NOT NULL DEFAULT ('standard'), + skin_gradients BIGINT NOT NULL DEFAULT 0 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE {{p}}draft_attachments ( @@ -297,7 +299,7 @@ CREATE TABLE {{p}}known_addresses ( CREATE TABLE {{p}}mail_preferences ( id BIGINT PRIMARY KEY, messages_per_page BIGINT NOT NULL DEFAULT 300, - message_loading_mode TEXT NOT NULL DEFAULT 'pagination', + message_loading_mode TEXT NOT NULL DEFAULT ('pagination'), mark_read_delay_ms BIGINT NOT NULL DEFAULT 0, remote_images TEXT NOT NULL DEFAULT ('ask'), preferred_body TEXT NOT NULL DEFAULT ('auto'), diff --git a/migrations/pgsql/V051__adaptive_email_colors_and_message_loading_mode.sql b/migrations/pgsql/V051__adaptive_email_colors_and_message_loading_mode.sql deleted file mode 100644 index 7e975c4..0000000 --- a/migrations/pgsql/V051__adaptive_email_colors_and_message_loading_mode.sql +++ /dev/null @@ -1,5 +0,0 @@ -ALTER TABLE {{p}}display_preferences - ADD COLUMN adaptive_email_colors BIGINT NOT NULL DEFAULT 0; - -ALTER TABLE {{p}}mail_preferences - ADD COLUMN message_loading_mode TEXT NOT NULL DEFAULT 'pagination'; diff --git a/migrations/pgsql/V052__snooze.sql b/migrations/pgsql/V052__snooze.sql deleted file mode 100644 index 0ee0b31..0000000 --- a/migrations/pgsql/V052__snooze.sql +++ /dev/null @@ -1,10 +0,0 @@ -CREATE TABLE {{p}}snoozed_messages ( - id TEXT PRIMARY KEY, - message_uid BIGINT NOT NULL, - message_folder TEXT NOT NULL, - wake_at BIGINT NOT NULL, - created_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text), - UNIQUE (message_uid, message_folder) -); - -CREATE INDEX {{p}}idx_snoozed_messages_wake ON {{p}}snoozed_messages(wake_at); diff --git a/migrations/pgsql/V053__skin_depth_and_gradients.sql b/migrations/pgsql/V053__skin_depth_and_gradients.sql new file mode 100644 index 0000000..69ce742 --- /dev/null +++ b/migrations/pgsql/V053__skin_depth_and_gradients.sql @@ -0,0 +1,3 @@ +ALTER TABLE {{p}}display_preferences + ADD COLUMN skin_depth TEXT NOT NULL DEFAULT 'standard', + ADD COLUMN skin_gradients BIGINT NOT NULL DEFAULT 0; diff --git a/migrations/pgsql/schema.sql b/migrations/pgsql/schema.sql index 33ff170..fbdaf17 100644 --- a/migrations/pgsql/schema.sql +++ b/migrations/pgsql/schema.sql @@ -1,13 +1,13 @@ -- RustBox 0.2.0 PostgreSQL schema. -- One physical database contains global sessions plus isolated per-account tables. -- Application tables are materialized by replacing {{p}} with a collision-checked prefix. --- Squashed compatibility baseline: V050; current schema: V052. +-- Squashed compatibility baseline: V052; current schema: V053. -- RUSTBOX:GLOBAL-BEGIN CREATE TABLE IF NOT EXISTS rustbox_accounts ( user_hash VARCHAR(128) PRIMARY KEY, table_prefix VARCHAR(64) NOT NULL UNIQUE, - schema_version BIGINT NOT NULL DEFAULT 50, + schema_version BIGINT NOT NULL DEFAULT 52, created_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text), updated_at TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP::text) ); @@ -177,7 +177,9 @@ CREATE TABLE {{p}}display_preferences ( spellcheck_enabled BIGINT NOT NULL DEFAULT 1, interface_skin TEXT NOT NULL DEFAULT 'rustbox', preset_scale_unlocked BIGINT NOT NULL DEFAULT 0, - adaptive_email_colors BIGINT NOT NULL DEFAULT 0 + adaptive_email_colors BIGINT NOT NULL DEFAULT 0, + skin_depth TEXT NOT NULL DEFAULT 'standard', + skin_gradients BIGINT NOT NULL DEFAULT 0 ); CREATE TABLE {{p}}draft_attachments ( diff --git a/migrations/sqlite/V051__adaptive_email_colors_and_message_loading_mode.sql b/migrations/sqlite/V051__adaptive_email_colors_and_message_loading_mode.sql deleted file mode 100644 index a75eb08..0000000 --- a/migrations/sqlite/V051__adaptive_email_colors_and_message_loading_mode.sql +++ /dev/null @@ -1,5 +0,0 @@ -ALTER TABLE {{p}}display_preferences - ADD COLUMN adaptive_email_colors INTEGER NOT NULL DEFAULT 0; - -ALTER TABLE {{p}}mail_preferences - ADD COLUMN message_loading_mode TEXT NOT NULL DEFAULT 'pagination'; diff --git a/migrations/sqlite/V052__snooze.sql b/migrations/sqlite/V052__snooze.sql deleted file mode 100644 index 7241b23..0000000 --- a/migrations/sqlite/V052__snooze.sql +++ /dev/null @@ -1,10 +0,0 @@ -CREATE TABLE {{p}}snoozed_messages ( - id TEXT PRIMARY KEY, - message_uid INTEGER NOT NULL, - message_folder TEXT NOT NULL, - wake_at INTEGER NOT NULL, - created_at TEXT NOT NULL DEFAULT (datetime('now')), - UNIQUE (message_uid, message_folder) -); - -CREATE INDEX {{p}}idx_snoozed_messages_wake ON {{p}}snoozed_messages(wake_at); diff --git a/migrations/sqlite/V053__skin_depth_and_gradients.sql b/migrations/sqlite/V053__skin_depth_and_gradients.sql new file mode 100644 index 0000000..aed8e59 --- /dev/null +++ b/migrations/sqlite/V053__skin_depth_and_gradients.sql @@ -0,0 +1,5 @@ +ALTER TABLE {{p}}display_preferences + ADD COLUMN skin_depth TEXT NOT NULL DEFAULT 'standard'; + +ALTER TABLE {{p}}display_preferences + ADD COLUMN skin_gradients INTEGER NOT NULL DEFAULT 0; diff --git a/migrations/sqlite/schema.sql b/migrations/sqlite/schema.sql index d4e1d43..734838a 100644 --- a/migrations/sqlite/schema.sql +++ b/migrations/sqlite/schema.sql @@ -1,13 +1,13 @@ -- RustBox 0.2.0 SQLite schema. -- One physical database contains global sessions plus isolated per-account tables. -- Application tables are materialized from the tenant section by replacing {{p}}. --- Squashed compatibility baseline: V050; current schema: V052. +-- Squashed compatibility baseline: V052; current schema: V053. -- RUSTBOX:GLOBAL-BEGIN CREATE TABLE IF NOT EXISTS rustbox_accounts ( user_hash TEXT PRIMARY KEY NOT NULL, table_prefix TEXT NOT NULL UNIQUE, - schema_version INTEGER NOT NULL DEFAULT 50, + schema_version INTEGER NOT NULL DEFAULT 52, created_at TEXT NOT NULL DEFAULT (datetime('now')), updated_at TEXT NOT NULL DEFAULT (datetime('now')) ); @@ -122,7 +122,7 @@ CREATE TABLE {{p}}display_preferences ( theme TEXT NOT NULL DEFAULT 'system', language TEXT NOT NULL DEFAULT 'en', updated_at TEXT NOT NULL DEFAULT (datetime('now')), - compose_format TEXT NOT NULL DEFAULT 'html', deep_index BOOLEAN NOT NULL DEFAULT 0, animation_mode TEXT NULL, preview_pane TEXT NOT NULL DEFAULT 'right', ui_scale TEXT NOT NULL DEFAULT 'normal', color_preset TEXT NOT NULL DEFAULT 'sage', accent_color TEXT NOT NULL DEFAULT '#6f9c86', font_family TEXT NOT NULL DEFAULT 'system', font_size INTEGER NOT NULL DEFAULT 13, row_height INTEGER NOT NULL DEFAULT 58, folder_pane_width INTEGER NOT NULL DEFAULT 228, message_pane_width INTEGER NOT NULL DEFAULT 420, border_radius INTEGER NOT NULL DEFAULT 4, contrast TEXT NOT NULL DEFAULT 'normal', show_avatars INTEGER NOT NULL DEFAULT 1, show_attachment_icons INTEGER NOT NULL DEFAULT 1, show_flags INTEGER NOT NULL DEFAULT 1, reduce_motion INTEGER NOT NULL DEFAULT 0, date_format TEXT NOT NULL DEFAULT 'locale', time_format TEXT NOT NULL DEFAULT 'locale', background_color TEXT NOT NULL DEFAULT '#121513', panel_color TEXT NOT NULL DEFAULT '#181c19', text_color TEXT NOT NULL DEFAULT '#edf0ec', compose_autosave_ms INTEGER NOT NULL DEFAULT 3000, default_priority TEXT NOT NULL DEFAULT 'normal', request_mdn_default INTEGER NOT NULL DEFAULT 0, attachment_reminder INTEGER NOT NULL DEFAULT 1, icon_size INTEGER NOT NULL DEFAULT 18, toolbar_density TEXT NOT NULL DEFAULT 'normal', sidebar_item_height INTEGER NOT NULL DEFAULT 29, reader_max_width INTEGER NOT NULL DEFAULT 0, composer_width INTEGER NOT NULL DEFAULT 900, selection_color TEXT NOT NULL DEFAULT '#28352e', unread_font_weight INTEGER NOT NULL DEFAULT 730, unread_badge_style TEXT NOT NULL DEFAULT 'dot', compact_headers INTEGER NOT NULL DEFAULT 0, show_borders INTEGER NOT NULL DEFAULT 1, scrollbar_density TEXT NOT NULL DEFAULT 'thin', monochrome INTEGER NOT NULL DEFAULT 0, folder_background TEXT NOT NULL DEFAULT '', message_background TEXT NOT NULL DEFAULT '', reader_background TEXT NOT NULL DEFAULT '', compose_font_family TEXT NOT NULL DEFAULT 'system', reply_position TEXT NOT NULL DEFAULT 'above', quote_style TEXT NOT NULL DEFAULT 'standard', forward_mode TEXT NOT NULL DEFAULT 'inline', spellcheck_enabled INTEGER NOT NULL DEFAULT 1, interface_skin TEXT NOT NULL DEFAULT 'rustbox', preset_scale_unlocked INTEGER NOT NULL DEFAULT 0, adaptive_email_colors INTEGER NOT NULL DEFAULT 0); + compose_format TEXT NOT NULL DEFAULT 'html', deep_index BOOLEAN NOT NULL DEFAULT 0, animation_mode TEXT NULL, preview_pane TEXT NOT NULL DEFAULT 'right', ui_scale TEXT NOT NULL DEFAULT 'normal', color_preset TEXT NOT NULL DEFAULT 'sage', accent_color TEXT NOT NULL DEFAULT '#6f9c86', font_family TEXT NOT NULL DEFAULT 'system', font_size INTEGER NOT NULL DEFAULT 13, row_height INTEGER NOT NULL DEFAULT 58, folder_pane_width INTEGER NOT NULL DEFAULT 228, message_pane_width INTEGER NOT NULL DEFAULT 420, border_radius INTEGER NOT NULL DEFAULT 4, contrast TEXT NOT NULL DEFAULT 'normal', show_avatars INTEGER NOT NULL DEFAULT 1, show_attachment_icons INTEGER NOT NULL DEFAULT 1, show_flags INTEGER NOT NULL DEFAULT 1, reduce_motion INTEGER NOT NULL DEFAULT 0, date_format TEXT NOT NULL DEFAULT 'locale', time_format TEXT NOT NULL DEFAULT 'locale', background_color TEXT NOT NULL DEFAULT '#121513', panel_color TEXT NOT NULL DEFAULT '#181c19', text_color TEXT NOT NULL DEFAULT '#edf0ec', compose_autosave_ms INTEGER NOT NULL DEFAULT 3000, default_priority TEXT NOT NULL DEFAULT 'normal', request_mdn_default INTEGER NOT NULL DEFAULT 0, attachment_reminder INTEGER NOT NULL DEFAULT 1, icon_size INTEGER NOT NULL DEFAULT 18, toolbar_density TEXT NOT NULL DEFAULT 'normal', sidebar_item_height INTEGER NOT NULL DEFAULT 29, reader_max_width INTEGER NOT NULL DEFAULT 0, composer_width INTEGER NOT NULL DEFAULT 900, selection_color TEXT NOT NULL DEFAULT '#28352e', unread_font_weight INTEGER NOT NULL DEFAULT 730, unread_badge_style TEXT NOT NULL DEFAULT 'dot', compact_headers INTEGER NOT NULL DEFAULT 0, show_borders INTEGER NOT NULL DEFAULT 1, scrollbar_density TEXT NOT NULL DEFAULT 'thin', monochrome INTEGER NOT NULL DEFAULT 0, folder_background TEXT NOT NULL DEFAULT '', message_background TEXT NOT NULL DEFAULT '', reader_background TEXT NOT NULL DEFAULT '', compose_font_family TEXT NOT NULL DEFAULT 'system', reply_position TEXT NOT NULL DEFAULT 'above', quote_style TEXT NOT NULL DEFAULT 'standard', forward_mode TEXT NOT NULL DEFAULT 'inline', spellcheck_enabled INTEGER NOT NULL DEFAULT 1, interface_skin TEXT NOT NULL DEFAULT 'rustbox', preset_scale_unlocked INTEGER NOT NULL DEFAULT 0, adaptive_email_colors INTEGER NOT NULL DEFAULT 0, skin_depth TEXT NOT NULL DEFAULT 'standard', skin_gradients INTEGER NOT NULL DEFAULT 0); CREATE TABLE {{p}}draft_attachments ( id TEXT PRIMARY KEY, diff --git a/packaging/rustbox.toml b/packaging/rustbox.toml index c2b69e4..2183b08 100644 --- a/packaging/rustbox.toml +++ b/packaging/rustbox.toml @@ -35,10 +35,10 @@ log_level = "warn" # system | dark | light default_theme = "system" -# Built-in examples: -# gmail, proton, zoho, outlook, fastmail, apple-mail, yahoo, hey, -# nord, github, gitlab, discord, slack, reddit, notion, minimal, -# and Roundcube variants. +# Built-in styles (full list in config.example.toml), e.g.: +# gmail, outlook, apple-mail, fastmail, github, slack, notion, nord, +# dracula, catppuccin, tokyo-night, rose-pine, paper, terminal, aqua, +# material, retro and Roundcube variants. default_interface_skin = "apple-mail" # Optional product features. Disabled features are removed from the API/UI. diff --git a/scripts/migrate_roundcube.py b/scripts/migrate_roundcube.py old mode 100755 new mode 100644 index cfad6e6..27ffb79 --- a/scripts/migrate_roundcube.py +++ b/scripts/migrate_roundcube.py @@ -453,7 +453,7 @@ def sqlite_tenant_schema() -> tuple[str, int]: raise ValueError(f"invalid RustBox tenant schema markers in {schema_path}") tenant_sql = schema.split(begin, 1)[1].split(end, 1)[0] - versions = [50] + versions = [52] for path in root.glob("V[0-9][0-9][0-9]__*.sql"): try: versions.append(int(path.name[1:4])) diff --git a/scripts/validate-release-static.py b/scripts/validate-release-static.py old mode 100755 new mode 100644 index c07e984..5f3cd52 --- a/scripts/validate-release-static.py +++ b/scripts/validate-release-static.py @@ -941,6 +941,78 @@ try: except Exception as exc: errors.append(f"shell syntax validation failed: {exc}") + +# Interface-style standard (0.2.23): every predefined style must be listed in +# the Rust catalog, the settings selector, the JS layout profiles, both palettes +# and the structural token table, so a style can never be half-defined. +skin_catalog_match = re.search(r"pub const INTERFACE_SKINS: &\[&str\] = &\[(.*?)\];", display_prefs_rs, re.S) +skin_catalog = re.findall(r'"([a-z0-9-]+)"', skin_catalog_match.group(1)) if skin_catalog_match else [] +require(len(skin_catalog) >= 30 and len(skin_catalog) == len(set(skin_catalog)) and "default" not in skin_catalog, "Rust interface-style catalog is complete and duplicate-free") +require("crate::db::display_preferences::INTERFACE_SKINS" in read("src/config.rs"), "server default interface style is validated against the shared Rust catalog") +skin_select = re.search(r'', index_html, re.S) +skin_options = re.findall(r'