Files
porthole/apps/web/app/page.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.1 KiB
TypeScript

"use client";
import Link from "next/link";
import { getAppName } from "@tline/config";
import { useState } from "react";
import { ErrorBoundary } from "./components/ErrorBoundary";
import { MediaPanel } from "./components/MediaPanel";
import { TimelineTree } from "./components/TimelineTree";
export default function HomePage() {
const [selectedDayIso, setSelectedDayIso] = useState<string | null>(null);
return (
<main style={{ padding: 16, display: "grid", gap: 16 }}>
<header>
<h1 style={{ marginTop: 0 }}>{getAppName()}</h1>
<ul>
<li>
<Link href="/admin">Admin</Link>
</li>
<li>
<a href="/api/healthz">API health</a>
</li>
</ul>
</header>
<div
style={{
display: "grid",
gridTemplateColumns: "2fr 1fr",
gap: 16,
alignItems: "start",
}}
>
<ErrorBoundary>
<TimelineTree onSelectDay={setSelectedDayIso} />
</ErrorBoundary>
<ErrorBoundary>
<MediaPanel selectedDayIso={selectedDayIso} />
</ErrorBoundary>
</div>
</main>
);
}