import path from 'path'; import fs from 'fs'; import * as p from '@clack/prompts'; import color from 'picocolors'; import { asyncAction } from '../utils/asyncActions'; import { Execution } from '../types/execution.types'; import { formatTime, getVerboseSchedule } from '../utils/general'; import { RunnningExecution } from '../types/types'; import { initalizeEnvironmentVariables } from '../api/auth'; import { YAML_TEMPLATE } from '../utils/constants'; export async function askAccessToken(): Promise { p.intro(color.bgCyan(color.black(' BlinqIO Executions service '))); while (true) { const token = await p.password({ message: 'Please provide your access token:', validate(value) { if (!value) return 'Token is required!'; }, }); if (p.isCancel(token)) { p.cancel('Operation cancelled.'); process.exit(0); } let validation: { valid: boolean; userName?: string } = { valid: false }; try { validation = await asyncAction(async () => { return await initalizeEnvironmentVariables(token as string); }, 10000, 'Validating token...'); } catch (err: any) { if (err.message && err.message.includes('401')) { p.note(color.redBright('Unauthorized - Invalid token, please try again!'), "Auth Error"); } else { p.note(color.redBright('Error verifying token! Please try again.'), "Token Error"); if (process.env.DEBUG === 'true') { p.note(color.gray(err.message.toString()), "Details"); } } continue; } if (!validation.valid) { p.note(color.red('Invalid token, please try again!'), "Token Error"); continue; } else { return validation.userName!; // Success: break out of while loop } } } function getExecutionLabel(e: Execution): string { // Use execution name, can include schedule details if needed if (e.schedule === undefined) return '' + e.name + ' (Draft)'; return e.name + ` - 🗓️: ` + (getVerboseSchedule(e.schedule)); } export async function askWhichExecutionToRun(executions: Execution[]) { const options = executions.map(exec => ({ value: exec._id, label: exec.name, hint: getExecutionLabel(exec) })); const executionId = await p.select({ message: 'Select an execution to trigger a run:', options, }); if (p.isCancel(executionId)) { p.cancel('Operation cancelled.'); return; } return executionId; } export async function askWhichExecutionToStop(runningExecutions: RunnningExecution[]) { const options = runningExecutions.filter((exec) => exec.running).map(exec => ({ value: exec.instanceId, label: exec.name, hint: 'Latest status: ' + exec.executionStatus.verboseStatus + ` - 🗓️: ` + formatTime(exec.executionStatus.startedAt) })); const executionId = await p.select({ message: 'Select an execution to terminate:', options, }); if (p.isCancel(executionId)) { p.cancel('Operation cancelled.'); return; } return executionId; } export async function askWhichOptionOnCreate(): Promise { const startChoice = await p.select({ message: 'How would you like to get started?', options: [ { label: 'Enter path to an execution configuration file', value: 'input-path' }, { label: 'Download a template file (executionTemplate.yaml) in your current working directory', value: 'download-template' }, { label: 'Cancel', value: 'cancel', hint: 'Press Ctrl+C or Esc to abort action' } ] }); if (p.isCancel(startChoice) || startChoice === 'cancel') { p.cancel('Operation cancelled.'); return 'cancel'; } if (startChoice === 'download-template') { const templatePath = path.resolve(process.cwd(), 'executionTemplate.yaml'); try { await fs.promises.writeFile(templatePath, YAML_TEMPLATE, { flag: 'wx' }); p.outro(`${color.green('✅ Created executionTemplate.yaml in the current folder.')} ${color.cyan('Edit this file, then run: \nnpx blinqio-executions-cli --mode=create --filePath=executionTemplate.yaml --token=')} `); } catch (err: any) { if (err.code === 'EEXIST') { p.outro(`${color.yellow('⚠ executionTemplate.yaml already exists.')} ${color.magenta('You can overwrite it manually or use another filename.')}`); } else { p.outro(color.red('Failed to create template: ' + err.message)); } } } return startChoice; } export async function askFilePath(): Promise { const filePath = await p.text({ message: 'Enter the path to the execution configuration file:', placeholder: 'path/to/execution-configuration.yaml', }); if (p.isCancel(filePath)) { p.cancel('Operation cancelled.'); return 'cancel'; } return filePath.trim(); }