feat(projects) : archivage en masse des tickets sur statut final
Auto Tag Develop / tag (push) Successful in 9s

- TaskBulkActions : prop canArchive + bouton archive conditionnel
- pages/projects/[id] : computed canArchiveSelection (true quand le filtre statut courant pointe vers un statut isFinal)
- purge la sélection des ids hors filtre courant pour garder le compteur cohérent en vue liste
This commit is contained in:
Matthieu
2026-05-28 10:50:48 +02:00
parent 8f75e2e310
commit a3c0696023
2 changed files with 28 additions and 0 deletions
@@ -79,6 +79,17 @@
@update:model-value="(v: number | null) => v && emit('bulk-update', 'group', v)" @update:model-value="(v: number | null) => v && emit('bulk-update', 'group', v)"
/> />
<!-- Archive (only when current filter targets a final status) -->
<MalioButtonIcon
v-if="canArchive"
icon="mdi:archive-outline"
aria-label="Archiver"
variant="ghost"
icon-size="22"
button-class="self-end text-neutral-500 hover:bg-primary-50 hover:text-primary-500"
@click="emit('bulk-archive')"
/>
<!-- Delete --> <!-- Delete -->
<MalioButtonIcon <MalioButtonIcon
icon="mdi:delete-outline" icon="mdi:delete-outline"
@@ -113,9 +124,11 @@ const props = withDefaults(defineProps<{
groups: TaskGroup[] groups: TaskGroup[]
selectedTasks?: Task[] selectedTasks?: Task[]
projects?: Project[] projects?: Project[]
canArchive?: boolean
}>(), { }>(), {
selectedTasks: () => [], selectedTasks: () => [],
projects: () => [], projects: () => [],
canArchive: false,
}) })
const emit = defineEmits<{ const emit = defineEmits<{
+15
View File
@@ -161,6 +161,7 @@
:priorities="priorities" :priorities="priorities"
:efforts="efforts" :efforts="efforts"
:groups="groups" :groups="groups"
:can-archive="canArchiveSelection"
@toggle-all="toggleSelectAll(filteredTasks)" @toggle-all="toggleSelectAll(filteredTasks)"
@bulk-update="onBulkUpdate" @bulk-update="onBulkUpdate"
@bulk-archive="onBulkArchive" @bulk-archive="onBulkArchive"
@@ -297,6 +298,12 @@ const effortFilterOptions = computed(() =>
efforts.value.map(e => ({ label: e.label, value: e.id })) efforts.value.map(e => ({ label: e.label, value: e.id }))
) )
const canArchiveSelection = computed(() => {
if (selectedStatusId.value === null) return false
const status = statuses.value.find(s => s.id === selectedStatusId.value)
return status?.isFinal === true
})
const filteredTasks = computed(() => { const filteredTasks = computed(() => {
let result = tasks.value.filter(t => !t.archived) let result = tasks.value.filter(t => !t.archived)
if (selectedGroupId.value) { if (selectedGroupId.value) {
@@ -323,6 +330,14 @@ const filteredTasks = computed(() => {
return result return result
}) })
watch(filteredTasks, (list) => {
if (selectedTaskIds.size === 0) return
const visibleIds = new Set(list.map(t => t.id))
for (const id of selectedTaskIds) {
if (!visibleIds.has(id)) selectedTaskIds.delete(id)
}
})
function tasksByStatus(statusId: number): Task[] { function tasksByStatus(statusId: number): Task[] {
return filteredTasks.value.filter(t => t.status?.id === statusId) return filteredTasks.value.filter(t => t.status?.id === statusId)
} }