This commit is contained in:
Martin
2026-02-03 20:13:09 +01:00
parent 44ddbc0f47
commit 1ffcf42773
5 changed files with 147 additions and 7 deletions

View File

@ -137,6 +137,7 @@ func (p *ReportPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case key.Matches(msg, p.common.Keymap.StartStop):
if p.selectedTask != nil && p.selectedTask.Status == "pending" {
if p.selectedTask.Start == "" {
p.common.TW.StopActiveTasks()
p.common.TW.StartTask(p.selectedTask)
} else {
p.common.TW.StopTask(p.selectedTask)

View File

@ -214,7 +214,6 @@ func (p *TimePage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
"hasUUID", timewarrior.ExtractUUID(interval.Tags) != "",
"uuid", timewarrior.ExtractUUID(interval.Tags))
p.common.TimeW.ContinueInterval(interval.ID)
common.SyncIntervalToTask(interval, p.common.TW, "start")
p.shouldSelectActive = true
// Set pending sync action instead of syncing immediately
// This ensures we sync AFTER intervals are refreshed

View File

@ -47,7 +47,7 @@ type Task struct {
Uuid string `json:"uuid,omitempty"`
Description string `json:"description,omitempty"`
Project string `json:"project"`
// Priority string `json:"priority"`
Priority string `json:"priority,omitempty"`
Status string `json:"status,omitempty"`
Tags []string `json:"tags"`
VirtualTags []string `json:"-"`
@ -149,8 +149,8 @@ func (t *Task) GetString(fieldWFormat string) string {
}
return t.Project
// case "priority":
// return t.Priority
case "priority":
return t.Priority
case "status":
return t.Status
@ -233,7 +233,33 @@ func (t *Task) GetString(fieldWFormat string) string {
return ""
}
func (t *Task) GetDate(dateString string) time.Time {
func (t *Task) GetDate(field string) time.Time {
var dateString string
switch field {
case "due":
dateString = t.Due
case "wait":
dateString = t.Wait
case "scheduled":
dateString = t.Scheduled
case "until":
dateString = t.Until
case "start":
dateString = t.Start
case "end":
dateString = t.End
case "entry":
dateString = t.Entry
case "modified":
dateString = t.Modified
default:
return time.Time{}
}
if dateString == "" {
return time.Time{}
}
dt, err := time.Parse(dtformat, dateString)
if err != nil {
slog.Error("Failed to parse time:", err)

View File

@ -0,0 +1,81 @@
package taskwarrior
import (
"testing"
"time"
)
func TestTask_GetString(t *testing.T) {
tests := []struct {
name string
task Task
fieldWFormat string
want string
}{
{
name: "Priority",
task: Task{
Priority: "H",
},
fieldWFormat: "priority",
want: "H",
},
{
name: "Description",
task: Task{
Description: "Buy milk",
},
fieldWFormat: "description.desc",
want: "Buy milk",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.task.GetString(tt.fieldWFormat); got != tt.want {
t.Errorf("Task.GetString() = %v, want %v", got, tt.want)
}
})
}
}
func TestTask_GetDate(t *testing.T) {
validDate := "20230101T120000Z"
parsedValid, _ := time.Parse("20060102T150405Z", validDate)
tests := []struct {
name string
task Task
field string
want time.Time
}{
{
name: "Due date valid",
task: Task{
Due: validDate,
},
field: "due",
want: parsedValid,
},
{
name: "Due date empty",
task: Task{},
field: "due",
want: time.Time{},
},
{
name: "Unknown field",
task: Task{Due: validDate},
field: "unknown",
want: time.Time{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.task.GetDate(tt.field); !got.Equal(tt.want) {
t.Errorf("Task.GetDate() = %v, want %v", got, tt.want)
}
})
}
}

View File

@ -98,6 +98,7 @@ type TaskWarrior interface {
DeleteTask(task *Task)
StartTask(task *Task)
StopTask(task *Task)
StopActiveTasks()
GetInformation(task *Task) string
AddTaskAnnotation(uuid string, annotation string)
@ -159,7 +160,12 @@ func (ts *TaskSquire) GetTasks(report *Report, filter ...string) Tasks {
args = append(args, filter...)
}
cmd := exec.Command(twBinary, append(args, []string{"export", report.Name}...)...)
exportArgs := []string{"export"}
if report.Name != "" {
exportArgs = append(exportArgs, report.Name)
}
cmd := exec.Command(twBinary, append(args, exportArgs...)...)
output, err := cmd.CombinedOutput()
if err != nil {
slog.Error("Failed getting report:", err)
@ -490,6 +496,33 @@ func (ts *TaskSquire) StopTask(task *Task) {
}
}
func (ts *TaskSquire) StopActiveTasks() {
ts.mutex.Lock()
defer ts.mutex.Unlock()
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"+ACTIVE", "export"}...)...)
output, err := cmd.CombinedOutput()
if err != nil {
slog.Error("Failed getting active tasks:", "error", err, "output", string(output))
return
}
tasks := make(Tasks, 0)
err = json.Unmarshal(output, &tasks)
if err != nil {
slog.Error("Failed unmarshalling active tasks:", err)
return
}
for _, task := range tasks {
cmd := exec.Command(twBinary, append(ts.defaultArgs, []string{"stop", task.Uuid}...)...)
err := cmd.Run()
if err != nil {
slog.Error("Failed stopping task:", err)
}
}
}
func (ts *TaskSquire) GetInformation(task *Task) string {
ts.mutex.Lock()
defer ts.mutex.Unlock()