From 65443a235a9a75db642d79ef51802049292d5e4a Mon Sep 17 00:00:00 2001 From: John Ellis Date: Tue, 25 Aug 2026 08:12:06 -0700 Subject: [PATCH] Ask only the recurrence rules, the live server settles it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A probe against the live 0.16.19 says a one-off event comes back from an expanded query as id "eaaaaai" with baseEventId "i" — an instance id of its own, and a base that is a different event. The clause that treated a differing base as an occurrence of a series would therefore have gone on calling every event recurring, which was the bug. So recurrence rules alone decide it. What that gives up is an expanded instance that arrives without its rules attached; whether Stalwart does that is still to be checked against a real series. --- web/src/store/__tests__/recurrence.test.ts | 6 +++--- web/src/store/calendar.ts | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/web/src/store/__tests__/recurrence.test.ts b/web/src/store/__tests__/recurrence.test.ts index d48a955..f6e0ae2 100644 --- a/web/src/store/__tests__/recurrence.test.ts +++ b/web/src/store/__tests__/recurrence.test.ts @@ -15,9 +15,9 @@ describe("isRecurring", () => { it("does not call a one-off event a series just because it has a baseEventId", () => { expect(isRecurring(ev({ baseEventId: "ev1" }))).toBe(false); expect(isRecurring(ev({}))).toBe(false); - }); - it("still recognises an occurrence whose base is another event", () => { - expect(isRecurring(ev({ id: "ev1_2", baseEventId: "ev1" }))).toBe(true); + // The shape a live 0.16.19 returns for a one-off: an instance id of its own, + // and a base that is a different id. Neither makes it a series. + expect(isRecurring(ev({ id: "eaaaaai", baseEventId: "i" }))).toBe(false); }); it("recognises a series by its recurrence rules", () => { expect(isRecurring(ev({ recurrenceRules: [{ "@type": "RecurrenceRule", frequency: "weekly" }] }))).toBe(true); diff --git a/web/src/store/calendar.ts b/web/src/store/calendar.ts index d74967b..04d2b8f 100644 --- a/web/src/store/calendar.ts +++ b/web/src/store/calendar.ts @@ -300,15 +300,15 @@ export const useCalendar = create((set, get) => ({ /** * Whether an event is part of a series. * - * Not the same question as "does it have a baseEventId": `CalendarEvent/query` - * runs with `expandRecurrences`, and Stalwart sets `baseEventId` on every event - * it returns that way — a one-off event included, pointing at itself. Recurrence - * rules are what make a series, so those are the question; a base that is some - * *other* event means this is one occurrence of one, whether or not the expanded - * instance carried the rules along with it. + * Not the same question as "does it have a baseEventId", nor "is that base some + * other event". `CalendarEvent/query` runs with `expandRecurrences`, and Stalwart + * hands back an instance id for everything it returns that way — a one-off event + * included, whose own id (`eaaaaai`) differs from its base (`i`), verified + * against a live 0.16.19. Recurrence rules are what make a series, so those are + * what we ask about. */ export function isRecurring(ev: CalendarEvent): boolean { - return Boolean(ev.recurrenceRules?.length || ev.excludedRecurrenceRules?.length || (ev.baseEventId && ev.baseEventId !== ev.id)); + return Boolean(ev.recurrenceRules?.length || ev.excludedRecurrenceRules?.length); } export function toInstance(e: CalendarEvent, calendars: Record): EventInstance | null {