summaryrefslogtreecommitdiff
path: root/internal/ui
diff options
context:
space:
mode:
Diffstat (limited to 'internal/ui')
-rw-r--r--internal/ui/handlers.go24
-rw-r--r--internal/ui/keyactions.go8
-rw-r--r--internal/ui/keyhandlers.go1
-rw-r--r--internal/ui/table.go25
-rw-r--r--internal/ui/table_test.go16
-rw-r--r--internal/ui/ultra.go1
6 files changed, 60 insertions, 15 deletions
diff --git a/internal/ui/handlers.go b/internal/ui/handlers.go
index 394aa80..45c0b10 100644
--- a/internal/ui/handlers.go
+++ b/internal/ui/handlers.go
@@ -47,14 +47,16 @@ func (m *Model) handleAnnotationMode(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
}
if m.replaceAnnotations {
- ctx, cancel := taskExportContext()
+ ctx, cancel := m.taskExportContext()
defer cancel()
if err := task.ReplaceAnnotations(ctx, m.annotateID, value); err != nil {
return err
}
m.replaceAnnotations = false
} else {
- if err := task.Annotate(m.annotateID, value); err != nil {
+ ctx, cancel := m.taskExportContext()
+ defer cancel()
+ if err := task.AnnotateContext(ctx, m.annotateID, value); err != nil {
return err
}
}
@@ -127,14 +129,18 @@ func (m *Model) handleTagsMode(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
}
}
}
- if len(adds) > 0 {
- if err := task.AddTags(m.tagsID, adds); err != nil {
- return err
+ if len(adds) > 0 || len(removes) > 0 {
+ ctx, cancel := m.taskExportContext()
+ defer cancel()
+ if len(adds) > 0 {
+ if err := task.AddTagsContext(ctx, m.tagsID, adds); err != nil {
+ return err
+ }
}
- }
- if len(removes) > 0 {
- if err := task.RemoveTags(m.tagsID, removes); err != nil {
- return err
+ if len(removes) > 0 {
+ if err := task.RemoveTagsContext(ctx, m.tagsID, removes); err != nil {
+ return err
+ }
}
}
if err := m.reload(); err != nil {
diff --git a/internal/ui/keyactions.go b/internal/ui/keyactions.go
index 072ea20..c84c172 100644
--- a/internal/ui/keyactions.go
+++ b/internal/ui/keyactions.go
@@ -159,7 +159,7 @@ func (m *Model) handleUndo() (tea.Model, tea.Cmd) {
}
filters = append(filters, "status:"+restore.status)
- ctx, cancel := taskExportContext()
+ ctx, cancel := m.taskExportContext()
tasks, err := task.Export(ctx, filters...)
cancel()
if err == nil && len(tasks) > 0 {
@@ -200,7 +200,7 @@ func (m *Model) deleteTaskWithUndo(tsk task.Task) (int, bool, error) {
recurring := isRecurringTask(tsk)
tasks := []task.Task{tsk}
if recurring {
- ctx, cancel := taskExportContext()
+ ctx, cancel := m.taskExportContext()
series, err := task.RecurringSeries(ctx, recurringRootUUID(tsk))
cancel()
if err != nil {
@@ -495,7 +495,9 @@ func (m *Model) handleTagToProject() (tea.Model, tea.Cmd) {
}
// Remove the tag from the task
- if err := task.RemoveTags(id, []string{firstTag}); err != nil {
+ ctx, cancel := m.taskExportContext()
+ defer cancel()
+ if err := task.RemoveTagsContext(ctx, id, []string{firstTag}); err != nil {
m.showError(err)
return m, nil
}
diff --git a/internal/ui/keyhandlers.go b/internal/ui/keyhandlers.go
index 0cfabec..16263db 100644
--- a/internal/ui/keyhandlers.go
+++ b/internal/ui/keyhandlers.go
@@ -184,6 +184,7 @@ func (m *Model) handleQuitKey() (tea.Model, tea.Cmd) {
m.reloadAndReport()
return m, nil
}
+ m.cancelTaskOperations()
return m, tea.Quit
}
diff --git a/internal/ui/table.go b/internal/ui/table.go
index 9aeeda1..c948d89 100644
--- a/internal/ui/table.go
+++ b/internal/ui/table.go
@@ -228,6 +228,9 @@ type Model struct {
statusMsg string // temporary status message shown in status bar
helpViewport viewport.Model
+
+ taskContext context.Context
+ cancelTaskContext context.CancelFunc
}
// editDoneMsg is emitted when the external editor process finishes.
@@ -262,8 +265,22 @@ type reloadData struct {
ultraFilterIDs []int
}
-func taskExportContext() (context.Context, context.CancelFunc) {
- return context.WithTimeout(context.Background(), taskExportTimeout)
+func (m *Model) initTaskContext() {
+ if m.taskContext != nil && m.cancelTaskContext != nil {
+ return
+ }
+ m.taskContext, m.cancelTaskContext = context.WithCancel(context.Background())
+}
+
+func (m *Model) cancelTaskOperations() {
+ if m.cancelTaskContext != nil {
+ m.cancelTaskContext()
+ }
+}
+
+func (m *Model) taskExportContext() (context.Context, context.CancelFunc) {
+ m.initTaskContext()
+ return context.WithTimeout(m.taskContext, taskExportTimeout)
}
// blinkInterval controls how quickly the row flashes when a task changes.
@@ -413,6 +430,7 @@ func (m *Model) startBlink(id int, markDone bool) tea.Cmd {
// New creates a new UI model with the provided rows.
func New(filters []string, browserCmd string) (Model, error) {
m := Model{filters: filters, browserCmd: browserCmd, agentFilterHotkey: "3", blinkState: blinkState{blinkEnabled: true}}
+ m.initTaskContext()
m.annotateInput = textinput.New()
m.annotateInput.Prompt = "annotation: "
m.descInput = textinput.New()
@@ -442,6 +460,7 @@ func New(filters []string, browserCmd string) (Model, error) {
m.theme = m.defaultTheme
if err := m.reload(); err != nil {
+ m.cancelTaskOperations()
return Model{}, err
}
@@ -491,7 +510,7 @@ func (m *Model) fetchTasks() (reloadData, error) {
// Always show only pending tasks by default.
filters := append([]string(nil), m.filters...)
filters = append(filters, "status:pending")
- ctx, cancel := taskExportContext()
+ ctx, cancel := m.taskExportContext()
defer cancel()
tasks, err := task.Export(ctx, filters...)
diff --git a/internal/ui/table_test.go b/internal/ui/table_test.go
index c4f1e82..3a383e3 100644
--- a/internal/ui/table_test.go
+++ b/internal/ui/table_test.go
@@ -1,6 +1,8 @@
package ui
import (
+ "context"
+ "errors"
"fmt"
"os"
"path/filepath"
@@ -1501,6 +1503,20 @@ func TestEscDoesNotQuitFromTable(t *testing.T) {
}
}
+func TestQuitCancelsTaskExportContext(t *testing.T) {
+ m := Model{}
+ ctx, cancel := m.taskExportContext()
+ defer cancel()
+
+ _, cmd := m.handleQuitKey()
+ if cmd == nil {
+ t.Fatal("quit returned nil command; want tea.Quit")
+ }
+ if !errors.Is(ctx.Err(), context.Canceled) {
+ t.Fatalf("task export context error = %v, want context canceled", ctx.Err())
+ }
+}
+
func TestEscDoesNotQuitUltraStartup(t *testing.T) {
tmp := t.TempDir()
taskPath := setupBasicTask(t, tmp)
diff --git a/internal/ui/ultra.go b/internal/ui/ultra.go
index 0d5f57b..9545c6f 100644
--- a/internal/ui/ultra.go
+++ b/internal/ui/ultra.go
@@ -1167,6 +1167,7 @@ func (m *Model) handleUltraExitKey(quit bool) (tea.Model, tea.Cmd) {
}
if m.ultraStartup {
if quit {
+ m.cancelTaskOperations()
return m, tea.Quit
}
return m, nil