feat: saved views of my work, across my projects
A person saves named views of «my work»: projects, assigned to me, that I follow, status categories, priorities, bugs only, overdue and text. They are private (Mongo my_views, no history), listed and deleted by their owner (GraphQL myViews / saveMyView / deleteMyView, REST /api/me/views), and run as the cross-project search, which gains project, priority, bugsOnly and overdue filters (also in MCP my_issues). The home page shows them as a bar above «my work», with a drawer to save a new one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1441,4 +1441,74 @@ describe('task-stream (e2e)', () => {
|
||||
expect(later.body['quality'].bugWeeks).toHaveLength(8);
|
||||
expect(later.body['fields']).toEqual([]);
|
||||
});
|
||||
|
||||
it('keeps my own views of my work, across my projects', async () => {
|
||||
const key = 'V' + Date.now().toString(36).slice(-5).toUpperCase();
|
||||
await rest('token-ana', 'POST', '/projects', { key, name: key });
|
||||
const project = await eventually(
|
||||
() => rest('token-ana', 'GET', `/projects/${key}`),
|
||||
(r) => r.status === 200,
|
||||
);
|
||||
const bug = (
|
||||
await rest('token-ana', 'POST', `/projects/${key}/issues`, {
|
||||
type: 'BUG',
|
||||
title: 'Late bug',
|
||||
priority: 'CRITICAL',
|
||||
dueDate: '2020-01-01',
|
||||
})
|
||||
).body['key'];
|
||||
await rest('token-ana', 'POST', `/projects/${key}/issues`, {
|
||||
type: 'TASK',
|
||||
title: 'Late task',
|
||||
priority: 'CRITICAL',
|
||||
dueDate: '2020-01-01',
|
||||
});
|
||||
await eventually(
|
||||
() => rest('token-ana', 'GET', `/issues/${key}-2`),
|
||||
(r) => r.status === 200,
|
||||
);
|
||||
|
||||
const criteria = {
|
||||
projectIds: [project.body['id']],
|
||||
priorities: ['CRITICAL'],
|
||||
bugsOnly: true,
|
||||
overdue: true,
|
||||
};
|
||||
const saved = await rest('token-ana', 'POST', '/me/views', {
|
||||
name: ' Bugs críticos vencidos ',
|
||||
criteria,
|
||||
});
|
||||
expect(saved.status).toBe(201);
|
||||
const views = await rest('token-ana', 'GET', '/me/views');
|
||||
expect(views.body).toEqual([
|
||||
expect.objectContaining({ name: 'Bugs críticos vencidos', criteria }),
|
||||
]);
|
||||
expect((await rest('token-bob', 'GET', '/me/views')).body).toEqual([]);
|
||||
|
||||
// Running it: the same criteria on my work.
|
||||
const page = await rest(
|
||||
'token-ana',
|
||||
'GET',
|
||||
`/me/issues?assignedToMe=false&project=${project.body['id']}&priority=CRITICAL&bugsOnly=true&overdue=true`,
|
||||
);
|
||||
expect(page.body['items'].map((i: { key: string }) => i.key)).toEqual([
|
||||
bug,
|
||||
]);
|
||||
const { myIssues } = await gql(
|
||||
'token-ana',
|
||||
`query($p: [ID!]) { myIssues(assignedToMe: false, projectIds: $p, overdue: true) { total } }`,
|
||||
{ p: [project.body['id']] },
|
||||
);
|
||||
expect(myIssues.total).toBe(2);
|
||||
|
||||
// Only its owner deletes it.
|
||||
const id = saved.body['id'];
|
||||
expect((await rest('token-bob', 'DELETE', `/me/views/${id}`)).status).toBe(
|
||||
404,
|
||||
);
|
||||
expect((await rest('token-ana', 'DELETE', `/me/views/${id}`)).status).toBe(
|
||||
204,
|
||||
);
|
||||
expect((await rest('token-ana', 'GET', '/me/views')).body).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2260,6 +2260,47 @@
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "project",
|
||||
"required": false,
|
||||
"in": "query",
|
||||
"description": "Only these of my projects (ids). Repeat or separate with commas",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "priority",
|
||||
"required": false,
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/IssuePriority"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "bugsOnly",
|
||||
"required": false,
|
||||
"in": "query",
|
||||
"description": "Only types with the bug icon",
|
||||
"schema": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "overdue",
|
||||
"required": false,
|
||||
"in": "query",
|
||||
"description": "Only open tickets past their due date",
|
||||
"schema": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -7806,6 +7847,271 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/me/views": {
|
||||
"get": {
|
||||
"operationId": "SavedFiltersController_myViews",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/MyViewDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid input",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Missing or rejected Pireon token",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Not a member of the project (or not allowed)",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"pireon-oauth": []
|
||||
},
|
||||
{
|
||||
"pireon": []
|
||||
}
|
||||
],
|
||||
"summary": "My saved views of my work, across my projects (by name)",
|
||||
"tags": [
|
||||
"Saved filters"
|
||||
]
|
||||
},
|
||||
"post": {
|
||||
"description": "Run it with GET /api/me/issues and the same criteria (project, priority, bugsOnly, overdue…).",
|
||||
"operationId": "SavedFiltersController_saveMyView",
|
||||
"parameters": [],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SaveMyViewDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SavedFilterIdDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid input",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Missing or rejected Pireon token",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Not a member of the project (or not allowed)",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"409": {
|
||||
"description": "Someone changed it at the same time: retry",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Business rule (e.g. a transition the workflow forbids)",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"pireon-oauth": []
|
||||
},
|
||||
{
|
||||
"pireon": []
|
||||
}
|
||||
],
|
||||
"summary": "Save a view of my work under a name",
|
||||
"tags": [
|
||||
"Saved filters"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/me/views/{id}": {
|
||||
"delete": {
|
||||
"operationId": "SavedFiltersController_deleteMyView",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"format": "uuid",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": ""
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid input",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Missing or rejected Pireon token",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Not a member of the project (or not allowed)",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"409": {
|
||||
"description": "Someone changed it at the same time: retry",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Business rule (e.g. a transition the workflow forbids)",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"pireon-oauth": []
|
||||
},
|
||||
{
|
||||
"pireon": []
|
||||
}
|
||||
],
|
||||
"summary": "Delete one of my views",
|
||||
"tags": [
|
||||
"Saved filters"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/projects/{project}/sprints": {
|
||||
"get": {
|
||||
"description": "The one under way, the planned ones, then the closed ones.",
|
||||
@@ -14193,6 +14499,132 @@
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"MyViewCriteriaResponseDto": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"projectIds": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
},
|
||||
"assignedToMe": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"watching": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"categories": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/StatusCategory"
|
||||
}
|
||||
},
|
||||
"priorities": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/IssuePriority"
|
||||
}
|
||||
},
|
||||
"bugsOnly": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"overdue": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"search": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"MyViewDto": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"example": "Bugs críticos de todos mis proyectos"
|
||||
},
|
||||
"criteria": {
|
||||
"$ref": "#/components/schemas/MyViewCriteriaResponseDto"
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"name",
|
||||
"criteria",
|
||||
"createdAt"
|
||||
]
|
||||
},
|
||||
"MyViewCriteriaDto": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"projectIds": {
|
||||
"description": "Only these of my projects (empty: all)",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
},
|
||||
"assignedToMe": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"watching": {
|
||||
"type": "boolean",
|
||||
"description": "Only the tickets I follow"
|
||||
},
|
||||
"categories": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/StatusCategory"
|
||||
}
|
||||
},
|
||||
"priorities": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/IssuePriority"
|
||||
}
|
||||
},
|
||||
"bugsOnly": {
|
||||
"type": "boolean",
|
||||
"description": "Only types with the bug icon"
|
||||
},
|
||||
"overdue": {
|
||||
"type": "boolean",
|
||||
"description": "Only open tickets past due"
|
||||
},
|
||||
"search": {
|
||||
"type": "string",
|
||||
"maxLength": 200
|
||||
}
|
||||
}
|
||||
},
|
||||
"SaveMyViewDto": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"example": "Bugs críticos de todos mis proyectos",
|
||||
"maxLength": 60
|
||||
},
|
||||
"criteria": {
|
||||
"$ref": "#/components/schemas/MyViewCriteriaDto"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"criteria"
|
||||
]
|
||||
},
|
||||
"SprintStatus": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
||||
@@ -836,6 +836,9 @@ type Mutation {
|
||||
"""Author or project admin"""
|
||||
deleteComment(commentId: ID!): CommandResult!
|
||||
|
||||
"""Delete one of my views"""
|
||||
deleteMyView(id: ID!): Boolean!
|
||||
|
||||
"""
|
||||
Delete the project (owner only), with its tickets, comments and releases. `confirmKey` must be the project key.
|
||||
"""
|
||||
@@ -893,6 +896,9 @@ type Mutation {
|
||||
"""Save the current board filters under a name (members of the project)"""
|
||||
saveFilter(input: SaveFilterInput!): ID!
|
||||
|
||||
"""Save a view of my work under a name"""
|
||||
saveMyView(input: SaveMyViewInput!): 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.
|
||||
"""
|
||||
@@ -965,6 +971,45 @@ type MyNotifications {
|
||||
unread: Int!
|
||||
}
|
||||
|
||||
"""A named view of my work (private)"""
|
||||
type MyView {
|
||||
createdAt: String!
|
||||
criteria: MyViewCriteria!
|
||||
id: ID!
|
||||
name: String!
|
||||
}
|
||||
|
||||
"""What a view of my work narrows to; empty: every ticket of my projects"""
|
||||
type MyViewCriteria {
|
||||
assignedToMe: Boolean
|
||||
|
||||
"""Only types with the bug icon"""
|
||||
bugsOnly: Boolean
|
||||
categories: [StatusCategory!]
|
||||
|
||||
"""Only open tickets past due"""
|
||||
overdue: Boolean
|
||||
priorities: [IssuePriority!]
|
||||
|
||||
"""Empty: all my projects"""
|
||||
projectIds: [ID!]
|
||||
search: String
|
||||
watching: Boolean
|
||||
}
|
||||
|
||||
input MyViewCriteriaInput {
|
||||
assignedToMe: Boolean
|
||||
bugsOnly: Boolean
|
||||
categories: [StatusCategory!]
|
||||
overdue: Boolean
|
||||
priorities: [IssuePriority!]
|
||||
|
||||
"""Empty: all my projects"""
|
||||
projectIds: [ID!]
|
||||
search: String
|
||||
watching: Boolean
|
||||
}
|
||||
|
||||
type Notification {
|
||||
actor: UserRef!
|
||||
createdAt: String!
|
||||
@@ -1234,10 +1279,20 @@ type Query {
|
||||
"""
|
||||
myIssues(
|
||||
assignedToMe: Boolean! = true
|
||||
|
||||
"""Only types drawn with the bug icon"""
|
||||
bugsOnly: Boolean
|
||||
categories: [StatusCategory!]
|
||||
limit: Int! = 50
|
||||
offset: Int! = 0
|
||||
|
||||
"""Only open tickets past their due date"""
|
||||
overdue: Boolean
|
||||
priorities: [IssuePriority!]
|
||||
|
||||
"""Only these of my projects"""
|
||||
projectIds: [ID!]
|
||||
|
||||
"""Matches key, title or description (global search)"""
|
||||
search: String
|
||||
statuses: [String!]
|
||||
@@ -1251,6 +1306,9 @@ type Query {
|
||||
|
||||
"""Projects where I am a member"""
|
||||
myProjects: [Project!]!
|
||||
|
||||
"""My saved views of my work, across my projects"""
|
||||
myViews: [MyView!]!
|
||||
notificationSettings: NotificationSettings!
|
||||
|
||||
"""A project of mine, or any public one (no sign-in needed)"""
|
||||
@@ -1399,6 +1457,11 @@ input SaveFilterInput {
|
||||
shared: Boolean! = false
|
||||
}
|
||||
|
||||
input SaveMyViewInput {
|
||||
criteria: MyViewCriteriaInput!
|
||||
name: String!
|
||||
}
|
||||
|
||||
"""
|
||||
A named view of the board: private to whoever saved it, or shared with the project
|
||||
"""
|
||||
|
||||
@@ -1188,6 +1188,44 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/me/views": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/** My saved views of my work, across my projects (by name) */
|
||||
get: operations["SavedFiltersController_myViews"];
|
||||
put?: never;
|
||||
/**
|
||||
* Save a view of my work under a name
|
||||
* @description Run it with GET /api/me/issues and the same criteria (project, priority, bugsOnly, overdue…).
|
||||
*/
|
||||
post: operations["SavedFiltersController_saveMyView"];
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/me/views/{id}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
get?: never;
|
||||
put?: never;
|
||||
post?: never;
|
||||
/** Delete one of my views */
|
||||
delete: operations["SavedFiltersController_deleteMyView"];
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/projects/{project}/sprints": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -2879,6 +2917,44 @@ export interface components {
|
||||
/** Format: uuid */
|
||||
id: string;
|
||||
};
|
||||
MyViewCriteriaResponseDto: {
|
||||
projectIds?: string[];
|
||||
assignedToMe?: boolean;
|
||||
watching?: boolean;
|
||||
categories?: components["schemas"]["StatusCategory"][];
|
||||
priorities?: components["schemas"]["IssuePriority"][];
|
||||
bugsOnly?: boolean;
|
||||
overdue?: boolean;
|
||||
search?: string;
|
||||
};
|
||||
MyViewDto: {
|
||||
/** Format: uuid */
|
||||
id: string;
|
||||
/** @example Bugs críticos de todos mis proyectos */
|
||||
name: string;
|
||||
criteria: components["schemas"]["MyViewCriteriaResponseDto"];
|
||||
/** Format: date-time */
|
||||
createdAt: string;
|
||||
};
|
||||
MyViewCriteriaDto: {
|
||||
/** @description Only these of my projects (empty: all) */
|
||||
projectIds?: string[];
|
||||
assignedToMe?: boolean;
|
||||
/** @description Only the tickets I follow */
|
||||
watching?: boolean;
|
||||
categories?: components["schemas"]["StatusCategory"][];
|
||||
priorities?: components["schemas"]["IssuePriority"][];
|
||||
/** @description Only types with the bug icon */
|
||||
bugsOnly?: boolean;
|
||||
/** @description Only open tickets past due */
|
||||
overdue?: boolean;
|
||||
search?: string;
|
||||
};
|
||||
SaveMyViewDto: {
|
||||
/** @example Bugs críticos de todos mis proyectos */
|
||||
name: string;
|
||||
criteria: components["schemas"]["MyViewCriteriaDto"];
|
||||
};
|
||||
/** @enum {string} */
|
||||
SprintStatus: "PLANNED" | "ACTIVE" | "CLOSED";
|
||||
SprintDto: {
|
||||
@@ -4600,6 +4676,13 @@ export interface operations {
|
||||
category?: components["schemas"]["StatusCategory"][];
|
||||
/** @description Matches key, title or description */
|
||||
search?: string;
|
||||
/** @description Only these of my projects (ids). Repeat or separate with commas */
|
||||
project?: string[];
|
||||
priority?: components["schemas"]["IssuePriority"][];
|
||||
/** @description Only types with the bug icon */
|
||||
bugsOnly?: boolean;
|
||||
/** @description Only open tickets past their due date */
|
||||
overdue?: boolean;
|
||||
};
|
||||
header?: never;
|
||||
path?: never;
|
||||
@@ -8458,6 +8541,211 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
SavedFiltersController_myViews: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["MyViewDto"][];
|
||||
};
|
||||
};
|
||||
/** @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_saveMyView: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["SaveMyViewDto"];
|
||||
};
|
||||
};
|
||||
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_deleteMyView: {
|
||||
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"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
SprintsController_list: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
||||
@@ -88,6 +88,15 @@ export class IssuesResolver {
|
||||
.array(CATEGORY)
|
||||
.optional()
|
||||
.describe('Default: open ones (TODO, IN_PROGRESS, QA)'),
|
||||
priorities: z.array(PRIORITY).optional(),
|
||||
bugsOnly: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe('Only types drawn with the bug icon, in each project'),
|
||||
overdue: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe('Only open tickets past their due date'),
|
||||
limit: limit(200, 50),
|
||||
}),
|
||||
annotations: READ,
|
||||
@@ -97,6 +106,9 @@ export class IssuesResolver {
|
||||
assignedToMe: boolean;
|
||||
watching: boolean;
|
||||
categories?: z.infer<typeof CATEGORY>[];
|
||||
priorities?: z.infer<typeof PRIORITY>[];
|
||||
bugsOnly?: boolean;
|
||||
overdue?: boolean;
|
||||
limit: number;
|
||||
},
|
||||
ctx: McpContext,
|
||||
@@ -109,6 +121,9 @@ export class IssuesResolver {
|
||||
assignedToMe: params.assignedToMe,
|
||||
watching: params.watching,
|
||||
category: params.categories ?? ['TODO', 'IN_PROGRESS', 'QA'],
|
||||
priority: params.priorities,
|
||||
bugsOnly: params.bugsOnly,
|
||||
overdue: params.overdue,
|
||||
limit: params.limit,
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user