diff --git a/frontend/components/TaskCard.vue b/frontend/components/TaskCard.vue
new file mode 100644
index 0000000..e0ccdd2
--- /dev/null
+++ b/frontend/components/TaskCard.vue
@@ -0,0 +1,72 @@
+
+
+
+
{{ task.title }}
+
+
+
+
+
+
+
+ {{ task.priority.label }}
+
+
+ {{ type.label }}
+
+
+ {{ task.assignee.username.substring(0, 2).toUpperCase() }}
+
+
+
+
+
+
+
+
+
diff --git a/frontend/components/TaskDrawer.vue b/frontend/components/TaskDrawer.vue
new file mode 100644
index 0000000..54f8637
--- /dev/null
+++ b/frontend/components/TaskDrawer.vue
@@ -0,0 +1,225 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/TaskGroupDrawer.vue b/frontend/components/TaskGroupDrawer.vue
new file mode 100644
index 0000000..a8714f2
--- /dev/null
+++ b/frontend/components/TaskGroupDrawer.vue
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
diff --git a/frontend/i18n/locales/fr.json b/frontend/i18n/locales/fr.json
index 36a49aa..e7c2342 100644
--- a/frontend/i18n/locales/fr.json
+++ b/frontend/i18n/locales/fr.json
@@ -28,5 +28,40 @@
"created": "Projet créé avec succès.",
"updated": "Projet mis à jour avec succès.",
"deleted": "Projet supprimé avec succès."
+ },
+ "taskStatuses": {
+ "created": "Statut créé avec succès.",
+ "updated": "Statut mis à jour avec succès.",
+ "deleted": "Statut supprimé avec succès."
+ },
+ "taskEfforts": {
+ "created": "Effort créé avec succès.",
+ "updated": "Effort mis à jour avec succès.",
+ "deleted": "Effort supprimé avec succès."
+ },
+ "taskPriorities": {
+ "created": "Priorité créée avec succès.",
+ "updated": "Priorité mise à jour avec succès.",
+ "deleted": "Priorité supprimée avec succès."
+ },
+ "taskTypes": {
+ "created": "Type créé avec succès.",
+ "updated": "Type mis à jour avec succès.",
+ "deleted": "Type supprimé avec succès."
+ },
+ "taskGroups": {
+ "created": "Groupe créé avec succès.",
+ "updated": "Groupe mis à jour avec succès.",
+ "deleted": "Groupe supprimé avec succès."
+ },
+ "tasks": {
+ "created": "Ticket créé avec succès.",
+ "updated": "Ticket mis à jour avec succès.",
+ "deleted": "Ticket supprimé avec succès."
+ },
+ "users": {
+ "created": "Utilisateur créé avec succès.",
+ "updated": "Utilisateur mis à jour avec succès.",
+ "deleted": "Utilisateur supprimé avec succès."
}
}
diff --git a/frontend/pages/projects/[id].vue b/frontend/pages/projects/[id].vue
new file mode 100644
index 0000000..6f63992
--- /dev/null
+++ b/frontend/pages/projects/[id].vue
@@ -0,0 +1,308 @@
+
+
+
+
{{ project?.name ?? '' }}
+
+
+ + Ajouter un groupe
+
+
+ + Ajouter un ticket
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ status.label }} ({{ tasksByStatus(status.id).length }})
+
+
+
+
+
+
+
+
Backlog
+
+
+
{{ task.title }}
+
+
+ {{ type.label }}
+
+
+ {{ task.priority.label }}
+
+
+ {{ task.effort.label }}
+
+
+ {{ task.assignee.username.substring(0, 2).toUpperCase() }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/pages/projects.vue b/frontend/pages/projects/index.vue
similarity index 83%
rename from frontend/pages/projects.vue
rename to frontend/pages/projects/index.vue
index d18b067..8ffd5d0 100644
--- a/frontend/pages/projects.vue
+++ b/frontend/pages/projects/index.vue
@@ -15,9 +15,17 @@
v-for="project in projects"
:key="project.id"
class="cursor-pointer rounded-lg border border-neutral-200 bg-tertiary-500 shadow-sm transition hover:shadow-md"
- @click="openEdit(project)"
+ @click="navigateTo(`/projects/${project.id}`)"
>
-
{{ project.name }}
diff --git a/frontend/services/dto/task-effort.ts b/frontend/services/dto/task-effort.ts
new file mode 100644
index 0000000..9d3e3e2
--- /dev/null
+++ b/frontend/services/dto/task-effort.ts
@@ -0,0 +1,9 @@
+export type TaskEffort = {
+ id: number
+ '@id'?: string
+ label: string
+}
+
+export type TaskEffortWrite = {
+ label: string
+}
diff --git a/frontend/services/dto/task-group.ts b/frontend/services/dto/task-group.ts
new file mode 100644
index 0000000..52bd804
--- /dev/null
+++ b/frontend/services/dto/task-group.ts
@@ -0,0 +1,17 @@
+import type { Project } from './project'
+
+export type TaskGroup = {
+ id: number
+ '@id'?: string
+ title: string
+ description: string | null
+ color: string
+ project: Project | null
+}
+
+export type TaskGroupWrite = {
+ title: string
+ description: string | null
+ color: string
+ project: string
+}
diff --git a/frontend/services/dto/task-priority.ts b/frontend/services/dto/task-priority.ts
new file mode 100644
index 0000000..2b71e6c
--- /dev/null
+++ b/frontend/services/dto/task-priority.ts
@@ -0,0 +1,11 @@
+export type TaskPriority = {
+ id: number
+ '@id'?: string
+ label: string
+ color: string
+}
+
+export type TaskPriorityWrite = {
+ label: string
+ color: string
+}
diff --git a/frontend/services/dto/task-status.ts b/frontend/services/dto/task-status.ts
new file mode 100644
index 0000000..073c1ec
--- /dev/null
+++ b/frontend/services/dto/task-status.ts
@@ -0,0 +1,13 @@
+export type TaskStatus = {
+ id: number
+ '@id'?: string
+ label: string
+ color: string
+ position: number
+}
+
+export type TaskStatusWrite = {
+ label: string
+ color: string
+ position: number
+}
diff --git a/frontend/services/dto/task-type.ts b/frontend/services/dto/task-type.ts
new file mode 100644
index 0000000..3153ab1
--- /dev/null
+++ b/frontend/services/dto/task-type.ts
@@ -0,0 +1,11 @@
+export type TaskType = {
+ id: number
+ '@id'?: string
+ label: string
+ color: string
+}
+
+export type TaskTypeWrite = {
+ label: string
+ color: string
+}
diff --git a/frontend/services/dto/task.ts b/frontend/services/dto/task.ts
new file mode 100644
index 0000000..8b103b4
--- /dev/null
+++ b/frontend/services/dto/task.ts
@@ -0,0 +1,31 @@
+import type { TaskStatus } from './task-status'
+import type { TaskEffort } from './task-effort'
+import type { TaskPriority } from './task-priority'
+import type { TaskType } from './task-type'
+import type { TaskGroup } from './task-group'
+import type { UserData } from './user-data'
+
+export type Task = {
+ id: number
+ '@id'?: string
+ title: string
+ description: string | null
+ status: TaskStatus | null
+ effort: TaskEffort | null
+ priority: TaskPriority | null
+ assignee: UserData | null
+ group: TaskGroup | null
+ types: TaskType[]
+}
+
+export type TaskWrite = {
+ title: string
+ description: string | null
+ status: string | null
+ effort: string | null
+ priority: string | null
+ assignee: string | null
+ group: string | null
+ project: string
+ types: string[]
+}
diff --git a/frontend/services/projects.ts b/frontend/services/projects.ts
index 852824c..a61d98a 100644
--- a/frontend/services/projects.ts
+++ b/frontend/services/projects.ts
@@ -10,6 +10,10 @@ export function useProjectService() {
return extractHydraMembers(data)
}
+ async function getById(id: number): Promise {
+ return api.get(`/projects/${id}`)
+ }
+
async function create(payload: ProjectWrite): Promise {
return api.post('/projects', payload as Record, {
toastSuccessKey: 'projects.created',
@@ -28,5 +32,5 @@ export function useProjectService() {
})
}
- return { getAll, create, update, remove }
+ return { getAll, getById, create, update, remove }
}
diff --git a/frontend/services/task-efforts.ts b/frontend/services/task-efforts.ts
new file mode 100644
index 0000000..4f80833
--- /dev/null
+++ b/frontend/services/task-efforts.ts
@@ -0,0 +1,32 @@
+import type { TaskEffort, TaskEffortWrite } from './dto/task-effort'
+import type { HydraCollection } from '~/utils/api'
+import { extractHydraMembers } from '~/utils/api'
+
+export function useTaskEffortService() {
+ const api = useApi()
+
+ async function getAll(): Promise {
+ const data = await api.get>('/task_efforts')
+ return extractHydraMembers(data)
+ }
+
+ async function create(payload: TaskEffortWrite): Promise {
+ return api.post('/task_efforts', payload as Record, {
+ toastSuccessKey: 'taskEfforts.created',
+ })
+ }
+
+ async function update(id: number, payload: Partial): Promise {
+ return api.patch(`/task_efforts/${id}`, payload as Record, {
+ toastSuccessKey: 'taskEfforts.updated',
+ })
+ }
+
+ async function remove(id: number): Promise {
+ await api.delete(`/task_efforts/${id}`, {}, {
+ toastSuccessKey: 'taskEfforts.deleted',
+ })
+ }
+
+ return { getAll, create, update, remove }
+}
diff --git a/frontend/services/task-groups.ts b/frontend/services/task-groups.ts
new file mode 100644
index 0000000..6866d77
--- /dev/null
+++ b/frontend/services/task-groups.ts
@@ -0,0 +1,39 @@
+import type { TaskGroup, TaskGroupWrite } from './dto/task-group'
+import type { HydraCollection } from '~/utils/api'
+import { extractHydraMembers } from '~/utils/api'
+
+export function useTaskGroupService() {
+ const api = useApi()
+
+ async function getAll(): Promise {
+ const data = await api.get>('/task_groups')
+ return extractHydraMembers(data)
+ }
+
+ async function getByProject(projectId: number): Promise {
+ const data = await api.get>('/task_groups', {
+ project: `/api/projects/${projectId}`,
+ })
+ return extractHydraMembers(data)
+ }
+
+ async function create(payload: TaskGroupWrite): Promise {
+ return api.post('/task_groups', payload as Record, {
+ toastSuccessKey: 'taskGroups.created',
+ })
+ }
+
+ async function update(id: number, payload: Partial): Promise {
+ return api.patch(`/task_groups/${id}`, payload as Record, {
+ toastSuccessKey: 'taskGroups.updated',
+ })
+ }
+
+ async function remove(id: number): Promise {
+ await api.delete(`/task_groups/${id}`, {}, {
+ toastSuccessKey: 'taskGroups.deleted',
+ })
+ }
+
+ return { getAll, getByProject, create, update, remove }
+}
diff --git a/frontend/services/task-priorities.ts b/frontend/services/task-priorities.ts
new file mode 100644
index 0000000..963afbc
--- /dev/null
+++ b/frontend/services/task-priorities.ts
@@ -0,0 +1,32 @@
+import type { TaskPriority, TaskPriorityWrite } from './dto/task-priority'
+import type { HydraCollection } from '~/utils/api'
+import { extractHydraMembers } from '~/utils/api'
+
+export function useTaskPriorityService() {
+ const api = useApi()
+
+ async function getAll(): Promise {
+ const data = await api.get>('/task_priorities')
+ return extractHydraMembers(data)
+ }
+
+ async function create(payload: TaskPriorityWrite): Promise {
+ return api.post('/task_priorities', payload as Record, {
+ toastSuccessKey: 'taskPriorities.created',
+ })
+ }
+
+ async function update(id: number, payload: Partial): Promise {
+ return api.patch(`/task_priorities/${id}`, payload as Record, {
+ toastSuccessKey: 'taskPriorities.updated',
+ })
+ }
+
+ async function remove(id: number): Promise {
+ await api.delete(`/task_priorities/${id}`, {}, {
+ toastSuccessKey: 'taskPriorities.deleted',
+ })
+ }
+
+ return { getAll, create, update, remove }
+}
diff --git a/frontend/services/task-statuses.ts b/frontend/services/task-statuses.ts
new file mode 100644
index 0000000..28c4e06
--- /dev/null
+++ b/frontend/services/task-statuses.ts
@@ -0,0 +1,32 @@
+import type { TaskStatus, TaskStatusWrite } from './dto/task-status'
+import type { HydraCollection } from '~/utils/api'
+import { extractHydraMembers } from '~/utils/api'
+
+export function useTaskStatusService() {
+ const api = useApi()
+
+ async function getAll(): Promise {
+ const data = await api.get>('/task_statuses')
+ return extractHydraMembers(data)
+ }
+
+ async function create(payload: TaskStatusWrite): Promise {
+ return api.post('/task_statuses', payload as Record, {
+ toastSuccessKey: 'taskStatuses.created',
+ })
+ }
+
+ async function update(id: number, payload: Partial): Promise {
+ return api.patch(`/task_statuses/${id}`, payload as Record, {
+ toastSuccessKey: 'taskStatuses.updated',
+ })
+ }
+
+ async function remove(id: number): Promise {
+ await api.delete(`/task_statuses/${id}`, {}, {
+ toastSuccessKey: 'taskStatuses.deleted',
+ })
+ }
+
+ return { getAll, create, update, remove }
+}
diff --git a/frontend/services/task-types.ts b/frontend/services/task-types.ts
new file mode 100644
index 0000000..22341be
--- /dev/null
+++ b/frontend/services/task-types.ts
@@ -0,0 +1,32 @@
+import type { TaskType, TaskTypeWrite } from './dto/task-type'
+import type { HydraCollection } from '~/utils/api'
+import { extractHydraMembers } from '~/utils/api'
+
+export function useTaskTypeService() {
+ const api = useApi()
+
+ async function getAll(): Promise {
+ const data = await api.get>('/task_types')
+ return extractHydraMembers(data)
+ }
+
+ async function create(payload: TaskTypeWrite): Promise {
+ return api.post('/task_types', payload as Record, {
+ toastSuccessKey: 'taskTypes.created',
+ })
+ }
+
+ async function update(id: number, payload: Partial): Promise {
+ return api.patch(`/task_types/${id}`, payload as Record, {
+ toastSuccessKey: 'taskTypes.updated',
+ })
+ }
+
+ async function remove(id: number): Promise {
+ await api.delete(`/task_types/${id}`, {}, {
+ toastSuccessKey: 'taskTypes.deleted',
+ })
+ }
+
+ return { getAll, create, update, remove }
+}
diff --git a/frontend/services/tasks.ts b/frontend/services/tasks.ts
new file mode 100644
index 0000000..6d9e1f6
--- /dev/null
+++ b/frontend/services/tasks.ts
@@ -0,0 +1,34 @@
+import type { Task, TaskWrite } from './dto/task'
+import type { HydraCollection } from '~/utils/api'
+import { extractHydraMembers } from '~/utils/api'
+
+export function useTaskService() {
+ const api = useApi()
+
+ async function getByProject(projectId: number): Promise {
+ const data = await api.get>('/tasks', {
+ project: `/api/projects/${projectId}`,
+ })
+ return extractHydraMembers(data)
+ }
+
+ async function create(payload: TaskWrite): Promise {
+ return api.post('/tasks', payload as Record, {
+ toastSuccessKey: 'tasks.created',
+ })
+ }
+
+ async function update(id: number, payload: Partial): Promise {
+ return api.patch(`/tasks/${id}`, payload as Record, {
+ toastSuccessKey: 'tasks.updated',
+ })
+ }
+
+ async function remove(id: number): Promise {
+ await api.delete(`/tasks/${id}`, {}, {
+ toastSuccessKey: 'tasks.deleted',
+ })
+ }
+
+ return { getByProject, create, update, remove }
+}