From 351208e6ac32abc2d3e69e3218e05620ac385887 Mon Sep 17 00:00:00 2001
From: mralonsocorona
Date: Tue, 23 Jun 2026 14:06:36 -0600
Subject: [PATCH 1/2] fix(frontend): add dashboard section fallbacks
---
frontend/src/components/Layout.tsx | 29 ++++++--
frontend/src/components/SectionFallback.tsx | 68 +++++++++++++++++++
frontend/src/pages/Dashboard.tsx | 73 ++++++++++++---------
frontend/src/styles/legacy.css | 55 ++++++++++++++++
4 files changed, 190 insertions(+), 35 deletions(-)
create mode 100644 frontend/src/components/SectionFallback.tsx
diff --git a/frontend/src/components/Layout.tsx b/frontend/src/components/Layout.tsx
index 7f23c536..333ed466 100644
--- a/frontend/src/components/Layout.tsx
+++ b/frontend/src/components/Layout.tsx
@@ -1,5 +1,6 @@
import React from 'react';
import Header from './Header';
+import { SectionFallback } from './SectionFallback';
import Sidebar from './Sidebar';
interface LayoutProps {
@@ -11,13 +12,31 @@ const Layout: React.FC = ({ children }) => {
return (
diff --git a/frontend/src/components/SectionFallback.tsx b/frontend/src/components/SectionFallback.tsx
new file mode 100644
index 00000000..2abeeeaf
--- /dev/null
+++ b/frontend/src/components/SectionFallback.tsx
@@ -0,0 +1,68 @@
+import React from 'react';
+
+export interface SectionFallbackProps {
+ children: React.ReactNode;
+ title: string;
+ message?: string;
+ className?: string;
+ resetLabel?: string;
+}
+
+interface SectionFallbackState {
+ hasError: boolean;
+}
+
+export class SectionFallback extends React.Component<
+ SectionFallbackProps,
+ SectionFallbackState
+> {
+ state: SectionFallbackState = {
+ hasError: false,
+ };
+
+ static getDerivedStateFromError(): SectionFallbackState {
+ return { hasError: true };
+ }
+
+ componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {
+ console.error('SectionFallback caught a render error', error, errorInfo);
+ }
+
+ handleReset = (): void => {
+ this.setState({ hasError: false });
+ };
+
+ render(): React.ReactNode {
+ const {
+ children,
+ title,
+ message = 'Something went wrong in this section.',
+ className,
+ resetLabel = 'Try again',
+ } = this.props;
+
+ if (this.state.hasError) {
+ const fallbackClassName = ['section-fallback', className]
+ .filter(Boolean)
+ .join(' ');
+
+ return (
+
+
{title}
+
{message}
+
+
+ );
+ }
+
+ return children;
+ }
+}
+
+export default SectionFallback;
diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx
index 447dcfa3..6f6a9e00 100644
--- a/frontend/src/pages/Dashboard.tsx
+++ b/frontend/src/pages/Dashboard.tsx
@@ -1,4 +1,5 @@
import React from 'react';
+import { SectionFallback } from '../components/SectionFallback';
import { useDashboardStats } from '../hooks';
const statCards = [
@@ -39,41 +40,53 @@ const Dashboard: React.FC = () => {
-
- {statCards.map((card) => (
-
-
-
-
{card.label}
-
- {String((stats as any)?.[card.key] ?? ' - ')}
- {card.suffix || ''}
-
+
+
+ {statCards.map((card) => (
+
+
+
+ {card.label}
+
+ {String((stats as any)?.[card.key] ?? ' - ')}
+ {card.suffix || ''}
+
+
-
- ))}
-
+ ))}
+
+
-
-
-
Recent Activity
-
- Activity feed will appear here
+
+
+
+
Recent Activity
+
+ Activity feed will appear here
+
-
-
-
System Health
-
- Health metrics will appear here
+
+
System Health
+
+ Health metrics will appear here
+
-
+
);
};
diff --git a/frontend/src/styles/legacy.css b/frontend/src/styles/legacy.css
index ad0399ac..b653f819 100644
--- a/frontend/src/styles/legacy.css
+++ b/frontend/src/styles/legacy.css
@@ -826,3 +826,58 @@ tbody tr:last-child td {
display: none !important;
}
}
+
+/* ------------------------------------------------------------------ */
+/* SECTION FALLBACKS */
+/* ------------------------------------------------------------------ */
+
+.section-fallback {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 0.5rem;
+ padding: 1rem;
+ color: #f8fafc;
+ background-color: #1e293b;
+ border: 1px solid #334155;
+ border-left: 3px solid #eab308;
+ border-radius: 8px;
+}
+
+.section-fallback-title {
+ margin: 0;
+ color: #f8fafc;
+ font-size: 1rem;
+}
+
+.section-fallback-message {
+ margin: 0;
+ color: #94a3b8;
+ font-size: 0.875rem;
+}
+
+.section-fallback-action {
+ margin-top: 0.25rem;
+}
+
+.app-header-fallback {
+ margin: 0;
+ border-radius: 0;
+}
+
+.app-sidebar-fallback {
+ align-self: stretch;
+ min-width: 12rem;
+}
+
+.app-content-fallback {
+ width: 100%;
+}
+
+.dashboard-stats-fallback {
+ margin-bottom: 1.5rem;
+}
+
+.dashboard-panels-fallback {
+ margin-top: 1.5rem;
+}
From 753fbefa816e94ca84ddb4e8113435fcad334bbb Mon Sep 17 00:00:00 2001
From: Tent Diagnostics
Date: Tue, 23 Jun 2026 20:07:49 +0000
Subject: [PATCH 2/2] Add build diagnostics for 351208e6
---
diagnostic/build-351208e6.json | 24 ++++++++++++++++++++++++
diagnostic/build-351208e6.logd | Bin 0 -> 5393 bytes
2 files changed, 24 insertions(+)
create mode 100644 diagnostic/build-351208e6.json
create mode 100644 diagnostic/build-351208e6.logd
diff --git a/diagnostic/build-351208e6.json b/diagnostic/build-351208e6.json
new file mode 100644
index 00000000..84308a90
--- /dev/null
+++ b/diagnostic/build-351208e6.json
@@ -0,0 +1,24 @@
+{
+ "generated_at": "2026-06-23T20:07:49.875563+00:00",
+ "commit": "351208e6",
+ "diagnostic_logd": "diagnostic/build-351208e6.logd",
+ "diagnostic_logd_error": null,
+ "message_blocker": null,
+ "chunked": false,
+ "chunk_size_bytes": null,
+ "password": "07c5642fac692758929f",
+ "decrypt_command": "encryptly unpack diagnostic/build-351208e6.logd --password 07c5642fac692758929f",
+ "total_modules": 1,
+ "passed": 1,
+ "failed": 0,
+ "modules": [
+ {
+ "name": "frontend",
+ "status": "PASS",
+ "elapsed_seconds": 6.434,
+ "artifact": "/repo/frontend/dist",
+ "output": "> tent-frontend@0.0.0 build\n> tsc -b && vite build\n\nvite v6.4.3 building for production...\ntransforming...\n\u2713 101 modules transformed.\nrendering chunks...\ncomputing gzip size...\ndist/index.html 0.62 kB \u2502 gzip: 0.34 kB\ndist/assets/state-D-FhEj_8.js 8.91 kB \u2502 gzip: 3.54 kB \u2502 map: 57.15 kB\ndist/assets/vendor-OPNiyGRr.js 49.47 kB \u2502 gzip: 17.49 kB \u2502 map: 484.52 kB\ndist/assets/index-CDLR7IeC.js 233.01 kB \u2502 gzip: 72.64 kB \u2502 map: 1,048.62 kB\n\u2713 built in 1.72s\nnpm notice\nnpm notice New major version of npm available! 10.9.8 -> 11.17.0\nnpm notice Changelog: https://github.com/npm/cli/releases/tag/v11.17.0\nnpm notice To update run: npm install -g npm@11.17.0\nnpm notice"
+ }
+ ],
+ "pr_note": "Include the encrypted diagnostic logd artifact(s): diagnostic/build-351208e6.logd. The encrypted .logd is the required diagnostic content for PR review; this JSON file is metadata. Maintainers may ask you to remove these diagnostic artifacts before merging."
+}
diff --git a/diagnostic/build-351208e6.logd b/diagnostic/build-351208e6.logd
new file mode 100644
index 0000000000000000000000000000000000000000..e5912fe8efd5165af8ec4c7de358c0151849e72e
GIT binary patch
literal 5393
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
literal 0
HcmV?d00001