@re-shell/cli
Version:
Full-stack development platform uniting microservices and microfrontends. Build complete applications with .NET (ASP.NET Core Web API, Minimal API), Java (Spring Boot, Quarkus, Micronaut, Vert.x), Rust (Actix-Web, Warp, Rocket, Axum), Python (FastAPI, Dja
205 lines (204 loc) • 7.06 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ProgressBar = exports.MultiStepProgress = exports.ProgressTracker = void 0;
exports.createProgressTracker = createProgressTracker;
exports.createMultiStepProgress = createMultiStepProgress;
exports.createProgressBar = createProgressBar;
const chalk_1 = __importDefault(require("chalk"));
const spinner_1 = require("./spinner");
// Enhanced progress tracker with substeps
class ProgressTracker {
constructor(title, totalSteps) {
this.currentStep = 0;
this.stepName = '';
this.totalSteps = totalSteps;
this.spinner = new spinner_1.ProgressSpinner({ text: this.formatText(title) });
}
start() {
this.spinner.start();
return this;
}
nextStep(stepName) {
this.currentStep++;
this.stepName = stepName;
this.spinner.setText(this.formatText(stepName));
return this;
}
updateStep(message) {
this.spinner.setText(this.formatText(message));
return this;
}
succeed(message) {
this.spinner.succeed(message || `✅ All ${this.totalSteps} steps completed successfully!`);
return this;
}
fail(message) {
this.spinner.fail(message || `❌ Failed at step ${this.currentStep}/${this.totalSteps}: ${this.stepName}`);
return this;
}
stop() {
this.spinner.stop();
return this;
}
formatText(text) {
if (this.totalSteps > 1) {
const progress = this.currentStep > 0 ? ` (${this.currentStep}/${this.totalSteps})` : '';
return `${text}${progress}`;
}
return text;
}
}
exports.ProgressTracker = ProgressTracker;
// Enhanced multi-step operations with better UX
class MultiStepProgress {
constructor(title, steps) {
this.steps = [];
this.steps = steps.map(name => ({ name, status: 'pending' }));
this.isInteractive = Boolean(process.stdout.isTTY &&
process.env.TERM !== 'dumb' &&
!process.env.CI &&
!process.env.RE_SHELL_NO_SPINNER);
this.spinner = new spinner_1.ProgressSpinner({ text: title });
}
start() {
if (this.isInteractive) {
this.spinner.start();
this.updateDisplay();
}
else {
console.log(chalk_1.default.cyan('⏳ Starting multi-step process...'));
this.steps.forEach((step, index) => {
console.log(chalk_1.default.gray(` ${index + 1}. ${step.name}`));
});
}
return this;
}
startStep(stepIndex) {
if (stepIndex >= 0 && stepIndex < this.steps.length) {
this.steps[stepIndex].status = 'running';
this.updateDisplay();
}
return this;
}
completeStep(stepIndex) {
if (stepIndex >= 0 && stepIndex < this.steps.length) {
this.steps[stepIndex].status = 'completed';
this.updateDisplay();
}
return this;
}
failStep(stepIndex) {
if (stepIndex >= 0 && stepIndex < this.steps.length) {
this.steps[stepIndex].status = 'failed';
this.updateDisplay();
}
return this;
}
succeed(message) {
if (this.isInteractive) {
this.spinner.succeed(message || 'All steps completed successfully!');
}
else {
console.log(chalk_1.default.green('✅'), message || 'All steps completed successfully!');
}
return this;
}
fail(message) {
if (this.isInteractive) {
this.spinner.fail(message || 'Process failed');
}
else {
console.log(chalk_1.default.red('❌'), message || 'Process failed');
}
return this;
}
stop() {
this.spinner.stop();
return this;
}
updateDisplay() {
if (!this.isInteractive) {
// For non-interactive, just log the current step
const runningStep = this.steps.find(s => s.status === 'running');
const completedCount = this.steps.filter(s => s.status === 'completed').length;
if (runningStep) {
console.log(chalk_1.default.cyan(`⏳ [${completedCount}/${this.steps.length}] ${runningStep.name}`));
}
return;
}
const completedCount = this.steps.filter(s => s.status === 'completed').length;
const runningStep = this.steps.find(s => s.status === 'running');
const failedStep = this.steps.find(s => s.status === 'failed');
let text = '';
if (failedStep) {
text = `❌ Failed: ${failedStep.name}`;
}
else if (runningStep) {
text = `[${completedCount}/${this.steps.length}] ${runningStep.name}`;
}
else if (completedCount === this.steps.length) {
text = `✅ All ${this.steps.length} steps completed`;
}
else {
text = `Preparing... (${completedCount}/${this.steps.length})`;
}
this.spinner.setText(text);
}
}
exports.MultiStepProgress = MultiStepProgress;
// Simple progress bar for file operations
class ProgressBar {
constructor(title, total) {
this.current = 0;
this.total = total;
this.title = title;
this.spinner = new spinner_1.ProgressSpinner({ text: this.formatText() });
}
start() {
this.spinner.start();
return this;
}
increment(amount = 1) {
this.current = Math.min(this.current + amount, this.total);
this.spinner.setText(this.formatText());
return this;
}
setProgress(current) {
this.current = Math.min(Math.max(current, 0), this.total);
this.spinner.setText(this.formatText());
return this;
}
succeed(message) {
this.spinner.succeed(message || `${this.title} completed`);
return this;
}
fail(message) {
this.spinner.fail(message || `${this.title} failed`);
return this;
}
formatText() {
const percentage = Math.round((this.current / this.total) * 100);
const progressBar = this.createProgressBar(percentage);
return `${this.title} ${progressBar} ${this.current}/${this.total} (${percentage}%)`;
}
createProgressBar(percentage) {
const width = 20;
const filled = Math.round((percentage / 100) * width);
const empty = width - filled;
return `[${'█'.repeat(filled)}${'░'.repeat(empty)}]`;
}
}
exports.ProgressBar = ProgressBar;
// Factory functions for common progress patterns
function createProgressTracker(title, steps) {
return new ProgressTracker(title, steps);
}
function createMultiStepProgress(title, steps) {
return new MultiStepProgress(title, steps);
}
function createProgressBar(title, total) {
return new ProgressBar(title, total);
}