mirror of
1
Fork 0

Merge pull request '[PORT] Replace DateTime with proper functions (gitea#32402)' (#5796) from gusted/forgejo-port-dateutils into forgejo

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/5796
Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org>
Reviewed-by: Otto <otto@codeberg.org>
This commit is contained in:
Otto 2024-11-05 21:46:29 +00:00
commit f28e728317
39 changed files with 144 additions and 80 deletions

View File

@ -52,6 +52,7 @@ func NewFuncMap() template.FuncMap {
"StringUtils": NewStringUtils, "StringUtils": NewStringUtils,
"SliceUtils": NewSliceUtils, "SliceUtils": NewSliceUtils,
"JsonUtils": NewJsonUtils, "JsonUtils": NewJsonUtils,
"DateUtils": NewDateUtils,
// ----------------------------------------------------------------- // -----------------------------------------------------------------
// svg / avatar / icon / color // svg / avatar / icon / color
@ -68,7 +69,7 @@ func NewFuncMap() template.FuncMap {
"CountFmt": base.FormatNumberSI, "CountFmt": base.FormatNumberSI,
"TimeSince": timeutil.TimeSince, "TimeSince": timeutil.TimeSince,
"TimeSinceUnix": timeutil.TimeSinceUnix, "TimeSinceUnix": timeutil.TimeSinceUnix,
"DateTime": timeutil.DateTime, "DateTime": dateTimeLegacy, // for backward compatibility only, do not use it anymore
"Sec2Time": util.SecToTime, "Sec2Time": util.SecToTime,
"LoadTimes": func(startTime time.Time) string { "LoadTimes": func(startTime time.Time) string {
return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms" return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms"

View File

@ -0,0 +1,60 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package templates
import (
"context"
"html/template"
"time"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
)
type DateUtils struct {
ctx context.Context
}
func NewDateUtils(ctx context.Context) *DateUtils {
return &DateUtils{ctx}
}
// AbsoluteShort renders in "Jan 01, 2006" format
func (du *DateUtils) AbsoluteShort(time any) template.HTML {
return timeutil.DateTime("short", time)
}
// AbsoluteLong renders in "January 01, 2006" format
func (du *DateUtils) AbsoluteLong(time any) template.HTML {
return timeutil.DateTime("long", time)
}
// FullTime renders in "Jan 01, 2006 20:33:44" format
func (du *DateUtils) FullTime(time any) template.HTML {
return timeutil.DateTime("full", time)
}
// ParseLegacy parses the datetime in legacy format, eg: "2016-01-02" in server's timezone.
// It shouldn't be used in new code. New code should use Time or TimeStamp as much as possible.
func (du *DateUtils) ParseLegacy(datetime string) time.Time {
return parseLegacy(datetime)
}
func parseLegacy(datetime string) time.Time {
t, err := time.Parse(time.RFC3339, datetime)
if err != nil {
t, _ = time.ParseInLocation(time.DateOnly, datetime, setting.DefaultUILocation)
}
return t
}
func dateTimeLegacy(format string, datetime any, _ ...string) template.HTML {
if !setting.IsProd || setting.IsInTesting {
panic("dateTimeLegacy is for backward compatibility only, do not use it in new code")
}
if s, ok := datetime.(string); ok {
datetime = parseLegacy(s)
}
return timeutil.DateTime(format, datetime)
}

View File

@ -1,47 +1,61 @@
// Copyright 2023 The Gitea Authors. All rights reserved. // Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
package timeutil package templates
import ( import (
"html/template"
"testing" "testing"
"time" "time"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/modules/timeutil"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestDateTime(t *testing.T) { func TestDateTime(t *testing.T) {
testTz, _ := time.LoadLocation("America/New_York") testTz, err := time.LoadLocation("America/New_York")
require.NoError(t, err)
defer test.MockVariableValue(&setting.DefaultUILocation, testTz)() defer test.MockVariableValue(&setting.DefaultUILocation, testTz)()
defer test.MockVariableValue(&setting.IsInTesting, false)()
du := NewDateUtils(nil)
refTimeStr := "2018-01-01T00:00:00Z" refTimeStr := "2018-01-01T00:00:00Z"
refDateStr := "2018-01-01" refDateStr := "2018-01-01"
refTime, _ := time.Parse(time.RFC3339, refTimeStr) refTime, _ := time.Parse(time.RFC3339, refTimeStr)
refTimeStamp := TimeStamp(refTime.Unix()) refTimeStamp := timeutil.TimeStamp(refTime.Unix())
assert.EqualValues(t, "-", DateTime("short", nil)) for _, val := range []any{nil, 0, time.Time{}, timeutil.TimeStamp(0)} {
assert.EqualValues(t, "-", DateTime("short", 0)) for _, fun := range []func(val any) template.HTML{du.AbsoluteLong, du.AbsoluteShort, du.FullTime} {
assert.EqualValues(t, "-", DateTime("short", time.Time{})) assert.EqualValues(t, "-", fun(val))
assert.EqualValues(t, "-", DateTime("short", TimeStamp(0))) }
}
actual := DateTime("short", "invalid") actual := dateTimeLegacy("short", "invalid")
assert.EqualValues(t, `<absolute-date weekday="" year="numeric" month="short" day="numeric" date="invalid">invalid</absolute-date>`, actual) assert.EqualValues(t, `-`, actual)
actual = DateTime("short", refTimeStr) actual = dateTimeLegacy("short", refTimeStr)
assert.EqualValues(t, `<absolute-date weekday="" year="numeric" month="short" day="numeric" date="2018-01-01T00:00:00Z">2018-01-01T00:00:00Z</absolute-date>`, actual)
actual = DateTime("short", refTime)
assert.EqualValues(t, `<absolute-date weekday="" year="numeric" month="short" day="numeric" date="2018-01-01T00:00:00Z">2018-01-01</absolute-date>`, actual) assert.EqualValues(t, `<absolute-date weekday="" year="numeric" month="short" day="numeric" date="2018-01-01T00:00:00Z">2018-01-01</absolute-date>`, actual)
actual = DateTime("short", refDateStr) actual = du.AbsoluteShort(refTime)
assert.EqualValues(t, `<absolute-date weekday="" year="numeric" month="short" day="numeric" date="2018-01-01">2018-01-01</absolute-date>`, actual) assert.EqualValues(t, `<absolute-date weekday="" year="numeric" month="short" day="numeric" date="2018-01-01T00:00:00Z">2018-01-01</absolute-date>`, actual)
actual = DateTime("short", refTimeStamp) actual = du.AbsoluteLong(refTime)
assert.EqualValues(t, `<absolute-date weekday="" year="numeric" month="long" day="numeric" date="2018-01-01T00:00:00Z">2018-01-01</absolute-date>`, actual)
actual = dateTimeLegacy("short", refDateStr)
assert.EqualValues(t, `<absolute-date weekday="" year="numeric" month="short" day="numeric" date="2018-01-01T00:00:00-05:00">2018-01-01</absolute-date>`, actual)
actual = du.AbsoluteShort(refTimeStamp)
assert.EqualValues(t, `<absolute-date weekday="" year="numeric" month="short" day="numeric" date="2017-12-31T19:00:00-05:00">2017-12-31</absolute-date>`, actual) assert.EqualValues(t, `<absolute-date weekday="" year="numeric" month="short" day="numeric" date="2017-12-31T19:00:00-05:00">2017-12-31</absolute-date>`, actual)
actual = DateTime("full", refTimeStamp) actual = du.AbsoluteLong(refTimeStamp)
assert.EqualValues(t, `<absolute-date weekday="" year="numeric" month="long" day="numeric" date="2017-12-31T19:00:00-05:00">2017-12-31</absolute-date>`, actual)
actual = du.FullTime(refTimeStamp)
assert.EqualValues(t, `<relative-time weekday="" year="numeric" format="datetime" month="short" day="numeric" hour="numeric" minute="numeric" second="numeric" data-tooltip-content data-tooltip-interactive="true" datetime="2017-12-31T19:00:00-05:00">2017-12-31 19:00:00 -05:00</relative-time>`, actual) assert.EqualValues(t, `<relative-time weekday="" year="numeric" format="datetime" month="short" day="numeric" hour="numeric" minute="numeric" second="numeric" data-tooltip-content data-tooltip-interactive="true" datetime="2017-12-31T19:00:00-05:00">2017-12-31 19:00:00 -05:00</relative-time>`, actual)
} }

View File

@ -12,9 +12,7 @@ import (
) )
// DateTime renders an absolute time HTML element by datetime. // DateTime renders an absolute time HTML element by datetime.
func DateTime(format string, datetime any, extraAttrs ...string) template.HTML { func DateTime(format string, datetime any) template.HTML {
// TODO: remove the extraAttrs argument, it's not used in any call to DateTime
if p, ok := datetime.(*time.Time); ok { if p, ok := datetime.(*time.Time); ok {
datetime = *p datetime = *p
} }
@ -34,9 +32,6 @@ func DateTime(format string, datetime any, extraAttrs ...string) template.HTML {
switch v := datetime.(type) { switch v := datetime.(type) {
case nil: case nil:
return "-" return "-"
case string:
datetimeEscaped = html.EscapeString(v)
textEscaped = datetimeEscaped
case time.Time: case time.Time:
if v.IsZero() || v.Unix() == 0 { if v.IsZero() || v.Unix() == 0 {
return "-" return "-"
@ -51,10 +46,7 @@ func DateTime(format string, datetime any, extraAttrs ...string) template.HTML {
panic(fmt.Sprintf("Unsupported time type %T", datetime)) panic(fmt.Sprintf("Unsupported time type %T", datetime))
} }
attrs := make([]string, 0, 10+len(extraAttrs)) attrs := []string{`weekday=""`, `year="numeric"`}
attrs = append(attrs, extraAttrs...)
attrs = append(attrs, `weekday=""`, `year="numeric"`)
switch format { switch format {
case "short", "long": // date only case "short", "long": // date only
attrs = append(attrs, `month="`+format+`"`, `day="numeric"`) attrs = append(attrs, `month="`+format+`"`, `day="numeric"`)

View File

@ -48,8 +48,8 @@ func Activity(ctx *context.Context) {
ctx.Data["Period"] = "weekly" ctx.Data["Period"] = "weekly"
timeFrom = timeUntil.Add(-time.Hour * 168) timeFrom = timeUntil.Add(-time.Hour * 168)
} }
ctx.Data["DateFrom"] = timeFrom.UTC().Format(time.RFC3339) ctx.Data["DateFrom"] = timeFrom
ctx.Data["DateUntil"] = timeUntil.UTC().Format(time.RFC3339) ctx.Data["DateUntil"] = timeUntil
ctx.Data["PeriodText"] = ctx.Tr("repo.activity.period." + ctx.Data["Period"].(string)) ctx.Data["PeriodText"] = ctx.Tr("repo.activity.period." + ctx.Data["Period"].(string))
var err error var err error

View File

@ -102,6 +102,7 @@ func NewTemplateContextForWeb(ctx *Context) TemplateContext {
tmplCtx := NewTemplateContext(ctx) tmplCtx := NewTemplateContext(ctx)
tmplCtx["Locale"] = ctx.Base.Locale tmplCtx["Locale"] = ctx.Base.Locale
tmplCtx["AvatarUtils"] = templates.NewAvatarUtils(ctx) tmplCtx["AvatarUtils"] = templates.NewAvatarUtils(ctx)
tmplCtx["DateUtils"] = templates.NewDateUtils(ctx)
return tmplCtx return tmplCtx
} }

View File

@ -26,8 +26,8 @@
<td><a href="{{AppSubUrl}}/admin/auths/{{.ID}}">{{.Name}}</a></td> <td><a href="{{AppSubUrl}}/admin/auths/{{.ID}}">{{.Name}}</a></td>
<td>{{.TypeName}}</td> <td>{{.TypeName}}</td>
<td>{{if .IsActive}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</td> <td>{{if .IsActive}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</td>
<td>{{DateTime "short" .UpdatedUnix}}</td> <td>{{ctx.DateUtils.AbsoluteShort .UpdatedUnix}}</td>
<td>{{DateTime "short" .CreatedUnix}}</td> <td>{{ctx.DateUtils.AbsoluteShort .CreatedUnix}}</td>
<td><a href="{{AppSubUrl}}/admin/auths/{{.ID}}">{{svg "octicon-pencil"}}</a></td> <td><a href="{{AppSubUrl}}/admin/auths/{{.ID}}">{{svg "octicon-pencil"}}</a></td>
</tr> </tr>
{{end}} {{end}}

View File

@ -23,8 +23,8 @@
<td><button type="submit" class="ui primary button" name="op" value="{{.Name}}" title="{{ctx.Locale.Tr "admin.dashboard.operation_run"}}">{{svg "octicon-triangle-right"}}</button></td> <td><button type="submit" class="ui primary button" name="op" value="{{.Name}}" title="{{ctx.Locale.Tr "admin.dashboard.operation_run"}}">{{svg "octicon-triangle-right"}}</button></td>
<td>{{ctx.Locale.Tr (printf "admin.dashboard.%s" .Name)}}</td> <td>{{ctx.Locale.Tr (printf "admin.dashboard.%s" .Name)}}</td>
<td>{{.Spec}}</td> <td>{{.Spec}}</td>
<td>{{DateTime "full" .Next}}</td> <td>{{ctx.DateUtils.FullTime .Next}}</td>
<td>{{if gt .Prev.Year 1}}{{DateTime "full" .Prev}}{{else}}-{{end}}</td> <td>{{if gt .Prev.Year 1}}{{ctx.DateUtils.FullTime .Prev}}{{else}}-{{end}}</td>
<td>{{.ExecTimes}}</td> <td>{{.ExecTimes}}</td>
<td {{if ne .Status ""}}data-tooltip-content="{{.FormatLastMessage ctx.Locale}}"{{end}} >{{if eq .Status ""}}{{else if eq .Status "finished"}}{{svg "octicon-check" 16}}{{else}}{{svg "octicon-x" 16}}{{end}}</td> <td {{if ne .Status ""}}data-tooltip-content="{{.FormatLastMessage ctx.Locale}}"{{end}} >{{if eq .Status ""}}{{else if eq .Status "finished"}}{{svg "octicon-check" 16}}{{else}}{{svg "octicon-x" 16}}{{end}}</td>
</tr> </tr>

View File

@ -21,7 +21,7 @@
<td>{{.ID}}</td> <td>{{.ID}}</td>
<td>{{ctx.Locale.Tr .TrStr}}</td> <td>{{ctx.Locale.Tr .TrStr}}</td>
<td class="view-detail auto-ellipsis tw-w-4/5"><span class="notice-description">{{.Description}}</span></td> <td class="view-detail auto-ellipsis tw-w-4/5"><span class="notice-description">{{.Description}}</span></td>
<td nowrap>{{DateTime "short" .CreatedUnix}}</td> <td nowrap>{{ctx.DateUtils.AbsoluteShort .CreatedUnix}}</td>
<td class="view-detail"><a href="#">{{svg "octicon-note" 16}}</a></td> <td class="view-detail"><a href="#">{{svg "octicon-note" 16}}</a></td>
</tr> </tr>
{{end}} {{end}}

View File

@ -63,7 +63,7 @@
<td>{{.NumTeams}}</td> <td>{{.NumTeams}}</td>
<td>{{.NumMembers}}</td> <td>{{.NumMembers}}</td>
<td>{{.NumRepos}}</td> <td>{{.NumRepos}}</td>
<td>{{DateTime "short" .CreatedUnix}}</td> <td>{{ctx.DateUtils.AbsoluteShort .CreatedUnix}}</td>
<td><a href="{{.OrganisationLink}}/settings" data-tooltip-content="{{ctx.Locale.Tr "edit"}}">{{svg "octicon-pencil"}}</a></td> <td><a href="{{.OrganisationLink}}/settings" data-tooltip-content="{{ctx.Locale.Tr "edit"}}">{{svg "octicon-pencil"}}</a></td>
</tr> </tr>
{{end}} {{end}}

View File

@ -71,7 +71,7 @@
{{end}} {{end}}
</td> </td>
<td>{{ctx.Locale.TrSize .CalculateBlobSize}}</td> <td>{{ctx.Locale.TrSize .CalculateBlobSize}}</td>
<td>{{DateTime "short" .Version.CreatedUnix}}</td> <td>{{ctx.DateUtils.AbsoluteShort .Version.CreatedUnix}}</td>
<td><a class="delete-button" href="" data-url="{{$.Link}}/delete?page={{$.Page.Paginater.Current}}&sort={{$.SortType}}" data-id="{{.Version.ID}}" data-name="{{.Package.Name}}" data-data-version="{{.Version.Version}}">{{svg "octicon-trash"}}</a></td> <td><a class="delete-button" href="" data-url="{{$.Link}}/delete?page={{$.Page.Paginater.Current}}&sort={{$.SortType}}" data-id="{{.Version.ID}}" data-name="{{.Package.Name}}" data-data-version="{{.Version.Version}}">{{svg "octicon-trash"}}</a></td>
</tr> </tr>
{{end}} {{end}}

View File

@ -82,8 +82,8 @@
<td>{{.NumIssues}}</td> <td>{{.NumIssues}}</td>
<td>{{ctx.Locale.TrSize .GitSize}}</td> <td>{{ctx.Locale.TrSize .GitSize}}</td>
<td>{{ctx.Locale.TrSize .LFSSize}}</td> <td>{{ctx.Locale.TrSize .LFSSize}}</td>
<td>{{DateTime "short" .UpdatedUnix}}</td> <td>{{ctx.DateUtils.AbsoluteShort .UpdatedUnix}}</td>
<td>{{DateTime "short" .CreatedUnix}}</td> <td>{{ctx.DateUtils.AbsoluteShort .CreatedUnix}}</td>
<td><a class="delete-button" href="" data-url="{{$.Link}}/delete?page={{$.Page.Paginater.Current}}&sort={{$.SortType}}" data-id="{{.ID}}" data-name="{{.Name}}">{{svg "octicon-trash"}}</a></td> <td><a class="delete-button" href="" data-url="{{$.Link}}/delete?page={{$.Page.Paginater.Current}}&sort={{$.SortType}}" data-id="{{.ID}}" data-name="{{.Name}}">{{svg "octicon-trash"}}</a></td>
</tr> </tr>
{{end}} {{end}}

View File

@ -96,9 +96,9 @@
<td>{{if .IsActive}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</td> <td>{{if .IsActive}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</td>
<td>{{if .IsRestricted}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</td> <td>{{if .IsRestricted}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</td>
<td>{{if index $.UsersTwoFaStatus .ID}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</td> <td>{{if index $.UsersTwoFaStatus .ID}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</td>
<td>{{DateTime "short" .CreatedUnix}}</td> <td>{{ctx.DateUtils.AbsoluteShort .CreatedUnix}}</td>
{{if .LastLoginUnix}} {{if .LastLoginUnix}}
<td>{{DateTime "short" .LastLoginUnix}}</td> <td>{{ctx.DateUtils.AbsoluteShort .LastLoginUnix}}</td>
{{else}} {{else}}
<td><span>{{ctx.Locale.Tr "admin.users.never_login"}}</span></td> <td><span>{{ctx.Locale.Tr "admin.users.never_login"}}</span></td>
{{end}} {{end}}

View File

@ -21,7 +21,7 @@
<a href="mailto:{{.Email}}">{{.Email}}</a> <a href="mailto:{{.Email}}">{{.Email}}</a>
</span> </span>
{{end}} {{end}}
<span class="flex-text-inline">{{svg "octicon-calendar"}}{{ctx.Locale.Tr "user.joined_on" (DateTime "short" .CreatedUnix)}}</span> <span class="flex-text-inline">{{svg "octicon-calendar"}}{{ctx.Locale.Tr "user.joined_on" (ctx.DateUtils.AbsoluteShort .CreatedUnix)}}</span>
</div> </div>
</div> </div>
</div> </div>

View File

@ -22,7 +22,7 @@
<td><a href="{{.VersionWebLink}}">{{.Version.Version}}</a></td> <td><a href="{{.VersionWebLink}}">{{.Version.Version}}</a></td>
<td><a href="{{.Creator.HomeLink}}">{{.Creator.Name}}</a></td> <td><a href="{{.Creator.HomeLink}}">{{.Creator.Name}}</a></td>
<td>{{ctx.Locale.TrSize .CalculateBlobSize}}</td> <td>{{ctx.Locale.TrSize .CalculateBlobSize}}</td>
<td>{{DateTime "short" .Version.CreatedUnix}}</td> <td>{{ctx.DateUtils.AbsoluteShort .Version.CreatedUnix}}</td>
</tr> </tr>
{{else}} {{else}}
<tr> <tr>

View File

@ -94,7 +94,7 @@
{{range .LatestVersions}} {{range .LatestVersions}}
<div class="item tw-flex"> <div class="item tw-flex">
<a class="tw-flex-1 gt-ellipsis" title="{{.Version}}" href="{{$.PackageDescriptor.PackageWebLink}}/{{PathEscape .LowerVersion}}">{{.Version}}</a> <a class="tw-flex-1 gt-ellipsis" title="{{.Version}}" href="{{$.PackageDescriptor.PackageWebLink}}/{{PathEscape .LowerVersion}}">{{.Version}}</a>
<span class="text small">{{DateTime "short" .CreatedUnix}}</span> <span class="text small">{{ctx.DateUtils.AbsoluteShort .CreatedUnix}}</span>
</div> </div>
{{end}} {{end}}
</div> </div>

View File

@ -212,7 +212,7 @@
{{if .Repository.ArchivedUnix.IsZero}} {{if .Repository.ArchivedUnix.IsZero}}
{{ctx.Locale.Tr "repo.archive.title"}} {{ctx.Locale.Tr "repo.archive.title"}}
{{else}} {{else}}
{{ctx.Locale.Tr "repo.archive.title_date" (DateTime "long" .Repository.ArchivedUnix)}} {{ctx.Locale.Tr "repo.archive.title_date" (ctx.DateUtils.AbsoluteLong .Repository.ArchivedUnix)}}
{{end}} {{end}}
</div> </div>
{{end}} {{end}}

View File

@ -10,7 +10,7 @@
{{if .Repository.ArchivedUnix.IsZero}} {{if .Repository.ArchivedUnix.IsZero}}
{{ctx.Locale.Tr "repo.archive.title"}} {{ctx.Locale.Tr "repo.archive.title"}}
{{else}} {{else}}
{{ctx.Locale.Tr "repo.archive.title_date" (DateTime "long" .Repository.ArchivedUnix)}} {{ctx.Locale.Tr "repo.archive.title_date" (ctx.DateUtils.AbsoluteLong .Repository.ArchivedUnix)}}
{{end}} {{end}}
</div> </div>
{{end}} {{end}}

View File

@ -71,7 +71,7 @@
{{$userName}} {{$userName}}
{{end}} {{end}}
</span> </span>
<span class="time tw-flex tw-items-center">{{DateTime "full" $commit.Date}}</span> <span class="time tw-flex tw-items-center">{{ctx.DateUtils.FullTime $commit.Date}}</span>
{{end}} {{end}}
</li> </li>
{{end}} {{end}}

View File

@ -53,7 +53,7 @@
{{if .Repository.ArchivedUnix.IsZero}} {{if .Repository.ArchivedUnix.IsZero}}
{{ctx.Locale.Tr "repo.archive.title"}} {{ctx.Locale.Tr "repo.archive.title"}}
{{else}} {{else}}
{{ctx.Locale.Tr "repo.archive.title_date" (DateTime "long" .Repository.ArchivedUnix)}} {{ctx.Locale.Tr "repo.archive.title_date" (ctx.DateUtils.AbsoluteLong .Repository.ArchivedUnix)}}
{{end}} {{end}}
</div> </div>
{{end}} {{end}}

View File

@ -38,7 +38,7 @@
{{if .Milestone.DeadlineString}} {{if .Milestone.DeadlineString}}
<span{{if .IsOverdue}} class="text red"{{end}}> <span{{if .IsOverdue}} class="text red"{{end}}>
{{svg "octicon-calendar"}} {{svg "octicon-calendar"}}
{{DateTime "short" .Milestone.DeadlineString}} {{ctx.DateUtils.AbsoluteShort (.Milestone.DeadlineString|ctx.DateUtils.ParseLegacy)}}
</span> </span>
{{else}} {{else}}
{{svg "octicon-calendar"}} {{svg "octicon-calendar"}}

View File

@ -61,7 +61,7 @@
{{if .DeadlineString}} {{if .DeadlineString}}
<span class="flex-text-inline {{if .IsOverdue}}text red{{end}}"> <span class="flex-text-inline {{if .IsOverdue}}text red{{end}}">
{{svg "octicon-calendar" 14}} {{svg "octicon-calendar" 14}}
{{DateTime "short" .DeadlineString}} {{ctx.DateUtils.AbsoluteShort (.DeadlineString|ctx.DateUtils.ParseLegacy)}}
</span> </span>
{{else}} {{else}}
{{svg "octicon-calendar" 14}} {{svg "octicon-calendar" 14}}

View File

@ -300,7 +300,8 @@
{{template "shared/user/avatarlink" dict "user" .Poster}} {{template "shared/user/avatarlink" dict "user" .Poster}}
<span class="text grey muted-links"> <span class="text grey muted-links">
{{template "shared/user/authorlink" .Poster}} {{template "shared/user/authorlink" .Poster}}
{{ctx.Locale.Tr "repo.issues.due_date_added" (DateTime "long" .Content) $createdStr}} {{$dueDate := ctx.DateUtils.AbsoluteLong (.Content|ctx.DateUtils.ParseLegacy)}}
{{ctx.Locale.Tr "repo.issues.due_date_added" $dueDate $createdStr}}
</span> </span>
</div> </div>
{{else if eq .Type 17}} {{else if eq .Type 17}}
@ -311,8 +312,8 @@
{{template "shared/user/authorlink" .Poster}} {{template "shared/user/authorlink" .Poster}}
{{$parsedDeadline := StringUtils.Split .Content "|"}} {{$parsedDeadline := StringUtils.Split .Content "|"}}
{{if eq (len $parsedDeadline) 2}} {{if eq (len $parsedDeadline) 2}}
{{$from := DateTime "long" (index $parsedDeadline 1)}} {{$to := ctx.DateUtils.AbsoluteLong ((index $parsedDeadline 0)|ctx.DateUtils.ParseLegacy)}}
{{$to := DateTime "long" (index $parsedDeadline 0)}} {{$from := ctx.DateUtils.AbsoluteLong ((index $parsedDeadline 1)|ctx.DateUtils.ParseLegacy)}}
{{ctx.Locale.Tr "repo.issues.due_date_modified" $to $from $createdStr}} {{ctx.Locale.Tr "repo.issues.due_date_modified" $to $from $createdStr}}
{{end}} {{end}}
</span> </span>
@ -323,7 +324,8 @@
{{template "shared/user/avatarlink" dict "user" .Poster}} {{template "shared/user/avatarlink" dict "user" .Poster}}
<span class="text grey muted-links"> <span class="text grey muted-links">
{{template "shared/user/authorlink" .Poster}} {{template "shared/user/authorlink" .Poster}}
{{ctx.Locale.Tr "repo.issues.due_date_remove" (DateTime "long" .Content) $createdStr}} {{$dueDate := ctx.DateUtils.AbsoluteLong (.Content|ctx.DateUtils.ParseLegacy)}}
{{ctx.Locale.Tr "repo.issues.due_date_remove" $dueDate $createdStr}}
</span> </span>
</div> </div>
{{else if eq .Type 19}} {{else if eq .Type 19}}

View File

@ -9,7 +9,7 @@
<div class="tw-flex tw-justify-between tw-items-center"> <div class="tw-flex tw-justify-between tw-items-center">
<div class="due-date {{if .Issue.IsOverdue}}text red{{end}}" {{if .Issue.IsOverdue}}data-tooltip-content="{{ctx.Locale.Tr "repo.issues.due_date_overdue"}}"{{end}}> <div class="due-date {{if .Issue.IsOverdue}}text red{{end}}" {{if .Issue.IsOverdue}}data-tooltip-content="{{ctx.Locale.Tr "repo.issues.due_date_overdue"}}"{{end}}>
{{svg "octicon-calendar" 16 "tw-mr-2"}} {{svg "octicon-calendar" 16 "tw-mr-2"}}
{{DateTime "long" .Issue.DeadlineUnix.FormatDate}} {{ctx.DateUtils.AbsoluteLong .Issue.DeadlineUnix}}
</div> </div>
<div> <div>
{{if and .HasIssuesOrPullsWritePermission (not .Repository.IsArchived)}} {{if and .HasIssuesOrPullsWritePermission (not .Repository.IsArchived)}}

View File

@ -1,5 +1,5 @@
<h2 class="ui header activity-header"> <h2 class="ui header activity-header">
<span>{{DateTime "long" .DateFrom}} - {{DateTime "long" .DateUntil}}</span> <span>{{ctx.DateUtils.AbsoluteLong .DateFrom}} - {{ctx.DateUtils.AbsoluteLong .DateUntil}}</span>
<!-- Period --> <!-- Period -->
<div class="ui floating dropdown jump filter"> <div class="ui floating dropdown jump filter">
<div class="ui basic compact button"> <div class="ui basic compact button">

View File

@ -55,7 +55,7 @@
{{.Fingerprint}} {{.Fingerprint}}
</div> </div>
<div class="flex-item-body"> <div class="flex-item-body">
<p>{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix)}}{{svg "octicon-info"}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="text green"{{end}}>{{DateTime "short" .UpdatedUnix}}</span>{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}} - <span>{{ctx.Locale.Tr "settings.can_read_info"}}{{if not .IsReadOnly}} / {{ctx.Locale.Tr "settings.can_write_info"}} {{end}}</span></p> <p>{{ctx.Locale.Tr "settings.added_on" (ctx.DateUtils.AbsoluteShort .CreatedUnix)}} {{svg "octicon-info"}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="text green"{{end}}>{{ctx.DateUtils.AbsoluteShort .UpdatedUnix}}</span>{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}} - <span>{{ctx.Locale.Tr "settings.can_read_info"}}{{if not .IsReadOnly}} / {{ctx.Locale.Tr "settings.can_write_info"}} {{end}}</span></p>
</div> </div>
</div> </div>
<div class="flex-item-trailing"> <div class="flex-item-trailing">

View File

@ -154,7 +154,7 @@
<tr> <tr>
<td>{{.PullMirror.RemoteAddress}}</td> <td>{{.PullMirror.RemoteAddress}}</td>
<td>{{ctx.Locale.Tr "repo.settings.mirror_settings.direction.pull"}}</td> <td>{{ctx.Locale.Tr "repo.settings.mirror_settings.direction.pull"}}</td>
<td>{{DateTime "full" .PullMirror.UpdatedUnix}}</td> <td>{{ctx.DateUtils.FullTime .PullMirror.UpdatedUnix}}</td>
<td class="right aligned"> <td class="right aligned">
<form method="post" class="tw-inline-block"> <form method="post" class="tw-inline-block">
{{.CsrfTokenHtml}} {{.CsrfTokenHtml}}
@ -243,9 +243,9 @@
<tr> <tr>
<td class="tw-break-anywhere">{{.RemoteAddress}}</td> <td class="tw-break-anywhere">{{.RemoteAddress}}</td>
<td>{{ctx.Locale.Tr "repo.settings.mirror_settings.direction.push"}}</td> <td>{{ctx.Locale.Tr "repo.settings.mirror_settings.direction.push"}}</td>
<td>{{if .LastUpdateUnix}}{{DateTime "full" .LastUpdateUnix}}{{else}}{{ctx.Locale.Tr "never"}}{{end}} {{if .LastError}}<div class="ui red label" data-tooltip-content="{{.LastError}}">{{ctx.Locale.Tr "error"}}</div>{{end}}</td> <td>{{if .LastUpdateUnix}}{{ctx.DateUtils.FullTime .LastUpdateUnix}}{{else}}{{ctx.Locale.Tr "never"}}{{end}} {{if .LastError}}<div class="ui red label" data-tooltip-content="{{.LastError}}">{{ctx.Locale.Tr "error"}}</div>{{end}}</td>
<td>{{if not (eq (len .GetPublicKey) 0)}}<a data-clipboard-text="{{.GetPublicKey}}">{{ctx.Locale.Tr "repo.settings.mirror_settings.push_mirror.copy_public_key"}}</a>{{else}}{{ctx.Locale.Tr "repo.settings.mirror_settings.push_mirror.none_ssh"}}{{end}}</td> <td>{{if not (eq (len .GetPublicKey) 0)}}<a data-clipboard-text="{{.GetPublicKey}}">{{ctx.Locale.Tr "repo.settings.mirror_settings.push_mirror.copy_public_key"}}</a>{{else}}{{ctx.Locale.Tr "repo.settings.mirror_settings.push_mirror.none_ssh"}}{{end}}</td>
<td class="right aligned df"> <td class="right aligned">
<button <button
class="ui tiny button show-modal" class="ui tiny button show-modal"
data-modal="#push-mirror-edit-modal" data-modal="#push-mirror-edit-modal"

View File

@ -20,7 +20,7 @@
{{else if .Location}} {{else if .Location}}
{{svg "octicon-location"}} {{.Location}} {{svg "octicon-location"}} {{.Location}}
{{else}} {{else}}
{{svg "octicon-calendar"}} {{ctx.Locale.Tr "user.joined_on" (DateTime "short" .CreatedUnix)}} {{svg "octicon-calendar"}} {{ctx.Locale.Tr "user.joined_on" (ctx.DateUtils.AbsoluteShort .CreatedUnix)}}
{{end}} {{end}}
</div> </div>
</div> </div>

View File

@ -117,7 +117,7 @@
<span class="due-date flex-text-inline" data-tooltip-content="{{ctx.Locale.Tr "repo.issues.due_date"}}"> <span class="due-date flex-text-inline" data-tooltip-content="{{ctx.Locale.Tr "repo.issues.due_date"}}">
<span{{if .IsOverdue}} class="text red"{{end}}> <span{{if .IsOverdue}} class="text red"{{end}}>
{{svg "octicon-calendar" 14}} {{svg "octicon-calendar" 14}}
{{DateTime "short" (.DeadlineUnix.FormatDate)}} {{ctx.DateUtils.AbsoluteShort .DeadlineUnix}}
</span> </span>
</span> </span>
{{end}} {{end}}

View File

@ -28,7 +28,7 @@
</div> </div>
<div class="flex-item-trailing"> <div class="flex-item-trailing">
<span class="color-text-light-2"> <span class="color-text-light-2">
{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix)}} {{ctx.Locale.Tr "settings.added_on" (ctx.DateUtils.AbsoluteShort .CreatedUnix)}}
</span> </span>
<button class="ui btn interact-bg link-action tw-p-2" <button class="ui btn interact-bg link-action tw-p-2"
data-url="{{$.Link}}/delete?id={{.ID}}" data-url="{{$.Link}}/delete?id={{.ID}}"

View File

@ -73,7 +73,7 @@
</li> </li>
{{end}} {{end}}
{{end}} {{end}}
<li>{{svg "octicon-calendar"}} <span>{{ctx.Locale.Tr "user.joined_on" (DateTime "short" .ContextUser.CreatedUnix)}}</span></li> <li>{{svg "octicon-calendar"}} <span>{{ctx.Locale.Tr "user.joined_on" (ctx.DateUtils.AbsoluteShort .ContextUser.CreatedUnix)}}</span></li>
{{if and .Orgs .HasOrgsVisible}} {{if and .Orgs .HasOrgsVisible}}
<li> <li>
<ul class="user-orgs"> <ul class="user-orgs">

View File

@ -30,7 +30,7 @@
</div> </div>
<div class="flex-item-trailing"> <div class="flex-item-trailing">
<span class="color-text-light-2"> <span class="color-text-light-2">
{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix)}} {{ctx.Locale.Tr "settings.added_on" (ctx.DateUtils.AbsoluteShort .CreatedUnix)}}
</span> </span>
<button class="btn interact-bg tw-p-2 show-modal" <button class="btn interact-bg tw-p-2 show-modal"
data-tooltip-content="{{ctx.Locale.Tr "actions.variables.edit"}}" data-tooltip-content="{{ctx.Locale.Tr "actions.variables.edit"}}"

View File

@ -116,7 +116,7 @@
{{if .DeadlineString}} {{if .DeadlineString}}
<span{{if .IsOverdue}} class="text red"{{end}}> <span{{if .IsOverdue}} class="text red"{{end}}>
{{svg "octicon-calendar" 14}} {{svg "octicon-calendar" 14}}
{{DateTime "short" .DeadlineString}} {{ctx.DateUtils.AbsoluteShort (.DeadlineString|ctx.DateUtils.ParseLegacy)}}
</span> </span>
{{else}} {{else}}
{{svg "octicon-calendar" 14}} {{svg "octicon-calendar" 14}}

View File

@ -36,7 +36,7 @@
</ul> </ul>
</details> </details>
<div class="flex-item-body"> <div class="flex-item-body">
<p>{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix)}}{{svg "octicon-info"}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="text green"{{end}}>{{DateTime "short" .UpdatedUnix}}</span>{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}}</p> <p>{{ctx.Locale.Tr "settings.added_on" (ctx.DateUtils.AbsoluteShort .CreatedUnix)}}{{svg "octicon-info"}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="text green"{{end}}>{{ctx.DateUtils.AbsoluteShort .UpdatedUnix}}</span>{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}}</p>
</div> </div>
</div> </div>
<div class="flex-item-trailing"> <div class="flex-item-trailing">

View File

@ -14,7 +14,7 @@
<div class="flex-item-main"> <div class="flex-item-main">
<div class="flex-item-title">{{.Application.Name}}</div> <div class="flex-item-title">{{.Application.Name}}</div>
<div class="flex-item-body"> <div class="flex-item-body">
<p>{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix)}}</p> <p>{{ctx.Locale.Tr "settings.added_on" (ctx.DateUtils.AbsoluteShort .CreatedUnix)}}</p>
</div> </div>
</div> </div>
<div class="flex-item-trailing"> <div class="flex-item-trailing">

View File

@ -63,15 +63,9 @@
<b>{{ctx.Locale.Tr "settings.subkeys"}}:</b> {{range .SubsKey}} {{.PaddedKeyID}} {{end}} <b>{{ctx.Locale.Tr "settings.subkeys"}}:</b> {{range .SubsKey}} {{.PaddedKeyID}} {{end}}
</div> </div>
<div class="flex-item-body"> <div class="flex-item-body">
<p> <p>{{ctx.Locale.Tr "settings.added_on" (ctx.DateUtils.AbsoluteShort .AddedUnix)}}</p>
{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .AddedUnix)}} -
- <p>{{if not .ExpiredUnix.IsZero}}{{ctx.Locale.Tr "settings.valid_until_date" (ctx.DateUtils.AbsoluteShort .ExpiredUnix)}}{{else}}{{ctx.Locale.Tr "settings.valid_forever"}}{{end}}</p>
{{if not .ExpiredUnix.IsZero}}
{{ctx.Locale.Tr "settings.valid_until_date" (DateTime "short" .ExpiredUnix)}}
{{else}}
{{ctx.Locale.Tr "settings.valid_forever"}}
{{end}}
</p>
</div> </div>
</div> </div>
<div class="flex-item-trailing"> <div class="flex-item-trailing">

View File

@ -22,7 +22,7 @@
<div class="flex-item-main"> <div class="flex-item-main">
<div class="flex-item-title">{{.Name}}</div> <div class="flex-item-title">{{.Name}}</div>
<div class="flex-item-body"> <div class="flex-item-body">
<p>{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix)}}{{svg "octicon-info" 16}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="green"{{end}}>{{DateTime "short" .UpdatedUnix}}</span>{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}}</p> <p>{{ctx.Locale.Tr "settings.added_on" (ctx.DateUtils.AbsoluteShort .CreatedUnix)}}{{svg "octicon-info" 16}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="green"{{end}}>{{ctx.DateUtils.AbsoluteShort .UpdatedUnix}}</span>{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}}</p>
</div> </div>
</div> </div>
<div class="flex-item-trailing"> <div class="flex-item-trailing">

View File

@ -53,7 +53,7 @@
{{.Fingerprint}} {{.Fingerprint}}
</div> </div>
<div class="flex-item-body"> <div class="flex-item-body">
<p>{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix)}}{{svg "octicon-info"}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="text green"{{end}}>{{DateTime "short" .UpdatedUnix}}</span>{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}}</p> <p>{{ctx.Locale.Tr "settings.added_on" (ctx.DateUtils.AbsoluteShort .CreatedUnix)}}{{svg "octicon-info"}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="text green"{{end}}>{{ctx.DateUtils.AbsoluteShort .UpdatedUnix}}</span>{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}}</p>
</div> </div>
</div> </div>
<div class="flex-item-trailing"> <div class="flex-item-trailing">

View File

@ -12,7 +12,7 @@
<div class="flex-item-main"> <div class="flex-item-main">
<div class="flex-item-title">{{.Name}}</div> <div class="flex-item-title">{{.Name}}</div>
<div class="flex-item-body"> <div class="flex-item-body">
<p>{{ctx.Locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix)}}</p> <p>{{ctx.Locale.Tr "settings.added_on" (ctx.DateUtils.AbsoluteShort .CreatedUnix)}}</p>
</div> </div>
</div> </div>
<div class="flex-item-trailing"> <div class="flex-item-trailing">