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' }"> <Dialog v-model:visible="showCalImportDialog" header="In welchen Kalender importieren?" modal :style="{ width: '420px' }">
<div class="field"> <div class="field">
<label>Kalender</label> <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> </div>
<p class="hint" style="font-size:0.85rem;color:var(--p-text-muted-color)">Datei: {{ pendingImportFile?.name }}</p> <p class="hint" style="font-size:0.85rem;color:var(--p-text-muted-color)">Datei: {{ pendingImportFile?.name }}</p>
<template #footer> <template #footer>
@ -171,7 +171,7 @@
</div> </div>
<div v-if="writableCalendars.length > 1" class="field"> <div v-if="writableCalendars.length > 1" class="field">
<label>Kalender</label> <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>
<div class="field-row"> <div class="field-row">
<div class="field"> <div class="field">
@ -636,6 +636,13 @@ const ownCalendars = computed(() => calendars.value.filter(c => c.permission ===
const writableCalendars = computed(() => const writableCalendars = computed(() =>
calendars.value.filter(c => c.permission === 'owner' || c.permission === 'readwrite') 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) const exportableCalendars = computed(() => calendars.value)
// --- Calendar Import / Export --- // --- Calendar Import / Export ---

View File

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

View File

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