From 2374f8f47df5eca692a83fc21fd4b834b040f2dc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Oto=20=C5=A0=C5=A5=C3=A1va?= <oto.stava@gmail.com>
Date: Sat, 23 Nov 2024 14:37:16 +0100
Subject: [PATCH] Show page titles in wiki search results (#6048)

Replace wiki page filenames with page titles in the search results,
fixing the problem with them showing unreadable URI-encoded names.

(cherry picked from commit fc31fa0eeb925dca634b2ffb64344fb58e4530fe)
---
 services/wiki/wiki.go               | 28 ++++++++++++++++++++++++++--
 templates/repo/wiki/search.tmpl     |  2 +-
 tests/e2e/repo-wiki.test.e2e.js     | 11 +++++++++++
 tests/integration/repo_wiki_test.go |  6 +++---
 4 files changed, 41 insertions(+), 6 deletions(-)

diff --git a/services/wiki/wiki.go b/services/wiki/wiki.go
index 24779d41e0..aba1115aab 100644
--- a/services/wiki/wiki.go
+++ b/services/wiki/wiki.go
@@ -408,18 +408,42 @@ func DeleteWiki(ctx context.Context, repo *repo_model.Repository) error {
 	return nil
 }
 
-func SearchWikiContents(ctx context.Context, repo *repo_model.Repository, keyword string) ([]*git.GrepResult, error) {
+type SearchContentsResult struct {
+	*git.GrepResult
+	Title string
+}
+
+func SearchWikiContents(ctx context.Context, repo *repo_model.Repository, keyword string) ([]SearchContentsResult, error) {
 	gitRepo, err := git.OpenRepository(ctx, repo.WikiPath())
 	if err != nil {
 		return nil, err
 	}
 	defer gitRepo.Close()
 
-	return git.GrepSearch(ctx, gitRepo, keyword, git.GrepOptions{
+	grepRes, err := git.GrepSearch(ctx, gitRepo, keyword, git.GrepOptions{
 		ContextLineNumber: 0,
 		IsFuzzy:           true,
 		RefName:           repo.GetWikiBranchName(),
 		MaxResultLimit:    10,
 		MatchesPerFile:    3,
 	})
+	if err != nil {
+		return nil, err
+	}
+
+	res := make([]SearchContentsResult, 0, len(grepRes))
+	for _, entry := range grepRes {
+		wp, err := GitPathToWebPath(entry.Filename)
+		if err != nil {
+			return nil, err
+		}
+		_, title := WebPathToUserTitle(wp)
+
+		res = append(res, SearchContentsResult{
+			GrepResult: entry,
+			Title:      title,
+		})
+	}
+
+	return res, nil
 }
diff --git a/templates/repo/wiki/search.tmpl b/templates/repo/wiki/search.tmpl
index 0bccd40840..1b774908d0 100644
--- a/templates/repo/wiki/search.tmpl
+++ b/templates/repo/wiki/search.tmpl
@@ -1,7 +1,7 @@
 {{if .Results}}
 	{{range .Results}}
 		<a class="item tw-max-w-[80vw]" href="{{$.RepoLink}}/wiki/{{.Filename}}">
-			<b class="tw-block tw-mb-2 tw-whitespace-break-spaces">{{.Filename}}</b>
+			<b class="tw-block tw-mb-2 tw-whitespace-break-spaces">{{.Title}}</b>
 			{{range .LineCodes}}
 				<p class="tw-my-0 tw-whitespace-break-spaces">{{.}}</p>
 			{{end}}
diff --git a/tests/e2e/repo-wiki.test.e2e.js b/tests/e2e/repo-wiki.test.e2e.js
index 4599fbd0c7..6941eb1d4a 100644
--- a/tests/e2e/repo-wiki.test.e2e.js
+++ b/tests/e2e/repo-wiki.test.e2e.js
@@ -14,3 +14,14 @@ test(`Search for long titles and test for no overflow`, async ({page}, workerInf
   // timeout is necessary because HTMX search could be slow
   await expect(page.locator('#wiki-search a[href]')).toBeInViewport({ratio: 1});
 });
+
+test(`Search results show titles (and not file names)`, async ({page}, workerInfo) => {
+  test.skip(workerInfo.project.name === 'Mobile Safari', 'Fails as always, see https://codeberg.org/forgejo/forgejo/pulls/5326#issuecomment-2313275');
+  await page.goto('/user2/repo1/wiki');
+  await page.getByPlaceholder('Search wiki').fill('spaces');
+  await page.getByPlaceholder('Search wiki').click();
+  // workaround: HTMX listens on keyup events, playwright's fill only triggers the input event
+  // so we manually "type" the last letter
+  await page.getByPlaceholder('Search wiki').dispatchEvent('keyup');
+  await expect(page.locator('#wiki-search a[href] b')).toHaveText('Page With Spaced Name');
+});
diff --git a/tests/integration/repo_wiki_test.go b/tests/integration/repo_wiki_test.go
index 316c04503a..6115010ba4 100644
--- a/tests/integration/repo_wiki_test.go
+++ b/tests/integration/repo_wiki_test.go
@@ -29,9 +29,9 @@ func TestWikiSearchContent(t *testing.T) {
 		return el.Text()
 	})
 	assert.Equal(t, []string{
-		"Home.md",
-		"Page-With-Spaced-Name.md",
-		"Unescaped File.md",
+		"Home",
+		"Page With Spaced Name",
+		"Unescaped File",
 	}, res)
 }