← 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
M frontend/src/components/AutonomyControl.tsxM frontend/src/components/Boardroom.tsxM frontend/src/components/DecisionPanel.tsxM frontend/src/components/DelegationForm.tsxM frontend/src/components/EscalationQueue.tsxM frontend/src/components/Initiatives.tsx
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 →