Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

Search for an issue when linking it to a change

838f282eebf7e68f61318eae93d03263df1341df · Keenan Nemetz · 10d ago · parent 267feec2

Search for an issue when linking it to a change

The link field only accepted an id that the author already knew. It is now a search box over the issue index that matches a title, a #number, or a ULID prefix. A matching issue is a button: picking one posts the same link write and replaces the Issues section with the new list. Issues already linked are left out of the results.

server/web/request_view.go +86

@@ -10,6 +10,7 @@ import (
10 10 "sort"
11 11 "strings"
12 12 "time"
13 "unicode/utf8"
13 14
14 15 "github.com/rodent-software/vole/ci/runs"
15 16 "github.com/rodent-software/vole/core/git"
@@ -410,6 +411,91 @@ func (w *Web) requestLinkedIssues(m *repo.Meta, req *metadata.Request, nums map[
410 411 return out
411 412 }
412 413
414 // requestIssueSearchLimit is how many matches the link picker offers. It is a
415 // picker beside the linked list, not the issue list: more than a handful makes the
416 // sidebar something to scroll before it is something to choose from.
417 const requestIssueSearchLimit = 8
418
419 // requestIssueSearchView is the result fragment under the link search box. It is
420 // separate from the Issues section so typing replaces only the results.
421 type requestIssueSearchView struct {
422 Page
423 Name string
424 Request *metadata.Request
425 Query string
426 Results []requestIssue
427 Error string
428 }
429
430 // SearchRequestIssues filters the issues the link picker may add. A term matches
431 // a title, a `#42` number, or a ULID prefix; the linked issues are left out
432 // because offering one again would only produce a refusal.
433 func (w *Web) SearchRequestIssues(rw http.ResponseWriter, r *http.Request) {
434 m, ok := w.open(rw, r)
435 if !ok {
436 return
437 }
438 req, err := metadata.GetRequest(m.Git(), r.PathValue("id"))
439 if err != nil {
440 w.notFound(rw, r)
441 return
442 }
443 query := strings.TrimSpace(r.URL.Query().Get("q"))
444 view := requestIssueSearchView{
445 Page: w.page(r, ""), Name: m.Name, Request: req, Query: query,
446 }
447 if query == "" || !req.Open() {
448 w.render(rw, "request_issue_search", view, 0)
449 return
450 }
451 if utf8.RuneCountInString(query) > 200 {
452 view.Error = "Search is limited to 200 characters."
453 w.render(rw, "request_issue_search", view, 0)
454 return
455 }
456 if w.Index == nil {
457 view.Error = "Issue search is unavailable right now."
458 w.render(rw, "request_issue_search", view, 0)
459 return
460 }
461 if err := w.Index.Ensure(m); err != nil {
462 if w.Logger != nil {
463 w.Logger("web: issue search index for %s: %v", m.Name, err)
464 }
465 view.Error = "Issue search is unavailable right now."
466 w.render(rw, "request_issue_search", view, 0)
467 return
468 }
469 linked := make(map[string]bool, len(req.Closes))
470 for _, id := range req.Closes {
471 linked[id] = true
472 }
473 // Ask for the linked issues too, then drop them: a title shared by a linked
474 // issue must not fill the picker with rows that cannot be added.
475 rows, err := w.Index.SearchIssues(m.ID, query, requestIssueSearchLimit+len(linked))
476 if err != nil {
477 if w.Logger != nil {
478 w.Logger("web: issue search for %s: %v", m.Name, err)
479 }
480 view.Error = "Issue search is unavailable right now."
481 w.render(rw, "request_issue_search", view, 0)
482 return
483 }
484 for _, row := range rows {
485 if linked[row.ID] {
486 continue
487 }
488 view.Results = append(view.Results, requestIssue{
489 ID: row.ID, Number: row.Number, Title: row.Title,
490 Author: row.Author, Created: row.Created,
491 })
492 if len(view.Results) == requestIssueSearchLimit {
493 break
494 }
495 }
496 w.render(rw, "request_issue_search", view, 0)
497 }
498
413 499 // pendingContributorCI finds the contributor branch whose tip is head and whose
414 500 // CI still waits for a maintainer. It is keyed by the commit: a branch that has
415 501 // moved past this request is not what is under review here.