feat(tasks): Berechtigung bestehender Freigaben nachtraeglich aendern

Stift-Icon neben Freigabe oeffnet Inline-Editor mit Select "Lesen" /
"Lesen+Schreiben" (analog zu Kontakten/Kalender).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Hacker 2026-04-14 15:26:59 +02:00
parent a21bf6de1b
commit e4dd555bd1
1 changed files with 39 additions and 6 deletions

View File

@ -127,11 +127,20 @@
<Button label="Teilen" size="small" @click="doShare" />
</div>
<div v-if="listShares.length" class="existing-shares">
<div v-for="s in listShares" :key="s.id" class="share-perm-item">
<i class="pi pi-user"></i> <span>{{ s.username }}</span>
<span class="perm-label">{{ s.permission === 'readwrite' ? 'Lesen+Schreiben' : 'Lesen' }}</span>
<Button icon="pi pi-trash" text size="small" severity="danger" @click="removeShare(s.id)" />
</div>
<template v-for="s in listShares" :key="s.id">
<div v-if="editingShareId !== s.id" class="share-perm-item">
<i class="pi pi-user"></i> <span>{{ s.username }}</span>
<span class="perm-label">{{ s.permission === 'readwrite' ? 'Lesen+Schreiben' : 'Lesen' }}</span>
<Button icon="pi pi-pencil" text size="small" title="Bearbeiten" @click="startEditShare(s)" />
<Button icon="pi pi-trash" text size="small" severity="danger" title="Entfernen" @click="removeShare(s.id)" />
</div>
<div v-else class="share-perm-item editing">
<i class="pi pi-user"></i> <span>{{ s.username }}</span>
<Select v-model="editSharePermission" :options="permOptions" optionLabel="label" optionValue="value" />
<Button icon="pi pi-check" text size="small" severity="success" title="Speichern" @click="saveEditShare(s)" />
<Button icon="pi pi-times" text size="small" title="Abbrechen" @click="editingShareId = null" />
</div>
</template>
</div>
</div>
<div v-if="menuList.permission === 'owner'" class="field" style="border-top:1px solid var(--p-surface-200); padding-top:1rem">
@ -248,8 +257,31 @@ const shareUsername = ref('')
const sharePermission = ref('read')
const listShares = ref([])
const shareSearchResults = ref([])
const editingShareId = ref(null)
const editSharePermission = ref('read')
let shareSearchTimer = null
function startEditShare(s) {
editingShareId.value = s.id
editSharePermission.value = s.permission
}
async function saveEditShare(s) {
if (!menuList.value) return
try {
await apiClient.post(`/tasklists/${menuList.value.id}/share`, {
username: s.username,
permission: editSharePermission.value,
})
editingShareId.value = null
await loadShares()
toast.add({ severity: 'success', summary: 'Berechtigung aktualisiert', life: 2500 })
} catch (err) {
toast.add({ severity: 'error', summary: 'Fehler',
detail: err.response?.data?.error || err.message, life: 4000 })
}
}
function onShareSearch() {
clearTimeout(shareSearchTimer)
const q = shareUsername.value.trim()
@ -655,7 +687,8 @@ watch(selectedListId, loadTasks)
display: flex; gap: 0.5rem; align-items: center; }
.user-result:hover { background: var(--p-primary-50); }
.existing-shares { margin-top: 0.5rem; }
.share-perm-item { display: flex; align-items: center; gap: 0.5rem; padding: 0.375rem 0; font-size: 0.875rem; }
.share-perm-item { display: flex; align-items: center; gap: 0.5rem; padding: 0.375rem 0; font-size: 0.875rem; flex-wrap: wrap; }
.share-perm-item.editing { background: var(--p-surface-50); padding: 0.5rem; border-radius: 4px; }
.perm-label { color: var(--p-text-muted-color); font-size: 0.75rem; }
.url-row { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; }
.url-row strong { min-width: 110px; font-size: 0.8rem; }