Commit Graph
187 Commits
Author SHA1 Message Date
Linus Rath 989385f4f6 Merge branch 'feat/desktop-offline' into feat/do-ux-compose-fixes
# Conflicts:
#	components/email/email-viewer.tsx
#	components/settings/accessibility-settings.tsx
#	lib/__tests__/settings-search.test.ts
#	lib/settings-search.ts
2026-11-04 09:54:25 +01:00
Linus Rath aa62855759 Merge branch 'feat/do-ux-settings-fixes' into feat/desktop-offline
# Conflicts:
#	components/layout/__tests__/account-switcher-mountain-view.test.tsx
#	components/layout/account-switcher.tsx
#	components/settings/accessibility-settings.tsx
#	components/settings/reading-settings.tsx
2026-11-04 09:44:51 +01:00
Linus Rath 4a764150b2 Merge branch 'feat/desktop-offline' into feat/do-ux-settings-fixes 2026-11-04 09:22:44 +01:00
Linus Rath ceaceb7f2a Merge branch 'feat/desktop-offline' into feat/do-ux-compose-fixes
# Conflicts:
#	components/email/email-composer.tsx
#	components/email/email-viewer.tsx
#	locales/ar/common.json
#	locales/ca/common.json
#	locales/cs/common.json
#	locales/da/common.json
#	locales/de/common.json
#	locales/en/common.json
#	locales/es/common.json
#	locales/et/common.json
#	locales/fa/common.json
#	locales/fr/common.json
#	locales/he/common.json
#	locales/hu/common.json
#	locales/it/common.json
#	locales/ja/common.json
#	locales/ko/common.json
#	locales/lv/common.json
#	locales/mn/common.json
#	locales/nb/common.json
#	locales/nl/common.json
#	locales/pl/common.json
#	locales/pt/common.json
#	locales/ro/common.json
#	locales/ru/common.json
#	locales/sk/common.json
#	locales/th/common.json
#	locales/tr/common.json
#	locales/uk/common.json
#	locales/vi/common.json
#	locales/zh-TW/common.json
#	locales/zh/common.json
2026-11-04 09:20:50 +01:00
Linus Rath fcc9fc0cc0 Merge branch 'feat/desktop-offline' into feat/do-ux-mail-fixes
# Conflicts:
#	components/email/email-viewer.tsx
#	components/mail/mail-app.tsx
#	components/offline/offline-host.tsx
#	components/ui/welcome-banner.tsx
#	locales/ar/common.json
#	locales/ca/common.json
#	locales/cs/common.json
#	locales/da/common.json
#	locales/de/common.json
#	locales/en/common.json
#	locales/es/common.json
#	locales/et/common.json
#	locales/fa/common.json
#	locales/fr/common.json
#	locales/he/common.json
#	locales/hu/common.json
#	locales/it/common.json
#	locales/ja/common.json
#	locales/ko/common.json
#	locales/lv/common.json
#	locales/mn/common.json
#	locales/nb/common.json
#	locales/nl/common.json
#	locales/pl/common.json
#	locales/pt/common.json
#	locales/ro/common.json
#	locales/ru/common.json
#	locales/sk/common.json
#	locales/th/common.json
#	locales/tr/common.json
#	locales/uk/common.json
#	locales/vi/common.json
#	locales/zh-TW/common.json
#	locales/zh/common.json
2026-11-04 09:11:09 +01:00
Linus Rath 2094cca388 fix: leave an emptied out-of-office message box empty instead of showing sample text 2026-11-04 09:08:30 +01:00
Linus Rath 044647ff34 fix: keep the desktop layout in a half-screen window and at 150 % zoom
A window snapped to half the screen (640-800 px) or a 1366x768 laptop
at 150 % (911 px) got the phone and tablet layout: bottom tab bar,
folders in a drawer, Settings as a phone list with a Back arrow. The
layout switched at the 64rem (1024 px) breakpoint.

Now the phone layout starts below 600 px. From 600 to 1024 px the app
is a compact desktop: app rail at the side, folder sidebar folded to
its icons (the existing collapsed state, opened per session with its
toggle), Settings with its two panes and a narrower page list. Below
840 px the split layout opens a message in the list's place, as the
focused layout does. This holds in the browser and the desktop app,
in the Pro shell (which now runs from 600 px) and under Mountain View.

- `hooks/use-media-query.ts`: classifyWidth, PHONE_BELOW 600,
  FULL_DESKTOP 1024; the tablet class (`isTablet`) is gone, the store
  has `isCompact` instead. Plugins still see "tablet" for it.
- `app/globals.css`: a `desk:` breakpoint at 37.5rem for the layout
  classes, and a `tap:` variant for 44px rows on phones and touch
  screens below 1024 px (was every window below 1024 px).
- Touch screens below 1024 px keep swiping list rows (was phones only).
- The boot skeletons, boot script, mail app, sidebar, reader, admin
  shell and calendar, contacts and files follow the new widths.

Tests changed with the behaviour: the tablet cases in pro-gate,
mail-app-mv-composer-move, mail-app-compose-handoff,
mail-app-thread-expand-mark-read, mobile-tour-end and
thread-list-item-columns now run on a phone or a compact desktop, as
those widths no longer exist as a tablet. mail-app-short-window-tab-bar
is replaced by mail-app-compact-layout: a phone on its side is a
compact desktop with the rail at the side, so the short-window tab bar
rule is gone. Class and media-query assertions follow desk:/tap: and
37.5rem; the 32px-text test uses 1100 px, since 1440 px at 32px is now
a compact desktop.
2026-11-04 09:07:06 +01:00
Linus Rath 3841bdd630 Merge branch 'feat/do-drop-overlay' into feat/desktop-offline
# Conflicts:
#	desktop-policies/de-DE/Bulwark.adml
#	desktop-policies/en-US/Bulwark.adml
2026-11-04 08:37:26 +01:00
Linus Rath 91b237330e Merge branch 'feat/desktop-offline' into feat/do-ux-settings-fixes
# Conflicts:
#	components/settings/desktop-os-settings.tsx
#	components/settings/notification-settings.tsx
#	components/settings/protocol-handler-settings.tsx
2026-11-04 08:35:53 +01:00
Linus Rath 217e04bb31 Merge branch 'feat/do-uxs-wording' into feat/do-ux-settings-fixes 2026-11-04 08:35:00 +01:00
Linus Rath d0c86a4fce Merge branch 'feat/do-uxs-folders' into feat/do-ux-settings-fixes 2026-11-04 08:34:58 +01:00
Linus Rath ceaa81cd9e Merge branch 'feat/do-uxs-plugins' into feat/do-ux-settings-fixes 2026-11-04 08:34:57 +01:00
Linus Rath e2236ea476 Merge branch 'feat/do-uxs-general' into feat/do-ux-settings-fixes
# Conflicts:
#	components/settings/__tests__/settings-search-anchors.test.tsx
#	components/settings/accessibility-settings.tsx
#	lib/settings-search.ts
2026-11-04 08:34:25 +01:00
Linus Rath adbab2e4aa Merge branch 'feat/do-uxs-structure' into feat/do-ux-settings-fixes
# Conflicts:
#	lib/settings-search.ts
2026-11-04 08:33:26 +01:00
Linus Rath e8f17e2e3a fix: say no sidebar apps were added yet instead of repeating the section text 2026-11-04 08:24:36 +01:00
Linus Rath 3609b5c99f fix: hide the stored keyword under each tag in settings
Tag rows no longer show "$label:…" under the name; with advanced
settings on it is the tag's tooltip. The page and the recover section
no longer talk about JMAP keywords, and the recover section is called
"Find tags on your messages that are missing here".

The keyword-settings test asserted the "$label:…" line; it now asserts
the line is gone and the tooltip shows with advanced settings on.
2026-11-04 08:08:26 +01:00
Linus Rath bc955be104 feat: offer to apply a new filter rule to the inbox and drop developer words from the rule editor
- After a new rule is saved in Settings > Filters, a notice offers
  "Apply to N existing messages in Inbox" when the rule would change
  mail already there (the same check and batch actions as rules made
  from a message).
- "Stop processing" is no longer an action. The checkbox "Don't apply
  later rules" does it; an old rule with the action opens with it
  folded into the checkbox, and what came after the stop (which never
  ran) is dropped.
- "matches regex" and the raw Sieve editor show only with advanced
  settings on (the editor stays for a script only it can change).
- "Match all conditions" / "Match any condition", no capitals.
- The folder picker names folders as the sidebar does, indented, and
  leaves out Drafts, Sent and Scheduled unless the rule already uses one.

The regex test now turns on advanced settings first, and the focus
tests open the raw editor with advanced settings on, since both are
advanced now.
2026-11-04 08:08:16 +01:00
Linus Rath 51beeb957b fix: name folders in settings as the sidebar does
Folders & tags and the All mail folder list showed the server's names
("Sent Items", "Junk Mail", "Deleted Items") with a second chip naming
the role. They now use the sidebar's names (Sent, Spam, Trash) through
the same helper, and the chip is gone.

The role-label test asserted the chip; it now asserts the sidebar names
and that no chip is drawn. The bulk-move test found the Inbox row by
its server name, which the row no longer shows.
2026-11-04 08:08:04 +01:00
Linus Rath e403478a05 fix: show the default calendar and contacts by plain names, hide CalDAV addresses until asked and translate the previews
The CalDAV fallback test now clicks "Use in other apps" first, because the
address is no longer shown on every calendar row.
2026-11-04 08:05:31 +01:00
Linus Rath e0f19bc6f1 feat: list the server settings for other mail apps and keep rare app password options behind More options 2026-11-04 08:05:31 +01:00
Linus Rath ce34617147 feat: turn plugins an admin installs on for every user, who can turn them off
The #1327 store test now serves its optional plugin with defaultOn false:
it checks that every plugin is listed when IndexedDB fails, and a plugin
the admin didn't force is on by default now.
2026-11-04 08:01:38 +01:00
Linus Rath aebc61e287 fix: keep only accessibility settings on the Accessibility page and link to the rest 2026-11-04 07:37:33 +01:00
Linus Rath b082ce582e feat: put offline, privacy and about on settings pages of their own and widen the settings search
Offline sat in the middle of Backup & reset, privacy settings were spread
over Reading, Composing and Message list, and the version card took room
from the page list in the sidebar's footer. The search matched letters
inside words ("lock" found Time format and Send Checks) and knew no other
words for a setting ("offline", "autoreply", "logout" found nothing).

- Offline is a page in the top group: Keep mail on this device, what is
  kept, Remove everything from this device, and the Outbox as its own
  section. Old `/settings/backup/offline` links and the offline notice
  land there.
- Privacy holds remote images and trusted senders, read receipts, sender
  pictures from the web, the desktop app's usage info and crash reports,
  and a link to the push relay on Notifications. Reading, Composing and
  Message list keep a link row; old links to those sections land on
  Privacy.
- About is the last page and holds the version card; the footer keeps the
  Advanced switch.
- The search matches whole words and word starts (substrings only in
  Chinese, Japanese and Thai), and each row can carry synonyms in the
  user's language. A page matches by its name and keywords or when one of
  its rows has every word. Account gets a Sign out row so "logout" leads
  somewhere.
- The index test now also fails when a page draws a section the index
  doesn't know, and a new test fails on two indexed rows with the same
  name. Tests that rendered remote content and sender pictures on Reading
  and Message list render Privacy instead, since that's where the rows are.
2026-11-04 07:37:25 +01:00
Linus Rath b3c9d99df7 fix: make the General and Notifications settings say what they do
The usability pass of 2026-11-04 found the General and Notifications
pages hard to read, and the desktop app showing browser-only rows.

- Time zone: a searchable list by city and offset, common zones
  first, with today's city names (Kolkata, Kyiv, Ho Chi Minh City).
  The stored value stays the IANA id the runtime knows.
- First day of the week: "First day of the week in calendars".
- Desktop app: no browser link handlers (the app has its own "Default
  mail app" row), no usage info on General (it moves to Privacy),
  time zone and app lock texts without the browser and tabs.
- Taskbar flashing and quiet hours move to Notifications.
- "Windows" is now "App windows".
- Notifications: "Sound for new mail", "Sound for reminders", a
  "Sound" section with a "Tone" row, "Notifications when Bulwark is
  closed" with "Turn on for this device", a short badge description.
- Link handlers: "Open email links in Bulwark" with "Use Bulwark for
  email links", no "Technically" sentence.
- App lock: "The PIN stays on this device.", the protection text
  behind "What does this protect?", "1 hour" and "4 hours", one line
  in the PIN dialog instead of repeating its title.
- Usage info names "the app's version numbers", as the desktop's
  first run does, instead of the Node version.

Test changes: the telemetry wording test looked for "Node version",
which the text no longer names; the search-anchor test now fills in
{appName} before comparing, as the search index does, because row
labels name the app.
2026-11-04 07:30:54 +01:00
Linus Rath 94b9fe8803 fix: start out of office with real text and never switch on a blank reply
Out of office used grey placeholder text, so switching the reply on sent
an empty message. A reply never written now opens with an editable subject
and message in the user's language; the switch stays off while the message
is empty and says "Write a message first", and a reply that is on can't be
saved with its text deleted. Forwarding won't switch on without an address,
and the address field shows while it is off. The page puts the switch
first, then "Reply to" with plain choices, then "From/Until (optional)",
then one message editor with formatting instead of a text box plus a
second "Formatted message (HTML)" box. A message nobody edited is sent as
the server has it. A failed save is no longer retried once at once when
the last change was a click.

Test changes: the forward tests type the address before switching
forwarding on (it no longer switches on without one) and check the new
order and option labels; the HTML-body and template tests use the one
editor instead of the text box and HTML switch, which are gone. The
search index names the new rows.
2026-11-04 06:29:53 +01:00
Linus Rath 364fc516dc fix: hide the browser's link handlers in the desktop app and call its window settings App windows 2026-11-04 06:29:25 +01:00
Linus Rath 80321e21a2 fix: explain replying from the received address in plain words
The admin-locks test finds the row by its label key, which moved to the
compose_words namespace with the new description.
2026-11-04 06:26:28 +01:00
Linus Rath 1cf03ff0e4 feat: add a developer tools switch to the desktop app's troubleshooting settings 2026-11-04 05:38:59 +01:00
Linus Rath 09d6bff12a fix: say push isn't available in the demo instead of offering a switch that fails 2026-11-04 03:13:58 +01:00
Linus Rath 71aaadef50 fix: run plugins' compose check in quick compose, keep a composer with one owner, and bring it back after a crash
The first version of quick compose skipped `onBeforeCompose`, a composer
moved back could end up open in both windows, a reply moved back under
Pro flagged the selected message, and a crashed pop-out came back blank.

- A new message in a pop-out runs `onBeforeCompose` with the same result
  as the main window: a plugin that stops it closes the window.
- The way back has two steps, so a pop-out that gave up can't leave a
  second owner. A handoff behind a plugin's gate makes it say busy.
- A Pro tab made from a composer moved back answers its own message.
- Each save writes `draft`, `account` and `owner` into the pop-out's
  address, which a reload after a crash starts from. What was typed since
  the last save, up to the 2 s autosave delay, is still lost.
- The recorder refuses keys that type a character on this keyboard, and
  what the shell refuses from a page, and says why.
2026-11-04 01:31:43 +01:00
Linus Rath 3da18cc2c0 feat: set the quick compose keys in the desktop settings and move a composer back into the main window 2026-11-03 23:25:10 +01:00
Linus Rath 54bda3ef3d Merge branch 'feat/do-packaging' into feat/desktop-offline
# Conflicts:
#	components/desktop/desktop-host.tsx
#	lib/desktop/languages.ts
2026-11-03 22:02:10 +01:00
Linus Rath 423fe28b0b Merge branch 'main' into feat/do-ci-fix 2026-11-03 19:50:46 +01:00
Linus Rath 4015bbad76 test: expect the hidden settings row without a plugin, since the desktop app shows it for the window controls 2026-11-03 19:49:56 +01:00
Linus Rath 529d334496 Merge branch 'fix/ui-bug-hunt' 2026-11-03 19:44:46 +01:00
Linus Rath a96c66fa5e Merge branch 'main' into feat/do-packaging
# Conflicts:
#	components/settings/general-settings.tsx
#	lib/desktop/types.ts
2026-11-03 19:37:41 +01:00
Linus Rath 3d5b02b75f fix: stop a page reporting once consent goes, and let nothing on disk aim the desktop app's telemetry
A review found that an open page kept sending to a DSN after consent was
taken back, that a state file or config file could name where telemetry
goes, and that `BULWARK_TELEMETRY=off` did nothing on the desktop build.
A due heartbeat now waits a random 30 s to 10 min, a refusal from the
collector isn't retried, crash files go at sign-out and account switch,
and server builds parse stacks as they did.

Existing assertions changed in the desktop telemetry tests: the catch-up
wait is now a range, the endpoint comes from the shell, and the platform
is `desktop` against the collector's patched branch.
2026-11-03 17:38:04 +01:00
Linus Rath 79014a63b2 Merge branch 'feat/desktop-offline' into feat/do-packaging
# Conflicts:
#	lib/desktop/types.ts
#	locales/ar/common.json
#	locales/ca/common.json
#	locales/cs/common.json
#	locales/da/common.json
#	locales/de/common.json
#	locales/en/common.json
#	locales/es/common.json
#	locales/et/common.json
#	locales/fa/common.json
#	locales/fr/common.json
#	locales/he/common.json
#	locales/hu/common.json
#	locales/it/common.json
#	locales/ja/common.json
#	locales/ko/common.json
#	locales/lv/common.json
#	locales/mn/common.json
#	locales/nb/common.json
#	locales/nl/common.json
#	locales/pl/common.json
#	locales/pt/common.json
#	locales/ro/common.json
#	locales/ru/common.json
#	locales/sk/common.json
#	locales/th/common.json
#	locales/tr/common.json
#	locales/uk/common.json
#	locales/vi/common.json
#	locales/zh-TW/common.json
#	locales/zh/common.json
2026-11-03 16:09:04 +01:00
Linus Rath 03cdf69bf2 feat: let desktop users opt in to usage info and crash reports, each with its own switch 2026-11-03 15:55:17 +01:00
Linus Rath 3687363d6e fix: stop Back doing nothing in Settings after the window crosses the phone width several times 2026-11-03 15:12:06 +01:00
Linus Rath 1d4587f7ea fix: stop a stuck certificate call holding mail rendering, and let a server's certificate access be taken back 2026-11-03 11:31:14 +01:00
Linus Rath 391edb8f92 feat: show the desktop app's updates and channel in the general settings 2026-11-03 09:56:16 +01:00
Linus Rath 12e643db9f test: expect spaces around the arrow in a filter rule summary 2026-11-03 06:42:39 +01:00
Linus Rath f88620208a fix: keep the open settings page when the window narrows to the phone layout 2026-11-03 05:52:19 +01:00
Linus Rath 308178beda fix: open each settings page at its top and keep the place in the phone's page list 2026-11-03 05:06:26 +01:00
Linus Rath bf19f21eaf test: give the composing settings test the useLocale the proofreading section needs 2026-11-03 02:35:24 +01:00
Linus Rath e9e07ddb64 Merge main into feat/assistant-everywhere 2026-11-03 01:35:57 +01:00
Linus Rath 267ca40522 Merge branch 'feat/assistant-everywhere' into feat/assistant-c 2026-11-03 00:24:12 +01:00
Linus Rath ad36f8d382 fix: show the side panel only where the plugin does, and keep it steady
- The button and the panel of Calendar, Contacts, Files and Settings
  show only when the plugin's shouldShow says yes, so a plugin switched
  off for these views (admin, user or no service) leaves no button that
  opens an empty panel, and no extra rows in Contacts and Settings.
- Files: while the details are open the panel steps aside there only;
  the other views keep it as the user left it. With both stored open the
  details fold when the page loads.
- Resizing stops where the view keeps its 480 px, so a drag or the arrow
  keys no longer fold the panel away (and the handle keeps the focus).
- Settings and Contacts render the same element with or without the
  panel, so a form keeps what was typed when the panel starts docking.
- Contacts on a phone: the panel button sits over an open contact too.
- The panel buttons of the reader and the views have one name, "Plugin
  panel", with aria-pressed, and name the plugin's panel shortcut in
  their title; the open panels are named landmarks.

The reader tests look the button up by its new name and pressed state
(viewer-toolbar-over-side-panel, reader-plugin-surfaces,
viewer-plugin-panel-width), since "Show/Hide plugin panel" is gone.
2026-11-02 23:54:53 +01:00
Linus Rath 8905d31b38 fix: show the admin's locks for plain text and the reply identity on the composing page 2026-11-02 23:14:21 +01:00