Files
aiops/frontend/src/components/deploy/pipeline-helpers.tsx
T
attacker c68aef4444 feat(alert): A2 告警引擎分布式安全 — Redis 分布式锁(SetNX)
- Cache 接口新增 SetNX 方法(go-redis 原子 / redka check-then-set 单副本安全)
- AlertEngine 改造为支持分布式锁: tryAcquireLock/releaseLock/GetEngineStatus
- 多副本部署时仅 Leader 执行告警检查, 60s TTL 防死锁, fail-open 容错
- 新增 GET /alerts/engine/status 监控端点(is_leader/instance_id/lock_holder)
- 修复 GrafanaDashboard.tsx Panel.options 类型不匹配导致构建中断
- 同步未提交的前端类型安全迁移(140+ 文件)
- ROADMAP/TDD_PLAN/PROJECT_EVALUATION 三文档同步更新

验证: go build 零错误, Docker 部署 healthy, 引擎状态端点正常,
锁竞争测试通过(非 Leader 跳过检查), 5/5 核心 API 回归通过
2026-06-26 21:13:15 +08:00

93 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Badge } from '@/components/ui/badge';
import { CheckCircle, XCircle, Loader2 } from 'lucide-react';
import type { JsonData } from '@/types/common';
// 流水线阶段定义 // Logan.Li
export interface PipelineStage {
id: string;
name: string;
status: 'pending' | 'running' | 'success' | 'failed' | 'skipped';
duration: string;
logs: string[];
}
// 流水线模板(新建时快捷选择) // Logan.Li
export 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: ['代码检出', '依赖安装', '代码检查', '测试', '部署'] },
];
// 解析 stages 字段(兼容 JSON 数组 / 逗号分隔字符串) // Logan.Li
export function parseStages( stages: string): PipelineStage[] {
if (Array.isArray(stages)) return stages;
if (typeof stages === 'string') {
try {
const parsed = JSON.parse(stages);
if (Array.isArray(parsed)) return parsed;
} catch {
return stages.split(',').map((s, i) => ({ id: `stage-${i + 1}`, name: s.trim(), status: 'success' as const, duration: '-', logs: [] }));
}
}
return [];
}
// 由流水线名称生成 code(kebab-case) // Logan.Li
export function nameToCode(name: string): string {
return name
.toLowerCase()
.replace(/[^a-z0-9]/g, '-')
.replace(/-+/g, '-')
.replace(/^-|-$/g, '') || `pipeline-${Date.now()}`;
}
// 状态徽章(使用后端 last_status 字段) // Logan.Li
export function getStatusBadge( status: string) {
switch (status) {
case 'success':
return (
<Badge variant="outline" className="border-emerald-500/30 text-emerald-400 bg-emerald-500/10">
<CheckCircle className="h-3 w-3 mr-1" />
成功
</Badge>
);
case 'failed':
return (
<Badge variant="outline" className="border-red-500/30 text-red-400 bg-red-500/10">
<XCircle className="h-3 w-3 mr-1" />
失败
</Badge>
);
case 'running':
return (
<Badge variant="outline" className="border-blue-500/30 text-blue-400 bg-blue-500/10 animate-pulse">
<Loader2 className="h-3 w-3 mr-1 animate-spin" />
运行中
</Badge>
);
default:
return (
<Badge variant="outline" className="border-[var(--dg-border)] text-[var(--dg-text-secondary)]">
从未运行
</Badge>
);
}
}
// 阶段状态图标 // Logan.Li
export function getStageStatusIcon(status: PipelineStage['status']) {
switch (status) {
case 'success':
return <CheckCircle className="h-4 w-4 text-emerald-400" />;
case 'failed':
return <XCircle className="h-4 w-4 text-red-400" />;
case 'running':
return <Loader2 className="h-4 w-4 text-blue-400 animate-spin" />;
case 'skipped':
return <span className="text-[var(--dg-text-secondary)] text-xs">跳过</span>;
default:
return <span className="text-[var(--dg-text-secondary)] opacity-60 text-xs">待执行</span>;
}
}