import { useState, useEffect, useCallback } from 'react'; import { useParams } from 'react-router-dom'; import { Plus, Trash2, ChevronUp, ChevronDown, ChevronRight, Save, Play, Loader2, GitBranch, Wrench, Server, FlaskConical, Zap, Terminal, FileCode, Container, Clock, Webhook, Hand, Check, X, StopCircle, ScrollText, Users, UserPlus, Shield, FileText, } from 'lucide-react'; import { Card, CardContent } 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 } from '@/components/ui/tabs'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Textarea } from '@/components/ui/textarea'; import { Switch } from '@/components/ui/switch'; import { Label } from '@/components/ui/label'; import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { toast } from 'sonner'; import { pipelineApi, deployApi } from '@/api'; import { useConfirm } from '@/components/ui/confirm-dialog'; import { PageShell } from '@/components/layout/PageShell'; import { PageEmpty } from '@/components/layout/PageEmpty'; import type { JsonData } from '@/types/common'; // ---- types ---- interface Task { id: string; name: string; type: string; icon: string; config: Record; script: string; script_type: string; } interface Stage { id: string; name: string; type: string; tasks: Task[]; } interface LogEntry { time: string; level: string; message: string; stage: string; } const stageTypeLabels: Record = { source: '拉取代码', build: '构建', deploy: '部署', test: '测试', custom: '自定义' }; const taskIcons: JsonData = { GitBranch, Wrench, Server, FlaskConical, Zap, Terminal, FileCode, Container }; function uid() { return `tsk-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`; } function fmtDuration(s: number | undefined): string { if (!s) return '-'; if (s < 60) return `${s}s`; const m = Math.floor(s / 60); const sec = s % 60; return sec > 0 ? `${m}分${sec}秒` : `${m}分`; } // ---- Task Card ---- function TaskCard({ task, selected, onSelect, onDelete }: { task: Task; selected: boolean; onSelect: () => void; onDelete: () => void }) { const Icon = taskIcons[task.icon] || Wrench; return (
{task.name}
{task.type}
); } // ---- Task Editor Panel ---- function TaskEditor({ task, onUpdate }: { task: Task | null; onUpdate: (t: Task) => void; onClose: () => void }) { if (!task) return
选择一个任务开始编辑
; return (
onUpdate({ ...task, name: e.target.value })} className="h-8 text-sm" />
{['shell', 'python'].map(t => ( onUpdate({ ...task, script_type: t })}>{t}))}