feat: Auswahl-Dropdowns zeigen "(geteilt von <Name>)" bei Freigaben

Wenn der eigene und ein freigegebener Kalender/Adressbuch/Aufgabenliste
denselben Namen tragen, sind sie in den Anlegen-Dialogen jetzt
unterscheidbar.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Hacker 2026-04-14 15:53:46 +02:00
parent ed944339c4
commit 9f6132a400
3 changed files with 25 additions and 6 deletions

View File

@ -119,7 +119,7 @@
<Dialog v-model:visible="showCalImportDialog" header="In welchen Kalender importieren?" modal :style="{ width: '420px' }">
<div class="field">
<label>Kalender</label>
<Select v-model="importTargetCalId" :options="writableCalendars" optionLabel="name" optionValue="id" fluid />
<Select v-model="importTargetCalId" :options="writableCalendarOptions" optionLabel="label" optionValue="id" fluid />
</div>
<p class="hint" style="font-size:0.85rem;color:var(--p-text-muted-color)">Datei: {{ pendingImportFile?.name }}</p>
<template #footer>
@ -171,7 +171,7 @@
</div>
<div v-if="writableCalendars.length > 1" class="field">
<label>Kalender</label>
<Select v-model="eventForm.calendar_id" :options="writableCalendars" optionLabel="name" optionValue="id" fluid />
<Select v-model="eventForm.calendar_id" :options="writableCalendarOptions" optionLabel="label" optionValue="id" fluid />
</div>
<div class="field-row">
<div class="field">
@ -636,6 +636,13 @@ const ownCalendars = computed(() => calendars.value.filter(c => c.permission ===
const writableCalendars = computed(() =>
calendars.value.filter(c => c.permission === 'owner' || c.permission === 'readwrite')
)
// Mit "(geteilt von <Name>)"-Suffix fuer eindeutige Anzeige in Selects.
const writableCalendarOptions = computed(() => writableCalendars.value.map(c => ({
...c,
label: c.permission === 'owner'
? c.name
: `${c.name} (geteilt von ${c.owner_display_name || c.owner_name})`,
})))
const exportableCalendars = computed(() => calendars.value)
// --- Calendar Import / Export ---

View File

@ -197,8 +197,8 @@
<TabPanel value="general">
<div v-if="writableBooks.length > 1" class="field" style="max-width:400px">
<label>Adressbuch</label>
<Select v-model="contactTargetBookId" :options="writableBooks"
optionLabel="name" optionValue="id" fluid />
<Select v-model="contactTargetBookId" :options="writableBookOptions"
optionLabel="label" optionValue="id" fluid />
</div>
<div class="photo-row">
<div class="avatar large" :style="{ background: avatarColor(contactForm) }">
@ -416,6 +416,12 @@ const contactTargetBookId = ref(null)
const writableBooks = computed(() =>
addressBooks.value.filter(b => b.permission === 'owner' || b.permission === 'readwrite')
)
const writableBookOptions = computed(() => writableBooks.value.map(b => ({
...b,
label: b.permission === 'owner'
? b.name
: `${b.name} (geteilt von ${b.owner_display_name || b.owner_name})`,
})))
const loading = ref(false)
const searchQuery = ref('')
let searchTimer = null

View File

@ -183,8 +183,8 @@
modal :style="{ width: '560px' }">
<div v-if="writableLists.length > 1" class="field">
<label>Liste</label>
<Select v-model="taskTargetListId" :options="writableLists"
optionLabel="name" optionValue="id" fluid />
<Select v-model="taskTargetListId" :options="writableListOptions"
optionLabel="label" optionValue="id" fluid />
</div>
<div class="field">
<label>Titel</label>
@ -271,6 +271,12 @@ const taskTargetListId = ref(null)
const writableLists = computed(() =>
lists.value.filter(l => l.permission === 'owner' || l.permission === 'readwrite')
)
const writableListOptions = computed(() => writableLists.value.map(l => ({
...l,
label: l.permission === 'owner'
? l.name
: `${l.name} (geteilt von ${l.owner_display_name || l.owner_name})`,
})))
const tasks = ref([])
const search = ref('')
const hideDone = ref(false)