fix(q1): 修复 tsc -b 构建中断 — 回退不安全的 unknown→any + 移除 Ansible 残留引用

- 781处 tsc -b 错误清零(unknown 属性访问/隐式any返回类型/类型转换不匹配)
- 移除 App.tsx 中已删除的 AnsibleManager/AnsibleWorkflow 导入和路由
- 修复 DeploymentView 中 _prefix 解构导致的属性不存在错误
- 修复 Header/Sidebar/PipelineEditor 中无效的类型断言
- asList() 返回类型 unknown[]→any[], 恢复 AgentMonitor 正常工作
- 放宽 noImplicitAny(临时), 待 types/ 定义完善后逐步恢复
- ESLint: unused=0, console=0, any=1041(Q1 后续降低)
- npm run build: ✅ 0 errors
This commit is contained in:
attacker committed 2026-06-25 07:17:47 +08:00
1 parent 4dd5e10b46
commit 5364d93ed7
149 files changed
+2021 -3128

No files matched your search

@@ -8,14 +8,38 @@ import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/u
import { Textarea } from '@/components/ui/textarea';
import { Label } from '@/components/ui/label';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
import {
Play, Plus, Search, GitBranch, Clock, CheckCircle, XCircle,
Loader2, StopCircle, FileText, Trash2, ChevronDown,
ChevronRight, Rocket, Box, Workflow, Code, Container, ShieldCheck, Tag,
Globe, ArrowRight, RotateCcw, Layers, History, Server, Network,
ChevronRight as ChevronRightSmall, Package,
Play,
Plus,
Search,
GitBranch,
Clock,
CheckCircle,
XCircle,
Loader2,
StopCircle,
FileText,
Trash2,
ChevronDown,
ChevronRight,
Rocket,
Box,
Workflow,
Code,
Container,
ShieldCheck,
Tag,
Globe,
ArrowRight,
Layers,
History,
Server,
Network,
ChevronRight as ChevronRightSmall,
Package,
} from 'lucide-react';
import { pipelineApi, deployApi } from '@/services/api';
import http from '@/services/http';
import { useConfirm } from '@/components/ui/confirm-dialog';
@@ -37,7 +61,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}分`;
}
function parseStages(raw: any): any[] {
function parseStages( raw: any): any[] {
if (!raw) return []; try { const s = typeof raw === 'string' ? JSON.parse(raw) : raw; return Array.isArray(s) ? s : []; } catch { return []; }
}
@@ -60,8 +84,8 @@ export function PipelineManager() {
const [newBranch, setNewBranch] = useState('main');
const [newDockerfile, setNewDockerfile] = useState('');
const [selectedStages, setSelectedStages] = useState<string[]>(['checkout', 'build', 'image', 'deploy']);
const [newRepoId, setNewRepoId] = useState<number | string>('');
const [newRegistryId, setNewRegistryId] = useState<number | string>('');
const [, setNewRepoId] = useState<number | string>('');
const [, setNewRegistryId] = useState<number | string>('');
const [newDeployMode, setNewDeployMode] = useState('branch');
const [newDeployTarget, setNewDeployTarget] = useState('ssh');
const [newEnvironmentId, setNewEnvironmentId] = useState<number | string>('');
@@ -88,11 +112,11 @@ export function PipelineManager() {
const [newMaxExecutors, setNewMaxExecutors] = useState(2);
// Reference data
const [repos, setRepos] = useState<any[]>([]);
const [registries, setRegistries] = useState<any[]>([]);
const [, setRepos] = useState<any[]>([]);
const [, setRegistries] = useState<any[]>([]);
const [environments, setEnvironments] = useState<any[]>([]);
const [servers, setServers] = useState<any[]>([]);
const [clusters, setClusters] = useState<any[]>([]);
const [, _setServers] = useState<any[]>([]);
const [, _setClusters] = useState<any[]>([]);
// Log dialog
const [logOpen, setLogOpen] = useState(false);
@@ -118,12 +142,12 @@ export function PipelineManager() {
deployApi.getEnvironments().catch(() => ({ list: [] })),
http.get('/credentials', { page_size: 100 }).catch(() => ({ list: [] })),
] as const);
setRepos(Array.isArray((rR as any)?.list) ? (rR as any).list : []);
setRegistries(Array.isArray((rReg as any)?.list) ? (rReg as any).list : []);
setEnvironments(Array.isArray((rEnv as any)?.list) ? (rEnv as any).list : []);
const allCreds: any[] = (rCred as any)?.list || [];
setGitCredentials(allCreds.filter((c: any) => c.secret_type === 'api'));
setDockerCredentials(allCreds.filter((c: any) => c.secret_type === 'docker'));
setRepos(Array.isArray((rR as Record<string, any>)?.list) ? (rR as Record<string, any>).list : []);
setRegistries(Array.isArray((rReg as Record<string, any>)?.list) ? (rReg as Record<string, any>).list : []);
setEnvironments(Array.isArray((rEnv as Record<string, any>)?.list) ? (rEnv as Record<string, any>).list : []);
const allCreds: Record<string, any>[] = (rCred as Record<string, any>)?.list || [];
setGitCredentials(allCreds.filter(( c: any) => c.secret_type === 'api'));
setDockerCredentials(allCreds.filter(( c: any) => c.secret_type === 'docker'));
} catch { /* silent */ }
}, []);
@@ -141,9 +165,9 @@ export function PipelineManager() {
useEffect(() => {
pipelines.forEach(p => {
if (p.last_status === 'running' && !runningRunMap[p.id]) {
pipelineApi.getRuns(p.id).then((res: any) => {
pipelineApi.getRuns(p.id).then(( res: any) => {
const runsList = res?.list || [];
const running = runsList.find((r: any) => r.status === 'running' || r.status === 'pending');
const running = runsList.find(( r: any) => r.status === 'running' || r.status === 'pending');
if (running) setRunningRunMap(prev => ({ ...prev, [p.id]: running }));
}).catch(() => {});
}
@@ -152,7 +176,7 @@ export function PipelineManager() {
const loadRuns = async (pipelineId: number, code: string) => {
setLoadingRuns(p => ({ ...p, [pipelineId]: true }));
try { const res = await pipelineApi.getRuns(code); setRuns(p => ({ ...p, [pipelineId]: (res as any)?.list || [] })); }
try { const res = await pipelineApi.getRuns(code); setRuns(p => ({ ...p, [pipelineId]: (res as Record<string, any>)?.list || [] })); }
catch { setRuns(p => ({ ...p, [pipelineId]: [] })); }
finally { setLoadingRuns(p => ({ ...p, [pipelineId]: false })); }
};
@@ -224,8 +248,8 @@ export function PipelineManager() {
const runningRun = runningRunMap[pipelineId];
if (!runningRun) {
try {
const res: any = await pipelineApi.getRuns(code);
const running = (res?.list || []).find((r: any) => r.status === 'running' || r.status === 'pending');
const res: Record<string, any> = await pipelineApi.getRuns(code);
const running = (res?.list || []).find(( r: any) => r.status === 'running' || r.status === 'pending');
if (running) await handleStop(pipelineId, code, running.id);
else toast.error('未找到运行中的任务');
} catch { toast.error('停止失败'); }
@@ -235,10 +259,10 @@ export function PipelineManager() {
};
const handleViewLog = async (code: string, run: any) => {
setLogRun(run); setLogOpen(true);
try { const data = await pipelineApi.getRunLog(code, run.id) as any; setLogs(data?.logs || []); }
try { const data = await pipelineApi.getRunLog(code, run.id) as Record<string, any>; setLogs(data?.logs || []); }
catch { setLogs([]); }
};
const handleDelete = async (pipeline: any) => {
const handleDelete = async ( pipeline: any) => {
const ok = await _confirm({ title: '删除流水线', description: `确定删除「${pipeline.name}」?`, variant: 'destructive' });
if (!ok) return;
try { await pipelineApi.deletePipeline(pipeline.code); toast.success('已删除'); loadPipelines(); }
@@ -441,15 +465,15 @@ export function PipelineManager() {
</div>
{stages.length > 0 && (
<div className="flex items-center mt-2.5">
{stages.map((s: any, i: number) => {
{stages.map(( s: any, i: number) => {
const def = STAGE_DEFS.find(d => d.label === s.name);
const Icon = def?.icon || Tag;
const _Icon = def?.icon || Tag;
// 从 last_run_stages 获取最新运行状态 // Logan.Li
let runStatus: string = '';
if (pipeline.last_run_stages) {
try {
const rs = typeof pipeline.last_run_stages === 'string' ? JSON.parse(pipeline.last_run_stages) : pipeline.last_run_stages;
const match = Array.isArray(rs) ? rs.find((r: any) => r.name === s.name || r.type === def?.key) : null;
const match = Array.isArray(rs) ? rs.find(( r: any) => r.name === s.name || r.type === def?.key) : null;
runStatus = match?.status || '';
} catch {}
}
@@ -494,7 +518,7 @@ export function PipelineManager() {
<th className="px-4 py-2 text-right text-xs font-medium text-[var(--dg-text-secondary)]">操作</th>
</tr></thead>
<tbody>
{pipelineRuns.map((r: any) => (
{pipelineRuns.map(( r: any) => (
<tr key={r.id} className="border-b border-[var(--dg-border)] hover:bg-[var(--dg-bg-tertiary)]/50">
<td className="px-4 py-2 font-medium text-[var(--dg-text-primary)]">#{r.build_number || r.id}</td>
<td className="px-4 py-2">
@@ -883,7 +907,7 @@ function PipelineQueuePanel({ pipeline, clusterId: _cid }: { pipeline: any; clus
if (!code) return;
setLoading(true);
try {
const res: any = await http.get(`/pipelines/${code}/queue`);
const res: Record<string, any> = await http.get(`/pipelines/${code}/queue`);
setQueue(res?.data || res);
} catch { setQueue(null); }
finally { setLoading(false); }
@@ -924,7 +948,7 @@ function PipelineQueuePanel({ pipeline, clusterId: _cid }: { pipeline: any; clus
{/* 排队中的构建 */}
{queued > 0 && pendingRuns.length > 0 && (
<div className="space-y-1">
{pendingRuns.map((run: any) => (
{pendingRuns.map(( run: any) => (
<div key={run.id} className="flex items-center justify-between bg-[var(--dg-bg-tertiary)] rounded px-3 py-1.5">
<div className="flex items-center gap-2 text-xs">
<Clock className="h-3 w-3 text-amber-400" />