Remove pre-1.0 production governance surfaces

This commit is contained in:
npc0-hue
2026-08-21 00:06:00 +08:00
parent a7e2e4c6c0
commit da6c8d607e
30 changed files with 89 additions and 429 deletions
+1 -1
View File
@@ -38,7 +38,7 @@ export function OperationsTray({ operations }: OperationsTrayProps) {
<div id="session-operations-panel" className="operations-tray-panel" role="region" aria-live="polite">
<div className="operations-tray-heading">
<strong></strong>
<span> Platform </span>
<span> Platform </span>
</div>
{items.length === 0 ? (
<p className="operations-tray-empty"></p>
@@ -63,7 +63,7 @@ export function PluginLifecycleWorkbench({ pluginId, pluginName, operations = li
idempotencyKey: `web:plugin.lifecycle:${pluginId}:${selectedServerId}:${operation}:${Date.now()}`,
confirmed: disruptiveOperations.includes(operation)
});
const evidence = [response.job?.id && `任务 ${response.job.id}`, response.installation.alertId && `告警 ${response.installation.alertId}`].filter(Boolean).join(" · ");
const evidence = [response.job?.id && `任务 ${response.job.id}`].filter(Boolean).join(" · ");
setResult({ status: response.status === "queued" || response.status === "accepted" ? "succeeded" : response.status === "deferred" ? "pending" : "failed", label: `${lifecycleOperationLabel(operation)}${response.status}${evidence ? ` · ${evidence}` : ""}` });
setConfirming(false);
await refresh();
@@ -102,7 +102,7 @@ export function PluginLifecycleWorkbench({ pluginId, pluginName, operations = li
<div className="console-record-head"><strong>{installation.currentState} {installation.desiredState}</strong><span className="status-pill status-active">{installation.compatibility || "pending"}</span></div>
<div className="console-record-meta">
<span> {installation.currentVersion || "--"}</span><span> {installation.targetVersion || "--"}</span><span> {installation.dependencyState || "unknown"}</span>
{installation.jobId && <span> {installation.jobId}</span>}{installation.alertId && <span> {installation.alertId}</span>}
{installation.jobId && <span> {installation.jobId}</span>}
</div>
{installation.failureReason && <p className="operation-error">{installation.failureReason}</p>}
</div>
@@ -2,21 +2,19 @@ import { renderToStaticMarkup } from "react-dom/server";
import { describe, expect, it } from "vitest";
import { AIConfigDiffReviewPanel } from "./AIConfigDiffReviewPanel";
import { ProductionOperationsPanel } from "./ProductionOperationsPanel";
import operationsSource from "./ProductionOperationsPanel.tsx?raw";
import { PluginLifecycleWorkbench } from "./PluginLifecycleWorkbench";
import lifecycleSource from "./PluginLifecycleWorkbench.tsx?raw";
import diffSource from "./AIConfigDiffReviewPanel.tsx?raw";
describe("production operations components", () => {
describe("plugin operations components", () => {
it("renders persisted loading states without optimistic terminal success", () => {
expect(renderToStaticMarkup(<ProductionOperationsPanel />)).toContain("正在同步容量与告警");
expect(renderToStaticMarkup(<PluginLifecycleWorkbench pluginId="game.example" pluginName="Example" />)).toContain("正在同步插件生命周期");
expect(renderToStaticMarkup(<AIConfigDiffReviewPanel />)).toContain("正在同步 AI 配置差异");
for (const source of [operationsSource, lifecycleSource, diffSource]) {
for (const source of [lifecycleSource, diffSource]) {
expect(source).not.toContain("setTimeout");
expect(source).not.toMatch(/apiKeyRef|rawApiKey|runSocket|providerBaseUrl|hostPath|directRun/i);
expect(source).toContain("disabled=");
}
expect(operationsSource).toContain("if (!intent || busyKey) return");
expect(lifecycleSource).toContain("if (!selectedServerId || busy) return");
expect(diffSource).toContain("if (!selected || busyId) return");
});
@@ -1,146 +0,0 @@
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 "重试来源";
}