From 2b32f8b95f13aac07a27449290ac4ca5d9a917f0 Mon Sep 17 00:00:00 2001
From: wxiaoguang <wxiaoguang@gmail.com>
Date: Mon, 17 Apr 2023 09:00:19 +0800
Subject: [PATCH] Sort repo topic labels by name (#24123) (#24153)

Backport #24123
Close #24077

Manually backported and tested.

<img width="330" alt="image"
src="https://user-images.githubusercontent.com/2114189/232283645-92cc85dd-ba16-44a9-a7ef-5712b9d285e9.png">
---
 models/repo/topic.go             | 4 +++-
 routers/web/repo/blame.go        | 7 +------
 web_src/js/features/repo-home.js | 6 +++---
 3 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/models/repo/topic.go b/models/repo/topic.go
index 05f50cfe46..88fe532be9 100644
--- a/models/repo/topic.go
+++ b/models/repo/topic.go
@@ -194,14 +194,16 @@ func (opts *FindTopicOptions) toConds() builder.Cond {
 // FindTopics retrieves the topics via FindTopicOptions
 func FindTopics(opts *FindTopicOptions) ([]*Topic, int64, error) {
 	sess := db.GetEngine(db.DefaultContext).Select("topic.*").Where(opts.toConds())
+	orderBy := "topic.repo_count DESC"
 	if opts.RepoID > 0 {
 		sess.Join("INNER", "repo_topic", "repo_topic.topic_id = topic.id")
+		orderBy = "topic.name" // when render topics for a repo, it's better to sort them by name, to get consistent result
 	}
 	if opts.PageSize != 0 && opts.Page != 0 {
 		sess = db.SetSessionPagination(sess, opts)
 	}
 	topics := make([]*Topic, 0, 10)
-	total, err := sess.Desc("topic.repo_count").FindAndCount(&topics)
+	total, err := sess.OrderBy(orderBy).FindAndCount(&topics)
 	return topics, total, err
 }
 
diff --git a/routers/web/repo/blame.go b/routers/web/repo/blame.go
index 3546334ed6..0e232c194c 100644
--- a/routers/web/repo/blame.go
+++ b/routers/web/repo/blame.go
@@ -12,7 +12,6 @@ import (
 
 	repo_model "code.gitea.io/gitea/models/repo"
 	user_model "code.gitea.io/gitea/models/user"
-	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/charset"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/git"
@@ -23,10 +22,6 @@ import (
 	"code.gitea.io/gitea/modules/util"
 )
 
-const (
-	tplBlame base.TplName = "repo/home"
-)
-
 type blameRow struct {
 	RowNumber      int
 	Avatar         gotemplate.HTML
@@ -140,7 +135,7 @@ func RefBlame(ctx *context.Context) {
 
 	renderBlame(ctx, blameParts, commitNames, previousCommits)
 
-	ctx.HTML(http.StatusOK, tplBlame)
+	ctx.HTML(http.StatusOK, tplRepoHome)
 }
 
 func processBlameParts(ctx *context.Context, blameParts []git.BlamePart) (map[string]*user_model.UserCommit, map[string]string) {
diff --git a/web_src/js/features/repo-home.js b/web_src/js/features/repo-home.js
index dfccffc794..2088f51b8d 100644
--- a/web_src/js/features/repo-home.js
+++ b/web_src/js/features/repo-home.js
@@ -39,7 +39,7 @@ export function initRepoTopicBar() {
         viewDiv.children('.topic').remove();
         if (topics.length) {
           const topicArray = topics.split(',');
-
+          topicArray.sort();
           const last = viewDiv.children('a').last();
           for (let i = 0; i < topicArray.length; i++) {
             const link = $('<a class="ui repo-topic large label topic"></a>');
@@ -57,12 +57,12 @@ export function initRepoTopicBar() {
           topicPrompts.formatPrompt = xhr.responseJSON.message;
 
           const {invalidTopics} = xhr.responseJSON;
-          const topicLables = topicDropdown.children('a.ui.label');
+          const topicLabels = topicDropdown.children('a.ui.label');
 
           for (const [index, value] of topics.split(',').entries()) {
             for (let i = 0; i < invalidTopics.length; i++) {
               if (invalidTopics[i] === value) {
-                topicLables.eq(index).removeClass('green').addClass('red');
+                topicLabels.eq(index).removeClass('green').addClass('red');
               }
             }
           }