Skip to content

Commit cdc33b2

Browse files
yardenshohamdelvh
andauthored
Add global setting how timestamps should be rendered (#28657)
- Resolves #22493 - Related to #4520 Some admins prefer all timestamps to display the full date instead of relative time. They can do that now by setting ```ini [ui] PREFERRED_TIMESTAMP_TENSE = absolute ``` This setting is set to `mixed` by default, allowing dates to render as "5 hours ago". Here are some screenshots of the UI with this setting set to `absolute`: ![image](https://github.com/go-gitea/gitea/assets/20454870/f496457f-6afa-44be-a1e7-249ee5fe0706) ![image](https://github.com/go-gitea/gitea/assets/20454870/c03b14f5-063d-4e13-9780-76ab002d76a9) ![image](https://github.com/go-gitea/gitea/assets/20454870/f4b34e28-1546-4374-9199-c43348844edd) --------- Signed-off-by: Yarden Shoham <git@yardenshoham.com> Co-authored-by: delvh <dev.lh@web.de>
1 parent f8f394c commit cdc33b2

File tree

7 files changed

+69
-49
lines changed

7 files changed

+69
-49
lines changed

custom/conf/app.example.ini

+4
Original file line numberDiff line numberDiff line change
@@ -1244,6 +1244,10 @@ LEVEL = Info
12441244
;; Change the sort type of the explore pages.
12451245
;; Default is "recentupdate", but you also have "alphabetically", "reverselastlogin", "newest", "oldest".
12461246
;EXPLORE_PAGING_DEFAULT_SORT = recentupdate
1247+
;;
1248+
;; The tense all timestamps should be rendered in. Possible values are `absolute` time (i.e. 1970-01-01, 11:59) and `mixed`.
1249+
;; `mixed` means most timestamps are rendered in relative time (i.e. 2 days ago).
1250+
;PREFERRED_TIMESTAMP_TENSE = mixed
12471251

12481252
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
12491253
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

docs/content/administration/config-cheat-sheet.en-us.md

+1
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
231231
- `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.
232232
A repo is considered irrelevant if it's a fork or if it has no metadata (no description, no icon, no topic).
233233
- `EXPLORE_PAGING_DEFAULT_SORT`: **recentupdate**: Change the sort type of the explore pages. Valid values are "recentupdate", "alphabetically", "reverselastlogin", "newest" and "oldest"
234+
- `PREFERRED_TIMESTAMP_TENSE`: **mixed**: The tense all timestamps should be rendered in. Possible values are `absolute` time (i.e. 1970-01-01, 11:59) and `mixed`. `mixed` means most timestamps are rendered in relative time (i.e. 2 days ago).
234235

235236
### UI - Admin (`ui.admin`)
236237

modules/setting/ui.go

+47-40
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,35 @@ import (
77
"time"
88

99
"code.gitea.io/gitea/modules/container"
10+
"code.gitea.io/gitea/modules/log"
1011
)
1112

1213
// UI settings
1314
var UI = struct {
14-
ExplorePagingNum int
15-
SitemapPagingNum int
16-
IssuePagingNum int
17-
RepoSearchPagingNum int
18-
MembersPagingNum int
19-
FeedMaxCommitNum int
20-
FeedPagingNum int
21-
PackagesPagingNum int
22-
GraphMaxCommitNum int
23-
CodeCommentLines int
24-
ReactionMaxUserNum int
25-
MaxDisplayFileSize int64
26-
ShowUserEmail bool
27-
DefaultShowFullName bool
28-
DefaultTheme string
29-
Themes []string
30-
Reactions []string
31-
ReactionsLookup container.Set[string] `ini:"-"`
32-
CustomEmojis []string
33-
CustomEmojisMap map[string]string `ini:"-"`
34-
SearchRepoDescription bool
35-
OnlyShowRelevantRepos bool
36-
ExploreDefaultSort string `ini:"EXPLORE_PAGING_DEFAULT_SORT"`
15+
ExplorePagingNum int
16+
SitemapPagingNum int
17+
IssuePagingNum int
18+
RepoSearchPagingNum int
19+
MembersPagingNum int
20+
FeedMaxCommitNum int
21+
FeedPagingNum int
22+
PackagesPagingNum int
23+
GraphMaxCommitNum int
24+
CodeCommentLines int
25+
ReactionMaxUserNum int
26+
MaxDisplayFileSize int64
27+
ShowUserEmail bool
28+
DefaultShowFullName bool
29+
DefaultTheme string
30+
Themes []string
31+
Reactions []string
32+
ReactionsLookup container.Set[string] `ini:"-"`
33+
CustomEmojis []string
34+
CustomEmojisMap map[string]string `ini:"-"`
35+
SearchRepoDescription bool
36+
OnlyShowRelevantRepos bool
37+
ExploreDefaultSort string `ini:"EXPLORE_PAGING_DEFAULT_SORT"`
38+
PreferredTimestampTense string
3739

3840
AmbiguousUnicodeDetection bool
3941

@@ -67,23 +69,24 @@ var UI = struct {
6769
Keywords string
6870
} `ini:"ui.meta"`
6971
}{
70-
ExplorePagingNum: 20,
71-
SitemapPagingNum: 20,
72-
IssuePagingNum: 20,
73-
RepoSearchPagingNum: 20,
74-
MembersPagingNum: 20,
75-
FeedMaxCommitNum: 5,
76-
FeedPagingNum: 20,
77-
PackagesPagingNum: 20,
78-
GraphMaxCommitNum: 100,
79-
CodeCommentLines: 4,
80-
ReactionMaxUserNum: 10,
81-
MaxDisplayFileSize: 8388608,
82-
DefaultTheme: `gitea-auto`,
83-
Themes: []string{`gitea-auto`, `gitea-light`, `gitea-dark`},
84-
Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`},
85-
CustomEmojis: []string{`git`, `gitea`, `codeberg`, `gitlab`, `github`, `gogs`},
86-
CustomEmojisMap: map[string]string{"git": ":git:", "gitea": ":gitea:", "codeberg": ":codeberg:", "gitlab": ":gitlab:", "github": ":github:", "gogs": ":gogs:"},
72+
ExplorePagingNum: 20,
73+
SitemapPagingNum: 20,
74+
IssuePagingNum: 20,
75+
RepoSearchPagingNum: 20,
76+
MembersPagingNum: 20,
77+
FeedMaxCommitNum: 5,
78+
FeedPagingNum: 20,
79+
PackagesPagingNum: 20,
80+
GraphMaxCommitNum: 100,
81+
CodeCommentLines: 4,
82+
ReactionMaxUserNum: 10,
83+
MaxDisplayFileSize: 8388608,
84+
DefaultTheme: `gitea-auto`,
85+
Themes: []string{`gitea-auto`, `gitea-light`, `gitea-dark`},
86+
Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`},
87+
CustomEmojis: []string{`git`, `gitea`, `codeberg`, `gitlab`, `github`, `gogs`},
88+
CustomEmojisMap: map[string]string{"git": ":git:", "gitea": ":gitea:", "codeberg": ":codeberg:", "gitlab": ":gitlab:", "github": ":github:", "gogs": ":gogs:"},
89+
PreferredTimestampTense: "mixed",
8790

8891
AmbiguousUnicodeDetection: true,
8992

@@ -142,6 +145,10 @@ func loadUIFrom(rootCfg ConfigProvider) {
142145
UI.DefaultShowFullName = sec.Key("DEFAULT_SHOW_FULL_NAME").MustBool(false)
143146
UI.SearchRepoDescription = sec.Key("SEARCH_REPO_DESCRIPTION").MustBool(true)
144147

148+
if UI.PreferredTimestampTense != "mixed" && UI.PreferredTimestampTense != "absolute" {
149+
log.Fatal("ui.PREFERRED_TIMESTAMP_TENSE must be either 'mixed' or 'absolute'")
150+
}
151+
145152
// OnlyShowRelevantRepos=false is important for many private/enterprise instances,
146153
// because many private repositories do not have "description/topic", users just want to search by their names.
147154
UI.OnlyShowRelevantRepos = sec.Key("ONLY_SHOW_RELEVANT_REPOS").MustBool(false)

modules/timeutil/datetime.go

+7-4
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ import (
77
"fmt"
88
"html"
99
"html/template"
10+
"strings"
1011
"time"
1112
)
1213

1314
// DateTime renders an absolute time HTML element by datetime.
14-
func DateTime(format string, datetime any) template.HTML {
15+
func DateTime(format string, datetime any, attrs ...string) template.HTML {
1516
if p, ok := datetime.(*time.Time); ok {
1617
datetime = *p
1718
}
@@ -48,13 +49,15 @@ func DateTime(format string, datetime any) template.HTML {
4849
panic(fmt.Sprintf("Unsupported time type %T", datetime))
4950
}
5051

52+
extraAttrs := strings.Join(attrs, " ")
53+
5154
switch format {
5255
case "short":
53-
return template.HTML(fmt.Sprintf(`<relative-time format="datetime" year="numeric" month="short" day="numeric" weekday="" datetime="%s">%s</relative-time>`, datetimeEscaped, textEscaped))
56+
return template.HTML(fmt.Sprintf(`<relative-time %s format="datetime" year="numeric" month="short" day="numeric" weekday="" datetime="%s">%s</relative-time>`, extraAttrs, datetimeEscaped, textEscaped))
5457
case "long":
55-
return template.HTML(fmt.Sprintf(`<relative-time format="datetime" year="numeric" month="long" day="numeric" weekday="" datetime="%s">%s</relative-time>`, datetimeEscaped, textEscaped))
58+
return template.HTML(fmt.Sprintf(`<relative-time %s format="datetime" year="numeric" month="long" day="numeric" weekday="" datetime="%s">%s</relative-time>`, extraAttrs, datetimeEscaped, textEscaped))
5659
case "full":
57-
return template.HTML(fmt.Sprintf(`<relative-time format="datetime" weekday="" year="numeric" month="short" day="numeric" hour="numeric" minute="numeric" second="numeric" datetime="%s">%s</relative-time>`, datetimeEscaped, textEscaped))
60+
return template.HTML(fmt.Sprintf(`<relative-time %s format="datetime" weekday="" year="numeric" month="short" day="numeric" hour="numeric" minute="numeric" second="numeric" datetime="%s">%s</relative-time>`, extraAttrs, datetimeEscaped, textEscaped))
5861
}
5962
panic(fmt.Sprintf("Unsupported format %s", format))
6063
}

modules/timeutil/datetime_test.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,17 @@ func TestDateTime(t *testing.T) {
2929
assert.EqualValues(t, "-", DateTime("short", TimeStamp(0)))
3030

3131
actual := DateTime("short", "invalid")
32-
assert.EqualValues(t, `<relative-time format="datetime" year="numeric" month="short" day="numeric" weekday="" datetime="invalid">invalid</relative-time>`, actual)
32+
assert.EqualValues(t, `<relative-time format="datetime" year="numeric" month="short" day="numeric" weekday="" datetime="invalid">invalid</relative-time>`, actual)
3333

3434
actual = DateTime("short", refTimeStr)
35-
assert.EqualValues(t, `<relative-time format="datetime" year="numeric" month="short" day="numeric" weekday="" datetime="2018-01-01T00:00:00Z">2018-01-01T00:00:00Z</relative-time>`, actual)
35+
assert.EqualValues(t, `<relative-time format="datetime" year="numeric" month="short" day="numeric" weekday="" datetime="2018-01-01T00:00:00Z">2018-01-01T00:00:00Z</relative-time>`, actual)
3636

3737
actual = DateTime("short", refTime)
38-
assert.EqualValues(t, `<relative-time format="datetime" year="numeric" month="short" day="numeric" weekday="" datetime="2018-01-01T00:00:00Z">2018-01-01</relative-time>`, actual)
38+
assert.EqualValues(t, `<relative-time format="datetime" year="numeric" month="short" day="numeric" weekday="" datetime="2018-01-01T00:00:00Z">2018-01-01</relative-time>`, actual)
3939

4040
actual = DateTime("short", refTimeStamp)
41-
assert.EqualValues(t, `<relative-time format="datetime" year="numeric" month="short" day="numeric" weekday="" datetime="2017-12-31T19:00:00-05:00">2017-12-31</relative-time>`, actual)
41+
assert.EqualValues(t, `<relative-time format="datetime" year="numeric" month="short" day="numeric" weekday="" datetime="2017-12-31T19:00:00-05:00">2017-12-31</relative-time>`, actual)
4242

4343
actual = DateTime("full", refTimeStamp)
44-
assert.EqualValues(t, `<relative-time format="datetime" weekday="" year="numeric" month="short" day="numeric" hour="numeric" minute="numeric" second="numeric" datetime="2017-12-31T19:00:00-05:00">2017-12-31 19:00:00 -05:00</relative-time>`, actual)
44+
assert.EqualValues(t, `<relative-time format="datetime" weekday="" year="numeric" month="short" day="numeric" hour="numeric" minute="numeric" second="numeric" datetime="2017-12-31T19:00:00-05:00">2017-12-31 19:00:00 -05:00</relative-time>`, actual)
4545
}

modules/timeutil/since.go

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"strings"
1010
"time"
1111

12+
"code.gitea.io/gitea/modules/setting"
1213
"code.gitea.io/gitea/modules/translation"
1314
)
1415

@@ -132,6 +133,9 @@ func timeSinceUnix(then, now time.Time, lang translation.Locale) template.HTML {
132133

133134
// TimeSince renders relative time HTML given a time.Time
134135
func TimeSince(then time.Time, lang translation.Locale) template.HTML {
136+
if setting.UI.PreferredTimestampTense == "absolute" {
137+
return DateTime("full", then, `class="time-since"`)
138+
}
135139
return timeSinceUnix(then, time.Now(), lang)
136140
}
137141

web_src/js/components/DiffCommitSelector.vue

+1
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ export default {
247247
<div class="gt-ellipsis text light-2">
248248
{{ commit.committer_or_author_name }}
249249
<span class="text right">
250+
<!-- TODO: make this respect the PreferredTimestampTense setting -->
250251
<relative-time class="time-since" prefix="" :datetime="commit.time" data-tooltip-content data-tooltip-interactive="true">{{ commit.time }}</relative-time>
251252
</span>
252253
</div>

0 commit comments

Comments
 (0)