Skip to content

Commit 5332bcd

Browse files
committed
feat(tasks): added reporting & additional task views
* extended task model for scoring, & dependencies
1 parent 000b121 commit 5332bcd

File tree

11 files changed

+524
-47
lines changed

11 files changed

+524
-47
lines changed

cmd/task_commands.go

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ time tracking. Tasks can be filtered by status, priority, project, or context.`,
3333
&cobra.Group{ID: "task-ops", Title: "Basic Operations"},
3434
&cobra.Group{ID: "task-meta", Title: "Metadata"},
3535
&cobra.Group{ID: "task-tracking", Title: "Tracking"},
36+
&cobra.Group{ID: "task-reports", Title: "Reports & Views"},
3637
)
3738

3839
for _, init := range []func(*handlers.TaskHandler) *cobra.Command{
@@ -59,6 +60,14 @@ time tracking. Tasks can be filtered by status, priority, project, or context.`,
5960
root.AddCommand(cmd)
6061
}
6162

63+
for _, init := range []func(*handlers.TaskHandler) *cobra.Command{
64+
nextActionsCmd, reportCompletedCmd, reportWaitingCmd, reportBlockedCmd, calendarCmd,
65+
} {
66+
cmd := init(c.handler)
67+
cmd.GroupID = "task-reports"
68+
root.AddCommand(cmd)
69+
}
70+
6271
return root
6372
}
6473

@@ -84,18 +93,22 @@ Examples:
8493
project, _ := c.Flags().GetString("project")
8594
context, _ := c.Flags().GetString("context")
8695
due, _ := c.Flags().GetString("due")
96+
wait, _ := c.Flags().GetString("wait")
97+
scheduled, _ := c.Flags().GetString("scheduled")
8798
recur, _ := c.Flags().GetString("recur")
8899
until, _ := c.Flags().GetString("until")
89100
parent, _ := c.Flags().GetString("parent")
90101
dependsOn, _ := c.Flags().GetString("depends-on")
91102
tags, _ := c.Flags().GetStringSlice("tags")
92103

93104
defer h.Close()
94-
return h.Create(c.Context(), description, priority, project, context, due, recur, until, parent, dependsOn, tags)
105+
// TODO: Make a CreateTask struct
106+
return h.Create(c.Context(), description, priority, project, context, due, wait, scheduled, recur, until, parent, dependsOn, tags)
95107
},
96108
}
97109
addCommonTaskFlags(cmd)
98110
addDueDateFlag(cmd)
111+
addWaitScheduledFlags(cmd)
99112
addRecurrenceFlags(cmd)
100113
addParentFlag(cmd)
101114
addDependencyFlags(cmd)
@@ -120,9 +133,11 @@ Use --all to show all tasks, otherwise only pending tasks are shown.`,
120133
priority, _ := c.Flags().GetString("priority")
121134
project, _ := c.Flags().GetString("project")
122135
context, _ := c.Flags().GetString("context")
136+
sortBy, _ := c.Flags().GetString("sort")
123137

124138
defer h.Close()
125-
return h.List(c.Context(), static, showAll, status, priority, project, context)
139+
// TODO: TaskFilter struct
140+
return h.List(c.Context(), static, showAll, status, priority, project, context, sortBy)
126141
},
127142
}
128143
cmd.Flags().BoolP("interactive", "i", false, "Force interactive mode (default)")
@@ -132,6 +147,7 @@ Use --all to show all tasks, otherwise only pending tasks are shown.`,
132147
cmd.Flags().String("priority", "", "Filter by priority")
133148
cmd.Flags().String("project", "", "Filter by project")
134149
cmd.Flags().String("context", "", "Filter by context")
150+
cmd.Flags().String("sort", "", "Sort by (urgency)")
135151

136152
return cmd
137153
}
@@ -451,6 +467,85 @@ configured.`,
451467
return root
452468
}
453469

470+
func nextActionsCmd(h *handlers.TaskHandler) *cobra.Command {
471+
cmd := &cobra.Command{
472+
Use: "next",
473+
Short: "Show next actions (actionable tasks sorted by urgency)",
474+
Aliases: []string{"na"},
475+
Long: `Display actionable tasks sorted by urgency score.
476+
477+
Shows tasks that can be worked on now (not waiting, not blocked, not completed),
478+
ordered by their computed urgency based on priority, due date, age, and other factors.`,
479+
RunE: func(c *cobra.Command, args []string) error {
480+
limit, _ := c.Flags().GetInt("limit")
481+
defer h.Close()
482+
return h.NextActions(c.Context(), limit)
483+
},
484+
}
485+
cmd.Flags().IntP("limit", "n", 10, "Limit number of tasks shown")
486+
return cmd
487+
}
488+
489+
func reportCompletedCmd(h *handlers.TaskHandler) *cobra.Command {
490+
cmd := &cobra.Command{
491+
Use: "completed",
492+
Short: "Show completed tasks",
493+
Long: "Display tasks that have been completed, sorted by completion date.",
494+
RunE: func(c *cobra.Command, args []string) error {
495+
limit, _ := c.Flags().GetInt("limit")
496+
defer h.Close()
497+
return h.ReportCompleted(c.Context(), limit)
498+
},
499+
}
500+
cmd.Flags().IntP("limit", "n", 20, "Limit number of tasks shown")
501+
return cmd
502+
}
503+
504+
func reportWaitingCmd(h *handlers.TaskHandler) *cobra.Command {
505+
cmd := &cobra.Command{
506+
Use: "waiting",
507+
Short: "Show waiting tasks",
508+
Long: "Display tasks that are waiting for a specific date before becoming actionable.",
509+
RunE: func(c *cobra.Command, args []string) error {
510+
defer h.Close()
511+
return h.ReportWaiting(c.Context())
512+
},
513+
}
514+
return cmd
515+
}
516+
517+
func reportBlockedCmd(h *handlers.TaskHandler) *cobra.Command {
518+
cmd := &cobra.Command{
519+
Use: "blocked",
520+
Short: "Show blocked tasks",
521+
Long: "Display tasks that are blocked by dependencies on other tasks.",
522+
RunE: func(c *cobra.Command, args []string) error {
523+
defer h.Close()
524+
return h.ReportBlocked(c.Context())
525+
},
526+
}
527+
return cmd
528+
}
529+
530+
func calendarCmd(h *handlers.TaskHandler) *cobra.Command {
531+
cmd := &cobra.Command{
532+
Use: "calendar",
533+
Short: "Show tasks in calendar view",
534+
Aliases: []string{"cal"},
535+
Long: `Display tasks with due dates in a calendar format.
536+
537+
Shows tasks organized by week and day, making it easy to see upcoming deadlines
538+
and plan your work schedule.`,
539+
RunE: func(c *cobra.Command, args []string) error {
540+
weeks, _ := c.Flags().GetInt("weeks")
541+
defer h.Close()
542+
return h.Calendar(c.Context(), weeks)
543+
},
544+
}
545+
cmd.Flags().IntP("weeks", "w", 4, "Number of weeks to show")
546+
return cmd
547+
}
548+
454549
func taskDependCmd(h *handlers.TaskHandler) *cobra.Command {
455550
root := &cobra.Command{
456551
Use: "depend",

cmd/task_flags.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,8 @@ func addOutputFlags(cmd *cobra.Command) {
3131
func addDueDateFlag(cmd *cobra.Command) {
3232
cmd.Flags().StringP("due", "d", "", "Set due date (YYYY-MM-DD)")
3333
}
34+
35+
func addWaitScheduledFlags(cmd *cobra.Command) {
36+
cmd.Flags().StringP("wait", "w", "", "Task not actionable until date (YYYY-MM-DD)")
37+
cmd.Flags().StringP("scheduled", "s", "", "Task scheduled to start on date (YYYY-MM-DD)")
38+
}

internal/docs/ROADMAP.md

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -126,20 +126,20 @@ Planned functionality for a complete baseline release.
126126

127127
### Tasks
128128

129-
- [ ] Model
130-
- [ ] Dependencies
131-
- [ ] Recurrence (`recur`, `until`, templates)
132-
- [ ] Wait/scheduled dates
133-
- [ ] Urgency scoring
129+
- [x] Model
130+
- [x] Dependencies
131+
- [x] Recurrence (`recur`, `until`, templates)
132+
- [x] Wait/scheduled dates
133+
- [x] Urgency scoring
134134
- [ ] Operations
135135
- [ ] `annotate`
136136
- [ ] Bulk edit and undo/history
137137
- [ ] `$EDITOR` integration
138-
- [ ] Reports and Views
139-
- [ ] Next actions
140-
- [ ] Completed/waiting/blocked reports
141-
- [ ] Calendar view
142-
- [ ] Sorting and urgency-based views
138+
- [x] Reports and Views
139+
- [x] Next actions
140+
- [x] Completed/waiting/blocked reports
141+
- [x] Calendar view
142+
- [x] Sorting and urgency-based views
143143
- [ ] Queries and Filters
144144
- [ ] Rich query language
145145
- [ ] Saved filters and aliases
@@ -442,8 +442,9 @@ SQLite persistence, CI with GitHub Actions and Codecov, TUIs with Charm stack, i
442442
| Tasks | Time tracking | Complete |
443443
| Tasks | Dependencies | Complete |
444444
| Tasks | Recurrence | Complete |
445-
| Tasks | Wait/scheduled | Planned |
446-
| Tasks | Urgency scoring | Planned |
445+
| Tasks | Wait/scheduled | Complete |
446+
| Tasks | Urgency scoring | Complete |
447+
| Tasks | Reports and views | Complete |
447448
| Notes | CRUD | Complete |
448449
| Notes | Search/tagging | Planned |
449450
| Publications | AT Protocol sync | Complete |

internal/handlers/task_helpers.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,16 @@ type ParsedTaskData struct {
1818
Context string
1919
Tags []string
2020
Due string
21+
Wait string
22+
Scheduled string
2123
Recur string
2224
Until string
2325
ParentUUID string
2426
DependsOn []string
2527
}
2628

2729
// parseDescription extracts inline metadata from description text
28-
// Supports: +project @context #tag due:YYYY-MM-DD recur:RULE until:DATE parent:UUID depends:UUID1,UUID2
30+
// Supports: +project @context #tag due:YYYY-MM-DD wait:YYYY-MM-DD scheduled:YYYY-MM-DD recur:RULE until:DATE parent:UUID depends:UUID1,UUID2
2931
func parseDescription(text string) *ParsedTaskData {
3032
parsed := &ParsedTaskData{Tags: []string{}, DependsOn: []string{}}
3133
words := strings.Fields(text)
@@ -41,6 +43,10 @@ func parseDescription(text string) *ParsedTaskData {
4143
parsed.Tags = append(parsed.Tags, strings.TrimPrefix(word, "#"))
4244
case strings.HasPrefix(word, "due:"):
4345
parsed.Due = strings.TrimPrefix(word, "due:")
46+
case strings.HasPrefix(word, "wait:"):
47+
parsed.Wait = strings.TrimPrefix(word, "wait:")
48+
case strings.HasPrefix(word, "scheduled:"):
49+
parsed.Scheduled = strings.TrimPrefix(word, "scheduled:")
4450
case strings.HasPrefix(word, "recur:"):
4551
parsed.Recur = strings.TrimPrefix(word, "recur:")
4652
case strings.HasPrefix(word, "until:"):

0 commit comments

Comments
 (0)