summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-01-12 14:05:27 -1000
committerPeter Stone <thepeterstone@gmail.com>2026-01-12 14:05:27 -1000
commit9ef5b7f37883f846f105da9dc5d2ba1415e594e3 (patch)
tree7b39b9328c1b649e6bb87fba3ed6734448046afb
parente57671031d0e792926d12701aace4ffbff6a5bdf (diff)
Sort Trello boards with active boards first
Improves UX by prioritizing boards with cards over empty boards. Both API and cached results now sort consistently: non-empty boards appear first, then empty boards, with alphabetical ordering within each group. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
-rw-r--r--SESSION_STATE.md7
-rw-r--r--internal/api/trello.go11
-rw-r--r--internal/store/sqlite.go8
3 files changed, 23 insertions, 3 deletions
diff --git a/SESSION_STATE.md b/SESSION_STATE.md
index a663d91..55138c9 100644
--- a/SESSION_STATE.md
+++ b/SESSION_STATE.md
@@ -1,7 +1,7 @@
# Current Session State
## 🎯 Active Goal
-Complete security test coverage for path traversal and SQL injection fixes.
+Board sorting implementation complete.
## ✅ Completed
- Initial Phase 1 feature set (Trello, Todoist, Obsidian, PlanToEat)
@@ -25,6 +25,11 @@ Complete security test coverage for path traversal and SQL injection fixes.
- internal/api/obsidian_test.go: TestGetNotes_SymlinkSecurity validates symlink protection
- internal/store/sqlite_test.go: TestGetNotes_LimitClause validates LIMIT parameterization
- 2 new test files with 7 total test cases, all passing
+ - **Commit:** e576710 "Add security tests for path traversal and SQL injection fixes"
+- **UX Improvement:** Board sorting - non-empty boards first, then alphabetical
+ - internal/api/trello.go:220-228: Added sort logic to GetBoardsWithCards
+ - internal/store/sqlite.go:428-433: Updated SQL query to sort cached boards consistently
+ - Empty boards now pushed to bottom, active boards at top
## 🏗️ Architecture & Decisions
- **Decision:** Use SQLite for caching with a 5-minute TTL.
diff --git a/internal/api/trello.go b/internal/api/trello.go
index cecf0dc..b9391d6 100644
--- a/internal/api/trello.go
+++ b/internal/api/trello.go
@@ -6,6 +6,7 @@ import (
"fmt"
"io"
"net/http"
+ "sort"
"sync"
"time"
@@ -216,6 +217,16 @@ func (c *TrelloClient) GetBoardsWithCards(ctx context.Context) ([]models.Board,
wg.Wait()
+ // Sort boards: Non-empty boards first, then alphabetical by name
+ sort.Slice(boards, func(i, j int) bool {
+ hasCardsI := len(boards[i].Cards) > 0
+ hasCardsJ := len(boards[j].Cards) > 0
+ if hasCardsI != hasCardsJ {
+ return hasCardsI // true (non-empty) comes before false
+ }
+ return boards[i].Name < boards[j].Name
+ })
+
return boards, nil
}
diff --git a/internal/store/sqlite.go b/internal/store/sqlite.go
index e2b0aee..5063336 100644
--- a/internal/store/sqlite.go
+++ b/internal/store/sqlite.go
@@ -424,9 +424,13 @@ func (s *Store) SaveBoards(boards []models.Board) error {
// GetBoards retrieves all boards with their cards from the database
func (s *Store) GetBoards() ([]models.Board, error) {
- // Fetch boards
+ // Fetch boards, sorted by: non-empty boards first, then alphabetical
boardRows, err := s.db.Query(`
- SELECT id, name FROM boards ORDER BY name
+ SELECT b.id, b.name
+ FROM boards b
+ ORDER BY
+ CASE WHEN (SELECT COUNT(*) FROM cards c WHERE c.board_id = b.id) > 0 THEN 0 ELSE 1 END,
+ b.name
`)
if err != nil {
return nil, err