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