Remove pre-1.0 audit and protected request scaffolding
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
import { Activity, ListChecks, RotateCcw, ServerCog, Sparkles, WandSparkles } from "lucide-react";
|
||||
import { ListChecks, RotateCcw, ServerCog, Sparkles, WandSparkles } from "lucide-react";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
|
||||
import { platformApiClient } from "../api/client";
|
||||
import type { AuditEventResponse, JobResponse, RunEndpointResponse, ServerInstanceResponse } from "../api/types";
|
||||
import type { JobResponse, RunEndpointResponse, ServerInstanceResponse } from "../api/types";
|
||||
import { EmptyState, ErrorState, LoadingState, ResultBadge } from "../components/StateViews";
|
||||
import { ProductionGovernancePanel } from "../components/ProductionGovernancePanel";
|
||||
import { ProductionOperationsPanel } from "../components/ProductionOperationsPanel";
|
||||
import { jobCapabilityLabel } from "../contracts/jobPresentation";
|
||||
import type { PageComponentProps } from "../contracts/page";
|
||||
import { cx } from "../utils/classes";
|
||||
@@ -13,7 +13,6 @@ type ModuleState<T> = { status: "loading" } | { status: "error"; reason: string
|
||||
|
||||
export function MaintenancePage({ session, operations, onNavigate }: PageComponentProps) {
|
||||
const [endpoints, setEndpoints] = useState<ModuleState<RunEndpointResponse[]>>({ status: "loading" });
|
||||
const [events, setEvents] = useState<ModuleState<AuditEventResponse[]>>({ status: "loading" });
|
||||
const [jobs, setJobs] = useState<ModuleState<JobResponse[]>>({ status: "loading" });
|
||||
const [servers, setServers] = useState<ModuleState<ServerInstanceResponse[]>>({ status: "loading" });
|
||||
const [triageResult, setTriageResult] = useState<{ status: "pending" | "succeeded" | "failed"; label: string } | null>(null);
|
||||
@@ -28,16 +27,6 @@ export function MaintenancePage({ session, operations, onNavigate }: PageCompone
|
||||
}
|
||||
}, []);
|
||||
|
||||
const refreshEvents = useCallback(async () => {
|
||||
setEvents({ status: "loading" });
|
||||
try {
|
||||
const response = await platformApiClient.listAuditEvents();
|
||||
setEvents({ status: "ready", data: response.items });
|
||||
} catch (error) {
|
||||
setEvents({ status: "error", reason: error instanceof Error ? error.message : "加载失败" });
|
||||
}
|
||||
}, []);
|
||||
|
||||
const refreshJobs = useCallback(async () => {
|
||||
setJobs({ status: "loading" });
|
||||
try {
|
||||
@@ -60,23 +49,20 @@ export function MaintenancePage({ session, operations, onNavigate }: PageCompone
|
||||
|
||||
const refreshAll = useCallback(() => {
|
||||
void refreshEndpoints();
|
||||
void refreshEvents();
|
||||
void refreshJobs();
|
||||
void refreshServers();
|
||||
}, [refreshEndpoints, refreshEvents, refreshJobs, refreshServers]);
|
||||
}, [refreshEndpoints, refreshJobs, refreshServers]);
|
||||
|
||||
useEffect(() => {
|
||||
refreshAll();
|
||||
}, [refreshAll]);
|
||||
|
||||
const endpointItems = endpoints.status === "ready" ? endpoints.data : [];
|
||||
const eventItems = events.status === "ready" ? events.data : [];
|
||||
const jobItems = jobs.status === "ready" ? jobs.data : [];
|
||||
const serverItems = servers.status === "ready" ? servers.data : [];
|
||||
const failedJobs = useMemo(() => jobItems.filter((job) => job.state === "failed").slice(0, 8), [jobItems]);
|
||||
const serverById = useMemo(() => new Map(serverItems.map((server) => [server.id, server])), [serverItems]);
|
||||
const endpointById = useMemo(() => new Map(endpointItems.map((endpoint) => [endpoint.id, endpoint])), [endpointItems]);
|
||||
const failedAuditCount = eventItems.filter((event) => event.result !== "success").length;
|
||||
const unhealthyEndpointCount = endpointItems.filter((endpoint) => endpoint.status !== "online" || heartbeatAgeMinutes(endpoint.lastHeartbeatAt) > 5).length;
|
||||
|
||||
async function retryJob(job: JobResponse) {
|
||||
@@ -121,7 +107,7 @@ export function MaintenancePage({ session, operations, onNavigate }: PageCompone
|
||||
|
||||
<div className="form-guidance maintenance-triage-intro">
|
||||
<strong>维护排障入口</strong>
|
||||
<span>从节点详情、最近失败任务和审计异常进入重试、查看相关服务器、查看日志链路,不需要直接接触 run 端。</span>
|
||||
<span>从节点详情和最近失败任务进入重试、查看相关服务器、查看日志链路,不需要直接接触 run 端。</span>
|
||||
</div>
|
||||
|
||||
<section className="maintenance-triage-grid" aria-label="维护排障入口">
|
||||
@@ -137,17 +123,11 @@ export function MaintenancePage({ session, operations, onNavigate }: PageCompone
|
||||
<strong>{jobs.status === "ready" ? `${failedJobs.length} 个失败` : "加载中"}</strong>
|
||||
<small>从失败任务进入重试、查看相关服务器和查看日志链路。</small>
|
||||
</button>
|
||||
<button type="button" className="triage-card" onClick={() => void refreshEvents()}>
|
||||
<Activity size={18} />
|
||||
<span>审计异常</span>
|
||||
<strong>{events.status === "ready" ? `${failedAuditCount} 条异常` : "加载中"}</strong>
|
||||
<small>按资源定位失败操作和平台拒绝原因。</small>
|
||||
</button>
|
||||
</section>
|
||||
|
||||
{triageResult && <ResultBadge status={triageResult.status} label={triageResult.label} />}
|
||||
|
||||
<ProductionGovernancePanel title="容量治理与告警闭环" />
|
||||
<ProductionOperationsPanel title="容量与告警闭环" />
|
||||
|
||||
<section className="console-panel" aria-label="run endpoints">
|
||||
<div className="panel-header">
|
||||
@@ -262,53 +242,6 @@ export function MaintenancePage({ session, operations, onNavigate }: PageCompone
|
||||
)}
|
||||
</section>
|
||||
|
||||
<section className="console-panel" aria-label="audit events">
|
||||
<div className="panel-header">
|
||||
<h2>审计事件</h2>
|
||||
</div>
|
||||
{events.status === "loading" && <LoadingState label="正在加载审计事件…" compact />}
|
||||
{events.status === "error" && (
|
||||
<ErrorState title="审计事件加载失败" reason={events.reason} diagnosticId="maintenance-audit" onRetry={() => void refreshEvents()} compact />
|
||||
)}
|
||||
{events.status === "ready" && events.data.length === 0 && (
|
||||
<EmptyState title="暂无审计事件" description="平台还没有记录任何审计事件。" actionLabel="刷新" onAction={() => void refreshEvents()} />
|
||||
)}
|
||||
{events.status === "ready" && events.data.length > 0 && (
|
||||
<div className="console-record-list">
|
||||
{events.data.slice(0, 30).map((event) => (
|
||||
<div key={event.id} className="console-record">
|
||||
<div className="console-record-head">
|
||||
<strong>{event.summary || `${event.action} ${event.resourceKind}`}</strong>
|
||||
<span className={cx("status-pill", auditResultClass(event))}>{event.result}</span>
|
||||
</div>
|
||||
<div className="console-record-meta">
|
||||
<span>
|
||||
事件 <code>{event.id}</code>
|
||||
</span>
|
||||
<span>操作者 {event.actorId}</span>
|
||||
<span>
|
||||
资源 {event.resourceKind}/{event.resourceId}
|
||||
</span>
|
||||
<span>{formatTimestamp(event.createdAt)}</span>
|
||||
</div>
|
||||
<div className="console-row-actions">
|
||||
<button type="button" className="theme-upload" onClick={() => void refreshEvents()}>
|
||||
查看审计链路
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="theme-upload"
|
||||
disabled={event.resourceKind !== "server-instance"}
|
||||
onClick={() => event.resourceKind === "server-instance" && onNavigate("serverDetail", { serverId: event.resourceId })}
|
||||
>
|
||||
查看相关服务器
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -355,10 +288,6 @@ function heartbeatAgeMinutes(value: string): number {
|
||||
return (Date.now() - timestamp) / 60000;
|
||||
}
|
||||
|
||||
function auditResultClass(event: AuditEventResponse): string {
|
||||
return event.result === "success" ? "status-active" : "status-error";
|
||||
}
|
||||
|
||||
function jobStateLabel(state: JobResponse["state"]): string {
|
||||
switch (state) {
|
||||
case "queued":
|
||||
|
||||
Reference in New Issue
Block a user