mirror of
https://github.com/go-gitea/gitea
synced 2025-07-22 18:28:37 +00:00
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:
74
routers/web/org/worktime.go
Normal file
74
routers/web/org/worktime.go
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package org
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
"code.gitea.io/gitea/modules/templates"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
)
|
||||
|
||||
const tplByRepos templates.TplName = "org/worktime"
|
||||
|
||||
// parseOrgTimes contains functionality that is required in all these functions,
|
||||
// like parsing the date from the request, setting default dates, etc.
|
||||
func parseOrgTimes(ctx *context.Context) (unixFrom, unixTo int64) {
|
||||
rangeFrom := ctx.FormString("from")
|
||||
rangeTo := ctx.FormString("to")
|
||||
if rangeFrom == "" {
|
||||
rangeFrom = time.Now().Format("2006-01") + "-01" // defaults to start of current month
|
||||
}
|
||||
if rangeTo == "" {
|
||||
rangeTo = time.Now().Format("2006-01-02") // defaults to today
|
||||
}
|
||||
|
||||
ctx.Data["RangeFrom"] = rangeFrom
|
||||
ctx.Data["RangeTo"] = rangeTo
|
||||
|
||||
timeFrom, err := time.Parse("2006-01-02", rangeFrom)
|
||||
if err != nil {
|
||||
ctx.ServerError("time.Parse", err)
|
||||
}
|
||||
timeTo, err := time.Parse("2006-01-02", rangeTo)
|
||||
if err != nil {
|
||||
ctx.ServerError("time.Parse", err)
|
||||
}
|
||||
unixFrom = timeFrom.Unix()
|
||||
unixTo = timeTo.Add(1440*time.Minute - 1*time.Second).Unix() // humans expect that we include the ending day too
|
||||
return unixFrom, unixTo
|
||||
}
|
||||
|
||||
func Worktime(ctx *context.Context) {
|
||||
ctx.Data["PageIsOrgTimes"] = true
|
||||
|
||||
unixFrom, unixTo := parseOrgTimes(ctx)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
worktimeBy := ctx.FormString("by")
|
||||
ctx.Data["WorktimeBy"] = worktimeBy
|
||||
|
||||
var worktimeSumResult any
|
||||
var err error
|
||||
if worktimeBy == "milestones" {
|
||||
worktimeSumResult, err = organization.GetWorktimeByMilestones(ctx.Org.Organization, unixFrom, unixTo)
|
||||
ctx.Data["WorktimeByMilestones"] = true
|
||||
} else if worktimeBy == "members" {
|
||||
worktimeSumResult, err = organization.GetWorktimeByMembers(ctx.Org.Organization, unixFrom, unixTo)
|
||||
ctx.Data["WorktimeByMembers"] = true
|
||||
} else /* by repos */ {
|
||||
worktimeSumResult, err = organization.GetWorktimeByRepos(ctx.Org.Organization, unixFrom, unixTo)
|
||||
ctx.Data["WorktimeByRepos"] = true
|
||||
}
|
||||
if err != nil {
|
||||
ctx.ServerError("GetWorktime", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["WorktimeSumResult"] = worktimeSumResult
|
||||
ctx.HTML(http.StatusOK, tplByRepos)
|
||||
}
|
@@ -913,6 +913,8 @@ func registerRoutes(m *web.Router) {
|
||||
m.Post("/teams/{team}/edit", web.Bind(forms.CreateTeamForm{}), org.EditTeamPost)
|
||||
m.Post("/teams/{team}/delete", org.DeleteTeam)
|
||||
|
||||
m.Get("/worktime", context.OrgAssignment(false, true), org.Worktime)
|
||||
|
||||
m.Group("/settings", func() {
|
||||
m.Combo("").Get(org.Settings).
|
||||
Post(web.Bind(forms.UpdateOrgSettingForm{}), org.SettingsPost)
|
||||
|
Reference in New Issue
Block a user