(null);
useEffect(() => {
@@ -48,12 +51,14 @@ export const InlineTaskCreate = ({ status, members, onSubmit }: InlineTaskCreate
description: description.trim(),
assignee_id: assigneeId !== "unassigned" ? assigneeId : undefined,
status,
+ parent_task_id: etapeId !== "none" ? etapeId : undefined,
});
// Reset form
setTitle("");
setDescription("");
setAssigneeId("unassigned");
+ setEtapeId("none");
setShowAdvanced(false);
setIsCreating(false);
};
@@ -91,6 +96,27 @@ export const InlineTaskCreate = ({ status, members, onSubmit }: InlineTaskCreate
required
/>
+ {etapes.length > 0 && (
+
+
+
+
+ )}
+
{/* Advanced Options */}
{showAdvanced && (
diff --git a/apps/main/src/components/kanban/KanbanBoard.tsx b/apps/main/src/components/kanban/KanbanBoard.tsx
index c780ac5..a894c35 100644
--- a/apps/main/src/components/kanban/KanbanBoard.tsx
+++ b/apps/main/src/components/kanban/KanbanBoard.tsx
@@ -1,4 +1,5 @@
import type {
+ Etape,
KanbanColumn as KanbanColumnType,
KanbanTask,
TaskStatus,
@@ -10,6 +11,8 @@ import type { TabloMember } from "./types";
interface KanbanBoardProps {
columns: KanbanColumnType[];
members: TabloMember[];
+ etapes: Etape[];
+ etapeTitles: Record;
onTaskClick: (task: KanbanTask) => void;
onAddTask: (status: TaskStatus) => void;
onAddTaskInline: (task: {
@@ -17,6 +20,7 @@ interface KanbanBoardProps {
description: string;
assignee_id?: string;
status: TaskStatus;
+ parent_task_id?: string | null;
}) => void;
onTaskMove: (taskId: string, newStatus: TaskStatus) => void;
}
@@ -24,6 +28,7 @@ interface KanbanBoardProps {
export const KanbanBoard = ({
columns,
members,
+ etapes,
onTaskClick,
onAddTask,
onAddTaskInline,
@@ -56,6 +61,7 @@ export const KanbanBoard = ({
key={column.id}
column={column}
members={members}
+ etapes={etapes}
onTaskClick={onTaskClick}
onAddTask={onAddTask}
onAddTaskInline={onAddTaskInline}
diff --git a/apps/main/src/components/kanban/KanbanColumn.tsx b/apps/main/src/components/kanban/KanbanColumn.tsx
index 7f7c97b..dcebecc 100644
--- a/apps/main/src/components/kanban/KanbanColumn.tsx
+++ b/apps/main/src/components/kanban/KanbanColumn.tsx
@@ -1,4 +1,5 @@
import type {
+ Etape,
KanbanColumn as KanbanColumnType,
KanbanTask,
TaskStatus,
@@ -12,6 +13,7 @@ import type { TabloMember } from "./types";
interface KanbanColumnProps {
column: KanbanColumnType;
members: TabloMember[];
+ etapes: Etape[];
onTaskClick: (task: KanbanTask) => void;
onAddTask: (status: KanbanColumnType["status"]) => void;
onAddTaskInline: (task: {
@@ -19,6 +21,7 @@ interface KanbanColumnProps {
description: string;
assignee_id?: string;
status: TaskStatus;
+ parent_task_id?: string | null;
}) => void;
onDragStart: (e: React.DragEvent, task: KanbanTask) => void;
onDragOver: (e: React.DragEvent) => void;
@@ -28,6 +31,7 @@ interface KanbanColumnProps {
export const KanbanColumn = ({
column,
members,
+ etapes,
onTaskClick,
onAddTask,
onAddTaskInline,
@@ -74,7 +78,13 @@ export const KanbanColumn = ({
onDragStart={(e) => onDragStart(e, task)}
className="cursor-move"
>
- onTaskClick(task)} />
+ etape.id === task.parent_task_id)?.title ?? undefined
+ }
+ onClick={() => onTaskClick(task)}
+ />
))
)}
@@ -82,7 +92,12 @@ export const KanbanColumn = ({
{/* Inline Task Creation */}
-
+
);
diff --git a/apps/main/src/components/kanban/KanbanTaskCard.tsx b/apps/main/src/components/kanban/KanbanTaskCard.tsx
index 3d19cfe..fdd9303 100644
--- a/apps/main/src/components/kanban/KanbanTaskCard.tsx
+++ b/apps/main/src/components/kanban/KanbanTaskCard.tsx
@@ -4,10 +4,11 @@ import { User } from "lucide-react";
interface KanbanTaskCardProps {
task: KanbanTask;
+ etapeTitle?: string;
onClick: () => void;
}
-export const KanbanTaskCard = ({ task, onClick }: KanbanTaskCardProps) => {
+export const KanbanTaskCard = ({ task, etapeTitle, onClick }: KanbanTaskCardProps) => {
return (
{
)}
{/* Status Pill */}
- {task.status && (
-
-
- {task.status === "todo"
- ? "À faire"
- : task.status === "in_progress"
- ? "En cours"
- : task.status === "in_review"
- ? "En révision"
- : task.status === "done"
- ? "Terminé"
- : task.status}
-
-
- )}
+
+
+ {etapeTitle ?? "Sans Étape"}
+
+
diff --git a/apps/main/src/components/kanban/TaskModal.tsx b/apps/main/src/components/kanban/TaskModal.tsx
index 88d692c..48962db 100644
--- a/apps/main/src/components/kanban/TaskModal.tsx
+++ b/apps/main/src/components/kanban/TaskModal.tsx
@@ -1,4 +1,4 @@
-import type { TaskStatus } from "@xtablo/shared-types";
+import type { Etape, TaskStatus } from "@xtablo/shared-types";
import { Button } from "@xtablo/ui/components/button";
import { Input } from "@xtablo/ui/components/input";
import { Label } from "@xtablo/ui/components/label";
@@ -23,6 +23,7 @@ interface TaskModalProps {
onClose: () => void;
members: TabloMember[];
initialStatus?: TaskStatus;
+ etapes: Etape[];
}
export const TaskModal = ({
@@ -32,17 +33,20 @@ export const TaskModal = ({
onClose,
members,
initialStatus = "todo",
+ etapes,
}: TaskModalProps) => {
const { data: task = null } = useTask(taskId);
const [title, setTitle] = useState("");
const [description, setDescription] = useState("");
const [assigneeId, setAssigneeId] = useState("unassigned");
+ const [etapeId, setEtapeId] = useState("none");
useEffect(() => {
if (task) {
setTitle(task.title ?? "");
setDescription(task.description ?? "");
setAssigneeId(task.assignee_id ?? "unassigned");
+ setEtapeId(task.parent_task_id ?? "none");
}
}, [task]);
@@ -61,6 +65,7 @@ export const TaskModal = ({
description: description.trim(),
assignee_id: assigneeId !== "unassigned" ? assigneeId : undefined,
status: initialStatus,
+ parent_task_id: etapeId !== "none" ? etapeId : null,
});
} else {
createTask({
@@ -69,12 +74,14 @@ export const TaskModal = ({
description: description.trim(),
assignee_id: assigneeId !== "unassigned" ? assigneeId : undefined,
status: initialStatus,
+ parent_task_id: etapeId !== "none" ? etapeId : null,
});
}
// Reset form
setTitle("");
setDescription("");
setAssigneeId("unassigned");
+ setEtapeId("none");
onClose();
};
@@ -158,6 +165,26 @@ export const TaskModal = ({
+ {/* Étape */}
+ {etapes.length > 0 && (
+
+
+
+
+ )}
+
{/* Actions */}