diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-01-13 14:04:12 -1000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-01-13 14:04:12 -1000 |
| commit | 0fda0e9e4b0c6a73be513987264329e4515170f1 (patch) | |
| tree | 046f9f903492d0a069c46b351479b652335e6fc2 /internal | |
| parent | 1c79f105c960ddab2265cbfd8dfd728630b1ebfb (diff) | |
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 <noreply@anthropic.com>
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/api/interfaces.go | 1 | ||||
| -rw-r--r-- | internal/api/trello.go | 38 | ||||
| -rw-r--r-- | internal/handlers/handlers_test.go | 4 | ||||
| -rw-r--r-- | internal/models/types.go | 7 |
4 files changed, 40 insertions, 10 deletions
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 |
