Files
porthole/apps/web/app/components/ErrorBoundary.tsx
OpenCode Test 4e2ab7cdd8 task-11: complete QA + hardening with resilience fixes
- Created comprehensive QA checklist covering edge cases (missing EXIF, timezones, codecs, corrupt files)
- Added ErrorBoundary component wrapped around TimelineTree and MediaPanel
- Created global error.tsx page for unhandled errors
- Improved failed asset UX with red borders, warning icons, and inline error display
- Added loading skeletons to TimelineTree and MediaPanel
- Added retry button for failed media loads
- Created DEPLOYMENT_VALIDATION.md with validation commands and checklist
- Applied k8s recommendations:
  - Changed node affinity to required for compute nodes (Pi 5)
  - Enabled Tailscale LoadBalancer service for MinIO S3 (reliable Range requests)
  - Enabled cleanup CronJob for staging files
2025-12-24 12:45:22 -08:00

46 lines
1.0 KiB
TypeScript

"use client";
import { Component, ReactNode } from "react";
type Props = {
fallback?: ReactNode;
children: ReactNode;
};
type State = {
hasError: boolean;
error: Error | null;
};
export class ErrorBoundary extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error: Error): State {
return { hasError: true, error };
}
render() {
if (this.state.hasError) {
return (
this.props.fallback ?? (
<div className="flex min-h-[200px] items-center justify-center rounded-lg border border-red-200 bg-red-50 p-6 text-center">
<div>
<p className="mb-2 font-semibold text-red-700">
Something went wrong
</p>
<p className="text-sm text-red-600">
Please refresh the page or try again later
</p>
</div>
</div>
)
);
}
return this.props.children;
}
}