feat(project-management) : extract Projects/Tasks front into Nuxt module layer
Tranche 4 of LST-65. Companion to the backend module migration.
- Move pages (my-tasks, projects, projects/[id]/{index,groups,archives}),
18 components (project + task), 10 services and 10 DTOs into
frontend/modules/project-management/ (auto-detected layer).
- Rewrite explicit ~/services/* and ~/services/dto/* imports across 38
consumers (admin tabs, mail modals, dashboard, mail page, layout) including
the time-tracking module whose DTOs referenced project/task/task-tag.
- clients.ts and shared DTOs (client, user-data) stay at the root.
- Routes /my-tasks, /projects, /projects/:id(/groups|/archives) preserved;
i18n stays global.
nuxt build passes; routes confirmed.
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
import type { Client } from '~/services/dto/client'
|
||||
import type { Workflow } from './workflow'
|
||||
|
||||
export type Project = {
|
||||
id: number
|
||||
'@id'?: string
|
||||
code: string
|
||||
name: string
|
||||
description: string | null
|
||||
color: string
|
||||
client: Client | null
|
||||
workflow: Workflow
|
||||
giteaOwner: string | null
|
||||
giteaRepo: string | null
|
||||
bookstackShelfId: number | null
|
||||
bookstackShelfName: string | null
|
||||
archived: boolean
|
||||
taskCount: number
|
||||
}
|
||||
|
||||
export type ProjectWrite = {
|
||||
code?: string
|
||||
name: string
|
||||
description: string | null
|
||||
color: string
|
||||
client: string | null // IRI : "/api/clients/1" ou null
|
||||
workflow?: string // IRI : "/api/workflows/1"
|
||||
giteaOwner?: string | null
|
||||
giteaRepo?: string | null
|
||||
bookstackShelfId?: number | null
|
||||
bookstackShelfName?: string | null
|
||||
archived?: boolean
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import type { UserData } from '~/services/dto/user-data'
|
||||
|
||||
export type TaskDocument = {
|
||||
'@id'?: string
|
||||
id: number
|
||||
task: string
|
||||
originalName: string
|
||||
fileName?: string | null
|
||||
sharePath?: string | null
|
||||
mimeType: string
|
||||
size: number
|
||||
createdAt: string
|
||||
uploadedBy: UserData | null
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export type TaskEffort = {
|
||||
id: number
|
||||
'@id'?: string
|
||||
label: string
|
||||
}
|
||||
|
||||
export type TaskEffortWrite = {
|
||||
label: string
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { Project } from './project'
|
||||
|
||||
export type TaskGroup = {
|
||||
id: number
|
||||
'@id'?: string
|
||||
title: string
|
||||
description: string | null
|
||||
color: string
|
||||
project: Project | null
|
||||
archived: boolean
|
||||
}
|
||||
|
||||
export type TaskGroupWrite = {
|
||||
title: string
|
||||
description: string | null
|
||||
color: string
|
||||
project: string
|
||||
archived?: boolean
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
export type TaskPriority = {
|
||||
id: number
|
||||
'@id'?: string
|
||||
label: string
|
||||
color: string
|
||||
}
|
||||
|
||||
export type TaskPriorityWrite = {
|
||||
label: string
|
||||
color: string
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
export type TaskRecurrence = {
|
||||
id: number
|
||||
'@id'?: string
|
||||
type: 'daily' | 'weekly' | 'monthly' | 'yearly'
|
||||
interval: number
|
||||
daysOfWeek: string[] | null
|
||||
dayOfMonth: number | null
|
||||
weekOfMonth: number | null
|
||||
endDate: string | null
|
||||
maxOccurrences: number | null
|
||||
occurrenceCount: number
|
||||
}
|
||||
|
||||
export type TaskRecurrenceWrite = {
|
||||
type: 'daily' | 'weekly' | 'monthly' | 'yearly'
|
||||
interval: number
|
||||
daysOfWeek?: string[] | null
|
||||
dayOfMonth?: number | null
|
||||
weekOfMonth?: number | null
|
||||
endDate?: string | null
|
||||
maxOccurrences?: number | null
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import type { StatusCategory } from './workflow'
|
||||
|
||||
export type TaskStatus = {
|
||||
id: number
|
||||
'@id'?: string
|
||||
label: string
|
||||
color: string
|
||||
position: number
|
||||
isFinal: boolean
|
||||
category: StatusCategory
|
||||
workflow?: { '@id': string, id: number } | string
|
||||
}
|
||||
|
||||
export type TaskStatusWrite = {
|
||||
label: string
|
||||
color: string
|
||||
position: number
|
||||
isFinal: boolean
|
||||
category: StatusCategory
|
||||
workflow?: string
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
export type TaskTag = {
|
||||
id: number
|
||||
'@id'?: string
|
||||
label: string
|
||||
color: string
|
||||
}
|
||||
|
||||
export type TaskTagWrite = {
|
||||
label: string
|
||||
color: string
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import type { TaskStatus } from './task-status'
|
||||
import type { TaskEffort } from './task-effort'
|
||||
import type { TaskPriority } from './task-priority'
|
||||
import type { TaskTag } from './task-tag'
|
||||
import type { TaskGroup } from './task-group'
|
||||
import type { UserData } from '~/services/dto/user-data'
|
||||
import type { Project } from './project'
|
||||
import type { TaskDocument } from './task-document'
|
||||
|
||||
export type Task = {
|
||||
id: number
|
||||
'@id'?: string
|
||||
number: number
|
||||
title: string
|
||||
description: string | null
|
||||
status: TaskStatus | null
|
||||
effort: TaskEffort | null
|
||||
priority: TaskPriority | null
|
||||
assignee: UserData | null
|
||||
collaborators: UserData[]
|
||||
group: TaskGroup | null
|
||||
project: Project | null
|
||||
tags: TaskTag[]
|
||||
documents: TaskDocument[]
|
||||
archived: boolean
|
||||
scheduledStart: string | null
|
||||
scheduledEnd: string | null
|
||||
deadline: string | null
|
||||
syncToCalendar: boolean
|
||||
calendarSyncError: string | null
|
||||
recurrence: {
|
||||
id: number
|
||||
'@id'?: string
|
||||
type: 'daily' | 'weekly' | 'monthly' | 'yearly'
|
||||
interval: number
|
||||
daysOfWeek: string[] | null
|
||||
dayOfMonth: number | null
|
||||
weekOfMonth: number | null
|
||||
endDate: string | null
|
||||
maxOccurrences: number | null
|
||||
occurrenceCount: number
|
||||
} | null
|
||||
}
|
||||
|
||||
export type TaskWrite = {
|
||||
title: string
|
||||
description: string | null
|
||||
status: string | null
|
||||
effort: string | null
|
||||
priority: string | null
|
||||
assignee: string | null
|
||||
collaborators?: string[]
|
||||
group: string | null
|
||||
project: string
|
||||
tags: string[]
|
||||
archived?: boolean
|
||||
scheduledStart?: string | null
|
||||
scheduledEnd?: string | null
|
||||
deadline?: string | null
|
||||
syncToCalendar?: boolean
|
||||
recurrence?: string | null
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import type { TaskStatus, TaskStatusWrite } from './task-status'
|
||||
|
||||
export type StatusCategory = 'todo' | 'in_progress' | 'blocked' | 'review' | 'done'
|
||||
|
||||
export const STATUS_CATEGORY_LABEL: Record<StatusCategory, string> = {
|
||||
todo: 'À faire',
|
||||
in_progress: 'En cours',
|
||||
blocked: 'Bloqué',
|
||||
review: 'En validation',
|
||||
done: 'Terminé',
|
||||
}
|
||||
|
||||
/** Palette canonique des catégories (couleurs « classiques »), indépendante des workflows. */
|
||||
export const STATUS_CATEGORY_COLOR: Record<StatusCategory, string> = {
|
||||
todo: '#222783',
|
||||
in_progress: '#4A90D9',
|
||||
blocked: '#C62828',
|
||||
review: '#FF8F00',
|
||||
done: '#26A69A',
|
||||
}
|
||||
|
||||
/** Renvoie '#1f2937' (foncé) ou '#ffffff' (blanc) selon la luminance du fond, pour rester lisible. */
|
||||
export function contrastText(hex: string): string {
|
||||
const c = hex.replace('#', '')
|
||||
const r = parseInt(c.slice(0, 2), 16)
|
||||
const g = parseInt(c.slice(2, 4), 16)
|
||||
const b = parseInt(c.slice(4, 6), 16)
|
||||
const lum = (0.299 * r + 0.587 * g + 0.114 * b) / 255
|
||||
return lum > 0.6 ? '#1f2937' : '#ffffff'
|
||||
}
|
||||
|
||||
export type Workflow = {
|
||||
id: number
|
||||
'@id'?: string
|
||||
name: string
|
||||
isDefault: boolean
|
||||
position: number
|
||||
statuses: TaskStatus[]
|
||||
}
|
||||
|
||||
export type WorkflowWrite = {
|
||||
name: string
|
||||
isDefault: boolean
|
||||
position: number
|
||||
statuses?: TaskStatusWrite[]
|
||||
}
|
||||
Reference in New Issue
Block a user