diff --git a/webui2/src/components/bugs/Timeline.tsx b/webui2/src/components/bugs/Timeline.tsx index 7a10da2469f98a5e4ba44aaf6dc25d88714faa3b..403f1f0aa978522cc9e0fb1595ea9dcd72e275b4 100644 --- a/webui2/src/components/bugs/Timeline.tsx +++ b/webui2/src/components/bugs/Timeline.tsx @@ -14,7 +14,6 @@ import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Button } from "@/components/ui/button"; import { Textarea } from "@/components/ui/textarea"; import { useAuth } from "@/lib/auth"; -import { useRepo } from "@/lib/repo"; import { LabelBadge } from "./LabelBadge"; @@ -23,6 +22,7 @@ type TimelineNode = NonNullable< >; interface TimelineProps { + repo: string | null; bugPrefix: string; items: TimelineNode[]; } @@ -30,20 +30,20 @@ interface TimelineProps { // Ordered sequence of events on a bug: comments (create and add-comment) and // inline events (label changes, status changes, title edits). Comment items // support inline editing for the logged-in user. -export function Timeline({ bugPrefix, items }: TimelineProps) { +export function Timeline({ repo, bugPrefix, items }: TimelineProps) { return (
{items.map((item) => { switch (item.__typename) { case "BugCreateTimelineItem": case "BugAddCommentTimelineItem": - return ; + return ; case "BugLabelChangeTimelineItem": - return ; + return ; case "BugSetStatusTimelineItem": - return ; + return ; case "BugSetTitleTimelineItem": - return ; + return ; default: return null; } @@ -59,9 +59,16 @@ type CommentItem = Extract< { __typename: "BugCreateTimelineItem" | "BugAddCommentTimelineItem" } >; -function CommentItem({ item, bugPrefix }: { item: CommentItem; bugPrefix: string }) { +function CommentItem({ + item, + bugPrefix, + repo, +}: { + item: CommentItem; + bugPrefix: string; + repo: string | null; +}) { const { user } = useAuth(); - const repo = useRepo(); const [editing, setEditing] = useState(false); const [editValue, setEditValue] = useState(item.message ?? ""); @@ -172,8 +179,7 @@ function EventRow({ icon, children }: { icon: React.ReactNode; children: React.R ); } -function LabelChangeItem({ item }: { item: LabelChangeItem }) { - const repo = useRepo(); +function LabelChangeItem({ item, repo }: { item: LabelChangeItem; repo: string | null }) { return ( }> @@ -206,8 +212,7 @@ function LabelChangeItem({ item }: { item: LabelChangeItem }) { ); } -function StatusChangeItem({ item }: { item: StatusChangeItem }) { - const repo = useRepo(); +function StatusChangeItem({ item, repo }: { item: StatusChangeItem; repo: string | null }) { const isOpen = item.status === Status.Open; return ( }> diff --git a/webui2/src/components/code/CommitList.tsx b/webui2/src/components/code/CommitList.tsx index 9e87fee884b3450d317f8c02456e6cb6da1caff6..3b0bec3fff3b05ca4a17ce9b1135f13b8aefac0b 100644 --- a/webui2/src/components/code/CommitList.tsx +++ b/webui2/src/components/code/CommitList.tsx @@ -10,7 +10,6 @@ import { useEffect, useState } from "react"; import { Button } from "@/components/ui/button"; import { Skeleton } from "@/components/ui/skeleton"; -import { useRepo } from "@/lib/repo"; const COMMITS_QUERY = gql` query CommitList($repo: String, $ref: String!, $path: String, $after: String, $first: Int) { @@ -44,6 +43,7 @@ interface CommitListQueryData { } interface CommitListProps { + repo: string | null; ref_: string; path?: string; } @@ -56,8 +56,7 @@ type CommitNode = { date: string; }; -export function CommitList({ ref_, path }: CommitListProps) { - const repo = useRepo(); +export function CommitList({ repo, ref_, path }: CommitListProps) { const [cursor, setCursor] = useState(null); const [allCommits, setAllCommits] = useState([]); diff --git a/webui2/src/components/code/FileDiffView.tsx b/webui2/src/components/code/FileDiffView.tsx index b1f88e2f1957af5df85a9721756e45309a532834..086b903fbd60774ba825469482ec50b016a2dd08 100644 --- a/webui2/src/components/code/FileDiffView.tsx +++ b/webui2/src/components/code/FileDiffView.tsx @@ -6,7 +6,6 @@ import { useLazyQuery } from "@apollo/client/react"; import { ChevronRight, FilePlus, FileMinus, FileEdit } from "lucide-react"; import { useState } from "react"; -import { useRepo } from "@/lib/repo"; import { cn } from "@/lib/utils"; const DIFF_QUERY = gql` @@ -53,6 +52,7 @@ interface DiffQueryData { } interface FileDiffViewProps { + repo: string | null; hash: string; path: string; oldPath?: string; @@ -72,8 +72,7 @@ const statusBadge: Record = { RENAMED: "R", }; -export function FileDiffView({ hash, path, oldPath, status }: FileDiffViewProps) { - const repo = useRepo(); +export function FileDiffView({ repo, hash, path, oldPath, status }: FileDiffViewProps) { const [open, setOpen] = useState(false); const [fetchDiff, { data, loading, error }] = useLazyQuery(DIFF_QUERY); diff --git a/webui2/src/components/code/FileTree.tsx b/webui2/src/components/code/FileTree.tsx index fa5daa21c53a538c33f8a3a403080f844d3eafcf..2d28742a8ca0189234e4c94b023f84a010ca71d7 100644 --- a/webui2/src/components/code/FileTree.tsx +++ b/webui2/src/components/code/FileTree.tsx @@ -4,7 +4,6 @@ import { Folder, File } from "lucide-react"; import { GitObjectType, type GitTreeEntry } from "@/__generated__/graphql"; import { Skeleton } from "@/components/ui/skeleton"; -import { useRepo } from "@/lib/repo"; export interface TreeEntryWithCommit extends GitTreeEntry { lastCommit?: { @@ -16,6 +15,7 @@ export interface TreeEntryWithCommit extends GitTreeEntry { } interface FileTreeProps { + repo: string | null; entries: TreeEntryWithCommit[]; path: string; loading?: boolean; @@ -25,7 +25,14 @@ interface FileTreeProps { // Directory listing table for the code browser. Shows each entry's icon, // name, last-commit message (linked to commit detail), and relative date. -export function FileTree({ entries, path, loading, onNavigate, onNavigateUp }: FileTreeProps) { +export function FileTree({ + repo, + entries, + path, + loading, + onNavigate, + onNavigateUp, +}: FileTreeProps) { // Directories first, then files — each group alphabetical const sorted = entries.toSorted((a, b) => { if (a.type !== b.type) return a.type === GitObjectType.Tree ? -1 : 1; @@ -49,7 +56,7 @@ export function FileTree({ entries, path, loading, onNavigate, onNavigateUp }: F )} {sorted.map((entry) => ( - + ))} @@ -59,13 +66,14 @@ export function FileTree({ entries, path, loading, onNavigate, onNavigateUp }: F function FileTreeRow({ entry, + repo, onNavigate, }: { entry: TreeEntryWithCommit; + repo: string | null; onNavigate: (entry: TreeEntryWithCommit) => void; }) { const isDir = entry.type === GitObjectType.Tree; - const repo = useRepo(); return ( onNavigate(entry)}> diff --git a/webui2/src/lib/repo.tsx b/webui2/src/lib/repo.tsx deleted file mode 100644 index 78c995331ff0f8c685d6b1a48b0febb03b078bff..0000000000000000000000000000000000000000 --- a/webui2/src/lib/repo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -// Returns the resolved repo ref from the router context. -// Returns null when rendered outside of a /$repo route (e.g. the picker page). -// -// The $repo route's beforeLoad normalizes the slug ("_" → null) and provides -// it as context.ref, so callers don't need to handle the "_" case. - -import { useRouteContext } from "@tanstack/react-router"; - -export function useRepo(): string | null { - const context = useRouteContext({ strict: false }); - return (context as { ref?: string | null }).ref ?? null; -} diff --git a/webui2/src/routes/$repo/commit/$hash.tsx b/webui2/src/routes/$repo/commit/$hash.tsx index 930c26411b760c5048ee147a5ae5209d72adc270..1f76a9732c52d294f4562c921647d628cadca12d 100644 --- a/webui2/src/routes/$repo/commit/$hash.tsx +++ b/webui2/src/routes/$repo/commit/$hash.tsx @@ -9,7 +9,6 @@ import { ArrowLeft, GitCommit } from "lucide-react"; import { FileDiffView } from "@/components/code/FileDiffView"; import { Skeleton } from "@/components/ui/skeleton"; -import { useRepo } from "@/lib/repo"; const COMMIT_QUERY = gql` query CommitPageDetail($repo: String, $hash: String!) { @@ -65,7 +64,7 @@ export const Route = createFileRoute("/$repo/commit/$hash")({ }); function RouteComponent() { - const repo = useRepo(); + const { ref: repo } = Route.useRouteContext(); const { commitRef } = Route.useLoaderData(); const { data } = useReadQuery(commitRef); @@ -137,6 +136,7 @@ function RouteComponent() { {files.map((file: { path: string; oldPath?: string | null; status: string }) => ( {viewMode === "commits" ? ( - + ) : viewMode === "tree" || !blob ? ( <> {/* Timeline + comment box */}
- +
diff --git a/webui2/src/routes/$repo/issues/index.tsx b/webui2/src/routes/$repo/issues/index.tsx index b8a941b2433ecbc95a861b9c3dce4652d30e363c..309c05eed7bb161937120ea8d94fe373f0e70028 100644 --- a/webui2/src/routes/$repo/issues/index.tsx +++ b/webui2/src/routes/$repo/issues/index.tsx @@ -12,7 +12,6 @@ import { QueryInput } from "@/components/bugs/QueryInput"; import { Button } from "@/components/ui/button"; import { ButtonLink } from "@/components/ui/button-link"; import { Skeleton } from "@/components/ui/skeleton"; -import { useRepo } from "@/lib/repo"; import { cn } from "@/lib/utils"; const issuesSearchSchema = v.object({ @@ -47,7 +46,7 @@ const PAGE_SIZE = 25; type StatusFilter = "open" | "closed"; function RouteComponent() { - const repo = useRepo(); + const { ref: repo } = Route.useRouteContext(); const navigate = useNavigate({ from: "/$repo/issues/" }); const { q, after } = Route.useSearch(); diff --git a/webui2/src/routes/$repo/issues/new.tsx b/webui2/src/routes/$repo/issues/new.tsx index d703048fc4b1244e5737ce4d1bffd29d142f1fcf..3bc47e6a4a6027b7b119a9888ea2fea24dbcd844 100644 --- a/webui2/src/routes/$repo/issues/new.tsx +++ b/webui2/src/routes/$repo/issues/new.tsx @@ -8,7 +8,6 @@ import { Button } from "@/components/ui/button"; import { ButtonLink } from "@/components/ui/button-link"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; -import { useRepo } from "@/lib/repo"; export const Route = createFileRoute("/$repo/issues/new")({ component: RouteComponent, @@ -17,7 +16,7 @@ export const Route = createFileRoute("/$repo/issues/new")({ // New issue form (/:repo/issues/new). Title + body with write/preview tabs. function RouteComponent() { const navigate = useNavigate(); - const repo = useRepo(); + const { ref: repo } = Route.useRouteContext(); const [title, setTitle] = useState(""); const [message, setMessage] = useState(""); const [preview, setPreview] = useState(false); diff --git a/webui2/src/routes/$repo/user/$id.tsx b/webui2/src/routes/$repo/user/$id.tsx index d5caba926773d664a84440cc16a274bc36d6841d..3a2c1c55520860229c4ab570d164e6afa38d4277 100644 --- a/webui2/src/routes/$repo/user/$id.tsx +++ b/webui2/src/routes/$repo/user/$id.tsx @@ -24,7 +24,6 @@ import { LabelBadge } from "@/components/bugs/LabelBadge"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Button } from "@/components/ui/button"; import { Skeleton } from "@/components/ui/skeleton"; -import { useRepo } from "@/lib/repo"; import { cn } from "@/lib/utils"; export const Route = createFileRoute("/$repo/user/$id")({ @@ -35,7 +34,7 @@ const PAGE_SIZE = 25; function RouteComponent() { const { id } = useParams({ strict: false }); - const repo = useRepo(); + const { ref: repo } = Route.useRouteContext(); const [statusFilter, setStatusFilter] = useState<"open" | "closed">("open"); // Cursor-stack pagination: cursors[i] is the `after` value to fetch page i.