diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 0949c3d399..1561a53da0 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -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 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 8ce8641365..05cedeb63d 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -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`) diff --git a/models/repo/repo_list.go b/models/repo/repo_list.go index 1fa469fcfe..ee72dc6ee7 100644 --- a/models/repo/repo_list.go +++ b/models/repo/repo_list.go @@ -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 } diff --git a/modules/setting/setting.go b/modules/setting/setting.go index becd52f011..09e510ffa0 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -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 { diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 0e309279d2..e87ee34441 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -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, show unfiltered results. + [auth] create_new_account = Register Account diff --git a/routers/web/explore/repo.go b/routers/web/explore/repo.go index b5485f5832..8cb615b7bc 100644 --- a/routers/web/explore/repo.go +++ b/routers/web/explore/repo.go @@ -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) diff --git a/templates/explore/repo_search.tmpl b/templates/explore/repo_search.tmpl index e1df2fa0ee..1dabfede8c 100644 --- a/templates/explore/repo_search.tmpl +++ b/templates/explore/repo_search.tmpl @@ -29,4 +29,9 @@ +{{if .OnlyShowRelevant}} +
+ {{.locale.Tr "explore.relevant_repositories" ((printf "%s%s" $.Link "?no_filter=1")|Escape) | Safe}} +
+{{end}}
diff --git a/web_src/less/_explore.less b/web_src/less/_explore.less index 0939f98fa1..3a31fe44d8 100644 --- a/web_src/less/_explore.less +++ b/web_src/less/_explore.less @@ -89,3 +89,9 @@ } } } + +.ui.explore-relevancy-note { + border-top: 0; + margin-top: 0; + max-width: 90%; +}