From 0fda0e9e4b0c6a73be513987264329e4515170f1 Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Tue, 13 Jan 2026 14:04:12 -1000 Subject: Add Trello Lists support for UI dropdowns Expose Trello Lists in Board model to enable card creation UI: - Add List model struct (ID, Name) to types.go - Add Lists []List field to Board model - Add GetLists method to TrelloAPI interface - Refactor private getLists to return []models.List - Update GetCards to build list map from slice - Add public GetLists method wrapping private implementation - Update GetBoardsWithCards to populate Lists field concurrently - Update mock Trello client in tests to implement GetLists All tests pass. Boards now include their lists for UI rendering. Co-Authored-By: Claude Sonnet 4.5 --- SESSION_STATE.md | 35 +++++++++++++++++----------------- internal/api/interfaces.go | 1 + internal/api/trello.go | 38 +++++++++++++++++++++++++++---------- internal/handlers/handlers_test.go | 4 ++++ internal/models/types.go | 7 +++++++ issues/phase3_step2_trello_lists.md | 21 ++++++++++++++++++++ 6 files changed, 78 insertions(+), 28 deletions(-) create mode 100644 issues/phase3_step2_trello_lists.md diff --git a/SESSION_STATE.md b/SESSION_STATE.md index 570c987..ce4619e 100644 --- a/SESSION_STATE.md +++ b/SESSION_STATE.md @@ -1,24 +1,23 @@ # Session State -**Current Phase:** Phase 3: Interactivity & Write Operations -**Current Focus:** Step 1: Trello Write Operations +## Current Phase +Phase 3: Interactivity & Write Operations -## Active Issues -* `issues/phase3_step1_trello_write.md`: Implementing `CreateCard` and `UpdateCard` in Trello client. +## Active Task +Step 2: Trello Lists Support (Backend) -## Completed Issues -* `issues/bug_002_tab_state.md`: Fixed tab state persistence. -* `issues/bug_001_template_rendering.md`: Fixed template error in notes tab. +## Recent Completed Tasks +* [x] Phase 2.5: Glassmorphism UI (CSS/HTML) +* [x] Phase 3 Step 1: Trello Write Ops (Create/Update Card) -## Roadmap -1. **Phase 3: Interactivity** - * **Step 1: Trello Write Ops (Active)** - * Step 2: Todoist Write Ops - * Step 3: Unified Quick Add -2. **Phase 4: Security Hardening** - * Audit API keys handling. - * Rate limiting. +## 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. -## Immediate Next Steps -1. Implement `CreateCard` and `UpdateCard` in `internal/api/trello.go`. -2. Verify with `internal/api/trello_test.go`. +## 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". diff --git a/internal/api/interfaces.go b/internal/api/interfaces.go index 95cc0e7..31da0a8 100644 --- a/internal/api/interfaces.go +++ b/internal/api/interfaces.go @@ -19,6 +19,7 @@ type TodoistAPI interface { type TrelloAPI interface { GetBoards(ctx context.Context) ([]models.Board, error) GetCards(ctx context.Context, boardID string) ([]models.Card, error) + GetLists(ctx context.Context, boardID string) ([]models.List, error) GetBoardsWithCards(ctx context.Context) ([]models.Board, error) CreateCard(ctx context.Context, listID, name, description string, dueDate *time.Time) (*models.Card, error) UpdateCard(ctx context.Context, cardID string, updates map[string]interface{}) error diff --git a/internal/api/trello.go b/internal/api/trello.go index 5b87e30..9c18ade 100644 --- a/internal/api/trello.go +++ b/internal/api/trello.go @@ -128,9 +128,12 @@ func (c *TrelloClient) GetCards(ctx context.Context, boardID string) ([]models.C // Fetch lists to get list names lists, err := c.getLists(ctx, boardID) - if err != nil { - // If we can't get lists, continue with empty list names - lists = make(map[string]string) + listMap := make(map[string]string) + if err == nil { + // Build map of list ID to name + for _, list := range lists { + listMap[list.ID] = list.Name + } } // Convert to our model @@ -140,7 +143,7 @@ func (c *TrelloClient) GetCards(ctx context.Context, boardID string) ([]models.C ID: apiCard.ID, Name: apiCard.Name, ListID: apiCard.IDList, - ListName: lists[apiCard.IDList], + ListName: listMap[apiCard.IDList], URL: apiCard.URL, } @@ -158,8 +161,8 @@ func (c *TrelloClient) GetCards(ctx context.Context, boardID string) ([]models.C return cards, nil } -// getLists fetches lists for a board and returns a map of list ID to name -func (c *TrelloClient) getLists(ctx context.Context, boardID string) (map[string]string, error) { +// getLists fetches lists for a board +func (c *TrelloClient) getLists(ctx context.Context, boardID string) ([]models.List, error) { url := fmt.Sprintf("%s/boards/%s/lists?key=%s&token=%s", c.baseURL, boardID, c.apiKey, c.token) req, err := http.NewRequestWithContext(ctx, "GET", url, nil) @@ -183,15 +186,23 @@ func (c *TrelloClient) getLists(ctx context.Context, boardID string) (map[string return nil, fmt.Errorf("failed to decode response: %w", err) } - // Convert to map - lists := make(map[string]string, len(apiLists)) - for _, list := range apiLists { - lists[list.ID] = list.Name + // Convert to model + lists := make([]models.List, 0, len(apiLists)) + for _, apiList := range apiLists { + lists = append(lists, models.List{ + ID: apiList.ID, + Name: apiList.Name, + }) } return lists, nil } +// GetLists fetches lists for a specific board +func (c *TrelloClient) GetLists(ctx context.Context, boardID string) ([]models.List, error) { + return c.getLists(ctx, boardID) +} + // GetBoardsWithCards fetches all boards and their cards in one call func (c *TrelloClient) GetBoardsWithCards(ctx context.Context) ([]models.Board, error) { boards, err := c.GetBoards(ctx) @@ -211,11 +222,18 @@ func (c *TrelloClient) GetBoardsWithCards(ctx context.Context) ([]models.Board, sem <- struct{}{} defer func() { <-sem }() + // Fetch cards cards, err := c.GetCards(ctx, boards[i].ID) if err == nil { // It is safe to write to specific indices of the slice concurrently boards[i].Cards = cards } + + // Fetch lists + lists, err := c.getLists(ctx, boards[i].ID) + if err == nil { + boards[i].Lists = lists + } }(i) } diff --git a/internal/handlers/handlers_test.go b/internal/handlers/handlers_test.go index 902bebb..13973df 100644 --- a/internal/handlers/handlers_test.go +++ b/internal/handlers/handlers_test.go @@ -106,6 +106,10 @@ func (m *mockTrelloClient) GetCards(ctx context.Context, boardID string) ([]mode return []models.Card{}, nil } +func (m *mockTrelloClient) GetLists(ctx context.Context, boardID string) ([]models.List, error) { + return []models.List{}, nil +} + func (m *mockTrelloClient) CreateCard(ctx context.Context, listID, name, description string, dueDate *time.Time) (*models.Card, error) { return nil, nil } diff --git a/internal/models/types.go b/internal/models/types.go index d39a1d6..31308fc 100644 --- a/internal/models/types.go +++ b/internal/models/types.go @@ -36,11 +36,18 @@ type Meal struct { RecipeURL string `json:"recipe_url"` } +// List represents a Trello list +type List struct { + ID string `json:"id"` + Name string `json:"name"` +} + // Board represents a Trello board type Board struct { ID string `json:"id"` Name string `json:"name"` Cards []Card `json:"cards"` + Lists []List `json:"lists"` } // Card represents a Trello card diff --git a/issues/phase3_step2_trello_lists.md b/issues/phase3_step2_trello_lists.md new file mode 100644 index 0000000..f16e226 --- /dev/null +++ b/issues/phase3_step2_trello_lists.md @@ -0,0 +1,21 @@ +# Phase 3 Step 2: Trello Lists Support + +## Description +To enable "Add Card" functionality, we need to know the available lists for each board. Currently, the `Board` model does not include lists, and the API client only fetches lists internally to map names. + +## Requirements +1. **Update Models**: Add `List` struct and `Lists` field to `Board`. +2. **Update Interface**: Add `GetLists` to `TrelloAPI`. +3. **Update Client**: + * Refactor `getLists` to return `[]models.List`. + * Update `GetBoardsWithCards` to populate `board.Lists`. + * Implement public `GetLists`. + +## Plan +1. Modify `internal/models/types.go`. +2. Modify `internal/api/interfaces.go`. +3. Modify `internal/api/trello.go`. + +## Verification +* Run `go test ./internal/api/...` to ensure no regressions. +* (Implicit) The UI will eventually use this data. -- cgit v1.2.3