Commit Graph
145 Commits
Author SHA1 Message Date
Linus Rath e127f5d24b fix: reuse the translated saving label on the event Save button #921 2026-09-30 14:23:33 +02:00
Linus Rath 7282adbb06 Merge pull request #921 from texchi2/fix/calendar-save-in-flight
fix(calendar): show in-flight state on Save, and surface the silent length-guard rejection
2026-09-30 14:23:09 +02:00
Linus Rath fa789a6d9f Merge pull request #748 from lucletoffe/fix/calendar-blank-cn-and-description
fix(calendar): stop writing blank participant names and empty descriptions
2026-09-30 14:21:20 +02:00
Linus Rath 62e07608fd fix: stop the mail list hiding dividers between some rows 2026-09-30 00:21:21 +02:00
Sebastian SanitzandClaude Opus 5.5 695cc7303f fix(calendar): add translations for the all-day expand toggle
The expand/collapse toggle referenced calendar.events.show_more and
show_less, which were missing from every locale (translations test failed),
and passed a defaultMessage option next-intl does not support. Add both keys
to all 27 locales, reusing each locale's existing email_composer.show_less
wording, and drop the unsupported option.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 00:08:15 +02:00
Sebastian SanitzandClaude Opus 5.5 ea6d0ee678 fix(calendar): size the week view all-day area from the visible week
The all-day/tasks area in the week view took its height from
(allDayRowCount + taskRowCount) across every loaded day. Since free
scrolling loads 37 to 180 days, one crowded day anywhere in that range
blew the header up to 250+ px for every week and pushed the time grid down;
tasks were also stacked below the global all-day row count, leaving a gap
on days without all-day events.

- Stack each day's tasks directly below that day's all-day events.
- Size the area from the days in view only: track the first visible day by
  date (so columns prepended while loading do not shift it) plus the number
  of visible columns (7 on desktop, by width on mobile).
- Cap the area at 3 rows with an expand/collapse toggle when a visible day
  has more entries.

Tests cover per-day task stacking, the 3-row cap and toggle, an empty week
next to a crowded one, and the area growing when scrolling into it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 23:42:30 +02:00
Linus Rath be3c4b0d99 feat: draw calendar events as solid blocks and toasts as plain cards 2026-09-27 12:45:19 +02:00
Linus Rath 09e0e2cfb3 fix: show events you declined struck through in the calendar #1110 2026-09-26 21:32:08 +02:00
Linus Rath 078e9f9676 feat: show tasks with due dates in the calendar month view #1107 2026-09-26 20:47:13 +02:00
Linus Rath 691cde6468 fix: explain why calendar subscriptions fail with not authenticated #1073 2026-09-23 18:31:27 +02:00
Linus Rath 6f82493dda fix: show the calendar import dropdown above the day and week views #1049 2026-09-23 18:24:36 +02:00
Linus Rath 28fd880582 fix: keep single-occurrence edits on that occurrence and keep its details 2026-09-23 13:40:01 +02:00
Linus Rath f95b826434 feat: let attendees answer a single occurrence of a recurring event #1086 2026-09-23 13:06:41 +02:00
Linus Rath d7fdd7ce61 fix: offer to save an event when the server refuses its invitations
From 0.16.21 Stalwart fails the whole CalendarEvent/set with
`forbidden` when the account may not send scheduling messages, so an
event with attendees was not saved at all and the calendar showed only
"Failed to save event".

Such a refusal now surfaces as SchedulingDeniedError, and the calendar
names the server's reason and offers to save the event without sending
the invitations.
2026-09-22 21:25:20 +02:00
Linus Rath d7548a4bab refactor: migrate icon set from Lucide to Tabler Icons 2026-09-19 13:32:41 +02:00
Tex LH Chi e9a72ec17e fix(calendar): show in-flight state on Save and surface the silent length-guard rejection 2026-09-18 17:43:21 +08:00
Linus Rath 5de98bc04b feat: add Bulwark Lite static export build 2026-09-17 23:54:33 +02:00
Linus Rath ee4763d5c0 Merge pull request #1036 from dealerweb/fix/calendar-principal-fetch
fix(calendar): stop the account principal fetch from failing on every load
2026-09-17 22:03:26 +02:00
Linus Rath 0cc1602933 Merge pull request #1037 from dealerweb/fix/mini-calendar-jump
fix(calendar): jump to the day picked in the mini calendar
2026-09-17 22:03:21 +02:00
Linus Rath 2e88a0c830 Merge main into fix/calendar-participants
Resolves the two conflicts in components/calendar/event-modal.tsx created
by #967 (RSVP controls), both keep-both:

- #967's canRsvp memo and #986's resolveContactName hook are both kept;
  they are independent and were simply inserted at the same point.
- #967's RsvpBar component is kept, and StatusBadge takes #986's
  signature ({ status, t }) since #986 drops the isOrganizer prop and
  updates both call sites to match.
2026-09-17 21:54:08 +02:00
Linus Rath e2f50cbb88 Merge pull request #967 from wrycu/fix/ui-rsvp
fix: rsvp controls
2026-09-17 21:49:38 +02:00
dealerweb 464586d0c1 fix(calendar): jump to the day picked in the mini calendar
Since the freely scrolling views (#759) the day, week and month views are
positioned by their own focus rather than by the selected date, and a grid
click deliberately only marks a day that is already on screen. The mini
calendar shared that handler, so picking a day there highlighted it but
left the view where it was. Give it its own handler that jumps to the day
(keeping the mobile month-to-day switch), the same path the prev/next/today
controls and deep links use.
2026-09-15 12:44:36 +02:00
dealerweb bc5302568d fix(calendar): wait for the JMAP client before loading the account principal
The calendar loads the principal's alias addresses so an alias-organised
event is recognised as the user's own. The fetch fired on mount, but after
a page load the JMAP client is restored asynchronously: the call failed
with "Not authenticated" in the console, and the once-only guard then
blocked the retry for the rest of the session, leaving the aliases empty.

Move the logic into useAccountPrincipalEmails, which waits for the client
and fetches once, and cover the sequence with a hook test.
2026-09-15 12:44:36 +02:00
Linus Rath ae403b06af feat: setting to turn off free scrolling in the calendar 2026-09-09 18:27:01 +02:00
Linus Rath 15a5497a12 feat: freely scrolling month, week and day views #759 2026-09-09 16:38:55 +02:00
Linus Rath 60e05c0041 feat: infinite scroll for the calendar agenda view 2026-09-09 15:19:53 +02:00
Linus Rath f349500546 fix: preserve task alarms that the edit dialog does not show #504 2026-09-07 22:34:47 +02:00
Linus Rath d28d8dcd86 fix: report calendar clear failures instead of counting zero #434 2026-09-07 22:34:47 +02:00
Linus Rath 07bbde4786 fix: make the iCal subscription size limit configurable and show the real error #692 2026-09-07 22:34:47 +02:00
ibayueandClaude 8cbc5bc539 fix(calendar): dedupe participants, resolve contact names, show organizer status
Three bugs when viewing an event's participants (#738):

1. Phantom participant. Stalwart can emit the organizer both as the
   ORGANIZER-derived participant and as an ATTENDEE line, so the same
   address rendered twice — "4 participants" for three people.
   getParticipantList() now folds same-address entries into the
   first-seen one (real RSVP beats needs-action on merge), and
   getParticipantCount() counts addresses so event-card and agenda
   badges agree.

2. Bare email for a known contact. The organizer's display name is
   dropped on Stalwart's iCalendar round-trip, so the organizer
   rendered as a bare address despite having a contact card with a
   备注 name. New useContactNameResolver() hook fills missing
   participant names from the contact store (fill-only — event data
   stays authoritative), threaded through the panel, the hover
   popover, the RSVP view, and the organizer name written on save.

3. Organizer status. The organizer with no explicit status read as
   待处理; they owe no reply, so they now display as accepted, and the
   panel's status badge no longer repeats the organizer label the
   (组织者) suffix already carries.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-09-07 16:48:26 +08:00
lucletoffeandClaude Opus 5 208f632ca3 fix(calendar): linkify URLs in the event description
A meeting invitation puts the join URL in the description - Teams, Meet,
Zoom and the plain iTIP fallbacks all do - and the three read-only
description renders (invitation RSVP view, event detail view, detail
popover) printed it as bare text. The one actionable thing in the event
was not clickable: you had to select the URL by hand, across the line
wraps, and paste it into the address bar.

Render those three through the same pipeline the plain-text mail body
already uses (`plainTextToSafeHtml` + `sanitizePlainTextRenderedHtml`),
wrapped in a small `LinkifiedText` component. The text stays plain text:
it is escaped, only `<a href="http(s)://...">` is emitted, and the result
is sanitized again before it reaches the DOM - an event description is
attacker-controlled, since anyone can send an iTIP invitation.

Two details along the way: `break-words` on the paragraphs, so a long
join URL wraps instead of widening the panel, and `whitespace-pre-line`
on the invitation view, which was the only one of the three dropping the
description's own line breaks.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QPPAw4SK4M9Z7euVPM2cL
2026-09-04 09:35:50 +02:00
wrycu 3a3ebc9155 fix: rsvp controls
* adds "canRSVP" in addition to the existing "getEventEditability"
* wires calendar to leverage "canRSVP" before editability checks
* adds tests for RSVP
2026-09-03 22:12:15 -07:00
Linus Rath 1d8e4b9d8a fix: duplicate calendar-app import and type errors the stale tsbuildinfo hid 2026-09-01 21:08:10 +02:00
Linus Rath 0c7437f67a feat: open global search hits through the owning login on every surface #847 2026-09-01 20:55:13 +02:00
Linus Rath 14cdb2f6ff feat: organize invitations as the default ParticipantIdentity 2026-08-29 18:07:47 +02:00
Linus Rath e8c594001d feat: show attendee free/busy via Principal/getAvailability 2026-08-29 18:03:26 +02:00
Linus Rath d800689924 feat: use Stalwart synthetic ids for recurring occurrences #140 2026-08-29 11:03:48 +02:00
Stefan Hildebrandt ced81835ef fix(calendar): drop default SKIP=OMIT from recurrence rules (DAVx5 sync)
Recurring events defaulted skip:"omit"+rscale:"gregorian" on every rule,
which Stalwart serialises into the CalDAV RRULE as RSCALE=GREGORIAN;SKIP=OMIT.
DAVx5 rejects that ("Invalid recurrence rule"), breaking Android sync. Those
RFC 7529 fields only matter for non-Gregorian scales / invalid-date handling,
so stop emitting them for plain Gregorian rules.

- lib/recurrence-rule.ts: createRecurrenceRule() helper with no skip/rscale.
- CalendarRecurrenceRule.rscale/skip are now optional.
- event-modal + recurrence-editor build rules via the helper.
- demo fixture cleaned; unit test asserts no skip/rscale.

Closes #805.
2026-08-25 21:13:34 +02:00
Linus Rath 819d3c78cc Merge pull request #898 from French-Asgeir/feature/event-toolbar-overflow
fix: event toolbar overflow in edit mode
2026-08-25 20:22:17 +02:00
French-AsgeirandCopilot Autofix powered by AI 7046f2d557 fix: fix save and cancel button being unavailable when event is created
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-08-25 20:20:29 +02:00
Linus Rath 9f32fc879b feat: add custom time zone setting overriding browser detection #755 2026-08-25 19:18:16 +02:00
Linus Rath 46ccd2267d fix: pin supported-calendar-component-set on created calendars #760 2026-08-25 19:16:20 +02:00
French-Asgeir e59b975464 fix: event toolbar overflow in edit mode 2026-08-24 02:57:25 +02:00
Linus Rath 7e9aeaf0d4 fix: calendar click/double-click created events near current time instead of the clicked slot 2026-08-21 18:04:33 +02:00
Linus Rath 65e70a8088 feat: address bar reflects the focused Pro tab + live deep-link delivery to mounted surfaces 2026-08-20 15:35:41 +02:00
Linus Rath 66be55f6a7 feat: show a pull-to-refresh indicator when dragging down #826 2026-08-16 22:50:51 +02:00
Linus Rath fc0ab57247 Merge pull request #835 from hildebrandttk/fix/hide-tasks-only-calendars
fix(calendar): hide tasks-only calendars from the event calendar UI
2026-08-16 21:59:36 +02:00
Stefan Hildebrandt b5e71e7b84 fix(calendar): edit a single recurring occurrence via a one-shot override patch
The "This event only" edit path built nested JMAP patch pointers
(recurrenceOverrides/<recurrenceId>/<field>). On the first edit of an
occurrence the override object doesn't exist yet, and JMAP pointers can't
create a missing intermediate object, so Stalwart returned notUpdated and
the edit failed with two error toasts.

Build the override as a single pointer recurrenceOverrides/<recurrenceId>
whose value is the occurrence's field set (dropping identity/series keys),
mirroring the working "delete this occurrence" path. Extracted as the pure,
tested helper buildRecurrenceOverridePatch.

Closes #774.
2026-08-16 21:24:52 +02:00
Stefan Hildebrandt 9c084d9d63 fix(calendar): hide tasks-only calendars from the event calendar UI
A calendar holding only tasks (VTODO, e.g. from tasks.org) appeared in the
event calendar UI as an empty calendar. Stalwart's Calendar/get exposes no
supported-component set, so tasks-only-ness is derived from the calendar's
objects (mirroring the existing event/task split): a calendar is tasks-only
iff it holds >=1 object and every object is a task.

- getTasksOnlyCalendarIds scans an account's objects (CalendarEvent/query +
  minimal /get), early-exits once every calendar has an event, only marks
  after a full scan, and fails open on the cap or any error.
- getAllCalendars/getCalendars annotate calendars with isTasksOnly.
- Such calendars stay in the store for the tasks view (task picker, task-list
  grouping) but are filtered from the event sidebar and default selection.

Verified against Stalwart v0.16.16: the tasks-only calendar is flagged, the
default (with an event) is not.

Closes #761.
2026-08-16 21:18:57 +02:00
Linus Rath 47cf0ed90d feat: rework pro split-screen shell, per-pane tab strips, drag & drop, pane-scoped overlays 2026-08-16 03:03:40 +02:00