fjtui/src/index.ts

107 lines
3.2 KiB
TypeScript
Raw Normal View History

2026-06-01 00:59:22 +00:00
#!/usr/bin/env node
import { Command } from 'commander';
import { AppState, Config } from './types.js';
import { TuiEngine } from './tui.js';
import { validateConnection, normalizeUrl } from './api.js';
import chalk from 'chalk';
const program = new Command();
program
.name('gitea-tui')
.description('A premium CLI TUI Dashboard for exploring Gitea and Forgejo issues')
.version('1.0.0')
.option('-u, --url <url>', 'Forgejo/Gitea instance base URL (e.g. https://forgejo.freshbrewed.science)')
.option('-r, --repo <owner/repo>', 'Repository path (e.g. owner/repo)')
.option('-t, --token <token>', 'Personal Access Token (optional for public repositories)');
program.parse(process.argv);
const options = program.opts();
async function bootstrap() {
// Initialize default state
const state: AppState = {
screen: 'setup',
config: {
url: '',
token: null,
owner: '',
repo: '',
},
issues: [],
currentPage: 1,
issuesPerPage: 15, // matches standard screen sizes perfectly
totalIssuesCount: 0,
loading: false,
error: null,
selectedIssueIndex: 0,
searchQuery: '',
stateFilter: 'open',
typeFilter: 'all',
sortField: 'created',
sortOrder: 'desc',
selectedIssue: null,
selectedIssueComments: [],
commentsLoading: false,
detailScrollOffset: 0,
setupForm: {
url: options.url || 'https://forgejo.freshbrewed.science',
repo: options.repo || '',
token: options.token || '',
activeField: options.url ? (options.repo ? 'token' : 'repo') : 'url',
},
};
// If parameters are provided, try direct connection first
if (options.url && options.repo) {
const repoParts = options.repo.split('/');
if (repoParts.length === 2 && repoParts[0].trim() && repoParts[1].trim()) {
const normalized = normalizeUrl(options.url);
const config: Config = {
url: normalized,
token: options.token ? options.token.trim() : null,
owner: repoParts[0].trim(),
repo: repoParts[1].trim(),
};
console.log(chalk.cyan(`Connecting to Gitea/Forgejo instance at ${normalized}...`));
try {
await validateConnection(config);
// Valid connection! Go straight to list screen
state.config = config;
state.screen = 'list';
} catch (err: any) {
// Validation failed, let's load setup form with the entered values and show error!
state.error = `Connection failed: ${err.message}`;
state.screen = 'setup';
state.setupForm = {
url: options.url,
repo: options.repo,
token: options.token || '',
activeField: 'url',
};
}
} else {
state.error = 'Invalid --repo option. Must be in owner/repo format.';
state.screen = 'setup';
}
}
// Create and start the TUI engine
const engine = new TuiEngine(state);
engine.start(() => {
// Perform cleanup and exit cleanly
console.log(chalk.bold.green('\nThank you for using Forgejo TUI Issue Explorer! Goodbye.'));
process.exit(0);
});
}
bootstrap().catch((err) => {
console.error(chalk.bold.red('Fatal Error on Bootstrap:'), err);
process.exit(1);
});