mirror of https://github.com/go-gitea/gitea
Commit
This commit is contained in:
parent
f7427d8b50
commit
1cff1a9e05
|
@ -6,12 +6,9 @@
|
|||
package issues
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
|
@ -250,6 +247,7 @@ type Comment struct {
|
|||
Milestone *Milestone `xorm:"-"`
|
||||
TimeID int64
|
||||
Time *TrackedTime `xorm:"-"`
|
||||
TimeTracked int64
|
||||
AssigneeID int64
|
||||
RemovedAssignee bool
|
||||
Assignee *user_model.User `xorm:"-"`
|
||||
|
@ -805,6 +803,7 @@ func CreateComment(ctx context.Context, opts *CreateCommentOptions) (_ *Comment,
|
|||
OldProjectID: opts.OldProjectID,
|
||||
ProjectID: opts.ProjectID,
|
||||
TimeID: opts.TimeID,
|
||||
TimeTracked: opts.TimeTracked,
|
||||
RemovedAssignee: opts.RemovedAssignee,
|
||||
AssigneeID: opts.AssigneeID,
|
||||
AssigneeTeamID: opts.AssigneeTeamID,
|
||||
|
@ -977,6 +976,7 @@ type CreateCommentOptions struct {
|
|||
OldProjectID int64
|
||||
ProjectID int64
|
||||
TimeID int64
|
||||
TimeTracked int64
|
||||
AssigneeID int64
|
||||
AssigneeTeamID int64
|
||||
RemovedAssignee bool
|
||||
|
@ -1259,40 +1259,3 @@ func FixCommentTypeLabelWithOutsideLabels(ctx context.Context) (int64, error) {
|
|||
func (c *Comment) HasOriginalAuthor() bool {
|
||||
return c.OriginalAuthor != "" && c.OriginalAuthorID != 0
|
||||
}
|
||||
|
||||
// TimeEstimateStr returns formatted time estimate string from seconds (e.g. "2 weeks 4 days 12 hours 5 minutes")
|
||||
func (c *Comment) TimeEstimateToStrTranslated(lang translation.Locale) string {
|
||||
var timeParts []string
|
||||
|
||||
timeSeconds := float64(c.TimeEstimate)
|
||||
|
||||
// Format weeks
|
||||
weeks := math.Floor(timeSeconds / (60 * 60 * 24 * 7))
|
||||
if weeks > 0 {
|
||||
timeParts = append(timeParts, lang.Tr("tool.hours", int64(weeks)))
|
||||
}
|
||||
timeSeconds -= weeks * (60 * 60 * 24 * 7)
|
||||
|
||||
// Format days
|
||||
days := math.Floor(timeSeconds / (60 * 60 * 24))
|
||||
if days > 0 {
|
||||
timeParts = append(timeParts, lang.Tr("tool.days", int64(days)))
|
||||
}
|
||||
timeSeconds -= days * (60 * 60 * 24)
|
||||
|
||||
// Format hours
|
||||
hours := math.Floor(timeSeconds / (60 * 60))
|
||||
if hours > 0 {
|
||||
timeParts = append(timeParts, lang.Tr("tool.hours", int64(hours)))
|
||||
}
|
||||
timeSeconds -= hours * (60 * 60)
|
||||
|
||||
// Format minutes
|
||||
minutes := math.Floor(timeSeconds / (60))
|
||||
if minutes > 0 {
|
||||
timeParts = append(timeParts, lang.Tr("tool.minutes", int64(minutes)))
|
||||
}
|
||||
timeSeconds -= minutes * (60)
|
||||
|
||||
return strings.Join(timeParts[:], " ")
|
||||
}
|
||||
|
|
|
@ -197,12 +197,12 @@ func FinishIssueStopwatch(ctx context.Context, user *user_model.User, issue *Iss
|
|||
}
|
||||
|
||||
if _, err := CreateComment(ctx, &CreateCommentOptions{
|
||||
Doer: user,
|
||||
Issue: issue,
|
||||
Repo: issue.Repo,
|
||||
Content: util.SecToTime(timediff),
|
||||
Type: CommentTypeStopTracking,
|
||||
TimeID: tt.ID,
|
||||
Doer: user,
|
||||
Issue: issue,
|
||||
Repo: issue.Repo,
|
||||
Type: CommentTypeStopTracking,
|
||||
TimeID: tt.ID,
|
||||
TimeTracked: tt.Time,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -173,12 +173,12 @@ func AddTime(user *user_model.User, issue *Issue, amount int64, created time.Tim
|
|||
}
|
||||
|
||||
if _, err := CreateComment(ctx, &CreateCommentOptions{
|
||||
Issue: issue,
|
||||
Repo: issue.Repo,
|
||||
Doer: user,
|
||||
Content: util.SecToTime(amount),
|
||||
Type: CommentTypeAddTimeManual,
|
||||
TimeID: t.ID,
|
||||
Issue: issue,
|
||||
Repo: issue.Repo,
|
||||
Doer: user,
|
||||
Type: CommentTypeAddTimeManual,
|
||||
TimeID: t.ID,
|
||||
TimeTracked: t.Time,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -221,7 +221,7 @@ func TotalTimes(options *FindTrackedTimesOptions) (map[*user_model.User]string,
|
|||
}
|
||||
return nil, err
|
||||
}
|
||||
totalTimes[user] = util.SecToTime(total)
|
||||
totalTimes[user] = util.SecToTimeExact(total)
|
||||
}
|
||||
return totalTimes, nil
|
||||
}
|
||||
|
@ -251,11 +251,11 @@ func DeleteIssueUserTimes(issue *Issue, user *user_model.User) error {
|
|||
return err
|
||||
}
|
||||
if _, err := CreateComment(ctx, &CreateCommentOptions{
|
||||
Issue: issue,
|
||||
Repo: issue.Repo,
|
||||
Doer: user,
|
||||
Content: "- " + util.SecToTime(removedTime),
|
||||
Type: CommentTypeDeleteTimeManual,
|
||||
Issue: issue,
|
||||
Repo: issue.Repo,
|
||||
Doer: user,
|
||||
TimeTracked: removedTime,
|
||||
Type: CommentTypeDeleteTimeManual,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -280,11 +280,11 @@ func DeleteTime(t *TrackedTime) error {
|
|||
}
|
||||
|
||||
if _, err := CreateComment(ctx, &CreateCommentOptions{
|
||||
Issue: t.Issue,
|
||||
Repo: t.Issue.Repo,
|
||||
Doer: t.User,
|
||||
Content: "- " + util.SecToTime(t.Time),
|
||||
Type: CommentTypeDeleteTimeManual,
|
||||
Issue: t.Issue,
|
||||
Repo: t.Issue.Repo,
|
||||
Doer: t.User,
|
||||
TimeTracked: t.Time,
|
||||
Type: CommentTypeDeleteTimeManual,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -278,9 +278,10 @@ func NewFuncMap() []template.FuncMap {
|
|||
}
|
||||
return dict, nil
|
||||
},
|
||||
"Printf": fmt.Sprintf,
|
||||
"Escape": Escape,
|
||||
"Sec2Time": util.SecToTime,
|
||||
"Printf": fmt.Sprintf,
|
||||
"Escape": Escape,
|
||||
"Sec2Time": util.SecToTime,
|
||||
"SecToTimeExact": util.SecToTimeExact,
|
||||
"ParseDeadline": func(deadline string) []string {
|
||||
return strings.Split(deadline, "|")
|
||||
},
|
||||
|
@ -549,9 +550,10 @@ func NewTextFuncMap() []texttmpl.FuncMap {
|
|||
}
|
||||
return dict, nil
|
||||
},
|
||||
"Printf": fmt.Sprintf,
|
||||
"Escape": Escape,
|
||||
"Sec2Time": util.SecToTime,
|
||||
"Printf": fmt.Sprintf,
|
||||
"Escape": Escape,
|
||||
"Sec2Time": util.SecToTime,
|
||||
"SecToTimeExact": util.SecToTimeExact,
|
||||
"ParseDeadline": func(deadline string) []string {
|
||||
return strings.Split(deadline, "|")
|
||||
},
|
||||
|
|
|
@ -64,6 +64,41 @@ func SecToTime(duration int64) string {
|
|||
return strings.TrimRight(formattedTime, " ")
|
||||
}
|
||||
|
||||
func SecToTimeExact(duration int64) string {
|
||||
formattedTime := ""
|
||||
|
||||
// The following four variables are calculated by taking
|
||||
// into account the previously calculated variables, this avoids
|
||||
// pitfalls when using remainders. As that could lead to incorrect
|
||||
// results when the calculated number equals the quotient number.
|
||||
remainingDays := duration / (60 * 60 * 24)
|
||||
years := remainingDays / 365
|
||||
remainingDays -= years * 365
|
||||
months := remainingDays * 12 / 365
|
||||
remainingDays -= months * 365 / 12
|
||||
weeks := remainingDays / 7
|
||||
remainingDays -= weeks * 7
|
||||
days := remainingDays
|
||||
|
||||
// The following three variables are calculated without depending
|
||||
// on the previous calculated variables.
|
||||
hours := (duration / 3600) % 24
|
||||
minutes := (duration / 60) % 60
|
||||
seconds := duration % 60
|
||||
|
||||
// Show exact time information
|
||||
formattedTime = formatTime(years, "year", formattedTime)
|
||||
formattedTime = formatTime(months, "month", formattedTime)
|
||||
formattedTime = formatTime(weeks, "week", formattedTime)
|
||||
formattedTime = formatTime(days, "day", formattedTime)
|
||||
formattedTime = formatTime(hours, "hour", formattedTime)
|
||||
formattedTime = formatTime(minutes, "minute", formattedTime)
|
||||
formattedTime = formatTime(seconds, "second", formattedTime)
|
||||
|
||||
// The formatTime() function always appends a space at the end. This will be trimmed
|
||||
return strings.TrimRight(formattedTime, " ")
|
||||
}
|
||||
|
||||
// formatTime appends the given value to the existing forammattedTime. E.g:
|
||||
// formattedTime = "1 year"
|
||||
// input: value = 3, name = "month"
|
||||
|
|
|
@ -1465,7 +1465,7 @@ issues.add_time_hours = Hours
|
|||
issues.add_time_minutes = Minutes
|
||||
issues.add_time_sum_to_small = No time was entered.
|
||||
issues.time_spent_total = Total Time Spent
|
||||
issues.time_spent_from_all_authors = `Total Time Spent: %s`
|
||||
issues.time_spent_from_all_authors = `Total Time Spent:`
|
||||
issues.due_date = Due Date
|
||||
issues.invalid_due_date_format = "Due date format must be 'yyyy-mm-dd'."
|
||||
issues.error_modifying_due_date = "Failed to modify the due date."
|
||||
|
|
|
@ -263,7 +263,7 @@
|
|||
{{template "repo/issue/view_content/comments_delete_time" Dict "ctx" $ "comment" .}}
|
||||
<div class="detail">
|
||||
{{svg "octicon-clock"}}
|
||||
<span class="text grey muted-links">{{.Content}}</span>
|
||||
<span class="text grey muted-links">{{SecToTimeExact .TimeTracked}}</span>
|
||||
</div>
|
||||
</div>
|
||||
{{else if eq .Type 14}}
|
||||
|
@ -277,7 +277,7 @@
|
|||
{{template "repo/issue/view_content/comments_delete_time" Dict "ctx" $ "comment" .}}
|
||||
<div class="detail">
|
||||
{{svg "octicon-clock"}}
|
||||
<span class="text grey muted-links">{{.Content}}</span>
|
||||
<span class="text grey muted-links">{{SecToTimeExact .TimeTracked}}</span>
|
||||
</div>
|
||||
</div>
|
||||
{{else if eq .Type 15}}
|
||||
|
@ -668,7 +668,7 @@
|
|||
</span>
|
||||
<div class="detail">
|
||||
{{svg "octicon-clock"}}
|
||||
<span class="text grey muted-links">{{.Content}}</span>
|
||||
<span class="text grey muted-links">- {{SecToTimeExact .TimeTracked}}</span>
|
||||
</div>
|
||||
</div>
|
||||
{{else if eq .Type 27}}
|
||||
|
@ -802,8 +802,7 @@
|
|||
{{if and (eq .TimeEstimate 0)}}
|
||||
{{$.locale.Tr "repo.issues.remove_time_estimate" $createdStr | Safe}}
|
||||
{{else}}
|
||||
{{$timeStr := .TimeEstimateToStrTranslated $.locale}}
|
||||
{{$.locale.Tr "repo.issues.change_time_estimate_at" $timeStr $createdStr | Safe}}
|
||||
{{$.locale.Tr "repo.issues.change_time_estimate_at" (SecToTimeExact .TimeEstimate) $createdStr | Safe}}
|
||||
{{end}}
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -413,8 +413,9 @@
|
|||
{{if gt (len .WorkingUsers) 0}}
|
||||
<div class="ui divider"></div>
|
||||
<div class="ui comments">
|
||||
<span class="text"><strong>{{.locale.Tr "repo.issues.time_spent_from_all_authors" ($.Issue.TotalTrackedTime | Sec2Time) | Safe}}</strong></span>
|
||||
<div>
|
||||
<div class="text"><strong>{{.locale.Tr "repo.issues.time_spent_from_all_authors" | Safe}}</strong></div>
|
||||
<div>{{SecToTimeExact .Issue.TotalTrackedTime}}</div>
|
||||
<div class="gt-mt-3">
|
||||
{{range $user, $trackedtime := .WorkingUsers}}
|
||||
<div class="comment gt-mt-3">
|
||||
<a class="avatar">
|
||||
|
|
Loading…
Reference in New Issue