fix(09): refresh etape counts on task delete

This commit is contained in:
Arthur Belleville 2026-05-15 23:02:05 +02:00
parent 0c95049447
commit ee62ff9f9b
No known key found for this signature in database
3 changed files with 76 additions and 2 deletions

View file

@ -366,9 +366,13 @@ func TaskDeleteHandler(deps TasksDeps) http.HandlerFunc {
}
if r.Header.Get("HX-Request") == "true" {
_, refreshedEtapes, refreshedCounts, refreshedFilter, ok := loadTasksTabData(w, r, deps.Queries, tablo)
if !ok {
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
// Return empty zone div so HTMX removes the card from the DOM (TASK-06).
_ = templates.TaskCardGone(task.ID).Render(r.Context(), w)
_ = templates.TaskCardGone(task.ID, tablo.ID, csrf.Token(r), refreshedFilter, refreshedEtapes, refreshedCounts).Render(r.Context(), w)
return
}
http.Redirect(w, r, "/tablos/"+tablo.ID.String(), http.StatusSeeOther)

View file

@ -1069,6 +1069,75 @@ func TestTaskDelete(t *testing.T) {
}
}
func TestTaskDeleteRefreshesEtapeCounts(t *testing.T) {
pool, cleanup := setupTestDB(t)
defer cleanup()
ctx := context.Background()
q := sqlc.New(pool)
store := auth.NewStore(q)
router := newTaskTestRouter(q, store)
user := preInsertUser(t, ctx, q, "taskdeletecount@example.com", "correct-horse-12")
tablo, err := q.InsertTablo(ctx, sqlc.InsertTabloParams{
UserID: user.ID,
Title: "Task Delete Count Tablo",
Description: pgtype.Text{Valid: false},
Color: pgtype.Text{Valid: false},
})
if err != nil {
t.Fatalf("InsertTablo: %v", err)
}
etape, err := q.InsertEtape(ctx, sqlc.InsertEtapeParams{
TabloID: tablo.ID,
Title: "Design",
Description: pgtype.Text{Valid: false},
Position: 100,
})
if err != nil {
t.Fatalf("InsertEtape: %v", err)
}
task, err := q.InsertTask(ctx, sqlc.InsertTaskParams{
TabloID: tablo.ID,
Title: "Delete Count",
Description: pgtype.Text{Valid: false},
Status: sqlc.TaskStatusTodo,
Position: 100,
EtapeID: pgtype.UUID{Bytes: etape.ID, Valid: true},
})
if err != nil {
t.Fatalf("InsertTask: %v", err)
}
cookieVal, _, err := store.Create(ctx, user.ID)
if err != nil {
t.Fatalf("store.Create: %v", err)
}
sessionCookie := &http.Cookie{Name: auth.SessionCookieName, Value: cookieVal}
csrfToken, csrfCookies := getCSRFToken(t, router, "/tablos/"+tablo.ID.String()+"/tasks?etape="+etape.ID.String(), []*http.Cookie{sessionCookie})
form := url.Values{"_csrf": {csrfToken}}
req := httptest.NewRequest(http.MethodPost, "/tablos/"+tablo.ID.String()+"/tasks/"+task.ID.String()+"/delete?etape="+etape.ID.String(), strings.NewReader(form.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("HX-Request", "true")
for _, c := range csrfCookies {
req.AddCookie(c)
}
rec := httptest.NewRecorder()
router.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("POST task delete status = %d; want 200", rec.Code)
}
body := rec.Body.String()
if !strings.Contains(body, `id="etape-strip"`) || !strings.Contains(body, `hx-swap-oob="outerHTML"`) {
t.Fatalf("task delete response did not include OOB etape strip refresh; body: %.800s", body)
}
if !strings.Contains(body, "Design") || !strings.Contains(body, ">0<") {
t.Fatalf("task delete response missing updated etape count; body: %.800s", body)
}
}
// ---- TestTaskOrderPersists (TASK-07) ----
// TestTaskOrderPersists verifies that after a reorder, a subsequent GET

View file

@ -382,8 +382,9 @@ templ AddTaskTrigger(tabloID uuid.UUID, status sqlc.TaskStatus, csrfToken string
// TaskCardGone renders an empty zone div with the task's id so HTMX outerHTML
// swap removes the card from the DOM after a successful delete (TASK-06).
templ TaskCardGone(taskID uuid.UUID) {
templ TaskCardGone(taskID uuid.UUID, tabloID uuid.UUID, csrfToken string, filter EtapeFilter, etapes []sqlc.Etape, counts EtapeTaskCounts) {
<div id={ "task-" + taskID.String() } class="task-card-zone"></div>
@EtapeStrip(tabloID, etapes, counts, filter, csrfToken, true)
}
// TaskCardOOB renders a new TaskCard AND an OOB swap that resets the add-task