Commit Graph

102 Commits

Author SHA1 Message Date
kolaente cefa42da86 refactor(search): limit BM25 relevance ranking to pure-text searches
Rank ParadeDB search results by BM25 relevance only for pure-text searches
over a plain project scope. Numeric searches (the `OR index = N` branch) and
the Favorites view (the `id IN (<subquery>)` scope) keep the default ordering
(unranked, as on main): pdb.score rejects both as unsupported query shapes, and
the contortions previously needed to score them (two-arm numeric merge with
in-memory pagination, a favorites LEFT JOIN) added far more complexity than the
ranking was worth. Neither path was ranked before this PR, so leaving them at
the default order is no regression.
2026-06-21 18:49:41 +02:00
kolaente 78dde2fb18 fix(search): derive userProvidedSort from the effective sort so relevance ranking applies in negative-id views 2026-06-19 23:14:55 +02:00
kolaente 9fb0d86c1b feat(search): rank ParadeDB search results by BM25 relevance (#2690)
When ParadeDB is in use and a search is run, results now keep the current
fuzzy/OR matching but are ordered by BM25 relevance so tasks matching all
query words rank above tasks matching only some.

Details:
- ParadeDB exposes the BM25 score via pdb.score(<key_field>); Vikunja's
  key_field is id, so we order by pdb.score(tasks.id) DESC, then the
  existing order-by (ending in a stable tasks.id tiebreak).
- Gating: relevance ordering only applies when ParadeDB is available, a
  search term is present, AND the user did not pass an explicit sort_by.
  An explicit user sort still wins; relevance only replaces the default
  (id / position) sort.
- DISTINCT requires every ORDER BY expression to appear in the SELECT
  list, so pdb.score(tasks.id) is added to the selected columns too (for
  both the plain and task_positions-join query shapes). Because xorm's
  Distinct() quotes each column and corrupts the function call, the
  ranking path uses Select(rawColumns).Distinct() instead.
- ParadeDB-only by nature: pdb.score is invalid SQL on sqlite, mysql and
  plain postgres, so those paths are completely unchanged.

A test (TestTaskSearchRelevanceRanking) creates a task matching all query
words plus tasks matching only one, then searches a multi-word query. On
ParadeDB it asserts the all-words task ranks first; on other databases it
only asserts the matching tasks are returned, so it stays green across the
whole CI database matrix. The CI ParadeDB matrix entry exercises the
ranking assertion.

Follow-up (not in this change): boosting results where the words appear in
order / in close proximity above plain all-words matches.

Fixes #2690
2026-06-19 20:46:28 +02:00
kolaente 3a84c491ae 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.
2026-06-11 18:31:03 +00:00
kolaente e197b1912f feat(time-tracking): count tracked time entries per task 2026-06-08 13:54:09 +00:00
kolaente 5ddc9d8ff0 feat(api/v2): add project view routes
Add ProjectView CRUD on /api/v2 under the nested path
/projects/{project}/views[/{view}], establishing the two-path-param
binding pattern for sub-resources. Mirrors the labels.go handler shape
and reuses handler.Do* so permission checks stay at the model layer.

Both {project} and {view} are bound on every operation; {project} is
threaded onto ProjectView.ProjectID (ReadOne resolves via
GetProjectViewByIDAndProject, which needs the parent id). List wraps the
[]*models.ProjectView slice in the shared Paginated envelope, read sends
an ETag for If-None-Match/304, and AutoPatch synthesises PATCH.

Also:
- Tag exposed ProjectView / ProjectViewBucketConfiguration / nested
  TaskCollection fields with doc: descriptions; mark server-controlled
  fields (id, project_id, created, updated) readOnly. Safe for v1.
- Give ProjectViewKind and BucketConfigurationModeKind a huma.SchemaProvider
  so the string-serialised enums reflect as string schemas instead of
  Huma's default integer schema (which rejected the string form with 422).

Routes registered in registerAPIRoutesV2 before EnableAutoPatch.
2026-06-01 13:04:34 +00:00
kolaente c6c57d9d15 refactor(models): remove *Arr helper fields now handled by normalizer 2026-05-31 12:56:57 +00:00
Timh e97b629d6c feat: support filter_include_nulls in project view configuration 2026-04-28 14:16:51 +00:00
Tink d11f097eee
fix(tasks): support both expand and expand[] query parameter formats (#2415)
The `expand` query parameter only supported the `expand[]=foo` array
format, but the swagger docs described it as a plain string parameter.
This adds support for both formats (`expand=foo` and `expand[]=foo`),
matching the existing pattern used by `sort_by` and `order_by`
parameters.

Closes #2408

---------

Co-authored-by: kolaente <k@knt.li>
2026-03-19 09:18:11 +00:00
renovate[bot] 9a61453e86
fix(deps): update module github.com/labstack/echo/v4 to v5 (#2131)
Closes https://github.com/go-vikunja/vikunja/pull/2133

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: kolaente <k@knt.li>
2026-01-24 20:38:32 +01:00
Mithilesh Gupta 7dddc5dfa2
feat: task unread tracking (#1857)
---------

Co-authored-by: Mithilesh Gupta <guptamithilesh@protonmail.com>
Co-authored-by: kolaente <k@knt.li>
2025-11-27 15:14:42 +01:00
Mithilesh Gupta 01a84dd2d5
feat: add comment count to tasks (#1771) 2025-11-11 23:00:05 +01:00
kolaente 22fc19cd24
fix: ignore filter_include_nulls from views
The filter_include_nulls property from the filter in a view would override the property set through the query string. Because we don't have a way in the UI to set this for filters in views, this makes the setting pretty opaque and unpredictable. Since we want to remove the nulls option anyways, we can just ignore it here.

Resolves https://github.com/go-vikunja/vikunja/issues/1781
2025-11-11 11:04:33 +01:00
kolaente a81a3ee0e5
feat!: rename right to permission (#1277) 2025-08-13 11:05:05 +02:00
kolaente 53264d350e
fix(kanban): make bucket query fixed per-view (#1007) 2025-06-25 11:38:24 +00:00
Dominik Pschenitschni 296577a875
fix: correct license header references (#882)
See originals:
- https://www.gnu.org/licenses/agpl-3.0.txt
- https://www.gnu.org/licenses/gpl-3.0.txt
2025-06-10 12:18:38 +02:00
kolaente ef01c2217b
fix(task): correctly validate all task fields 2025-01-25 14:38:25 +01:00
kolaente 9aa197b196
fix: swagger docs 2025-01-24 14:20:07 +01:00
kolaente 6b7c3ffef3
feat(tasks): add parameter to expand comments on a task 2025-01-24 13:00:06 +01:00
kolaente e887cdeb5e
feat(task): expand reactions via parameter 2025-01-24 11:39:51 +01:00
kolaente 333e35e648
feat: add expand property to read one task 2025-01-24 11:20:23 +01:00
kolaente 7f6cb1e06e
feat: expand buckets 2025-01-24 11:03:40 +01:00
kolaente bc0c0b103f
feat: validate expand api parameter 2025-01-24 10:09:36 +01:00
kolaente debdcd4dd3
docs: clarify return value of /tasks 2025-01-20 16:23:26 +01:00
kolaente a7be41ef04
fix(filter): do not override filter include nulls query
This fixes a bug where the "include nulls" query parameter would get overridden when the current view had a filter set, even if that filter didn't specify the parameter.
2025-01-20 14:23:35 +01:00
kolaente 7ac2c42e4d
fix(caldav): fetch saved filter
This fixes a bug which caused fetching saved filter and favorite projects to crash, because the respective project ID is not a valid project id without special handling.
2024-12-11 17:05:51 +01:00
kolaente bbbd936868
fix(saved filters): check permissions when accessing tasks of a filter 2024-11-21 15:42:26 +01:00
kolaente f2eac4623d
fix(filters): do not crash when paginating bucket with empty filter
Resolves https://community.vikunja.io/t/error-in-kanban-view-of-virtual-project-saved-filter/2876/7
2024-11-19 19:32:09 +01:00
kolaente d616bab76d fix(views): enable search in bucket filters 2024-11-19 16:27:22 +00:00
kolaente 624907ad6a fix: make search in saved filter work 2024-11-19 16:27:22 +00:00
kolaente d81f2db6ef
chore: replace all uses of bucket_id with the const 2024-10-02 10:43:51 +02:00
kolaente 425f6378c6
fix(kanban): make loading tasks for a bucket work
This fixes two closely-related bugs:
1. When loading tasks from a bucket of a saved filter, the saved filter query would override the user-supplied filter, which would cause to only tasks matching the saved filter query to be returned.
2. When a filter query for a bucket was specified, the function would only check if one of the top level filters was a filter for tasks in a specific bucket. That means a filter like "bucket_id = 42 && labels = foo" would return the expected result, while a filter like "labels = foo && (bucket_id = 42 && priority = 1)" would fail with an error 500 because the task_buckets table was not joined to the sql query. The fix from the first bug caused such filter queries.
2024-10-02 10:41:38 +02:00
kolaente 1451f6e46f
fix(kanban): correctly paginate filtered kanban buckets
Resolves https://github.com/go-vikunja/vikunja/issues/314
2024-09-14 09:37:21 +02:00
kolaente 45ff5907e6
fix(view): correctly resolve bucket filter when paginating 2024-09-13 19:45:48 +02:00
kolaente 2063da9eec
chore(web): move web handler package to Vikunja 2024-08-29 16:15:28 +02:00
kolaente e56b2232bb
fix(typesense): do not try to sort by position when searching in a saved filter
This change fixes a bug where Typesense would try to sort by the project view of a saved filter. The view position is not indexed in Typesense, hence filtering fails. Because sorting by position is not a feature in saved filters, I've removed the logic for sorting saved filters with Typesense.
2024-06-05 10:24:28 +02:00
kolaente 48676050d7 feat(tasks): expand subtasks (#2345)
This change adds a parameter to expand subtasks - if provided, Vikunja will ensure all subtasks are present in the results list.

Resolves https://community.vikunja.io/t/subtasks-show-on-different-pages/2292
Reviewed-on: https://kolaente.dev/vikunja/vikunja/pulls/2345
Co-authored-by: kolaente <k@knt.li>
Co-committed-by: kolaente <k@knt.li>
2024-06-04 10:27:23 +00:00
kolaente d8ca1a2de1
fix(favorites): make favorites work with configurable views 2024-04-14 17:12:16 +02:00
kolaente 3519b8b2fe
fix(tasks): index and order by task position when using typesense 2024-04-13 17:19:27 +02:00
kolaente 6f51b56589
fix: lint 2024-03-19 16:49:39 +01:00
kolaente e940db6d32
fix(views): return only tasks when the bucket id was already specified 2024-03-19 13:55:28 +01:00
kolaente 7368a51f18
fix(views): make setting task position in saved filters work 2024-03-19 00:47:49 +01:00
kolaente e1774cc49a
feat(views): show tasks on kanban board in saved filter 2024-03-19 00:47:49 +01:00
kolaente 7f1788eba9
fix(views): get tasks in saved filter 2024-03-19 00:47:49 +01:00
kolaente 5451ddf58d
fix(views): return tasks directly or in buckets, no matter if accessing via user or link share 2024-03-19 00:47:49 +01:00
kolaente f364f3bec8
feat(views): return position when retriving tasks 2024-03-19 00:47:48 +01:00
kolaente 73e5483e87
fix(views): do not break filters when combining them with view filters 2024-03-19 00:47:48 +01:00
kolaente ca4e3e01c5
feat(views): recalculate all positions when updating 2024-03-19 00:47:47 +01:00
kolaente d1d07f462c
feat(views): sort tasks by their position relative to the view they're in 2024-03-19 00:47:46 +01:00
kolaente 2502776460
feat(views)!: move task position handling to its own crud entity
BREAKING CHANGE: the position of tasks now can't be updated anymore via the task update endpoint. Instead, there is a new endpoint which takes the project view into account as well.
2024-03-19 00:47:46 +01:00