diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-02-06 14:53:47 -1000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-02-06 14:53:47 -1000 |
| commit | 27ee1a271248e9f1de8ecb981a6cabfa8e498b1b (patch) | |
| tree | 7a5b8555ea4199094104f3e2b1227c08a33037ed /internal/store | |
| parent | 0a1001eb0bd2d1f7c0624ae1ef8ae7ccdb3447d4 (diff) | |
Fix missing settings button, disappeared events, and tab refresh bug
- Add settings gear icon link to dashboard header
- Fix GetTasksByDateRange/GetCardsByDateRange to include overdue items
(changed from BETWEEN to <= end, filter completed tasks)
- Fix refresh replacing active tab with tasks tab by using
htmx.trigger(body, 'refresh-tasks') instead of innerHTML+htmx.process
- Add refresh-tasks hx-trigger to meals, shopping, conditions tabs
- Add tests for overdue inclusion/exclusion, settings link, template data
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/store')
| -rw-r--r-- | internal/store/sqlite.go | 15 | ||||
| -rw-r--r-- | internal/store/sqlite_test.go | 67 |
2 files changed, 73 insertions, 9 deletions
diff --git a/internal/store/sqlite.go b/internal/store/sqlite.go index 465c3c1..24a24d7 100644 --- a/internal/store/sqlite.go +++ b/internal/store/sqlite.go @@ -735,14 +735,16 @@ func (s *Store) GetShoppingItemChecks(source string) (map[string]bool, error) { return checks, rows.Err() } -// GetTasksByDateRange retrieves tasks due within a specific date range +// GetTasksByDateRange retrieves tasks due within a specific date range, +// including overdue tasks (due before start) so they appear in the timeline. func (s *Store) GetTasksByDateRange(start, end time.Time) ([]models.Task, error) { rows, err := s.db.Query(` SELECT id, content, description, project_id, project_name, due_date, priority, completed, labels, url, created_at FROM tasks - WHERE due_date BETWEEN ? AND ? + WHERE due_date IS NOT NULL AND due_date <= ? + AND completed = FALSE ORDER BY due_date ASC, priority DESC - `, start, end) + `, end) if err != nil { return nil, err } @@ -755,15 +757,16 @@ func (s *Store) GetMealsByDateRange(start, end time.Time) ([]models.Meal, error) return s.GetMeals(start, end) } -// GetCardsByDateRange retrieves cards due within a specific date range +// GetCardsByDateRange retrieves cards due within a specific date range, +// including overdue cards (due before start) so they appear in the timeline. func (s *Store) GetCardsByDateRange(start, end time.Time) ([]models.Card, error) { rows, err := s.db.Query(` SELECT c.id, c.name, b.name, c.list_id, c.list_name, c.due_date, c.url FROM cards c JOIN boards b ON c.board_id = b.id - WHERE c.due_date BETWEEN ? AND ? + WHERE c.due_date IS NOT NULL AND c.due_date <= ? ORDER BY c.due_date ASC - `, start, end) + `, end) if err != nil { return nil, err } diff --git a/internal/store/sqlite_test.go b/internal/store/sqlite_test.go index 69d188a..9c56252 100644 --- a/internal/store/sqlite_test.go +++ b/internal/store/sqlite_test.go @@ -482,17 +482,78 @@ func TestGetTasksByDateRange(t *testing.T) { t.Fatalf("Failed to save tasks: %v", err) } - // Test range covering today and tomorrow + // Test range covering today and tomorrow — should include all tasks <= end start := now.Add(-1 * time.Hour) end := tomorrow.Add(1 * time.Hour) - + results, err := store.GetTasksByDateRange(start, end) if err != nil { t.Fatalf("GetTasksByDateRange failed: %v", err) } if len(results) != 2 { - t.Errorf("Expected 2 tasks, got %d", len(results)) + t.Errorf("Expected 2 tasks (today + tomorrow, not next week), got %d", len(results)) + } +} + +func TestGetTasksByDateRange_IncludesOverdue(t *testing.T) { + store := setupTestStoreWithTasks(t) + defer func() { _ = store.Close() }() + + now := time.Now() + yesterday := now.Add(-24 * time.Hour) + tomorrow := now.Add(24 * time.Hour) + + tasks := []models.Task{ + {ID: "overdue", Content: "Overdue", DueDate: &yesterday}, + {ID: "current", Content: "Current", DueDate: &now}, + } + + if err := store.SaveTasks(tasks); err != nil { + t.Fatalf("Failed to save tasks: %v", err) + } + + // Query from "today" onward — overdue tasks (before start) should also be included + results, err := store.GetTasksByDateRange(now, tomorrow) + if err != nil { + t.Fatalf("GetTasksByDateRange failed: %v", err) + } + + if len(results) != 2 { + t.Errorf("Expected 2 tasks (overdue + current), got %d", len(results)) + for _, r := range results { + t.Logf(" task: %s due=%v", r.Content, r.DueDate) + } + } +} + +func TestGetTasksByDateRange_ExcludesCompleted(t *testing.T) { + store := setupTestStoreWithTasks(t) + defer func() { _ = store.Close() }() + + now := time.Now() + yesterday := now.Add(-24 * time.Hour) + tomorrow := now.Add(24 * time.Hour) + + tasks := []models.Task{ + {ID: "done", Content: "Completed overdue", DueDate: &yesterday, Completed: true}, + {ID: "active", Content: "Active", DueDate: &now}, + } + + if err := store.SaveTasks(tasks); err != nil { + t.Fatalf("Failed to save tasks: %v", err) + } + + results, err := store.GetTasksByDateRange(now, tomorrow) + if err != nil { + t.Fatalf("GetTasksByDateRange failed: %v", err) + } + + if len(results) != 1 { + t.Errorf("Expected 1 task (only active), got %d", len(results)) + } + if len(results) > 0 && results[0].ID != "active" { + t.Errorf("Expected active task, got %s", results[0].ID) } } |
