[object Object]

← back to Dw Boardroom Governance

Add error handling to frontend API mutation handlers to prevent unhandled promise rejections

83b5830352d8a72c3b845839d3caaf2da50bf4cb · 2026-05-18 20:19:26 -0700 · Steve Abrams

Files touched

Diff

commit 83b5830352d8a72c3b845839d3caaf2da50bf4cb
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon May 18 20:19:26 2026 -0700

    Add error handling to frontend API mutation handlers to prevent unhandled promise rejections
---
 frontend/src/components/AutonomyControl.tsx |  8 +++++++-
 frontend/src/components/Boardroom.tsx       | 16 ++++++++++++----
 frontend/src/components/DecisionPanel.tsx   |  8 ++++++--
 frontend/src/components/DelegationForm.tsx  | 18 +++++++++++++-----
 frontend/src/components/EscalationQueue.tsx |  8 ++++++--
 frontend/src/components/Initiatives.tsx     | 28 ++++++++++++++++++++--------
 6 files changed, 64 insertions(+), 22 deletions(-)

diff --git a/frontend/src/components/AutonomyControl.tsx b/frontend/src/components/AutonomyControl.tsx
index 5c0c447..476754d 100644
--- a/frontend/src/components/AutonomyControl.tsx
+++ b/frontend/src/components/AutonomyControl.tsx
@@ -10,9 +10,15 @@ export default function AutonomyControl() {
   }, []);
 
   async function updateSetting(key: string, value: any) {
+    const previous = config;
     const updated = { ...config, [key]: value };
     setConfig(updated);
-    await api.updateConfig({ [key]: value });
+    try {
+      await api.updateConfig({ [key]: value });
+    } catch (err: any) {
+      console.error('[AutonomyControl] updateConfig failed:', err.message);
+      setConfig(previous); // revert optimistic update on failure
+    }
   }
 
   const mode = (typeof config.governance_mode === 'string' ? config.governance_mode : 'supervised').replace(/"/g, '');
diff --git a/frontend/src/components/Boardroom.tsx b/frontend/src/components/Boardroom.tsx
index 9e85621..086e5e4 100644
--- a/frontend/src/components/Boardroom.tsx
+++ b/frontend/src/components/Boardroom.tsx
@@ -53,14 +53,22 @@ export default function Boardroom({ events }: { events: WSEvent[] }) {
 
   async function halt() {
     if (!meeting) return;
-    await api.haltMeeting(meeting.id);
-    await loadActive();
+    try {
+      await api.haltMeeting(meeting.id);
+      await loadActive();
+    } catch (err: any) {
+      alert(err.message);
+    }
   }
 
   async function advance() {
     if (!meeting) return;
-    await api.advanceMeeting(meeting.id);
-    await loadActive();
+    try {
+      await api.advanceMeeting(meeting.id);
+      await loadActive();
+    } catch (err: any) {
+      alert(err.message);
+    }
   }
 
   const currentPhaseIdx = meeting ? PHASE_KEYS.indexOf(meeting.phase) : -1;
diff --git a/frontend/src/components/DecisionPanel.tsx b/frontend/src/components/DecisionPanel.tsx
index 59adf50..353c8e2 100644
--- a/frontend/src/components/DecisionPanel.tsx
+++ b/frontend/src/components/DecisionPanel.tsx
@@ -37,8 +37,12 @@ export default function DecisionPanel() {
 
   async function resolve(id: string, action: 'approve' | 'reject' | 'defer') {
     const fn = action === 'approve' ? api.approveDecision : action === 'reject' ? api.rejectDecision : api.deferDecision;
-    await fn(id);
-    refresh();
+    try {
+      await fn(id);
+      refresh();
+    } catch (err: any) {
+      console.error('[DecisionPanel] resolve failed:', err.message);
+    }
   }
 
   return (
diff --git a/frontend/src/components/DelegationForm.tsx b/frontend/src/components/DelegationForm.tsx
index e5e35a5..24e3b5a 100644
--- a/frontend/src/components/DelegationForm.tsx
+++ b/frontend/src/components/DelegationForm.tsx
@@ -25,14 +25,22 @@ export default function DelegationForm() {
 
   async function suggest() {
     if (!searchText) return;
-    const result = await api.suggestDelegate(searchText);
-    setSuggestion(result);
-    if (result.suggestedDelegate) setDelegate(result.suggestedDelegate);
+    try {
+      const result = await api.suggestDelegate(searchText);
+      setSuggestion(result);
+      if (result.suggestedDelegate) setDelegate(result.suggestedDelegate);
+    } catch (err: any) {
+      console.error('[DelegationForm] suggest failed:', err.message);
+    }
   }
 
   async function revoke(id: string) {
-    await api.revokeDelegation(id);
-    refresh();
+    try {
+      await api.revokeDelegation(id);
+      refresh();
+    } catch (err: any) {
+      console.error('[DelegationForm] revoke failed:', err.message);
+    }
   }
 
   return (
diff --git a/frontend/src/components/EscalationQueue.tsx b/frontend/src/components/EscalationQueue.tsx
index df64ae9..fb7ca16 100644
--- a/frontend/src/components/EscalationQueue.tsx
+++ b/frontend/src/components/EscalationQueue.tsx
@@ -5,8 +5,12 @@ export default function EscalationQueue() {
   const { data: escalations, refresh } = useApi(() => api.getActiveEscalations(), []);
 
   async function triggerCheck() {
-    await api.triggerEscalationCheck();
-    refresh();
+    try {
+      await api.triggerEscalationCheck();
+      refresh();
+    } catch (err: any) {
+      console.error('[EscalationQueue] triggerCheck failed:', err.message);
+    }
   }
 
   return (
diff --git a/frontend/src/components/Initiatives.tsx b/frontend/src/components/Initiatives.tsx
index e021820..9740d40 100644
--- a/frontend/src/components/Initiatives.tsx
+++ b/frontend/src/components/Initiatives.tsx
@@ -16,20 +16,32 @@ export default function Initiatives() {
 
   async function create() {
     if (!title.trim()) return;
-    await api.createInitiative({ title, driverAgent: driver || 'unassigned', kpi, riskLevel: risk });
-    setTitle(''); setDriver(''); setKpi('');
-    setShowForm(false);
-    refresh();
+    try {
+      await api.createInitiative({ title, driverAgent: driver || 'unassigned', kpi, riskLevel: risk });
+      setTitle(''); setDriver(''); setKpi('');
+      setShowForm(false);
+      refresh();
+    } catch (err: any) {
+      console.error('[Initiatives] create failed:', err.message);
+    }
   }
 
   async function updateStatus(id: string, status: string) {
-    await api.updateInitiative(id, { status });
-    refresh();
+    try {
+      await api.updateInitiative(id, { status });
+      refresh();
+    } catch (err: any) {
+      console.error('[Initiatives] updateStatus failed:', err.message);
+    }
   }
 
   async function updateProgress(id: string, progress: number) {
-    await api.updateInitiative(id, { progress });
-    refresh();
+    try {
+      await api.updateInitiative(id, { progress });
+      refresh();
+    } catch (err: any) {
+      console.error('[Initiatives] updateProgress failed:', err.message);
+    }
   }
 
   return (

← 44b2fa8 Fix useWebSocket: prevent zombie reconnect timer firing afte  ·  back to Dw Boardroom Governance  ·  security: strip hardcoded dw_admin DSN password -> env-first 3c19ba6 →