feat(KB-022): add GitHub issue status badges to task cards
- Extend core types with GitHub issue tracking fields (issueNumber, issueStatus, lastIssueSync) - Add TaskStore.getTaskGitHubIssueInfo() to fetch issue details from GitHub API - Create server-side API endpoint for issue status lookup with caching - Build GitHubBadge component with color-coded status indicators (open/closed) - Integrate badges into TaskCard with hover state linking to GitHub issues - Add CSS styles for badge positioning and visual polish - Include comprehensive tests for GitHubBadge and TaskCard badge rendering
This commit is contained in:
@@ -220,6 +220,56 @@ export class GitHubClient {
|
||||
private mapPrState(state: string): "open" | "closed" {
|
||||
return state === "open" ? "open" : "closed";
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch current issue status from GitHub API.
|
||||
* Returns null if the issue is not found or is a pull request.
|
||||
*/
|
||||
async getIssueStatus(
|
||||
owner: string,
|
||||
repo: string,
|
||||
number: number,
|
||||
): Promise<Omit<import("@kb/core").IssueInfo, "lastCheckedAt"> | null> {
|
||||
const url = `${this.baseUrl}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues/${number}`;
|
||||
|
||||
const headers = this.buildHeaders();
|
||||
|
||||
const response = await fetch(url, { headers });
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 404) {
|
||||
return null;
|
||||
}
|
||||
const error = await response.json().catch(() => ({ message: response.statusText }));
|
||||
throw new Error(`GitHub API error: ${response.status} ${error.message || response.statusText}`);
|
||||
}
|
||||
|
||||
const data = (await response.json()) as {
|
||||
number: number;
|
||||
html_url: string;
|
||||
title: string;
|
||||
state: string;
|
||||
state_reason?: "completed" | "not_planned" | "reopened";
|
||||
pull_request?: unknown;
|
||||
};
|
||||
|
||||
// Filter out pull requests - this endpoint returns both issues and PRs
|
||||
if (data.pull_request) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
url: data.html_url,
|
||||
number: data.number,
|
||||
state: this.mapIssueState(data.state),
|
||||
title: data.title,
|
||||
stateReason: data.state_reason,
|
||||
};
|
||||
}
|
||||
|
||||
private mapIssueState(state: string): "open" | "closed" {
|
||||
return state === "open" ? "open" : "closed";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user