mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-11-25 08:22:49 +01:00
Add ability to see open and closed issues at the same time (#28757)
By clicking the currently active "Open" or "Closed" filter button in the issue list, the user can toggle that filter off in order to see all issues regardless of state. The URL "state" parameter will be set to "all" and the "Open"/"Closed" button will not show as active.
This commit is contained in:
parent
2d343f8987
commit
2c3da59e27
4 changed files with 42 additions and 19 deletions
|
@ -340,7 +340,7 @@ func GetTrackedTimeByID(ctx context.Context, id int64) (*TrackedTime, error) {
|
|||
}
|
||||
|
||||
// GetIssueTotalTrackedTime returns the total tracked time for issues by given conditions.
|
||||
func GetIssueTotalTrackedTime(ctx context.Context, opts *IssuesOptions, isClosed bool) (int64, error) {
|
||||
func GetIssueTotalTrackedTime(ctx context.Context, opts *IssuesOptions, isClosed util.OptionalBool) (int64, error) {
|
||||
if len(opts.IssueIDs) <= MaxQueryParameters {
|
||||
return getIssueTotalTrackedTimeChunk(ctx, opts, isClosed, opts.IssueIDs)
|
||||
}
|
||||
|
@ -363,7 +363,7 @@ func GetIssueTotalTrackedTime(ctx context.Context, opts *IssuesOptions, isClosed
|
|||
return accum, nil
|
||||
}
|
||||
|
||||
func getIssueTotalTrackedTimeChunk(ctx context.Context, opts *IssuesOptions, isClosed bool, issueIDs []int64) (int64, error) {
|
||||
func getIssueTotalTrackedTimeChunk(ctx context.Context, opts *IssuesOptions, isClosed util.OptionalBool, issueIDs []int64) (int64, error) {
|
||||
sumSession := func(opts *IssuesOptions, issueIDs []int64) *xorm.Session {
|
||||
sess := db.GetEngine(ctx).
|
||||
Table("tracked_time").
|
||||
|
@ -377,7 +377,9 @@ func getIssueTotalTrackedTimeChunk(ctx context.Context, opts *IssuesOptions, isC
|
|||
Time int64
|
||||
}
|
||||
|
||||
return sumSession(opts, issueIDs).
|
||||
And("issue.is_closed = ?", isClosed).
|
||||
SumInt(new(trackedTime), "tracked_time.time")
|
||||
session := sumSession(opts, issueIDs)
|
||||
if !isClosed.IsNone() {
|
||||
session = session.And("issue.is_closed = ?", isClosed.IsTrue())
|
||||
}
|
||||
return session.SumInt(new(trackedTime), "tracked_time.time")
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -119,11 +120,15 @@ func TestTotalTimesForEachUser(t *testing.T) {
|
|||
func TestGetIssueTotalTrackedTime(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
ttt, err := issues_model.GetIssueTotalTrackedTime(db.DefaultContext, &issues_model.IssuesOptions{MilestoneIDs: []int64{1}}, false)
|
||||
ttt, err := issues_model.GetIssueTotalTrackedTime(db.DefaultContext, &issues_model.IssuesOptions{MilestoneIDs: []int64{1}}, util.OptionalBoolFalse)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 3682, ttt)
|
||||
|
||||
ttt, err = issues_model.GetIssueTotalTrackedTime(db.DefaultContext, &issues_model.IssuesOptions{MilestoneIDs: []int64{1}}, true)
|
||||
ttt, err = issues_model.GetIssueTotalTrackedTime(db.DefaultContext, &issues_model.IssuesOptions{MilestoneIDs: []int64{1}}, util.OptionalBoolTrue)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 0, ttt)
|
||||
|
||||
ttt, err = issues_model.GetIssueTotalTrackedTime(db.DefaultContext, &issues_model.IssuesOptions{MilestoneIDs: []int64{1}}, util.OptionalBoolNone)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 3682, ttt)
|
||||
}
|
||||
|
|
|
@ -237,10 +237,18 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
|
|||
}
|
||||
}
|
||||
|
||||
isShowClosed := ctx.FormString("state") == "closed"
|
||||
// if open issues are zero and close don't, use closed as default
|
||||
var isShowClosed util.OptionalBool
|
||||
switch ctx.FormString("state") {
|
||||
case "closed":
|
||||
isShowClosed = util.OptionalBoolTrue
|
||||
case "all":
|
||||
isShowClosed = util.OptionalBoolNone
|
||||
default:
|
||||
isShowClosed = util.OptionalBoolFalse
|
||||
}
|
||||
// if there are closed issues and no open issues, default to showing all issues
|
||||
if len(ctx.FormString("state")) == 0 && issueStats.OpenCount == 0 && issueStats.ClosedCount != 0 {
|
||||
isShowClosed = true
|
||||
isShowClosed = util.OptionalBoolNone
|
||||
}
|
||||
|
||||
if repo.IsTimetrackerEnabled(ctx) {
|
||||
|
@ -260,10 +268,13 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
|
|||
}
|
||||
|
||||
var total int
|
||||
if !isShowClosed {
|
||||
total = int(issueStats.OpenCount)
|
||||
} else {
|
||||
switch isShowClosed {
|
||||
case util.OptionalBoolTrue:
|
||||
total = int(issueStats.ClosedCount)
|
||||
case util.OptionalBoolNone:
|
||||
total = int(issueStats.OpenCount + issueStats.ClosedCount)
|
||||
default:
|
||||
total = int(issueStats.OpenCount)
|
||||
}
|
||||
pager := context.NewPagination(total, setting.UI.IssuePagingNum, page, 5)
|
||||
|
||||
|
@ -282,7 +293,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
|
|||
ReviewedID: reviewedID,
|
||||
MilestoneIDs: mileIDs,
|
||||
ProjectID: projectID,
|
||||
IsClosed: util.OptionalBoolOf(isShowClosed),
|
||||
IsClosed: isShowClosed,
|
||||
IsPull: isPullOption,
|
||||
LabelIDs: labelIDs,
|
||||
SortType: sortType,
|
||||
|
@ -428,6 +439,9 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
|
|||
ctx.Data["OpenCount"] = issueStats.OpenCount
|
||||
ctx.Data["ClosedCount"] = issueStats.ClosedCount
|
||||
linkStr := "%s?q=%s&type=%s&sort=%s&state=%s&labels=%s&milestone=%d&project=%d&assignee=%d&poster=%d&archived=%t"
|
||||
ctx.Data["AllStatesLink"] = fmt.Sprintf(linkStr, ctx.Link,
|
||||
url.QueryEscape(keyword), url.QueryEscape(viewType), url.QueryEscape(sortType), "all", url.QueryEscape(selectLabels),
|
||||
mentionedID, projectID, assigneeID, posterID, archived)
|
||||
ctx.Data["OpenLink"] = fmt.Sprintf(linkStr, ctx.Link,
|
||||
url.QueryEscape(keyword), url.QueryEscape(viewType), url.QueryEscape(sortType), "open", url.QueryEscape(selectLabels),
|
||||
mentionedID, projectID, assigneeID, posterID, archived)
|
||||
|
@ -442,11 +456,13 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
|
|||
ctx.Data["ProjectID"] = projectID
|
||||
ctx.Data["AssigneeID"] = assigneeID
|
||||
ctx.Data["PosterID"] = posterID
|
||||
ctx.Data["IsShowClosed"] = isShowClosed
|
||||
ctx.Data["Keyword"] = keyword
|
||||
if isShowClosed {
|
||||
switch isShowClosed {
|
||||
case util.OptionalBoolTrue:
|
||||
ctx.Data["State"] = "closed"
|
||||
} else {
|
||||
case util.OptionalBoolNone:
|
||||
ctx.Data["State"] = "all"
|
||||
default:
|
||||
ctx.Data["State"] = "open"
|
||||
}
|
||||
ctx.Data["ShowArchivedLabels"] = archived
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="small-menu-items ui compact tiny menu">
|
||||
<a class="{{if not .IsShowClosed}}active {{end}}item" href="{{.OpenLink}}">
|
||||
<a class="{{if eq .State "open"}}active {{end}}item" href="{{if eq .State "open"}}{{.AllStatesLink}}{{else}}{{.OpenLink}}{{end}}">
|
||||
{{if .PageIsMilestones}}
|
||||
{{svg "octicon-milestone" 16 "gt-mr-3"}}
|
||||
{{else if .PageIsPullList}}
|
||||
|
@ -9,7 +9,7 @@
|
|||
{{end}}
|
||||
{{ctx.Locale.PrettyNumber .OpenCount}} {{ctx.Locale.Tr "repo.issues.open_title"}}
|
||||
</a>
|
||||
<a class="{{if .IsShowClosed}}active {{end}}item" href="{{.ClosedLink}}">
|
||||
<a class="{{if eq .State "closed"}}active {{end}}item" href="{{if eq .State "closed"}}{{.AllStatesLink}}{{else}}{{.ClosedLink}}{{end}}">
|
||||
{{svg "octicon-check" 16 "gt-mr-3"}}
|
||||
{{ctx.Locale.PrettyNumber .ClosedCount}} {{ctx.Locale.Tr "repo.issues.closed_title"}}
|
||||
</a>
|
||||
|
|
Loading…
Reference in a new issue