summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
Diffstat (limited to 'internal')
-rw-r--r--internal/handlers/agent.go2
-rw-r--r--internal/handlers/atoms.go18
-rw-r--r--internal/handlers/handlers.go109
-rw-r--r--internal/handlers/handlers_test.go2
-rw-r--r--internal/handlers/timeline.go2
-rw-r--r--internal/handlers/timeline_logic.go56
-rw-r--r--internal/handlers/timeline_logic_test.go21
-rw-r--r--internal/models/atom.go31
-rw-r--r--internal/models/types.go1
-rw-r--r--internal/store/sqlite.go109
10 files changed, 272 insertions, 79 deletions
diff --git a/internal/handlers/agent.go b/internal/handlers/agent.go
index 6d6079f..826ffd7 100644
--- a/internal/handlers/agent.go
+++ b/internal/handlers/agent.go
@@ -326,7 +326,7 @@ func (h *Handler) HandleAgentContext(w http.ResponseWriter, r *http.Request) {
// buildAgentContext builds the context timeline by reusing BuildTimeline
func (h *Handler) buildAgentContext(ctx context.Context, start, end time.Time) []agentContextItem {
// Reuse the main BuildTimeline function (excludes live API calls for Google services)
- timelineItems, err := BuildTimeline(ctx, h.store, nil, start, end)
+ timelineItems, err := BuildTimeline(ctx, h.store, start, end)
if err != nil {
return nil
}
diff --git a/internal/handlers/atoms.go b/internal/handlers/atoms.go
index 0ebf4e6..e99c879 100644
--- a/internal/handlers/atoms.go
+++ b/internal/handlers/atoms.go
@@ -1,13 +1,14 @@
package handlers
import (
+ "log"
"sort"
"task-dashboard/internal/models"
"task-dashboard/internal/store"
)
-// BuildUnifiedAtomList creates a list of atoms from tasks and cards
+// BuildUnifiedAtomList creates a list of atoms from tasks, cards, and google tasks
func BuildUnifiedAtomList(s *store.Store) ([]models.Atom, []models.Board, error) {
tasks, err := s.GetTasks()
if err != nil {
@@ -19,7 +20,13 @@ func BuildUnifiedAtomList(s *store.Store) ([]models.Atom, []models.Board, error)
return nil, nil, err
}
- atoms := make([]models.Atom, 0, len(tasks))
+ gTasks, err := s.GetGoogleTasks()
+ if err != nil {
+ // Log but don't fail if gtasks fails (might be new/not configured)
+ log.Printf("Warning: failed to fetch cached google tasks: %v", err)
+ }
+
+ atoms := make([]models.Atom, 0, len(tasks)+len(gTasks))
// Add incomplete tasks
for _, task := range tasks {
@@ -28,6 +35,13 @@ func BuildUnifiedAtomList(s *store.Store) ([]models.Atom, []models.Board, error)
}
}
+ // Add incomplete google tasks
+ for _, gTask := range gTasks {
+ if !gTask.Completed {
+ atoms = append(atoms, models.GoogleTaskToAtom(gTask))
+ }
+ }
+
// Add cards with due dates or from actionable lists
for _, board := range boards {
for _, card := range board.Cards {
diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go
index b0fd952..8abd4d7 100644
--- a/internal/handlers/handlers.go
+++ b/internal/handlers/handlers.go
@@ -173,26 +173,6 @@ func (h *Handler) HandleGetShoppingList(w http.ResponseWriter, r *http.Request)
JSONResponse(w, items)
}
-// HandleTasksTab renders the tasks tab content (Trello + Todoist + PlanToEat)
-func (h *Handler) HandleTasksTab(w http.ResponseWriter, r *http.Request) {
- data, err := h.aggregateData(r.Context(), false)
- if err != nil {
- JSONError(w, http.StatusInternalServerError, "Failed to load tasks", err)
- return
- }
- HTMLResponse(w, h.renderer, "tasks-tab", data)
-}
-
-// HandleRefreshTab refreshes and re-renders the specified tab
-func (h *Handler) HandleRefreshTab(w http.ResponseWriter, r *http.Request) {
- data, err := h.aggregateData(r.Context(), true)
- if err != nil {
- JSONError(w, http.StatusInternalServerError, "Failed to refresh", err)
- return
- }
- HTMLResponse(w, h.renderer, "tasks-tab", data)
-}
-
// aggregateData fetches and caches data from all sources concurrently
func (h *Handler) aggregateData(ctx context.Context, forceRefresh bool) (*models.DashboardData, error) {
data := &models.DashboardData{
@@ -267,6 +247,18 @@ func (h *Handler) aggregateData(ctx context.Context, forceRefresh bool) (*models
})
}
+ if h.googleTasksClient != nil {
+ fetch("Google Tasks", func() error {
+ tasks, err := h.fetchGoogleTasks(ctx, forceRefresh)
+ if err == nil {
+ mu.Lock()
+ data.GoogleTasks = tasks
+ mu.Unlock()
+ }
+ return err
+ })
+ }
+
wg.Wait()
// Populate projects from cached tasks (avoids deprecated REST API)
@@ -392,6 +384,22 @@ func (h *Handler) fetchCalendarEvents(ctx context.Context, forceRefresh bool) ([
return fetcher.FetchWithCache(ctx, forceRefresh)
}
+// fetchGoogleTasks fetches Google Tasks from cache or API
+func (h *Handler) fetchGoogleTasks(ctx context.Context, forceRefresh bool) ([]models.GoogleTask, error) {
+ if h.googleTasksClient == nil {
+ return nil, nil
+ }
+ fetcher := &CacheFetcher[models.GoogleTask]{
+ Store: h.store,
+ CacheKey: store.CacheKeyGoogleTasks,
+ TTLMinutes: h.config.CacheTTLMinutes,
+ Fetch: func(ctx context.Context) ([]models.GoogleTask, error) { return h.googleTasksClient.GetTasks(ctx) },
+ GetFromCache: h.store.GetGoogleTasks,
+ SaveToCache: h.store.SaveGoogleTasks,
+ }
+ return fetcher.FetchWithCache(ctx, forceRefresh)
+}
+
// fetchBoards fetches Trello boards from cache or API
func (h *Handler) fetchBoards(ctx context.Context, forceRefresh bool) ([]models.Board, error) {
fetcher := &CacheFetcher[models.Board]{
@@ -684,7 +692,8 @@ func (h *Handler) HandleUnifiedAdd(w http.ResponseWriter, r *http.Request) {
switch source {
case "todoist":
- if _, err := h.todoistClient.CreateTask(ctx, title, "", dueDate, 1); err != nil {
+ projectID := r.FormValue("project_id")
+ if _, err := h.todoistClient.CreateTask(ctx, title, projectID, dueDate, 1); err != nil {
JSONError(w, http.StatusInternalServerError, "Failed to create Todoist task", err)
return
}
@@ -805,7 +814,7 @@ func (h *Handler) HandleUpdateTask(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}
-// HandleTabTasks renders the unified Tasks tab (Todoist + Trello cards with due dates + Bugs)
+// HandleTabTasks renders the unified Tasks tab (Todoist + Trello cards with due dates + Bugs + Google Tasks)
func (h *Handler) HandleTabTasks(w http.ResponseWriter, r *http.Request) {
atoms, boards, err := BuildUnifiedAtomList(h.store)
if err != nil {
@@ -816,15 +825,19 @@ func (h *Handler) HandleTabTasks(w http.ResponseWriter, r *http.Request) {
SortAtomsByUrgency(atoms)
currentAtoms, futureAtoms := PartitionAtomsByTime(atoms)
+ projects, _ := h.store.GetProjectsFromTasks()
+
data := struct {
Atoms []models.Atom
FutureAtoms []models.Atom
Boards []models.Board
+ Projects []models.Project
Today string
}{
Atoms: currentAtoms,
FutureAtoms: futureAtoms,
Boards: boards,
+ Projects: projects,
Today: config.Now().Format("2006-01-02"),
}
@@ -839,6 +852,7 @@ func (h *Handler) HandleTabPlanning(w http.ResponseWriter, r *http.Request) {
boards, _ := h.store.GetBoards()
tasks, _ := h.store.GetTasks()
+ gTasks, _ := h.store.GetGoogleTasks()
events, _ := h.fetchCalendarEvents(r.Context(), false)
@@ -941,21 +955,72 @@ func (h *Handler) HandleTabPlanning(w http.ResponseWriter, r *http.Request) {
}
}
+ for _, gTask := range gTasks {
+ if gTask.Completed {
+ continue
+ }
+
+ if gTask.DueDate == nil {
+ atom := models.GoogleTaskToAtom(gTask)
+ atom.ComputeUIFields()
+ unscheduled = append(unscheduled, atom)
+ continue
+ }
+
+ dueDate := *gTask.DueDate
+ // Google Tasks usually don't have times, but if they did we'd handle them here
+ hasTime := dueDate.Hour() != 0 || dueDate.Minute() != 0
+
+ if dueDate.Before(tomorrow) {
+ if hasTime {
+ scheduled = append(scheduled, ScheduledItem{
+ Type: "task",
+ ID: gTask.ID,
+ Title: gTask.Title,
+ Start: dueDate,
+ URL: gTask.URL,
+ Source: "gtasks",
+ SourceIcon: "🔵",
+ Priority: 2,
+ })
+ } else {
+ atom := models.GoogleTaskToAtom(gTask)
+ atom.ComputeUIFields()
+ unscheduled = append(unscheduled, atom)
+ }
+ } else if dueDate.Before(in3Days) {
+ upcoming = append(upcoming, ScheduledItem{
+ Type: "task",
+ ID: gTask.ID,
+ Title: gTask.Title,
+ Start: dueDate,
+ URL: gTask.URL,
+ Source: "gtasks",
+ SourceIcon: "🔵",
+ Priority: 2,
+ })
+ }
+ }
+
sort.Slice(scheduled, func(i, j int) bool { return scheduled[i].Start.Before(scheduled[j].Start) })
sort.Slice(unscheduled, func(i, j int) bool { return unscheduled[i].Priority > unscheduled[j].Priority })
sort.Slice(upcoming, func(i, j int) bool { return upcoming[i].Start.Before(upcoming[j].Start) })
+ projects, _ := h.store.GetProjectsFromTasks()
+
data := struct {
Scheduled []ScheduledItem
Unscheduled []models.Atom
Upcoming []ScheduledItem
Boards []models.Board
+ Projects []models.Project
Today string
}{
Scheduled: scheduled,
Unscheduled: unscheduled,
Upcoming: upcoming,
Boards: boards,
+ Projects: projects,
Today: today.Format("2006-01-02"),
}
diff --git a/internal/handlers/handlers_test.go b/internal/handlers/handlers_test.go
index 0d097c8..105641a 100644
--- a/internal/handlers/handlers_test.go
+++ b/internal/handlers/handlers_test.go
@@ -2818,6 +2818,7 @@ func TestHandleTabPlanning_HappyPath(t *testing.T) {
Unscheduled []models.Atom
Upcoming []ScheduledItem
Boards []models.Board
+ Projects []models.Project
Today string
})
if !ok {
@@ -2910,6 +2911,7 @@ func TestHandleTabPlanning_TomorrowBoundary(t *testing.T) {
Unscheduled []models.Atom
Upcoming []ScheduledItem
Boards []models.Board
+ Projects []models.Project
Today string
})
if !ok {
diff --git a/internal/handlers/timeline.go b/internal/handlers/timeline.go
index 86b89ea..bbdae51 100644
--- a/internal/handlers/timeline.go
+++ b/internal/handlers/timeline.go
@@ -70,7 +70,7 @@ func (h *Handler) HandleTimeline(w http.ResponseWriter, r *http.Request) {
}
// Call BuildTimeline
- items, err := BuildTimeline(r.Context(), h.store, h.googleTasksClient, start, end)
+ items, err := BuildTimeline(r.Context(), h.store, start, end)
if err != nil {
JSONError(w, http.StatusInternalServerError, "Failed to build timeline", err)
return
diff --git a/internal/handlers/timeline_logic.go b/internal/handlers/timeline_logic.go
index 145e851..8430ee9 100644
--- a/internal/handlers/timeline_logic.go
+++ b/internal/handlers/timeline_logic.go
@@ -7,14 +7,13 @@ import (
"strings"
"time"
- "task-dashboard/internal/api"
"task-dashboard/internal/config"
"task-dashboard/internal/models"
"task-dashboard/internal/store"
)
// BuildTimeline aggregates and normalizes data into a timeline structure
-func BuildTimeline(ctx context.Context, s *store.Store, tasksClient api.GoogleTasksAPI, start, end time.Time) ([]models.TimelineItem, error) {
+func BuildTimeline(ctx context.Context, s *store.Store, start, end time.Time) ([]models.TimelineItem, error) {
var items []models.TimelineItem
now := config.Now()
@@ -145,37 +144,32 @@ func BuildTimeline(ctx context.Context, s *store.Store, tasksClient api.GoogleTa
}
}
- // 5. Fetch Google Tasks
- if tasksClient != nil {
- gTasks, err := tasksClient.GetTasksByDateRange(ctx, start, end)
- if err != nil {
- log.Printf("Warning: failed to fetch Google Tasks: %v", err)
- } else {
- log.Printf("Google Tasks: fetched %d tasks in date range", len(gTasks))
- for _, gTask := range gTasks {
- // Tasks without due date are placed in today section
- taskTime := now
- if gTask.DueDate != nil {
- taskTime = *gTask.DueDate
- }
- item := models.TimelineItem{
- ID: gTask.ID,
- Type: models.TimelineItemTypeGTask,
- Title: gTask.Title,
- Time: taskTime,
- Description: gTask.Notes,
- URL: gTask.URL,
- OriginalItem: gTask,
- IsCompleted: gTask.Completed,
- Source: "gtasks",
- ListID: gTask.ListID,
- }
- item.ComputeDaySection(now)
- items = append(items, item)
+ // 5. Fetch Google Tasks from store cache
+ gTasks, err := s.GetGoogleTasksByDateRange(start, end)
+ if err != nil {
+ log.Printf("Warning: failed to read cached Google Tasks: %v", err)
+ } else {
+ for _, gTask := range gTasks {
+ // Tasks without due date are placed in today section
+ taskTime := now
+ if gTask.DueDate != nil {
+ taskTime = *gTask.DueDate
+ }
+ item := models.TimelineItem{
+ ID: gTask.ID,
+ Type: models.TimelineItemTypeGTask,
+ Title: gTask.Title,
+ Time: taskTime,
+ Description: gTask.Notes,
+ URL: gTask.URL,
+ OriginalItem: gTask,
+ IsCompleted: gTask.Completed,
+ Source: "gtasks",
+ ListID: gTask.ListID,
}
+ item.ComputeDaySection(now)
+ items = append(items, item)
}
- } else {
- log.Printf("Google Tasks client not configured")
}
// Sort items by Time
diff --git a/internal/handlers/timeline_logic_test.go b/internal/handlers/timeline_logic_test.go
index 8104a96..d6959da 100644
--- a/internal/handlers/timeline_logic_test.go
+++ b/internal/handlers/timeline_logic_test.go
@@ -90,6 +90,17 @@ func setupTestStore(t *testing.T) *store.Store {
html_link TEXT,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
+ CREATE TABLE IF NOT EXISTS google_tasks (
+ id TEXT PRIMARY KEY,
+ title TEXT NOT NULL,
+ notes TEXT,
+ status TEXT NOT NULL,
+ completed BOOLEAN NOT NULL DEFAULT 0,
+ due_date DATETIME,
+ updated_at DATETIME,
+ list_id TEXT NOT NULL,
+ url TEXT
+ );
`
if err := os.WriteFile(filepath.Join(migrationDir, "001_init.sql"), []byte(schema), 0644); err != nil {
t.Fatalf("Failed to write migration file: %v", err)
@@ -143,7 +154,7 @@ func TestBuildTimeline(t *testing.T) {
start := time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)
end := time.Date(2023, 1, 2, 0, 0, 0, 0, time.UTC)
- items, err := BuildTimeline(context.Background(), s, nil, start, end)
+ items, err := BuildTimeline(context.Background(), s, start, end)
if err != nil {
t.Fatalf("BuildTimeline failed: %v", err)
}
@@ -277,7 +288,7 @@ func TestBuildTimeline_IncludesOverdueItems(t *testing.T) {
// Query range: today through tomorrow
end := today.AddDate(0, 0, 1)
- items, err := BuildTimeline(context.Background(), s, nil,today, end)
+ items, err := BuildTimeline(context.Background(), s, today, end)
if err != nil {
t.Fatalf("BuildTimeline failed: %v", err)
}
@@ -320,7 +331,7 @@ func TestBuildTimeline_ExcludesCompletedOverdue(t *testing.T) {
{ID: "done1", Content: "Done overdue", DueDate: &yesterday, Completed: true},
})
- items, err := BuildTimeline(context.Background(), s, nil,today, end)
+ items, err := BuildTimeline(context.Background(), s, today, end)
if err != nil {
t.Fatalf("BuildTimeline failed: %v", err)
}
@@ -348,7 +359,7 @@ func TestBuildTimeline_ReadsCalendarEventsFromStore(t *testing.T) {
}
// Call BuildTimeline with NO calendar client (nil) — events should come from store
- items, err := BuildTimeline(context.Background(), s, nil,start, end)
+ items, err := BuildTimeline(context.Background(), s, start, end)
if err != nil {
t.Fatalf("BuildTimeline failed: %v", err)
}
@@ -473,7 +484,7 @@ func TestBuildTimeline_IncludesUndatedTodoistTasks(t *testing.T) {
start := time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)
end := time.Date(2023, 1, 2, 0, 0, 0, 0, time.UTC)
- items, err := BuildTimeline(context.Background(), s, nil, start, end)
+ items, err := BuildTimeline(context.Background(), s, start, end)
if err != nil {
t.Fatalf("BuildTimeline failed: %v", err)
}
diff --git a/internal/models/atom.go b/internal/models/atom.go
index 3745917..767ccdd 100644
--- a/internal/models/atom.go
+++ b/internal/models/atom.go
@@ -12,6 +12,7 @@ const (
SourceTrello AtomSource = "trello"
SourceTodoist AtomSource = "todoist"
SourceMeal AtomSource = "plantoeat"
+ SourceGTasks AtomSource = "gtasks"
)
type AtomType string
@@ -122,24 +123,24 @@ func CardToAtom(c Card) Atom {
}
}
-// MealToAtom converts a PlanToEat Meal to an Atom
-func MealToAtom(m Meal) Atom {
- // Meals don't have priority, default to low (1)
- priority := 1
+// GoogleTaskToAtom converts a Google Task to an Atom
+func GoogleTaskToAtom(t GoogleTask) Atom {
+ // Google Tasks don't have explicit priority, default to medium (2)
+ priority := 2
return Atom{
- ID: m.ID,
- Title: m.RecipeName,
- Description: m.MealType, // breakfast, lunch, dinner
- Source: SourceMeal,
- Type: TypeMeal,
- URL: m.RecipeURL,
- DueDate: &m.Date, // Meal date is effectively the "due date"
- CreatedAt: time.Time{},
+ ID: t.ID,
+ Title: t.Title,
+ Description: t.Notes,
+ Source: SourceGTasks,
+ Type: TypeTask,
+ URL: t.URL,
+ DueDate: t.DueDate,
+ CreatedAt: t.UpdatedAt,
Priority: priority,
- SourceIcon: "🍽️", // Fork and knife emoji for meals
- ColorClass: "border-green-500",
- Raw: m,
+ SourceIcon: "🔵", // Blue circle for Google Tasks
+ ColorClass: "border-blue-400",
+ Raw: t,
}
}
diff --git a/internal/models/types.go b/internal/models/types.go
index 194eca9..0b025ce 100644
--- a/internal/models/types.go
+++ b/internal/models/types.go
@@ -175,6 +175,7 @@ func (cm *CacheMetadata) IsCacheValid() bool {
// DashboardData aggregates all data for the main view
type DashboardData struct {
Tasks []Task `json:"tasks"`
+ GoogleTasks []GoogleTask `json:"google_tasks,omitempty"`
Meals []Meal `json:"meals"`
Boards []Board `json:"boards,omitempty"`
TrelloTasks []Card `json:"trello_tasks,omitempty"`
diff --git a/internal/store/sqlite.go b/internal/store/sqlite.go
index 3879395..f9c9a6b 100644
--- a/internal/store/sqlite.go
+++ b/internal/store/sqlite.go
@@ -23,6 +23,7 @@ const (
CacheKeyTrelloBoards = "trello_boards"
CacheKeyPlanToEatMeals = "plantoeat_meals"
CacheKeyGoogleCalendar = "google_calendar"
+ CacheKeyGoogleTasks = "google_tasks"
)
type Store struct {
@@ -867,6 +868,110 @@ func (s *Store) GetCalendarEventsByDateRange(start, end time.Time) ([]models.Cal
return events, rows.Err()
}
+// Google Tasks operations
+
+// SaveGoogleTasks replaces all cached Google Tasks
+func (s *Store) SaveGoogleTasks(tasks []models.GoogleTask) error {
+ tx, err := s.db.Begin()
+ if err != nil {
+ return err
+ }
+ defer func() { _ = tx.Rollback() }()
+
+ if _, err := tx.Exec(`DELETE FROM google_tasks`); err != nil {
+ return err
+ }
+
+ stmt, err := tx.Prepare(`
+ INSERT INTO google_tasks (id, title, notes, status, completed, due_date, updated_at, list_id, url)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
+ `)
+ if err != nil {
+ return err
+ }
+ defer func() { _ = stmt.Close() }()
+
+ for _, t := range tasks {
+ _, err = stmt.Exec(t.ID, t.Title, t.Notes, t.Status, t.Completed, t.DueDate, t.UpdatedAt, t.ListID, t.URL)
+ if err != nil {
+ return err
+ }
+ }
+
+ return tx.Commit()
+}
+
+// GetGoogleTasks retrieves all cached Google Tasks
+func (s *Store) GetGoogleTasks() ([]models.GoogleTask, error) {
+ rows, err := s.db.Query(`
+ SELECT id, title, notes, status, completed, due_date, updated_at, list_id, url
+ FROM google_tasks
+ ORDER BY completed ASC, CASE WHEN due_date IS NULL THEN 1 ELSE 0 END, due_date ASC
+ `)
+ if err != nil {
+ return nil, err
+ }
+ defer func() { _ = rows.Close() }()
+
+ var tasks []models.GoogleTask
+ for rows.Next() {
+ var t models.GoogleTask
+ var dueDate, updatedAt sql.NullTime
+
+ err := rows.Scan(&t.ID, &t.Title, &t.Notes, &t.Status, &t.Completed, &dueDate, &updatedAt, &t.ListID, &t.URL)
+ if err != nil {
+ return nil, err
+ }
+
+ if dueDate.Valid {
+ t.DueDate = &dueDate.Time
+ }
+ if updatedAt.Valid {
+ t.UpdatedAt = updatedAt.Time
+ }
+
+ tasks = append(tasks, t)
+ }
+
+ return tasks, rows.Err()
+}
+
+// GetGoogleTasksByDateRange retrieves cached Google Tasks in a date range
+func (s *Store) GetGoogleTasksByDateRange(start, end time.Time) ([]models.GoogleTask, error) {
+ rows, err := s.db.Query(`
+ SELECT id, title, notes, status, completed, due_date, updated_at, list_id, url
+ FROM google_tasks
+ WHERE due_date IS NULL OR (due_date >= ? AND due_date < ?)
+ ORDER BY completed ASC, CASE WHEN due_date IS NULL THEN 1 ELSE 0 END, due_date ASC
+ `, start, end)
+ if err != nil {
+ return nil, err
+ }
+ defer func() { _ = rows.Close() }()
+
+ var tasks []models.GoogleTask
+ for rows.Next() {
+ var t models.GoogleTask
+ var dueDate, updatedAt sql.NullTime
+
+ err := rows.Scan(&t.ID, &t.Title, &t.Notes, &t.Status, &t.Completed, &dueDate, &updatedAt, &t.ListID, &t.URL)
+ if err != nil {
+ return nil, err
+ }
+
+ if dueDate.Valid {
+ t.DueDate = &dueDate.Time
+ }
+ if updatedAt.Valid {
+ t.UpdatedAt = updatedAt.Time
+ }
+
+ tasks = append(tasks, t)
+ }
+
+ return tasks, rows.Err()
+}
+
// Agent operations
// CreateAgentSession creates a new pending agent session
@@ -1403,8 +1508,8 @@ func (s *Store) SyncSourceConfigs(source, itemType string, items []models.Source
// InvalidateAllCaches removes cache metadata for all known cache keys
func (s *Store) InvalidateAllCaches() error {
- _, err := s.db.Exec(`DELETE FROM cache_metadata WHERE key IN (?, ?, ?, ?)`,
- CacheKeyTodoistTasks, CacheKeyTrelloBoards, CacheKeyPlanToEatMeals, CacheKeyGoogleCalendar)
+ _, err := s.db.Exec(`DELETE FROM cache_metadata WHERE key IN (?, ?, ?, ?, ?)`,
+ CacheKeyTodoistTasks, CacheKeyTrelloBoards, CacheKeyPlanToEatMeals, CacheKeyGoogleCalendar, CacheKeyGoogleTasks)
return err
}