From 0c95049447625c4bb9536b123b1af4438cea8655 Mon Sep 17 00:00:00 2001 From: Arthur Belleville Date: Fri, 15 May 2026 22:59:01 +0200 Subject: [PATCH] fix(09): refresh etape counts on task create --- backend/internal/web/handlers_tasks.go | 6 +- backend/internal/web/handlers_tasks_test.go | 63 +++++++++++++++++++++ backend/templates/etapes.templ | 10 +++- backend/templates/tablos.templ | 2 +- backend/templates/tasks.templ | 3 +- 5 files changed, 79 insertions(+), 5 deletions(-) diff --git a/backend/internal/web/handlers_tasks.go b/backend/internal/web/handlers_tasks.go index e92e161..87aa021 100644 --- a/backend/internal/web/handlers_tasks.go +++ b/backend/internal/web/handlers_tasks.go @@ -302,10 +302,14 @@ func TaskCreateHandler(deps TasksDeps) http.HandlerFunc { // HTMX: set retarget/reswap headers and return combined card+OOB fragment. 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") w.Header().Set("HX-Reswap", "beforeend") w.Header().Set("HX-Retarget", "#column-"+string(status)) - _ = templates.TaskCardOOB(status, task, tablo.ID, csrf.Token(r), filter).Render(ctx, w) + _ = templates.TaskCardOOB(status, task, tablo.ID, csrf.Token(r), refreshedFilter, refreshedEtapes, refreshedCounts).Render(ctx, w) return } http.Redirect(w, r, "/tablos/"+tablo.ID.String(), http.StatusSeeOther) diff --git a/backend/internal/web/handlers_tasks_test.go b/backend/internal/web/handlers_tasks_test.go index bbc60c7..d87b660 100644 --- a/backend/internal/web/handlers_tasks_test.go +++ b/backend/internal/web/handlers_tasks_test.go @@ -167,6 +167,69 @@ func TestTaskCreate(t *testing.T) { } } +func TestTaskCreateRefreshesEtapeCounts(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, "taskcreatecount@example.com", "correct-horse-12") + tablo, err := q.InsertTablo(ctx, sqlc.InsertTabloParams{ + UserID: user.ID, + Title: "Task 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) + } + + 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{ + "title": {"Refresh Count"}, + "status": {"todo"}, + "etape_id": {etape.ID.String()}, + "_csrf": {csrfToken}, + } + req := httptest.NewRequest(http.MethodPost, "/tablos/"+tablo.ID.String()+"/tasks?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 create 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 create response did not include OOB etape strip refresh; body: %.800s", body) + } + if !strings.Contains(body, "Design") || !strings.Contains(body, ">1<") { + t.Fatalf("task create response missing updated etape count; body: %.800s", body) + } +} + // ---- TestTaskCreateValidation (TASK-02) ---- // TestTaskCreateValidation verifies that POST /tablos/{id}/tasks with an empty diff --git a/backend/templates/etapes.templ b/backend/templates/etapes.templ index d7fa261..9bf54e1 100644 --- a/backend/templates/etapes.templ +++ b/backend/templates/etapes.templ @@ -8,8 +8,14 @@ import ( "github.com/google/uuid" ) -templ EtapeStrip(tabloID uuid.UUID, etapes []sqlc.Etape, counts EtapeTaskCounts, filter EtapeFilter, csrfToken string) { -
+templ EtapeStrip(tabloID uuid.UUID, etapes []sqlc.Etape, counts EtapeTaskCounts, filter EtapeFilter, csrfToken string, oob bool) { +