From d3676e635fa90dffc6ab1093a363feb1409efc72 Mon Sep 17 00:00:00 2001 From: Isaac Johnson Date: Mon, 1 Jun 2026 18:20:58 -0500 Subject: [PATCH] reload --- src/api.ts | 43 +++++++++++++++++++++++++++++++++++++++++++ src/tui.ts | 40 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 81 insertions(+), 2 deletions(-) diff --git a/src/api.ts b/src/api.ts index f6f1fd2..75e6e3a 100644 --- a/src/api.ts +++ b/src/api.ts @@ -139,6 +139,49 @@ export async function fetchIssues( } } +/** + * Fetches a single issue by number. + */ +export async function fetchIssue( + config: Config, + issueNumber: number +): Promise { + const client = createAxiosInstance(config); + try { + const response = await client.get(`/repos/${config.owner}/${config.repo}/issues/${issueNumber}`); + const item = response.data; + return { + id: item.id, + number: item.number, + title: item.title, + state: item.state, + body: item.body || '', + user: { + id: item.user?.id || 0, + login: item.user?.login || 'unknown', + full_name: item.user?.full_name || '', + }, + created_at: item.created_at, + updated_at: item.updated_at, + comments: item.comments_count || item.comments || 0, + labels: (item.labels || []).map((l: any) => ({ + id: l.id, + name: l.name, + color: l.color, + })), + pull_request: item.pull_request, + }; + } catch (error: any) { + if (error.response) { + if (error.response.status === 401) { + throw new Error('Unauthorized: Please check your token.'); + } + throw new Error(`Failed to fetch issue: ${error.response.data?.message || error.message}`); + } + throw new Error(`Network Error: ${error.message}`); + } +} + /** * Fetches comments for a specific issue. */ diff --git a/src/tui.ts b/src/tui.ts index 8b51c21..22104b1 100644 --- a/src/tui.ts +++ b/src/tui.ts @@ -1,7 +1,7 @@ import readline from 'readline'; import chalk from 'chalk'; import { AppState, Issue, Comment } from './types.js'; -import { fetchIssues, fetchIssueComments, validateConnection, normalizeUrl, authenticateAndFetchRepos, createIssue, createIssueComment, editIssue } from './api.js'; +import { fetchIssues, fetchIssue, fetchIssueComments, validateConnection, normalizeUrl, authenticateAndFetchRepos, createIssue, createIssueComment, editIssue } from './api.js'; import { saveGlobalConfig } from './config.js'; // Setup readline for stdin keypress events @@ -198,6 +198,35 @@ export class TuiEngine { } } + /** + * Fetches the current single issue and its comments again. + */ + private async reloadSingleIssue() { + if (!this.state.selectedIssue) return; + this.state.loading = true; + this.state.error = null; + this.startSpinner(); + + try { + const issue = await fetchIssue(this.state.config, this.state.selectedIssue.number); + this.state.selectedIssue = issue; + + // Update in the main list as well + const listIndex = this.state.issues.findIndex(i => i.number === issue.number); + if (listIndex !== -1) { + this.state.issues[listIndex] = issue; + } + + await this.loadComments(issue); + } catch (err: any) { + this.state.error = `Failed to reload issue: ${err.message}`; + } finally { + this.state.loading = false; + this.stopSpinner(); + this.render(); + } + } + /** * Fetches comments for the selected issue. */ @@ -690,6 +719,13 @@ export class TuiEngine { } return; } + + if (str === 'r' || str === 'R') { + if (this.state.selectedIssue) { + this.reloadSingleIssue(); + } + return; + } if ((key && (key.name === 'escape' || key.name === 'backspace')) || str === '\u001b' || str === 'q' || str === 'Q') { this.state.screen = 'list'; @@ -1124,7 +1160,7 @@ export class TuiEngine { scrollHelp += chalk.yellow(` (${pct}%)`); } - const helpLine = chalk.gray(` [Esc/Backspace] Back to List [C] Add Comment [E] Edit [O] Settings ${scrollHelp}`); + const helpLine = chalk.gray(` [Esc/Backspace] Back to List [C] Add Comment [E] Edit [R] Reload [O] Settings ${scrollHelp}`); process.stdout.write(helpLine); }