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

@@ -871,6 +871,44 @@ export interface paths {
patch?: never;
trace?: never;
};
"/api/projects/{project}/filters": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/** My views of the project's board, then the shared ones */
get: operations["SavedFiltersController_list"];
put?: never;
/**
* Save board filters under a name
* @description Project members only. `shared` makes it visible to the whole project (not for viewers).
*/
post: operations["SavedFiltersController_save"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/filters/{id}": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
post?: never;
/** Delete a saved view (whoever saved it, or an admin if shared) */
delete: operations["SavedFiltersController_delete"];
options?: never;
head?: never;
patch?: never;
trace?: never;
};
}
export type webhooks = Record<string, never>;
export interface components {
@@ -1616,6 +1654,59 @@ export interface components {
/** @description Copies by e-mail */
email: boolean;
};
SavedFilterCriteriaResponseDto: {
types?: string[];
areas?: string[];
priorities?: components["schemas"]["IssuePriority"][];
assigneeId?: string | null;
unassigned?: boolean;
/** Format: uuid */
releaseId?: string | null;
labels?: string[];
search?: string | null;
};
SavedFilterDto: {
/** Format: uuid */
id: string;
/** Format: uuid */
projectId: string;
owner: components["schemas"]["UserRefDto"];
/** @example Bugs críticos de frontend */
name: string;
/** @description Visible to the whole project */
shared: boolean;
criteria: components["schemas"]["SavedFilterCriteriaResponseDto"];
/** Format: date-time */
createdAt: string;
};
SavedFilterCriteriaDto: {
/** @description Ticket type ids */
types?: string[];
/** @description Area ids */
areas?: string[];
priorities?: components["schemas"]["IssuePriority"][];
/** @description Pireon user id */
assigneeId?: string | null;
unassigned?: boolean;
/** Format: uuid */
releaseId?: string | null;
labels?: string[];
search?: string | null;
};
SaveFilterDto: {
/** @example Bugs críticos de frontend */
name: string;
/**
* @description Visible to the whole project (members, not viewers, share)
* @default false
*/
shared: Record<string, never>;
criteria: components["schemas"]["SavedFilterCriteriaDto"];
};
SavedFilterIdDto: {
/** Format: uuid */
id: string;
};
};
responses: never;
parameters: never;
@@ -2339,6 +2430,14 @@ export interface operations {
assigneeId?: string;
/** @description An area id */
area?: string;
/** @description Ticket type ids */
type?: string[];
priority?: components["schemas"]["IssuePriority"][];
label?: string[];
/** @description Matches key, title or description */
search?: string;
/** @description Only tickets without assignee */
unassigned?: boolean;
perColumn?: number;
};
header?: never;
@@ -5702,4 +5801,215 @@ export interface operations {
};
};
};
SavedFiltersController_list: {
parameters: {
query?: never;
header?: never;
path: {
/** @description Project id or key */
project: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["SavedFilterDto"][];
};
};
/** @description Invalid input */
400: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ApiErrorDto"];
};
};
/** @description Missing or rejected Pireon token */
401: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ApiErrorDto"];
};
};
/** @description Not a member of the project (or not allowed) */
403: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ApiErrorDto"];
};
};
/** @description Not found */
404: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ApiErrorDto"];
};
};
};
};
SavedFiltersController_save: {
parameters: {
query?: never;
header?: never;
path: {
/** @description Project id or key */
project: string;
};
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["SaveFilterDto"];
};
};
responses: {
201: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["SavedFilterIdDto"];
};
};
/** @description Invalid input */
400: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ApiErrorDto"];
};
};
/** @description Missing or rejected Pireon token */
401: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ApiErrorDto"];
};
};
/** @description Not a member of the project (or not allowed) */
403: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ApiErrorDto"];
};
};
/** @description Not found */
404: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ApiErrorDto"];
};
};
/** @description Someone changed it at the same time: retry */
409: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ApiErrorDto"];
};
};
/** @description Business rule (e.g. a transition the workflow forbids) */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ApiErrorDto"];
};
};
};
};
SavedFiltersController_delete: {
parameters: {
query?: never;
header?: never;
path: {
id: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
204: {
headers: {
[name: string]: unknown;
};
content?: never;
};
/** @description Invalid input */
400: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ApiErrorDto"];
};
};
/** @description Missing or rejected Pireon token */
401: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ApiErrorDto"];
};
};
/** @description Not a member of the project (or not allowed) */
403: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ApiErrorDto"];
};
};
/** @description Not found */
404: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ApiErrorDto"];
};
};
/** @description Someone changed it at the same time: retry */
409: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ApiErrorDto"];
};
};
/** @description Business rule (e.g. a transition the workflow forbids) */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ApiErrorDto"];
};
};
};
};
}