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/issues_changes_test.go +23−5

@@ -338,7 +338,7 @@ func TestChangeLinksIssuesFromTheIssuesSection(t *testing.T) {
338 338 _, page := f.browserGet(t, "/r/"+f.repo+"/requests/"+id, cookie)
339 339 for _, want := range []string{
340 340 `id="request-issues"`, "First linked issue", `value="` + first + `"`,
341 `value="add"`, `value="remove"`, `request-unlink`,
341 `value="remove"`, `request-unlink`, `class="request-issue-search"`,
342 342 } {
343 343 if !strings.Contains(page, want) {
344 344 t.Fatalf("the request page is missing %q:\n%s", want, page)
@@ -348,7 +348,8 @@ func TestChangeLinksIssuesFromTheIssuesSection(t *testing.T) {
348 348 t.Fatalf("the old closes line is still on the page:\n%s", page)
349 349 }
350 350
351 // A number works in the link field, and the section comes back in place.
351 // The search box filters by title, `#number` and ULID prefix. A match is a
352 // button that posts the link, and the Issues section comes back in place.
352 353 m := mustRepo(t, f)
353 354 nums, err := metadata.LoadNumbers(m.Git(), metadata.Ref)
354 355 if err != nil {
@@ -358,8 +359,25 @@ func TestChangeLinksIssuesFromTheIssuesSection(t *testing.T) {
358 359 if !ok {
359 360 t.Fatalf("the second issue has no number")
360 361 }
362 for _, query := range []string{"Second", "#" + strconv.Itoa(number), second[:8]} {
363 resp, results := f.htmxGet(t, "/r/"+f.repo+"/requests/"+id+"/issues/search?q="+url.QueryEscape(query), cookie)
364 if resp.StatusCode != http.StatusOK || !strings.Contains(results, "Second linked issue") ||
365 !strings.Contains(results, `value="`+second+`"`) || !strings.Contains(results, `value="add"`) ||
366 !strings.Contains(results, `hx-target="#request-issues"`) {
367 t.Fatalf("search %q is not the expected result (%d):\n%s", query, resp.StatusCode, results)
368 }
369 }
370 // An issue already linked is not offered, so a shared title cannot hide the
371 // rows that are still available.
372 resp, results := f.htmxGet(t, "/r/"+f.repo+"/requests/"+id+"/issues/search?q=First", cookie)
373 if resp.StatusCode != http.StatusOK || strings.Contains(results, "First linked issue") ||
374 !strings.Contains(results, "No issues match") {
375 t.Fatalf("a linked issue is still in the search results (%d):\n%s", resp.StatusCode, results)
376 }
377
378 // Clicking a result posts its id, and the section comes back with both links.
361 379 resp, body = f.htmxPost(t, "/r/"+f.repo+"/requests/"+id+"/issues", cookie, url.Values{
362 "csrf": {sess.CSRF}, "action": {"add"}, "issue": {"#" + strconv.Itoa(number)},
380 "csrf": {sess.CSRF}, "action": {"add"}, "issue": {second},
363 381 })
364 382 if resp.StatusCode != http.StatusOK || !strings.Contains(body, `id="request-issues"`) ||
365 383 !strings.Contains(body, "Second linked issue") || !strings.Contains(body, "First linked issue") {
@@ -399,8 +417,8 @@ func TestChangeLinksIssuesFromTheIssuesSection(t *testing.T) {
399 417 t.Fatalf("close change: %d\n%s", resp.StatusCode, body)
400 418 }
401 419 _, page = f.browserGet(t, "/r/"+f.repo+"/requests/"+id, cookie)
402 if !strings.Contains(page, "Second linked issue") || strings.Contains(page, `value="remove"`) ||
403 strings.Contains(page, `value="add"`) {
420 if !strings.Contains(page, "Second linked issue") || strings.Contains(page, `request-unlink`) ||
421 strings.Contains(page, `class="request-issue-search"`) {
404 422 t.Fatalf("a closed request does not show the right Issues section:\n%s", page)
405 423 }
406 424 resp, _ = f.htmxPost(t, "/r/"+f.repo+"/requests/"+id+"/issues", cookie, url.Values{