Fix working set IDs to match display order
BREAKING CHANGE: BuildWorkingSet() now accepts []*Task instead of *Filter Problem: - Working set IDs were assigned based on database query order (unsorted) - Reports displayed tasks in sorted order (by urgency) - Result: IDs didn't match displayed task positions (ID 1 wasn't first task) Solution: - Changed BuildWorkingSet() to accept pre-sorted task slice - Reports now pass sorted tasks to BuildWorkingSet() - IDs are assigned sequentially to match display order (1, 2, 3...) Behavior: - Reports rebuild working set on every execution with fresh IDs - Task operations (done, modify, info) use saved working set IDs - After completing a task, re-running report renumbers remaining tasks Example: Before: opal list shows ID 1 = low urgency task (wrong) After: opal list shows ID 1 = highest urgency task (correct) Tested scenarios: ✓ List report: IDs 1-N match urgency order ✓ Next report: IDs 1-5 match top urgent tasks ✓ Task completion: IDs renumber correctly after removal ✓ Multiple operations: Use saved working set (correct behavior) ✓ Different reports: Each builds own sequential IDs
This commit is contained in:
@@ -50,8 +50,12 @@ func modifyTasks(filterArgs, modifierArgs []string) error {
|
|||||||
// Load working set for ID resolution
|
// Load working set for ID resolution
|
||||||
ws, err := engine.LoadWorkingSet()
|
ws, err := engine.LoadWorkingSet()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If no working set exists yet, build one
|
// If no working set exists yet, build one from filtered tasks
|
||||||
ws, err = engine.BuildWorkingSet(filter)
|
tasks, err := engine.GetTasks(filter)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get tasks: %w", err)
|
||||||
|
}
|
||||||
|
ws, err = engine.BuildWorkingSet(tasks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to build working set: %w", err)
|
return fmt.Errorf("failed to build working set: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,14 +47,14 @@ func runReport(reportName string, filters []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the report
|
// Execute the report (returns sorted tasks)
|
||||||
tasks, err := report.Execute(filters)
|
tasks, err := report.Execute(filters)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to execute report: %w", err)
|
return fmt.Errorf("failed to execute report: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build working set for display IDs
|
// Build working set from sorted tasks - IDs will match display order
|
||||||
ws, err := engine.BuildWorkingSet(report.BaseFilter)
|
ws, err := engine.BuildWorkingSet(tasks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to build working set: %w", err)
|
return fmt.Errorf("failed to build working set: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,13 +14,10 @@ type WorkingSet struct {
|
|||||||
byID map[int]uuid.UUID // display_id -> UUID
|
byID map[int]uuid.UUID // display_id -> UUID
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildWorkingSet creates a working set from filter results and persists to DB
|
// BuildWorkingSet creates a working set from a list of tasks and persists to DB
|
||||||
func BuildWorkingSet(filter *Filter) (*WorkingSet, error) {
|
// Tasks should be pre-sorted in the desired display order
|
||||||
tasks, err := GetTasks(filter)
|
// IDs are assigned sequentially (1, 2, 3, ...) based on task order in the slice
|
||||||
if err != nil {
|
func BuildWorkingSet(tasks []*Task) (*WorkingSet, error) {
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ws := &WorkingSet{
|
ws := &WorkingSet{
|
||||||
byUUID: make(map[uuid.UUID]*Task),
|
byUUID: make(map[uuid.UUID]*Task),
|
||||||
byID: make(map[int]uuid.UUID),
|
byID: make(map[int]uuid.UUID),
|
||||||
|
|||||||
@@ -10,8 +10,13 @@ func TestBuildWorkingSet(t *testing.T) {
|
|||||||
task2, _ := CreateTask("Task 2")
|
task2, _ := CreateTask("Task 2")
|
||||||
task3, _ := CreateTask("Task 3")
|
task3, _ := CreateTask("Task 3")
|
||||||
|
|
||||||
// Build working set with default filter
|
// Get tasks and build working set
|
||||||
ws, err := BuildWorkingSet(DefaultFilter())
|
tasks, err := GetTasks(DefaultFilter())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to get tasks: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ws, err := BuildWorkingSet(tasks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to build working set: %v", err)
|
t.Fatalf("Failed to build working set: %v", err)
|
||||||
}
|
}
|
||||||
@@ -52,7 +57,12 @@ func TestLoadWorkingSet(t *testing.T) {
|
|||||||
CreateTask("Load test 1")
|
CreateTask("Load test 1")
|
||||||
CreateTask("Load test 2")
|
CreateTask("Load test 2")
|
||||||
|
|
||||||
ws1, err := BuildWorkingSet(DefaultFilter())
|
tasks, err := GetTasks(DefaultFilter())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to get tasks: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ws1, err := BuildWorkingSet(tasks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to build working set: %v", err)
|
t.Fatalf("Failed to build working set: %v", err)
|
||||||
}
|
}
|
||||||
@@ -82,7 +92,12 @@ func TestWorkingSetWithFilter(t *testing.T) {
|
|||||||
|
|
||||||
// Build working set with high priority filter
|
// Build working set with high priority filter
|
||||||
filter, _ := ParseFilter([]string{"priority:H"})
|
filter, _ := ParseFilter([]string{"priority:H"})
|
||||||
ws, err := BuildWorkingSet(filter)
|
tasks, err := GetTasks(filter)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to get tasks: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ws, err := BuildWorkingSet(tasks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to build filtered working set: %v", err)
|
t.Fatalf("Failed to build filtered working set: %v", err)
|
||||||
}
|
}
|
||||||
@@ -105,7 +120,8 @@ func TestGetTaskByDisplayID(t *testing.T) {
|
|||||||
CreateTask("Display ID test 2")
|
CreateTask("Display ID test 2")
|
||||||
CreateTask("Display ID test 3")
|
CreateTask("Display ID test 3")
|
||||||
|
|
||||||
ws, _ := BuildWorkingSet(DefaultFilter())
|
tasks, _ := GetTasks(DefaultFilter())
|
||||||
|
ws, _ := BuildWorkingSet(tasks)
|
||||||
|
|
||||||
// Test valid display IDs
|
// Test valid display IDs
|
||||||
for i := 1; i <= ws.Size(); i++ {
|
for i := 1; i <= ws.Size(); i++ {
|
||||||
@@ -130,7 +146,8 @@ func TestWorkingSetGetTasks(t *testing.T) {
|
|||||||
CreateTask("GetTasks test 1")
|
CreateTask("GetTasks test 1")
|
||||||
CreateTask("GetTasks test 2")
|
CreateTask("GetTasks test 2")
|
||||||
|
|
||||||
ws, _ := BuildWorkingSet(DefaultFilter())
|
taskList, _ := GetTasks(DefaultFilter())
|
||||||
|
ws, _ := BuildWorkingSet(taskList)
|
||||||
|
|
||||||
tasks := ws.GetTasks()
|
tasks := ws.GetTasks()
|
||||||
if len(tasks) != ws.Size() {
|
if len(tasks) != ws.Size() {
|
||||||
|
|||||||
Reference in New Issue
Block a user