feat(workflow) : bulk status désactivé sur sélection multi-projets, scoped au workflow du projet

This commit is contained in:
2026-05-19 20:12:01 +02:00
parent 52b78d6bbc
commit 6a37349cf7
2 changed files with 47 additions and 10 deletions

View File

@@ -14,8 +14,9 @@
</span> </span>
<div v-if="selectedCount > 0" class="ml-2 flex items-center gap-1"> <div v-if="selectedCount > 0" class="ml-2 flex items-center gap-1">
<!-- Bulk status --> <!-- Bulk status (scoped to single project's workflow) -->
<MalioSelect <MalioSelect
v-if="!isMultiProject"
:model-value="null" :model-value="null"
:options="statusOptions" :options="statusOptions"
label="Status" label="Status"
@@ -25,6 +26,13 @@
text-value="text-xs" text-value="text-xs"
@update:model-value="(v: number | null) => v && emit('bulk-update', 'status', v)" @update:model-value="(v: number | null) => v && emit('bulk-update', 'status', v)"
/> />
<span
v-else
class="rounded border border-neutral-200 px-2 py-1 text-xs text-neutral-400"
title="Sélection multi-projets le statut dépend du workflow de chaque projet"
>
Status —
</span>
<!-- Bulk user --> <!-- Bulk user -->
<MalioSelect <MalioSelect
:model-value="null" :model-value="null"
@@ -85,13 +93,15 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { Task } from '~/services/dto/task'
import type { TaskStatus } from '~/services/dto/task-status' import type { TaskStatus } from '~/services/dto/task-status'
import type { TaskEffort } from '~/services/dto/task-effort' import type { TaskEffort } from '~/services/dto/task-effort'
import type { TaskPriority } from '~/services/dto/task-priority' import type { TaskPriority } from '~/services/dto/task-priority'
import type { TaskGroup } from '~/services/dto/task-group' import type { TaskGroup } from '~/services/dto/task-group'
import type { UserData } from '~/services/dto/user-data' import type { UserData } from '~/services/dto/user-data'
import type { Project } from '~/services/dto/project'
const props = defineProps<{ const props = withDefaults(defineProps<{
selectedCount: number selectedCount: number
totalCount: number totalCount: number
allSelected: boolean allSelected: boolean
@@ -101,7 +111,12 @@ const props = defineProps<{
priorities: TaskPriority[] priorities: TaskPriority[]
efforts: TaskEffort[] efforts: TaskEffort[]
groups: TaskGroup[] groups: TaskGroup[]
}>() selectedTasks?: Task[]
projects?: Project[]
}>(), {
selectedTasks: () => [],
projects: () => [],
})
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'toggle-all'): void (e: 'toggle-all'): void
@@ -110,23 +125,42 @@ const emit = defineEmits<{
(e: 'bulk-delete'): void (e: 'bulk-delete'): void
}>() }>()
const statusOptions = computed(() => const distinctProjectIds = computed(() => {
props.statuses.map(s => ({ label: s.label, value: s.id })) const ids = new Set<number>()
) for (const t of props.selectedTasks) {
if (t.project) ids.add(t.project.id)
}
return ids
})
const isMultiProject = computed(() => distinctProjectIds.value.size > 1)
const statusOptions = computed<{ label: string, value: number }[]>(() => {
// Si on connait les projets et qu'on est sur un seul, on scope au workflow de ce projet
if (distinctProjectIds.value.size === 1 && props.projects.length > 0) {
const projectId = [...distinctProjectIds.value][0]
const project = props.projects.find(p => p.id === projectId)
if (project?.workflow?.statuses) {
return project.workflow.statuses.map(s => ({ label: s.label, value: s.id }))
}
}
// Fallback : statuts globaux fournis en props (ex. depuis projects/[id])
return props.statuses.map(s => ({ label: s.label, value: s.id }))
})
const userOptions = computed(() => const userOptions = computed(() =>
props.users.map(u => ({ label: u.username, value: u.id })) props.users.map(u => ({ label: u.username, value: u.id })),
) )
const priorityOptions = computed(() => const priorityOptions = computed(() =>
props.priorities.map(p => ({ label: p.label, value: p.id })) props.priorities.map(p => ({ label: p.label, value: p.id })),
) )
const effortOptions = computed(() => const effortOptions = computed(() =>
props.efforts.map(e => ({ label: e.label, value: e.id })) props.efforts.map(e => ({ label: e.label, value: e.id })),
) )
const groupOptions = computed(() => const groupOptions = computed(() =>
props.groups.filter(g => !g.archived).map(g => ({ label: g.title, value: g.id })) props.groups.filter(g => !g.archived).map(g => ({ label: g.title, value: g.id })),
) )
</script> </script>

View File

@@ -62,6 +62,7 @@ const viewMode = ref<'kanban' | 'list'>('kanban')
// Bulk selection // Bulk selection
const selectedTaskIds = reactive(new Set<number>()) const selectedTaskIds = reactive(new Set<number>())
const selectedTasksArray = computed(() => tasks.value.filter(t => selectedTaskIds.has(t.id)))
// Modal // Modal
const taskModalOpen = ref(false) const taskModalOpen = ref(false)
@@ -456,6 +457,8 @@ onMounted(async () => {
:priorities="priorities" :priorities="priorities"
:efforts="efforts" :efforts="efforts"
:groups="groups" :groups="groups"
:selected-tasks="selectedTasksArray"
:projects="projects"
@toggle-all="toggleSelectAll(tasks)" @toggle-all="toggleSelectAll(tasks)"
@bulk-update="onBulkUpdate" @bulk-update="onBulkUpdate"
@bulk-archive="onBulkArchive" @bulk-archive="onBulkArchive"