Remove pre-1.0 audit and protected request scaffolding
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
import { Activity, AlertTriangle, Check, CheckCheck, RotateCw } from "lucide-react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
import { platformApiClient } from "../api/client";
|
||||
import type { AlertResponse, ProductionCapacitySummaryResponse } from "../api/types";
|
||||
import { cx } from "../utils/classes";
|
||||
import { ConfirmDialog } from "./OperationControls";
|
||||
import { ErrorState, LoadingState, ResultBadge } from "./StateViews";
|
||||
|
||||
type AlertAction = "acknowledge" | "resolve" | "retry";
|
||||
|
||||
interface ProductionOperationsPanelProps {
|
||||
compact?: boolean;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export function ProductionOperationsPanel({ compact = false, title = "容量与告警" }: ProductionOperationsPanelProps) {
|
||||
const [capacity, setCapacity] = useState<ProductionCapacitySummaryResponse | null>(null);
|
||||
const [alerts, setAlerts] = useState<AlertResponse[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState("");
|
||||
const [intent, setIntent] = useState<{ alert: AlertResponse; action: AlertAction } | null>(null);
|
||||
const [busyKey, setBusyKey] = useState("");
|
||||
const [result, setResult] = useState<{ status: "succeeded" | "failed"; label: string } | null>(null);
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
setLoading(true);
|
||||
setError("");
|
||||
try {
|
||||
const [capacityResponse, alertResponse] = await Promise.all([platformApiClient.getProductionCapacity(), platformApiClient.listAlerts()]);
|
||||
setCapacity(capacityResponse);
|
||||
setAlerts(alertResponse.items);
|
||||
} catch (caught) {
|
||||
setError(caught instanceof Error ? caught.message : "生产状态加载失败");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
void refresh();
|
||||
}, [refresh]);
|
||||
|
||||
async function submitIntent() {
|
||||
if (!intent || busyKey) return;
|
||||
const key = `${intent.alert.id}:${intent.action}`;
|
||||
setBusyKey(key);
|
||||
setResult(null);
|
||||
try {
|
||||
if (intent.action === "acknowledge") {
|
||||
await platformApiClient.acknowledgeAlert(intent.alert.id, "operator acknowledged from production console");
|
||||
} else if (intent.action === "resolve") {
|
||||
await platformApiClient.resolveAlert(intent.alert.id, "operator resolved after production review");
|
||||
} else {
|
||||
await platformApiClient.retryAlert(intent.alert.id, `web:alert.retry:${intent.alert.id}:${Date.now()}`);
|
||||
}
|
||||
setResult({ status: "succeeded", label: `${alertActionLabel(intent.action)}已由 Platform 持久化` });
|
||||
setIntent(null);
|
||||
await refresh();
|
||||
} catch (caught) {
|
||||
setResult({ status: "failed", label: caught instanceof Error ? caught.message : `${alertActionLabel(intent.action)}失败` });
|
||||
setIntent(null);
|
||||
} finally {
|
||||
setBusyKey("");
|
||||
}
|
||||
}
|
||||
|
||||
const visibleAlerts = compact ? alerts.filter((alert) => alert.state !== "resolved").slice(0, 3) : alerts.slice(0, 12);
|
||||
const visibleEndpoints = compact ? capacity?.endpoints.slice(0, 3) ?? [] : capacity?.endpoints ?? [];
|
||||
|
||||
return (
|
||||
<section className="console-panel console-module production-operations-panel" aria-label="production capacity and alerts">
|
||||
<div className="panel-header">
|
||||
<h2><AlertTriangle size={16} /> {title}</h2>
|
||||
<button type="button" className="icon-command" disabled={loading || Boolean(busyKey)} onClick={() => void refresh()} title="刷新容量与告警">
|
||||
<RotateCw size={14} />
|
||||
<span>刷新</span>
|
||||
</button>
|
||||
</div>
|
||||
{result && <ResultBadge status={result.status} label={result.label} />}
|
||||
{loading && <LoadingState label="正在同步容量与告警…" compact />}
|
||||
{!loading && error && <ErrorState title="生产状态不可用" reason={error} diagnosticId="production-operations" onRetry={() => void refresh()} compact />}
|
||||
{!loading && !error && capacity && (
|
||||
<>
|
||||
<dl className="console-stat-strip console-stat-strip-spaced">
|
||||
<div><dt>运行槽位</dt><dd>{capacity.totalRunningJobs}/{capacity.totalMaxJobs}</dd></div>
|
||||
<div><dt>排队</dt><dd>{capacity.totalQueuedJobs}</dd></div>
|
||||
<div><dt>未关闭告警</dt><dd>{capacity.activeAlerts}</dd></div>
|
||||
</dl>
|
||||
<div className="console-row-list" aria-label="capacity endpoints">
|
||||
{visibleEndpoints.map((endpoint) => (
|
||||
<div key={endpoint.runEndpointId} className="console-row">
|
||||
<span><strong>{endpoint.displayName}</strong><small>{endpoint.pressureCodes?.join(", ") || "capacity.available"}</small></span>
|
||||
<span className={cx("status-pill", endpoint.pressureCodes?.length ? "status-warning" : `status-${endpoint.status}`)}>{endpoint.pressureCodes?.length ? "压力" : endpoint.status}</span>
|
||||
<span>{endpoint.runningJobs}/{endpoint.maxJobs} · 队列 {endpoint.queuedJobs}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="console-record-list console-record-list-spaced production-alert-list" aria-label="durable alerts">
|
||||
{visibleAlerts.length === 0 && <p className="console-empty-note">当前没有持久告警。</p>}
|
||||
{visibleAlerts.map((alert) => {
|
||||
const pending = busyKey.startsWith(`${alert.id}:`);
|
||||
return (
|
||||
<div key={alert.id} className="console-record operation-item">
|
||||
<div className="console-record-head">
|
||||
<strong>{alert.title}</strong>
|
||||
<span className={cx("status-pill", alert.severity === "critical" ? "status-failed" : alert.state === "resolved" ? "status-succeeded" : "status-warning")}>{alert.state}</span>
|
||||
</div>
|
||||
<p>{alert.message}</p>
|
||||
<div className="console-record-meta">
|
||||
<span>{alert.sourceKind} · {alert.sourceId}</span>
|
||||
<span>发生 {alert.occurrenceCount} 次</span>
|
||||
{alert.lastJobId && <span>任务 {alert.lastJobId}</span>}
|
||||
</div>
|
||||
{alert.state !== "resolved" && (
|
||||
<div className="row-actions console-row-actions production-alert-actions">
|
||||
{alert.state === "active" && <button type="button" disabled={pending} onClick={() => setIntent({ alert, action: "acknowledge" })}><Check size={14} /><span>确认</span></button>}
|
||||
<button type="button" disabled={pending} onClick={() => setIntent({ alert, action: "resolve" })}><CheckCheck size={14} /><span>解决</span></button>
|
||||
{alert.retryable && <button type="button" disabled={pending} onClick={() => setIntent({ alert, action: "retry" })}><Activity size={14} /><span>重试源</span></button>}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<ConfirmDialog
|
||||
open={intent !== null}
|
||||
title={intent ? `${alertActionLabel(intent.action)}告警` : "告警操作"}
|
||||
description={intent ? `目标 ${intent.alert.id},仅处理来源 ${intent.alert.sourceKind}/${intent.alert.sourceId}。` : "确认告警操作。"}
|
||||
confirmLabel={intent ? alertActionLabel(intent.action) : "确认"}
|
||||
danger={intent?.action === "resolve"}
|
||||
busy={Boolean(busyKey)}
|
||||
onCancel={() => { if (!busyKey) setIntent(null); }}
|
||||
onConfirm={() => void submitIntent()}
|
||||
/>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function alertActionLabel(action: AlertAction) {
|
||||
if (action === "acknowledge") return "确认";
|
||||
if (action === "resolve") return "解决";
|
||||
return "重试来源";
|
||||
}
|
||||
Reference in New Issue
Block a user