Update a re-imported event rather than skipping it
Contacts and calendars disagreed on a re-import: a vCard or LDIF entry whose identity a book already held overwrote the card there (#242, #274), while an event whose UID a calendar held was counted and thrown away (#222). The asymmetry was never decided -- it was where each half stopped. Decided on #279: calendars update too, with two properties held back. `participants` carries every attendee's accepted/declined and `recurrenceOverrides` holds every "just this Wednesday" edit made here. Both are decisions taken after the file was written, and a file that mentions them at all describes them as they were at export, so writing either one over would destroy work silently and return no error. A corrected export now fixes the time, the title and the location, and leaves who said yes alone. `uid` is held back with them: it is what the two were matched on, so it is already equal. The scan returns uid -> id rather than a set of UIDs, since updating needs something to address, and creates and updates now share one `maxObjectsInSet` budget the way contacts' `writeCards` does -- 300 new and 300 changed batched separately would be two calls of 300, neither over a ceiling of 500 and both refused. Counts become created/updated, reported as the contacts import reports them. Still no scheduling messages, on an update as much as on a create. That is a real cost -- an event a re-import moves is moved here and nowhere else -- and it is the lesser one: an import is not the place to start mailing a room full of people who never asked for it. Driven against the mock end to end: a second file with the same UID updated the event in place, took the file's title, start and location, and left an accepted RSVP and a per-occurrence override untouched even though the file carried participants of its own.
This commit is contained in:
@@ -65,16 +65,19 @@ export function CalendarSidebar() {
|
||||
const calendarId = importInto.current;
|
||||
if (!calendarId) return;
|
||||
try {
|
||||
const { created, skipped } = await cal.importIcs(await file.text(), calendarId);
|
||||
const { created, updated } = await cal.importIcs(await file.text(), calendarId);
|
||||
/*
|
||||
* The two counts are kept apart on purpose. "Imported 40 events" over a
|
||||
* file of 240 reads as a failure when 200 of them were simply already
|
||||
* here, and a re-import where everything is already here would otherwise
|
||||
* report importing nothing at all.
|
||||
* The two counts are kept apart on purpose, the way the contacts import
|
||||
* keeps them. "Imported 40 events" over a file of 240 reads as a failure
|
||||
* when the other 200 were updated, and a re-import of a corrected export
|
||||
* -- the reason for doing this at all -- creates nothing and would
|
||||
* otherwise report importing nothing at all.
|
||||
*/
|
||||
if (!created) toast.success(plural(skipped, { one: "Already here: {n} event, nothing imported", other: "Already here: {n} events, nothing imported" }));
|
||||
else if (skipped) toast.success(`${plural(created, { one: "Imported {n} event", other: "Imported {n} events" })} · ${plural(skipped, { one: "{n} was already here", other: "{n} were already here" })}`);
|
||||
else toast.success(plural(created, { one: "Imported {n} event", other: "Imported {n} events" }));
|
||||
const imported = plural(created, { one: "Imported {n} event", other: "Imported {n} events" });
|
||||
const refreshed = plural(updated, { one: "{n} updated", other: "{n} updated" });
|
||||
if (!created) toast.success(plural(updated, { one: "Updated {n} event, nothing new", other: "Updated {n} events, nothing new" }));
|
||||
else if (updated) toast.success(`${imported} · ${refreshed}`);
|
||||
else toast.success(imported);
|
||||
} catch (err) {
|
||||
toast.error(t("Could not import this file: {error}", { error: (err as Error).message }));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user