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.
This commit is contained in:
kolaente 2026-06-10 14:06:35 +02:00 committed by kolaente
parent 070ce19286
commit 3a84c491ae
1 changed files with 17 additions and 4 deletions

View File

@ -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)
}