// Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package setting import ( "time" "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/log" ) // UI settings var UI = struct { ExplorePagingNum int SitemapPagingNum int IssuePagingNum int RepoSearchPagingNum int MembersPagingNum int FeedMaxCommitNum int FeedPagingNum int PackagesPagingNum int GraphMaxCommitNum int CodeCommentLines int ReactionMaxUserNum int MaxDisplayFileSize int64 ShowUserEmail bool DefaultTheme string Themes []string FileIconTheme string FolderIconTheme string Reactions []string ReactionsLookup container.Set[string] `ini:"-"` CustomEmojis []string CustomEmojisMap map[string]string `ini:"-"` EnabledEmojis []string EnabledEmojisSet container.Set[string] `ini:"-"` SearchRepoDescription bool OnlyShowRelevantRepos bool ExploreDefaultSort string `ini:"EXPLORE_PAGING_DEFAULT_SORT"` PreferredTimestampTense string AmbiguousUnicodeDetection bool // TODO: DefaultShowFullName is introduced by https://github.com/go-gitea/gitea/pull/6710 // But there are still many edge cases: // * Many places still use "username", not respecting this setting // * Many places use "Full Name" if it is not empty, cause inconsistent UI for users who have set their full name but some others don't // * Even if DefaultShowFullName=false, many places still need to show the full name // For most cases, either "username" or "username (Full Name)" should be used and are good enough. // Only in very few cases (e.g.: unimportant lists, narrow layout), "username" or "Full Name" can be used. DefaultShowFullName bool Notification struct { MinTimeout time.Duration TimeoutStep time.Duration MaxTimeout time.Duration EventSourceUpdateTime time.Duration } `ini:"ui.notification"` SVG struct { Enabled bool `ini:"ENABLE_RENDER"` } `ini:"ui.svg"` CSV struct { MaxFileSize int64 MaxRows int } `ini:"ui.csv"` Admin struct { UserPagingNum int RepoPagingNum int NoticePagingNum int OrgPagingNum int } `ini:"ui.admin"` User struct { RepoPagingNum int OrgPagingNum int } `ini:"ui.user"` Meta struct { Author string Description string Keywords string } `ini:"ui.meta"` }{ ExplorePagingNum: 20, SitemapPagingNum: 20, IssuePagingNum: 20, RepoSearchPagingNum: 20, MembersPagingNum: 20, FeedMaxCommitNum: 5, FeedPagingNum: 20, PackagesPagingNum: 20, GraphMaxCommitNum: 100, CodeCommentLines: 4, ReactionMaxUserNum: 10, MaxDisplayFileSize: 8388608, DefaultTheme: `gitea-auto`, FileIconTheme: `material`, FolderIconTheme: `basic`, Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`}, CustomEmojis: []string{`git`, `gitea`, `codeberg`, `gitlab`, `github`, `gogs`}, CustomEmojisMap: map[string]string{"git": ":git:", "gitea": ":gitea:", "codeberg": ":codeberg:", "gitlab": ":gitlab:", "github": ":github:", "gogs": ":gogs:"}, ExploreDefaultSort: "recentupdate", PreferredTimestampTense: "mixed", AmbiguousUnicodeDetection: true, Notification: struct { MinTimeout time.Duration TimeoutStep time.Duration MaxTimeout time.Duration EventSourceUpdateTime time.Duration }{ MinTimeout: 10 * time.Second, TimeoutStep: 10 * time.Second, MaxTimeout: 60 * time.Second, EventSourceUpdateTime: 10 * time.Second, }, SVG: struct { Enabled bool `ini:"ENABLE_RENDER"` }{ Enabled: true, }, CSV: struct { MaxFileSize int64 MaxRows int }{ MaxFileSize: 524288, MaxRows: 2500, }, Admin: struct { UserPagingNum int RepoPagingNum int NoticePagingNum int OrgPagingNum int }{ UserPagingNum: 50, RepoPagingNum: 50, NoticePagingNum: 25, OrgPagingNum: 50, }, User: struct { RepoPagingNum int OrgPagingNum int }{ RepoPagingNum: 15, OrgPagingNum: 15, }, Meta: struct { Author string Description string Keywords string }{ Author: "Gitea - Git with a cup of tea", Description: "Gitea (Git with a cup of tea) is a painless self-hosted Git service written in Go", Keywords: "go,git,self-hosted,gitea", }, } func loadUIFrom(rootCfg ConfigProvider) { mustMapSetting(rootCfg, "ui", &UI) sec := rootCfg.Section("ui") UI.ShowUserEmail = sec.Key("SHOW_USER_EMAIL").MustBool(true) UI.DefaultShowFullName = sec.Key("DEFAULT_SHOW_FULL_NAME").MustBool(false) UI.SearchRepoDescription = sec.Key("SEARCH_REPO_DESCRIPTION").MustBool(true) if UI.PreferredTimestampTense != "mixed" && UI.PreferredTimestampTense != "absolute" { log.Fatal("ui.PREFERRED_TIMESTAMP_TENSE must be either 'mixed' or 'absolute'") } // OnlyShowRelevantRepos=false is important for many private/enterprise instances, // because many private repositories do not have "description/topic", users just want to search by their names. UI.OnlyShowRelevantRepos = sec.Key("ONLY_SHOW_RELEVANT_REPOS").MustBool(false) UI.ReactionsLookup = make(container.Set[string]) for _, reaction := range UI.Reactions { UI.ReactionsLookup.Add(reaction) } UI.CustomEmojisMap = make(map[string]string) for _, emoji := range UI.CustomEmojis { UI.CustomEmojisMap[emoji] = ":" + emoji + ":" } UI.EnabledEmojisSet = container.SetOf(UI.EnabledEmojis...) }