Skip to content

Move UI configurations that do not require restarting gitea to take effect to the admin dashboard #33740

New issue

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

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

Already on GitHub? # to your account

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
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
13 changes: 13 additions & 0 deletions custom/conf/app.example.ini
Original file line number Diff line number Diff line change
@@ -1258,24 +1258,31 @@ LEVEL = Info
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Number of repositories that are displayed on one explore page
;; Deprecated in v1.24
;EXPLORE_PAGING_NUM = 20
;;
;; Number of issues that are displayed on one page
;; Deprecated in v1.24
;ISSUE_PAGING_NUM = 20
;;
;; Number of maximum commits displayed in one activity feed
;; Deprecated in v1.24
;FEED_MAX_COMMIT_NUM = 5
;;
;; Number of items that are displayed in home feed
;; Deprecated in v1.24
;FEED_PAGING_NUM = 20
;;
;; Number of items that are displayed in a single subsitemap
;; Deprecated in v1.24
;SITEMAP_PAGING_NUM = 20
;;
;; Number of maximum commits displayed in commit graph.
;; Deprecated in v1.24
;GRAPH_MAX_COMMIT_NUM = 100
;;
;; Number of line of codes shown for a code comment
;; Deprecated in v1.24
;CODE_COMMENT_LINES = 4
;;
;; Max size of files to be displayed (default is 8MiB)
@@ -1285,6 +1292,7 @@ LEVEL = Info
;AMBIGUOUS_UNICODE_DETECTION = true
;;
;; Whether the email of the user should be shown in the Explore Users page
;; Deprecated in v1.24
;SHOW_USER_EMAIL = true
;;
;; Set the default theme for the Gitea install
@@ -1303,6 +1311,7 @@ LEVEL = Info
;REACTIONS = +1, -1, laugh, hooray, confused, heart, rocket, eyes
;;
;; Change the number of users that are displayed in reactions tooltip (triggered by mouse hover).
;; Deprecated in v1.24
;REACTION_MAX_USER_NUM = 10
;;
;; Additional Emojis not defined in the utf8 standard
@@ -1311,17 +1320,21 @@ LEVEL = Info
;CUSTOM_EMOJIS = gitea, codeberg, gitlab, git, github, gogs
;;
;; Whether the full name of the users should be shown where possible. If the full name isn't set, the username will be used.
;; Deprecated in v1.24
;DEFAULT_SHOW_FULL_NAME = false
;;
;; Whether to search within description at repository search on explore page.
;; Deprecated in v1.24
;SEARCH_REPO_DESCRIPTION = true
;;
;; 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).
;; Deprecated in v1.24
;ONLY_SHOW_RELEVANT_REPOS = false
;;
;; Change the sort type of the explore pages.
;; Default is "recentupdate", but you also have "alphabetically", "reverselastlogin", "newest", "oldest".
;; Deprecated in v1.24
;EXPLORE_PAGING_DEFAULT_SORT = recentupdate
;;
;; The tense all timestamps should be rendered in. Possible values are `absolute` time (i.e. 1970-01-01, 11:59) and `mixed`.
2 changes: 1 addition & 1 deletion models/actions/run_list.go
Original file line number Diff line number Diff line change
@@ -134,6 +134,6 @@ func GetActors(ctx context.Context, repoID int64) ([]*user_model.User, error) {
GroupBy("`action_run`.trigger_user_id").
Where(builder.Eq{"`action_run`.repo_id": repoID}))).
Cols("id", "name", "full_name", "avatar", "avatar_email", "use_custom_avatar").
OrderBy(user_model.GetOrderByName()).
OrderBy(user_model.GetOrderByName(ctx)).
Find(&actors)
}
4 changes: 2 additions & 2 deletions models/activities/action.go
Original file line number Diff line number Diff line change
@@ -227,7 +227,7 @@ func (a *Action) ShortActUserName(ctx context.Context) string {

// GetActDisplayName gets the action's display name based on DEFAULT_SHOW_FULL_NAME, or falls back to the username if it is blank.
func (a *Action) GetActDisplayName(ctx context.Context) string {
if setting.UI.DefaultShowFullName {
if setting.Config().UI.DefaultShowFullName.Value(ctx) {
trimmedFullName := strings.TrimSpace(a.GetActFullName(ctx))
if len(trimmedFullName) > 0 {
return trimmedFullName
@@ -238,7 +238,7 @@ func (a *Action) GetActDisplayName(ctx context.Context) string {

// GetActDisplayNameTitle gets the action's display name used for the title (tooltip) based on DEFAULT_SHOW_FULL_NAME
func (a *Action) GetActDisplayNameTitle(ctx context.Context) string {
if setting.UI.DefaultShowFullName {
if setting.Config().UI.DefaultShowFullName.Value(ctx) {
return a.ShortActUserName(ctx)
}
return a.GetActFullName(ctx)
2 changes: 1 addition & 1 deletion models/issues/issue_list.go
Original file line number Diff line number Diff line change
@@ -251,7 +251,7 @@ func (issues IssueList) LoadAssignees(ctx context.Context) error {
}
rows, err := db.GetEngine(ctx).Table("issue_assignees").
Join("INNER", "`user`", "`user`.id = `issue_assignees`.assignee_id").
In("`issue_assignees`.issue_id", issueIDs[:limit]).OrderBy(user_model.GetOrderByName()).
In("`issue_assignees`.issue_id", issueIDs[:limit]).OrderBy(user_model.GetOrderByName(ctx)).
Rows(new(AssigneeIssue))
if err != nil {
return err
8 changes: 4 additions & 4 deletions models/issues/milestone_test.go
Original file line number Diff line number Diff line change
@@ -98,7 +98,7 @@ func TestGetMilestones(t *testing.T) {
milestones, err := db.Find[issues_model.Milestone](db.DefaultContext, issues_model.FindMilestoneOptions{
ListOptions: db.ListOptions{
Page: page,
PageSize: setting.UI.IssuePagingNum,
PageSize: setting.Config().UI.IssuePagingNum.Value(t.Context()),
},
RepoID: repo.ID,
IsClosed: optional.Some(false),
@@ -115,7 +115,7 @@ func TestGetMilestones(t *testing.T) {
milestones, err = db.Find[issues_model.Milestone](db.DefaultContext, issues_model.FindMilestoneOptions{
ListOptions: db.ListOptions{
Page: page,
PageSize: setting.UI.IssuePagingNum,
PageSize: setting.Config().UI.IssuePagingNum.Value(t.Context()),
},
RepoID: repo.ID,
IsClosed: optional.Some(true),
@@ -231,7 +231,7 @@ func TestGetMilestonesByRepoIDs(t *testing.T) {
openMilestones, err := db.Find[issues_model.Milestone](db.DefaultContext, issues_model.FindMilestoneOptions{
ListOptions: db.ListOptions{
Page: page,
PageSize: setting.UI.IssuePagingNum,
PageSize: setting.Config().UI.IssuePagingNum.Value(t.Context()),
},
RepoIDs: []int64{repo1.ID, repo2.ID},
IsClosed: optional.Some(false),
@@ -249,7 +249,7 @@ func TestGetMilestonesByRepoIDs(t *testing.T) {
issues_model.FindMilestoneOptions{
ListOptions: db.ListOptions{
Page: page,
PageSize: setting.UI.IssuePagingNum,
PageSize: setting.Config().UI.IssuePagingNum.Value(t.Context()),
},
RepoIDs: []int64{repo1.ID, repo2.ID},
IsClosed: optional.Some(true),
10 changes: 5 additions & 5 deletions models/issues/reaction.go
Original file line number Diff line number Diff line change
@@ -355,9 +355,9 @@ func (list ReactionList) LoadUsers(ctx context.Context, repo *repo_model.Reposit
}

// GetFirstUsers returns first reacted user display names separated by comma
func (list ReactionList) GetFirstUsers() string {
func (list ReactionList) GetFirstUsers(ctx context.Context) string {
var buffer bytes.Buffer
rem := setting.UI.ReactionMaxUserNum
rem := setting.Config().UI.ReactionMaxUserNum.Value(ctx)
for _, reaction := range list {
if buffer.Len() > 0 {
buffer.WriteString(", ")
@@ -371,9 +371,9 @@ func (list ReactionList) GetFirstUsers() string {
}

// GetMoreUserCount returns count of not shown users in reaction tooltip
func (list ReactionList) GetMoreUserCount() int {
if len(list) <= setting.UI.ReactionMaxUserNum {
func (list ReactionList) GetMoreUserCount(ctx context.Context) int {
if len(list) <= setting.Config().UI.ReactionMaxUserNum.Value(ctx) {
return 0
}
return len(list) - setting.UI.ReactionMaxUserNum
return len(list) - setting.Config().UI.ReactionMaxUserNum.Value(ctx)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# type Setting struct {
# ID int64 `xorm:"pk autoincr"`
# SettingKey string `xorm:"varchar(255) unique"` // key should be lowercase
# SettingValue string `xorm:"text"`
# Version int `xorm:"version"`
# Created timeutil.TimeStamp `xorm:"created"`
# Updated timeutil.TimeStamp `xorm:"updated"`
# }
-
id: 1
setting_key: revision
version: 1

-
id: 2
setting_key: picture.enable_federated_avatar
setting_value: false
version: 1

-
id: 3
setting_key: picture.disable_gravatar
setting_value: true
version: 1
1 change: 1 addition & 0 deletions models/migrations/migrations.go
Original file line number Diff line number Diff line change
@@ -375,6 +375,7 @@ func prepareMigrationTasks() []*migration {
newMigration(312, "Add DeleteBranchAfterMerge to AutoMerge", v1_24.AddDeleteBranchAfterMergeForAutoMerge),
newMigration(313, "Move PinOrder from issue table to a new table issue_pin", v1_24.MovePinOrderToTableIssuePin),
newMigration(314, "Update OwnerID as zero for repository level action tables", v1_24.UpdateOwnerIDOfRepoLevelActionsTables),
newMigration(315, "Migrate the configuration of the ui section of the ini configuration file to the system setting table.", v1_24.MigrateIniToDatabase),
}
return preparedMigrations
}
14 changes: 14 additions & 0 deletions models/migrations/v1_24/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package v1_24 //nolint

import (
"testing"

"code.gitea.io/gitea/models/migrations/base"
)

func TestMain(m *testing.M) {
base.MainTest(m)
}
98 changes: 98 additions & 0 deletions models/migrations/v1_24/v315.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package v1_24 //nolint

import (
"math"

"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"

"xorm.io/xorm"
)

const keyRevision = "revision"

type Setting struct {
ID int64 `xorm:"pk autoincr"`
SettingKey string `xorm:"varchar(255) unique"` // key should be lowercase
SettingValue string `xorm:"text"`
Version int `xorm:"version"`
Created timeutil.TimeStamp `xorm:"created"`
Updated timeutil.TimeStamp `xorm:"updated"`
}

// TableName sets the table name for the settings struct
func (s *Setting) TableName() string {
return "system_setting"
}

func MigrateIniToDatabase(x *xorm.Engine) error {
uiMap, err := util.ConfigSectionToMap(
setting.UI, "ui",
[]string{
"Reactions", "CustomEmojis", "MaxDisplayFileSize", "DefaultTheme", "Themes",
"FileIconTheme", "PreferredTimestampTense", "AmbiguousUnicodeDetection",
}...,
)
if err != nil {
return err
}

sess := x.NewSession()
defer sess.Close()

if err = sess.Begin(); err != nil {
return err
}

if err = sess.Sync(new(Setting)); err != nil {
return err
}

_ = getRevision(sess) // prepare the "revision" key ahead

_, err = sess.Exec("UPDATE system_setting SET version=version+1 WHERE setting_key=?", keyRevision)
if err != nil {
return err
}
for k, v := range uiMap {
res, err := sess.Exec("UPDATE system_setting SET version=version+1, setting_value=? WHERE setting_key=?", v, k)
if err != nil {
return err
}
rows, _ := res.RowsAffected()
if rows == 0 { // if no existing row, insert a new row
if _, err = sess.Insert(&Setting{SettingKey: k, SettingValue: v}); err != nil {
return err
}
}
}

return sess.Commit()
}

func getRevision(sess *xorm.Session) int {
revision := &Setting{}
exist, err := sess.Where("setting_key = ?", keyRevision).Get(revision)
if err != nil {
return 0
} else if !exist {
_, err = sess.Insert(&Setting{SettingKey: keyRevision, Version: 1})
if err != nil {
return 0
}
return 1
}

if revision.Version <= 0 || revision.Version >= math.MaxInt-1 {
_, err = sess.Exec("UPDATE system_setting SET version=1 WHERE setting_key=?", keyRevision)
if err != nil {
return 0
}
return 1
}
return revision.Version
}
27 changes: 27 additions & 0 deletions models/migrations/v1_24/v315_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package v1_24 //nolint

import (
"testing"

"code.gitea.io/gitea/models/migrations/base"

"github.com/stretchr/testify/assert"
)

func Test_MigrateIniToDatabase(t *testing.T) {
// Prepare and load the testing database
x, deferable := base.PrepareTestEnv(t, 0, new(Setting))
defer deferable()
if x == nil || t.Failed() {
return
}

assert.NoError(t, MigrateIniToDatabase(x))

cnt, err := x.Table("system_setting").Where("setting_key LIKE 'ui.%'").Count()
assert.NoError(t, err)
assert.EqualValues(t, 16, cnt)
}
4 changes: 2 additions & 2 deletions models/organization/org.go
Original file line number Diff line number Diff line change
@@ -169,8 +169,8 @@ func (org *Organization) OrganisationLink() string {
}

// ShortName ellipses username to length
func (org *Organization) ShortName(length int) string {
return org.AsUser().ShortName(length)
func (org *Organization) ShortName(ctx context.Context, length int) string {
return org.AsUser().ShortName(ctx, length)
}

// HomeLink returns the user or organization home page link.
2 changes: 1 addition & 1 deletion models/organization/org_user.go
Original file line number Diff line number Diff line change
@@ -163,7 +163,7 @@ func GetOrgAssignees(ctx context.Context, orgID int64) (_ []*user_model.User, er
if len(userIDs) > 0 {
if err = e.In("id", uniqueUserIDs.Values()).
Where(builder.Eq{"`user`.is_active": true}).
OrderBy(user_model.GetOrderByName()).
OrderBy(user_model.GetOrderByName(ctx)).
Find(&users); err != nil {
return nil, err
}
2 changes: 1 addition & 1 deletion models/repo/user_repo.go
Original file line number Diff line number Diff line change
@@ -134,7 +134,7 @@ func GetRepoAssignees(ctx context.Context, repo *Repository) (_ []*user_model.Us
if len(uniqueUserIDs) > 0 {
if err = e.In("id", uniqueUserIDs.Values()).
Where(builder.Eq{"`user`.is_active": true}).
OrderBy(user_model.GetOrderByName()).
OrderBy(user_model.GetOrderByName(ctx)).
Find(&users); err != nil {
return nil, err
}
Loading
Loading