PatchList.tsx
Raw
1import type { PatchRow, RepositoryRow } from "../../db/index.ts";
2import { formatDate } from "../../lib/formatDate.ts";
3import { displayName } from "../../lib/users.ts";
4import type { SessionUser } from "../../middleware/session.ts";
5import { Avatar } from "../Avatar.tsx";
6import { Layout } from "../layout.tsx";
7import { Pagination, type PaginationInfo } from "../Pagination.tsx";
8import { RepoHeader } from "../repos/RepoHeader.tsx";
9import { RepoNav } from "../repos/RepoNav.tsx";
10
11interface PatchListProps {
12 user: SessionUser | null;
13 repo: RepositoryRow;
14 patches: (PatchRow & {
15 author_username: string;
16 author_avatar_version: number | null;
17 })[];
18 status: string;
19 counts: Record<string, number>;
20 pagination: PaginationInfo;
21}
22
23export function PatchList({
24 user,
25 repo,
26 patches,
27 status,
28 counts,
29 pagination,
30}: PatchListProps) {
31 return (
32 <Layout user={user} title={`Patches — ${repo.name}`}>
33 <div class="container">
34 <RepoHeader repo={repo} />
35 <RepoNav repo={repo} active="patches" user={user} />
36 <div class="list-header">
37 <div class="list-header-tabs">
38 <a
39 href={`/${repo.name}/patches?status=open`}
40 class={`list-tab${status === "open" ? " active" : ""}`}
41 >
42 Open{" "}
43 {(counts.open ?? 0) > 0 && (
44 <span class="tab-count">{counts.open}</span>
45 )}
46 </a>
47 <a
48 href={`/${repo.name}/patches?status=merged`}
49 class={`list-tab${status === "merged" ? " active" : ""}`}
50 >
51 Merged{" "}
52 {(counts.merged ?? 0) > 0 && (
53 <span class="tab-count">{counts.merged}</span>
54 )}
55 </a>
56 <a
57 href={`/${repo.name}/patches?status=closed`}
58 class={`list-tab${status === "closed" ? " active" : ""}`}
59 >
60 Closed{" "}
61 {(counts.closed ?? 0) > 0 && (
62 <span class="tab-count">{counts.closed}</span>
63 )}
64 </a>
65 </div>
66 {user && (
67 <a
68 href={`/${repo.name}/patches/new`}
69 class="btn btn-primary btn-sm"
70 >
71 Upload patch
72 </a>
73 )}
74 </div>
75 {patches.length === 0 ? (
76 <div class="empty-state">
77 <p>No {status} patches.</p>
78 </div>
79 ) : (
80 <ul class="issue-list">
81 {patches.map((patch) => (
82 <li class="issue-item">
83 <div class="issue-main">
84 <span
85 class={`patch-status-dot ${patch.status}`}
86 />
87 <a
88 href={`/${repo.name}/patches/${patch.number}`}
89 class="issue-title"
90 >
91 {patch.title}
92 </a>
93 <span class="issue-number">
94 #{patch.number}
95 </span>
96 </div>
97 <div class="issue-meta">
98 <Avatar
99 userId={patch.author_id}
100 version={patch.author_avatar_version}
101 size={20}
102 />
103 <span>
104 by {displayName(patch.author_username)}
105 </span>
106 <time datetime={patch.created_at}>
107 {formatDate(patch.created_at)}
108 </time>
109 </div>
110 </li>
111 ))}
112 </ul>
113 )}
114 <Pagination {...pagination} />
115 </div>
116 </Layout>
117 );
118}
119