Implement destructive CalDAV move saga

This commit is contained in:
2026-08-02 17:30:24 +02:00
parent 56d7b2108d
commit a125b666da
16 changed files with 2384 additions and 36 deletions
+74
View File
@@ -220,6 +220,49 @@ export type CalendarOutboxOperationListResponse = {
operations: CalendarOutboxOperation[];
};
export type CalendarMigrationResource = {
id: string;
source_href: string;
destination_href: string;
event_ids: string[];
status: string;
destination_operation_id?: string | null;
destination_operation_status?: string | null;
source_delete_operation_id?: string | null;
source_delete_operation_status?: string | null;
last_error?: string | null;
};
export type CalendarMigrationBatch = {
id: string;
migration_kind: string;
status: string;
phase: string;
source_calendar_id: string;
target_calendar_id: string;
source_sync_source_id: string;
target_sync_source_id: string;
total_resources: number;
copied_resources: number;
deleted_source_resources: number;
conflict_count: number;
total_events: number;
last_error?: string | null;
can_cancel: boolean;
authorization_evidence: Record<string, unknown>;
cancellation_evidence?: Record<string, unknown> | null;
created_by_user_id?: string | null;
created_by_api_key_id?: string | null;
created_at: string;
updated_at: string;
completed_at?: string | null;
resources: CalendarMigrationResource[];
};
export type CalendarMigrationBatchListResponse = {
migrations: CalendarMigrationBatch[];
};
export type CalendarCollectionCreatePayload = {
name: string;
slug?: string | null;
@@ -241,6 +284,8 @@ export type CalendarCollectionDeletePayload = {
target_calendar_id?: string | null;
make_target_default?: boolean;
external_action?: CalendarBulkMoveExternalAction | null;
destructive_confirmation?: string | null;
evidence_note?: string | null;
};
export type CalendarEventCreatePayload = {
@@ -396,6 +441,35 @@ export function recoverCalendarOutboxOperation(
});
}
export function listCalendarMigrations(
settings: ApiSettings,
params: { calendar_id?: string; limit?: number } = {},
): Promise<CalendarMigrationBatchListResponse> {
const search = new URLSearchParams();
if (params.calendar_id) search.set("calendar_id", params.calendar_id);
if (params.limit) search.set("limit", String(params.limit));
const suffix = search.toString() ? `?${search.toString()}` : "";
return apiFetch<CalendarMigrationBatchListResponse>(settings, `/api/v1/calendar/migrations${suffix}`);
}
export function getCalendarMigration(
settings: ApiSettings,
batchId: string,
): Promise<CalendarMigrationBatch> {
return apiFetch<CalendarMigrationBatch>(settings, `/api/v1/calendar/migrations/${batchId}`);
}
export function cancelCalendarMigration(
settings: ApiSettings,
batchId: string,
evidenceNote: string,
): Promise<CalendarMigrationBatch> {
return apiFetch<CalendarMigrationBatch>(settings, `/api/v1/calendar/migrations/${batchId}/cancel`, {
method: "POST",
body: JSON.stringify({ evidence_note: evidenceNote }),
});
}
export function listCalendarEvents(
settings: ApiSettings,
params: { calendar_id?: string; start_at?: string; end_at?: string; expand_recurring?: boolean } = {}