From 6a6f17594c3680adebed9d04badacdadb4ceee9b Mon Sep 17 00:00:00 2001 From: pikann22 Date: Mon, 19 Oct 2026 08:51:19 +0000 Subject: [PATCH] feat: enhance task listing with pagination support and add TaskPage interface --- README.md | 2 +- src/api-client.ts | 23 ++++++++++++++++------- src/index.ts | 1 + src/types.ts | 13 +++++++++++++ 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 0f7075c..3d1637a 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Returns `{ api, ui, meta }` from the nearest ``. ### `PluginApiClient` Scoped HTTP client. Methods: -- `listTasks(filters?)` — list tasks in current project +- `listTasks(filters?)` — the first page of the current project's tasks (up to 200); use `listTasksPage(filters?)` and follow `next_cursor` to read them all - `getTask(taskId)` — fetch a single task - `getProject()` — fetch current project summary - `listMembers()` — list project members diff --git a/src/api-client.ts b/src/api-client.ts index d4dfc4c..4630cc6 100644 --- a/src/api-client.ts +++ b/src/api-client.ts @@ -11,6 +11,7 @@ import type { ListMembersOptions, MemberPage, ProjectSummary, + TaskPage, Task, TaskFilters, TaskSummary, @@ -59,13 +60,23 @@ export class PluginApiClient { // ── Core read-only helpers ────────────────────────────────────────────── /** - * List tasks for the current project with optional filters. - * Defaults to the host's max page size (200) when the caller doesn't - * specify one, since most callers use this for an unfiltered "get the - * project's tasks" lookup and the host otherwise defaults to only 20. + * The first page of the current project's tasks (up to 200 by default). + * A project with more matching tasks is truncated: use `listTasksPage` and + * follow `next_cursor` when every task matters. */ async listTasks(filters: TaskFilters = {}): Promise { + return (await this.listTasksPage(filters)).items; + } + + /** + * One page of the current project's tasks with optional filters. Pass the + * previous page's `next_cursor` as `filters.cursor` for the next page. + * Defaults to the host's max page size (200) when the caller doesn't + * specify one, since the host otherwise defaults to only 20. + */ + async listTasksPage(filters: TaskFilters = {}): Promise { const params = new URLSearchParams(); + if (filters.cursor) params.set("cursor", filters.cursor); if (filters.status_ids?.length) params.set("status_ids", filters.status_ids.join(",")); if (filters.assignee_ids?.length) @@ -73,13 +84,11 @@ export class PluginApiClient { if (filters.sprint_id) params.set("sprint_id", filters.sprint_id); if (filters.parent_task_id) params.set("parent_task_id", filters.parent_task_id); - if (filters.page) params.set("page", String(filters.page)); params.set("page_size", String(filters.page_size ?? 200)); const qs = params.toString(); const url = `${this.baseUrl}/projects/${this.projectId}/tasks${qs ? `?${qs}` : ""}`; - const envelope = await this._get<{ items: TaskSummary[] }>(url); - return envelope.items; + return this._get(url); } /** Get a single task by ID. */ diff --git a/src/index.ts b/src/index.ts index f9f93d5..68d47c3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -40,6 +40,7 @@ export type { ProjectSummary, Task, TaskFilters, + TaskPage, TaskSummary, } from "./types"; export { permissionsFromRole } from "./types"; diff --git a/src/types.ts b/src/types.ts index 862ec62..431fd77 100644 --- a/src/types.ts +++ b/src/types.ts @@ -26,10 +26,23 @@ export interface TaskFilters { assignee_ids?: string[]; sprint_id?: string; parent_task_id?: string; + /** Cursor from a previous page's `next_cursor` (see listTasksPage). */ + cursor?: string; + /** @deprecated Ignored: tasks page by cursor. Use `cursor` (see listTasksPage). */ page?: number; page_size?: number; } +/** One page of the tasks list, keyset-paginated by cursor. */ +export interface TaskPage { + items: TaskSummary[]; + page_size: number; + /** Pass as `cursor` for the next page; null on the last page. */ + next_cursor: string | null; + /** Tasks matching the filters across all pages (first page only). */ + total_count?: number; +} + // ── Project ─────────────────────────────────────────────────────────────────── /** Project summary returned by the project_get host function. */