diff --git a/backend/templates/tasks.templ b/backend/templates/tasks.templ index 3883fd0..808af5f 100644 --- a/backend/templates/tasks.templ +++ b/backend/templates/tasks.templ @@ -17,10 +17,76 @@ func groupTasksByStatus(tasks []sqlc.Task) map[sqlc.TaskStatus][]sqlc.Task { return result } +// EtapeGroup holds tasks for one etape within a kanban column. +type EtapeGroup struct { + EtapeID string // "" for unassigned + EtapeTitle string // "No etape" for unassigned + EtapeColor string // "" for unassigned + Tasks []sqlc.Task +} + +// groupTasksByEtape groups tasks by etape in declaration order; unassigned last. +// Model: groupTasksByStatus above. Uses uuid.UUID(id.Bytes).String() same as taskEtapeIDString. +func groupTasksByEtape(tasks []sqlc.Task, etapes []sqlc.Etape) []EtapeGroup { + // Collect tasks per etape ID string + tasksByEtapeID := make(map[string][]sqlc.Task) + var unassigned []sqlc.Task + + for _, t := range tasks { + if !t.EtapeID.Valid { + unassigned = append(unassigned, t) + } else { + keyStr := uuid.UUID(t.EtapeID.Bytes).String() + tasksByEtapeID[keyStr] = append(tasksByEtapeID[keyStr], t) + } + } + + var groups []EtapeGroup + for _, etape := range etapes { + id := etape.ID.String() + ts := tasksByEtapeID[id] + if len(ts) == 0 { + continue + } + groups = append(groups, EtapeGroup{ + EtapeID: id, + EtapeTitle: etape.Title, + EtapeColor: "", // Etape struct has no Color field in this schema + Tasks: ts, + }) + } + + if len(unassigned) > 0 { + groups = append(groups, EtapeGroup{ + EtapeID: "", + EtapeTitle: "No etape", + EtapeColor: "", + Tasks: unassigned, + }) + } + + return groups +} + +// EtapeGroupHeader renders the sub-heading row for an etape group within a kanban column. +// "No etape" / unassigned group omits the color dot and uses muted label style. +templ EtapeGroupHeader(group EtapeGroup) { +
+ if group.EtapeColor != "" { + + } + if group.EtapeID == "" { + { group.EtapeTitle } + } else { + { group.EtapeTitle } + } +
+} + // KanbanBoard renders the outer board container with 4 columns and a hidden // reorder form. Used by TabloDetailPage below the tablo header section. // UI-SPEC §1 and D-08. -templ KanbanBoard(tabloID uuid.UUID, csrfToken string, tasks []sqlc.Task, filter EtapeFilter) { +templ KanbanBoard(tabloID uuid.UUID, csrfToken string, tasks []sqlc.Task, filter EtapeFilter, etapes []sqlc.Etape) { {{ grouped := groupTasksByStatus(tasks) }}
for _, status := range TaskColumns { - @KanbanColumn(tabloID, status, grouped[status], csrfToken, filter) + @KanbanColumn(tabloID, status, grouped[status], csrfToken, filter, etapes) }