web/app/%5Bowner%5D/%5Brepo%5D/(tabs)/diffs/page.tsxblame
View source
d12933e1import type { Metadata } from "next";
d12933e2import Link from "next/link";
d12933e3import { timeAgoFromDate, groveApiUrl } from "@/lib/utils";
d12933e4
d12933e5interface Props {
d12933e6 params: Promise<{ owner: string; repo: string }>;
d12933e7 searchParams: Promise<{ status?: string }>;
d12933e8}
d12933e9
d12933e10export async function generateMetadata({ params }: Props): Promise<Metadata> {
d12933e11 const { repo } = await params;
d12933e12 return { title: `Diffs · ${repo}` };
d12933e13}
d12933e14
d12933e15async function getDiffs(owner: string, repo: string, status: string) {
d12933e16 try {
d12933e17 const res = await fetch(
d12933e18 `${groveApiUrl}/api/repos/${owner}/${repo}/diffs?status=${status}`,
d12933e19 { cache: "no-store" }
d12933e20 );
d12933e21 if (!res.ok) return null;
d12933e22 return res.json();
d12933e23 } catch {
d12933e24 return null;
d12933e25 }
d12933e26}
d12933e27
d12933e28const statusStyles: Record<string, { bg: string; text: string; border: string }> = {
d12933e29 open: { bg: "var(--status-open-bg)", text: "var(--status-open-text)", border: "var(--status-open-border)" },
2ec686830 landed: { bg: "var(--status-merged-bg)", text: "var(--status-merged-text)", border: "var(--status-merged-border)" },
d12933e31 closed: { bg: "var(--status-closed-bg)", text: "var(--status-closed-text)", border: "var(--status-closed-border)" },
d12933e32};
d12933e33
d12933e34export default async function DiffsPage({
d12933e35 params,
d12933e36 searchParams,
d12933e37}: Props) {
d12933e38 const { owner, repo } = await params;
d12933e39 const { status: statusParam } = await searchParams;
d12933e40 const status = statusParam ?? "open";
d12933e41
d12933e42 const data = await getDiffs(owner, repo, status);
d12933e43
d12933e44 return (
d12933e45 <>
d12933e46 <div className="flex items-center justify-between mb-4">
d12933e47 <div className="flex gap-4 text-sm">
2ec686848 {(["open", "landed", "closed"] as const).map((s) => (
d12933e49 <Link
d12933e50 key={s}
d12933e51 href={`/${owner}/${repo}/diffs?status=${s}`}
d12933e52 className="capitalize"
d12933e53 style={{
d12933e54 color: status === s ? "var(--text-primary)" : "var(--text-muted)",
d12933e55 fontWeight: status === s ? 600 : 400,
d12933e56 }}
d12933e57 >
d12933e58 {s}
d12933e59 </Link>
d12933e60 ))}
d12933e61 </div>
55e950162 <Link
55e950163 href={`/${owner}/${repo}/diffs/new`}
55e950164 className="text-sm px-3 py-1"
55e950165 style={{
55e950166 backgroundColor: "var(--accent)",
55e950167 color: "var(--accent-text)",
55e950168 }}
55e950169 >
55e950170 New diff
55e950171 </Link>
d12933e72 </div>
d12933e73
d12933e74 {data?.diffs?.length ? (
d12933e75 <div style={{ border: "1px solid var(--border-subtle)" }}>
d12933e76 <table className="w-full text-sm">
d12933e77 <tbody>
d12933e78 {data.diffs.map((d: any, i: number) => {
d12933e79 const style = statusStyles[d.status ?? status] ?? statusStyles.open;
d12933e80 return (
d12933e81 <tr
d12933e82 key={d.id}
d12933e83 className="hover-row"
d12933e84 style={{
d12933e85 borderTop:
d12933e86 i > 0 ? "1px solid var(--divide)" : undefined,
d12933e87 }}
d12933e88 >
d12933e89 <td className="py-2.5 pl-3 pr-3">
d12933e90 <div className="flex items-center gap-2">
d12933e91 <span
d12933e92 className="text-xs px-1.5 py-0.5 shrink-0"
d12933e93 style={{
d12933e94 backgroundColor: style.bg,
d12933e95 color: style.text,
d12933e96 border: `1px solid ${style.border}`,
d12933e97 }}
d12933e98 >
d12933e99 {d.status ?? status}
d12933e100 </span>
d12933e101 <Link
d12933e102 href={`/${owner}/${repo}/diffs/${d.number}`}
d12933e103 className="hover:underline truncate"
d12933e104 style={{ color: "var(--accent)" }}
d12933e105 >
d12933e106 {d.title}
d12933e107 </Link>
d12933e108 </div>
d12933e109 <div
d12933e110 className="text-xs mt-0.5 ml-0"
d12933e111 style={{ color: "var(--text-muted)" }}
d12933e112 >
d12933e113 D{d.number} by {d.author_name}
d12933e114 </div>
d12933e115 </td>
d12933e116 <td
2ec6868117 className="py-2 text-xs font-mono text-right w-28 hidden sm:table-cell"
d12933e118 style={{ color: "var(--text-faint)" }}
d12933e119 >
2ec6868120 {d.head_commit?.slice(0, 8)}
d12933e121 </td>
d12933e122 <td
d12933e123 className="py-2 pr-3 text-xs text-right w-20"
d12933e124 style={{ color: "var(--text-faint)" }}
d12933e125 >
d12933e126 {timeAgoFromDate(d.created_at)}
d12933e127 </td>
d12933e128 </tr>
d12933e129 );
d12933e130 })}
d12933e131 </tbody>
d12933e132 </table>
d12933e133 </div>
d12933e134 ) : (
d12933e135 <p className="text-sm py-8 text-center" style={{ color: "var(--text-faint)" }}>
d12933e136 No {status} diffs.
d12933e137 </p>
d12933e138 )}
d12933e139 </>
d12933e140 );
d12933e141}