fjtui/src/index.ts

176 lines
5.1 KiB
JavaScript

#!/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 { loadSavedConfig, saveGlobalConfig } from './config.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('-i, --userid <userid>', 'Forgejo/Gitea user ID / username')
.option('-r, --repo <owner/repo>', 'Repository path (e.g. owner/repo)')
.option('-t, --token <token>', 'Personal Access Token (optional for public repositories)')
.option('-s, --save', 'Save the provided settings to the global config file (~/.config/fjtui/fjtui.json)');
program.parse(process.argv);
const options = program.opts();
async function bootstrap() {
const savedConfig = loadSavedConfig();
const url = options.url || savedConfig.url || '';
const userid = options.userid || savedConfig.userid || '';
const token = options.token || savedConfig.token || '';
const repo = options.repo || savedConfig.repo || '';
// Initialize default state
const state: AppState = {
screen: 'setup',
previousScreen: 'list',
focusedPane: 'list',
selectedSettingIndex: 0,
autoRefreshInterval: savedConfig.autoRefreshInterval || 0,
config: {
url: '',
token: null,
userid: '',
owner: '',
repo: '',
autoRefreshInterval: savedConfig.autoRefreshInterval || 0,
},
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,
assigneesInput: '',
repos: [],
selectedRepoIndex: 0,
repoSearchQuery: '',
repoPickerActiveSearch: false,
setupForm: {
url: url || 'https://forgejo.freshbrewed.science',
userid: userid || '',
token: token || '',
saveConfig: true,
activeField: url ? (userid ? 'token' : 'userid') : 'url',
},
createIssueForm: {
title: '',
body: '',
activeField: 'title',
},
addCommentForm: {
body: '',
},
editIssueForm: {
title: '',
body: '',
activeField: 'title',
},
addTimeForm: {
timeInput: '',
},
labels: [],
selectedLabelIndex: 0,
labelsLoading: false,
labelForm: {
name: '',
color: '',
description: '',
exclusive: false,
activeField: 'name',
},
};
// If parameters are provided, try direct connection first
if (url && repo) {
const repoParts = repo.split('/');
if (repoParts.length === 2 && repoParts[0].trim() && repoParts[1].trim()) {
const normalized = normalizeUrl(url);
const config: Config = {
url: normalized,
token: token ? token.trim() : null,
userid: userid || repoParts[0].trim(),
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';
// Optionally save to global config if --save option is provided
if (options.save) {
saveGlobalConfig({
url: normalized,
userid: config.userid,
token: config.token,
repo: repo,
autoRefreshInterval: state.autoRefreshInterval,
});
console.log(chalk.green('Settings saved successfully to global config file!'));
}
} 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: url,
userid: userid || '',
token: token || '',
saveConfig: true,
activeField: 'url',
};
}
} else {
state.error = 'Invalid repository path. Must be in owner/repo format.';
state.screen = 'setup';
state.setupForm = {
url: url,
userid: userid || '',
token: token || '',
saveConfig: true,
activeField: 'url',
};
}
}
// 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);
});