From 2fee76ea41f37e3a068273c05a98b892ab29228c Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Tue, 13 Jan 2026 14:09:50 -1000 Subject: Add Trello card creation and completion UI (Phase 3 Step 3) Implement interactive Trello card management with HTMX: Frontend: - Create trello-board.html partial with add card form - Add collapsible form with list selector and card title input - Add completion checkbox on each card - Update trello-boards.html to use new partial - Use HTMX for seamless partial updates (hx-post, hx-swap) Backend: - Add HandleCreateCard: creates card and re-renders board - Add HandleCompleteCard: marks card as closed - Register /cards and /cards/complete POST routes Features: - Add cards to any list via dropdown - Mark cards complete with checkbox (removes from view) - Real-time board updates without full page reload - Glassmorphism styling for form All tests pass. Full Trello write operations now available in UI. Co-Authored-By: Claude Sonnet 4.5 --- SESSION_STATE.md | 33 ++++++------ cmd/dashboard/main.go | 4 ++ internal/handlers/handlers.go | 90 +++++++++++++++++++++++++++++++ issues/phase3_step3_trello_ui.md | 36 +++++++++++++ web/templates/partials/trello-board.html | 82 ++++++++++++++++++++++++++++ web/templates/partials/trello-boards.html | 29 +--------- 6 files changed, 231 insertions(+), 43 deletions(-) create mode 100644 issues/phase3_step3_trello_ui.md create mode 100644 web/templates/partials/trello-board.html diff --git a/SESSION_STATE.md b/SESSION_STATE.md index ce4619e..7fd2eaa 100644 --- a/SESSION_STATE.md +++ b/SESSION_STATE.md @@ -1,23 +1,26 @@ # Session State -## Current Phase -Phase 3: Interactivity & Write Operations +**Current Phase:** Phase 3: Interactivity & Write Operations +**Current Step:** Step 3: Trello UI & Handlers -## Active Task -Step 2: Trello Lists Support (Backend) +## Active Issues +* `issues/phase3_step3_trello_ui.md` (In Progress) -## Recent Completed Tasks -* [x] Phase 2.5: Glassmorphism UI (CSS/HTML) -* [x] Phase 3 Step 1: Trello Write Ops (Create/Update Card) +## Completed Issues +* `issues/bug_002_tab_state.md` (Resolved) +* `issues/bug_001_template_rendering.md` (Resolved) +* `issues/phase3_step1_trello_write.md` (Resolved) +* `issues/phase3_step2_trello_lists.md` (Resolved) + +## Recent Changes +* **Trello API:** Implemented `CreateCard` and `UpdateCard`. +* **Trello Lists:** Added `Lists` support to Board model and API. +* **UI:** Glassmorphism overhaul (Phase 2.5) completed. ## Next Steps -1. **Implement Trello Lists Support** (Current) - * Update models and API client to fetch and expose lists. -2. **Trello UI Integration** - * Add "Add Card" button and modal. - * Add "Done" checkbox. -3. **Todoist Write Ops** - * Implement Create/Complete Task. +1. **Implement Trello UI:** Create partials and handlers for adding/completing cards. +2. **Todoist Write Ops:** Implement `CreateTask` and `CompleteTask`. +3. **Unified Quick Add:** Implement global command bar. ## Context -We are adding write capabilities. We just implemented `CreateCard` and `UpdateCard` in the Trello client. Now we need to expose the Lists so the UI can present a dropdown for "Add Card". +We are turning the read-only dashboard into an interactive tool. We just finished the backend plumbing for Trello (Write Ops + List fetching). Now we are connecting it to the frontend. diff --git a/cmd/dashboard/main.go b/cmd/dashboard/main.go index 3f46e8d..a307484 100644 --- a/cmd/dashboard/main.go +++ b/cmd/dashboard/main.go @@ -77,6 +77,10 @@ func main() { r.Get("/tabs/meals", tabsHandler.HandleMeals) r.Post("/tabs/refresh", h.HandleRefreshTab) + // Trello card operations + r.Post("/cards", h.HandleCreateCard) + r.Post("/cards/complete", h.HandleCompleteCard) + // Serve static files fileServer := http.FileServer(http.Dir("web/static")) r.Handle("/static/*", http.StripPrefix("/static/", fileServer)) diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go index ed100fc..8762035 100644 --- a/internal/handlers/handlers.go +++ b/internal/handlers/handlers.go @@ -438,3 +438,93 @@ func (h *Handler) fetchBoards(ctx context.Context, forceRefresh bool) ([]models. return boards, nil } + +// HandleCreateCard creates a new Trello card +func (h *Handler) HandleCreateCard(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + // Parse form data + if err := r.ParseForm(); err != nil { + http.Error(w, "Failed to parse form", http.StatusBadRequest) + log.Printf("Error parsing form: %v", err) + return + } + + boardID := r.FormValue("board_id") + listID := r.FormValue("list_id") + name := r.FormValue("name") + + if boardID == "" || listID == "" || name == "" { + http.Error(w, "Missing required fields", http.StatusBadRequest) + return + } + + // Create the card + _, err := h.trelloClient.CreateCard(ctx, listID, name, "", nil) + if err != nil { + http.Error(w, "Failed to create card", http.StatusInternalServerError) + log.Printf("Error creating card: %v", err) + return + } + + // Force refresh to get updated data + data, err := h.aggregateData(ctx, true) + if err != nil { + http.Error(w, "Failed to refresh data", http.StatusInternalServerError) + log.Printf("Error refreshing data: %v", err) + return + } + + // Find the specific board + var targetBoard *models.Board + for i := range data.Boards { + if data.Boards[i].ID == boardID { + targetBoard = &data.Boards[i] + break + } + } + + if targetBoard == nil { + http.Error(w, "Board not found", http.StatusNotFound) + return + } + + // Render the updated board + if err := h.templates.ExecuteTemplate(w, "trello-board", targetBoard); err != nil { + http.Error(w, "Failed to render template", http.StatusInternalServerError) + log.Printf("Error rendering board template: %v", err) + } +} + +// HandleCompleteCard marks a Trello card as complete +func (h *Handler) HandleCompleteCard(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + // Parse form data + if err := r.ParseForm(); err != nil { + http.Error(w, "Failed to parse form", http.StatusBadRequest) + log.Printf("Error parsing form: %v", err) + return + } + + cardID := r.FormValue("card_id") + + if cardID == "" { + http.Error(w, "Missing card_id", http.StatusBadRequest) + return + } + + // Mark card as closed (complete) + updates := map[string]interface{}{ + "closed": true, + } + + if err := h.trelloClient.UpdateCard(ctx, cardID, updates); err != nil { + http.Error(w, "Failed to complete card", http.StatusInternalServerError) + log.Printf("Error completing card: %v", err) + return + } + + // Return empty response (card will be removed from DOM) + w.WriteHeader(http.StatusOK) +} diff --git a/issues/phase3_step3_trello_ui.md b/issues/phase3_step3_trello_ui.md new file mode 100644 index 0000000..92dd8a5 --- /dev/null +++ b/issues/phase3_step3_trello_ui.md @@ -0,0 +1,36 @@ +# Phase 3 Step 3: Trello UI & Handlers + +**Status:** Open +**Priority:** High +**Created:** 2024-05-22 + +## Description +Implement the UI and backend handlers to enable creating and completing Trello cards directly from the dashboard. + +## Requirements + +### 1. UI Updates +* **Refactor:** Extract individual board rendering into a new partial `web/templates/partials/trello-board.html`. +* **Add Card:** Add a "Quick Add" form to each board (using `
` for simplicity) that allows selecting a List and entering a Name. +* **Complete Card:** Add a checkbox to each card that marks it as complete (archives/closes it). + +### 2. Backend Handlers +* `HandleCreateCard`: + * POST `/cards` + * Params: `board_id`, `list_id`, `name` + * Action: Call `CreateCard` API. + * Response: Re-render the specific board partial with updated data. +* `HandleCompleteCard`: + * POST `/cards/complete` + * Params: `card_id` + * Action: Call `UpdateCard` API (set `closed=true`). + * Response: Empty string (removes the card from UI via HTMX). + +### 3. Routing +* Register the new routes in `cmd/dashboard/main.go`. + +## Implementation Plan +1. Create `web/templates/partials/trello-board.html`. +2. Update `web/templates/partials/trello-boards.html`. +3. Implement handlers in `internal/handlers/handlers.go`. +4. Register routes in `cmd/dashboard/main.go`. diff --git a/web/templates/partials/trello-board.html b/web/templates/partials/trello-board.html new file mode 100644 index 0000000..0b176cd --- /dev/null +++ b/web/templates/partials/trello-board.html @@ -0,0 +1,82 @@ +{{define "trello-board"}} +
+ +
+

{{.Name}}

+
+ + + {{if .Lists}} +
+ + + Add Card + +
+ + + + + + + +
+
+ {{end}} + + +
+ {{range .Cards}} +
+
+ + + +
+

{{.Name}}

+
+ {{if .ListName}} + + {{.ListName}} + + {{end}} + {{if .DueDate}} + + Due: {{.DueDate.Format "Jan 2"}} + + {{end}} + {{if .URL}} + + View → + + {{end}} +
+
+
+
+ {{end}} +
+
+{{end}} diff --git a/web/templates/partials/trello-boards.html b/web/templates/partials/trello-boards.html index bd460cf..3d42517 100644 --- a/web/templates/partials/trello-boards.html +++ b/web/templates/partials/trello-boards.html @@ -11,34 +11,7 @@
{{range .Boards}} {{if .Cards}} -
-

{{.Name}}

-
- {{range .Cards}} -
-

{{.Name}}

-
- {{if .ListName}} - - {{.ListName}} - - {{end}} - {{if .DueDate}} - - Due: {{.DueDate.Format "Jan 2"}} - - {{end}} - {{if .URL}} - - View → - - {{end}} -
-
- {{end}} -
-
+ {{template "trello-board" .}} {{end}} {{end}}
-- cgit v1.2.3