mcpengine/studio/apps/web/components/deploy/DeployStepIndicator.tsx
Jake Shore 96e52666c5 MCPEngine full sync — studio scaffold, factory v2, server updates, state.json — 2026-02-12
=== NEW ===
- studio/ — MCPEngine Studio scaffold (Next.js monorepo, build plan)
- docs/FACTORY-V2.md — Factory v2 architecture doc
- docs/CALENDLY_MCP_BUILD_SUMMARY.md — Calendly MCP build report

=== UPDATED SERVERS ===
- fieldedge: Added jobs-tools, UI build script, main entry update
- lightspeed: Updated main + server entry points
- squarespace: Added collection-browser + page-manager apps
- toast: Added main + server entry points

=== INFRA ===
- infra/command-center/state.json — Updated pipeline state
- infra/command-center/FACTORY-V2.md — Factory v2 operator playbook
2026-02-12 17:58:33 -05:00

97 lines
3.1 KiB
TypeScript

'use client';
import React from 'react';
import { Check, X, Loader2 } from 'lucide-react';
import { cn } from '@/lib/utils';
// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------
export type StepState = 'waiting' | 'active' | 'complete' | 'failed';
export interface DeployStepIndicatorProps {
label: string;
state: StepState;
index: number;
isLast?: boolean;
}
// ---------------------------------------------------------------------------
// Component
// ---------------------------------------------------------------------------
export function DeployStepIndicator({
label,
state,
index,
isLast = false,
}: DeployStepIndicatorProps) {
return (
<div className="flex items-center">
{/* Step circle */}
<div className="flex flex-col items-center">
<div
className={cn(
'relative flex h-10 w-10 items-center justify-center rounded-full border-2 text-sm font-semibold transition-all duration-500',
// Waiting
state === 'waiting' &&
'border-gray-600 bg-gray-800 text-gray-500',
// Active
state === 'active' &&
'border-indigo-500 bg-indigo-500/20 text-indigo-400 shadow-lg shadow-indigo-500/25',
// Complete
state === 'complete' &&
'border-emerald-500 bg-emerald-500/20 text-emerald-400 shadow-lg shadow-emerald-500/25',
// Failed
state === 'failed' &&
'border-red-500 bg-red-500/20 text-red-400 shadow-lg shadow-red-500/25',
)}
>
{/* Pulse ring for active */}
{state === 'active' && (
<span className="absolute inset-0 animate-ping rounded-full border-2 border-indigo-400 opacity-30" />
)}
{/* Icon */}
{state === 'complete' && <Check className="h-5 w-5" />}
{state === 'failed' && <X className="h-5 w-5" />}
{state === 'active' && (
<Loader2 className="h-5 w-5 animate-spin" />
)}
{state === 'waiting' && <span>{index + 1}</span>}
</div>
{/* Label */}
<span
className={cn(
'mt-2 text-xs font-medium transition-colors duration-300',
state === 'waiting' && 'text-gray-500',
state === 'active' && 'text-indigo-400',
state === 'complete' && 'text-emerald-400',
state === 'failed' && 'text-red-400',
)}
>
{label}
</span>
</div>
{/* Connector line */}
{!isLast && (
<div className="mx-2 mb-6 h-0.5 w-12 sm:w-16 lg:w-20">
<div
className={cn(
'h-full rounded-full transition-all duration-700',
state === 'complete'
? 'bg-gradient-to-r from-emerald-500 to-emerald-500/50'
: state === 'active'
? 'bg-gradient-to-r from-indigo-500 to-gray-700 animate-pulse'
: 'bg-gray-700',
)}
/>
</div>
)}
</div>
);
}