diff options
author | wxiaoguang <wxiaoguang@gmail.com> | 2024-12-11 14:33:24 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-12-11 06:33:24 +0000 |
commit | e619384098419569e570796a57ee6af4948067ae (patch) | |
tree | 9c5413be580d91ed9912878f80336eab89543670 /routers/web/shared | |
parent | 734ddf71180a9bf843d12dd9664eed28ba1a5748 (diff) | |
download | gitea-e619384098419569e570796a57ee6af4948067ae.tar.gz gitea-e619384098419569e570796a57ee6af4948067ae.zip |
Add label/author/assignee filters to the user/org home issue list (#32779)
Replace #26661, fix #25979
Not perfect, but usable and much better than before. Since it is quite
complex, I am not quite sure whether there would be any regression, if
any, I will fix in first time.
I have tested the related pages many times: issue list, milestone issue
list, project view, user issue list, org issue list.
Diffstat (limited to 'routers/web/shared')
-rw-r--r-- | routers/web/shared/issue/issue_label.go | 71 | ||||
-rw-r--r-- | routers/web/shared/user/helper.go | 17 |
2 files changed, 82 insertions, 6 deletions
diff --git a/routers/web/shared/issue/issue_label.go b/routers/web/shared/issue/issue_label.go new file mode 100644 index 0000000000..eacea36b02 --- /dev/null +++ b/routers/web/shared/issue/issue_label.go @@ -0,0 +1,71 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package issue + +import ( + "strings" + + "code.gitea.io/gitea/models/db" + issues_model "code.gitea.io/gitea/models/issues" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/services/context" +) + +// PrepareFilterIssueLabels reads the "labels" query parameter, sets `ctx.Data["Labels"]` and `ctx.Data["SelectLabels"]` +func PrepareFilterIssueLabels(ctx *context.Context, repoID int64, owner *user_model.User) (labelIDs []int64) { + // 1,-2 means including label 1 and excluding label 2 + // 0 means issues with no label + // blank means labels will not be filtered for issues + selectLabels := ctx.FormString("labels") + if selectLabels != "" { + var err error + labelIDs, err = base.StringsToInt64s(strings.Split(selectLabels, ",")) + if err != nil { + ctx.Flash.Error(ctx.Tr("invalid_data", selectLabels), true) + } + } + + var allLabels []*issues_model.Label + if repoID != 0 { + repoLabels, err := issues_model.GetLabelsByRepoID(ctx, repoID, "", db.ListOptions{}) + if err != nil { + ctx.ServerError("GetLabelsByRepoID", err) + return nil + } + allLabels = append(allLabels, repoLabels...) + } + + if owner != nil && owner.IsOrganization() { + orgLabels, err := issues_model.GetLabelsByOrgID(ctx, owner.ID, "", db.ListOptions{}) + if err != nil { + ctx.ServerError("GetLabelsByOrgID", err) + return nil + } + allLabels = append(allLabels, orgLabels...) + } + + // Get the exclusive scope for every label ID + labelExclusiveScopes := make([]string, 0, len(labelIDs)) + for _, labelID := range labelIDs { + foundExclusiveScope := false + for _, label := range allLabels { + if label.ID == labelID || label.ID == -labelID { + labelExclusiveScopes = append(labelExclusiveScopes, label.ExclusiveScope()) + foundExclusiveScope = true + break + } + } + if !foundExclusiveScope { + labelExclusiveScopes = append(labelExclusiveScopes, "") + } + } + + for _, l := range allLabels { + l.LoadSelectedLabelsAfterClick(labelIDs, labelExclusiveScopes) + } + ctx.Data["Labels"] = allLabels + ctx.Data["SelectLabels"] = selectLabels + return labelIDs +} diff --git a/routers/web/shared/user/helper.go b/routers/web/shared/user/helper.go index 7268767e0a..b82181a1df 100644 --- a/routers/web/shared/user/helper.go +++ b/routers/web/shared/user/helper.go @@ -8,7 +8,9 @@ import ( "slices" "strconv" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/optional" ) func MakeSelfOnTop(doer *user.User, users []*user.User) []*user.User { @@ -31,17 +33,20 @@ func MakeSelfOnTop(doer *user.User, users []*user.User) []*user.User { // Before, the "issue filter" passes user ID to query the list, but in many cases, it's impossible to pre-fetch the full user list. // So it's better to make it work like GitHub: users could input username directly. // Since it only converts the username to ID directly and is only used internally (to search issues), so no permission check is needed. -// Old usage: poster=123, new usage: poster=the-username (at the moment, non-existing username is treated as poster=0, not ideal but acceptable) -func GetFilterUserIDByName(ctx context.Context, name string) int64 { +// Return values: +// * nil: no filter +// * some(id): match the id, the id could be -1 to match the issues without assignee +// * some(NonExistingID): match no issue (due to the user doesn't exist) +func GetFilterUserIDByName(ctx context.Context, name string) optional.Option[int64] { if name == "" { - return 0 + return optional.None[int64]() } u, err := user.GetUserByName(ctx, name) if err != nil { if id, err := strconv.ParseInt(name, 10, 64); err == nil { - return id + return optional.Some(id) } - return 0 + return optional.Some(db.NonExistingID) } - return u.ID + return optional.Some(u.ID) } |