fix: add calendarAddress and replyTo to calendar participants for Stalwart compatibility #189 #192

This commit is contained in:
Linus Rath
2026-04-14 14:26:28 +02:00
parent 6678501501
commit 168b36d419
4 changed files with 52 additions and 3 deletions
+10
View File
@@ -112,6 +112,16 @@ export default function CalendarPage() {
// Swipe navigation ref (handlers defined after navigatePrev/navigateNext) // Swipe navigation ref (handlers defined after navigatePrev/navigateNext)
const touchStartRef = useRef<{ x: number; y: number; time: number } | null>(null); const touchStartRef = useRef<{ x: number; y: number; time: number } | null>(null);
// Keep detailEvent in sync with store events (e.g. after update + refetch)
useEffect(() => {
if (detailEvent) {
const updated = events.find(e => e.id === detailEvent.id);
if (updated && updated !== detailEvent) {
setDetailEvent(updated);
}
}
}, [events, detailEvent]);
// Check auth on mount // Check auth on mount
useEffect(() => { useEffect(() => {
checkAuth().finally(() => { checkAuth().finally(() => {
+2
View File
@@ -380,8 +380,10 @@ export function EventModal({
{ name: organizerName, email: organizerEmail }, { name: organizerName, email: organizerEmail },
attendees attendees
) as Record<string, CalendarParticipant>; ) as Record<string, CalendarParticipant>;
data.replyTo = { imip: `mailto:${organizerEmail}` };
} else if (attendees.length === 0 && event?.participants) { } else if (attendees.length === 0 && event?.participants) {
data.participants = null; data.participants = null;
data.replyTo = null;
} }
const shouldSendScheduling = attendees.length > 0 && sendInvitations; const shouldSendScheduling = attendees.length > 0 && sendInvitations;
+2
View File
@@ -111,6 +111,7 @@ export function buildParticipantMap(
'@type': 'Participant', '@type': 'Participant',
name: organizer.name, name: organizer.name,
email: organizer.email, email: organizer.email,
calendarAddress: `mailto:${organizer.email}`,
roles: { owner: true, attendee: true }, roles: { owner: true, attendee: true },
participationStatus: 'accepted', participationStatus: 'accepted',
scheduleAgent: 'server', scheduleAgent: 'server',
@@ -124,6 +125,7 @@ export function buildParticipantMap(
'@type': 'Participant', '@type': 'Participant',
name: a.name, name: a.name,
email: a.email, email: a.email,
calendarAddress: `mailto:${a.email}`,
roles: { attendee: true }, roles: { attendee: true },
participationStatus: 'needs-action', participationStatus: 'needs-action',
scheduleAgent: 'server', scheduleAgent: 'server',
+38 -3
View File
@@ -3462,9 +3462,24 @@ export class JMAPClient implements IJMAPClient {
} }
} }
return allEvents const filtered = allEvents
.filter((event) => !isTaskObject(event)) .filter((event) => !isTaskObject(event))
.map((event) => normalizeCalendarEventLike(event)); .map((event) => normalizeCalendarEventLike(event));
const eventsWithParticipants = filtered.filter(e => e.participants && Object.keys(e.participants).length > 0);
debug.log('calendar', 'queryCalendarEvents participant summary', {
totalEvents: filtered.length,
eventsWithParticipants: eventsWithParticipants.length,
details: eventsWithParticipants.map(e => ({
id: e.id,
title: e.title,
participantCount: Object.keys(e.participants!).length,
participants: e.participants,
replyTo: e.replyTo,
})),
});
return filtered;
} catch (error) { } catch (error) {
console.error('Failed to query calendar events:', error); console.error('Failed to query calendar events:', error);
return []; return [];
@@ -3505,6 +3520,10 @@ export class JMAPClient implements IJMAPClient {
accountId, accountId,
sendSchedulingMessages, sendSchedulingMessages,
eventKeys: Object.keys(cleanEvent), eventKeys: Object.keys(cleanEvent),
hasParticipants: !!cleanEvent.participants,
participantCount: cleanEvent.participants ? Object.keys(cleanEvent.participants).length : 0,
participants: cleanEvent.participants || null,
replyTo: cleanEvent.replyTo || null,
}); });
const setArgs: Record<string, unknown> = { const setArgs: Record<string, unknown> = {
@@ -3543,7 +3562,13 @@ export class JMAPClient implements IJMAPClient {
if (createdId) { if (createdId) {
const created = await this.getCalendarEvent(createdId, targetAccountId); const created = await this.getCalendarEvent(createdId, targetAccountId);
debug.log('calendar', 'CalendarEvent/create fetched created event', getCalendarEventDebugSnapshot(created)); debug.log('calendar', 'CalendarEvent/create fetched created event', {
...getCalendarEventDebugSnapshot(created),
hasParticipants: !!created?.participants,
participantCount: created?.participants ? Object.keys(created.participants).length : 0,
participants: created?.participants || null,
replyTo: created?.replyTo || null,
});
if (created?.uid) { if (created?.uid) {
try { try {
@@ -3666,7 +3691,16 @@ export class JMAPClient implements IJMAPClient {
setArgs.sendSchedulingMessages = sendSchedulingMessages; setArgs.sendSchedulingMessages = sendSchedulingMessages;
} }
debug.log('calendar', 'CalendarEvent/set update request', { eventId, accountId, cleanUpdateKeys: Object.keys(cleanUpdates), sendSchedulingMessages }); debug.log('calendar', 'CalendarEvent/set update request', {
eventId,
accountId,
cleanUpdateKeys: Object.keys(cleanUpdates),
sendSchedulingMessages,
hasParticipants: !!cleanUpdates.participants,
participantCount: cleanUpdates.participants ? Object.keys(cleanUpdates.participants).length : 0,
participants: cleanUpdates.participants || null,
replyTo: (cleanUpdates as Record<string, unknown>).replyTo || null,
});
const response = await this.request([ const response = await this.request([
["CalendarEvent/set", setArgs, "0"] ["CalendarEvent/set", setArgs, "0"]
@@ -3688,6 +3722,7 @@ export class JMAPClient implements IJMAPClient {
debug.error('CalendarEvent/set notUpdated', { eventId, error }); debug.error('CalendarEvent/set notUpdated', { eventId, error });
throw new Error(error.description || "Failed to update calendar event"); throw new Error(error.description || "Failed to update calendar event");
} }
debug.log('calendar', 'CalendarEvent/set update full response', { methodName, result });
debug.log('calendar', 'CalendarEvent/set update success', { eventId, updated: result.updated ? Object.keys(result.updated) : null }); debug.log('calendar', 'CalendarEvent/set update success', { eventId, updated: result.updated ? Object.keys(result.updated) : null });
return; return;
} }