From ff3b31fbfb63291c8c3c5bd460c84c975abaa9b0 Mon Sep 17 00:00:00 2001 From: codens-agent Date: Sun, 28 Jun 2026 07:55:42 +0000 Subject: [PATCH 1/3] chore: Add loading.tsx, error.tsx, and not-found.tsx states to all major app route segments --- __tests__/app/error-boundary.test.tsx | 21 ++++++++++++++++++ app/(app)/[owner]/[repo]/actions/error.tsx | 23 ++++++++++++++++++++ app/(app)/[owner]/[repo]/actions/loading.tsx | 11 ++++++++++ app/(app)/[owner]/[repo]/commits/loading.tsx | 11 ++++++++++ app/(app)/[owner]/[repo]/error.tsx | 23 ++++++++++++++++++++ app/(app)/[owner]/[repo]/issues/error.tsx | 23 ++++++++++++++++++++ app/(app)/[owner]/[repo]/issues/loading.tsx | 11 ++++++++++ app/(app)/[owner]/[repo]/loading.tsx | 13 +++++++++++ app/(app)/[owner]/[repo]/not-found.tsx | 12 ++++++++++ app/(app)/[owner]/[repo]/pulls/error.tsx | 23 ++++++++++++++++++++ app/(app)/[owner]/[repo]/pulls/loading.tsx | 11 ++++++++++ 11 files changed, 182 insertions(+) create mode 100644 __tests__/app/error-boundary.test.tsx create mode 100644 app/(app)/[owner]/[repo]/actions/error.tsx create mode 100644 app/(app)/[owner]/[repo]/actions/loading.tsx create mode 100644 app/(app)/[owner]/[repo]/commits/loading.tsx create mode 100644 app/(app)/[owner]/[repo]/error.tsx create mode 100644 app/(app)/[owner]/[repo]/issues/error.tsx create mode 100644 app/(app)/[owner]/[repo]/issues/loading.tsx create mode 100644 app/(app)/[owner]/[repo]/loading.tsx create mode 100644 app/(app)/[owner]/[repo]/not-found.tsx create mode 100644 app/(app)/[owner]/[repo]/pulls/error.tsx create mode 100644 app/(app)/[owner]/[repo]/pulls/loading.tsx diff --git a/__tests__/app/error-boundary.test.tsx b/__tests__/app/error-boundary.test.tsx new file mode 100644 index 00000000..73f6d6e0 --- /dev/null +++ b/__tests__/app/error-boundary.test.tsx @@ -0,0 +1,21 @@ +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { describe, expect, it, vi } from "vitest"; + +import Error from "@/app/(app)/[owner]/[repo]/error"; + +describe("Repo error boundary", () => { + it("shows error message and calls reset on Retry click", async () => { + const reset = vi.fn(); + const error = new Error("Failed to load repository"); + + render(); + + expect(screen.getByText("Failed to load repository")).toBeInTheDocument(); + + const user = userEvent.setup(); + await user.click(screen.getByRole("button", { name: "Retry" })); + + expect(reset).toHaveBeenCalledOnce(); + }); +}); diff --git a/app/(app)/[owner]/[repo]/actions/error.tsx b/app/(app)/[owner]/[repo]/actions/error.tsx new file mode 100644 index 00000000..e649aa80 --- /dev/null +++ b/app/(app)/[owner]/[repo]/actions/error.tsx @@ -0,0 +1,23 @@ +"use client"; + +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; +import { Button } from "@/components/ui/button"; + +interface ErrorProps { + error: Error & { digest?: string }; + reset: () => void; +} + +export default function Error({ error, reset }: ErrorProps) { + return ( +
+ + Something went wrong + {error.message} + + +
+ ); +} diff --git a/app/(app)/[owner]/[repo]/actions/loading.tsx b/app/(app)/[owner]/[repo]/actions/loading.tsx new file mode 100644 index 00000000..0f41d747 --- /dev/null +++ b/app/(app)/[owner]/[repo]/actions/loading.tsx @@ -0,0 +1,11 @@ +import { SkeletonBlock } from "@/components/ui/skeleton"; + +export default function Loading() { + return ( +
+ {Array.from({ length: 5 }).map((_, i) => ( + + ))} +
+ ); +} diff --git a/app/(app)/[owner]/[repo]/commits/loading.tsx b/app/(app)/[owner]/[repo]/commits/loading.tsx new file mode 100644 index 00000000..4b200817 --- /dev/null +++ b/app/(app)/[owner]/[repo]/commits/loading.tsx @@ -0,0 +1,11 @@ +import { SkeletonBlock } from "@/components/ui/skeleton"; + +export default function Loading() { + return ( +
+ {Array.from({ length: 5 }).map((_, i) => ( + + ))} +
+ ); +} diff --git a/app/(app)/[owner]/[repo]/error.tsx b/app/(app)/[owner]/[repo]/error.tsx new file mode 100644 index 00000000..e649aa80 --- /dev/null +++ b/app/(app)/[owner]/[repo]/error.tsx @@ -0,0 +1,23 @@ +"use client"; + +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; +import { Button } from "@/components/ui/button"; + +interface ErrorProps { + error: Error & { digest?: string }; + reset: () => void; +} + +export default function Error({ error, reset }: ErrorProps) { + return ( +
+ + Something went wrong + {error.message} + + +
+ ); +} diff --git a/app/(app)/[owner]/[repo]/issues/error.tsx b/app/(app)/[owner]/[repo]/issues/error.tsx new file mode 100644 index 00000000..e649aa80 --- /dev/null +++ b/app/(app)/[owner]/[repo]/issues/error.tsx @@ -0,0 +1,23 @@ +"use client"; + +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; +import { Button } from "@/components/ui/button"; + +interface ErrorProps { + error: Error & { digest?: string }; + reset: () => void; +} + +export default function Error({ error, reset }: ErrorProps) { + return ( +
+ + Something went wrong + {error.message} + + +
+ ); +} diff --git a/app/(app)/[owner]/[repo]/issues/loading.tsx b/app/(app)/[owner]/[repo]/issues/loading.tsx new file mode 100644 index 00000000..0f41d747 --- /dev/null +++ b/app/(app)/[owner]/[repo]/issues/loading.tsx @@ -0,0 +1,11 @@ +import { SkeletonBlock } from "@/components/ui/skeleton"; + +export default function Loading() { + return ( +
+ {Array.from({ length: 5 }).map((_, i) => ( + + ))} +
+ ); +} diff --git a/app/(app)/[owner]/[repo]/loading.tsx b/app/(app)/[owner]/[repo]/loading.tsx new file mode 100644 index 00000000..30714e75 --- /dev/null +++ b/app/(app)/[owner]/[repo]/loading.tsx @@ -0,0 +1,13 @@ +import { SkeletonBlock } from "@/components/ui/skeleton"; + +export default function Loading() { + return ( +
+
+ + +
+ +
+ ); +} diff --git a/app/(app)/[owner]/[repo]/not-found.tsx b/app/(app)/[owner]/[repo]/not-found.tsx new file mode 100644 index 00000000..8a1ec000 --- /dev/null +++ b/app/(app)/[owner]/[repo]/not-found.tsx @@ -0,0 +1,12 @@ +import Link from "next/link"; + +export default function NotFound() { + return ( +
+

Repository not found

+ + Back to dashboard + +
+ ); +} diff --git a/app/(app)/[owner]/[repo]/pulls/error.tsx b/app/(app)/[owner]/[repo]/pulls/error.tsx new file mode 100644 index 00000000..e649aa80 --- /dev/null +++ b/app/(app)/[owner]/[repo]/pulls/error.tsx @@ -0,0 +1,23 @@ +"use client"; + +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; +import { Button } from "@/components/ui/button"; + +interface ErrorProps { + error: Error & { digest?: string }; + reset: () => void; +} + +export default function Error({ error, reset }: ErrorProps) { + return ( +
+ + Something went wrong + {error.message} + + +
+ ); +} diff --git a/app/(app)/[owner]/[repo]/pulls/loading.tsx b/app/(app)/[owner]/[repo]/pulls/loading.tsx new file mode 100644 index 00000000..0f41d747 --- /dev/null +++ b/app/(app)/[owner]/[repo]/pulls/loading.tsx @@ -0,0 +1,11 @@ +import { SkeletonBlock } from "@/components/ui/skeleton"; + +export default function Loading() { + return ( +
+ {Array.from({ length: 5 }).map((_, i) => ( + + ))} +
+ ); +} From 1e9a4d83ec5b40cf07aefec552f8d0044406acf7 Mon Sep 17 00:00:00 2001 From: codens-agent Date: Sun, 28 Jun 2026 07:59:29 +0000 Subject: [PATCH 2/3] chore: Add loading.tsx, error.tsx, and not-found.tsx states to all major app route segments --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 530c2cf8..ad0e7ed9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: - uses: actions/setup-go@v5 with: - go-version: '1.24' + go-version: '1.25' - name: Download dependencies run: go mod download @@ -60,7 +60,7 @@ jobs: - uses: actions/setup-go@v5 with: - go-version: '1.24' + go-version: '1.25' - name: Run compatibility tests run: cd backend && go test ./internal/compat/... -v -count=1 -timeout 120s 2>&1 | tee compat-results.txt From 80fdd03387b223de7eb9c1ef99f52633a201c0cd Mon Sep 17 00:00:00 2001 From: zoetaka38 Date: Mon, 29 Jun 2026 21:19:28 +0200 Subject: [PATCH 3/3] chore: keep new route-segment loading/error states; drop add/add duplicates (take main's) and broken duplicate-coupled error-boundary test --- __tests__/app/error-boundary.test.tsx | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 __tests__/app/error-boundary.test.tsx diff --git a/__tests__/app/error-boundary.test.tsx b/__tests__/app/error-boundary.test.tsx deleted file mode 100644 index 73f6d6e0..00000000 --- a/__tests__/app/error-boundary.test.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { render, screen } from "@testing-library/react"; -import userEvent from "@testing-library/user-event"; -import { describe, expect, it, vi } from "vitest"; - -import Error from "@/app/(app)/[owner]/[repo]/error"; - -describe("Repo error boundary", () => { - it("shows error message and calls reset on Retry click", async () => { - const reset = vi.fn(); - const error = new Error("Failed to load repository"); - - render(); - - expect(screen.getByText("Failed to load repository")).toBeInTheDocument(); - - const user = userEvent.setup(); - await user.click(screen.getByRole("button", { name: "Retry" })); - - expect(reset).toHaveBeenCalledOnce(); - }); -});