feat(ui) : add deadline/scheduled columns and sort options to Mes tâches page

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Matthieu
2026-03-19 10:33:54 +01:00
parent 6a8e406cc5
commit 1aa72c3b56
2 changed files with 32 additions and 8 deletions

View File

@@ -186,7 +186,11 @@
"allAssignees": "Tous", "allAssignees": "Tous",
"noTasks": "Aucune tâche", "noTasks": "Aucune tâche",
"backlog": "Backlog", "backlog": "Backlog",
"createTask": "Créer une tâche" "createTask": "Créer une tâche",
"sortBy": "Trier par",
"sortDefault": "Par défaut",
"sortDeadline": "Échéance",
"sortScheduledStart": "Date planifiée"
}, },
"dashboard": { "dashboard": {
"title": "Tableau de bord", "title": "Tableau de bord",

View File

@@ -50,6 +50,10 @@ const selectedPriorityId = ref<number | null>(null)
const selectedEffortId = ref<number | null>(null) const selectedEffortId = ref<number | null>(null)
const selectedAssigneeId = ref<number | null>(auth.user?.id ?? null) const selectedAssigneeId = ref<number | null>(auth.user?.id ?? null)
// Sort
type SortOption = 'default' | 'deadline' | 'scheduledStart'
const sortBy = ref<SortOption>('default')
// View toggle // View toggle
const viewMode = ref<'kanban' | 'list'>('kanban') const viewMode = ref<'kanban' | 'list'>('kanban')
@@ -157,6 +161,11 @@ async function loadTasks() {
if (selectedTagId.value) { if (selectedTagId.value) {
params['tags[]'] = `/api/task_tags/${selectedTagId.value}` params['tags[]'] = `/api/task_tags/${selectedTagId.value}`
} }
if (sortBy.value === 'deadline') {
params['order[deadline]'] = 'asc'
} else if (sortBy.value === 'scheduledStart') {
params['order[scheduledStart]'] = 'asc'
}
tasks.value = await taskService.getFiltered(params) tasks.value = await taskService.getFiltered(params)
} }
@@ -169,9 +178,9 @@ async function loadAll() {
} }
} }
// Watch filters to reload tasks // Watch filters and sort to reload tasks
watch( watch(
[selectedProjectId, selectedGroupId, selectedTagId, selectedPriorityId, selectedEffortId, selectedAssigneeId], [selectedProjectId, selectedGroupId, selectedTagId, selectedPriorityId, selectedEffortId, selectedAssigneeId, sortBy],
() => { loadTasks() }, () => { loadTasks() },
) )
@@ -311,7 +320,7 @@ onMounted(async () => {
<template> <template>
<div class="min-w-0"> <div class="min-w-0">
<!-- Header + Filters --> <!-- Header + Filters -->
<div class="sticky top-8 z-20 bg-white pb-4 sm:top-12"> <div class="sticky top-8 z-20 bg-white pb-4 sm:top-12 dark:bg-dark-base">
<div class="flex items-center justify-between gap-3"> <div class="flex items-center justify-between gap-3">
<h1 class="text-xl font-bold text-primary-500 sm:text-2xl">{{ $t('myTasks.title') }}</h1> <h1 class="text-xl font-bold text-primary-500 sm:text-2xl">{{ $t('myTasks.title') }}</h1>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
@@ -390,6 +399,17 @@ onMounted(async () => {
text-field="text-sm" text-field="text-sm"
text-value="text-sm" text-value="text-sm"
/> />
<div class="flex flex-col gap-0.5">
<span class="text-xs font-semibold text-neutral-500">{{ $t('myTasks.sortBy') }}</span>
<select
v-model="sortBy"
class="rounded-lg border border-neutral-300 bg-white px-2 py-1.5 text-sm text-neutral-700 focus:outline-none focus:ring-2 focus:ring-primary-500"
>
<option value="default">{{ $t('myTasks.sortDefault') }}</option>
<option value="deadline">{{ $t('myTasks.sortDeadline') }}</option>
<option value="scheduledStart">{{ $t('myTasks.sortScheduledStart') }}</option>
</select>
</div>
</div> </div>
</div> </div>
@@ -400,7 +420,7 @@ onMounted(async () => {
v-for="status in sortedStatuses" v-for="status in sortedStatuses"
:key="status.id" :key="status.id"
class="flex min-w-36 flex-1 flex-col rounded-lg transition-colors" class="flex min-w-36 flex-1 flex-col rounded-lg transition-colors"
:class="dragOverStatusId === status.id ? 'bg-neutral-200' : 'bg-neutral-50'" :class="dragOverStatusId === status.id ? 'bg-neutral-200 dark:bg-dark-hover' : 'bg-neutral-50 dark:bg-dark-surface/50'"
@dragover.prevent @dragover.prevent
@dragenter.prevent="onDragEnter(status.id)" @dragenter.prevent="onDragEnter(status.id)"
@dragleave="onDragLeave" @dragleave="onDragLeave"
@@ -435,13 +455,13 @@ onMounted(async () => {
<!-- Backlog below kanban --> <!-- Backlog below kanban -->
<div <div
class="mt-8 rounded-lg p-4 transition-colors" class="mt-8 rounded-lg p-4 transition-colors"
:class="dragOverStatusId === 0 ? 'bg-neutral-200' : 'bg-neutral-50'" :class="dragOverStatusId === 0 ? 'bg-neutral-200 dark:bg-dark-hover' : 'bg-neutral-50 dark:bg-dark-surface'"
@dragover.prevent @dragover.prevent
@dragenter.prevent="onDragEnter(0)" @dragenter.prevent="onDragEnter(0)"
@dragleave="onDragLeave" @dragleave="onDragLeave"
@drop.prevent="onDropBacklog($event)" @drop.prevent="onDropBacklog($event)"
> >
<h2 class="text-lg font-bold text-neutral-900">{{ $t('myTasks.backlog') }} ({{ backlogTasks.length }})</h2> <h2 class="text-lg font-bold text-neutral-900 dark:text-neutral-100">{{ $t('myTasks.backlog') }} ({{ backlogTasks.length }})</h2>
<div class="mt-4 grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"> <div class="mt-4 grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
<TaskCard <TaskCard
v-for="task in backlogTasks" v-for="task in backlogTasks"
@@ -461,7 +481,7 @@ onMounted(async () => {
</div> </div>
<!-- List View --> <!-- List View -->
<div v-if="viewMode === 'list'" class="mt-6 flex flex-col gap-2.5 rounded-[10px] bg-tertiary-500 p-2.5"> <div v-if="viewMode === 'list'" class="mt-6 flex flex-col gap-2.5 rounded-[10px] bg-tertiary-500 p-2.5 dark:bg-dark-surface">
<TaskBulkActions <TaskBulkActions
:selected-count="selectedTaskIds.size" :selected-count="selectedTaskIds.size"
:total-count="tasks.length" :total-count="tasks.length"