UNPKG

linear-cmd

Version:

A GitHub CLI-like tool for Linear - manage issues, accounts, and more

106 lines (105 loc) 5 kB
import { Command } from 'commander'; import { colors } from '../../lib/colors.js'; import { ConfigManager } from '../../lib/config-manager.js'; import { getLinearClientForAccount, handleValidationError, ValidationError } from '../../lib/linear-client.js'; import { logger } from '../../lib/logger.js'; import {} from '../../schemas/definitions/project.js'; import { CommandNames, SubCommandNames } from '../../schemas/definitions.js'; import { createSubCommandFromSchema } from '../../schemas/utils.js'; export function createListProjectsCommand() { return createSubCommandFromSchema(CommandNames.PROJECT, SubCommandNames.PROJECT_LIST, async (options) => { const configManager = new ConfigManager(); try { const { client, account } = await getLinearClientForAccount(configManager, options.account); // Build filter const filter = {}; // Handle team filter if (options.team) { const teams = await client.teams({ filter: { key: { eq: options.team.toUpperCase() } } }); if (teams.nodes.length > 0) { filter.accessibleTeams = { some: { id: { eq: teams.nodes[0].id } } }; } else { logger.error(`Team '${options.team}' not found`); logger.dim('\nAvailable teams:'); const allTeams = await client.teams(); allTeams.nodes.forEach((t) => logger.dim(` - ${t.key}: ${t.name}`)); process.exit(1); } } logger.loading(`Fetching projects from account: ${account.name}...`); const limit = options.limit ? parseInt(options.limit) : 50; const projectsConnection = await client.projects({ filter: Object.keys(filter).length > 0 ? filter : undefined, first: limit }); const projects = projectsConnection.nodes; if (projects.length === 0) { logger.info('No projects found'); return; } if (options.format === 'json') { const projectsData = await Promise.all(projects.map(async (project) => ({ id: project.id, name: project.name, description: project.description, state: project.state, url: project.url, progress: project.progress, startDate: project.startDate, targetDate: project.targetDate, lead: (await project.lead)?.name, teams: await project.teams().then((teams) => teams.nodes.map((t) => ({ key: t.key, name: t.name }))) }))); logger.json(projectsData); } else { // Pretty format console.log(); logger.success(`Found ${projects.length} project${projects.length === 1 ? '' : 's'}:\n`); // Fetch all leads and teams in parallel for better performance const projectsData = await Promise.all(projects.map(async (project) => ({ project, lead: await project.lead, teams: await project.teams() }))); for (const { project, lead, teams } of projectsData) { console.log(colors.boldCyan(`📁 ${project.name}`)); console.log(colors.dim(` ${project.url}`)); if (project.description) { console.log(` ${colors.gray(project.description)}`); } const details = []; if (project.state) { details.push(`State: ${project.state}`); } if (project.progress !== undefined) { details.push(`Progress: ${Math.round(project.progress * 100)}%`); } if (lead) { details.push(`Lead: ${lead.name}`); } if (teams.nodes.length > 0) { details.push(`Teams: ${teams.nodes.map((t) => t.key).join(', ')}`); } if (details.length > 0) { console.log(` ${colors.dim(details.join(' • '))}`); } console.log(); } if (projects.length >= limit) { logger.dim(`(Showing first ${limit} projects. Use --limit to show more)`); } } } catch (error) { if (error instanceof ValidationError) { handleValidationError(error); } else { logger.error('Error listing projects', error); } process.exit(1); } }); }