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 && <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={
158 MAX_BRANCH_NAME_LENGTH
159 }
160 />
161 <button
162 type="submit"
163 class="btn btn-sm btn-primary"
164 >
165 Rename
166 </button>
167 </form>
168 </div>
169 </details>
170 {b.name !== repo.default_branch && (
171 <details class="confirm-details confirm-details-inline">
172 <summary class="btn btn-sm btn-danger">
173 Delete
174 </summary>
175 <div class="confirm-popup">
176 Delete branch{" "}
177 <strong>
178 {b.name}
179 </strong>
180 ?
181 <form
182 method="POST"
183 action={`/${repo.name}/branches/delete`}
184 class="inline-form"
185 >
186 <input
187 type="hidden"
188 name="name"
189 value={b.name}
190 />
191 <button
192 type="submit"
193 class="btn btn-sm btn-danger"
194 >
195 Yes, delete
196 </button>
197 </form>
198 </div>
199 </details>
200 )}
201 </span>
202 )}
203 </div>
204 </li>
205 ))}
206 </ul>
207 )}
208 <Pagination
209 page={page}
210 totalPages={totalPages}
211 pageUrlTemplate={`/${repo.name}/branches?page={page}`}
212 />
213 </div>
214 </Layout>
215 );
216}
217