Worktime tracking for the organization level (#19808)

Dear Gitea team,

first of all, thanks for the great work you're doing with this project.

I'm planning to introduce Gitea at a client site, and noticed that while
there is time recording, there are no project-manager-friendly reports
to actually make use of that data, as were also mentioned by others in
#4870 #8684 and #13531.

Since I had a little time last weekend, I had put together something
that I hope to be a useful contribution to this great project (while of
course useful for me too).

This PR adds a new "Worktime" tab to the Organisation level. There is a
date range selector (by default set to the current month), and there are
three possible views:

- by repository,
- by milestone, and
- by team member.

Happy to receive any feedback!

There are several possible future improvements of course (predefined
date ranges, charts, a member time sheet, matrix of repos/members, etc)
but I hope that even in this relatively simple state this would be
useful to lots of people.

<img width="1161" alt="Screen Shot 2022-05-25 at 22 12 58"
src="https://user-images.githubusercontent.com/118010/170366976-af00c7af-c4f3-4117-86d7-00356d6797a5.png">

Keep up the good work!

Kristof

---------

Co-authored-by: user <user@kk-git1>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
K Kovacs 2025-02-02 18:51:12 +01:00 committed by GitHub
parent 869f8fdbe4
commit 34692a20b1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 612 additions and 15 deletions

View file

@ -69,7 +69,7 @@ func NewFuncMap() template.FuncMap {
// time / number / format
"FileSize": base.FileSize,
"CountFmt": countFmt,
"Sec2Time": util.SecToHours,
"Sec2Hour": util.SecToHours,
"TimeEstimateString": timeEstimateString,

View file

@ -11,16 +11,20 @@ import (
// SecToHours converts an amount of seconds to a human-readable hours string.
// This is stable for planning and managing timesheets.
// Here it only supports hours and minutes, because a work day could contain 6 or 7 or 8 hours.
// If the duration is less than 1 minute, it will be shown as seconds.
func SecToHours(durationVal any) string {
duration, _ := ToInt64(durationVal)
hours := duration / 3600
minutes := (duration / 60) % 60
seconds, _ := ToInt64(durationVal)
hours := seconds / 3600
minutes := (seconds / 60) % 60
formattedTime := ""
formattedTime = formatTime(hours, "hour", formattedTime)
formattedTime = formatTime(minutes, "minute", formattedTime)
// The formatTime() function always appends a space at the end. This will be trimmed
if formattedTime == "" && seconds > 0 {
formattedTime = formatTime(seconds, "second", "")
}
return strings.TrimRight(formattedTime, " ")
}

View file

@ -22,4 +22,7 @@ func TestSecToHours(t *testing.T) {
assert.Equal(t, "156 hours 30 minutes", SecToHours(6*day+12*hour+30*minute+18*second))
assert.Equal(t, "98 hours 16 minutes", SecToHours(4*day+2*hour+16*minute+58*second))
assert.Equal(t, "672 hours", SecToHours(4*7*day))
assert.Equal(t, "1 second", SecToHours(1))
assert.Equal(t, "2 seconds", SecToHours(2))
assert.Equal(t, "", SecToHours(nil)) // old behavior, empty means no output
}