feat: 去 mock 化 —— 全模块接入真实数据 (参考 jianmu/opsx-jenkins/aiops)

后端(35+ 新路由):
- AES-256-GCM 字段加密(enc:v1:),密钥自动生成 data/encryption.key
- 新模型:Host/K8sCluster/Credential/BuildNode/DeployTool/WebhookEndpoint/
  JenkinsServer/SystemSetting;Pipeline 扩展触发器/变量/缓存列,
  PipelineRun 扩展 buildNumber/externalUrl
- 资源 CRUD + 真实测试端点:主机/集群/构建节点 TCP 拨号、
  工具真实执行版本检测(保守安装策略)、Webhook HMAC-SHA256 签名发送、
  入站流水线触发 /api/hooks/pipeline/:id
- Jenkins 完整集成(移植 opsx-jenkins 生产客户端):crumb/BasicAuth/
  buildWithParameters/Location 队列/progressiveText 增量控制台,
  服务器 CRUD+测试、Job 树拉取(folder 压平)、导入为流水线、
  jenkins 类型流水线真实执行回传日志
- 流水线列表附带 lastRun、运行重试、summary 统计、系统设置单行表
- 运行结束触发出站 Webhook 通知;GitOps 同步状态真实推进

前端(14 页全部去 mock):
- 流水线列表/发布记录/批量发布/环境/凭证/构建节点/工具/Webhook/
  系统设置/Jenkins 导入/GitOps(资源树+差异) 全部接入真实 API
- 编辑器 4 Tab 持久化(基本信息/触发设置含真实 Webhook URL/变量缓存/发布历史)
- TopBar 真实流水线切换 + 仅保存/保存并运行
- Sidebar 徽标真实统计;删除未使用组件与 mock 数据文件
This commit is contained in:
Logan.Li committed 2026-10-27 03:15:20 +08:00
1 parent 04d1342b27
commit 26341c3e8a
37 files changed
+5702 -4683

No files matched your search

+36 -17
View File
@@ -1,9 +1,9 @@
import {
GitBranch,
Server,
Key,
Cpu,
Wrench,
import {
GitBranch,
Server,
Key,
Cpu,
Wrench,
Download,
ChevronLeft,
ChevronRight,
@@ -15,6 +15,8 @@ import {
Puzzle,
Settings
} from 'lucide-react';
import { useQuery } from '@tanstack/react-query';
import { apiClient } from '@/lib/api';
type ModuleType = 'pipelines' | 'gitops' | 'batch-release' | 'release-records' | 'environments' | 'credentials' | 'build-nodes' | 'tools' | 'jenkins-import' | 'webhooks' | 'plugins' | 'settings';
@@ -61,6 +63,19 @@ const menuGroups: { label: string; items: { id: ModuleType; label: string; icon:
];
export default function Sidebar({ activeModule, onModuleChange, collapsed, onToggleCollapse }: SidebarProps) {
// 徽标数来自后端真实统计
const { data: summary } = useQuery({
queryKey: ['summary'],
queryFn: apiClient.getSummary,
refetchInterval: 15000,
});
const badgeFor = (id: ModuleType): string | null => {
if (id === 'build-nodes') return summary?.buildNodes != null ? String(summary.buildNodes) : null;
if (id === 'plugins') return summary?.plugins != null ? String(summary.plugins) : null;
return null;
};
return (
<div
className="flex flex-col border-r transition-all duration-300 ease-in-out h-full"
@@ -121,17 +136,21 @@ export default function Sidebar({ activeModule, onModuleChange, collapsed, onTog
<span className="text-[13px] font-medium truncate flex-1 text-left">
{item.label}
</span>
{item.badge && (
<span
className="text-[9px] px-1 py-[1px] rounded font-medium"
style={{
background: item.badge === 'New' ? '#ddf4ff' : 'var(--panel-bg-secondary)',
color: item.badge === 'New' ? 'var(--accent-blue)' : 'var(--text-tertiary)',
}}
>
{item.badge}
</span>
)}
{(() => {
const badge = item.badge === 'New' ? 'New' : badgeFor(item.id);
if (!badge) return null;
return (
<span
className="text-[9px] px-1 py-[1px] rounded font-medium"
style={{
background: badge === 'New' ? '#ddf4ff' : 'var(--panel-bg-secondary)',
color: badge === 'New' ? 'var(--accent-blue)' : 'var(--text-tertiary)',
}}
>
{badge}
</span>
);
})()}
</>
)}
{isActive && !collapsed && (