BranchList.tsx
Raw
1import type { RepositoryRow } from "../../db/index.ts";
2import { formatDateTime } from "../../lib/formatDate.ts";
3import type { SessionUser } from "../../middleware/session.ts";
4import type { BranchInfo } from "../../services/git.ts";
5import { MAX_BRANCH_NAME_LENGTH } from "../../constants.ts";
6import { Layout } from "../layout.tsx";
7import { Pagination } from "../Pagination.tsx";
8import { RepoHeader } from "./RepoHeader.tsx";
9import { RepoNav } from "./RepoNav.tsx";
10
11interface BranchListProps {
12 user: SessionUser | null;
13 repo: RepositoryRow;
14 branches: BranchInfo[];
15 page: number;
16 totalPages: number;
17 success?: string;
18 error?: string;
19}
20
21export function BranchList({
22 user,
23 repo,
24 branches,
25 page,
26 totalPages,
27 success,
28 error,
29}: BranchListProps) {
30 return (
31 <Layout user={user} title={`Branches — ${repo.name}`}>
32 <div class="container">
33 <RepoHeader repo={repo} />
34 <RepoNav repo={repo} active="branches" user={user} />
35 {success && <p class="form-success">{success}</p>}
36 {error && <p class="form-error">{error}</p>}
37 <div class="list-header">
38 <h2 class="list-heading">Branches</h2>
39 {user?.isAdmin && (
40 <details class="confirm-details">
41 <summary class="btn btn-primary btn-sm">
42 New branch
43 </summary>
44 <div class="confirm-popup confirm-popup-form">
45 <form
46 method="POST"
47 action={`/${repo.name}/branches/create`}
48 class="popup-form"
49 >
50 <div class="form-group">
51 <label for="new-branch-name">
52 Branch name
53 </label>
54 <input
55 id="new-branch-name"
56 name="name"
57 type="text"
58 required
59 placeholder="feature/my-branch"
60 maxlength={MAX_BRANCH_NAME_LENGTH}
61 />
62 </div>
63 <div class="form-group">
64 <label for="new-branch-source">
65 From
66 </label>
67 <input
68 id="new-branch-source"
69 name="source_ref"
70 type="text"
71 required
72 value={repo.default_branch}
73 placeholder="branch, tag, or commit"
74 maxlength={MAX_BRANCH_NAME_LENGTH}
75 />
76 </div>
77 <button
78 type="submit"
79 class="btn btn-primary btn-sm"
80 >
81 Create branch
82 </button>
83 </form>
84 </div>
85 </details>
86 )}
87 </div>
88 {branches.length === 0 ? (
89 <div class="empty-state">
90 <p>No branches yet.</p>
91 </div>
92 ) : (
93 <ul class="ref-list">
94 {branches.map((b) => (
95 <li class="ref-item">
96 <div class="ref-name-row">
97 <a
98 href={`/${repo.name}/tree/${b.name}`}
99 class="ref-name"
100 >
101 {b.name}
102 </a>
103 {b.name === repo.default_branch && (
104 <span class="badge">default</span>
105 )}
106 </div>
107 <div class="ref-meta-row">
108 {b.authorName && (
109 <span class="ref-author">
110 {b.authorName}
111 </span>
112 )}
113 {b.shortHash && (
114 <a
115 href={`/${repo.name}/commit/${b.shortHash}`}
116 class="ref-hash mono"
117 >
118 {b.shortHash}
119 </a>
120 )}
121 {b.subject && (
122 <span class="ref-subject">
123 {b.subject}
124 </span>
125 )}
126 {b.date && (
127 <time
128 class="ref-date"
129 datetime={b.date}
130 >
131 {formatDateTime(b.date)}
132 </time>
133 )}
134 {user?.isAdmin && (
135 <span class="ref-actions">
136 <details class="confirm-details confirm-details-inline">
137 <summary class="btn btn-sm">
138 Rename
139 </summary>
140 <div class="confirm-popup">
141 <form
142 method="POST"
143 action={`/${repo.name}/branches/rename`}
144 class="popup-form"
145 >
146 <input
147 type="hidden"
148 name="old_name"
149 value={b.name}
150 />
151 <input
152 name="new_name"
153 type="text"
154 required
155 placeholder="new-name"
156 value={b.name}
157 maxlength={MAX_BRANCH_NAME_LENGTH}
158 />
159 <button
160 type="submit"
161 class="btn btn-sm btn-primary"
162 >
163 Rename
164 </button>
165 </form>
166 </div>
167 </details>
168 {b.name !== repo.default_branch && (
169 <details class="confirm-details confirm-details-inline">
170 <summary class="btn btn-sm btn-danger">
171 Delete
172 </summary>
173 <div class="confirm-popup">
174 Delete branch{" "}
175 <strong>
176 {b.name}
177 </strong>
178 ?
179 <form
180 method="POST"
181 action={`/${repo.name}/branches/delete`}
182 class="inline-form"
183 >
184 <input
185 type="hidden"
186 name="name"
187 value={b.name}
188 />
189 <button
190 type="submit"
191 class="btn btn-sm btn-danger"
192 >
193 Yes, delete
194 </button>
195 </form>
196 </div>
197 </details>
198 )}
199 </span>
200 )}
201 </div>
202 </li>
203 ))}
204 </ul>
205 )}
206 <Pagination
207 page={page}
208 totalPages={totalPages}
209 pageUrlTemplate={`/${repo.name}/branches?page={page}`}
210 />
211 </div>
212 </Layout>
213 );
214}
215