web: interface guidelines fixes !461
22 files changed, +116 −51
Layout: unified · split
e2e/adminusersweb_test.go +4
| @@ -57,6 +57,10 @@ func TestAdminUsersWeb(t *testing.T) { | |||
| 57 | } | 57 | } |
| 58 | post(url.Values{"field": {"enable"}, "user": {"alice"}}) | 58 | post(url.Values{"field": {"enable"}, "user": {"alice"}}) |
| 59 | post(url.Values{"field": {"promote"}, "user": {"alice"}}) | 59 | post(url.Values{"field": {"promote"}, "user": {"alice"}}) |
| 60 | if out, _, _ := inst.ssh(t, rootKey, "", "admin", "user", "show", "alice", "--json"); strings.Contains(out, `"admin":true`) { | ||
| 61 | t.Fatalf("promote without a confirm took: %s", out) | ||
| 62 | } | ||
| 63 | post(url.Values{"field": {"promote"}, "user": {"alice"}, "confirm": {"alice"}}) | ||
| 60 | if out, _, _ := inst.ssh(t, rootKey, "", "admin", "user", "show", "alice", "--json"); !strings.Contains(out, `"admin":true`) { | 64 | if out, _, _ := inst.ssh(t, rootKey, "", "admin", "user", "show", "alice", "--json"); !strings.Contains(out, `"admin":true`) { |
| 61 | t.Fatalf("promote did not take: %s", out) | 65 | t.Fatalf("promote did not take: %s", out) |
| 62 | } | 66 | } |
e2e/mrweb_test.go +2 −1
| @@ -483,7 +483,8 @@ func TestMRSupersedes(t *testing.T) { | |||
| 483 | } | 483 | } |
| 484 | 484 | ||
| 485 | alice := inst.login(t, aliceKey) | 485 | alice := inst.login(t, aliceKey) |
| 486 | if status, body := browserPost(t, alice, inst.base()+"/alice/app/mrs/1/close", url.Values{"by": {"2"}}); status != 200 { | 486 | // The field's placeholder is "!N", so the "!" is accepted. |
| 487 | if status, body := browserPost(t, alice, inst.base()+"/alice/app/mrs/1/close", url.Values{"by": {"!2"}}); status != 200 { | ||
| 487 | t.Fatalf("close post: %d\n%s", status, body) | 488 | t.Fatalf("close post: %d\n%s", status, body) |
| 488 | } | 489 | } |
| 489 | 490 | ||
e2e/orgweb_test.go +33 −2
| @@ -85,10 +85,32 @@ func TestOrgManagementWeb(t *testing.T) { | |||
| 85 | } | 85 | } |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | // Revoking and removing work the same way round. | 88 | // Revoking and removing need the team's name typed; a bare post |
| 89 | // changes nothing. | ||
| 89 | browserPost(t, alice, inst.base()+"/acme", url.Values{ | 90 | browserPost(t, alice, inst.base()+"/acme", url.Values{ |
| 90 | "field": {"team-revoke"}, "team": {"builders"}, "repo": {"acme/widget"}, | 91 | "field": {"team-revoke"}, "team": {"builders"}, "repo": {"acme/widget"}, |
| 91 | }) | 92 | }) |
| 93 | if out, _, _ := inst.ssh(t, aliceKey, "", "org", "team", "show", "acme", "builders", "--json"); !strings.Contains(out, `"acme/widget"`) { | ||
| 94 | t.Fatalf("unconfirmed revoke dropped the grant: %s", out) | ||
| 95 | } | ||
| 96 | browserPost(t, alice, inst.base()+"/acme", url.Values{ | ||
| 97 | "field": {"team-revoke"}, "team": {"builders"}, "repo": {"acme/widget"}, "confirm": {"builders"}, | ||
| 98 | }) | ||
| 99 | if out, _, _ := inst.ssh(t, aliceKey, "", "org", "team", "show", "acme", "builders", "--json"); strings.Contains(out, `"acme/widget"`) { | ||
| 100 | t.Fatalf("confirmed revoke left the grant: %s", out) | ||
| 101 | } | ||
| 102 | browserPost(t, alice, inst.base()+"/acme", url.Values{ | ||
| 103 | "field": {"team-remove"}, "team": {"builders"}, "user": {"bob"}, | ||
| 104 | }) | ||
| 105 | if out, _, _ := inst.ssh(t, aliceKey, "", "org", "team", "show", "acme", "builders", "--json"); !strings.Contains(out, `"bob"`) { | ||
| 106 | t.Fatalf("unconfirmed team remove took bob out: %s", out) | ||
| 107 | } | ||
| 108 | browserPost(t, alice, inst.base()+"/acme", url.Values{ | ||
| 109 | "field": {"team-remove"}, "team": {"builders"}, "user": {"bob"}, "confirm": {"builders"}, | ||
| 110 | }) | ||
| 111 | if out, _, _ := inst.ssh(t, aliceKey, "", "org", "team", "show", "acme", "builders", "--json"); strings.Contains(out, `"bob"`) { | ||
| 112 | t.Fatalf("confirmed team remove left bob in: %s", out) | ||
| 113 | } | ||
| 92 | 114 | ||
| 93 | // Deleting the team needs its name typed; a bare post is refused and | 115 | // Deleting the team needs its name typed; a bare post is refused and |
| 94 | // the team stays. | 116 | // the team stays. |
| @@ -108,9 +130,18 @@ func TestOrgManagementWeb(t *testing.T) { | |||
| 108 | t.Fatalf("team not deleted: exit %d", code) | 130 | t.Fatalf("team not deleted: exit %d", code) |
| 109 | } | 131 | } |
| 110 | 132 | ||
| 111 | browserPost(t, alice, inst.base()+"/acme", url.Values{ | 133 | _, body = browserPost(t, alice, inst.base()+"/acme", url.Values{ |
| 112 | "field": {"member-remove"}, "user": {"bob"}, | 134 | "field": {"member-remove"}, "user": {"bob"}, |
| 113 | }) | 135 | }) |
| 136 | if !strings.Contains(body, "type bob to confirm") { | ||
| 137 | t.Fatalf("unconfirmed member remove was not refused:\n%s", body) | ||
| 138 | } | ||
| 139 | if members := orgMembers(t, inst, aliceKey); len(members) != 2 { | ||
| 140 | t.Fatalf("member removed without confirmation: %v", members) | ||
| 141 | } | ||
| 142 | browserPost(t, alice, inst.base()+"/acme", url.Values{ | ||
| 143 | "field": {"member-remove"}, "user": {"bob"}, "confirm": {"bob"}, | ||
| 144 | }) | ||
| 114 | if members := orgMembers(t, inst, aliceKey); len(members) != 1 { | 145 | if members := orgMembers(t, inst, aliceKey); len(members) != 1 { |
| 115 | t.Fatalf("member not removed: %v", members) | 146 | t.Fatalf("member not removed: %v", members) |
| 116 | } | 147 | } |
internal/httpd/adminusers.go +1 −1
| @@ -105,7 +105,7 @@ func (s *Server) adminUsersSubmit(w http.ResponseWriter, r *http.Request, viewer | |||
| 105 | back("unknown action") | 105 | back("unknown action") |
| 106 | return | 106 | return |
| 107 | } | 107 | } |
| 108 | if verb == "demote" || verb == "disable" { | 108 | if verb == "promote" || verb == "demote" || verb == "disable" { |
| 109 | if ok, msg := confirmed(r, name); !ok { | 109 | if ok, msg := confirmed(r, name); !ok { |
| 110 | back(msg) | 110 | back(msg) |
| 111 | return | 111 | return |
internal/httpd/mractions.go +1 −1
| @@ -87,7 +87,7 @@ func (s *Server) mrMergeSubmit(w http.ResponseWriter, r *http.Request, u store.U | |||
| 87 | 87 | ||
| 88 | func (s *Server) mrCloseSubmit(w http.ResponseWriter, r *http.Request, u store.User) { | 88 | func (s *Server) mrCloseSubmit(w http.ResponseWriter, r *http.Request, u store.User) { |
| 89 | args := []string{} | 89 | args := []string{} |
| 90 | if by := strings.TrimSpace(r.FormValue("by")); by != "" { | 90 | if by := strings.TrimPrefix(strings.TrimSpace(r.FormValue("by")), "!"); by != "" { |
| 91 | if _, err := strconv.ParseInt(by, 10, 64); err != nil { | 91 | if _, err := strconv.ParseInt(by, 10, 64); err != nil { |
| 92 | s.mrRedirect(w, r, "the superseding request is a number") | 92 | s.mrRedirect(w, r, "the superseding request is a number") |
| 93 | return | 93 | return |
internal/httpd/orgweb.go +12
| @@ -78,6 +78,10 @@ func (s *Server) orgSubmit(w http.ResponseWriter, r *http.Request, u store.User) | |||
| 78 | argv = append(argv, "--role", role) | 78 | argv = append(argv, "--role", role) |
| 79 | } | 79 | } |
| 80 | case "member-remove": | 80 | case "member-remove": |
| 81 | if ok, msg := confirmed(r, user); !ok { | ||
| 82 | back(msg) | ||
| 83 | return | ||
| 84 | } | ||
| 81 | argv = []string{"org", "members", "remove", owner, user} | 85 | argv = []string{"org", "members", "remove", owner, user} |
| 82 | case "team-create": | 86 | case "team-create": |
| 83 | argv = []string{"org", "team", "create", owner, team} | 87 | argv = []string{"org", "team", "create", owner, team} |
| @@ -90,11 +94,19 @@ func (s *Server) orgSubmit(w http.ResponseWriter, r *http.Request, u store.User) | |||
| 90 | case "team-add": | 94 | case "team-add": |
| 91 | argv = append([]string{"org", "team", "add", owner, team}, strings.Fields(user)...) | 95 | argv = append([]string{"org", "team", "add", owner, team}, strings.Fields(user)...) |
| 92 | case "team-remove": | 96 | case "team-remove": |
| 97 | if ok, msg := confirmed(r, team); !ok { | ||
| 98 | back(msg) | ||
| 99 | return | ||
| 100 | } | ||
| 93 | argv = append([]string{"org", "team", "remove", owner, team}, strings.Fields(user)...) | 101 | argv = append([]string{"org", "team", "remove", owner, team}, strings.Fields(user)...) |
| 94 | case "team-grant": | 102 | case "team-grant": |
| 95 | argv = []string{"org", "team", "grant", owner, team, | 103 | argv = []string{"org", "team", "grant", owner, team, |
| 96 | strings.TrimSpace(r.FormValue("repo")), r.FormValue("role")} | 104 | strings.TrimSpace(r.FormValue("repo")), r.FormValue("role")} |
| 97 | case "team-revoke": | 105 | case "team-revoke": |
| 106 | if ok, msg := confirmed(r, team); !ok { | ||
| 107 | back(msg) | ||
| 108 | return | ||
| 109 | } | ||
| 98 | argv = []string{"org", "team", "revoke", owner, team, strings.TrimSpace(r.FormValue("repo"))} | 110 | argv = []string{"org", "team", "revoke", owner, team, strings.TrimSpace(r.FormValue("repo"))} |
| 99 | default: | 111 | default: |
| 100 | back("unknown form") | 112 | back("unknown form") |
internal/web/static/style.css +6 −6
| @@ -523,7 +523,7 @@ nav.tabs a i { font-style: normal; color: var(--muted); margin-left: 4px; } | |||
| 523 | .pagehead h1, .listhead h1, .headrow h1, .listhead h2, .headrow h2 { margin: 0; } | 523 | .pagehead h1, .listhead h1, .headrow h1, .listhead h2, .headrow h2 { margin: 0; } |
| 524 | .pagehead > p, .listhead > p, .headrow > p { margin: 0; } | 524 | .pagehead > p, .listhead > p, .headrow > p { margin: 0; } |
| 525 | .pagehead .grow, .listhead .spacer, .headrow .spacer { flex: 1; } | 525 | .pagehead .grow, .listhead .spacer, .headrow .spacer { flex: 1; } |
| 526 | .issuetitle { margin: 0 0 var(--sp-2); font-size: var(--fs-5); } | 526 | .issuetitle { margin: 0 0 var(--sp-2); font-size: var(--fs-5); text-wrap: balance; } |
| 527 | .issuenumber { color: var(--muted); font-weight: 400; } | 527 | .issuenumber { color: var(--muted); font-weight: 400; } |
| 528 | .issuemeta { color: var(--muted); font-size: var(--fs-2); margin: 0 0 var(--sp-4); } | 528 | .issuemeta { color: var(--muted); font-size: var(--fs-2); margin: 0 0 var(--sp-4); } |
| 529 | .commithead p { margin: var(--sp-1) 0; } | 529 | .commithead p { margin: var(--sp-1) 0; } |
| @@ -905,7 +905,7 @@ table.tree td.lastcommit a { | |||
| 905 | table.tree td.lastcommit a:hover { color: var(--link); } | 905 | table.tree td.lastcommit a:hover { color: var(--link); } |
| 906 | table.tree th.age, table.tree td.age { width: 20%; } | 906 | table.tree th.age, table.tree td.age { width: 20%; } |
| 907 | td.age, th.age { text-align: right; white-space: nowrap; color: var(--muted); font-variant-numeric: tabular-nums; } | 907 | td.age, th.age { text-align: right; white-space: nowrap; color: var(--muted); font-variant-numeric: tabular-nums; } |
| 908 | td.size, td.mode { color: var(--muted); white-space: nowrap; } | 908 | td.size, td.mode { color: var(--muted); white-space: nowrap; font-variant-numeric: tabular-nums; } |
| 909 | table.tree th.size, table.tree td.size { text-align: right; } | 909 | table.tree th.size, table.tree td.size { text-align: right; } |
| 910 | table.refs td.name { width: 100%; } | 910 | table.refs td.name { width: 100%; } |
| 911 | table.refs td.sha, td.sha { color: var(--muted); } | 911 | table.refs td.sha, td.sha { color: var(--muted); } |
| @@ -928,8 +928,8 @@ table.keys.nowrap th, table.keys.nowrap td { white-space: nowrap; } | |||
| 928 | The cell is two fixed slots, each right-aligned. A form cannot span | 928 | The cell is two fixed slots, each right-aligned. A form cannot span |
| 929 | table cells, so one column per control — which would let the table | 929 | table cells, so one column per control — which would let the table |
| 930 | align them — is out without form="" plumbing, and the forms hold | 930 | align them — is out without form="" plumbing, and the forms hold |
| 931 | different numbers of controls: only an admin's role form has a | 931 | different numbers of controls: the enable form and the disabled |
| 932 | confirm field, and the enable form has none. Sizing the slot instead | 932 | row's Promote have no confirm field. Sizing the slot instead |
| 933 | of the form is what puts every button in one column and every field | 933 | of the form is what puts every button in one column and every field |
| 934 | in another; right-aligning the cell alone left the disabled row's | 934 | in another; right-aligning the cell alone left the disabled row's |
| 935 | Promote where other rows keep their field. A slot is a field, a gap | 935 | Promote where other rows keep their field. A slot is a field, a gap |
| @@ -1486,7 +1486,7 @@ a.memberchip { | |||
| 1486 | a.memberchip:hover { text-decoration: none; border-color: var(--link); color: var(--link); } | 1486 | a.memberchip:hover { text-decoration: none; border-color: var(--link); color: var(--link); } |
| 1487 | a.memberchip .role { color: var(--muted); } | 1487 | a.memberchip .role { color: var(--muted); } |
| 1488 | 1488 | ||
| 1489 | .pathbar { display: flex; align-items: center; gap: var(--sp-2) var(--sp-3); margin: 0 0 var(--sp-3); flex-wrap: wrap; font-size: var(--fs-2); } | 1489 | .pathbar { display: flex; align-items: center; gap: var(--sp-2) var(--sp-3); margin: 0 0 var(--sp-3); flex-wrap: wrap; font-size: var(--fs-2); overflow-wrap: anywhere; } |
| 1490 | .pathbar .spacer { flex: 1; } | 1490 | .pathbar .spacer { flex: 1; } |
| 1491 | .pathbar .actions { display: flex; align-items: center; gap: var(--sp-2); } | 1491 | .pathbar .actions { display: flex; align-items: center; gap: var(--sp-2); } |
| 1492 | /* history · blame · raw were 21px tall and "raw" 22px wide (#232) */ | 1492 | /* history · blame · raw were 21px tall and "raw" 22px wide (#232) */ |
| @@ -1608,6 +1608,7 @@ details.refmenu .refdrop { | |||
| 1608 | min-width: 12rem; | 1608 | min-width: 12rem; |
| 1609 | max-height: 20rem; | 1609 | max-height: 20rem; |
| 1610 | overflow-y: auto; | 1610 | overflow-y: auto; |
| 1611 | overscroll-behavior: contain; | ||
| 1611 | background: var(--canvas); | 1612 | background: var(--canvas); |
| 1612 | border: 1px solid var(--line); | 1613 | border: 1px solid var(--line); |
| 1613 | border-radius: var(--r-card); | 1614 | border-radius: var(--r-card); |
| @@ -1849,7 +1850,6 @@ svg.icon { vertical-align: -0.125em; } | |||
| 1849 | cell padding and the card clipped the age; a long name wraps (#232) */ | 1850 | cell padding and the card clipped the age; a long name wraps (#232) */ |
| 1850 | table.tree td.name { white-space: normal; overflow-wrap: anywhere; } | 1851 | table.tree td.name { white-space: normal; overflow-wrap: anywhere; } |
| 1851 | .clone pre { white-space: pre-wrap; word-break: break-all; } | 1852 | .clone pre { white-space: pre-wrap; word-break: break-all; } |
| 1852 | .pathbar { overflow-wrap: anywhere; } | ||
| 1853 | .readme .cardbody, .code { padding: var(--sp-3); } | 1853 | .readme .cardbody, .code { padding: var(--sp-3); } |
| 1854 | .thread { margin-left: var(--sp-3); } | 1854 | .thread { margin-left: var(--sp-3); } |
| 1855 | .blamehunk { flex-direction: column; gap: 0; } | 1855 | .blamehunk { flex-direction: column; gap: 0; } |
internal/web/templates/account.html +4 −4
| @@ -32,7 +32,7 @@ | |||
| 32 | <label for="p-website">Website</label> | 32 | <label for="p-website">Website</label> |
| 33 | <input type="text" id="p-website" name="website" value="{{.Profile.Website}}" placeholder="https://example.org"> | 33 | <input type="text" id="p-website" name="website" value="{{.Profile.Website}}" placeholder="https://example.org"> |
| 34 | <label for="p-links">Links</label> | 34 | <label for="p-links">Links</label> |
| 35 | <textarea id="p-links" name="links" rows="3" placeholder="one per line: label|https://... or a bare https://... (at most 5)">{{.LinksText}}</textarea> | 35 | <textarea id="p-links" name="links" rows="3" placeholder="one per line: label|https://… or a bare https://… (at most 5)">{{.LinksText}}</textarea> |
| 36 | <span class="btngroup"><button type="submit" class="btn">Save profile</button></span> | 36 | <span class="btngroup"><button type="submit" class="btn">Save profile</button></span> |
| 37 | </form> | 37 | </form> |
| 38 | <h3>About</h3> | 38 | <h3>About</h3> |
| @@ -65,7 +65,7 @@ commands and push; a <code>git</code> key can only move git data (e.g., CI).</p> | |||
| 65 | <form method="post" action="/settings" class="setform stack"> | 65 | <form method="post" action="/settings" class="setform stack"> |
| 66 | <input type="hidden" name="field" value="key-add"> | 66 | <input type="hidden" name="field" value="key-add"> |
| 67 | <label for="key">Public key</label> | 67 | <label for="key">Public key</label> |
| 68 | <textarea id="key" name="key" rows="3" required placeholder="ssh-ed25519 AAAA... you@machine"></textarea> | 68 | <textarea id="key" name="key" rows="3" required spellcheck="false" placeholder="ssh-ed25519 AAAA… you@machine"></textarea> |
| 69 | <label for="key-label">Label</label> | 69 | <label for="key-label">Label</label> |
| 70 | <input id="key-label" name="label" maxlength="64" placeholder="defaults to the key's comment"> | 70 | <input id="key-label" name="label" maxlength="64" placeholder="defaults to the key's comment"> |
| 71 | <label for="scope">Scope</label> | 71 | <label for="scope">Scope</label> |
| @@ -94,13 +94,13 @@ account and where notifications go.</p> | |||
| 94 | <form method="post" action="/settings" class="setform"> | 94 | <form method="post" action="/settings" class="setform"> |
| 95 | <input type="hidden" name="field" value="email-add"> | 95 | <input type="hidden" name="field" value="email-add"> |
| 96 | <label for="address">Address</label> | 96 | <label for="address">Address</label> |
| 97 | <input type="email" id="address" name="address" required placeholder="you@example.org"> | 97 | <input type="email" id="address" name="address" required autocomplete="email" placeholder="you@example.org"> |
| 98 | <button type="submit" class="btn">Send code</button> | 98 | <button type="submit" class="btn">Send code</button> |
| 99 | </form> | 99 | </form> |
| 100 | <form method="post" action="/settings" class="setform"> | 100 | <form method="post" action="/settings" class="setform"> |
| 101 | <input type="hidden" name="field" value="email-verify"> | 101 | <input type="hidden" name="field" value="email-verify"> |
| 102 | <label for="code">Verification code</label> | 102 | <label for="code">Verification code</label> |
| 103 | <input type="text" id="code" name="code" required placeholder="from the mail"> | 103 | <input type="text" id="code" name="code" required autocomplete="one-time-code" autocapitalize="none" spellcheck="false" placeholder="from the mail"> |
| 104 | <button type="submit" class="btn">Verify</button> | 104 | <button type="submit" class="btn">Verify</button> |
| 105 | </form> | 105 | </form> |
| 106 | </details> | 106 | </details> |
internal/web/templates/adminusers.html +1 −1
| @@ -38,7 +38,7 @@ | |||
| 38 | <input type="hidden" name="field" value="promote"> | 38 | <input type="hidden" name="field" value="promote"> |
| 39 | <input type="hidden" name="user" value="{{.Username}}"> | 39 | <input type="hidden" name="user" value="{{.Username}}"> |
| 40 | <input type="hidden" name="state" value="{{$.State}}"> | 40 | <input type="hidden" name="state" value="{{$.State}}"> |
| 41 | <button type="submit" class="btn">Promote</button> | 41 | {{template "confirmfield" .Username}} <button type="submit" class="btn">Promote</button> |
| 42 | </form> | 42 | </form> |
| 43 | {{else}} | 43 | {{else}} |
| 44 | {{/* An account that is not active cannot be promoted, but the row | 44 | {{/* An account that is not active cannot be promoted, but the row |
internal/web/templates/builds.html +1 −1
| @@ -11,7 +11,7 @@ | |||
| 11 | </div>{{end}}{{end}} | 11 | </div>{{end}}{{end}} |
| 12 | <form method="get" class="searchform compact"> | 12 | <form method="get" class="searchform compact"> |
| 13 | <label for="ref" class="colhead">Branch</label> | 13 | <label for="ref" class="colhead">Branch</label> |
| 14 | <input type="text" id="ref" name="ref" value="{{.Filter.Ref}}" list="buildrefs"> | 14 | <input type="text" id="ref" name="ref" value="{{.Filter.Ref}}" list="buildrefs" spellcheck="false"> |
| 15 | <datalist id="buildrefs">{{range .Refs}}<option value="{{.}}">{{end}}</datalist> | 15 | <datalist id="buildrefs">{{range .Refs}}<option value="{{.}}">{{end}}</datalist> |
| 16 | <input type="hidden" name="status" value="{{.Filter.Status}}"> | 16 | <input type="hidden" name="status" value="{{.Filter.Status}}"> |
| 17 | <input type="hidden" name="job" value="{{.Filter.Job}}"> | 17 | <input type="hidden" name="job" value="{{.Filter.Job}}"> |
internal/web/templates/fork.html +1 −1
| @@ -11,7 +11,7 @@ own.</p> | |||
| 11 | <option value="{{.Viewer}}">{{.Viewer}}</option> | 11 | <option value="{{.Viewer}}">{{.Viewer}}</option> |
| 12 | {{range .Orgs}}<option value="{{.}}"{{if eq . $.Owner}} selected{{end}}>{{.}}</option>{{end}} | 12 | {{range .Orgs}}<option value="{{.}}"{{if eq . $.Owner}} selected{{end}}>{{.}}</option>{{end}} |
| 13 | </select></label> | 13 | </select></label> |
| 14 | <label>/ Name <input name="name" required maxlength="63" pattern="[a-z0-9][a-z0-9._\-]{0,62}" value="{{.Name}}" aria-describedby="forkhint"></label> | 14 | <label>/ Name <input name="name" required maxlength="63" pattern="[a-z0-9][a-z0-9._\-]{0,62}" value="{{.Name}}" aria-describedby="forkhint" autocomplete="off" spellcheck="false"></label> |
| 15 | <span class="hint" id="forkhint">Defaults to the source name; change it to fork twice into the same owner.</span></p> | 15 | <span class="hint" id="forkhint">Defaults to the source name; change it to fork twice into the same owner.</span></p> |
| 16 | <p><button type="submit">Create fork</button></p> | 16 | <p><button type="submit">Create fork</button></p> |
| 17 | </form> | 17 | </form> |
internal/web/templates/issue.html +4 −4
| @@ -55,8 +55,8 @@ | |||
| 55 | {{else}}<p class="none">none yet</p>{{end}} | 55 | {{else}}<p class="none">none yet</p>{{end}} |
| 56 | {{if .CanWrite}} | 56 | {{if .CanWrite}} |
| 57 | <form method="post" action="{{$base}}/label" class="actions"> | 57 | <form method="post" action="{{$base}}/label" class="actions"> |
| 58 | <input type="text" name="add" aria-label="Add labels" placeholder="add, space-separated"> | 58 | <input type="text" name="add" aria-label="Add labels" autocomplete="off" spellcheck="false" placeholder="add, space-separated"> |
| 59 | <input type="text" name="remove" aria-label="Remove labels" placeholder="remove"> | 59 | <input type="text" name="remove" aria-label="Remove labels" autocomplete="off" spellcheck="false" placeholder="remove"> |
| 60 | <button type="submit" class="btn">Apply</button> | 60 | <button type="submit" class="btn">Apply</button> |
| 61 | </form> | 61 | </form> |
| 62 | {{end}} | 62 | {{end}} |
| @@ -67,8 +67,8 @@ | |||
| 67 | {{else}}<p class="none">nobody yet</p>{{end}} | 67 | {{else}}<p class="none">nobody yet</p>{{end}} |
| 68 | {{if .CanWrite}} | 68 | {{if .CanWrite}} |
| 69 | <form method="post" action="{{$base}}/assign" class="actions"> | 69 | <form method="post" action="{{$base}}/assign" class="actions"> |
| 70 | <input type="text" name="add" aria-label="Add assignees" placeholder="add, space-separated"> | 70 | <input type="text" name="add" aria-label="Add assignees" autocomplete="off" spellcheck="false" placeholder="add, space-separated"> |
| 71 | <input type="text" name="remove" aria-label="Remove assignees" placeholder="remove"> | 71 | <input type="text" name="remove" aria-label="Remove assignees" autocomplete="off" spellcheck="false" placeholder="remove"> |
| 72 | <button type="submit" class="btn">Apply</button> | 72 | <button type="submit" class="btn">Apply</button> |
| 73 | </form> | 73 | </form> |
| 74 | {{end}} | 74 | {{end}} |
internal/web/templates/layout.html +2 −1
| @@ -6,6 +6,7 @@ | |||
| 6 | <title>{{template "title" .}}</title> | 6 | <title>{{template "title" .}}</title> |
| 7 | <link rel="stylesheet" href="/static/style.css?v={{styleVersion}}"> | 7 | <link rel="stylesheet" href="/static/style.css?v={{styleVersion}}"> |
| 8 | <link rel="icon" href="/favicon.svg" type="image/svg+xml"> | 8 | <link rel="icon" href="/favicon.svg" type="image/svg+xml"> |
| 9 | <meta name="theme-color" content="#000000"> | ||
| 9 | {{with field . "Feed"}}<link rel="alternate" type="application/atom+xml" href="{{.}}"> | 10 | {{with field . "Feed"}}<link rel="alternate" type="application/atom+xml" href="{{.}}"> |
| 10 | {{end}}</head> | 11 | {{end}}</head> |
| 11 | <body> | 12 | <body> |
| @@ -223,7 +224,7 @@ | |||
| 223 | 224 | ||
| 224 | {{/* cmtln turns a line number into the link that opens the comment form | 225 | {{/* cmtln turns a line number into the link that opens the comment form |
| 225 | on that line. No JavaScript: the anchor travels in the query. */}} | 226 | on that line. No JavaScript: the anchor travels in the query. */}} |
| 226 | {{define "cmtln"}}{{if and .Viewer .Base}}<a class="cmt" title="Comment on this line" href="{{.Base}}?view=diff&cpath={{.Path}}&cline={{.N}}&cside={{.Side}}#compose">{{.N}}</a>{{else}}{{.N}}{{end}}{{end}} | 227 | {{define "cmtln"}}{{if and .Viewer .Base}}<a class="cmt" aria-label="Comment on line {{.N}}" title="Comment on this line" href="{{.Base}}?view=diff&cpath={{.Path}}&cline={{.N}}&cside={{.Side}}#compose">{{.N}}</a>{{else}}{{.N}}{{end}}{{end}} |
| 227 | 228 | ||
| 228 | {{/* thread renders one review thread with its reply and resolve controls. | 229 | {{/* thread renders one review thread with its reply and resolve controls. |
| 229 | Class carries "stale" for threads whose anchor is gone. */}} | 230 | Class carries "stale" for threads whose anchor is gone. */}} |
internal/web/templates/login.html +1 −1
| @@ -11,7 +11,7 @@ expires in fifteen minutes.</p> | |||
| 11 | {{if .EmailLogin}} | 11 | {{if .EmailLogin}} |
| 12 | <form method="post" action="/login"> | 12 | <form method="post" action="/login"> |
| 13 | <div class="field"><label for="identifier">Username or email address</label> | 13 | <div class="field"><label for="identifier">Username or email address</label> |
| 14 | <input type="text" id="identifier" name="identifier" autocomplete="username" required></div> | 14 | <input type="text" id="identifier" name="identifier" autocomplete="username" autocapitalize="none" spellcheck="false" required></div> |
| 15 | <button type="submit">Email me a link</button> | 15 | <button type="submit">Email me a link</button> |
| 16 | </form> | 16 | </form> |
| 17 | <p>Or, from a machine with your registered key:</p> | 17 | <p>Or, from a machine with your registered key:</p> |
internal/web/templates/mr.html +5 −5
| @@ -107,7 +107,7 @@ | |||
| 107 | </form> | 107 | </form> |
| 108 | <form method="post" action="{{$base}}/close" class="actions"> | 108 | <form method="post" action="{{$base}}/close" class="actions"> |
| 109 | <label class="vh" for="by">Closed in favour of</label> | 109 | <label class="vh" for="by">Closed in favour of</label> |
| 110 | <input type="text" id="by" name="by" inputmode="numeric" size="4" placeholder="!N"> | 110 | <input type="text" id="by" name="by" size="4" autocomplete="off" placeholder="!N"> |
| 111 | <button type="submit" class="danger">Close without merging</button> | 111 | <button type="submit" class="danger">Close without merging</button> |
| 112 | </form> | 112 | </form> |
| 113 | <form method="post" action="{{$base}}/draft" class="actions"> | 113 | <form method="post" action="{{$base}}/draft" class="actions"> |
| @@ -143,8 +143,8 @@ | |||
| 143 | {{else}}<p class="none">nobody yet</p>{{end}} | 143 | {{else}}<p class="none">nobody yet</p>{{end}} |
| 144 | {{if and .CanWrite (or (eq .MR.State "open") (eq .MR.State "source_gone"))}} | 144 | {{if and .CanWrite (or (eq .MR.State "open") (eq .MR.State "source_gone"))}} |
| 145 | <form method="post" action="{{$base}}/review-request" class="actions"> | 145 | <form method="post" action="{{$base}}/review-request" class="actions"> |
| 146 | <input type="text" name="add" aria-label="Add reviewers" placeholder="add, space-separated"> | 146 | <input type="text" name="add" aria-label="Add reviewers" autocomplete="off" spellcheck="false" placeholder="add, space-separated"> |
| 147 | <input type="text" name="remove" aria-label="Remove reviewers" placeholder="remove"> | 147 | <input type="text" name="remove" aria-label="Remove reviewers" autocomplete="off" spellcheck="false" placeholder="remove"> |
| 148 | <button type="submit" class="btn">Apply</button> | 148 | <button type="submit" class="btn">Apply</button> |
| 149 | </form> | 149 | </form> |
| 150 | {{end}} | 150 | {{end}} |
| @@ -174,8 +174,8 @@ | |||
| 174 | {{else}}<p class="none">none yet</p>{{end}} | 174 | {{else}}<p class="none">none yet</p>{{end}} |
| 175 | {{if .CanWrite}} | 175 | {{if .CanWrite}} |
| 176 | <form method="post" action="{{$base}}/label" class="actions"> | 176 | <form method="post" action="{{$base}}/label" class="actions"> |
| 177 | <input type="text" name="add" aria-label="Add labels" placeholder="add, space-separated"> | 177 | <input type="text" name="add" aria-label="Add labels" autocomplete="off" spellcheck="false" placeholder="add, space-separated"> |
| 178 | <input type="text" name="remove" aria-label="Remove labels" placeholder="remove"> | 178 | <input type="text" name="remove" aria-label="Remove labels" autocomplete="off" spellcheck="false" placeholder="remove"> |
| 179 | <button type="submit" class="btn">Apply</button> | 179 | <button type="submit" class="btn">Apply</button> |
| 180 | </form> | 180 | </form> |
| 181 | {{end}} | 181 | {{end}} |
internal/web/templates/new.html +2 −2
| @@ -9,7 +9,7 @@ | |||
| 9 | <option value="{{.Viewer}}">{{.Viewer}}</option> | 9 | <option value="{{.Viewer}}">{{.Viewer}}</option> |
| 10 | {{range .Orgs}}<option value="{{.}}">{{.}}</option>{{end}} | 10 | {{range .Orgs}}<option value="{{.}}">{{.}}</option>{{end}} |
| 11 | </select></label> | 11 | </select></label> |
| 12 | <label>/ Name <input name="name" required maxlength="63" pattern="[a-z0-9][a-z0-9._\-]{0,62}" aria-describedby="namehint"></label> | 12 | <label>/ Name <input name="name" required maxlength="63" pattern="[a-z0-9][a-z0-9._\-]{0,62}" aria-describedby="namehint" autocomplete="off" spellcheck="false"></label> |
| 13 | <span class="hint" id="namehint">Lowercase letters, digits, dot, dash and underscore; must start with a letter or digit; up to 63 characters.</span></p> | 13 | <span class="hint" id="namehint">Lowercase letters, digits, dot, dash and underscore; must start with a letter or digit; up to 63 characters.</span></p> |
| 14 | <fieldset class="segmented"> | 14 | <fieldset class="segmented"> |
| 15 | <legend>Visibility</legend> | 15 | <legend>Visibility</legend> |
| @@ -26,7 +26,7 @@ | |||
| 26 | grants access through teams. You are its first admin.</p> | 26 | grants access through teams. You are its first admin.</p> |
| 27 | <form method="post" action="/new"> | 27 | <form method="post" action="/new"> |
| 28 | <input type="hidden" name="field" value="org-create"> | 28 | <input type="hidden" name="field" value="org-create"> |
| 29 | <p><label>Name <input name="name" required maxlength="63" pattern="[a-z0-9][a-z0-9._\-]{0,62}" aria-describedby="orghint"></label> | 29 | <p><label>Name <input name="name" required maxlength="63" pattern="[a-z0-9][a-z0-9._\-]{0,62}" aria-describedby="orghint" autocomplete="off" spellcheck="false"></label> |
| 30 | <span class="hint" id="orghint">The same rules as a repository name, and it becomes a top-level path.</span></p> | 30 | <span class="hint" id="orghint">The same rules as a repository name, and it becomes a top-level path.</span></p> |
| 31 | <p><button type="submit">Create organization</button></p> | 31 | <p><button type="submit">Create organization</button></p> |
| 32 | </form> | 32 | </form> |
internal/web/templates/owner.html +27 −11
| @@ -89,7 +89,7 @@ | |||
| 89 | {{range .Members}}<tr> | 89 | {{range .Members}}<tr> |
| 90 | <td><a href="/{{.Name}}">{{.Name}}</a></td> | 90 | <td><a href="/{{.Name}}">{{.Name}}</a></td> |
| 91 | <td>{{.Role}}</td> | 91 | <td>{{.Role}}</td> |
| 92 | <td class="act"><form method="post" action="/{{$org}}"><input type="hidden" name="field" value="member-remove"><input type="hidden" name="user" value="{{.Name}}"><button type="submit" class="linklike">Remove</button></form></td> | 92 | <td class="act"><form method="post" action="/{{$org}}"><input type="hidden" name="field" value="member-remove"><input type="hidden" name="user" value="{{.Name}}">{{template "confirmfield" .Name}} <button type="submit" class="linklike">Remove</button></form></td> |
| 93 | </tr> | 93 | </tr> |
| 94 | {{end}}</table></div> | 94 | {{end}}</table></div> |
| 95 | <details class="editbox"> | 95 | <details class="editbox"> |
| @@ -97,7 +97,7 @@ | |||
| 97 | <form method="post" action="/{{$org}}" class="setform stack"> | 97 | <form method="post" action="/{{$org}}" class="setform stack"> |
| 98 | <input type="hidden" name="field" value="member-add"> | 98 | <input type="hidden" name="field" value="member-add"> |
| 99 | <label for="member">Username</label> | 99 | <label for="member">Username</label> |
| 100 | <input type="text" id="member" name="user" required> | 100 | <input type="text" id="member" name="user" required autocomplete="off" spellcheck="false"> |
| 101 | <label class="none" for="memberrole">Role</label> | 101 | <label class="none" for="memberrole">Role</label> |
| 102 | <select id="memberrole" name="role"> | 102 | <select id="memberrole" name="role"> |
| 103 | <option value="member">member</option> | 103 | <option value="member">member</option> |
| @@ -118,25 +118,41 @@ of a team get its role on every repository it is granted.</p> | |||
| 118 | <p class="meta">members: {{range .Members}}<a class="memberchip" href="/{{.}}">{{.}}</a> {{else}}<span class="none">none yet</span>{{end}}</p> | 118 | <p class="meta">members: {{range .Members}}<a class="memberchip" href="/{{.}}">{{.}}</a> {{else}}<span class="none">none yet</span>{{end}}</p> |
| 119 | <p class="meta">repositories: {{range .Grants}}<span class="memberchip"><a href="/{{.RepoPath}}">{{.RepoPath}}</a> <span class="role">{{.Role}}</span></span> {{else}}<span class="none">none yet</span>{{end}}</p> | 119 | <p class="meta">repositories: {{range .Grants}}<span class="memberchip"><a href="/{{.RepoPath}}">{{.RepoPath}}</a> <span class="role">{{.Role}}</span></span> {{else}}<span class="none">none yet</span>{{end}}</p> |
| 120 | <form method="post" action="/{{$org}}" class="setform stack"> | 120 | <form method="post" action="/{{$org}}" class="setform stack"> |
| 121 | <input type="hidden" name="field" value="team-add"> | ||
| 121 | <input type="hidden" name="team" value="{{.Name}}"> | 122 | <input type="hidden" name="team" value="{{.Name}}"> |
| 122 | <label class="none" for="tm-{{.Name}}">Members</label> | 123 | <label class="none" for="tm-{{.Name}}">Add members</label> |
| 123 | <input type="text" id="tm-{{.Name}}" name="user" placeholder="usernames, space-separated"> | 124 | <input type="text" id="tm-{{.Name}}" name="user" placeholder="usernames, space-separated" autocomplete="off" spellcheck="false"> |
| 124 | <button type="submit" name="field" value="team-add" class="btn">Add</button> | 125 | <button type="submit" class="btn">Add</button> |
| 125 | <button type="submit" name="field" value="team-remove" class="btn">Remove</button> | ||
| 126 | </form> | 126 | </form> |
| 127 | {{if .Members}}<form method="post" action="/{{$org}}" class="setform stack"> | ||
| 128 | <input type="hidden" name="field" value="team-remove"> | ||
| 129 | <input type="hidden" name="team" value="{{.Name}}"> | ||
| 130 | <label class="none" for="tmr-{{.Name}}">Remove members</label> | ||
| 131 | <input type="text" id="tmr-{{.Name}}" name="user" placeholder="usernames, space-separated" autocomplete="off" spellcheck="false"> | ||
| 132 | {{template "confirmfield" .Name}} | ||
| 133 | <button type="submit" class="btn">Remove</button> | ||
| 134 | </form>{{end}} | ||
| 127 | <form method="post" action="/{{$org}}" class="setform stack"> | 135 | <form method="post" action="/{{$org}}" class="setform stack"> |
| 136 | <input type="hidden" name="field" value="team-grant"> | ||
| 128 | <input type="hidden" name="team" value="{{.Name}}"> | 137 | <input type="hidden" name="team" value="{{.Name}}"> |
| 129 | <label class="none" for="tr-{{.Name}}">Repository</label> | 138 | <label class="none" for="tr-{{.Name}}">Grant a repository</label> |
| 130 | <input type="text" id="tr-{{.Name}}" name="repo" placeholder="owner/name"> | 139 | <input type="text" id="tr-{{.Name}}" name="repo" placeholder="owner/name" autocomplete="off" spellcheck="false"> |
| 131 | <label class="none" for="trr-{{.Name}}">Role</label> | 140 | <label class="none" for="trr-{{.Name}}">Role</label> |
| 132 | <select id="trr-{{.Name}}" name="role"> | 141 | <select id="trr-{{.Name}}" name="role"> |
| 133 | <option value="read">read</option> | 142 | <option value="read">read</option> |
| 134 | <option value="write">write</option> | 143 | <option value="write">write</option> |
| 135 | <option value="admin">admin</option> | 144 | <option value="admin">admin</option> |
| 136 | </select> | 145 | </select> |
| 137 | <button type="submit" name="field" value="team-grant" class="btn">Grant</button> | 146 | <button type="submit" class="btn">Grant</button> |
| 138 | <button type="submit" name="field" value="team-revoke" class="btn">Revoke</button> | ||
| 139 | </form> | 147 | </form> |
| 148 | {{if .Grants}}<form method="post" action="/{{$org}}" class="setform stack"> | ||
| 149 | <input type="hidden" name="field" value="team-revoke"> | ||
| 150 | <input type="hidden" name="team" value="{{.Name}}"> | ||
| 151 | <label class="none" for="trv-{{.Name}}">Revoke a repository</label> | ||
| 152 | <input type="text" id="trv-{{.Name}}" name="repo" placeholder="owner/name" autocomplete="off" spellcheck="false"> | ||
| 153 | {{template "confirmfield" .Name}} | ||
| 154 | <button type="submit" class="btn">Revoke</button> | ||
| 155 | </form>{{end}} | ||
| 140 | <form method="post" action="/{{$org}}" class="setform"> | 156 | <form method="post" action="/{{$org}}" class="setform"> |
| 141 | <input type="hidden" name="field" value="team-delete"> | 157 | <input type="hidden" name="field" value="team-delete"> |
| 142 | <input type="hidden" name="team" value="{{.Name}}"> | 158 | <input type="hidden" name="team" value="{{.Name}}"> |
| @@ -162,7 +178,7 @@ of a team get its role on every repository it is granted.</p> | |||
| 162 | <form method="post" action="/{{$org}}" class="setform"> | 178 | <form method="post" action="/{{$org}}" class="setform"> |
| 163 | <input type="hidden" name="field" value="org-rename"> | 179 | <input type="hidden" name="field" value="org-rename"> |
| 164 | <label for="orgrename">New name</label> | 180 | <label for="orgrename">New name</label> |
| 165 | <input type="text" id="orgrename" name="name" value="{{$org}}" required> | 181 | <input type="text" id="orgrename" name="name" value="{{$org}}" required autocomplete="off" spellcheck="false"> |
| 166 | <button type="submit" class="btn">Rename</button> | 182 | <button type="submit" class="btn">Rename</button> |
| 167 | </form> | 183 | </form> |
| 168 | <p class="meta">Every clone URL under this organization changes with the name.</p> | 184 | <p class="meta">Every clone URL under this organization changes with the name.</p> |
internal/web/templates/refs.html +2 −2
| @@ -2,8 +2,8 @@ | |||
| 2 | {{define "content"}} | 2 | {{define "content"}} |
| 3 | <h1>Refs</h1> | 3 | <h1>Refs</h1> |
| 4 | <form method="get" action="/{{.Repo.OwnerName}}/{{.Repo.Name}}/compare" class="compareform"> | 4 | <form method="get" action="/{{.Repo.OwnerName}}/{{.Repo.Name}}/compare" class="compareform"> |
| 5 | <label>Compare <input name="base" value="{{.Repo.DefaultBranch}}" size="14" aria-label="base ref"></label> | 5 | <label>Compare <input name="base" value="{{.Repo.DefaultBranch}}" size="14" aria-label="Compare base ref" autocomplete="off" spellcheck="false"></label> |
| 6 | <label>with <input name="head" size="14" placeholder="branch, tag or sha" aria-label="head ref"></label> | 6 | <label>with <input name="head" size="14" placeholder="branch, tag or sha" aria-label="with head ref" autocomplete="off" spellcheck="false"></label> |
| 7 | <button type="submit" class="btn">Compare</button> | 7 | <button type="submit" class="btn">Compare</button> |
| 8 | </form> | 8 | </form> |
| 9 | <h2>Branches</h2> | 9 | <h2>Branches</h2> |
internal/web/templates/register.html +4 −4
| @@ -6,9 +6,9 @@ | |||
| 6 | {{else}}<p class="lede">Open registration. Your account activates once you verify your email.</p>{{end}} | 6 | {{else}}<p class="lede">Open registration. Your account activates once you verify your email.</p>{{end}} |
| 7 | {{if .Error}}<p class="error" role="alert">{{.Error}}</p>{{end}} | 7 | {{if .Error}}<p class="error" role="alert">{{.Error}}</p>{{end}} |
| 8 | <form method="post" action="/register" class="signupform"> | 8 | <form method="post" action="/register" class="signupform"> |
| 9 | <div class="field"><label for="username">Username</label><input type="text" id="username" name="username" value="{{.Username}}" required></div> | 9 | <div class="field"><label for="username">Username</label><input type="text" id="username" name="username" value="{{.Username}}" required autocomplete="username" autocapitalize="none" spellcheck="false"></div> |
| 10 | {{if eq .Mode "invite"}}<div class="field"><label for="invite">Invite code</label><input type="text" id="invite" name="invite" required></div> | 10 | {{if eq .Mode "invite"}}<div class="field"><label for="invite">Invite code</label><input type="text" id="invite" name="invite" required autocomplete="off" spellcheck="false"></div> |
| 11 | {{else}}<div class="field"><label for="email">Email</label><input type="text" id="email" name="email" required></div>{{end}} | 11 | {{else}}<div class="field"><label for="email">Email</label><input type="email" id="email" name="email" required autocomplete="email"></div>{{end}} |
| 12 | <div class="field"><label for="key">SSH public key</label> | 12 | <div class="field"><label for="key">SSH public key</label> |
| 13 | <p class="hint">Paste the contents of your public key file, usually <code>~/.ssh/id_ed25519.pub</code>. It starts with <code>ssh-ed25519</code> or <code>ssh-rsa</code>.</p> | 13 | <p class="hint">Paste the contents of your public key file, usually <code>~/.ssh/id_ed25519.pub</code>. It starts with <code>ssh-ed25519</code> or <code>ssh-rsa</code>.</p> |
| 14 | {{/* The help is a disclosure rather than a link out: a wiki page is on | 14 | {{/* The help is a disclosure rather than a link out: a wiki page is on |
| @@ -19,7 +19,7 @@ | |||
| 19 | <pre class="code" tabindex="0">ssh-keygen -t ed25519 | 19 | <pre class="code" tabindex="0">ssh-keygen -t ed25519 |
| 20 | cat ~/.ssh/id_ed25519.pub</pre> | 20 | cat ~/.ssh/id_ed25519.pub</pre> |
| 21 | </details> | 21 | </details> |
| 22 | <textarea id="key" name="key" rows="3" required placeholder="ssh-ed25519 AAAA... you@host"></textarea></div> | 22 | <textarea id="key" name="key" rows="3" required spellcheck="false" placeholder="ssh-ed25519 AAAA… you@host"></textarea></div> |
| 23 | <p><button type="submit">Create account</button></p> | 23 | <p><button type="submit">Create account</button></p> |
| 24 | </form> | 24 | </form> |
| 25 | <p class="meta">Prefer the terminal? <code>ssh git@{{.Host}} register --username you {{if eq .Mode "invite"}}--invite <code>{{else}}--email you@example.org{{end}}</code></p> | 25 | <p class="meta">Prefer the terminal? <code>ssh git@{{.Host}} register --username you {{if eq .Mode "invite"}}--invite <code>{{else}}--email you@example.org{{end}}</code></p> |
internal/web/templates/settings.html +1 −1
| @@ -186,7 +186,7 @@ | |||
| 186 | <input type="hidden" name="field" value="runner-add"> | 186 | <input type="hidden" name="field" value="runner-add"> |
| 187 | <label for="runner-key">Attach a runner</label> | 187 | <label for="runner-key">Attach a runner</label> |
| 188 | <p class="hint">Install <code>gitbay-runner</code>, run <code>gitbay-runner init</code>, and paste the key it prints. The runner builds your commits with the repository's secrets; merge requests from forks wait unless it runs with <code>-untrusted</code>.</p> | 188 | <p class="hint">Install <code>gitbay-runner</code>, run <code>gitbay-runner init</code>, and paste the key it prints. The runner builds your commits with the repository's secrets; merge requests from forks wait unless it runs with <code>-untrusted</code>.</p> |
| 189 | <textarea id="runner-key" name="key" rows="3" placeholder="ssh-ed25519 AAAA… (from gitbay-runner init)">{{index .Submitted "key"}}</textarea> | 189 | <textarea id="runner-key" name="key" rows="3" spellcheck="false" placeholder="ssh-ed25519 AAAA… (from gitbay-runner init)">{{index .Submitted "key"}}</textarea> |
| 190 | <button type="submit" class="btn">Attach</button> | 190 | <button type="submit" class="btn">Attach</button> |
| 191 | </form> | 191 | </form> |
| 192 | </section> | 192 | </section> |
internal/web/templates/snippet.html +1 −1
| @@ -29,7 +29,7 @@ | |||
| 29 | {{if .CanWrite}} | 29 | {{if .CanWrite}} |
| 30 | <details class="editbox"><summary>add a file</summary> | 30 | <details class="editbox"><summary>add a file</summary> |
| 31 | <form method="post" action="/{{.Owner}}/-/snippets/{{.Snippet.PublicID}}/file" class="commentform"> | 31 | <form method="post" action="/{{.Owner}}/-/snippets/{{.Snippet.PublicID}}/file" class="commentform"> |
| 32 | <p><input type="text" name="name" aria-label="File name" placeholder="filename" required></p> | 32 | <p><input type="text" name="name" aria-label="File name" placeholder="filename" required autocomplete="off" spellcheck="false"></p> |
| 33 | <p><textarea name="content" aria-label="Content" rows="12" required></textarea></p> | 33 | <p><textarea name="content" aria-label="Content" rows="12" required></textarea></p> |
| 34 | <p><button type="submit" class="btn">Add file</button></p> | 34 | <p><button type="submit" class="btn">Add file</button></p> |
| 35 | </form></details> | 35 | </form></details> |
internal/web/templates/snippetnew.html +1 −1
| @@ -4,7 +4,7 @@ | |||
| 4 | <h1>New snippet</h1> | 4 | <h1>New snippet</h1> |
| 5 | {{if .Error}}<p class="error" role="alert">{{.Error}}</p>{{end}} | 5 | {{if .Error}}<p class="error" role="alert">{{.Error}}</p>{{end}} |
| 6 | <form method="post" action="/{{.Owner}}/-/snippets/new" class="commentform"> | 6 | <form method="post" action="/{{.Owner}}/-/snippets/new" class="commentform"> |
| 7 | <p><input type="text" name="name" aria-label="File name" placeholder="filename" value="{{.Name}}" required></p> | 7 | <p><input type="text" name="name" aria-label="File name" placeholder="filename" value="{{.Name}}" required autocomplete="off" spellcheck="false"></p> |
| 8 | <p><input type="text" name="description" aria-label="Description" placeholder="description" value="{{.Description}}"></p> | 8 | <p><input type="text" name="description" aria-label="Description" placeholder="description" value="{{.Description}}"></p> |
| 9 | <p><select name="visibility" aria-label="Visibility"> | 9 | <p><select name="visibility" aria-label="Visibility"> |
| 10 | <option value="unlisted"{{if or (eq .Visibility "unlisted") (eq .Visibility "")}} selected{{end}}>unlisted</option> | 10 | <option value="unlisted"{{if or (eq .Visibility "unlisted") (eq .Visibility "")}} selected{{end}}>unlisted</option> |