Commit Graph
19 Commits
Author SHA1 Message Date
xhzeemandLinus Rath adb8686293 fix(rtl): anchor floating menus with logical start/end instead of left/right
Popovers and dropdown menus across the app (sub-address helper, calendar
toolbar/color pickers, contact/template/attachment menus, rich text editor
color and table pickers, unsubscribe confirmation, composer send menu)
were anchored with physical `left-0`/`right-0`. In RTL locales those
don't flip with the trigger, so the menu detaches from the button that
opened it. Switched to Tailwind's logical `start-0`/`end-0` (and the
matching `rounded-s-*`/`rounded-e-*` corners on hover-action overlays)
so they mirror correctly for RTL locales (ar, he, fa) while staying
identical in LTR.
2026-07-21 23:08:02 +02:00
Stefan HildebrandtandLinus Rath 01e5cd69cf fix(identity): sync default sender identity per account (#507)
The default sender identity (`preferredPrimaryId`) lived only in the
browser-local `identity-storage` store and was never written to the synced
settings, so the choice was lost on clearing site data / switching browsers and
never appeared in exported settings.

Persist it in the synced settings store, keyed **per account**
(`preferredIdentityIds: Record<accountId, identityId>`), mirroring the existing
per-account `allMailFolderIds`. Per-account keying is required because JMAP
identity ids are account-scoped and would otherwise collide across accounts /
the unified mailbox.

This supersedes the earlier username-keyed fix that had landed on main: the
username-keyed map, `loadIdentities()` fallback write, and the
`applyPreferredIdentityOrdering` store action (plus its settings-store hook)
are removed so a single account-keyed mechanism remains.

- settings-store: `preferredIdentityIds` (accountId -> identityId) in state,
  defaults, export, import (non-record guard), rehydrate coercion, v6 migration.
- auth-store: `applyPreferredIdentity(accountId?)` reorders the active account's
  identities once synced settings load, and performs the one-time migration of
  the pre-#507 browser-local default into the synced map (keyed by accountId).
  Invoked from every `loadFromServer().finally()` (login / OAuth / SSO / switch
  / restore). `loadIdentities()` now only applies the local fallback ordering.
- identity-manager-modal: the star action writes the choice by `activeAccountId`.
- identity-store: `preferredPrimaryId` kept as a local (sync-off) fallback.
- tests: per-account independence, export/import round-trip, import guard, and
  applyPreferredIdentity reorder / active-account gating / local-default
  migration.
2026-07-13 21:21:34 +02:00
honzupandLinus Rath 42798c2b7c fix: open signature links in a new tab instead of navigating the app away
Signatures render into the main document - the identity form's live preview
and the composer's signature block - rather than the sandboxed iframe used for
message bodies. SIGNATURE_SANITIZE_CONFIG allows no target attribute, so those
anchors were live and target-less: one click navigated the whole app away,
discarding the unsent draft or the unsaved signature with it.

Add sanitizeSignatureHtmlForDisplay, which keeps the storage sanitizer's image
restrictions but forces target="_blank" rel="noopener noreferrer" on every
anchor, and use it at the two render sites. The composer's SignatureBlock
NodeView stamps the target on its rendered DOM instead, because attrs.html is
what serializeEditorContent emits into the sent message - storage and the
recipient's copy stay exactly as the user wrote them.
2026-07-11 10:45:01 +02:00
Shuki VakninandLinus Rath 22418c17cf feat(i18n): Hebrew locale + full RTL support 2026-07-08 00:07:34 +02:00
Linus Rath f90cd6abc4 fix: sync default identity (preferredPrimaryId) to server settings #507 2026-06-28 20:12:54 +02:00
Linus Rath 9db7b6b55f docs: clarify signature byte cap comment is Stalwart-specific 2026-06-04 10:40:42 +02:00
Linus Rath ed6b5d5f33 fix: clear identity signature fields when emptied 2026-05-18 00:53:54 +02:00
Linus Rath 7a72903632 feat: show size cap on identity signature fields 2026-05-18 00:34:01 +02:00
Timo StreuleandLinus Rath 4b7009dfc2 feat: raise HTML signature length cap to 50000 chars
5000 chars is too tight for signatures containing base64-embedded images (even a small PNG can run a few thousand chars).
2026-05-15 14:46:43 +02:00
Linus Rath c555973b6b feat: configurable sub-addressing delimiter #239 2026-05-01 01:42:06 +02:00
Linus Rath d0cc439fd1 feat: add automatic identity synchronization (#167) 2026-04-09 19:39:04 +02:00
Linus Rath 7a191cf78b fix: resolve all 69 ESLint warnings across 40 files
- Remove unused imports (Mail, CalendarIcon, Plus, Circle, cn, Link,
  MessageCircle, User, Tag, FolderUp, useEffect, LogOut, GripVertical,
  Check, X, HoverActionsMode, HoverActionsCorner, asn1js, Convert, etc.)
- Prefix unused variables/params with underscore to satisfy no-unused-vars
- Add missing React hook dependencies (exhaustive-deps)
- Wrap handleNavigateUp in useCallback and selectedGroupMembers in useMemo
- Remove unused eslint-disable directives in jmap/client.ts
- Replace as any with typed casts in filter-store and smime-store tests
- Remove dead code (macOk assignment, unused now variable)
2026-03-26 18:35:56 +01:00
Linus Rath 0fcc932e66 fix: adjust popover alignment to the right 2026-03-19 07:44:11 +01:00
Linus Rath fc79bf4f9b fix: resolve default sender to canonical identity on local-part login
When authenticating with a local-part username (e.g. 'user' instead of
'user@domain.tld') on Stalwart 0.15.x, the default sender could resolve
to an alias identity instead of the canonical mailbox address.

- Add emailMatchesUsername() helper that matches local-part usernames
  against full email addresses (e.g. 'user' matches 'user@domain.tld')
- Prefer canonical identities (mayDelete=false) over aliases as tiebreaker
- Add preferredPrimaryId to identity store (persisted to localStorage)
  so users can explicitly set their default sender
- Add 'Set as Primary' star button in identity manager modal
- Fix sendEmail() fallback identity resolution for local-part usernames
- Add i18n strings for all 8 supported locales

Fixes #43
2026-03-18 20:05:35 +01:00
Linus Rath 3186198fad feat: enhance identity management with identity refresh functionality and improved modal behavior 2026-03-17 21:50:35 +01:00
Linus Rath 0080d27b3e fix: sync identity stores and append signatures to outgoing emails (#15)
- Add syncIdentities() to auth store to propagate identity changes from
  identity store, fixing stale data that caused save failures and duplicates
- Call syncIdentities() after every create, update, and delete in the
  identity manager modal
- Switch email composer to read identities from identity store for
  consistency with the rest of the app
- Append identity text signature (with RFC 3676 separator) to email body
  when sending from the composer and quick reply paths
- Add tests for syncIdentities and signature appending logic
2026-03-15 16:07:45 +01:00
Linus Rath cf02f587de feat: resizable columns, nav rail overhaul, multi-select & drag-drop, UI polish
Resizable Columns
- Add ResizeHandle component with mouse drag, keyboard (Arrow keys),
  and double-click to reset to default width
- Add sidebarWidth/emailListWidth to ui-store with clamping + persistence
- Wire resize handles between sidebar/email-list panels on desktop

Navigation Rail Overhaul
- Move StorageQuotaCircle, push-status, sign-out from Sidebar to NavigationRail
- Interactive SVG ring with popover breakdown (used/free/total)
- Sidebar collapse state lifted to ui-store
- Show total email count per mailbox alongside unread badge

Email Multi-Selection & Drag-and-Drop
- Ctrl+Click (toggle) and Shift+Click (range) on all list items
- Add selectRangeEmails and lastSelectedEmailId to email-store
- Enable drag-and-drop on thread items and thread headers
- useEmailDrag accepts optional threadEmails for full-thread drag

Email Viewer Layout
- Remove card wrapper for cleaner full-width reading
- Always render HTML body when available
- Adjust skeleton loader to match flat layout

Modal & UI Polish
- Standardise backdrops, close buttons, padding, border-radius, transitions
- Migrate template-string classNames to cn() in settings
- Unify focus-ring token to ring-ring on form controls

i18n
- Add storage_used/free/total keys to all 8 locales

Dev Mock JMAP Server (new, gated by DEV_MOCK_JMAP=true)
- Session, Mailbox/Email/Thread/Identity CRUD, back-references, upload
- GET /download with Content-Disposition, GET /eventsource SSE

Tests (46 new)
- ui-store (13), email-selection (10), resize-handle (9), mock-server (14)
2026-03-09 16:46:25 +01:00
Matthieu MALVACHEandMatthieu MALVACHE a43096485b feat: add UI/UX polish with navigation rail, confirm dialogs, welcome banner, and form validation
- Add NavigationRail component (desktop vertical icon sidebar + mobile bottom tab bar)
- Add ConfirmDialog with promise-based useConfirmDialog hook for async confirmation flow
- Add WelcomeBanner onboarding component (one-time display, localStorage persistence)
- Polish login form UX (shake on error, TOTP slide animation, password visibility toggle, session expired banner)
- Add inline form validation with shake animation in email composer and contacts
- Add empty state patterns for contacts (no data vs no search results with contextual actions)
- Improve toast notification system with undo action support and typed durations
- Add WCAG AA prefers-reduced-motion media query, safe area insets, sr-only live regions
- Add template settings tab and keyboard shortcut integration
- Update all 8 locale translations
2026-02-17 02:31:50 +01:00
Matthieu MALVACHEandMatthieu MALVACHE 5d273e2109 feat: expand internationalization and add identity management
This release significantly expands internationalization support and adds comprehensive identity management features.

Internationalization (i18n):
- Add 5 new languages: Spanish, Italian, German, Dutch, Portuguese
- Expand from 3 to 8 total supported languages
- Redesign language switcher for better scalability (dropdown UI)
- Complete translations for all features across all languages

Identity Management:
- Multiple sender identities with per-identity signatures
- Sub-addressing support (user+tag@domain.com)
- Context-aware tag suggestions for sub-addresses
- Identity badges in email viewer and list
- Full CRUD operations for managing identities

Newsletter Management:
- RFC 2369 List-Unsubscribe support (one-click unsubscribe)
- HTTP and mailto unsubscribe methods
- Security validation prevents XSS attacks
- Two-step confirmation with persistent dismissal

Security & Accessibility:
- Dark mode email readability (intelligent color transformation)
- WCAG 2.0 Level AA color contrast compliance
- Comprehensive XSS prevention with validation utilities
- Unit test coverage for security-critical code (57 validation tests)

Testing:
- Add unit tests for validation utilities
- Add unit tests for email sanitization
- Add unit tests for color transformation
- Full test coverage for XSS attack vectors
2026-01-08 22:15:32 +01:00