import { useState } from 'react'; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Badge } from '@/components/ui/badge'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Progress } from '@/components/ui/progress'; import { ScrollArea } from '@/components/ui/scroll-area'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Textarea } from '@/components/ui/textarea'; import { Label } from '@/components/ui/label'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import { Play, Plus, Search, Settings, GitBranch, GitCommit, Clock, CheckCircle, XCircle, Loader2, MoreHorizontal, Edit, Trash2, Copy, Eye, Terminal, Pause, RotateCw, History, ChevronRight, ChevronDown, FileCode, Workflow, } from 'lucide-react'; import { pipelines, pipelineExecutions, releases } from '@/mocks/data'; interface PipelineStage { id: string; name: string; status: 'pending' | 'running' | 'success' | 'failed' | 'skipped'; duration: string; logs: string[]; } interface Pipeline { id: string; name: string; description: string; repository: string; branch: string; stages: PipelineStage[]; lastRun: string; lastStatus: 'success' | 'failed' | 'running' | 'never'; triggerType: 'manual' | 'auto'; createdAt: string; } const mockPipelines: Pipeline[] = [ { id: 'pipe-001', name: 'frontend-build-and-deploy', description: '前端项目构建与部署', repository: 'https://gitlab.company.com/frontend/app.git', branch: 'main', stages: [ { id: 'stage-1', name: '代码检出', status: 'success', duration: '15s', logs: ['检出代码...', '代码检出完成'] }, { id: 'stage-2', name: '依赖安装', status: 'success', duration: '45s', logs: ['安装依赖...', '依赖安装完成'] }, { id: 'stage-3', name: '代码检查', status: 'success', duration: '30s', logs: ['执行 ESLint...', '代码检查通过'] }, { id: 'stage-4', name: '构建打包', status: 'success', duration: '2m 15s', logs: ['开始构建...', '构建完成'] }, { id: 'stage-5', name: '部署到测试环境', status: 'success', duration: '30s', logs: ['部署中...', '部署完成'] }, ], lastRun: '2025-04-14 10:30:00', lastStatus: 'success', triggerType: 'auto', createdAt: '2025-01-15', }, { id: 'pipe-002', name: 'backend-api-deploy', description: '后端API服务部署', repository: 'https://gitlab.company.com/backend/api.git', branch: 'develop', stages: [ { id: 'stage-1', name: '代码检出', status: 'success', duration: '12s', logs: [] }, { id: 'stage-2', name: '单元测试', status: 'success', duration: '1m 30s', logs: [] }, { id: 'stage-3', name: '构建镜像', status: 'running', duration: '45s', logs: ['构建Docker镜像...'] }, { id: 'stage-4', name: '推送镜像', status: 'pending', duration: '-', logs: [] }, { id: 'stage-5', name: '部署到K8s', status: 'pending', duration: '-', logs: [] }, ], lastRun: '2025-04-14 11:15:00', lastStatus: 'running', triggerType: 'manual', createdAt: '2025-02-01', }, { id: 'pipe-003', name: 'database-migration', description: '数据库迁移脚本执行', repository: 'https://gitlab.company.com/database/migrations.git', branch: 'main', stages: [ { id: 'stage-1', name: '代码检出', status: 'success', duration: '10s', logs: [] }, { id: 'stage-2', name: '数据库备份', status: 'success', duration: '2m 00s', logs: [] }, { id: 'stage-3', name: '执行迁移', status: 'failed', duration: '15s', logs: ['迁移失败: 表已存在'] }, ], lastRun: '2025-04-14 09:00:00', lastStatus: 'failed', triggerType: 'manual', createdAt: '2025-01-20', }, ]; const pipelineTemplates = [ { id: 'template-1', name: 'Node.js 项目', description: '适用于 Node.js 前端项目', stages: ['代码检出', '依赖安装', '代码检查', '构建打包', '部署'] }, { id: 'template-2', name: 'Go 项目', description: '适用于 Go 后端项目', stages: ['代码检出', '单元测试', '构建', '构建镜像', '部署'] }, { id: 'template-3', name: 'Java 项目', description: '适用于 Java Spring Boot 项目', stages: ['代码检出', 'Maven构建', '单元测试', '打包', '部署'] }, { id: 'template-4', name: 'Python 项目', description: '适用于 Python 项目', stages: ['代码检出', '依赖安装', '代码检查', '测试', '部署'] }, ]; export function PipelineManager() { const [searchQuery, setSearchQuery] = useState(''); const [selectedPipeline, setSelectedPipeline] = useState(null); const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false); const [isDetailDialogOpen, setIsDetailDialogOpen] = useState(false); const [isRunDialogOpen, setIsRunDialogOpen] = useState(false); const [activeStage, setActiveStage] = useState(null); const [newPipeline, setNewPipeline] = useState({ name: '', description: '', repository: '', branch: 'main', template: '', }); const filteredPipelines = mockPipelines.filter( (p) => p.name.toLowerCase().includes(searchQuery.toLowerCase()) || p.description.toLowerCase().includes(searchQuery.toLowerCase()) ); const getStatusBadge = (status: Pipeline['lastStatus']) => { switch (status) { case 'success': return ( 成功 ); case 'failed': return ( 失败 ); case 'running': return ( 运行中 ); default: return ( 从未运行 ); } }; const getStageStatusIcon = (status: PipelineStage['status']) => { switch (status) { case 'success': return ; case 'failed': return ; case 'running': return ; case 'skipped': return 跳过; default: return 待执行; } }; const handleCreatePipeline = () => { // Mock create setIsCreateDialogOpen(false); setNewPipeline({ name: '', description: '', repository: '', branch: 'main', template: '' }); }; const handleRunPipeline = () => { setIsRunDialogOpen(false); }; return (
{/* Header */}

流水线管理

CI/CD 流水线配置与管理

{/* Stats */}

流水线总数

{mockPipelines.length}

运行中

{mockPipelines.filter((p) => p.lastStatus === 'running').length}

今日成功

12

今日失败

2

{/* Filters */}
setSearchQuery(e.target.value)} className="pl-10 bg-slate-800 border-slate-700 text-slate-100" />
{/* Pipeline List */}
{filteredPipelines.map((pipeline) => (

{pipeline.name}

{getStatusBadge(pipeline.lastStatus)} {pipeline.triggerType === 'auto' ? '自动触发' : '手动触发'}

{pipeline.description}

{pipeline.branch} 上次运行: {pipeline.lastRun}
{/* Pipeline Stages */}
{pipeline.stages.map((stage, index) => (
{getStageStatusIcon(stage.status)} {stage.name}
{index < pipeline.stages.length - 1 && ( )}
))}
))}
{/* Create Pipeline Dialog */} 新建流水线 配置新的 CI/CD 流水线
setNewPipeline({ ...newPipeline, name: e.target.value })} placeholder="例如: frontend-build" className="bg-slate-800 border-slate-700 text-slate-100 mt-1" />