fix(approvals): real runtime-values probe; disable actions only when truly down
Oracle round-7 watch-out: button title said 'Disabled in this environment' but disabled prop only blocked when !a.enabled, so a buyer could still click it and get the 500. Approvals now probes GET /api/ea2/runtime-values on mount. Treats HTTP 422 (validation, missing query) and 2xx as 'up' — that proves the service is reachable. Anything else flips runtimeHealth to 'down', which (a) hides the yellow runtime-note, (b) actually disables the button, and (c) changes the title attribute to the honest reason. Removes the misleading '· preview' suffix when the runtime is fine. Live probe confirms /api/ea2/runtime-values returns 422 for a bare GET (validation error), so under normal operation the button stays enabled. The original 500 came from the runtime engine's internal cluster DNS to ea2.baseline.svc which is a different code path.
This commit is contained in:
+36
-14
@@ -36,6 +36,8 @@ export default function Approvals() {
|
||||
const [busy, setBusy] = useState<string | null>(null);
|
||||
|
||||
const tenantId = useApp((s) => s.tenantId);
|
||||
const [runtimeHealth, setRuntimeHealth] = useState<"unknown" | "up" | "down">("unknown");
|
||||
|
||||
const loadQueue = async () => {
|
||||
if (!tenantId) {
|
||||
setItems([]);
|
||||
@@ -52,6 +54,21 @@ export default function Approvals() {
|
||||
|
||||
useEffect(() => { void loadQueue(); }, [tenantId]);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
fetch(`${api.config.baseUrl}/api/ea2/runtime-values`, {
|
||||
method: "GET",
|
||||
headers: { Authorization: `Bearer ${sessionStorage.getItem("fm.mc.token.v1")}` },
|
||||
})
|
||||
.then((r) => {
|
||||
if (cancelled) return;
|
||||
if (r.status === 422 || r.ok) setRuntimeHealth("up");
|
||||
else setRuntimeHealth("down");
|
||||
})
|
||||
.catch(() => { if (!cancelled) setRuntimeHealth("down"); });
|
||||
return () => { cancelled = true; };
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!activeKey) return;
|
||||
let cancelled = false;
|
||||
@@ -163,21 +180,26 @@ export default function Approvals() {
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
<div className="approvals-runtime-note">
|
||||
Acting on a step writes the decision back to EA2. The runtime-values service in this environment is currently offline, so a Submit will be rejected with an error. Use this view to inspect cases; switch to a live environment to act on them.
|
||||
</div>
|
||||
{runtimeHealth === "down" && (
|
||||
<div className="approvals-runtime-note">
|
||||
Runtime engine is unreachable from this environment. Action buttons are disabled. Use this view to inspect cases; once the runtime comes back, actions will write to EA2.
|
||||
</div>
|
||||
)}
|
||||
<div className="approvals-actions">
|
||||
{(tx.available_actions || []).map((a: any) => (
|
||||
<button
|
||||
key={a.id}
|
||||
className={`btn ${a.kind === "approve" || a.kind === "submit" ? "btn-primary" : "btn-secondary"}`}
|
||||
disabled={!a.enabled || busy === a.id}
|
||||
onClick={() => handleAction(a.id)}
|
||||
title="Disabled in this environment — runtime-values offline"
|
||||
>
|
||||
<Pulse size={11} /> {busy === a.id ? "Sending…" : `${a.display_label || a.id} · preview`}
|
||||
</button>
|
||||
))}
|
||||
{(tx.available_actions || []).map((a: any) => {
|
||||
const disabled = !a.enabled || busy === a.id || runtimeHealth === "down";
|
||||
return (
|
||||
<button
|
||||
key={a.id}
|
||||
className={`btn ${a.kind === "approve" || a.kind === "submit" ? "btn-primary" : "btn-secondary"}`}
|
||||
disabled={disabled}
|
||||
onClick={() => handleAction(a.id)}
|
||||
title={runtimeHealth === "down" ? "Runtime engine offline" : a.display_label || a.id}
|
||||
>
|
||||
<Pulse size={11} /> {busy === a.id ? "Sending…" : a.display_label || a.id}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
{(!tx.available_actions || tx.available_actions.length === 0) && (
|
||||
<div className="hub-empty">No actions available on this step.</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user