From 227a9704836eb95c1c3a286c443a4950f3b27c8d Mon Sep 17 00:00:00 2001 From: Brad Albright Date: Mon, 21 Oct 2019 22:30:56 -0500 Subject: [PATCH 01/28] in progress checkpoint --- models/issue_milestone.go | 51 +++++++ routers/routes/routes.go | 2 + routers/user/home.go | 184 ++++++++++++++++++++++- templates/base/head_navbar.tmpl | 1 + templates/user/dashboard/milestones.tmpl | 4 + 5 files changed, 238 insertions(+), 4 deletions(-) create mode 100644 templates/user/dashboard/milestones.tmpl diff --git a/models/issue_milestone.go b/models/issue_milestone.go index d32cb3c7d1f4a..20867912ba414 100644 --- a/models/issue_milestone.go +++ b/models/issue_milestone.go @@ -453,3 +453,54 @@ func DeleteMilestoneByRepoID(repoID, id int64) error { } return sess.Commit() } + +// CountMilestonesByRepo map from repoID to number of milestones matching the options` +func CountMilestonesByRepo(repoIDs []int64, isClosed bool) (map[int64]int64, error) { + sess := x.Where("is_closed = ?", isClosed) + sess.In("repo_id", repoIDs) + + countsSlice := make([]*struct { + RepoID int64 + Count int64 + }, 0, 10) + if err := sess.GroupBy("repo_id"). + Select("repo_id AS repo_id, COUNT(*) AS count"). + Table("milestone"). + Find(&countsSlice); err != nil { + return nil, err + } + + countMap := make(map[int64]int64, len(countsSlice)) + for _, c := range countsSlice { + countMap[c.RepoID] = c.Count + } + return countMap, nil +} + +// GetMilestonesForRepos returns a list of milestones of given repositories and status. +func GetMilestonesForRepos(repoIDs []int64, page int, isClosed bool, sortType string) (MilestoneList, error) { + miles := make([]*Milestone, 0, setting.UI.IssuePagingNum) + sess := x.Where("is_closed = ?", isClosed) + sess.In("repo_id", repoIDs) + if page > 0 { + sess = sess.Limit(setting.UI.IssuePagingNum, (page-1)*setting.UI.IssuePagingNum) + } + + switch sortType { + case "furthestduedate": + sess.Desc("deadline_unix") + case "leastcomplete": + sess.Asc("completeness") + case "mostcomplete": + sess.Desc("completeness") + case "leastissues": + sess.Asc("num_issues") + case "mostissues": + sess.Desc("num_issues") + default: + sess.Asc("deadline_unix") + } + return miles, sess.Find(&miles) +} + +//TODO models.GetUserMilestoneStats(ctxUser.ID, repoID, userRepoIDs, filterMode, isShowClosed) diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 9572ea80390a4..c2377e8d01e2b 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -276,6 +276,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Combo("/install", routers.InstallInit).Get(routers.Install). Post(bindIgnErr(auth.InstallForm{}), routers.InstallPost) m.Get("/^:type(issues|pulls)$", reqSignIn, user.Issues) + m.Get("/milestones", reqSignIn, user.Milestones) // ***** START: User ***** m.Group("/user", func() { @@ -555,6 +556,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Group("/:org", func() { m.Get("/dashboard", user.Dashboard) m.Get("/^:type(issues|pulls)$", user.Issues) + m.Get("/milestones", user.Milestones) m.Get("/members", org.Members) m.Get("/members/action/:action", org.MembersAction) diff --git a/routers/user/home.go b/routers/user/home.go index 40b3bc3fc1b81..8d9cba15c7121 100644 --- a/routers/user/home.go +++ b/routers/user/home.go @@ -24,10 +24,11 @@ import ( ) const ( - tplDashboard base.TplName = "user/dashboard/dashboard" - tplIssues base.TplName = "user/dashboard/issues" - tplProfile base.TplName = "user/profile" - tplOrgHome base.TplName = "org/home" + tplDashboard base.TplName = "user/dashboard/dashboard" + tplIssues base.TplName = "user/dashboard/issues" + tplMilestones base.TplName = "user/dashboard/milestones" + tplProfile base.TplName = "user/profile" + tplOrgHome base.TplName = "org/home" ) // getDashboardContextUser finds out dashboard is viewing as which context user. @@ -149,6 +150,181 @@ func Dashboard(ctx *context.Context) { ctx.HTML(200, tplDashboard) } +// Milestones render the user milestones page +func Milestones(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("milestones") + ctx.Data["PageIsMilestones"] = true + + ctxUser := getDashboardContextUser(ctx) + if ctx.Written() { + return + } + + //milestone sorts: closest due date, furthest due date, least complete, most complete, most issues, least issues + + var ( + viewType = "all" + sortType = ctx.Query("sort") + filterMode = models.FilterModeAll + ) + + page := ctx.QueryInt("page") + if page <= 1 { + page = 1 + } + + repoID := ctx.QueryInt64("repo") + isShowClosed := ctx.Query("state") == "closed" + + // Get repositories. + var err error + var userRepoIDs []int64 + if ctxUser.IsOrganization() { + env, err := ctxUser.AccessibleReposEnv(ctx.User.ID) + if err != nil { + ctx.ServerError("AccessibleReposEnv", err) + return + } + userRepoIDs, err = env.RepoIDs(1, ctxUser.NumRepos) + if err != nil { + ctx.ServerError("env.RepoIDs", err) + return + } + } else { + //TODO is unit type issues correct? there's no unit type for milestones + unitType := models.UnitTypeIssues + userRepoIDs, err = ctxUser.GetAccessRepoIDs(unitType) + if err != nil { + ctx.ServerError("ctxUser.GetAccessRepoIDs", err) + return + } + } + if len(userRepoIDs) == 0 { + userRepoIDs = []int64{-1} + } + + var repoIDs []int64 + if repoID > 0 { + repoIDs = []int64{repoID} + if !com.IsSliceContainsInt64(userRepoIDs, repoID) { + // force an empty result + repoIDs = []int64{-1} + } + } else { + repoIDs = userRepoIDs + } + + counts, err := models.CountMilestonesByRepo(repoIDs, isShowClosed) + if err != nil { + ctx.ServerError("CountMilestonesByRepo", err) + return + } + + milestones, err := models.GetMilestonesForRepos(repoIDs, page, isShowClosed, sortType) + if err != nil { + ctx.ServerError("GetMilestones", err) + return + } + + showReposMap := make(map[int64]*models.Repository, len(counts)) + for repoID := range counts { + repo, err := models.GetRepositoryByID(repoID) + if err != nil { + ctx.ServerError("GetRepositoryByID", err) + return + } + showReposMap[repoID] = repo + } + + if repoID > 0 { + if _, ok := showReposMap[repoID]; !ok { + repo, err := models.GetRepositoryByID(repoID) + if models.IsErrRepoNotExist(err) { + ctx.NotFound("GetRepositoryByID", err) + return + } else if err != nil { + ctx.ServerError("GetRepositoryByID", fmt.Errorf("[%d]%v", repoID, err)) + return + } + showReposMap[repoID] = repo + } + + repo := showReposMap[repoID] + + // Check if user has access to given repository. + perm, err := models.GetUserRepoPermission(repo, ctxUser) + if err != nil { + ctx.ServerError("GetUserRepoPermission", fmt.Errorf("[%d]%v", repoID, err)) + return + } + if !perm.CanRead(models.UnitTypeIssues) { + if log.IsTrace() { + log.Trace("Permission Denied: User %-v cannot read %-v of repo %-v\n"+ + "User in repo has Permissions: %-+v", + ctxUser, + models.UnitTypeIssues, + repo, + perm) + } + ctx.Status(404) + return + } + } + + showRepos := models.RepositoryListOfMap(showReposMap) + sort.Sort(showRepos) + if err = showRepos.LoadAttributes(); err != nil { + ctx.ServerError("LoadAttributes", err) + return + } + + //TODO in the issues code, it would do something like this to assign the repo to the issue object, + //but the milestone object does not have a repo reference...is this a problem? + //for _, issue := range issues { + // issue.Repo = showReposMap[issue.RepoID] + + //TODO need to write this method in issue_milestone.go + milestoneStats, err := models.GetUserMilestoneStats(ctxUser.ID, repoID, userRepoIDs, filterMode, isShowClosed) + if err != nil { + ctx.ServerError("GetUserMilestoneStats", err) + return + } + + var total int + if !isShowClosed { + total = int(milestoneStats.OpenCount) + } else { + total = int(milestoneStats.ClosedCount) + } + + ctx.Data["Milestones"] = milestones + ctx.Data["Repos"] = showRepos + ctx.Data["Counts"] = counts + ctx.Data["MilestoneStats"] = milestoneStats + ctx.Data["ViewType"] = viewType + ctx.Data["SortType"] = sortType + ctx.Data["RepoID"] = repoID + ctx.Data["IsShowClosed"] = isShowClosed + + if isShowClosed { + ctx.Data["State"] = "closed" + } else { + ctx.Data["State"] = "open" + } + + pager := context.NewPagination(total, setting.UI.IssuePagingNum, page, 5) + //TODO what are these for??? + pager.AddParam(ctx, "type", "ViewType") + pager.AddParam(ctx, "repo", "RepoID") + pager.AddParam(ctx, "sort", "SortType") + pager.AddParam(ctx, "state", "State") + pager.AddParam(ctx, "milestone", "MilestoneID") + pager.AddParam(ctx, "assignee", "AssigneeID") + ctx.Data["Page"] = pager + + ctx.HTML(200, tplMilestones) +} + // Issues render the user issues page func Issues(ctx *context.Context) { isPullList := ctx.Params(":type") == "pulls" diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl index 390a1fe8044ca..afe462604c5ac 100644 --- a/templates/base/head_navbar.tmpl +++ b/templates/base/head_navbar.tmpl @@ -12,6 +12,7 @@ {{.i18n.Tr "dashboard"}} {{.i18n.Tr "issues"}} {{.i18n.Tr "pull_requests"}} + {{.i18n.Tr "milestones"}} {{.i18n.Tr "explore"}} {{else if .IsLandingPageHome}} {{.i18n.Tr "home"}} diff --git a/templates/user/dashboard/milestones.tmpl b/templates/user/dashboard/milestones.tmpl new file mode 100644 index 0000000000000..65b0b15f57290 --- /dev/null +++ b/templates/user/dashboard/milestones.tmpl @@ -0,0 +1,4 @@ +{{template "base/head" .}} +
+ milestones! +
\ No newline at end of file From 9fe22ba0e01fc5de2ab9093889c9a7b2817ad7b0 Mon Sep 17 00:00:00 2001 From: Brad Albright Date: Tue, 22 Oct 2019 22:34:52 -0500 Subject: [PATCH 02/28] an initial crack at the milestones showing up; the expected milestones are showing up for a user, but the UI isn't right; also don't have organizations handled yet --- models/issue_milestone.go | 43 ++++++++++- options/locale/locale_en-US.ini | 1 + routers/user/home.go | 19 ++--- templates/user/dashboard/milestones.tmpl | 94 +++++++++++++++++++++++- 4 files changed, 139 insertions(+), 18 deletions(-) diff --git a/models/issue_milestone.go b/models/issue_milestone.go index 20867912ba414..81fa1ad5fc66d 100644 --- a/models/issue_milestone.go +++ b/models/issue_milestone.go @@ -477,8 +477,8 @@ func CountMilestonesByRepo(repoIDs []int64, isClosed bool) (map[int64]int64, err return countMap, nil } -// GetMilestonesForRepos returns a list of milestones of given repositories and status. -func GetMilestonesForRepos(repoIDs []int64, page int, isClosed bool, sortType string) (MilestoneList, error) { +// GetMilestonesByRepoIDs returns a list of milestones of given repositories and status. +func GetMilestonesByRepoIDs(repoIDs []int64, page int, isClosed bool, sortType string) (MilestoneList, error) { miles := make([]*Milestone, 0, setting.UI.IssuePagingNum) sess := x.Where("is_closed = ?", isClosed) sess.In("repo_id", repoIDs) @@ -503,4 +503,41 @@ func GetMilestonesForRepos(repoIDs []int64, page int, isClosed bool, sortType st return miles, sess.Find(&miles) } -//TODO models.GetUserMilestoneStats(ctxUser.ID, repoID, userRepoIDs, filterMode, isShowClosed) +// UserMilestoneStats represents milestone statistic information. +type UserMilestoneStats struct { + OpenCount, ClosedCount int64 + YourRepositoriesCount int64 +} + +// GetUserMilestoneStats returns milestone statistic information for dashboard by given conditions. +func GetUserMilestoneStats(userID int64, repoID int64, userRepoIDs []int64) (*UserMilestoneStats, error) { + var err error + stats := &UserMilestoneStats{} + + cond := builder.NewCond() + if repoID > 0 { + cond = cond.And(builder.Eq{"repo_id": repoID}) + } + + stats.OpenCount, err = x.Where(cond).And("is_closed = ?", false). + And(builder.In("repo_id", userRepoIDs)). + Count(new(Milestone)) + if err != nil { + return nil, err + } + stats.ClosedCount, err = x.Where(cond).And("is_closed = ?", true). + And(builder.In("repo_id", userRepoIDs)). + Count(new(Milestone)) + if err != nil { + return nil, err + } + + stats.YourRepositoriesCount, err = x.Where(cond). + And(builder.In("repo_id", userRepoIDs)). + Count(new(Milestone)) + if err != nil { + return nil, err + } + + return stats, nil +} diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 4923f2f88400d..e2638e29a98a9 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -68,6 +68,7 @@ forks = Forks activities = Activities pull_requests = Pull Requests issues = Issues +milestones = Milestones cancel = Cancel diff --git a/routers/user/home.go b/routers/user/home.go index 8d9cba15c7121..47d8fdcb4ceac 100644 --- a/routers/user/home.go +++ b/routers/user/home.go @@ -162,11 +162,8 @@ func Milestones(ctx *context.Context) { //milestone sorts: closest due date, furthest due date, least complete, most complete, most issues, least issues - var ( - viewType = "all" - sortType = ctx.Query("sort") - filterMode = models.FilterModeAll - ) + viewType := "all" + sortType := ctx.Query("sort") page := ctx.QueryInt("page") if page <= 1 { @@ -191,7 +188,6 @@ func Milestones(ctx *context.Context) { return } } else { - //TODO is unit type issues correct? there's no unit type for milestones unitType := models.UnitTypeIssues userRepoIDs, err = ctxUser.GetAccessRepoIDs(unitType) if err != nil { @@ -220,9 +216,9 @@ func Milestones(ctx *context.Context) { return } - milestones, err := models.GetMilestonesForRepos(repoIDs, page, isShowClosed, sortType) + milestones, err := models.GetMilestonesByRepoIDs(repoIDs, page, isShowClosed, sortType) if err != nil { - ctx.ServerError("GetMilestones", err) + ctx.ServerError("GetMilestonesByRepoIDs", err) return } @@ -283,8 +279,7 @@ func Milestones(ctx *context.Context) { //for _, issue := range issues { // issue.Repo = showReposMap[issue.RepoID] - //TODO need to write this method in issue_milestone.go - milestoneStats, err := models.GetUserMilestoneStats(ctxUser.ID, repoID, userRepoIDs, filterMode, isShowClosed) + milestoneStats, err := models.GetUserMilestoneStats(ctxUser.ID, repoID, userRepoIDs) if err != nil { ctx.ServerError("GetUserMilestoneStats", err) return @@ -318,8 +313,8 @@ func Milestones(ctx *context.Context) { pager.AddParam(ctx, "repo", "RepoID") pager.AddParam(ctx, "sort", "SortType") pager.AddParam(ctx, "state", "State") - pager.AddParam(ctx, "milestone", "MilestoneID") - pager.AddParam(ctx, "assignee", "AssigneeID") + //pager.AddParam(ctx, "milestone", "MilestoneID") + //pager.AddParam(ctx, "assignee", "AssigneeID") ctx.Data["Page"] = pager ctx.HTML(200, tplMilestones) diff --git a/templates/user/dashboard/milestones.tmpl b/templates/user/dashboard/milestones.tmpl index 65b0b15f57290..db6fd168b7b96 100644 --- a/templates/user/dashboard/milestones.tmpl +++ b/templates/user/dashboard/milestones.tmpl @@ -1,4 +1,92 @@ {{template "base/head" .}} -
- milestones! -
\ No newline at end of file +
+ {{template "user/dashboard/navbar" .}} +
+
+ +
+ + + +
+ {{range .Milestones}} +
  • + {{.Name}} +
    +
    +
    +
    +
    +
    + {{ $closedDate:= TimeSinceUnix .ClosedDateUnix $.Lang }} + {{if .IsClosed}} + {{$.i18n.Tr "repo.milestones.closed" $closedDate|Str2html}} + {{else}} + + {{if .DeadlineString}} + {{.DeadlineString}} + {{else}} + {{$.i18n.Tr "repo.milestones.no_due_date"}} + {{end}} + {{end}} + + {{$.i18n.Tr "repo.milestones.open_tab" .NumOpenIssues}} + {{$.i18n.Tr "repo.milestones.close_tab" .NumClosedIssues}} + {{if .TotalTrackedTime}} {{.TotalTrackedTime|Sec2Time}}{{end}} + +
    + {{if .Content}} +
    + {{.RenderedContent|Str2html}} +
    + {{end}} +
  • + {{end}} + + {{template "base/paginate" .}} +
    + +
    +
    +
    +
    +{{template "base/footer" .}} From 614f95e33c52ffbc6fba57dbf4427725a71bf582 Mon Sep 17 00:00:00 2001 From: Brad Albright Date: Wed, 23 Oct 2019 22:37:49 -0500 Subject: [PATCH 03/28] in progress checkpoint, ui looks better and got the repo name to show on the milestones. still need to add time tracking totals and handle for organizations --- routers/user/home.go | 12 ++++++++++++ templates/user/dashboard/milestones.tmpl | 7 ++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/routers/user/home.go b/routers/user/home.go index 47d8fdcb4ceac..3a2a3c3fb07cd 100644 --- a/routers/user/home.go +++ b/routers/user/home.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" @@ -231,6 +232,16 @@ func Milestones(ctx *context.Context) { } showReposMap[repoID] = repo } + //TODO yes have to do this... + //if ctx.Repo.Repository.IsTimetrackerEnabled() { + // if err := miles.LoadTotalTrackedTimes(); err != nil { + // ctx.ServerError("LoadTotalTrackedTimes", err) + // return + // } + //} + for _, m := range milestones { + m.RenderedContent = string(markdown.Render([]byte(m.Content), showReposMap[m.RepoID].Link(), showReposMap[m.RepoID].ComposeMetas())) + } if repoID > 0 { if _, ok := showReposMap[repoID]; !ok { @@ -294,6 +305,7 @@ func Milestones(ctx *context.Context) { ctx.Data["Milestones"] = milestones ctx.Data["Repos"] = showRepos + ctx.Data["RepoMap"] = showReposMap ctx.Data["Counts"] = counts ctx.Data["MilestoneStats"] = milestoneStats ctx.Data["ViewType"] = viewType diff --git a/templates/user/dashboard/milestones.tmpl b/templates/user/dashboard/milestones.tmpl index db6fd168b7b96..af25e5279eb7f 100644 --- a/templates/user/dashboard/milestones.tmpl +++ b/templates/user/dashboard/milestones.tmpl @@ -1,5 +1,5 @@ {{template "base/head" .}} -
    +
    {{template "user/dashboard/navbar" .}}
    @@ -50,6 +50,11 @@
    {{range .Milestones}}
  • +
    + {{if not $.RepoID}} + {{ with (index $.RepoMap .RepoID) }}{{ .FullName }}{{ end }} + {{end}} +
    {{.Name}}
    From 7dae2dfaf896c8915026ebcab94a7867b36a128f Mon Sep 17 00:00:00 2001 From: Brad Albright Date: Fri, 25 Oct 2019 21:33:19 -0500 Subject: [PATCH 04/28] in-progress work on adding time tracking totals to the milestones on the dashboard view --- models/issue_milestone.go | 53 +++++++++++++++++++++++- routers/user/home.go | 34 ++++++++------- templates/user/dashboard/milestones.tmpl | 8 +--- 3 files changed, 71 insertions(+), 24 deletions(-) diff --git a/models/issue_milestone.go b/models/issue_milestone.go index 81fa1ad5fc66d..26c99df6eb0f4 100644 --- a/models/issue_milestone.go +++ b/models/issue_milestone.go @@ -17,8 +17,9 @@ import ( // Milestone represents a milestone of repository. type Milestone struct { - ID int64 `xorm:"pk autoincr"` - RepoID int64 `xorm:"INDEX"` + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"INDEX"` + Repo *Repository `xorm:"-"` Name string Content string `xorm:"TEXT"` RenderedContent string `xorm:"-"` @@ -177,11 +178,59 @@ func (milestones MilestoneList) loadTotalTrackedTimes(e Engine) error { return nil } +func (m *Milestone) loadTotalTrackedTime(e Engine) error { + type totalTimesByMilestone struct { + MilestoneID int64 + Time int64 + } + + //TODO don't do it this way, instead just select out one row (?) + totalTime, err := e.Table("issue"). + Join("INNER", "milestone", "issue.milestone_id = milestone.id"). + Join("LEFT", "tracked_time", "tracked_time.issue_id = issue.id"). + Select("milestone_id, sum(time) as time"). + Where("milestone_id = ?", m.ID). + GroupBy("milestone_id"). + Find(new(totalTimesByMilestone)) + if err != nil { + return err + } + m.TotalTrackedTime = totalTime.Time + //TODO don't do it this way, instead just select out one row (?) + //rows, err := e.Table("issue"). + // Join("INNER", "milestone", "issue.milestone_id = milestone.id"). + // Join("LEFT", "tracked_time", "tracked_time.issue_id = issue.id"). + // Select("milestone_id, sum(time) as time"). + // Where("milestone_id = ?", m.ID). + // GroupBy("milestone_id"). + // Rows(new(totalTimesByMilestone)) + //if err != nil { + // return err + //} + + //defer rows.Close() + + //if rows.Next() { + // var totalTime totalTimesByMilestone + // err = rows.Scan(&totalTime) + // if err != nil { + // return err + // } + // m.TotalTrackedTime = totalTime.Time + //} + return nil +} + // LoadTotalTrackedTimes loads for every milestone in the list the TotalTrackedTime by a batch request func (milestones MilestoneList) LoadTotalTrackedTimes() error { return milestones.loadTotalTrackedTimes(x) } +// LoadTotalTrackedTime loads the tracked time for the milestone +func (m *Milestone) LoadTotalTrackedTime() error { + return m.loadTotalTrackedTime(x) +} + func (milestones MilestoneList) getMilestoneIDs() []int64 { var ids = make([]int64, 0, len(milestones)) for _, ms := range milestones { diff --git a/routers/user/home.go b/routers/user/home.go index 3a2a3c3fb07cd..d33d55ad18237 100644 --- a/routers/user/home.go +++ b/routers/user/home.go @@ -232,16 +232,6 @@ func Milestones(ctx *context.Context) { } showReposMap[repoID] = repo } - //TODO yes have to do this... - //if ctx.Repo.Repository.IsTimetrackerEnabled() { - // if err := miles.LoadTotalTrackedTimes(); err != nil { - // ctx.ServerError("LoadTotalTrackedTimes", err) - // return - // } - //} - for _, m := range milestones { - m.RenderedContent = string(markdown.Render([]byte(m.Content), showReposMap[m.RepoID].Link(), showReposMap[m.RepoID].ComposeMetas())) - } if repoID > 0 { if _, ok := showReposMap[repoID]; !ok { @@ -285,10 +275,23 @@ func Milestones(ctx *context.Context) { return } - //TODO in the issues code, it would do something like this to assign the repo to the issue object, - //but the milestone object does not have a repo reference...is this a problem? - //for _, issue := range issues { - // issue.Repo = showReposMap[issue.RepoID] + //TODO yes have to do this... + //if ctx.Repo.Repository.IsTimetrackerEnabled() { + // if err := miles.LoadTotalTrackedTimes(); err != nil { + // ctx.ServerError("LoadTotalTrackedTimes", err) + // return + // } + //} + //for _, m := range milestones { + // m.RenderedContent = string(markdown.Render([]byte(m.Content), showReposMap[m.RepoID].Link(), showReposMap[m.RepoID].ComposeMetas())) + //} + for _, m := range milestones { + m.Repo = showReposMap[m.RepoID] + m.RenderedContent = string(markdown.Render([]byte(m.Content), m.Repo.Link(), m.Repo.ComposeMetas())) + if m.Repo.IsTimetrackerEnabled() { + m.LoadTotalTrackedTime() + } + } milestoneStats, err := models.GetUserMilestoneStats(ctxUser.ID, repoID, userRepoIDs) if err != nil { @@ -305,7 +308,6 @@ func Milestones(ctx *context.Context) { ctx.Data["Milestones"] = milestones ctx.Data["Repos"] = showRepos - ctx.Data["RepoMap"] = showReposMap ctx.Data["Counts"] = counts ctx.Data["MilestoneStats"] = milestoneStats ctx.Data["ViewType"] = viewType @@ -320,7 +322,7 @@ func Milestones(ctx *context.Context) { } pager := context.NewPagination(total, setting.UI.IssuePagingNum, page, 5) - //TODO what are these for??? + //TODO do I need all these? pager.AddParam(ctx, "type", "ViewType") pager.AddParam(ctx, "repo", "RepoID") pager.AddParam(ctx, "sort", "SortType") diff --git a/templates/user/dashboard/milestones.tmpl b/templates/user/dashboard/milestones.tmpl index af25e5279eb7f..054a04070d8b3 100644 --- a/templates/user/dashboard/milestones.tmpl +++ b/templates/user/dashboard/milestones.tmpl @@ -50,12 +50,8 @@
    {{range .Milestones}}
  • -
    - {{if not $.RepoID}} - {{ with (index $.RepoMap .RepoID) }}{{ .FullName }}{{ end }} - {{end}} -
    - {{.Name}} +
    {{if not $.RepoID}}{{.Repo.FullName}}{{end}}
    + {{.Name}}
    From 6a2136e2d120eeae4711824525490b559ce16f27 Mon Sep 17 00:00:00 2001 From: Brad Albright Date: Fri, 25 Oct 2019 22:22:21 -0500 Subject: [PATCH 05/28] adding time tracking totals to milestrones for the dashboard view --- models/issue_milestone.go | 31 +++++-------------------------- routers/user/home.go | 10 ---------- 2 files changed, 5 insertions(+), 36 deletions(-) diff --git a/models/issue_milestone.go b/models/issue_milestone.go index 26c99df6eb0f4..f63a2cbac8ad9 100644 --- a/models/issue_milestone.go +++ b/models/issue_milestone.go @@ -183,41 +183,20 @@ func (m *Milestone) loadTotalTrackedTime(e Engine) error { MilestoneID int64 Time int64 } - - //TODO don't do it this way, instead just select out one row (?) - totalTime, err := e.Table("issue"). + totalTime := &totalTimesByMilestone{MilestoneID: m.ID} + has, err := e.Table("issue"). Join("INNER", "milestone", "issue.milestone_id = milestone.id"). Join("LEFT", "tracked_time", "tracked_time.issue_id = issue.id"). Select("milestone_id, sum(time) as time"). Where("milestone_id = ?", m.ID). GroupBy("milestone_id"). - Find(new(totalTimesByMilestone)) + Get(totalTime) if err != nil { return err + } else if !has { + return nil } m.TotalTrackedTime = totalTime.Time - //TODO don't do it this way, instead just select out one row (?) - //rows, err := e.Table("issue"). - // Join("INNER", "milestone", "issue.milestone_id = milestone.id"). - // Join("LEFT", "tracked_time", "tracked_time.issue_id = issue.id"). - // Select("milestone_id, sum(time) as time"). - // Where("milestone_id = ?", m.ID). - // GroupBy("milestone_id"). - // Rows(new(totalTimesByMilestone)) - //if err != nil { - // return err - //} - - //defer rows.Close() - - //if rows.Next() { - // var totalTime totalTimesByMilestone - // err = rows.Scan(&totalTime) - // if err != nil { - // return err - // } - // m.TotalTrackedTime = totalTime.Time - //} return nil } diff --git a/routers/user/home.go b/routers/user/home.go index d33d55ad18237..7ff6d9cc6feed 100644 --- a/routers/user/home.go +++ b/routers/user/home.go @@ -275,16 +275,6 @@ func Milestones(ctx *context.Context) { return } - //TODO yes have to do this... - //if ctx.Repo.Repository.IsTimetrackerEnabled() { - // if err := miles.LoadTotalTrackedTimes(); err != nil { - // ctx.ServerError("LoadTotalTrackedTimes", err) - // return - // } - //} - //for _, m := range milestones { - // m.RenderedContent = string(markdown.Render([]byte(m.Content), showReposMap[m.RepoID].Link(), showReposMap[m.RepoID].ComposeMetas())) - //} for _, m := range milestones { m.Repo = showReposMap[m.RepoID] m.RenderedContent = string(markdown.Render([]byte(m.Content), m.Repo.Link(), m.Repo.ComposeMetas())) From f770682e4563b1f8fb584950822725c250bfbfaa Mon Sep 17 00:00:00 2001 From: Brad Albright Date: Sat, 26 Oct 2019 21:46:35 -0500 Subject: [PATCH 06/28] fixed issue with in your repositories total on milestones dashboard --- routers/user/home.go | 3 +-- templates/user/dashboard/milestones.tmpl | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/routers/user/home.go b/routers/user/home.go index 7ff6d9cc6feed..6daa1aef4a564 100644 --- a/routers/user/home.go +++ b/routers/user/home.go @@ -161,8 +161,6 @@ func Milestones(ctx *context.Context) { return } - //milestone sorts: closest due date, furthest due date, least complete, most complete, most issues, least issues - viewType := "all" sortType := ctx.Query("sort") @@ -300,6 +298,7 @@ func Milestones(ctx *context.Context) { ctx.Data["Repos"] = showRepos ctx.Data["Counts"] = counts ctx.Data["MilestoneStats"] = milestoneStats + ctx.Data["Total"] = total ctx.Data["ViewType"] = viewType ctx.Data["SortType"] = sortType ctx.Data["RepoID"] = repoID diff --git a/templates/user/dashboard/milestones.tmpl b/templates/user/dashboard/milestones.tmpl index 054a04070d8b3..3f15cc358c9ab 100644 --- a/templates/user/dashboard/milestones.tmpl +++ b/templates/user/dashboard/milestones.tmpl @@ -7,7 +7,7 @@
  • -
    {{if not $.RepoID}}{{.Repo.FullName}}{{end}}
    +
    {{if not $.RepoIDs}}{{.Repo.FullName}}{{end}}
    {{.Name}}
    From aaad76879b2fad032b1e49bd28df12e9f8787848 Mon Sep 17 00:00:00 2001 From: Brad Albright <32200834+bhalbright@users.noreply.github.com> Date: Sat, 14 Dec 2019 13:51:12 -0600 Subject: [PATCH 25/28] Update integrations/links_test.go Co-Authored-By: 6543 <6543@obermui.de> --- integrations/links_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/links_test.go b/integrations/links_test.go index db86b22812526..39581a6513155 100644 --- a/integrations/links_test.go +++ b/integrations/links_test.go @@ -91,7 +91,7 @@ func testLinksAsUser(userName string, t *testing.T) { "/milestones?type=your_repositories&sort=mostcomplete&state=closed", "/milestones?sort=&repo=1&state=closed", "/milestones?sort=&repo=1&state=open", - "/milestones?repo=0&sort=mostissues&state=open", + "/milestones?repos=[0]&sort=mostissues&state=open", "/notifications", "/repo/create", "/repo/migrate", From f264f5d636b37ac8e54d018252a1e729b8a15080 Mon Sep 17 00:00:00 2001 From: Brad Albright <32200834+bhalbright@users.noreply.github.com> Date: Sat, 14 Dec 2019 13:51:36 -0600 Subject: [PATCH 26/28] Update integrations/links_test.go Co-Authored-By: 6543 <6543@obermui.de> --- integrations/links_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/links_test.go b/integrations/links_test.go index 39581a6513155..97340adcdd0ae 100644 --- a/integrations/links_test.go +++ b/integrations/links_test.go @@ -87,7 +87,7 @@ func testLinksAsUser(userName string, t *testing.T) { "/pulls?type=assigned&repos=[0]&sort=&state=closed", "/pulls?type=created_by&repos=[0]&sort=&state=closed", "/milestones", - "/milestones?repo=0&sort=mostcomplete&state=closed", + "/milestones?sort=mostcomplete&state=closed", "/milestones?type=your_repositories&sort=mostcomplete&state=closed", "/milestones?sort=&repo=1&state=closed", "/milestones?sort=&repo=1&state=open", From b33d30aaf0bf41d3b28853b6b7735030109ecd4f Mon Sep 17 00:00:00 2001 From: Brad Albright <32200834+bhalbright@users.noreply.github.com> Date: Sun, 15 Dec 2019 07:07:35 -0600 Subject: [PATCH 27/28] Update integrations/links_test.go Co-Authored-By: 6543 <6543@obermui.de> --- integrations/links_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/links_test.go b/integrations/links_test.go index 97340adcdd0ae..6fb928173193b 100644 --- a/integrations/links_test.go +++ b/integrations/links_test.go @@ -89,7 +89,7 @@ func testLinksAsUser(userName string, t *testing.T) { "/milestones", "/milestones?sort=mostcomplete&state=closed", "/milestones?type=your_repositories&sort=mostcomplete&state=closed", - "/milestones?sort=&repo=1&state=closed", + "/milestones?sort=&repos=[1]&state=closed", "/milestones?sort=&repo=1&state=open", "/milestones?repos=[0]&sort=mostissues&state=open", "/notifications", From 218aa5be050cdcd33862a4f239c3e94a6a5b7796 Mon Sep 17 00:00:00 2001 From: Brad Albright <32200834+bhalbright@users.noreply.github.com> Date: Sun, 15 Dec 2019 07:08:06 -0600 Subject: [PATCH 28/28] Update integrations/links_test.go Co-Authored-By: 6543 <6543@obermui.de> --- integrations/links_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/links_test.go b/integrations/links_test.go index 6fb928173193b..329e54528a7d4 100644 --- a/integrations/links_test.go +++ b/integrations/links_test.go @@ -90,7 +90,7 @@ func testLinksAsUser(userName string, t *testing.T) { "/milestones?sort=mostcomplete&state=closed", "/milestones?type=your_repositories&sort=mostcomplete&state=closed", "/milestones?sort=&repos=[1]&state=closed", - "/milestones?sort=&repo=1&state=open", + "/milestones?sort=&repos=[1]&state=open", "/milestones?repos=[0]&sort=mostissues&state=open", "/notifications", "/repo/create",