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 [busy, setBusy] = useState<string | null>(null);
|
||||||
|
|
||||||
const tenantId = useApp((s) => s.tenantId);
|
const tenantId = useApp((s) => s.tenantId);
|
||||||
|
const [runtimeHealth, setRuntimeHealth] = useState<"unknown" | "up" | "down">("unknown");
|
||||||
|
|
||||||
const loadQueue = async () => {
|
const loadQueue = async () => {
|
||||||
if (!tenantId) {
|
if (!tenantId) {
|
||||||
setItems([]);
|
setItems([]);
|
||||||
@@ -52,6 +54,21 @@ export default function Approvals() {
|
|||||||
|
|
||||||
useEffect(() => { void loadQueue(); }, [tenantId]);
|
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(() => {
|
useEffect(() => {
|
||||||
if (!activeKey) return;
|
if (!activeKey) return;
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
@@ -163,21 +180,26 @@ export default function Approvals() {
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="approvals-runtime-note">
|
{runtimeHealth === "down" && (
|
||||||
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 className="approvals-runtime-note">
|
||||||
</div>
|
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">
|
<div className="approvals-actions">
|
||||||
{(tx.available_actions || []).map((a: any) => (
|
{(tx.available_actions || []).map((a: any) => {
|
||||||
<button
|
const disabled = !a.enabled || busy === a.id || runtimeHealth === "down";
|
||||||
key={a.id}
|
return (
|
||||||
className={`btn ${a.kind === "approve" || a.kind === "submit" ? "btn-primary" : "btn-secondary"}`}
|
<button
|
||||||
disabled={!a.enabled || busy === a.id}
|
key={a.id}
|
||||||
onClick={() => handleAction(a.id)}
|
className={`btn ${a.kind === "approve" || a.kind === "submit" ? "btn-primary" : "btn-secondary"}`}
|
||||||
title="Disabled in this environment — runtime-values offline"
|
disabled={disabled}
|
||||||
>
|
onClick={() => handleAction(a.id)}
|
||||||
<Pulse size={11} /> {busy === a.id ? "Sending…" : `${a.display_label || a.id} · preview`}
|
title={runtimeHealth === "down" ? "Runtime engine offline" : a.display_label || a.id}
|
||||||
</button>
|
>
|
||||||
))}
|
<Pulse size={11} /> {busy === a.id ? "Sending…" : a.display_label || a.id}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
{(!tx.available_actions || tx.available_actions.length === 0) && (
|
{(!tx.available_actions || tx.available_actions.length === 0) && (
|
||||||
<div className="hub-empty">No actions available on this step.</div>
|
<div className="hub-empty">No actions available on this step.</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user