Publish curated ITWorx-ModelForge source from 990401737f96c8d46a9f7b0d84994516cadcb6a0
This commit is contained in:
1 parent
7082ab955a
commit
848f0d8f8a
434 files changed
+67298
-4315
No files matched your search
@@ -0,0 +1,139 @@
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { Clock3, RefreshCw } from "lucide-react";
|
||||
|
||||
import { api, ApiError } from "../lib/api";
|
||||
import type {
|
||||
ArtifactJob, BackupSet, CapacitySnapshot, CapabilityDeployment, CompatibilityAssessment, GatewayRequest, OperationalAlert,
|
||||
HardwareState, MigrationCutoverOperation, MigrationPlan, RecoveryDashboard, RuntimeProbe, SchedulerBudget,
|
||||
SecretSlotCatalog,
|
||||
} from "../types";
|
||||
import type { ProjectWorkspaceView } from "../model-management-types";
|
||||
import { diagnoseTroubleshooting, type EvidenceRead, type TroubleshootingCheck, type TroubleshootingEvidence } from "../lib/troubleshooting";
|
||||
|
||||
const readFailed = <T,>(): EvidenceRead<T> => ({ state: "unknown", reason: "read_failed" });
|
||||
const adminRequired = <T,>(): EvidenceRead<T> => ({ state: "unknown", reason: "admin_required" });
|
||||
const identityUnavailable = <T,>(): EvidenceRead<T> => ({ state: "unknown", reason: "identity_unavailable" });
|
||||
|
||||
async function read<T>(request: () => Promise<T>): Promise<EvidenceRead<T>> {
|
||||
try { return { state: "loaded", value: await request() }; }
|
||||
catch (cause) {
|
||||
if (cause instanceof ApiError) {
|
||||
return {
|
||||
state: "unknown",
|
||||
reason: "read_failed",
|
||||
errorCode: cause.code,
|
||||
correlationId: cause.correlationId,
|
||||
};
|
||||
}
|
||||
return readFailed();
|
||||
}
|
||||
}
|
||||
|
||||
function unavailableEvidence(reason: "read_failed" | "admin_required" | "identity_unavailable"): TroubleshootingEvidence {
|
||||
const result = <T,>(): EvidenceRead<T> => ({ state: "unknown", reason });
|
||||
return {
|
||||
hardware: result<HardwareState>(), capacity: result<CapacitySnapshot[]>(), scheduler: result<SchedulerBudget[]>(),
|
||||
artifactJobs: result<ArtifactJob[]>(), operationalAlerts: result<OperationalAlert[]>(),
|
||||
assessments: result<CompatibilityAssessment[]>(), probes: result<RuntimeProbe[]>(),
|
||||
deployments: result<CapabilityDeployment[]>(), projects: result<ProjectWorkspaceView[]>(), secretSlots: result<SecretSlotCatalog>(),
|
||||
gatewayRequests: result<GatewayRequest[]>(), backups: result<BackupSet[]>(), recovery: result<RecoveryDashboard>(),
|
||||
migrations: result<MigrationPlan[]>(), cutovers: result<MigrationCutoverOperation[]>(),
|
||||
};
|
||||
}
|
||||
|
||||
async function loadEvidence(token: string): Promise<TroubleshootingEvidence> {
|
||||
if (!token) return unavailableEvidence("read_failed");
|
||||
|
||||
const [identity, common] = await Promise.all([
|
||||
read(() => api.verifyOperatorCredential(token)),
|
||||
Promise.all([
|
||||
read(() => api.hardware()),
|
||||
read(() => api.scheduler()),
|
||||
read(() => api.artifactJobs()),
|
||||
read(() => api.compatibilityAssessments()),
|
||||
read(() => api.runtimeProbes()),
|
||||
read(() => api.capabilityDeployments()),
|
||||
read(() => api.projectWorkspace()),
|
||||
read(() => api.secretSlots()),
|
||||
]),
|
||||
]);
|
||||
|
||||
let capacity: EvidenceRead<CapacitySnapshot[]>;
|
||||
let operationalAlerts: EvidenceRead<OperationalAlert[]>;
|
||||
let gatewayRequests: EvidenceRead<GatewayRequest[]>;
|
||||
let backups: EvidenceRead<BackupSet[]>;
|
||||
let recovery: EvidenceRead<RecoveryDashboard>;
|
||||
let migrations: EvidenceRead<MigrationPlan[]>;
|
||||
let cutovers: EvidenceRead<MigrationCutoverOperation[]>;
|
||||
if (identity.state === "loaded" && identity.value.role === "admin") {
|
||||
[capacity, operationalAlerts, gatewayRequests, backups, recovery, migrations, cutovers] = await Promise.all([
|
||||
read(() => api.capacitySnapshots(token)),
|
||||
read(() => api.operationalAlerts(token)),
|
||||
read(() => api.gatewayRequests(token)),
|
||||
read(() => api.backupSets(token)),
|
||||
read(() => api.recoveryDashboard(token)),
|
||||
read(() => api.migrationPlans(token)),
|
||||
read(() => api.migrationCutovers(token)),
|
||||
]);
|
||||
} else if (identity.state === "loaded") {
|
||||
capacity = adminRequired(); operationalAlerts = adminRequired(); gatewayRequests = adminRequired(); backups = adminRequired();
|
||||
recovery = adminRequired(); migrations = adminRequired(); cutovers = adminRequired();
|
||||
} else {
|
||||
capacity = identityUnavailable(); operationalAlerts = identityUnavailable(); gatewayRequests = identityUnavailable(); backups = identityUnavailable();
|
||||
recovery = identityUnavailable(); migrations = identityUnavailable(); cutovers = identityUnavailable();
|
||||
}
|
||||
|
||||
const [hardware, scheduler, artifactJobs, assessments, probes, deployments, projects, secretSlots] = common;
|
||||
return {
|
||||
hardware, capacity, scheduler, artifactJobs, operationalAlerts, assessments, probes, deployments, projects, secretSlots,
|
||||
gatewayRequests, backups, recovery, migrations, cutovers,
|
||||
};
|
||||
}
|
||||
|
||||
function stateClass(value: string): string { return value.toLowerCase().replaceAll("_", "-"); }
|
||||
|
||||
export function TroubleshootingPanel({ token }: { token: string }) {
|
||||
const [checks, setChecks] = useState<TroubleshootingCheck[] | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [refreshKey, setRefreshKey] = useState(0);
|
||||
const requestVersion = useRef(0);
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
const version = ++requestVersion.current;
|
||||
setLoading(true);
|
||||
try {
|
||||
const evidence = await loadEvidence(token);
|
||||
let nextChecks: TroubleshootingCheck[];
|
||||
try { nextChecks = diagnoseTroubleshooting(evidence); }
|
||||
catch { nextChecks = diagnoseTroubleshooting(unavailableEvidence("read_failed")); }
|
||||
if (requestVersion.current === version) setChecks(nextChecks);
|
||||
} finally {
|
||||
if (requestVersion.current === version) setLoading(false);
|
||||
}
|
||||
}, [token]);
|
||||
|
||||
useEffect(() => {
|
||||
void refresh();
|
||||
return () => { requestVersion.current += 1; };
|
||||
}, [refresh, refreshKey]);
|
||||
|
||||
return <section className="troubleshooting-stack" aria-labelledby="troubleshooting-title">
|
||||
<div className="operations-section-title">
|
||||
<div><span className="eyebrow">READ-ONLY EVIDENCE</span><h2 id="troubleshooting-title">Troubleshooting</h2>
|
||||
<p>Findings come from typed node, capacity, artifact, runtime, credential, backup, and migration records. No finding is not proof of health; unavailable or unauthorized sources stay unknown.</p>
|
||||
</div>
|
||||
<button type="button" onClick={() => setRefreshKey((value) => value + 1)} disabled={loading || !token}>
|
||||
<RefreshCw size={15} className={loading ? "spin" : ""} />{loading ? "Reading evidence…" : "Refresh diagnosis"}
|
||||
</button>
|
||||
</div>
|
||||
{checks ? <div className="operations-grid troubleshooting-grid">
|
||||
{checks.map((check) => <article className="panel operation-card troubleshooting-card" key={check.id}>
|
||||
<div><span className="eyebrow">{check.title}</span><span className={`status-chip ${stateClass(check.state)}`}>{check.state.replaceAll("_", " ")}</span></div>
|
||||
<h3>{check.state === "ISSUE_OBSERVED" ? "Typed issue observed" : check.state === "UNKNOWN" ? "State unknown" : "No typed failure observed"}</h3>
|
||||
<ul className="troubleshooting-evidence">{check.evidence.map((item, index) => <li key={`${check.id}-${index}`}>{item}</li>)}</ul>
|
||||
<p><strong>Next action:</strong> {check.nextAction}</p>
|
||||
<a href={check.runbook.href} target="_blank" rel="noreferrer">{check.runbook.label}</a>
|
||||
</article>)}
|
||||
</div> : <div className="state-card" role="status"><Clock3 size={18} />{loading ? "Reading typed operational evidence…" : "No operational evidence has been loaded."}</div>}
|
||||
</section>;
|
||||
}
|
||||
Reference in new issue
Block a user