0
0
mirror of https://github.com/go-gitea/gitea.git synced 2026-04-04 21:06:20 +02:00

Merge 9dd223917d304d9e0bd9d7a563262a8ee376747a into 30c07c20e94551141cc1873ab14bdd4c104bba94

This commit is contained in:
Lunny Xiao 2026-04-03 07:09:35 +00:00 committed by GitHub
commit 3cba42f68c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 132 additions and 18 deletions

View File

@ -24,4 +24,6 @@ const (
SettingEmailNotificationGiteaActionsDisabled = "disabled"
SettingsKeyActionsConfig = "actions.config"
SettingsKeyOrgRepoDefaultSort = "org.repo_default_sort"
)

View File

@ -2744,6 +2744,10 @@
"org.settings.email": "Contact Email Address",
"org.settings.website": "Website",
"org.settings.location": "Location",
"org.settings.repo_default_sort": "Default repository sort",
"org.settings.repo_default_sort_default": "Instance default",
"org.settings.repo_default_sort_desc": "Used when visitors do not select a sort option on the organization repositories page.",
"org.settings.repo_default_sort_invalid": "Repository sort option is invalid.",
"org.settings.permission": "Permissions",
"org.settings.repoadminchangeteam": "Repository admin can add and remove access for teams",
"org.settings.visibility": "Visibility",

View File

@ -55,7 +55,16 @@ func home(ctx *context.Context, viewRepositories bool) {
var orderBy db.SearchOrderBy
sortOrder := ctx.FormString("sort")
if _, ok := repo_model.OrderByFlatMap[sortOrder]; !ok {
sortOrder = setting.UI.ExploreDefaultSort // TODO: add new default sort order for org home?
repoDefaultSort, err := getOrgRepoDefaultSort(ctx, org)
if err != nil {
ctx.ServerError("GetUserSetting", err)
return
}
if repoDefaultSort != "" {
sortOrder = repoDefaultSort
} else {
sortOrder = setting.UI.ExploreDefaultSort
}
}
ctx.Data["SortType"] = sortOrder
orderBy = repo_model.OrderByFlatMap[sortOrder]

View File

@ -0,0 +1,24 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package org
import (
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/services/context"
)
func getOrgRepoDefaultSort(ctx *context.Context, org *organization.Organization) (string, error) {
defaultSort, err := user_model.GetUserSetting(ctx, org.ID, user_model.SettingsKeyOrgRepoDefaultSort)
if err != nil {
return "", err
}
if defaultSort != "" {
if _, ok := repo_model.OrderByFlatMap[defaultSort]; !ok {
return "", nil
}
}
return defaultSort, nil
}

View File

@ -48,6 +48,13 @@ func Settings(ctx *context.Context) {
ctx.Data["RepoAdminChangeTeamAccess"] = ctx.Org.Organization.RepoAdminChangeTeamAccess
ctx.Data["ContextUser"] = ctx.ContextUser
repoDefaultSort, err := getOrgRepoDefaultSort(ctx, ctx.Org.Organization)
if err != nil {
ctx.ServerError("GetUserSetting", err)
return
}
ctx.Data["RepoDefaultSort"] = repoDefaultSort
if _, err := shared_user.RenderUserOrgHeader(ctx); err != nil {
ctx.ServerError("RenderUserOrgHeader", err)
return
@ -65,6 +72,9 @@ func SettingsPost(ctx *context.Context) {
ctx.Data["CurrentVisibility"] = ctx.Org.Organization.Visibility
if ctx.HasError() {
if repoDefaultSort, err := getOrgRepoDefaultSort(ctx, ctx.Org.Organization); err == nil {
ctx.Data["RepoDefaultSort"] = repoDefaultSort
}
ctx.HTML(http.StatusOK, tplSettingsOptions)
return
}
@ -80,6 +90,19 @@ func SettingsPost(ctx *context.Context) {
return
}
repoDefaultSort := ""
if form.RepoDefaultSort != nil {
repoDefaultSort = *form.RepoDefaultSort
if repoDefaultSort != "" {
if _, ok := repo_model.OrderByFlatMap[repoDefaultSort]; !ok {
ctx.Data["Err_RepoDefaultSort"] = true
ctx.Data["RepoDefaultSort"] = repoDefaultSort
ctx.RenderWithErrDeprecated(ctx.Tr("org.settings.repo_default_sort_invalid"), tplSettingsOptions, &form)
return
}
}
}
opts := &user_service.UpdateOptions{
FullName: optional.FromPtr(form.FullName),
Description: optional.FromPtr(form.Description),
@ -96,6 +119,20 @@ func SettingsPost(ctx *context.Context) {
return
}
if form.RepoDefaultSort != nil {
if repoDefaultSort == "" {
if err := user_model.DeleteUserSetting(ctx, org.ID, user_model.SettingsKeyOrgRepoDefaultSort); err != nil {
ctx.ServerError("DeleteUserSetting", err)
return
}
} else {
if err := user_model.SetUserSetting(ctx, org.ID, user_model.SettingsKeyOrgRepoDefaultSort, repoDefaultSort); err != nil {
ctx.ServerError("SetUserSetting", err)
return
}
}
}
log.Trace("Organization setting updated: %s", org.Name)
ctx.Flash.Success(ctx.Tr("org.settings.update_setting_success"))
ctx.Redirect(ctx.Org.OrgLink + "/settings")

View File

@ -43,6 +43,7 @@ type UpdateOrgSettingForm struct {
Location *string `binding:"MaxSize(50)"`
MaxRepoCreation *int
RepoAdminChangeTeamAccess *bool
RepoDefaultSort *string `binding:"MaxSize(50)"`
}
// Validate validates the fields

View File

@ -38,9 +38,18 @@
</div>
</div>
{{if .SignedUser.IsAdmin}}
<div class="divider"></div>
<div class="field {{if .Err_RepoDefaultSort}}error{{end}}">
<label for="repo_default_sort">{{ctx.Locale.Tr "org.settings.repo_default_sort"}}</label>
<select id="repo_default_sort" name="repo_default_sort" class="ui dropdown">
<option value="" {{if eq .RepoDefaultSort ""}}selected{{end}}>{{ctx.Locale.Tr "org.settings.repo_default_sort_default"}}</option>
{{template "shared/repo/sort_options" dict "CurrentSort" .RepoDefaultSort "DisableStars" false "Kind" "select"}}
</select>
<p class="help">{{ctx.Locale.Tr "org.settings.repo_default_sort_desc"}}</p>
</div>
{{if .SignedUser.IsAdmin}}
<div class="inline field {{if .Err_MaxRepoCreation}}error{{end}}">
<label for="max_repo_creation">{{ctx.Locale.Tr "admin.users.max_repo_creation"}}</label>
<input id="max_repo_creation" name="max_repo_creation" type="number" min="-1" value="{{.Org.MaxRepoCreation}}">

View File

@ -36,20 +36,7 @@
<span class="text">{{ctx.Locale.Tr "repo.issues.filter_sort"}}</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu">
<label class="{{if eq .SortType "newest"}}active {{end}}item"><input hidden type="radio" name="sort" {{if eq .SortType "newest"}}checked{{end}} value="newest"> {{ctx.Locale.Tr "repo.issues.filter_sort.latest"}}</label>
<label class="{{if eq .SortType "oldest"}}active {{end}}item"><input hidden type="radio" name="sort" {{if eq .SortType "oldest"}}checked{{end}} value="oldest"> {{ctx.Locale.Tr "repo.issues.filter_sort.oldest"}}</label>
<label class="{{if eq .SortType "alphabetically"}}active {{end}}item"><input hidden type="radio" name="sort" {{if eq .SortType "alphabetically"}}checked{{end}} value="alphabetically"> {{ctx.Locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</label>
<label class="{{if eq .SortType "reversealphabetically"}}active {{end}}item"><input hidden type="radio" name="sort" {{if eq .SortType "reversealphabetically"}}checked{{end}} value="reversealphabetically"> {{ctx.Locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</label>
<label class="{{if eq .SortType "recentupdate"}}active {{end}}item"><input hidden type="radio" name="sort" {{if eq .SortType "recentupdate"}}checked{{end}} value="recentupdate"> {{ctx.Locale.Tr "repo.issues.filter_sort.recentupdate"}}</label>
<label class="{{if eq .SortType "leastupdate"}}active {{end}}item"><input hidden type="radio" name="sort" {{if eq .SortType "leastupdate"}}checked{{end}} value="leastupdate"> {{ctx.Locale.Tr "repo.issues.filter_sort.leastupdate"}}</label>
{{if not .DisableStars}}
<label class="{{if eq .SortType "moststars"}}active {{end}}item"><input hidden type="radio" name="sort" {{if eq .SortType "moststars"}}checked{{end}} value="moststars"> {{ctx.Locale.Tr "repo.issues.filter_sort.moststars"}}</label>
<label class="{{if eq .SortType "feweststars"}}active {{end}}item"><input hidden type="radio" name="sort" {{if eq .SortType "feweststars"}}checked{{end}} value="feweststars"> {{ctx.Locale.Tr "repo.issues.filter_sort.feweststars"}}</label>
{{end}}
<label class="{{if eq .SortType "mostforks"}}active {{end}}item"><input hidden type="radio" name="sort" {{if eq .SortType "mostforks"}}checked{{end}} value="mostforks"> {{ctx.Locale.Tr "repo.issues.filter_sort.mostforks"}}</label>
<label class="{{if eq .SortType "fewestforks"}}active {{end}}item"><input hidden type="radio" name="sort" {{if eq .SortType "fewestforks"}}checked{{end}} value="fewestforks"> {{ctx.Locale.Tr "repo.issues.filter_sort.fewestforks"}}</label>
<label class="{{if eq .SortType "size"}}active {{end}}item"><input hidden type="radio" name="sort" {{if eq .SortType "size"}}checked{{end}} value="size"> {{ctx.Locale.Tr "repo.issues.label.filter_sort.by_size"}}</label>
<label class="{{if eq .SortType "reversesize"}}active {{end}}item"><input hidden type="radio" name="sort" {{if eq .SortType "reversesize"}}checked{{end}} value="reversesize"> {{ctx.Locale.Tr "repo.issues.label.filter_sort.reverse_by_size"}}</label>
{{template "shared/repo/sort_options" dict "CurrentSort" .SortType "DisableStars" .DisableStars "Kind" "radio"}}
</div>
</div>
</form>

View File

@ -0,0 +1,24 @@
{{define "shared/repo/sort_option"}}
{{if eq .Kind "select"}}
<option value="{{.Value}}" {{if eq .CurrentSort .Value}}selected{{end}}>{{.Label}}</option>
{{else}}
<label class="{{if eq .CurrentSort .Value}}active {{end}}item"><input hidden type="radio" name="sort" {{if eq .CurrentSort .Value}}checked{{end}} value="{{.Value}}"> {{.Label}}</label>
{{end}}
{{end}}
{{define "shared/repo/sort_options"}}
{{template "shared/repo/sort_option" dict "CurrentSort" .CurrentSort "Kind" .Kind "Value" "newest" "Label" (ctx.Locale.Tr "repo.issues.filter_sort.latest")}}
{{template "shared/repo/sort_option" dict "CurrentSort" .CurrentSort "Kind" .Kind "Value" "oldest" "Label" (ctx.Locale.Tr "repo.issues.filter_sort.oldest")}}
{{template "shared/repo/sort_option" dict "CurrentSort" .CurrentSort "Kind" .Kind "Value" "alphabetically" "Label" (ctx.Locale.Tr "repo.issues.label.filter_sort.alphabetically")}}
{{template "shared/repo/sort_option" dict "CurrentSort" .CurrentSort "Kind" .Kind "Value" "reversealphabetically" "Label" (ctx.Locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically")}}
{{template "shared/repo/sort_option" dict "CurrentSort" .CurrentSort "Kind" .Kind "Value" "recentupdate" "Label" (ctx.Locale.Tr "repo.issues.filter_sort.recentupdate")}}
{{template "shared/repo/sort_option" dict "CurrentSort" .CurrentSort "Kind" .Kind "Value" "leastupdate" "Label" (ctx.Locale.Tr "repo.issues.filter_sort.leastupdate")}}
{{if not .DisableStars}}
{{template "shared/repo/sort_option" dict "CurrentSort" .CurrentSort "Kind" .Kind "Value" "moststars" "Label" (ctx.Locale.Tr "repo.issues.filter_sort.moststars")}}
{{template "shared/repo/sort_option" dict "CurrentSort" .CurrentSort "Kind" .Kind "Value" "feweststars" "Label" (ctx.Locale.Tr "repo.issues.filter_sort.feweststars")}}
{{end}}
{{template "shared/repo/sort_option" dict "CurrentSort" .CurrentSort "Kind" .Kind "Value" "mostforks" "Label" (ctx.Locale.Tr "repo.issues.filter_sort.mostforks")}}
{{template "shared/repo/sort_option" dict "CurrentSort" .CurrentSort "Kind" .Kind "Value" "fewestforks" "Label" (ctx.Locale.Tr "repo.issues.filter_sort.fewestforks")}}
{{template "shared/repo/sort_option" dict "CurrentSort" .CurrentSort "Kind" .Kind "Value" "size" "Label" (ctx.Locale.Tr "repo.issues.label.filter_sort.by_size")}}
{{template "shared/repo/sort_option" dict "CurrentSort" .CurrentSort "Kind" .Kind "Value" "reversesize" "Label" (ctx.Locale.Tr "repo.issues.label.filter_sort.reverse_by_size")}}
{{end}}

View File

@ -255,13 +255,27 @@ func testOrgSettings(t *testing.T) {
session := loginUser(t, "user2")
req := NewRequestWithValues(t, "POST", "/org/org3/settings", map[string]string{
"full_name": "org3 new full name",
"email": "org3-new-email@example.com",
"full_name": "org3 new full name",
"email": "org3-new-email@example.com",
"repo_default_sort": "reversealphabetically",
})
session.MakeRequest(t, req, http.StatusSeeOther)
org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3})
assert.Equal(t, "org3 new full name", org.FullName)
assert.Equal(t, "org3-new-email@example.com", org.Email)
repoDefaultSort, err := user_model.GetUserSetting(t.Context(), org.ID, user_model.SettingsKeyOrgRepoDefaultSort)
require.NoError(t, err)
assert.Equal(t, "reversealphabetically", repoDefaultSort)
req = NewRequest(t, "GET", "/org3")
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
sel := htmlDoc.doc.Find("a.name")
expectedRepos := []string{"repo5", "repo3", "repo21"}
assert.Len(t, expectedRepos, len(sel.Nodes))
for i := range expectedRepos {
assert.Equal(t, expectedRepos[i], strings.TrimSpace(sel.Eq(i).Text()))
}
req = NewRequestWithValues(t, "POST", "/org/org3/settings", map[string]string{
"email": "", // empty email means "clear email"
@ -270,4 +284,7 @@ func testOrgSettings(t *testing.T) {
org = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3})
assert.Equal(t, "org3 new full name", org.FullName)
assert.Empty(t, org.Email)
repoDefaultSort, err = user_model.GetUserSetting(t.Context(), org.ID, user_model.SettingsKeyOrgRepoDefaultSort)
require.NoError(t, err)
assert.Equal(t, "reversealphabetically", repoDefaultSort)
}