Skip to content

WIP: Add Sec2TrackedTime time format template helper #25213

New issue

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

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

Already on GitHub? Sign in to your account

Closed
wants to merge 38 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
3007f78
Add Sec2TrackedTime time-format-func
6543 Jun 12, 2023
3c4ab6c
use in templates
6543 Jun 12, 2023
201e227
Also apply it for sidebar in issue/pull view for single users
6543 Jun 12, 2023
645fe79
add
6543 Jun 12, 2023
4690b36
also use it for timeline comments
6543 Jun 12, 2023
885d41b
Merge branch 'main' into up_format_tracked-time
6543 Jun 13, 2023
1f2bd71
Merge branch 'main' into up_format_tracked-time
6543 Jun 19, 2023
9f7da35
Merge branch 'main' into up_format_tracked-time
6543 Jun 19, 2023
7d41418
frontend: rm dep "pretty-ms"
6543 Jun 19, 2023
82bb7dd
use Sec2TrackedTime for stowpatch init too
6543 Jun 19, 2023
99a50f1
port util.Sec2TrackedTime to javaScript
6543 Jun 19, 2023
4bbfa26
create time.js in utils and use it
6543 Jun 19, 2023
acb7c3f
fix
6543 Jun 19, 2023
868ae80
ignore ms
6543 Jun 19, 2023
6477807
use old format for API
6543 Jun 19, 2023
848c0dd
store timestamp instead of string for CommentTypeStopTracking & Comme…
6543 Jun 19, 2023
95caebf
store and use seconds for timeline time comments
6543 Jun 20, 2023
4df03a3
store and use seconds for timeline time comments
6543 Jun 20, 2023
c0e96f3
next
6543 Jun 20, 2023
5e0e77c
need helper until we convert time in frontend
6543 Jun 20, 2023
3b4a0b8
...
6543 Jun 20, 2023
b2cc1ee
non breaking API
6543 Jun 20, 2023
99fbd23
code format
6543 Jun 20, 2023
81ba06a
adjust test
6543 Jun 20, 2023
d20a89d
Merge branch 'main' into up_format_tracked-time
6543 Jun 20, 2023
7e429ff
Merge branch 'refactor_store_seconds-not-string' into up_format_track…
6543 Jun 20, 2023
a960c2e
Merge branch 'main' into up_format_tracked-time
6543 Jun 23, 2023
e61e1eb
clean
6543 Jun 23, 2023
358cb5e
wip
6543 Jun 23, 2023
919b9d6
Merge branch 'main' into up_format_tracked-time
6543 Jun 26, 2023
a22d5ff
Merge branch 'main' into up_format_tracked-time
6543 Aug 22, 2023
9dcfd38
Merge branch 'main' into up_format_tracked-time
6543 Oct 14, 2023
1ad09f9
Merge branch 'main' into up_format_tracked-time
6543 Oct 20, 2023
bbdd894
Update filters.tmpl
6543 Oct 20, 2023
cc14191
Update list.tmpl
6543 Oct 20, 2023
311ac33
Update milestone_issues.tmpl
6543 Oct 20, 2023
2c5af52
Merge branch 'main' into up_format_tracked-time
6543 Nov 7, 2023
0953506
Merge branch 'main' into up_format_tracked-time
6543 Dec 3, 2023
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
7 changes: 1 addition & 6 deletions models/issues/stopwatch.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,6 @@ func (s Stopwatch) Seconds() int64 {
return int64(timeutil.TimeStampNow() - s.CreatedUnix)
}

// Duration returns a human-readable duration string based on local server time
func (s Stopwatch) Duration() string {
return util.SecToTime(s.Seconds())
}

func getStopwatch(ctx context.Context, userID, issueID int64) (sw *Stopwatch, exists bool, err error) {
sw = new(Stopwatch)
exists, err = db.GetEngine(ctx).
Expand Down Expand Up @@ -215,7 +210,7 @@ func FinishIssueStopwatch(ctx context.Context, user *user_model.User, issue *Iss
Doer: user,
Issue: issue,
Repo: issue.Repo,
Content: util.SecToTime(timediff),
Content: fmt.Sprintf("|%d", timediff),
Type: CommentTypeStopTracking,
TimeID: tt.ID,
}); err != nil {
Expand Down
2 changes: 2 additions & 0 deletions models/user/setting_keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ const (
UserActivityPubPrivPem = "activitypub.priv_pem"
// UserActivityPubPubPem is user's public key
UserActivityPubPubPem = "activitypub.pub_pem"
// SettingsKeyTrackedTimeMaxUnit set how tracked time values are converted from seconds to sting
SettingsKeyTrackedTimeMaxUnit = "tracked_time.max_unit"
)
13 changes: 7 additions & 6 deletions modules/templates/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,13 @@ func NewFuncMap() template.FuncMap {

// -----------------------------------------------------------------
// time / number / format
"FileSize": base.FileSize,
"CountFmt": base.FormatNumberSI,
"TimeSince": timeutil.TimeSince,
"TimeSinceUnix": timeutil.TimeSinceUnix,
"DateTime": timeutil.DateTime,
"Sec2Time": util.SecToTime,
"FileSize": base.FileSize,
"CountFmt": base.FormatNumberSI,
"TimeSince": timeutil.TimeSince,
"TimeSinceUnix": timeutil.TimeSinceUnix,
"DateTime": timeutil.DateTime,
"Sec2Time": util.SecToTime,
"Sec2TrackedTime": util.Sec2TrackedTime,
"LoadTimes": func(startTime time.Time) string {
return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms"
},
Expand Down
41 changes: 37 additions & 4 deletions modules/util/sec_to_time.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import (
)

// SecToTime converts an amount of seconds to a human-readable string. E.g.
// 66s -> 1 minute 6 seconds
// 52410s -> 14 hours 33 minutes
// 563418 -> 6 days 12 hours
// 66s -> 1 minute 6 seconds
// 52410s -> 14 hours 33 minutes
// 563418 -> 6 days 12 hours
// 1563418 -> 2 weeks 4 days
// 3937125s -> 1 month 2 weeks
// 3937125s -> 1 month 2 weeks
// 45677465s -> 1 year 6 months
func SecToTime(durationVal any) string {
duration, _ := ToInt64(durationVal)
Expand Down Expand Up @@ -79,3 +79,36 @@ func formatTime(value int64, name, formattedTime string) string {

return formattedTime
}

// Sec2TrackedTime converts an amount of seconds to a human-readable string. E.g.
// 66s -> 1 minute 6 seconds
// 52410s -> 14 hours 33 minutes
// 563418s -> 156 hours 30 minutes
// 1563418s -> 434 hours 16 minutes
// 3937125s -> 1093 hours 38 minutes
// 45677465s -> 12688 hours 11 minutes
func Sec2TrackedTime(durationVal any) string {
duration, _ := ToInt64(durationVal)

formattedTime := ""

// The following three variables are calculated without depending
// on the previous calculated variables.
hours := (duration / 3600)
minutes := (duration / 60) % 60
seconds := duration % 60

// Extract only the relevant information of the time
// If the time is greater than a year, it makes no sense to display seconds.
switch {
case hours > 0:
formattedTime = formatTime(hours, "hour", formattedTime)
formattedTime = formatTime(minutes, "minute", formattedTime)
default:
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, " ")
}
20 changes: 20 additions & 0 deletions modules/util/sec_to_time_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,23 @@ func TestSecToTime(t *testing.T) {
assert.Equal(t, "11 months", SecToTime(year-25*day))
assert.Equal(t, "1 year 5 months", SecToTime(year+163*day+10*hour+11*minute+5*second))
}

func TestSec2TrackedTime(t *testing.T) {
second := int64(1)
minute := 60 * second
hour := 60 * minute
day := 24 * hour
year := 365 * day

assert.Equal(t, "1 minute 6 seconds", Sec2TrackedTime(minute+6*second))
assert.Equal(t, "1 hour", Sec2TrackedTime(hour))
assert.Equal(t, "1 hour", Sec2TrackedTime(hour+second))
assert.Equal(t, "14 hours 33 minutes", Sec2TrackedTime(14*hour+33*minute+30*second))
assert.Equal(t, "156 hours 30 minutes", Sec2TrackedTime(6*day+12*hour+30*minute+18*second))
assert.Equal(t, "434 hours 16 minutes", Sec2TrackedTime((2*7+4)*day+2*hour+16*minute+58*second))
assert.Equal(t, "672 hours", Sec2TrackedTime(4*7*day))
assert.Equal(t, "696 hours", Sec2TrackedTime((4*7+1)*day))
assert.Equal(t, "1093 hours 38 minutes", Sec2TrackedTime((6*7+3)*day+13*hour+38*minute+45*second))
assert.Equal(t, "8160 hours", Sec2TrackedTime(year-25*day))
assert.Equal(t, "12682 hours 11 minutes", Sec2TrackedTime(year+163*day+10*hour+11*minute+5*second))
}
26 changes: 0 additions & 26 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
"monaco-editor": "0.44.0",
"monaco-editor-webpack-plugin": "7.1.0",
"pdfobject": "2.2.12",
"pretty-ms": "8.0.0",
"sortablejs": "1.15.0",
"swagger-ui-dist": "5.10.0",
"throttle-debounce": "5.0.0",
Expand Down
2 changes: 1 addition & 1 deletion routers/web/repo/issue_timetrack.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,6 @@ func DeleteTime(c *context.Context) {
return
}

c.Flash.Success(c.Tr("repo.issues.del_time_history", util.SecToTime(t.Time)))
c.Flash.Success(c.Tr("repo.issues.del_time_history", util.Sec2TrackedTime(t.Time)))
c.Redirect(issue.Link())
}
6 changes: 6 additions & 0 deletions routers/web/user/setting/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,12 @@ func Appearance(ctx *context.Context) {
return forms.IsUserHiddenCommentTypeGroupChecked(commentTypeGroup, hiddenCommentTypes)
}

ctx.Data["TrackedTimeMaxUnit"], err = user_model.GetUserSetting(ctx.Doer.ID, user_model.SettingsKeyTrackedTimeMaxUnit, "year") // TODO: make default set via system?
if err != nil {
ctx.ServerError("GetUserSetting", err)
return
}

ctx.HTML(http.StatusOK, tplSettingsAppearance)
}

Expand Down
3 changes: 2 additions & 1 deletion services/convert/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
)

func ToIssue(ctx context.Context, issue *issues_model.Issue) *api.Issue {
Expand Down Expand Up @@ -180,7 +181,7 @@ func ToStopWatches(ctx context.Context, sws []*issues_model.Stopwatch) (api.Stop
result = append(result, api.StopWatch{
Created: sw.CreatedUnix.AsTime(),
Seconds: sw.Seconds(),
Duration: sw.Duration(),
Duration: util.SecToTime(sw.Seconds()),
IssueIndex: issue.Index,
IssueTitle: issue.Title,
RepoOwnerName: repo.OwnerName,
Expand Down
2 changes: 1 addition & 1 deletion templates/base/head_navbar.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
{{svg "octicon-issue-opened" 16 "gt-mr-3"}}
<span class="stopwatch-issue">{{.ActiveStopwatch.RepoSlug}}#{{.ActiveStopwatch.IssueIndex}}</span>
<span class="ui primary label stopwatch-time gt-my-0 gt-mx-4" data-seconds="{{.ActiveStopwatch.Seconds}}">
{{if .ActiveStopwatch}}{{Sec2Time .ActiveStopwatch.Seconds}}{{end}}
{{if .ActiveStopwatch}}{{Sec2TrackedTime .ActiveStopwatch.Seconds}}{{end}}
</span>
</a>
<form class="stopwatch-commit" method="post" action="{{.ActiveStopwatch.IssueLink}}/times/stopwatch/toggle">
Expand Down
2 changes: 1 addition & 1 deletion templates/repo/issue/filters.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<div class="ui compact tiny secondary menu">
<span class="item" data-tooltip-content='{{ctx.Locale.Tr "tracked_time_summary"}}'>
{{svg "octicon-clock"}}
{{.TotalTrackedTime | Sec2Time}}
{{.TotalTrackedTime | Sec2TrackedTime}}
</span>
</div>
{{end}}
Expand Down
2 changes: 1 addition & 1 deletion templates/repo/issue/list.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
<div class="ui compact tiny secondary menu">
<span class="item" data-tooltip-content='{{ctx.Locale.Tr "tracked_time_summary"}}'>
{{svg "octicon-clock"}}
{{.TotalTrackedTime | Sec2Time}}
{{.TotalTrackedTime | Sec2TrackedTime}}
</span>
</div>
{{end}}
Expand Down
2 changes: 1 addition & 1 deletion templates/repo/issue/milestone_issues.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
{{if .TotalTrackedTime}}
<div data-tooltip-content='{{ctx.Locale.Tr "tracked_time_summary"}}'>
{{svg "octicon-clock"}}
{{.TotalTrackedTime | Sec2Time}}
{{.TotalTrackedTime | Sec2TrackedTime}}
</div>
{{end}}
</div>
Expand Down
2 changes: 1 addition & 1 deletion templates/repo/issue/milestones.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
{{if .TotalTrackedTime}}
<div class="flex-text-block">
{{svg "octicon-clock"}}
{{.TotalTrackedTime|Sec2Time}}
{{.TotalTrackedTime|Sec2TrackedTime}}
</div>
{{end}}
{{if .UpdatedUnix}}
Expand Down
6 changes: 3 additions & 3 deletions templates/repo/issue/view_content/comments.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@
{{/* compatibility with time comments made before v1.21 */}}
<span class="text grey muted-links">{{.RenderedContent}}</span>
{{else}}
<span class="text grey muted-links">{{.Content|Sec2Time}}</span>
<span class="text grey muted-links">{{.Content|Sec2TrackedTime}}</span>
{{end}}
</div>
</div>
Expand All @@ -271,7 +271,7 @@
{{/* compatibility with time comments made before v1.21 */}}
<span class="text grey muted-links">{{.RenderedContent}}</span>
{{else}}
<span class="text grey muted-links">{{.Content|Sec2Time}}</span>
<span class="text grey muted-links">{{.Content|Sec2TrackedTime}}</span>
{{end}}
</div>
</div>
Expand Down Expand Up @@ -647,7 +647,7 @@
{{/* compatibility with time comments made before v1.21 */}}
<span class="text grey muted-links">{{.RenderedContent}}</span>
{{else}}
<span class="text grey muted-links">- {{.Content|Sec2Time}}</span>
<span class="text grey muted-links">- {{.Content|Sec2TrackedTime}}</span>
{{end}}
</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions templates/repo/issue/view_content/sidebar.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@
{{if gt (len .WorkingUsers) 0}}
<div class="divider"></div>
<div class="ui comments">
<span class="text"><strong>{{ctx.Locale.Tr "repo.issues.time_spent_from_all_authors" ($.Issue.TotalTrackedTime | Sec2Time) | Safe}}</strong></span>
<span class="text"><strong>{{ctx.locale.Tr "repo.issues.time_spent_from_all_authors" ($.Issue.TotalTrackedTime | Sec2TrackedTime) | Safe}}</strong></span>
<div>
{{range $user, $trackedtime := .WorkingUsers}}
<div class="comment gt-mt-3">
Expand All @@ -352,7 +352,7 @@
<div class="content">
{{template "shared/user/authorlink" $user}}
<div class="text">
{{$trackedtime|Sec2Time}}
{{$trackedtime|Sec2TrackedTime}}
</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion templates/shared/issuelist.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
{{if .TotalTrackedTime}}
<div class="text grey flex-text-block">
{{svg "octicon-clock" 16}}
{{.TotalTrackedTime | Sec2Time}}
{{.TotalTrackedTime | Sec2TrackedTime}}
</div>
{{end}}
{{if .Assignees}}
Expand Down
2 changes: 1 addition & 1 deletion templates/user/dashboard/milestones.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
{{if .TotalTrackedTime}}
<div class="flex-text-block">
{{svg "octicon-clock"}}
{{.TotalTrackedTime|Sec2Time}}
{{.TotalTrackedTime|Sec2TrackedTime}}
</div>
{{end}}
{{if .UpdatedUnix}}
Expand Down
6 changes: 3 additions & 3 deletions web_src/js/features/stopwatch.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import $ from 'jquery';
import prettyMilliseconds from 'pretty-ms';
import {formatTrackedTime} from '../utils/time.js';
import {createTippy} from '../modules/tippy.js';

const {appSubUrl, csrfToken, notificationSettings, enableTimeTracking, assetVersionEncoded} = window.config;
Expand Down Expand Up @@ -154,8 +154,8 @@ function updateStopwatchTime(seconds) {
const $stopwatch = $('.stopwatch-time');
const start = Date.now();
const updateUi = () => {
const delta = Date.now() - start;
const dur = prettyMilliseconds(secs * 1000 + delta, {compact: true});
const delta = (Date.now() - start) / 1000;
const dur = formatTrackedTime(secs + delta);
$stopwatch.text(dur);
};
updateUi();
Expand Down
28 changes: 28 additions & 0 deletions web_src/js/utils/time.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export function formatTrackedTime(durationSec) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WIP: make units set via user config

let formattedTime = '';

const duration = Math.floor(durationSec / 1);
const hours = Math.floor(duration / 3600);
const minutes = Math.floor((duration / 60) % 60);
const seconds = duration % 60;

if (hours > 0) {
formattedTime = formatTime(hours, 'hour', formattedTime);
formattedTime = formatTime(minutes, 'minute', formattedTime);
} else {
formattedTime = formatTime(minutes, 'minute', formattedTime);
formattedTime = formatTime(seconds, 'second', formattedTime);
}

formattedTime = formattedTime.trimEnd();
return formattedTime;
}

function formatTime(value, name, formattedTime) {
if (value === 1) {
formattedTime = `${formattedTime}1 ${name} `;
} else if (value > 1) {
formattedTime = `${formattedTime}${value} ${name}s `;
}
return formattedTime;
}
15 changes: 15 additions & 0 deletions web_src/js/utils/time.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {test, expect} from 'vitest';
import {formatTrackedTime} from './time.js';

test('formatTrackedTime', () => {
expect(formatTrackedTime('')).toEqual('');
expect(formatTrackedTime('0')).toEqual('');
expect(formatTrackedTime('66')).toEqual('1 minute 6 seconds');
expect(formatTrackedTime('52410')).toEqual('14 hours 33 minutes');
expect(formatTrackedTime('563418')).toEqual('156 hours 30 minutes');
expect(formatTrackedTime('1563418')).toEqual('434 hours 16 minutes');
expect(formatTrackedTime('3937125')).toEqual('1093 hours 38 minutes');
expect(formatTrackedTime('45677465')).toEqual('12688 hours 11 minutes');
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handle - 123 values too

expect(formatTrackedTime(1.333)).toEqual('1 second');
expect(formatTrackedTime(1.999)).toEqual('1 second');
});