Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions apps/desktop/src/calendar/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,37 @@ export function findCalendarByTrackingId(

return foundRowId;
}

export function findLegacyCalendarByTrackingId(
store: Store<Schemas>,
{
provider,
trackingId,
source,
}: {
provider: string;
trackingId: string;
source?: string;
},
): string | null {
if (!source) {
return null;
}

let foundRowId: string | null = null;

store.forEachRow("calendars", (rowId, _forEachCell) => {
if (foundRowId) return;
const row = store.getRow("calendars", rowId);
if (
row?.provider === provider &&
!row?.connection_id &&
row?.tracking_id_calendar === trackingId &&
row?.source === source
) {
foundRowId = rowId;
}
});

return foundRowId;
}
47 changes: 47 additions & 0 deletions apps/desktop/src/services/calendar/ctx.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,51 @@ describe("syncCalendars", () => {
name: "Personal",
});
});

test("preserves enabled state for legacy Google calendars without connection ids", async () => {
const store = createStore();

store.setRow("calendars", "legacy-row", {
user_id: "user-1",
created_at: "2026-03-25T00:00:00.000Z",
tracking_id_calendar: "primary",
name: "John (Hyprnote)",
enabled: true,
provider: "google",
source: "john@hyprnote.com",
color: "#4285f4",
connection_id: "",
});

pluginCalendar.listCalendars.mockResolvedValue({
status: "success",
data: [
{
id: "primary",
title: "John (Hyprnote)",
source: "john@hyprnote.com",
color: "#4285f4",
},
],
});

await syncCalendars(store, [
{
provider: "google",
connection_ids: ["conn-john"],
},
]);

const calendars = getCalendarsByConnection(store, "google");

expect(calendars).toHaveLength(1);
expect(calendars[0]).toMatchObject({
id: "legacy-row",
tracking_id_calendar: "primary",
name: "John (Hyprnote)",
enabled: true,
source: "john@hyprnote.com",
connection_id: "conn-john",
});
});
});
52 changes: 39 additions & 13 deletions apps/desktop/src/services/calendar/ctx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {

import {
findCalendarByTrackingId,
findLegacyCalendarByTrackingId,
getCalendarTrackingKey,
} from "~/calendar/utils";
import { QUERIES, type Schemas, type Store } from "~/store/tinybase/store/main";
Expand Down Expand Up @@ -127,19 +128,38 @@ export async function syncCalendars(

store.transaction(() => {
const disabledCalendarIds = new Set<string>();
const legacyMatchedRowIds = new Set<string>();

for (const { calendars } of perConnection) {
for (const cal of calendars) {
const legacyRowId = findLegacyCalendarByTrackingId(store, {
provider,
trackingId: cal.id,
source: cal.source ?? undefined,
});

if (legacyRowId) {
legacyMatchedRowIds.add(legacyRowId);
}
}
}

for (const rowId of store.getRowIds("calendars")) {
const row = store.getRow("calendars", rowId);
if (
row.provider === provider &&
!incomingKeys.has(
getCalendarTrackingKey({
provider: row.provider as string | undefined,
connectionId: row.connection_id as string | undefined,
trackingId: row.tracking_id_calendar as string | undefined,
}),
)
legacyMatchedRowIds.has(rowId) ||
(row.provider === provider &&
!incomingKeys.has(
getCalendarTrackingKey({
provider: row.provider as string | undefined,
connectionId: row.connection_id as string | undefined,
trackingId: row.tracking_id_calendar as string | undefined,
}),
))
) {
if (legacyMatchedRowIds.has(rowId)) {
continue;
}
disabledCalendarIds.add(rowId);
store.delRow("calendars", rowId);
} else if (row.provider === provider && !row.enabled) {
Expand All @@ -158,11 +178,17 @@ export async function syncCalendars(

for (const { connectionId, calendars } of perConnection) {
for (const cal of calendars) {
const existingRowId = findCalendarByTrackingId(store, {
provider,
connectionId,
trackingId: cal.id,
});
const existingRowId =
findCalendarByTrackingId(store, {
provider,
connectionId,
trackingId: cal.id,
}) ??
findLegacyCalendarByTrackingId(store, {
provider,
trackingId: cal.id,
source: cal.source ?? undefined,
});
const rowId = existingRowId ?? crypto.randomUUID();
const existing = existingRowId
? store.getRow("calendars", existingRowId)
Expand Down
Loading