summaryrefslogtreecommitdiff
path: root/internal/handlers
diff options
context:
space:
mode:
Diffstat (limited to 'internal/handlers')
-rw-r--r--internal/handlers/agent.go101
-rw-r--r--internal/handlers/handlers.go28
2 files changed, 98 insertions, 31 deletions
diff --git a/internal/handlers/agent.go b/internal/handlers/agent.go
index 6f47524..92f4ce8 100644
--- a/internal/handlers/agent.go
+++ b/internal/handlers/agent.go
@@ -51,6 +51,15 @@ type agentContextItem struct {
Priority int `json:"priority,omitempty"`
Completable bool `json:"completable"`
URL string `json:"url,omitempty"`
+ DaySection string `json:"day_section,omitempty"` // "overdue", "today", "tomorrow", "later"
+}
+
+// agentCompletedItem represents a completed task in the log
+type agentCompletedItem struct {
+ Source string `json:"source"`
+ Title string `json:"title"`
+ DueDate *time.Time `json:"due_date,omitempty"`
+ CompletedAt time.Time `json:"completed_at"`
}
// -----------------------------------------------------------------------------
@@ -83,6 +92,7 @@ func timelineItemToAgentItem(item models.TimelineItem) agentContextItem {
Due: &t,
Completable: item.Type == models.TimelineItemTypeTask || item.Type == models.TimelineItemTypeCard || item.Type == models.TimelineItemTypeGTask,
URL: item.URL,
+ DaySection: string(item.DaySection),
}
}
@@ -285,10 +295,14 @@ func (h *Handler) HandleAgentContext(w http.ResponseWriter, r *http.Request) {
_ = h.store.UpdateAgentLastSeen(session.AgentID)
now := config.Now()
- startDate := config.Today()
- endDate := startDate.Add(7 * 24 * time.Hour)
+ today := config.Today()
+ // Extend range: 7 days back (overdue) to 14 days forward
+ startDate := today.Add(-7 * 24 * time.Hour)
+ endDate := today.Add(14 * 24 * time.Hour)
- timeline := h.buildAgentContext(r.Context(), startDate, endDate)
+ ctx := r.Context()
+ timeline := h.buildAgentContext(ctx, startDate, endDate)
+ completedLog := h.buildCompletedLog(50) // Last 50 completed tasks
resp := map[string]interface{}{
"generated_at": now.Format(time.RFC3339),
@@ -296,8 +310,9 @@ func (h *Handler) HandleAgentContext(w http.ResponseWriter, r *http.Request) {
"start": startDate.Format("2006-01-02"),
"end": endDate.Format("2006-01-02"),
},
- "timeline": timeline,
- "summary": h.buildContextSummary(timeline, startDate),
+ "timeline": timeline,
+ "completed_log": completedLog,
+ "summary": h.buildContextSummary(timeline, today),
}
w.Header().Set("Content-Type", "application/json")
@@ -326,16 +341,18 @@ func (h *Handler) buildAgentContext(ctx context.Context, start, end time.Time) [
// buildContextSummary builds summary statistics for the agent context
func (h *Handler) buildContextSummary(items []agentContextItem, today time.Time) map[string]interface{} {
bySource := make(map[string]int)
- var overdue, todayCount int
+ bySection := make(map[string]int)
endOfToday := today.Add(24 * time.Hour)
for _, item := range items {
bySource[item.Source]++
- if item.Due != nil {
+ if item.DaySection != "" {
+ bySection[item.DaySection]++
+ } else if item.Due != nil {
if item.Due.Before(today) {
- overdue++
+ bySection["overdue"]++
} else if item.Due.Before(endOfToday) {
- todayCount++
+ bySection["today"]++
}
}
}
@@ -343,9 +360,27 @@ func (h *Handler) buildContextSummary(items []agentContextItem, today time.Time)
return map[string]interface{}{
"total_items": len(items),
"by_source": bySource,
- "overdue": overdue,
- "today": todayCount,
+ "by_section": bySection,
+ }
+}
+
+// buildCompletedLog retrieves recently completed tasks
+func (h *Handler) buildCompletedLog(limit int) []agentCompletedItem {
+ completed, err := h.store.GetCompletedTasks(limit)
+ if err != nil {
+ return nil
+ }
+
+ items := make([]agentCompletedItem, len(completed))
+ for i, c := range completed {
+ items[i] = agentCompletedItem{
+ Source: c.Source,
+ Title: c.Title,
+ DueDate: c.DueDate,
+ CompletedAt: c.CompletedAt,
+ }
}
+ return items
}
// -----------------------------------------------------------------------------
@@ -489,11 +524,15 @@ func (h *Handler) HandleAgentWebContext(w http.ResponseWriter, r *http.Request)
_ = h.store.UpdateAgentLastSeen(session.AgentID)
now := config.Now()
- startDate := config.Today()
- endDate := startDate.Add(7 * 24 * time.Hour)
+ today := config.Today()
+ startDate := today.Add(-7 * 24 * time.Hour)
+ endDate := today.Add(14 * 24 * time.Hour)
- timeline := h.buildAgentContext(r.Context(), startDate, endDate)
- h.renderAgentContext(w, session, timeline, startDate, endDate, now)
+ ctx := r.Context()
+ timeline := h.buildAgentContext(ctx, startDate, endDate)
+ completedLog := h.buildCompletedLog(50)
+
+ h.renderAgentContextFull(w, session, timeline, completedLog, today, startDate, endDate, now)
}
// renderAgentError renders an error page for agent web endpoints
@@ -547,14 +586,30 @@ func (h *Handler) renderAgentStatus(w http.ResponseWriter, session *models.Agent
h.renderAgentTemplate(w, "agent-status.html", data)
}
-// renderAgentContext renders the context page with timeline data
-func (h *Handler) renderAgentContext(w http.ResponseWriter, session *models.AgentSession, timeline []agentContextItem, startDate, endDate, now time.Time) {
+// renderAgentContextFull renders the context page with full timeline data and completed log
+func (h *Handler) renderAgentContextFull(w http.ResponseWriter, session *models.AgentSession, timeline []agentContextItem, completedLog []agentCompletedItem, today, startDate, endDate, now time.Time) {
+ // Separate today's items for calendar view
+ var todayItems []agentContextItem
+ var otherItems []agentContextItem
+ endOfToday := today.Add(24 * time.Hour)
+
+ for _, item := range timeline {
+ if item.Due != nil && !item.Due.Before(today) && item.Due.Before(endOfToday) {
+ todayItems = append(todayItems, item)
+ } else {
+ otherItems = append(otherItems, item)
+ }
+ }
+
h.renderAgentTemplate(w, "agent-context.html", map[string]interface{}{
- "AgentName": session.AgentName,
- "GeneratedAt": now.Format(time.RFC3339),
- "RangeStart": startDate.Format("2006-01-02"),
- "RangeEnd": endDate.Format("2006-01-02"),
- "Timeline": timeline,
- "Summary": h.buildContextSummary(timeline, startDate),
+ "AgentName": session.AgentName,
+ "GeneratedAt": now.Format(time.RFC3339),
+ "Today": today.Format("2006-01-02"),
+ "RangeStart": startDate.Format("2006-01-02"),
+ "RangeEnd": endDate.Format("2006-01-02"),
+ "TodayItems": todayItems,
+ "Timeline": otherItems,
+ "CompletedLog": completedLog,
+ "Summary": h.buildContextSummary(timeline, today),
})
}
diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go
index 9fe1b2c..0e5edcc 100644
--- a/internal/handlers/handlers.go
+++ b/internal/handlers/handlers.go
@@ -673,8 +673,11 @@ func (h *Handler) handleAtomToggle(w http.ResponseWriter, r *http.Request, compl
}
if complete {
- // Get task title before removing from cache
- title := h.getAtomTitle(id, source)
+ // Get task details before removing from cache
+ title, dueDate := h.getAtomDetails(id, source)
+
+ // Log to completed tasks
+ _ = h.store.SaveCompletedTask(source, id, title, dueDate)
// Remove from local cache
switch source {
@@ -706,14 +709,14 @@ func (h *Handler) handleAtomToggle(w http.ResponseWriter, r *http.Request, compl
}
}
-// getAtomTitle retrieves the title for a task/card/bug from the store
-func (h *Handler) getAtomTitle(id, source string) string {
+// getAtomDetails retrieves title and due date for a task/card/bug from the store
+func (h *Handler) getAtomDetails(id, source string) (string, *time.Time) {
switch source {
case "todoist":
if tasks, err := h.store.GetTasks(); err == nil {
for _, t := range tasks {
if t.ID == id {
- return t.Content
+ return t.Content, t.DueDate
}
}
}
@@ -722,7 +725,7 @@ func (h *Handler) getAtomTitle(id, source string) string {
for _, b := range boards {
for _, c := range b.Cards {
if c.ID == id {
- return c.Name
+ return c.Name, c.DueDate
}
}
}
@@ -733,13 +736,22 @@ func (h *Handler) getAtomTitle(id, source string) string {
if _, err := fmt.Sscanf(id, "bug-%d", &bugID); err == nil {
for _, b := range bugs {
if b.ID == bugID {
- return b.Description
+ return b.Description, nil
}
}
}
}
+ case "gtasks":
+ // Google Tasks don't have local cache, return generic title
+ return "Google Task", nil
}
- return "Task"
+ return "Task", nil
+}
+
+// getAtomTitle retrieves the title for a task/card/bug from the store (legacy)
+func (h *Handler) getAtomTitle(id, source string) string {
+ title, _ := h.getAtomDetails(id, source)
+ return title
}
// HandleUnifiedAdd creates a task in Todoist or a card in Trello from the Quick Add form