From 3a84c491aeacd83080849deeb3e4b0caff9ef50c Mon Sep 17 00:00:00 2001 From: kolaente Date: Wed, 10 Jun 2026 14:06:35 +0200 Subject: [PATCH] feat(models): let TaskCollection force a flat task list v1's TaskCollection.ReadAll is polymorphic: a kanban view returns []*Bucket, everything else []*Task. v2 splits the task list into a flat-tasks endpoint and a separate buckets-with-tasks endpoint, so the flat endpoint needs ReadAll to return tasks even for a kanban view. SetForceFlatTasks toggles that; v1 leaves it unset and keeps its shape. --- pkg/models/task_collection.go | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/pkg/models/task_collection.go b/pkg/models/task_collection.go index 833cc7851..bc217f7ca 100644 --- a/pkg/models/task_collection.go +++ b/pkg/models/task_collection.go @@ -58,6 +58,12 @@ type TaskCollection struct { isSavedFilter bool + // forceFlatTasks makes ReadAll always return []*Task, never []*Bucket, even + // for a kanban view. v1's single tasks endpoint is polymorphic; v2 splits it + // into a flat-tasks endpoint and a separate buckets-with-tasks one, and the + // former sets this so a kanban view path still yields tasks. + forceFlatTasks bool + web.CRUDable `xorm:"-" json:"-"` web.Permissions `xorm:"-" json:"-"` } @@ -149,8 +155,14 @@ func getTaskFilterOptsFromCollection(tf *TaskCollection, projectView *ProjectVie return opts, err } -func getTaskOrTasksInBuckets(s *xorm.Session, a web.Auth, projects []*Project, view *ProjectView, opts *taskSearchOptions, filteringForBucket bool) (tasks interface{}, resultCount int, totalItems int64, err error) { - if filteringForBucket { +// SetForceFlatTasks makes ReadAll return a flat []*Task even for a kanban view. +// The v2 tasks endpoint uses it; v1 leaves it unset for the polymorphic shape. +func (tf *TaskCollection) SetForceFlatTasks() { + tf.forceFlatTasks = true +} + +func getTaskOrTasksInBuckets(s *xorm.Session, a web.Auth, projects []*Project, view *ProjectView, opts *taskSearchOptions, filteringForBucket, forceFlatTasks bool) (tasks interface{}, resultCount int, totalItems int64, err error) { + if filteringForBucket || forceFlatTasks { return getTasksForProjects(s, projects, a, opts, view) } @@ -280,6 +292,7 @@ func (tf *TaskCollection) ReadAll(s *xorm.Session, a web.Auth, search string, pa tc.ProjectID = tf.ProjectID tc.isSavedFilter = true tc.Expand = tf.Expand + tc.forceFlatTasks = tf.forceFlatTasks if tf.Filter != "" { if tc.Filter != "" { @@ -372,7 +385,7 @@ func (tf *TaskCollection) ReadAll(s *xorm.Session, a web.Auth, search string, pa if err != nil { return nil, 0, 0, err } - return getTaskOrTasksInBuckets(s, a, []*Project{project}, view, opts, filteringForBucket) + return getTaskOrTasksInBuckets(s, a, []*Project{project}, view, opts, filteringForBucket, tf.forceFlatTasks) } projects, err := getRelevantProjectsFromCollection(s, a, tf) @@ -380,5 +393,5 @@ func (tf *TaskCollection) ReadAll(s *xorm.Session, a web.Auth, search string, pa return nil, 0, 0, err } - return getTaskOrTasksInBuckets(s, a, projects, view, opts, filteringForBucket) + return getTaskOrTasksInBuckets(s, a, projects, view, opts, filteringForBucket, tf.forceFlatTasks) }