style fixes of repo danger zone

AuthorKonata <konata@posteo.jp>
Date
Commit041dbc641d5f0f99a6effe6b695d1a20df58ec8d
Parent29b661e
4 files changed, 95 insertions(+), 86 deletions(-)
Msrc/routes/repos.tsx
@@ -1073,15 +1073,11 @@ export const repoRoutes = new Elysia()
10731073
10741074 const oldName = repo.name;
10751075 const newName = body.new_name?.trim() ?? "";
1076- const confirm = body.confirm_name?.trim() ?? "";
10771076 const back = (msg: string) =>
10781077 redirect(
10791078 `/${oldName}/settings?error=${encodeURIComponent(msg)}`,
10801079 );
10811080
1082- if (confirm !== oldName) {
1083- return back("Confirmation did not match the current name.");
1084- }
10851081 if (newName === oldName) {
10861082 return back("New name is the same as the current name.");
10871083 }
@@ -1141,7 +1137,6 @@ export const repoRoutes = new Elysia()
11411137 {
11421138 body: t.Object({
11431139 new_name: t.String(),
1144- confirm_name: t.String(),
11451140 }),
11461141 },
11471142 )
Msrc/styles/components.css
@@ -1168,14 +1168,39 @@
11681168 }
11691169 .danger-item {
11701170 display: flex;
1171- align-items: center;
1172- justify-content: space-between;
1173- gap: var(--space-4);
1174- flex-wrap: wrap;
1171+ flex-direction: column;
1172+ gap: var(--space-3);
1173+ padding: var(--space-4) 0;
1174+ }
1175+ .danger-item:first-child {
1176+ padding-top: 0;
1177+ }
1178+ .danger-item:last-child {
1179+ padding-bottom: 0;
1180+ }
1181+ .danger-item + .danger-item {
1182+ border-top: 1px solid var(--color-danger);
11751183 }
1176- .danger-item p {
1184+ .danger-item-info p {
11771185 margin: var(--space-1) 0 0;
11781186 }
1187+ .danger-form {
1188+ display: flex;
1189+ flex-direction: column;
1190+ align-items: flex-start;
1191+ gap: var(--space-3);
1192+ }
1193+ .danger-form .form-group {
1194+ width: min(360px, 100%);
1195+ }
1196+ .danger-form .form-group input {
1197+ width: 100%;
1198+ }
1199+ .danger-form .confirm-popup {
1200+ left: calc(100% + var(--space-2));
1201+ right: auto;
1202+ top: 0;
1203+ }
11791204 .btn-danger {
11801205 background: var(--color-danger);
11811206 border-color: transparent;
Msrc/views/repos/RepoSettings.tsx
@@ -305,7 +305,7 @@ export function RepoSettings({
305305 <h2 class="section-title danger-title">Danger zone</h2>
306306 <div class="form-card danger-card">
307307 <div class="danger-item">
308- <div>
308+ <div class="danger-item-info">
309309 <strong>Rename this repository</strong>
310310 <p class="text-muted">
311311 Changing the name breaks existing clone
@@ -313,80 +313,83 @@ export function RepoSettings({
313313 will need to update their remotes.
314314 </p>
315315 </div>
316- <details class="confirm-details">
317- <summary class="btn btn-danger">
318- Rename repository
319- </summary>
320- <div class="confirm-popup">
321- <form
322- method="POST"
323- action={`/${repo.name}/settings/rename`}
324- class="inline-form"
325- >
326- <div class="form-group">
327- <label for="new_name">
328- New name
329- </label>
330- <input
331- id="new_name"
332- name="new_name"
333- type="text"
334- required
335- pattern="[A-Za-z0-9._\-]+"
336- autocomplete="off"
337- />
338- </div>
339- <div class="form-group">
340- <label for="confirm_name">
341- Type <code safe>{repo.name}</code>{" "}
342- to confirm
343- </label>
344- <input
345- id="confirm_name"
346- name="confirm_name"
347- type="text"
348- required
349- autocomplete="off"
350- />
351- </div>
316+ <form
317+ method="POST"
318+ action={`/${repo.name}/settings/rename`}
319+ class="danger-form"
320+ >
321+ <div class="form-group">
322+ <label for="new_name">New name</label>
323+ <input
324+ id="new_name"
325+ name="new_name"
326+ type="text"
327+ required
328+ pattern="[A-Za-z0-9._\-]+"
329+ autocomplete="off"
330+ />
331+ </div>
332+ <details class="confirm-details">
333+ <summary class="btn btn-danger">
334+ Rename repository
335+ </summary>
336+ <div class="confirm-popup">
337+ Rename <span safe>{repo.name}</span>?
352338 <button
353339 type="submit"
354340 class="btn btn-danger"
355341 >
356- Rename repository
342+ Yes, rename
357343 </button>
358- </form>
359- </div>
360- </details>
344+ </div>
345+ </details>
346+ </form>
361347 </div>
362348 <div class="danger-item">
363- <div>
349+ <div class="danger-item-info">
364350 <strong>Delete this repository</strong>
365351 <p class="text-muted">
366352 Once deleted, there is no going back.
367353 </p>
368354 </div>
369- <details class="confirm-details">
370- <summary class="btn btn-danger">
371- Delete repository
372- </summary>
373- <div class="confirm-popup">
374- Delete <span safe>{repo.name}</span>? This
375- cannot be undone.
376- <form
377- method="POST"
378- action={`/${repo.name}/settings/delete`}
379- class="inline-form"
380- >
355+ <form
356+ method="POST"
357+ action={`/${repo.name}/settings/delete`}
358+ class="danger-form"
359+ >
360+ <div class="form-group">
361+ <label for="confirm_delete">
362+ Type <code safe>{repo.name}</code> to
363+ confirm deletion
364+ </label>
365+ <input
366+ id="confirm_delete"
367+ name="confirm_name"
368+ type="text"
369+ required
370+ pattern={repo.name.replace(
371+ /[.*+?^${}()|[\]\\]/g,
372+ "\\$&",
373+ )}
374+ autocomplete="off"
375+ />
376+ </div>
377+ <details class="confirm-details">
378+ <summary class="btn btn-danger">
379+ Delete repository
380+ </summary>
381+ <div class="confirm-popup">
382+ Delete <span safe>{repo.name}</span>?
383+ This cannot be undone.
381384 <button
382385 type="submit"
383386 class="btn btn-danger"
384387 >
385388 Yes, delete
386389 </button>
387- </form>
388- </div>
389- </details>
390+ </div>
391+ </details>
392+ </form>
390393 </div>
391394 </div>
392395 </div>
Mtests/e2e.settings.test.ts
@@ -362,23 +362,9 @@ describe('repository rename', () => {
362362
363363 afterAll(async () => { await adminCtx.close(); });
364364
365- test('rejects wrong confirmation', async () => {
366- const resp = await adminCtx.request.post(`${BASE}/renameme-repo/settings/rename`, {
367- form: { new_name: 'whatever', confirm_name: 'wrong' },
368- maxRedirects: 0,
369- });
370- expect(resp.status()).toBe(302);
371- const loc = resp.headers()['location']!;
372- expect(loc).toContain('/renameme-repo/settings?error=');
373- expect(decodeURIComponent(loc)).toContain('Confirmation');
374-
375- const check = await adminCtx.request.get(`${BASE}/renameme-repo`);
376- expect(check.status()).toBe(200);
377- });
378-
379365 test('rejects invalid name', async () => {
380366 const resp = await adminCtx.request.post(`${BASE}/renameme-repo/settings/rename`, {
381- form: { new_name: 'bad name', confirm_name: 'renameme-repo' },
367+ form: { new_name: 'bad name' },
382368 maxRedirects: 0,
383369 });
384370 expect(resp.status()).toBe(302);
@@ -389,7 +375,7 @@ describe('repository rename', () => {
389375
390376 test('rejects no-op rename', async () => {
391377 const resp = await adminCtx.request.post(`${BASE}/renameme-repo/settings/rename`, {
392- form: { new_name: 'renameme-repo', confirm_name: 'renameme-repo' },
378+ form: { new_name: 'renameme-repo' },
393379 maxRedirects: 0,
394380 });
395381 expect(resp.status()).toBe(302);
@@ -398,7 +384,7 @@ describe('repository rename', () => {
398384
399385 test('rejects duplicate name', async () => {
400386 const resp = await adminCtx.request.post(`${BASE}/renameme-repo/settings/rename`, {
401- form: { new_name: 'rename-other', confirm_name: 'renameme-repo' },
387+ form: { new_name: 'rename-other' },
402388 maxRedirects: 0,
403389 });
404390 expect(resp.status()).toBe(302);
@@ -409,7 +395,7 @@ describe('repository rename', () => {
409395 const aliceCtx = await loggedInContext('alice', 'password123');
410396 try {
411397 const resp = await aliceCtx.request.post(`${BASE}/renameme-repo/settings/rename`, {
412- form: { new_name: 'hijack', confirm_name: 'renameme-repo' },
398+ form: { new_name: 'hijack' },
413399 maxRedirects: 0,
414400 });
415401 expect(resp.status()).toBe(403);
@@ -418,7 +404,7 @@ describe('repository rename', () => {
418404
419405 test('admin can rename repository', async () => {
420406 const resp = await adminCtx.request.post(`${BASE}/renameme-repo/settings/rename`, {
421- form: { new_name: 'renamed-repo', confirm_name: 'renameme-repo' },
407+ form: { new_name: 'renamed-repo' },
422408 maxRedirects: 0,
423409 });
424410 expect(resp.status()).toBe(302);