Skip to content

RE: Added language as a filter to explore/repo_search #29044

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 37 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
9e7ecdd
Added language as a filter to explore/repo_search
snematoda Apr 19, 2023
94d2db8
Display only relevent languages
snematoda Apr 22, 2023
bd8e749
Rename Languages to ProgramLanguages
snematoda Apr 23, 2023
d199a13
Support searching and fix error msg
snematoda Apr 24, 2023
d5f5ef2
Switch Sort and set max height
snematoda Apr 24, 2023
d5eaca8
Minor style fixes
snematoda Apr 24, 2023
9a77fb8
improve styling
snematoda Aug 1, 2023
453b677
Update templates/explore/repo_search.tmpl
silverwind Aug 8, 2023
55884cc
Merge remote-tracking branch 'up/main' into patch-1
snematoda Aug 13, 2023
120c830
use unique css classes
snematoda Aug 13, 2023
093a267
Merge branch 'main' into patch-1
silverwind Aug 14, 2023
1e59ce2
use flex instead of float
silverwind Aug 14, 2023
84dd029
move language before sort as we are no longer using float
silverwind Aug 14, 2023
ab87133
remove pointless margin, use gap
silverwind Aug 14, 2023
e95e6bf
remove unused classes, align language names
wxiaoguang Aug 14, 2023
5a9d382
add support for user/org repos
snematoda Aug 15, 2023
7c4b55d
Merge branch 'main' into patch-1
snematoda Aug 15, 2023
22262e0
use translated all instead of 'Any'
snematoda Aug 15, 2023
f2c304e
display only relevent user repos
snematoda Aug 15, 2023
e50b52c
add api for languages
snematoda Aug 21, 2023
97a73e5
Merge branch 'main' into patch-1
snematoda Aug 21, 2023
85f1389
Update routers/api/v1/repo/languages.go
silverwind Aug 21, 2023
1393328
added ownerID to languages api
snematoda Aug 22, 2023
219d4d4
Merge branch 'main' into patch-1
snematoda Aug 22, 2023
3794e37
Merge branch 'main' into patch-1
silverwind Aug 25, 2023
2a8d0c8
Improved api and db calls
snematoda Aug 27, 2023
bc4d8b5
add tests and fix styling
snematoda Aug 27, 2023
00fb639
move styles to base.css
snematoda Aug 27, 2023
3ae0bb8
Merge branch 'main' into patch-1
snematoda Aug 27, 2023
7fb0de1
hotfixes
snematoda Aug 28, 2023
50049de
improve tests
snematoda Aug 30, 2023
721cf39
merge upstream
snematoda Feb 4, 2024
372ab85
hotfixes, follow style guidlines
snematoda Feb 7, 2024
e1d166a
Merge branch 'main' into patch-2
snematoda Feb 7, 2024
b399bb5
lint
snematoda Feb 7, 2024
50c1a81
lint
snematoda Feb 7, 2024
7982916
prealloc array
snematoda Feb 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions models/repo/repo_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -745,3 +745,31 @@ func GetUserRepositories(ctx context.Context, opts *SearchRepoOptions) (Reposito
repos := make(RepositoryList, 0, opts.PageSize)
return repos, count, db.SetSessionPagination(sess, opts).Find(&repos)
}

func GetPrimaryRepoLanguageList(ctx context.Context, ownerID int64, user *user_model.User) (LanguageStatList, error) {
sess := db.GetEngine(ctx).
Table("language_stat").
Cols("language").
Where(builder.Eq{"is_primary": true})

if ownerID > 0 {
ownerIDs, err := FindUserCodeAccessibleOwnerRepoIDs(ctx, ownerID, user)
if err != nil {
return nil, err
}

sess = sess.In("repo_id", ownerIDs)
}

languageList := make(LanguageStatList, 0)

err := sess.Distinct("language").
OrderBy("language").
Find(&languageList)
if err != nil {
return nil, err
}

languageList.LoadAttributes()
return languageList, nil
}
6 changes: 6 additions & 0 deletions modules/structs/miscellaneous.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ type LicenseTemplateInfo struct {
Body string `json:"body"`
}

// LanguagesInfo contains information about a Language
type LanguageInfo struct {
Name string `json:"name"`
Color string `json:"color"`
}

// APIError is an api error with a message
type APIError struct {
Message string `json:"message"`
Expand Down
3 changes: 3 additions & 0 deletions routers/api/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -907,6 +907,7 @@ func Routes() *web.Route {
m.Get("/heatmap", user.GetUserHeatmapData)
}

m.Get("/languages", repo.GetUserPrimaryLanguageList)
m.Get("/repos", tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository), reqExploreSignIn(), user.ListUserRepos)
m.Group("/tokens", func() {
m.Combo("").Get(user.ListAccessTokens).
Expand Down Expand Up @@ -1044,6 +1045,7 @@ func Routes() *web.Route {
// Repos (requires repo scope)
m.Group("/repos", func() {
m.Get("/search", repo.Search)
m.Get("/languages", repo.ListPrimaryLanguages)

// (repo scope)
m.Post("/migrate", reqToken(), bind(api.MigrateRepoOptions{}), repo.Migrate)
Expand Down Expand Up @@ -1434,6 +1436,7 @@ func Routes() *web.Route {
m.Combo("/{username}").Get(reqToken(), org.IsMember).
Delete(reqToken(), reqOrgOwnership(), org.DeleteMember)
})
m.Get("/languages", repo.GetOrgPrimaryLanguageList)
m.Group("/actions", func() {
m.Group("/secrets", func() {
m.Get("", reqToken(), reqOrgOwnership(), org.ListActionsSecrets)
Expand Down
89 changes: 89 additions & 0 deletions routers/api/v1/repo/languages.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package repo

import (
"net/http"

repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/context"
api "code.gitea.io/gitea/modules/structs"
)

func listPrimaryLanguageList(ctx *context.APIContext, ownerID int64) {
langs, err := repo_model.GetPrimaryRepoLanguageList(ctx, ownerID, ctx.Doer)
if err != nil {
ctx.InternalServerError(err)
return
}

list := make([]api.LanguageInfo, 0, len(langs))

for _, i := range langs {
list = append(list, api.LanguageInfo{
Name: i.Language,
Color: i.Color,
})
}

ctx.JSON(http.StatusOK, list)
}

// List all primary languages
func ListPrimaryLanguages(ctx *context.APIContext) {
// swagger:operation GET /repos/languages repository repoListPrimaryLanguages
// ---
// summary: Get primary languages and their color
// produces:
// - application/json
// responses:
// "200":
// "$ref": "#/responses/PrimaryLanguageList"

listPrimaryLanguageList(ctx, 0)
}

// List user primary languages
func GetUserPrimaryLanguageList(ctx *context.APIContext) {
// swagger:operation GET /users/{username}/languages user userListPrimaryLanguages
// ---
// summary: Get primary languages and their color
// produces:
// - application/json
// parameters:
// - name: username
// in: path
// description: username of user to get
// type: string
// required: true
// responses:
// "404":
// "$ref": "#/responses/notFound"
// "200":
// "$ref": "#/responses/PrimaryLanguageList"

listPrimaryLanguageList(ctx, ctx.ContextUser.ID)
}

// List org primary languages
func GetOrgPrimaryLanguageList(ctx *context.APIContext) {
// swagger:operation GET /orgs/{org}/languages organization orgListPrimaryLanguages
// ---
// summary: Get primary languages and their color
// produces:
// - application/json
// parameters:
// - name: org
// in: path
// description: name of the organization to get
// type: string
// required: true
// responses:
// "404":
// "$ref": "#/responses/notFound"
// "200":
// "$ref": "#/responses/PrimaryLanguageList"

listPrimaryLanguageList(ctx, ctx.Org.Organization.ID)
}
7 changes: 7 additions & 0 deletions routers/api/v1/swagger/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,13 @@ type swaggerLanguageStatistics struct {
Body map[string]int64 `json:"body"`
}

// PrimaryLanguageList
// swagger:response PrimaryLanguageList
type swaggerPrimaryLanguageList struct {
// in: body
Body []api.LanguageInfo `json:"body"`
}

// CombinedStatus
// swagger:response CombinedStatus
type swaggerCombinedStatus struct {
Expand Down
7 changes: 7 additions & 0 deletions routers/web/explore/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,17 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
return
}

programmingLanguages, err := repo_model.GetPrimaryRepoLanguageList(ctx, 0, ctx.Doer)
if err != nil {
ctx.ServerError("GetPrimaryRepoLanguageList", err)
return
}

ctx.Data["Keyword"] = keyword
ctx.Data["Total"] = count
ctx.Data["Repos"] = repos
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
ctx.Data["ProgrammingLanguages"] = programmingLanguages

pager := context.NewPagination(int(count), opts.PageSize, page, 5)
pager.SetDefaultParams(ctx)
Expand Down
7 changes: 7 additions & 0 deletions routers/web/org/home.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,20 @@ func Home(ctx *context.Context) {
isFollowing = user_model.IsFollowing(ctx, ctx.Doer.ID, ctx.ContextUser.ID)
}

programmingLanguages, err := repo_model.GetPrimaryRepoLanguageList(ctx, org.ID, ctx.Doer)
if err != nil {
ctx.ServerError("GetPrimaryRepoLanguageList", err)
return
}

ctx.Data["Repos"] = repos
ctx.Data["Total"] = count
ctx.Data["Members"] = members
ctx.Data["Teams"] = ctx.Org.Teams
ctx.Data["DisableNewPullMirrors"] = setting.Mirror.DisableNewPull
ctx.Data["PageIsViewRepositories"] = true
ctx.Data["IsFollowing"] = isFollowing
ctx.Data["ProgrammingLanguages"] = programmingLanguages

err = shared_user.LoadHeaderCount(ctx)
if err != nil {
Expand Down
7 changes: 7 additions & 0 deletions routers/web/user/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,13 @@ func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileDb
}

total = int(count)

programmingLanguages, err := repo_model.GetPrimaryRepoLanguageList(ctx, ctx.ContextUser.ID, ctx.Doer)
if err != nil {
ctx.ServerError("GetPrimaryRepoLanguageList", err)
return
}
ctx.Data["ProgrammingLanguages"] = programmingLanguages
}
ctx.Data["Repos"] = repos
ctx.Data["Total"] = total
Expand Down
65 changes: 44 additions & 21 deletions templates/explore/repo_search.tmpl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div class="ui secondary filter menu gt-ac gt-mx-0">
<form class="ui form ignore-dirty gt-f1">
<div class="ui secondary filter menu explore-menu gt-ac gt-mx-0">
<form class="ui form ignore-dirty gt-f1 explore-form">
<input type="hidden" name="sort" value="{{$.SortType}}">
<input type="hidden" name="language" value="{{$.Language}}">
<div class="ui fluid action input">
Expand All @@ -12,25 +12,48 @@
<button class="ui primary button">{{ctx.Locale.Tr "explore.search"}}</button>
</div>
</form>
<!-- Sort -->
<div class="ui dropdown type jump item gt-mr-0">
<span class="text">
{{ctx.Locale.Tr "repo.issues.filter_sort"}}
</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu">
<a class="{{if eq .SortType "newest"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=newest&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.filter_sort.latest"}}</a>
<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=oldest&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.filter_sort.oldest"}}</a>
<a class="{{if eq .SortType "alphabetically"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=alphabetically&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
<a class="{{if eq .SortType "reversealphabetically"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=reversealphabetically&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=recentupdate&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=leastupdate&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
{{if not .DisableStars}}
<a class="{{if eq .SortType "moststars"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=moststars&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.filter_sort.moststars"}}</a>
<a class="{{if eq .SortType "feweststars"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=feweststars&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.filter_sort.feweststars"}}</a>
{{end}}
<a class="{{if eq .SortType "mostforks"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=mostforks&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.filter_sort.mostforks"}}</a>
<a class="{{if eq .SortType "fewestforks"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=fewestforks&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.filter_sort.fewestforks"}}</a>

<div class="explore-filters gt-df">
<!-- Language -->
{{if .ProgrammingLanguages}}
<div class="ui dropdown type jump item gt-mx-0">
<span class="text">{{ctx.Locale.Tr "repo.repo_lang"}}</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu short">
<div class="ui icon search input">
<i class="icon">{{svg "octicon-search" 16}}</i>
<input type="text" placeholder="{{ctx.Locale.Tr "repo.repo_lang"}}" />
</div>
<a class="{{if not $.Language}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&sort={{$.SortType}}">
<span class="gt-df gt-ac gt-gap-3"><i class="color-icon gt-border-secondary" style="background-color: inherit;"></i>{{ctx.Locale.Tr "all"}}</span>
</a>
{{range .ProgrammingLanguages}}
<a class="{{if eq $.Language .Language}}active {{end}}item" href="{{$.Link}}?q={{$.Keyword}}&language={{.Language}}&sort={{$.SortType}}">
<span class="gt-df gt-ac gt-gap-3"><i class="color-icon" style="background-color: {{.Color}}"></i>{{.Language}}</span>
</a>
{{end}}
</div>
</div>
{{end}}

<!-- Sort -->
<div class="ui dropdown type jump item gt-mr-0">
<span class="text">{{ctx.Locale.Tr "repo.issues.filter_sort"}}</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu">
<a class="{{if eq .SortType "newest"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=newest&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.filter_sort.latest"}}</a>
<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=oldest&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.filter_sort.oldest"}}</a>
<a class="{{if eq .SortType "alphabetically"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=alphabetically&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
<a class="{{if eq .SortType "reversealphabetically"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=reversealphabetically&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=recentupdate&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=leastupdate&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
{{if not .DisableStars}}
<a class="{{if eq .SortType "moststars"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=moststars&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.filter_sort.moststars"}}</a>
<a class="{{if eq .SortType "feweststars"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=feweststars&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.filter_sort.feweststars"}}</a>
{{end}}
<a class="{{if eq .SortType "mostforks"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=mostforks&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.filter_sort.mostforks"}}</a>
<a class="{{if eq .SortType "fewestforks"}}active {{end}}item" href="{{$.Link}}?tab={{$.TabName}}&sort=fewestforks&q={{$.Keyword}}&language={{$.Language}}">{{ctx.Locale.Tr "repo.issues.filter_sort.fewestforks"}}</a>
</div>
</div>
</div>
</div>
Expand Down
Loading