Skip to content

Commit d454c66

Browse files
committed
Add ability to see open and closed issues at the same time
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.
1 parent 669bbba commit d454c66

File tree

4 files changed

+42
-19
lines changed

4 files changed

+42
-19
lines changed

models/issues/tracked_time.go

+7-5
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ func GetTrackedTimeByID(ctx context.Context, id int64) (*TrackedTime, error) {
328328
}
329329

330330
// GetIssueTotalTrackedTime returns the total tracked time for issues by given conditions.
331-
func GetIssueTotalTrackedTime(ctx context.Context, opts *IssuesOptions, isClosed bool) (int64, error) {
331+
func GetIssueTotalTrackedTime(ctx context.Context, opts *IssuesOptions, isClosed util.OptionalBool) (int64, error) {
332332
if len(opts.IssueIDs) <= MaxQueryParameters {
333333
return getIssueTotalTrackedTimeChunk(ctx, opts, isClosed, opts.IssueIDs)
334334
}
@@ -351,7 +351,7 @@ func GetIssueTotalTrackedTime(ctx context.Context, opts *IssuesOptions, isClosed
351351
return accum, nil
352352
}
353353

354-
func getIssueTotalTrackedTimeChunk(ctx context.Context, opts *IssuesOptions, isClosed bool, issueIDs []int64) (int64, error) {
354+
func getIssueTotalTrackedTimeChunk(ctx context.Context, opts *IssuesOptions, isClosed util.OptionalBool, issueIDs []int64) (int64, error) {
355355
sumSession := func(opts *IssuesOptions, issueIDs []int64) *xorm.Session {
356356
sess := db.GetEngine(ctx).
357357
Table("tracked_time").
@@ -365,7 +365,9 @@ func getIssueTotalTrackedTimeChunk(ctx context.Context, opts *IssuesOptions, isC
365365
Time int64
366366
}
367367

368-
return sumSession(opts, issueIDs).
369-
And("issue.is_closed = ?", isClosed).
370-
SumInt(new(trackedTime), "tracked_time.time")
368+
session := sumSession(opts, issueIDs)
369+
if !isClosed.IsNone() {
370+
session = session.And("issue.is_closed = ?", isClosed.IsTrue())
371+
}
372+
return session.SumInt(new(trackedTime), "tracked_time.time")
371373
}

models/issues/tracked_time_test.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
issues_model "code.gitea.io/gitea/models/issues"
1212
"code.gitea.io/gitea/models/unittest"
1313
user_model "code.gitea.io/gitea/models/user"
14+
"code.gitea.io/gitea/modules/util"
1415

1516
"github.com/stretchr/testify/assert"
1617
)
@@ -119,11 +120,15 @@ func TestTotalTimesForEachUser(t *testing.T) {
119120
func TestGetIssueTotalTrackedTime(t *testing.T) {
120121
assert.NoError(t, unittest.PrepareTestDatabase())
121122

122-
ttt, err := issues_model.GetIssueTotalTrackedTime(db.DefaultContext, &issues_model.IssuesOptions{MilestoneIDs: []int64{1}}, false)
123+
ttt, err := issues_model.GetIssueTotalTrackedTime(db.DefaultContext, &issues_model.IssuesOptions{MilestoneIDs: []int64{1}}, util.OptionalBoolFalse)
123124
assert.NoError(t, err)
124125
assert.EqualValues(t, 3682, ttt)
125126

126-
ttt, err = issues_model.GetIssueTotalTrackedTime(db.DefaultContext, &issues_model.IssuesOptions{MilestoneIDs: []int64{1}}, true)
127+
ttt, err = issues_model.GetIssueTotalTrackedTime(db.DefaultContext, &issues_model.IssuesOptions{MilestoneIDs: []int64{1}}, util.OptionalBoolTrue)
127128
assert.NoError(t, err)
128129
assert.EqualValues(t, 0, ttt)
130+
131+
ttt, err = issues_model.GetIssueTotalTrackedTime(db.DefaultContext, &issues_model.IssuesOptions{MilestoneIDs: []int64{1}}, util.OptionalBoolNone)
132+
assert.NoError(t, err)
133+
assert.EqualValues(t, 3682, ttt)
129134
}

routers/web/repo/issue.go

+26-10
Original file line numberDiff line numberDiff line change
@@ -237,10 +237,18 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
237237
}
238238
}
239239

240-
isShowClosed := ctx.FormString("state") == "closed"
241-
// if open issues are zero and close don't, use closed as default
240+
var isShowClosed util.OptionalBool
241+
switch ctx.FormString("state") {
242+
case "closed":
243+
isShowClosed = util.OptionalBoolTrue
244+
case "all":
245+
isShowClosed = util.OptionalBoolNone
246+
default:
247+
isShowClosed = util.OptionalBoolFalse
248+
}
249+
// if there are closed issues and no open issues, default to showing all issues
242250
if len(ctx.FormString("state")) == 0 && issueStats.OpenCount == 0 && issueStats.ClosedCount != 0 {
243-
isShowClosed = true
251+
isShowClosed = util.OptionalBoolNone
244252
}
245253

246254
if repo.IsTimetrackerEnabled(ctx) {
@@ -260,10 +268,13 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
260268
}
261269

262270
var total int
263-
if !isShowClosed {
264-
total = int(issueStats.OpenCount)
265-
} else {
271+
switch isShowClosed {
272+
case util.OptionalBoolTrue:
266273
total = int(issueStats.ClosedCount)
274+
case util.OptionalBoolNone:
275+
total = int(issueStats.OpenCount + issueStats.ClosedCount)
276+
default:
277+
total = int(issueStats.OpenCount)
267278
}
268279
pager := context.NewPagination(total, setting.UI.IssuePagingNum, page, 5)
269280

@@ -282,7 +293,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
282293
ReviewedID: reviewedID,
283294
MilestoneIDs: mileIDs,
284295
ProjectID: projectID,
285-
IsClosed: util.OptionalBoolOf(isShowClosed),
296+
IsClosed: isShowClosed,
286297
IsPull: isPullOption,
287298
LabelIDs: labelIDs,
288299
SortType: sortType,
@@ -428,6 +439,9 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
428439
ctx.Data["OpenCount"] = issueStats.OpenCount
429440
ctx.Data["ClosedCount"] = issueStats.ClosedCount
430441
linkStr := "%s?q=%s&type=%s&sort=%s&state=%s&labels=%s&milestone=%d&project=%d&assignee=%d&poster=%d&archived=%t"
442+
ctx.Data["AllStatesLink"] = fmt.Sprintf(linkStr, ctx.Link,
443+
url.QueryEscape(keyword), url.QueryEscape(viewType), url.QueryEscape(sortType), "all", url.QueryEscape(selectLabels),
444+
mentionedID, projectID, assigneeID, posterID, archived)
431445
ctx.Data["OpenLink"] = fmt.Sprintf(linkStr, ctx.Link,
432446
url.QueryEscape(keyword), url.QueryEscape(viewType), url.QueryEscape(sortType), "open", url.QueryEscape(selectLabels),
433447
mentionedID, projectID, assigneeID, posterID, archived)
@@ -442,11 +456,13 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
442456
ctx.Data["ProjectID"] = projectID
443457
ctx.Data["AssigneeID"] = assigneeID
444458
ctx.Data["PosterID"] = posterID
445-
ctx.Data["IsShowClosed"] = isShowClosed
446459
ctx.Data["Keyword"] = keyword
447-
if isShowClosed {
460+
switch isShowClosed {
461+
case util.OptionalBoolTrue:
448462
ctx.Data["State"] = "closed"
449-
} else {
463+
case util.OptionalBoolNone:
464+
ctx.Data["State"] = "all"
465+
default:
450466
ctx.Data["State"] = "open"
451467
}
452468
ctx.Data["ShowArchivedLabels"] = archived

templates/repo/issue/openclose.tmpl

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<div class="small-menu-items ui compact tiny menu">
2-
<a class="{{if not .IsShowClosed}}active {{end}}item" href="{{.OpenLink}}">
2+
<a class="{{if eq .State "open"}}active {{end}}item" href="{{if eq .State "open"}}{{.AllStatesLink}}{{else}}{{.OpenLink}}{{end}}">
33
{{if .PageIsMilestones}}
44
{{svg "octicon-milestone" 16 "gt-mr-3"}}
55
{{else if .PageIsPullList}}
@@ -9,7 +9,7 @@
99
{{end}}
1010
{{ctx.Locale.PrettyNumber .OpenCount}}&nbsp;{{ctx.Locale.Tr "repo.issues.open_title"}}
1111
</a>
12-
<a class="{{if .IsShowClosed}}active {{end}}item" href="{{.ClosedLink}}">
12+
<a class="{{if eq .State "closed"}}active {{end}}item" href="{{if eq .State "closed"}}{{.AllStatesLink}}{{else}}{{.ClosedLink}}{{end}}">
1313
{{svg "octicon-check" 16 "gt-mr-3"}}
1414
{{ctx.Locale.PrettyNumber .ClosedCount}}&nbsp;{{ctx.Locale.Tr "repo.issues.closed_title"}}
1515
</a>

0 commit comments

Comments
 (0)