feat(calendar): expose loss-safe bulk move modes
This commit is contained in:
@@ -182,10 +182,12 @@ export type CalendarCollectionCreatePayload = {
|
|||||||
|
|
||||||
export type CalendarCollectionUpdatePayload = Partial<CalendarCollectionCreatePayload>;
|
export type CalendarCollectionUpdatePayload = Partial<CalendarCollectionCreatePayload>;
|
||||||
export type CalendarDeleteEventAction = "delete" | "move";
|
export type CalendarDeleteEventAction = "delete" | "move";
|
||||||
|
export type CalendarBulkMoveExternalAction = "detach_keep_remote" | "copy_to_remote" | "remote_move";
|
||||||
export type CalendarCollectionDeletePayload = {
|
export type CalendarCollectionDeletePayload = {
|
||||||
event_action?: CalendarDeleteEventAction;
|
event_action?: CalendarDeleteEventAction;
|
||||||
target_calendar_id?: string | null;
|
target_calendar_id?: string | null;
|
||||||
make_target_default?: boolean;
|
make_target_default?: boolean;
|
||||||
|
external_action?: CalendarBulkMoveExternalAction | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CalendarEventCreatePayload = {
|
export type CalendarEventCreatePayload = {
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import {
|
|||||||
type CalendarCalDavDiscoveryCandidate,
|
type CalendarCalDavDiscoveryCandidate,
|
||||||
type CalendarCalDavDiscoveryPayload,
|
type CalendarCalDavDiscoveryPayload,
|
||||||
type CalendarCalDavSyncDirection,
|
type CalendarCalDavSyncDirection,
|
||||||
|
type CalendarBulkMoveExternalAction,
|
||||||
type CalendarCollection,
|
type CalendarCollection,
|
||||||
type CalendarCollectionDeletePayload,
|
type CalendarCollectionDeletePayload,
|
||||||
type CalendarDeleteEventAction,
|
type CalendarDeleteEventAction,
|
||||||
@@ -897,6 +898,7 @@ export default function CalendarPage({ settings, auth }: {settings: ApiSettings;
|
|||||||
<CalendarCollectionDeleteDialog
|
<CalendarCollectionDeleteDialog
|
||||||
state={calendarDeleteDialog}
|
state={calendarDeleteDialog}
|
||||||
calendars={calendars}
|
calendars={calendars}
|
||||||
|
syncSources={syncSources}
|
||||||
saving={saving}
|
saving={saving}
|
||||||
onCancel={() => setCalendarDeleteDialog(null)}
|
onCancel={() => setCalendarDeleteDialog(null)}
|
||||||
onDelete={handleCalendarDelete} />
|
onDelete={handleCalendarDelete} />
|
||||||
@@ -1713,6 +1715,7 @@ function CalendarCollectionDialog({
|
|||||||
function CalendarCollectionDeleteDialog({
|
function CalendarCollectionDeleteDialog({
|
||||||
state,
|
state,
|
||||||
calendars,
|
calendars,
|
||||||
|
syncSources,
|
||||||
saving,
|
saving,
|
||||||
onCancel,
|
onCancel,
|
||||||
onDelete
|
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 { 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 firstMoveTargetId = moveTargets[0]?.id || "";
|
||||||
const hasEvents = (eventCount ?? 0) > 0;
|
const hasEvents = (eventCount ?? 0) > 0;
|
||||||
const canMoveEvents = hasEvents && moveTargets.length > 0;
|
const canMoveEvents = hasEvents && moveTargets.length > 0;
|
||||||
@@ -1734,12 +1741,15 @@ function CalendarCollectionDeleteDialog({
|
|||||||
const effectiveEventAction: CalendarDeleteEventAction = canMoveEvents ? eventAction : "delete";
|
const effectiveEventAction: CalendarDeleteEventAction = canMoveEvents ? eventAction : "delete";
|
||||||
const confirmDisabled = saving || loadingEventCount || canMoveEvents && effectiveEventAction === "move" && !targetCalendarId;
|
const confirmDisabled = saving || loadingEventCount || canMoveEvents && effectiveEventAction === "move" && !targetCalendarId;
|
||||||
const actionLabel = calendarDeleteActionLabel(calendar);
|
const actionLabel = calendarDeleteActionLabel(calendar);
|
||||||
|
const targetSource = syncSourceByCalendarId.get(targetCalendarId) ?? null;
|
||||||
|
const externalAction = calendarBulkMoveExternalAction(source, targetSource);
|
||||||
|
|
||||||
function confirm() {
|
function confirm() {
|
||||||
void onDelete(calendar, {
|
void onDelete(calendar, {
|
||||||
event_action: effectiveEventAction,
|
event_action: effectiveEventAction,
|
||||||
target_calendar_id: effectiveEventAction === "move" ? targetCalendarId : null,
|
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"}
|
checked={eventAction === "move"}
|
||||||
onChange={() => setEventAction("move")} />
|
onChange={() => setEventAction("move")} />
|
||||||
|
|
||||||
<span>i18n:govoplan-calendar.move_events_to_another_calendar.830c7b09</span>
|
<span>{calendarBulkMoveOptionLabel(externalAction)}</span>
|
||||||
</label>
|
</label>
|
||||||
{eventAction === "move" &&
|
{eventAction === "move" &&
|
||||||
<>
|
<>
|
||||||
@@ -1807,10 +1817,16 @@ function CalendarCollectionDeleteDialog({
|
|||||||
<span>i18n:govoplan-calendar.make_target_calendar_the_default.10a3977b</span>
|
<span>i18n:govoplan-calendar.make_target_calendar_the_default.10a3977b</span>
|
||||||
</label>
|
</label>
|
||||||
}
|
}
|
||||||
|
<p className="calendar-form-note">{calendarBulkMoveConsequence(externalAction)}</p>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
</fieldset>
|
</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>
|
</div>
|
||||||
</Dialog>);
|
</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";
|
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(
|
function calendarDeleteWarning(
|
||||||
calendar: CalendarCollection,
|
calendar: CalendarCollection,
|
||||||
eventCount: number,
|
eventCount: number,
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ export const generatedTranslations: PlatformTranslations = {
|
|||||||
"i18n:govoplan-calendar.delete.f6fdbe48": "Delete",
|
"i18n:govoplan-calendar.delete.f6fdbe48": "Delete",
|
||||||
"i18n:govoplan-calendar.deleting.2cda36c9": "Deleting",
|
"i18n:govoplan-calendar.deleting.2cda36c9": "Deleting",
|
||||||
"i18n:govoplan-calendar.description.55f8ebc8": "Description",
|
"i18n:govoplan-calendar.description.55f8ebc8": "Description",
|
||||||
|
"i18n:govoplan-calendar.detach_local_events_and_keep_remote_events.c58ad4e7": "Detach local events and keep remote events",
|
||||||
"i18n:govoplan-calendar.direction.fd8e45ba": "Direction",
|
"i18n:govoplan-calendar.direction.fd8e45ba": "Direction",
|
||||||
"i18n:govoplan-calendar.discover.4827ea22": "Discover",
|
"i18n:govoplan-calendar.discover.4827ea22": "Discover",
|
||||||
"i18n:govoplan-calendar.discovering.1884f689": "Discovering...",
|
"i18n:govoplan-calendar.discovering.1884f689": "Discovering...",
|
||||||
@@ -67,12 +68,15 @@ export const generatedTranslations: PlatformTranslations = {
|
|||||||
"i18n:govoplan-calendar.event_count_could_not_be_loaded_the_backend_will.163ff055": "Event count could not be loaded. The backend will still apply the selected delete action.",
|
"i18n:govoplan-calendar.event_count_could_not_be_loaded_the_backend_will.163ff055": "Event count could not be loaded. The backend will still apply the selected delete action.",
|
||||||
"i18n:govoplan-calendar.events": "events",
|
"i18n:govoplan-calendar.events": "events",
|
||||||
"i18n:govoplan-calendar.events_are_stored_in_govoplan_and_are_not_synced.3660e504": "Events are stored in GovOPlaN and are not synced to an external calendar source.",
|
"i18n:govoplan-calendar.events_are_stored_in_govoplan_and_are_not_synced.3660e504": "Events are stored in GovOPlaN and are not synced to an external calendar source.",
|
||||||
|
"i18n:govoplan-calendar.events_remain_in_govoplan_no_external_calendar_is_.62cb5937": "Events remain in GovOPlaN; no external calendar is changed.",
|
||||||
"i18n:govoplan-calendar.ews_endpoint.a3273983": "EWS endpoint",
|
"i18n:govoplan-calendar.ews_endpoint.a3273983": "EWS endpoint",
|
||||||
"i18n:govoplan-calendar.exchange_web_services_source.53caabf3": "Exchange Web Services source",
|
"i18n:govoplan-calendar.exchange_web_services_source.53caabf3": "Exchange Web Services source",
|
||||||
"i18n:govoplan-calendar.exchange.5b13eac7": "Exchange",
|
"i18n:govoplan-calendar.exchange.5b13eac7": "Exchange",
|
||||||
"i18n:govoplan-calendar.exdate_json.7d0c538d": "EXDATE JSON",
|
"i18n:govoplan-calendar.exdate_json.7d0c538d": "EXDATE JSON",
|
||||||
"i18n:govoplan-calendar.fri.bbd6e32e": "Fri",
|
"i18n:govoplan-calendar.fri.bbd6e32e": "Fri",
|
||||||
"i18n:govoplan-calendar.full_sync.21b89c76": "Full sync",
|
"i18n:govoplan-calendar.full_sync.21b89c76": "Full sync",
|
||||||
|
"i18n:govoplan-calendar.govoplan_moves_the_events_locally_and_queues_durab.da075b16": "GovOPlaN moves the events locally and queues durable CalDAV copies. Delivery failures remain visible and retryable.",
|
||||||
|
"i18n:govoplan-calendar.govoplan_moves_the_local_event_copies_to_the_targe.4863e46b": "GovOPlaN moves the local event copies to the target calendar and unlinks this source. The remote calendar and its events remain unchanged.",
|
||||||
"i18n:govoplan-calendar.graph_calendar_url.e59607f3": "Graph calendar URL",
|
"i18n:govoplan-calendar.graph_calendar_url.e59607f3": "Graph calendar URL",
|
||||||
"i18n:govoplan-calendar.graph.9a7405eb": "Graph",
|
"i18n:govoplan-calendar.graph.9a7405eb": "Graph",
|
||||||
"i18n:govoplan-calendar.icalendar_json.fb6cc33e": "iCalendar JSON",
|
"i18n:govoplan-calendar.icalendar_json.fb6cc33e": "iCalendar JSON",
|
||||||
@@ -96,6 +100,7 @@ export const generatedTranslations: PlatformTranslations = {
|
|||||||
"i18n:govoplan-calendar.microsoft_graph_source.ec4f1383": "Microsoft Graph source",
|
"i18n:govoplan-calendar.microsoft_graph_source.ec4f1383": "Microsoft Graph source",
|
||||||
"i18n:govoplan-calendar.mon.24b2a099": "Mon",
|
"i18n:govoplan-calendar.mon.24b2a099": "Mon",
|
||||||
"i18n:govoplan-calendar.month.082bc378": "Month",
|
"i18n:govoplan-calendar.month.082bc378": "Month",
|
||||||
|
"i18n:govoplan-calendar.move_and_copy_events_to_the_external_calendar.23c3a004": "Move and copy events to the external calendar",
|
||||||
"i18n:govoplan-calendar.move_events_to_another_calendar.830c7b09": "Move events to another calendar",
|
"i18n:govoplan-calendar.move_events_to_another_calendar.830c7b09": "Move events to another calendar",
|
||||||
"i18n:govoplan-calendar.name.709a2322": "Name",
|
"i18n:govoplan-calendar.name.709a2322": "Name",
|
||||||
"i18n:govoplan-calendar.never.80c3052d": "Never",
|
"i18n:govoplan-calendar.never.80c3052d": "Never",
|
||||||
@@ -103,9 +108,11 @@ export const generatedTranslations: PlatformTranslations = {
|
|||||||
"i18n:govoplan-calendar.new.6403f2b7": "New",
|
"i18n:govoplan-calendar.new.6403f2b7": "New",
|
||||||
"i18n:govoplan-calendar.next_sync.88c7af72": "Next sync",
|
"i18n:govoplan-calendar.next_sync.88c7af72": "Next sync",
|
||||||
"i18n:govoplan-calendar.next.bc981983": "Next",
|
"i18n:govoplan-calendar.next.bc981983": "Next",
|
||||||
|
"i18n:govoplan-calendar.no_compatible_target_calendar_is_available_add_a_l.1cf6e47b": "No compatible target calendar is available. Add a local calendar or an active two-way CalDAV calendar.",
|
||||||
"i18n:govoplan-calendar.no_calendar_collections_found.6453624a": "No calendar collections found.",
|
"i18n:govoplan-calendar.no_calendar_collections_found.6453624a": "No calendar collections found.",
|
||||||
"i18n:govoplan-calendar.no_calendars.3a7e4a7a": "No calendars",
|
"i18n:govoplan-calendar.no_calendars.3a7e4a7a": "No calendars",
|
||||||
"i18n:govoplan-calendar.no_events.e339ba73": "No events",
|
"i18n:govoplan-calendar.no_events.e339ba73": "No events",
|
||||||
|
"i18n:govoplan-calendar.no_local_target_calendar_is_available_add_a_local_.fad3cb65": "No local target calendar is available. Add a local calendar to detach these events without changing the remote calendar.",
|
||||||
"i18n:govoplan-calendar.none.6eef6648": "None",
|
"i18n:govoplan-calendar.none.6eef6648": "None",
|
||||||
"i18n:govoplan-calendar.not_configured.811931bb": "Not configured",
|
"i18n:govoplan-calendar.not_configured.811931bb": "Not configured",
|
||||||
"i18n:govoplan-calendar.not_scheduled.9c367369": "Not scheduled",
|
"i18n:govoplan-calendar.not_scheduled.9c367369": "Not scheduled",
|
||||||
@@ -223,6 +230,7 @@ export const generatedTranslations: PlatformTranslations = {
|
|||||||
"i18n:govoplan-calendar.delete.f6fdbe48": "Löschen",
|
"i18n:govoplan-calendar.delete.f6fdbe48": "Löschen",
|
||||||
"i18n:govoplan-calendar.deleting.2cda36c9": "Deleting",
|
"i18n:govoplan-calendar.deleting.2cda36c9": "Deleting",
|
||||||
"i18n:govoplan-calendar.description.55f8ebc8": "Beschreibung",
|
"i18n:govoplan-calendar.description.55f8ebc8": "Beschreibung",
|
||||||
|
"i18n:govoplan-calendar.detach_local_events_and_keep_remote_events.c58ad4e7": "Lokale Termine abtrennen und entfernte Termine beibehalten",
|
||||||
"i18n:govoplan-calendar.direction.fd8e45ba": "Direction",
|
"i18n:govoplan-calendar.direction.fd8e45ba": "Direction",
|
||||||
"i18n:govoplan-calendar.discover.4827ea22": "Discover",
|
"i18n:govoplan-calendar.discover.4827ea22": "Discover",
|
||||||
"i18n:govoplan-calendar.discovering.1884f689": "Discovering...",
|
"i18n:govoplan-calendar.discovering.1884f689": "Discovering...",
|
||||||
@@ -244,12 +252,15 @@ export const generatedTranslations: PlatformTranslations = {
|
|||||||
"i18n:govoplan-calendar.event_count_could_not_be_loaded_the_backend_will.163ff055": "Event count could not be loaded. The backend will still apply the selected delete action.",
|
"i18n:govoplan-calendar.event_count_could_not_be_loaded_the_backend_will.163ff055": "Event count could not be loaded. The backend will still apply the selected delete action.",
|
||||||
"i18n:govoplan-calendar.events": "events",
|
"i18n:govoplan-calendar.events": "events",
|
||||||
"i18n:govoplan-calendar.events_are_stored_in_govoplan_and_are_not_synced.3660e504": "Events are stored in GovOPlaN and are not synced to an external calendar source.",
|
"i18n:govoplan-calendar.events_are_stored_in_govoplan_and_are_not_synced.3660e504": "Events are stored in GovOPlaN and are not synced to an external calendar source.",
|
||||||
|
"i18n:govoplan-calendar.events_remain_in_govoplan_no_external_calendar_is_.62cb5937": "Die Termine bleiben in GovOPlaN; kein externer Kalender wird geändert.",
|
||||||
"i18n:govoplan-calendar.ews_endpoint.a3273983": "EWS endpoint",
|
"i18n:govoplan-calendar.ews_endpoint.a3273983": "EWS endpoint",
|
||||||
"i18n:govoplan-calendar.exchange_web_services_source.53caabf3": "Exchange Web Services source",
|
"i18n:govoplan-calendar.exchange_web_services_source.53caabf3": "Exchange Web Services source",
|
||||||
"i18n:govoplan-calendar.exchange.5b13eac7": "Exchange",
|
"i18n:govoplan-calendar.exchange.5b13eac7": "Exchange",
|
||||||
"i18n:govoplan-calendar.exdate_json.7d0c538d": "EXDATE JSON",
|
"i18n:govoplan-calendar.exdate_json.7d0c538d": "EXDATE JSON",
|
||||||
"i18n:govoplan-calendar.fri.bbd6e32e": "Fri",
|
"i18n:govoplan-calendar.fri.bbd6e32e": "Fri",
|
||||||
"i18n:govoplan-calendar.full_sync.21b89c76": "Full sync",
|
"i18n:govoplan-calendar.full_sync.21b89c76": "Full sync",
|
||||||
|
"i18n:govoplan-calendar.govoplan_moves_the_events_locally_and_queues_durab.da075b16": "GovOPlaN verschiebt die Termine lokal und reiht dauerhafte CalDAV-Kopien ein. Zustellfehler bleiben sichtbar und können erneut versucht werden.",
|
||||||
|
"i18n:govoplan-calendar.govoplan_moves_the_local_event_copies_to_the_targe.4863e46b": "GovOPlaN verschiebt die lokalen Terminkopien in den Zielkalender und trennt diese Quelle. Der entfernte Kalender und seine Termine bleiben unverändert.",
|
||||||
"i18n:govoplan-calendar.graph_calendar_url.e59607f3": "Graph calendar URL",
|
"i18n:govoplan-calendar.graph_calendar_url.e59607f3": "Graph calendar URL",
|
||||||
"i18n:govoplan-calendar.graph.9a7405eb": "Graph",
|
"i18n:govoplan-calendar.graph.9a7405eb": "Graph",
|
||||||
"i18n:govoplan-calendar.icalendar_json.fb6cc33e": "iCalendar JSON",
|
"i18n:govoplan-calendar.icalendar_json.fb6cc33e": "iCalendar JSON",
|
||||||
@@ -273,16 +284,19 @@ export const generatedTranslations: PlatformTranslations = {
|
|||||||
"i18n:govoplan-calendar.microsoft_graph_source.ec4f1383": "Microsoft Graph source",
|
"i18n:govoplan-calendar.microsoft_graph_source.ec4f1383": "Microsoft Graph source",
|
||||||
"i18n:govoplan-calendar.mon.24b2a099": "Mon",
|
"i18n:govoplan-calendar.mon.24b2a099": "Mon",
|
||||||
"i18n:govoplan-calendar.month.082bc378": "Monat",
|
"i18n:govoplan-calendar.month.082bc378": "Monat",
|
||||||
"i18n:govoplan-calendar.move_events_to_another_calendar.830c7b09": "Move events to another calendar",
|
"i18n:govoplan-calendar.move_and_copy_events_to_the_external_calendar.23c3a004": "Termine verschieben und in den externen Kalender kopieren",
|
||||||
|
"i18n:govoplan-calendar.move_events_to_another_calendar.830c7b09": "Termine in einen anderen Kalender verschieben",
|
||||||
"i18n:govoplan-calendar.name.709a2322": "Name",
|
"i18n:govoplan-calendar.name.709a2322": "Name",
|
||||||
"i18n:govoplan-calendar.never.80c3052d": "Never",
|
"i18n:govoplan-calendar.never.80c3052d": "Never",
|
||||||
"i18n:govoplan-calendar.new_event.2ef3795c": "New event",
|
"i18n:govoplan-calendar.new_event.2ef3795c": "New event",
|
||||||
"i18n:govoplan-calendar.new.6403f2b7": "New",
|
"i18n:govoplan-calendar.new.6403f2b7": "New",
|
||||||
"i18n:govoplan-calendar.next_sync.88c7af72": "Next sync",
|
"i18n:govoplan-calendar.next_sync.88c7af72": "Next sync",
|
||||||
"i18n:govoplan-calendar.next.bc981983": "Weiter",
|
"i18n:govoplan-calendar.next.bc981983": "Weiter",
|
||||||
|
"i18n:govoplan-calendar.no_compatible_target_calendar_is_available_add_a_l.1cf6e47b": "Kein kompatibler Zielkalender ist verfügbar. Fügen Sie einen lokalen Kalender oder einen aktiven CalDAV-Kalender mit bidirektionaler Synchronisierung hinzu.",
|
||||||
"i18n:govoplan-calendar.no_calendar_collections_found.6453624a": "No calendar collections found.",
|
"i18n:govoplan-calendar.no_calendar_collections_found.6453624a": "No calendar collections found.",
|
||||||
"i18n:govoplan-calendar.no_calendars.3a7e4a7a": "No calendars",
|
"i18n:govoplan-calendar.no_calendars.3a7e4a7a": "No calendars",
|
||||||
"i18n:govoplan-calendar.no_events.e339ba73": "No events",
|
"i18n:govoplan-calendar.no_events.e339ba73": "No events",
|
||||||
|
"i18n:govoplan-calendar.no_local_target_calendar_is_available_add_a_local_.fad3cb65": "Kein lokaler Zielkalender ist verfügbar. Fügen Sie einen lokalen Kalender hinzu, um diese Termine abzutrennen, ohne den entfernten Kalender zu ändern.",
|
||||||
"i18n:govoplan-calendar.none.6eef6648": "Keine",
|
"i18n:govoplan-calendar.none.6eef6648": "Keine",
|
||||||
"i18n:govoplan-calendar.not_configured.811931bb": "Nicht konfiguriert",
|
"i18n:govoplan-calendar.not_configured.811931bb": "Nicht konfiguriert",
|
||||||
"i18n:govoplan-calendar.not_scheduled.9c367369": "Not scheduled",
|
"i18n:govoplan-calendar.not_scheduled.9c367369": "Not scheduled",
|
||||||
|
|||||||
Reference in New Issue
Block a user