Only show relevant repositories on explore page (#19361)
Adds a new option to only show relevant repo's on the explore page, for bigger Gitea instances like Codeberg this is a nice option to enable to make the explore page more populated with unique and "high" quality repo's. A note is shown that the results are filtered and have the possibility to see the unfiltered results. Co-authored-by: vednoc <vednoc@protonmail.com> Co-authored-by: delvh <dev.lh@web.de> Co-authored-by: 6543 <6543@obermui.de>
This commit is contained in:
		
							parent
							
								
									dc0253b063
								
							
						
					
					
						commit
						27ac65a124
					
				| 
						 | 
				
			
			@ -1164,6 +1164,10 @@ ROUTER = console
 | 
			
		|||
;;
 | 
			
		||||
;; Whether to enable a Service Worker to cache frontend assets
 | 
			
		||||
;USE_SERVICE_WORKER = false
 | 
			
		||||
;;
 | 
			
		||||
;; Whether to only show relevant repos on the explore page when no keyword is specified and default sorting is used.
 | 
			
		||||
;; A repo is considered irrelevant if it's a fork or if it has no metadata (no description, no icon, no topic).
 | 
			
		||||
;ONLY_SHOW_RELEVANT_REPOS = false
 | 
			
		||||
 | 
			
		||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | 
			
		||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -194,6 +194,8 @@ The following configuration set `Content-Type: application/vnd.android.package-a
 | 
			
		|||
- `DEFAULT_SHOW_FULL_NAME`: **false**: Whether the full name of the users should be shown where possible. If the full name isn't set, the username will be used.
 | 
			
		||||
- `SEARCH_REPO_DESCRIPTION`: **true**: Whether to search within description at repository search on explore page.
 | 
			
		||||
- `USE_SERVICE_WORKER`: **false**: Whether to enable a Service Worker to cache frontend assets.
 | 
			
		||||
- `ONLY_SHOW_RELEVANT_REPOS`: **false** Whether to only show relevant repos on the explore page when no keyword is specified and default sorting is used.
 | 
			
		||||
    A repo is considered irrelevant if it's a fork or if it has no metadata (no description, no icon, no topic).
 | 
			
		||||
 | 
			
		||||
### UI - Admin (`ui.admin`)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -163,6 +163,10 @@ type SearchRepoOptions struct {
 | 
			
		|||
	HasMilestones util.OptionalBool
 | 
			
		||||
	// LowerNames represents valid lower names to restrict to
 | 
			
		||||
	LowerNames []string
 | 
			
		||||
	// When specified true, apply some filters over the conditions:
 | 
			
		||||
	// - Don't show forks, when opts.Fork is OptionalBoolNone.
 | 
			
		||||
	// - Do not display repositories that don't have a description, an icon and topics.
 | 
			
		||||
	OnlyShowRelevant bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SearchOrderBy is used to sort the result
 | 
			
		||||
| 
						 | 
				
			
			@ -463,8 +467,12 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
 | 
			
		|||
			Where(builder.Eq{"language": opts.Language}).And(builder.Eq{"is_primary": true})))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if opts.Fork != util.OptionalBoolNone {
 | 
			
		||||
		cond = cond.And(builder.Eq{"is_fork": opts.Fork == util.OptionalBoolTrue})
 | 
			
		||||
	if opts.Fork != util.OptionalBoolNone || opts.OnlyShowRelevant {
 | 
			
		||||
		if opts.OnlyShowRelevant && opts.Fork == util.OptionalBoolNone {
 | 
			
		||||
			cond = cond.And(builder.Eq{"is_fork": false})
 | 
			
		||||
		} else {
 | 
			
		||||
			cond = cond.And(builder.Eq{"is_fork": opts.Fork == util.OptionalBoolTrue})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if opts.Mirror != util.OptionalBoolNone {
 | 
			
		||||
| 
						 | 
				
			
			@ -486,6 +494,25 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
 | 
			
		|||
		cond = cond.And(builder.Eq{"num_milestones": 0}.Or(builder.IsNull{"num_milestones"}))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if opts.OnlyShowRelevant {
 | 
			
		||||
		// Only show a repo that either has a topic or description.
 | 
			
		||||
		subQueryCond := builder.NewCond()
 | 
			
		||||
 | 
			
		||||
		// Topic checking. Topics is non-null.
 | 
			
		||||
		subQueryCond = subQueryCond.Or(builder.And(builder.Neq{"topics": "null"}, builder.Neq{"topics": "[]"}))
 | 
			
		||||
 | 
			
		||||
		// Description checking. Description not empty.
 | 
			
		||||
		subQueryCond = subQueryCond.Or(builder.Neq{"description": ""})
 | 
			
		||||
 | 
			
		||||
		// Repo has a avatar.
 | 
			
		||||
		subQueryCond = subQueryCond.Or(builder.Neq{"avatar": ""})
 | 
			
		||||
 | 
			
		||||
		// Always hide repo's that are empty.
 | 
			
		||||
		subQueryCond = subQueryCond.And(builder.Eq{"is_empty": false})
 | 
			
		||||
 | 
			
		||||
		cond = cond.And(subQueryCond)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return cond
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -240,6 +240,7 @@ var (
 | 
			
		|||
		CustomEmojisMap       map[string]string `ini:"-"`
 | 
			
		||||
		SearchRepoDescription bool
 | 
			
		||||
		UseServiceWorker      bool
 | 
			
		||||
		OnlyShowRelevantRepos bool
 | 
			
		||||
 | 
			
		||||
		Notification struct {
 | 
			
		||||
			MinTimeout            time.Duration
 | 
			
		||||
| 
						 | 
				
			
			@ -1087,6 +1088,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
 | 
			
		|||
	UI.DefaultShowFullName = Cfg.Section("ui").Key("DEFAULT_SHOW_FULL_NAME").MustBool(false)
 | 
			
		||||
	UI.SearchRepoDescription = Cfg.Section("ui").Key("SEARCH_REPO_DESCRIPTION").MustBool(true)
 | 
			
		||||
	UI.UseServiceWorker = Cfg.Section("ui").Key("USE_SERVICE_WORKER").MustBool(false)
 | 
			
		||||
	UI.OnlyShowRelevantRepos = Cfg.Section("ui").Key("ONLY_SHOW_RELEVANT_REPOS").MustBool(false)
 | 
			
		||||
 | 
			
		||||
	HasRobotsTxt, err = util.IsFile(path.Join(CustomPath, "robots.txt"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -277,6 +277,9 @@ org_no_results = No matching organizations found.
 | 
			
		|||
code_no_results = No source code matching your search term found.
 | 
			
		||||
code_search_results = Search results for '%s'
 | 
			
		||||
code_last_indexed_at = Last indexed %s
 | 
			
		||||
relevant_repositories_tooltip = Repositories that are forks or that have no topic, no icon, and no description are hidden.
 | 
			
		||||
relevant_repositories = Only relevant repositories are being shown, <a href="%s">show unfiltered results</a>.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[auth]
 | 
			
		||||
create_new_account = Register Account
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,10 +48,11 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		repos   []*repo_model.Repository
 | 
			
		||||
		count   int64
 | 
			
		||||
		err     error
 | 
			
		||||
		orderBy db.SearchOrderBy
 | 
			
		||||
		repos            []*repo_model.Repository
 | 
			
		||||
		count            int64
 | 
			
		||||
		err              error
 | 
			
		||||
		orderBy          db.SearchOrderBy
 | 
			
		||||
		onlyShowRelevant bool
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	ctx.Data["SortType"] = ctx.FormString("sort")
 | 
			
		||||
| 
						 | 
				
			
			@ -60,8 +61,6 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
 | 
			
		|||
		orderBy = db.SearchOrderByNewest
 | 
			
		||||
	case "oldest":
 | 
			
		||||
		orderBy = db.SearchOrderByOldest
 | 
			
		||||
	case "recentupdate":
 | 
			
		||||
		orderBy = db.SearchOrderByRecentUpdated
 | 
			
		||||
	case "leastupdate":
 | 
			
		||||
		orderBy = db.SearchOrderByLeastUpdated
 | 
			
		||||
	case "reversealphabetically":
 | 
			
		||||
| 
						 | 
				
			
			@ -83,9 +82,16 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
 | 
			
		|||
	default:
 | 
			
		||||
		ctx.Data["SortType"] = "recentupdate"
 | 
			
		||||
		orderBy = db.SearchOrderByRecentUpdated
 | 
			
		||||
		onlyShowRelevant = setting.UI.OnlyShowRelevantRepos && !ctx.FormBool("no_filter")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	keyword := ctx.FormTrim("q")
 | 
			
		||||
	if keyword != "" {
 | 
			
		||||
		onlyShowRelevant = false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.Data["OnlyShowRelevant"] = onlyShowRelevant
 | 
			
		||||
 | 
			
		||||
	topicOnly := ctx.FormBool("topic")
 | 
			
		||||
	ctx.Data["TopicOnly"] = topicOnly
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -107,6 +113,7 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
 | 
			
		|||
		TopicOnly:          topicOnly,
 | 
			
		||||
		Language:           language,
 | 
			
		||||
		IncludeDescription: setting.UI.SearchRepoDescription,
 | 
			
		||||
		OnlyShowRelevant:   onlyShowRelevant,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.ServerError("SearchRepository", err)
 | 
			
		||||
| 
						 | 
				
			
			@ -133,6 +140,7 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
 | 
			
		|||
	pager.SetDefaultParams(ctx)
 | 
			
		||||
	pager.AddParam(ctx, "topic", "TopicOnly")
 | 
			
		||||
	pager.AddParam(ctx, "language", "Language")
 | 
			
		||||
	pager.AddParamString("no_filter", ctx.FormString("no_filter"))
 | 
			
		||||
	ctx.Data["Page"] = pager
 | 
			
		||||
 | 
			
		||||
	ctx.HTML(http.StatusOK, opts.TplName)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,4 +29,9 @@
 | 
			
		|||
		<button class="ui primary button">{{.locale.Tr "explore.search"}}</button>
 | 
			
		||||
	</div>
 | 
			
		||||
</form>
 | 
			
		||||
{{if .OnlyShowRelevant}}
 | 
			
		||||
	<div class="ui blue attached message explore-relevancy-note">
 | 
			
		||||
		<span class="ui tooltip" data-content="{{.locale.Tr "explore.relevant_repositories_tooltip"}}">{{.locale.Tr "explore.relevant_repositories" ((printf "%s%s" $.Link "?no_filter=1")|Escape) | Safe}}</span>
 | 
			
		||||
	</div>
 | 
			
		||||
{{end}}
 | 
			
		||||
<div class="ui divider"></div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -89,3 +89,9 @@
 | 
			
		|||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.ui.explore-relevancy-note {
 | 
			
		||||
  border-top: 0;
 | 
			
		||||
  margin-top: 0;
 | 
			
		||||
  max-width: 90%;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue