feat(calendar): expose loss-safe bulk move modes
This commit is contained in:
@@ -46,6 +46,7 @@ import {
|
||||
type CalendarCalDavDiscoveryCandidate,
|
||||
type CalendarCalDavDiscoveryPayload,
|
||||
type CalendarCalDavSyncDirection,
|
||||
type CalendarBulkMoveExternalAction,
|
||||
type CalendarCollection,
|
||||
type CalendarCollectionDeletePayload,
|
||||
type CalendarDeleteEventAction,
|
||||
@@ -897,6 +898,7 @@ export default function CalendarPage({ settings, auth }: {settings: ApiSettings;
|
||||
<CalendarCollectionDeleteDialog
|
||||
state={calendarDeleteDialog}
|
||||
calendars={calendars}
|
||||
syncSources={syncSources}
|
||||
saving={saving}
|
||||
onCancel={() => setCalendarDeleteDialog(null)}
|
||||
onDelete={handleCalendarDelete} />
|
||||
@@ -1713,6 +1715,7 @@ function CalendarCollectionDialog({
|
||||
function CalendarCollectionDeleteDialog({
|
||||
state,
|
||||
calendars,
|
||||
syncSources,
|
||||
saving,
|
||||
onCancel,
|
||||
onDelete
|
||||
@@ -1722,9 +1725,13 @@ function CalendarCollectionDeleteDialog({
|
||||
|
||||
|
||||
|
||||
}: {state: CalendarDeleteDialogState;calendars: CalendarCollection[];saving: boolean;onCancel: () => void;onDelete: (calendar: CalendarCollection, payload: CalendarCollectionDeletePayload) => Promise<void>;}) {
|
||||
}: {state: CalendarDeleteDialogState;calendars: CalendarCollection[];syncSources: CalendarSyncSource[];saving: boolean;onCancel: () => void;onDelete: (calendar: CalendarCollection, payload: CalendarCollectionDeletePayload) => Promise<void>;}) {
|
||||
const { calendar, eventCount, loadingEventCount } = state;
|
||||
const moveTargets = calendars.filter((item) => item.id !== calendar.id);
|
||||
const syncSourceByCalendarId = new Map(syncSources.map((source) => [source.calendar_id, source]));
|
||||
const source = syncSourceByCalendarId.get(calendar.id) ?? null;
|
||||
const moveTargets = calendars.filter((item) =>
|
||||
item.id !== calendar.id && calendarMoveTargetIsSupported(source, syncSourceByCalendarId.get(item.id) ?? null)
|
||||
);
|
||||
const firstMoveTargetId = moveTargets[0]?.id || "";
|
||||
const hasEvents = (eventCount ?? 0) > 0;
|
||||
const canMoveEvents = hasEvents && moveTargets.length > 0;
|
||||
@@ -1734,12 +1741,15 @@ function CalendarCollectionDeleteDialog({
|
||||
const effectiveEventAction: CalendarDeleteEventAction = canMoveEvents ? eventAction : "delete";
|
||||
const confirmDisabled = saving || loadingEventCount || canMoveEvents && effectiveEventAction === "move" && !targetCalendarId;
|
||||
const actionLabel = calendarDeleteActionLabel(calendar);
|
||||
const targetSource = syncSourceByCalendarId.get(targetCalendarId) ?? null;
|
||||
const externalAction = calendarBulkMoveExternalAction(source, targetSource);
|
||||
|
||||
function confirm() {
|
||||
void onDelete(calendar, {
|
||||
event_action: effectiveEventAction,
|
||||
target_calendar_id: effectiveEventAction === "move" ? targetCalendarId : null,
|
||||
make_target_default: effectiveEventAction === "move" && calendar.is_default && makeTargetDefault
|
||||
make_target_default: effectiveEventAction === "move" && calendar.is_default && makeTargetDefault,
|
||||
external_action: effectiveEventAction === "move" ? externalAction : null
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1789,7 +1799,7 @@ function CalendarCollectionDeleteDialog({
|
||||
checked={eventAction === "move"}
|
||||
onChange={() => setEventAction("move")} />
|
||||
|
||||
<span>i18n:govoplan-calendar.move_events_to_another_calendar.830c7b09</span>
|
||||
<span>{calendarBulkMoveOptionLabel(externalAction)}</span>
|
||||
</label>
|
||||
{eventAction === "move" &&
|
||||
<>
|
||||
@@ -1807,10 +1817,16 @@ function CalendarCollectionDeleteDialog({
|
||||
<span>i18n:govoplan-calendar.make_target_calendar_the_default.10a3977b</span>
|
||||
</label>
|
||||
}
|
||||
<p className="calendar-form-note">{calendarBulkMoveConsequence(externalAction)}</p>
|
||||
</>
|
||||
}
|
||||
</fieldset>
|
||||
}
|
||||
{!loadingEventCount && hasEvents && moveTargets.length === 0 &&
|
||||
<p className="calendar-form-note">{source ?
|
||||
"i18n:govoplan-calendar.no_local_target_calendar_is_available_add_a_local_.fad3cb65" :
|
||||
"i18n:govoplan-calendar.no_compatible_target_calendar_is_available_add_a_l.1cf6e47b"}</p>
|
||||
}
|
||||
</div>
|
||||
</Dialog>);
|
||||
|
||||
@@ -2473,6 +2489,39 @@ function calendarEventDeleteOptionLabel(calendar: CalendarCollection): string {
|
||||
return calendarIsExternal(calendar) ? "i18n:govoplan-calendar.remove_local_events_with_this_calendar.fb8831e1" : "i18n:govoplan-calendar.delete_events_with_this_calendar.cc0e1287";
|
||||
}
|
||||
|
||||
function calendarMoveTargetIsSupported(
|
||||
source: CalendarSyncSource | null,
|
||||
targetSource: CalendarSyncSource | null)
|
||||
: boolean {
|
||||
if (source) return targetSource === null;
|
||||
return targetSource === null || calendarSyncSourceAcceptsCopies(targetSource);
|
||||
}
|
||||
|
||||
function calendarSyncSourceAcceptsCopies(source: CalendarSyncSource): boolean {
|
||||
return source.source_kind === "caldav" && source.sync_enabled && source.sync_direction === "two_way";
|
||||
}
|
||||
|
||||
function calendarBulkMoveExternalAction(
|
||||
source: CalendarSyncSource | null,
|
||||
targetSource: CalendarSyncSource | null)
|
||||
: CalendarBulkMoveExternalAction | undefined {
|
||||
if (source && !targetSource) return "detach_keep_remote";
|
||||
if (!source && targetSource && calendarSyncSourceAcceptsCopies(targetSource)) return "copy_to_remote";
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function calendarBulkMoveOptionLabel(action: CalendarBulkMoveExternalAction | undefined): string {
|
||||
if (action === "detach_keep_remote") return "i18n:govoplan-calendar.detach_local_events_and_keep_remote_events.c58ad4e7";
|
||||
if (action === "copy_to_remote") return "i18n:govoplan-calendar.move_and_copy_events_to_the_external_calendar.23c3a004";
|
||||
return "i18n:govoplan-calendar.move_events_to_another_calendar.830c7b09";
|
||||
}
|
||||
|
||||
function calendarBulkMoveConsequence(action: CalendarBulkMoveExternalAction | undefined): string {
|
||||
if (action === "detach_keep_remote") return "i18n:govoplan-calendar.govoplan_moves_the_local_event_copies_to_the_targe.4863e46b";
|
||||
if (action === "copy_to_remote") return "i18n:govoplan-calendar.govoplan_moves_the_events_locally_and_queues_durab.da075b16";
|
||||
return "i18n:govoplan-calendar.events_remain_in_govoplan_no_external_calendar_is_.62cb5937";
|
||||
}
|
||||
|
||||
function calendarDeleteWarning(
|
||||
calendar: CalendarCollection,
|
||||
eventCount: number,
|
||||
|
||||
Reference in New Issue
Block a user