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:
Gwyneth Morgan 2024-01-15 07:07:22 -08:00 committed by GitHub
parent 2d343f8987
commit 2c3da59e27
Signed by: GitHub
GPG Key ID: 4AEE18F83AFDEB23
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}}&nbsp;{{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}}&nbsp;{{ctx.Locale.Tr "repo.issues.closed_title"}}
</a>