feat: saved board views and richer board filters

The board now filters by text, type, priority and unassigned tickets as
well. Any combination can be saved as a named view, private or shared with
the project, and opened again with one click.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 14:14:38 +02:00
parent 0606f53026
commit 298383f19f
46 changed files with 2922 additions and 26 deletions

View File

@@ -399,6 +399,9 @@ type Mutation {
Delete the project (owner only), with its tickets, comments and releases. `confirmKey` must be the project key.
"""
deleteProject(confirmKey: String!, projectId: ID!): CommandResult!
"""Delete a view: whoever saved it, or an admin if it is shared"""
deleteSavedFilter(id: ID!): Boolean!
editComment(body: String!, commentId: ID!): CommandResult!
"""Relate tickets, e.g. FE DEPENDS_ON BE, QA TESTS FE"""
@@ -422,6 +425,9 @@ type Mutation {
removeChecklistItem(issueId: ID!, itemId: ID!): CommandResult!
removeProjectMember(projectId: ID!, userId: ID!): CommandResult!
"""Save the current board filters under a name (members of the project)"""
saveFilter(input: SaveFilterInput!): ID!
"""
Place a ticket under an epic or another ticket of the same project (null: back to the top). Three levels at most: epic → ticket → subtask.
"""
@@ -501,7 +507,19 @@ type Project {
analytics(days: Int! = 90): ProjectAnalytics!
"""Kanban board, one column per status"""
board(area: String, assigneeId: ID, perColumn: Int! = 50, releaseId: ID): [BoardColumn!]!
board(
area: String
assigneeId: ID
labels: [String!]
perColumn: Int! = 50
priorities: [IssuePriority!]
releaseId: ID
"""Matches key, title or description"""
search: String
types: [String!]
unassigned: Boolean
): [BoardColumn!]!
createdAt: String!
description: String
id: ID!
@@ -648,6 +666,9 @@ type Query {
publicProjects: [Project!]!
release(id: ID!): Release!
"""My views of the project's board, then the shared ones"""
savedFilters(projectId: ID!): [SavedFilter!]!
"""Planned releases of all my projects, soonest target date first"""
upcomingReleases(limit: Int! = 10): [Release!]!
user(id: String!): User
@@ -718,6 +739,51 @@ enum ReleaseStatus {
RELEASED
}
input SaveFilterInput {
criteria: SavedFilterCriteriaInput!
name: String!
projectId: ID!
"""Visible to the whole project (members, not viewers, share)"""
shared: Boolean! = false
}
"""
A named view of the board: private to whoever saved it, or shared with the project
"""
type SavedFilter {
createdAt: String!
criteria: SavedFilterCriteria!
id: ID!
name: String!
owner: UserRef!
projectId: ID!
shared: Boolean!
}
"""What a saved view narrows the board to; empty: everything"""
type SavedFilterCriteria {
areas: [String!]
assigneeId: ID
labels: [String!]
priorities: [IssuePriority!]
releaseId: ID
search: String
types: [String!]
unassigned: Boolean
}
input SavedFilterCriteriaInput {
areas: [String!]
assigneeId: ID
labels: [String!]
priorities: [IssuePriority!]
releaseId: ID
search: String
types: [String!]
unassigned: Boolean
}
"""
What a status means, whatever each project calls it. DONE and CANCELLED are finished.
"""