diff --git a/packages/desktop-client/src/components/reports/Overview.tsx b/packages/desktop-client/src/components/reports/Overview.tsx
index 323eb143ef..1fc3f01940 100644
--- a/packages/desktop-client/src/components/reports/Overview.tsx
+++ b/packages/desktop-client/src/components/reports/Overview.tsx
@@ -1,5 +1,6 @@
import { useCallback, useMemo, useState } from 'react';
import { Dialog, DialogTrigger } from 'react-aria-components';
+import { ErrorBoundary } from 'react-error-boundary';
import ReactGridLayout from 'react-grid-layout';
import type { Layout } from 'react-grid-layout';
import { useHotkeys } from 'react-hotkeys-hook';
@@ -34,6 +35,7 @@ import { CrossoverCard } from './reports/CrossoverCard';
import { CustomReportListCards } from './reports/CustomReportListCards';
import { FormulaCard } from './reports/FormulaCard';
import { MarkdownCard } from './reports/MarkdownCard';
+import { MissingReportCard } from './reports/MissingReportCard';
import { NetWorthCard } from './reports/NetWorthCard';
import { SankeyCard } from './reports/SankeyCard';
import './overview.scss';
@@ -770,142 +772,176 @@ export function Overview({ dashboard }: OverviewProps) {
return (
- {widget.type === 'net-worth-card' ? (
-
onMetaChange(item, newMeta)}
- onRemove={() => onRemoveWidget(item.i)}
- onCopy={targetDashboardId =>
- onCopyWidget(item.i, targetDashboardId)
- }
- />
- ) : widget.type === 'crossover-card' &&
- crossoverReportEnabled ? (
- onMetaChange(item, newMeta)}
- onRemove={() => onRemoveWidget(item.i)}
- onCopy={targetDashboardId =>
- onCopyWidget(item.i, targetDashboardId)
- }
- />
- ) : widget.type === 'age-of-money-card' &&
- ageOfMoneyReportEnabled ? (
- onMetaChange(item, newMeta)}
- onRemove={() => onRemoveWidget(item.i)}
- onCopy={targetDashboardId =>
- onCopyWidget(item.i, targetDashboardId)
- }
- />
- ) : widget.type === 'cash-flow-card' ? (
- onMetaChange(item, newMeta)}
- onRemove={() => onRemoveWidget(item.i)}
- onCopy={targetDashboardId =>
- onCopyWidget(item.i, targetDashboardId)
- }
- />
- ) : widget.type === 'spending-card' ? (
- onMetaChange(item, newMeta)}
- onRemove={() => onRemoveWidget(item.i)}
- onCopy={targetDashboardId =>
- onCopyWidget(item.i, targetDashboardId)
- }
- />
- ) : widget.type === 'budget-analysis-card' &&
- budgetAnalysisReportEnabled ? (
- onMetaChange(item, newMeta)}
- onRemove={() => onRemoveWidget(item.i)}
- onCopy={targetDashboardId =>
- onCopyWidget(item.i, targetDashboardId)
- }
- />
- ) : widget.type === 'markdown-card' ? (
- onMetaChange(item, newMeta)}
- onRemove={() => onRemoveWidget(item.i)}
- onCopy={targetDashboardId =>
- onCopyWidget(item.i, targetDashboardId)
- }
- />
- ) : widget.type === 'custom-report' ? (
- onRemoveWidget(item.i)}
- onCopy={targetDashboardId =>
- onCopyWidget(item.i, targetDashboardId)
- }
- />
- ) : widget.type === 'summary-card' ? (
- onMetaChange(item, newMeta)}
- onRemove={() => onRemoveWidget(item.i)}
- onCopy={targetDashboardId =>
- onCopyWidget(item.i, targetDashboardId)
- }
- />
- ) : widget.type === 'calendar-card' ? (
- onMetaChange(item, newMeta)}
- onRemove={() => onRemoveWidget(item.i)}
- onCopy={targetDashboardId =>
- onCopyWidget(item.i, targetDashboardId)
- }
- />
- ) : widget.type === 'formula-card' && formulaMode ? (
- onMetaChange(item, newMeta)}
- onRemove={() => onRemoveWidget(item.i)}
- onCopy={targetDashboardId =>
- onCopyWidget(item.i, targetDashboardId)
- }
- />
- ) : widget.type === 'sankey-card' && sankeyFeatureFlag ? (
- onMetaChange(item, newMeta)}
- onRemove={() => onRemoveWidget(item.i)}
- onCopy={targetDashboardId =>
- onCopyWidget(item.i, targetDashboardId)
- }
- />
- ) : null}
+ (
+ onRemoveWidget(item.i)}
+ >
+ This widget has failed to load.
+
+ )}
+ >
+ {widget.type === 'net-worth-card' ? (
+
+ onMetaChange(item, newMeta)
+ }
+ onRemove={() => onRemoveWidget(item.i)}
+ onCopy={targetDashboardId =>
+ onCopyWidget(item.i, targetDashboardId)
+ }
+ />
+ ) : widget.type === 'crossover-card' &&
+ crossoverReportEnabled ? (
+
+ onMetaChange(item, newMeta)
+ }
+ onRemove={() => onRemoveWidget(item.i)}
+ onCopy={targetDashboardId =>
+ onCopyWidget(item.i, targetDashboardId)
+ }
+ />
+ ) : widget.type === 'age-of-money-card' &&
+ ageOfMoneyReportEnabled ? (
+
+ onMetaChange(item, newMeta)
+ }
+ onRemove={() => onRemoveWidget(item.i)}
+ onCopy={targetDashboardId =>
+ onCopyWidget(item.i, targetDashboardId)
+ }
+ />
+ ) : widget.type === 'cash-flow-card' ? (
+
+ onMetaChange(item, newMeta)
+ }
+ onRemove={() => onRemoveWidget(item.i)}
+ onCopy={targetDashboardId =>
+ onCopyWidget(item.i, targetDashboardId)
+ }
+ />
+ ) : widget.type === 'spending-card' ? (
+
+ onMetaChange(item, newMeta)
+ }
+ onRemove={() => onRemoveWidget(item.i)}
+ onCopy={targetDashboardId =>
+ onCopyWidget(item.i, targetDashboardId)
+ }
+ />
+ ) : widget.type === 'budget-analysis-card' &&
+ budgetAnalysisReportEnabled ? (
+
+ onMetaChange(item, newMeta)
+ }
+ onRemove={() => onRemoveWidget(item.i)}
+ onCopy={targetDashboardId =>
+ onCopyWidget(item.i, targetDashboardId)
+ }
+ />
+ ) : widget.type === 'markdown-card' ? (
+
+ onMetaChange(item, newMeta)
+ }
+ onRemove={() => onRemoveWidget(item.i)}
+ onCopy={targetDashboardId =>
+ onCopyWidget(item.i, targetDashboardId)
+ }
+ />
+ ) : widget.type === 'custom-report' ? (
+ onRemoveWidget(item.i)}
+ onCopy={targetDashboardId =>
+ onCopyWidget(item.i, targetDashboardId)
+ }
+ />
+ ) : widget.type === 'summary-card' ? (
+
+ onMetaChange(item, newMeta)
+ }
+ onRemove={() => onRemoveWidget(item.i)}
+ onCopy={targetDashboardId =>
+ onCopyWidget(item.i, targetDashboardId)
+ }
+ />
+ ) : widget.type === 'calendar-card' ? (
+
+ onMetaChange(item, newMeta)
+ }
+ onRemove={() => onRemoveWidget(item.i)}
+ onCopy={targetDashboardId =>
+ onCopyWidget(item.i, targetDashboardId)
+ }
+ />
+ ) : widget.type === 'formula-card' && formulaMode ? (
+
+ onMetaChange(item, newMeta)
+ }
+ onRemove={() => onRemoveWidget(item.i)}
+ onCopy={targetDashboardId =>
+ onCopyWidget(item.i, targetDashboardId)
+ }
+ />
+ ) : widget.type === 'sankey-card' &&
+ sankeyFeatureFlag ? (
+
+ onMetaChange(item, newMeta)
+ }
+ onRemove={() => onRemoveWidget(item.i)}
+ onCopy={targetDashboardId =>
+ onCopyWidget(item.i, targetDashboardId)
+ }
+ />
+ ) : null}
+
);
})}
diff --git a/upcoming-release-notes/7382.md b/upcoming-release-notes/7382.md
new file mode 100644
index 0000000000..0f4850b0e3
--- /dev/null
+++ b/upcoming-release-notes/7382.md
@@ -0,0 +1,6 @@
+---
+category: Enhancements
+authors: [MatissJanis]
+---
+
+Add error boundary to dashboard widgets, displaying fallback UI for rendering failures.