mirror of
https://github.com/go-gitea/gitea.git
synced 2024-12-28 16:36:53 +00:00
Refactor issue list (#32755)
1. add backend support for filtering "poster" and "assignee" * due to the limits, there is no frontend support at the moment 2. rewrite TS code without jquery, now there are 14 jQuery files left:
This commit is contained in:
parent
9d08d3fbf5
commit
23471e1333
@ -42,6 +42,7 @@ func NewFuncMap() template.FuncMap {
|
|||||||
"HTMLFormat": htmlutil.HTMLFormat,
|
"HTMLFormat": htmlutil.HTMLFormat,
|
||||||
"HTMLEscape": htmlEscape,
|
"HTMLEscape": htmlEscape,
|
||||||
"QueryEscape": queryEscape,
|
"QueryEscape": queryEscape,
|
||||||
|
"QueryBuild": queryBuild,
|
||||||
"JSEscape": jsEscapeSafe,
|
"JSEscape": jsEscapeSafe,
|
||||||
"SanitizeHTML": SanitizeHTML,
|
"SanitizeHTML": SanitizeHTML,
|
||||||
"URLJoin": util.URLJoin,
|
"URLJoin": util.URLJoin,
|
||||||
@ -293,6 +294,71 @@ func timeEstimateString(timeSec any) string {
|
|||||||
return util.TimeEstimateString(v)
|
return util.TimeEstimateString(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type QueryString string
|
||||||
|
|
||||||
|
func queryBuild(a ...any) QueryString {
|
||||||
|
var s string
|
||||||
|
if len(a)%2 == 1 {
|
||||||
|
if v, ok := a[0].(string); ok {
|
||||||
|
if v == "" || (v[0] != '?' && v[0] != '&') {
|
||||||
|
panic("queryBuild: invalid argument")
|
||||||
|
}
|
||||||
|
s = v
|
||||||
|
} else if v, ok := a[0].(QueryString); ok {
|
||||||
|
s = string(v)
|
||||||
|
} else {
|
||||||
|
panic("queryBuild: invalid argument")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := len(a) % 2; i < len(a); i += 2 {
|
||||||
|
k, ok := a[i].(string)
|
||||||
|
if !ok {
|
||||||
|
panic("queryBuild: invalid argument")
|
||||||
|
}
|
||||||
|
var v string
|
||||||
|
if va, ok := a[i+1].(string); ok {
|
||||||
|
v = va
|
||||||
|
} else if a[i+1] != nil {
|
||||||
|
v = fmt.Sprint(a[i+1])
|
||||||
|
}
|
||||||
|
// pos1 to pos2 is the "k=v&" part, "&" is optional
|
||||||
|
pos1 := strings.Index(s, "&"+k+"=")
|
||||||
|
if pos1 != -1 {
|
||||||
|
pos1++
|
||||||
|
} else {
|
||||||
|
pos1 = strings.Index(s, "?"+k+"=")
|
||||||
|
if pos1 != -1 {
|
||||||
|
pos1++
|
||||||
|
} else if strings.HasPrefix(s, k+"=") {
|
||||||
|
pos1 = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos2 := len(s)
|
||||||
|
if pos1 == -1 {
|
||||||
|
pos1 = len(s)
|
||||||
|
} else {
|
||||||
|
pos2 = pos1 + 1
|
||||||
|
for pos2 < len(s) && s[pos2-1] != '&' {
|
||||||
|
pos2++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v != "" {
|
||||||
|
sep := ""
|
||||||
|
hasPrefixSep := pos1 == 0 || (pos1 <= len(s) && (s[pos1-1] == '?' || s[pos1-1] == '&'))
|
||||||
|
if !hasPrefixSep {
|
||||||
|
sep = "&"
|
||||||
|
}
|
||||||
|
s = s[:pos1] + sep + k + "=" + url.QueryEscape(v) + "&" + s[pos2:]
|
||||||
|
} else {
|
||||||
|
s = s[:pos1] + s[pos2:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if s != "" && s != "&" && s[len(s)-1] == '&' {
|
||||||
|
s = s[:len(s)-1]
|
||||||
|
}
|
||||||
|
return QueryString(s)
|
||||||
|
}
|
||||||
|
|
||||||
func panicIfDevOrTesting() {
|
func panicIfDevOrTesting() {
|
||||||
if !setting.IsProd || setting.IsInTesting {
|
if !setting.IsProd || setting.IsInTesting {
|
||||||
panic("legacy template functions are for backward compatibility only, do not use them in new code")
|
panic("legacy template functions are for backward compatibility only, do not use them in new code")
|
||||||
|
@ -504,19 +504,16 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt
|
|||||||
if !util.SliceContainsString(types, viewType, true) {
|
if !util.SliceContainsString(types, viewType, true) {
|
||||||
viewType = "all"
|
viewType = "all"
|
||||||
}
|
}
|
||||||
|
// TODO: "assignee" should also use GetFilterUserIDByName in the future to support usernames directly
|
||||||
var (
|
assigneeID := ctx.FormInt64("assignee")
|
||||||
assigneeID = ctx.FormInt64("assignee")
|
posterUsername := ctx.FormString("poster")
|
||||||
posterID = ctx.FormInt64("poster")
|
posterUserID := shared_user.GetFilterUserIDByName(ctx, posterUsername)
|
||||||
mentionedID int64
|
var mentionedID, reviewRequestedID, reviewedID int64
|
||||||
reviewRequestedID int64
|
|
||||||
reviewedID int64
|
|
||||||
)
|
|
||||||
|
|
||||||
if ctx.IsSigned {
|
if ctx.IsSigned {
|
||||||
switch viewType {
|
switch viewType {
|
||||||
case "created_by":
|
case "created_by":
|
||||||
posterID = ctx.Doer.ID
|
posterUserID = ctx.Doer.ID
|
||||||
case "mentioned":
|
case "mentioned":
|
||||||
mentionedID = ctx.Doer.ID
|
mentionedID = ctx.Doer.ID
|
||||||
case "assigned":
|
case "assigned":
|
||||||
@ -564,7 +561,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt
|
|||||||
ProjectID: projectID,
|
ProjectID: projectID,
|
||||||
AssigneeID: assigneeID,
|
AssigneeID: assigneeID,
|
||||||
MentionedID: mentionedID,
|
MentionedID: mentionedID,
|
||||||
PosterID: posterID,
|
PosterID: posterUserID,
|
||||||
ReviewRequestedID: reviewRequestedID,
|
ReviewRequestedID: reviewRequestedID,
|
||||||
ReviewedID: reviewedID,
|
ReviewedID: reviewedID,
|
||||||
IsPull: isPullOption,
|
IsPull: isPullOption,
|
||||||
@ -646,7 +643,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt
|
|||||||
},
|
},
|
||||||
RepoIDs: []int64{repo.ID},
|
RepoIDs: []int64{repo.ID},
|
||||||
AssigneeID: assigneeID,
|
AssigneeID: assigneeID,
|
||||||
PosterID: posterID,
|
PosterID: posterUserID,
|
||||||
MentionedID: mentionedID,
|
MentionedID: mentionedID,
|
||||||
ReviewRequestedID: reviewRequestedID,
|
ReviewRequestedID: reviewRequestedID,
|
||||||
ReviewedID: reviewedID,
|
ReviewedID: reviewedID,
|
||||||
@ -800,16 +797,16 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt
|
|||||||
ctx.Data["IssueStats"] = issueStats
|
ctx.Data["IssueStats"] = issueStats
|
||||||
ctx.Data["OpenCount"] = issueStats.OpenCount
|
ctx.Data["OpenCount"] = issueStats.OpenCount
|
||||||
ctx.Data["ClosedCount"] = issueStats.ClosedCount
|
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"
|
linkStr := "%s?q=%s&type=%s&sort=%s&state=%s&labels=%s&milestone=%d&project=%d&assignee=%d&poster=%v&archived=%t"
|
||||||
ctx.Data["AllStatesLink"] = fmt.Sprintf(linkStr, ctx.Link,
|
ctx.Data["AllStatesLink"] = fmt.Sprintf(linkStr, ctx.Link,
|
||||||
url.QueryEscape(keyword), url.QueryEscape(viewType), url.QueryEscape(sortType), "all", url.QueryEscape(selectLabels),
|
url.QueryEscape(keyword), url.QueryEscape(viewType), url.QueryEscape(sortType), "all", url.QueryEscape(selectLabels),
|
||||||
milestoneID, projectID, assigneeID, posterID, archived)
|
milestoneID, projectID, assigneeID, url.QueryEscape(posterUsername), archived)
|
||||||
ctx.Data["OpenLink"] = fmt.Sprintf(linkStr, ctx.Link,
|
ctx.Data["OpenLink"] = fmt.Sprintf(linkStr, ctx.Link,
|
||||||
url.QueryEscape(keyword), url.QueryEscape(viewType), url.QueryEscape(sortType), "open", url.QueryEscape(selectLabels),
|
url.QueryEscape(keyword), url.QueryEscape(viewType), url.QueryEscape(sortType), "open", url.QueryEscape(selectLabels),
|
||||||
milestoneID, projectID, assigneeID, posterID, archived)
|
milestoneID, projectID, assigneeID, url.QueryEscape(posterUsername), archived)
|
||||||
ctx.Data["ClosedLink"] = fmt.Sprintf(linkStr, ctx.Link,
|
ctx.Data["ClosedLink"] = fmt.Sprintf(linkStr, ctx.Link,
|
||||||
url.QueryEscape(keyword), url.QueryEscape(viewType), url.QueryEscape(sortType), "closed", url.QueryEscape(selectLabels),
|
url.QueryEscape(keyword), url.QueryEscape(viewType), url.QueryEscape(sortType), "closed", url.QueryEscape(selectLabels),
|
||||||
milestoneID, projectID, assigneeID, posterID, archived)
|
milestoneID, projectID, assigneeID, url.QueryEscape(posterUsername), archived)
|
||||||
ctx.Data["SelLabelIDs"] = labelIDs
|
ctx.Data["SelLabelIDs"] = labelIDs
|
||||||
ctx.Data["SelectLabels"] = selectLabels
|
ctx.Data["SelectLabels"] = selectLabels
|
||||||
ctx.Data["ViewType"] = viewType
|
ctx.Data["ViewType"] = viewType
|
||||||
@ -817,7 +814,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt
|
|||||||
ctx.Data["MilestoneID"] = milestoneID
|
ctx.Data["MilestoneID"] = milestoneID
|
||||||
ctx.Data["ProjectID"] = projectID
|
ctx.Data["ProjectID"] = projectID
|
||||||
ctx.Data["AssigneeID"] = assigneeID
|
ctx.Data["AssigneeID"] = assigneeID
|
||||||
ctx.Data["PosterID"] = posterID
|
ctx.Data["PosterUsername"] = posterUsername
|
||||||
ctx.Data["Keyword"] = keyword
|
ctx.Data["Keyword"] = keyword
|
||||||
ctx.Data["IsShowClosed"] = isShowClosed
|
ctx.Data["IsShowClosed"] = isShowClosed
|
||||||
switch {
|
switch {
|
||||||
@ -838,7 +835,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt
|
|||||||
pager.AddParamString("milestone", fmt.Sprint(milestoneID))
|
pager.AddParamString("milestone", fmt.Sprint(milestoneID))
|
||||||
pager.AddParamString("project", fmt.Sprint(projectID))
|
pager.AddParamString("project", fmt.Sprint(projectID))
|
||||||
pager.AddParamString("assignee", fmt.Sprint(assigneeID))
|
pager.AddParamString("assignee", fmt.Sprint(assigneeID))
|
||||||
pager.AddParamString("poster", fmt.Sprint(posterID))
|
pager.AddParamString("poster", posterUsername)
|
||||||
pager.AddParamString("archived", fmt.Sprint(archived))
|
pager.AddParamString("archived", fmt.Sprint(archived))
|
||||||
|
|
||||||
ctx.Data["Page"] = pager
|
ctx.Data["Page"] = pager
|
||||||
|
@ -4,7 +4,9 @@
|
|||||||
package user
|
package user
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"slices"
|
"slices"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/user"
|
"code.gitea.io/gitea/models/user"
|
||||||
)
|
)
|
||||||
@ -24,3 +26,22 @@ func MakeSelfOnTop(doer *user.User, users []*user.User) []*user.User {
|
|||||||
}
|
}
|
||||||
return users
|
return users
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetFilterUserIDByName tries to get the user ID from the given username.
|
||||||
|
// 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 {
|
||||||
|
if name == "" {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
u, err := user.GetUserByName(ctx, name)
|
||||||
|
if err != nil {
|
||||||
|
if id, err := strconv.ParseInt(name, 10, 64); err == nil {
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return u.ID
|
||||||
|
}
|
||||||
|
@ -31,7 +31,9 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/markup/markdown"
|
"code.gitea.io/gitea/modules/markup/markdown"
|
||||||
"code.gitea.io/gitea/modules/optional"
|
"code.gitea.io/gitea/modules/optional"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/routers/web/feed"
|
"code.gitea.io/gitea/routers/web/feed"
|
||||||
|
"code.gitea.io/gitea/routers/web/shared/user"
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
feed_service "code.gitea.io/gitea/services/feed"
|
feed_service "code.gitea.io/gitea/services/feed"
|
||||||
issue_service "code.gitea.io/gitea/services/issue"
|
issue_service "code.gitea.io/gitea/services/issue"
|
||||||
@ -375,16 +377,8 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
viewType string
|
|
||||||
sortType = ctx.FormString("sort")
|
|
||||||
filterMode int
|
|
||||||
)
|
|
||||||
|
|
||||||
// Default to recently updated, unlike repository issues list
|
// Default to recently updated, unlike repository issues list
|
||||||
if sortType == "" {
|
sortType := util.IfZero(ctx.FormString("sort"), "recentupdate")
|
||||||
sortType = "recentupdate"
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------
|
||||||
// Distinguish User from Organization.
|
// Distinguish User from Organization.
|
||||||
@ -399,7 +393,8 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
|
|||||||
|
|
||||||
// TODO: distinguish during routing
|
// TODO: distinguish during routing
|
||||||
|
|
||||||
viewType = ctx.FormString("type")
|
viewType := ctx.FormString("type")
|
||||||
|
var filterMode int
|
||||||
switch viewType {
|
switch viewType {
|
||||||
case "assigned":
|
case "assigned":
|
||||||
filterMode = issues_model.FilterModeAssign
|
filterMode = issues_model.FilterModeAssign
|
||||||
@ -443,6 +438,14 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
|
|||||||
Team: team,
|
Team: team,
|
||||||
User: ctx.Doer,
|
User: ctx.Doer,
|
||||||
}
|
}
|
||||||
|
// Get filter by author id & assignee id
|
||||||
|
// FIXME: this feature doesn't work at the moment, because frontend can't use a "user-remote-search" dropdown directly
|
||||||
|
// the existing "/posters" handlers doesn't work for this case, it is unable to list the related users correctly.
|
||||||
|
// In the future, we need something like github: "author:user1" to accept usernames directly.
|
||||||
|
posterUsername := ctx.FormString("poster")
|
||||||
|
opts.PosterID = user.GetFilterUserIDByName(ctx, posterUsername)
|
||||||
|
// TODO: "assignee" should also use GetFilterUserIDByName in the future to support usernames directly
|
||||||
|
opts.AssigneeID, _ = strconv.ParseInt(ctx.FormString("assignee"), 10, 64)
|
||||||
|
|
||||||
isFuzzy := ctx.FormBool("fuzzy")
|
isFuzzy := ctx.FormBool("fuzzy")
|
||||||
|
|
||||||
@ -573,8 +576,22 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
|
|||||||
// -------------------------------
|
// -------------------------------
|
||||||
// Fill stats to post to ctx.Data.
|
// Fill stats to post to ctx.Data.
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
issueStats, err := getUserIssueStats(ctx, ctxUser, filterMode, issue_indexer.ToSearchOptions(keyword, opts).Copy(
|
issueStats, err := getUserIssueStats(ctx, filterMode, issue_indexer.ToSearchOptions(keyword, opts).Copy(
|
||||||
func(o *issue_indexer.SearchOptions) { o.IsFuzzyKeyword = isFuzzy },
|
func(o *issue_indexer.SearchOptions) {
|
||||||
|
o.IsFuzzyKeyword = isFuzzy
|
||||||
|
// If the doer is the same as the context user, which means the doer is viewing his own dashboard,
|
||||||
|
// it's not enough to show the repos that the doer owns or has been explicitly granted access to,
|
||||||
|
// because the doer may create issues or be mentioned in any public repo.
|
||||||
|
// So we need search issues in all public repos.
|
||||||
|
o.AllPublic = ctx.Doer.ID == ctxUser.ID
|
||||||
|
// TODO: to make it work with poster/assignee filter, then these IDs should be kept
|
||||||
|
o.AssigneeID = nil
|
||||||
|
o.PosterID = nil
|
||||||
|
|
||||||
|
o.MentionID = nil
|
||||||
|
o.ReviewRequestedID = nil
|
||||||
|
o.ReviewedID = nil
|
||||||
|
},
|
||||||
))
|
))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("getUserIssueStats", err)
|
ctx.ServerError("getUserIssueStats", err)
|
||||||
@ -630,6 +647,8 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
|
|||||||
ctx.Data["IsShowClosed"] = isShowClosed
|
ctx.Data["IsShowClosed"] = isShowClosed
|
||||||
ctx.Data["SelectLabels"] = selectedLabels
|
ctx.Data["SelectLabels"] = selectedLabels
|
||||||
ctx.Data["IsFuzzy"] = isFuzzy
|
ctx.Data["IsFuzzy"] = isFuzzy
|
||||||
|
ctx.Data["SearchFilterPosterID"] = util.Iif[any](opts.PosterID != 0, opts.PosterID, nil)
|
||||||
|
ctx.Data["SearchFilterAssigneeID"] = util.Iif[any](opts.AssigneeID != 0, opts.AssigneeID, nil)
|
||||||
|
|
||||||
if isShowClosed {
|
if isShowClosed {
|
||||||
ctx.Data["State"] = "closed"
|
ctx.Data["State"] = "closed"
|
||||||
@ -643,7 +662,11 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
|
|||||||
pager.AddParamString("sort", sortType)
|
pager.AddParamString("sort", sortType)
|
||||||
pager.AddParamString("state", fmt.Sprint(ctx.Data["State"]))
|
pager.AddParamString("state", fmt.Sprint(ctx.Data["State"]))
|
||||||
pager.AddParamString("labels", selectedLabels)
|
pager.AddParamString("labels", selectedLabels)
|
||||||
pager.AddParamString("fuzzy", fmt.Sprintf("%v", isFuzzy))
|
pager.AddParamString("fuzzy", fmt.Sprint(isFuzzy))
|
||||||
|
pager.AddParamString("poster", posterUsername)
|
||||||
|
if opts.AssigneeID != 0 {
|
||||||
|
pager.AddParamString("assignee", fmt.Sprint(opts.AssigneeID))
|
||||||
|
}
|
||||||
ctx.Data["Page"] = pager
|
ctx.Data["Page"] = pager
|
||||||
|
|
||||||
ctx.HTML(http.StatusOK, tplIssues)
|
ctx.HTML(http.StatusOK, tplIssues)
|
||||||
@ -768,27 +791,10 @@ func UsernameSubRoute(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUserIssueStats(ctx *context.Context, ctxUser *user_model.User, filterMode int, opts *issue_indexer.SearchOptions) (*issues_model.IssueStats, error) {
|
func getUserIssueStats(ctx *context.Context, filterMode int, opts *issue_indexer.SearchOptions) (ret *issues_model.IssueStats, err error) {
|
||||||
|
ret = &issues_model.IssueStats{}
|
||||||
doerID := ctx.Doer.ID
|
doerID := ctx.Doer.ID
|
||||||
|
|
||||||
opts = opts.Copy(func(o *issue_indexer.SearchOptions) {
|
|
||||||
// If the doer is the same as the context user, which means the doer is viewing his own dashboard,
|
|
||||||
// it's not enough to show the repos that the doer owns or has been explicitly granted access to,
|
|
||||||
// because the doer may create issues or be mentioned in any public repo.
|
|
||||||
// So we need search issues in all public repos.
|
|
||||||
o.AllPublic = doerID == ctxUser.ID
|
|
||||||
o.AssigneeID = nil
|
|
||||||
o.PosterID = nil
|
|
||||||
o.MentionID = nil
|
|
||||||
o.ReviewRequestedID = nil
|
|
||||||
o.ReviewedID = nil
|
|
||||||
})
|
|
||||||
|
|
||||||
var (
|
|
||||||
err error
|
|
||||||
ret = &issues_model.IssueStats{}
|
|
||||||
)
|
|
||||||
|
|
||||||
{
|
{
|
||||||
openClosedOpts := opts.Copy()
|
openClosedOpts := opts.Copy()
|
||||||
switch filterMode {
|
switch filterMode {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
{{$queryLink := QueryBuild "?" "q" $.Keyword "type" $.ViewType "sort" $.SortType "state" $.State "labels" $.SelectLabels "milestone" $.MilestoneID "project" $.ProjectID "assignee" $.AssigneeID "poster" $.PosterUsername "archived" (Iif $.ShowArchivedLabels NIL)}}
|
||||||
<!-- Label -->
|
<!-- Label -->
|
||||||
<div class="ui {{if not .Labels}}disabled{{end}} dropdown jump item label-filter">
|
<div class="ui {{if not .Labels}}disabled{{end}} dropdown jump item label-filter">
|
||||||
<span class="text">
|
<span class="text">
|
||||||
@ -23,8 +24,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<span class="info">{{ctx.Locale.Tr "repo.issues.filter_label_exclude"}}</span>
|
<span class="info">{{ctx.Locale.Tr "repo.issues.filter_label_exclude"}}</span>
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
<a class="{{if .AllLabels}}active selected {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_label_no_select"}}</a>
|
<a class="{{if .AllLabels}}active selected {{end}}item" href="{{QueryBuild $queryLink "labels" NIL}}">{{ctx.Locale.Tr "repo.issues.filter_label_no_select"}}</a>
|
||||||
<a class="{{if .NoLabel}}active selected {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels=0&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_label_select_no_label"}}</a>
|
<a class="{{if .NoLabel}}active selected {{end}}item" href="{{QueryBuild $queryLink "labels" 0}}">{{ctx.Locale.Tr "repo.issues.filter_label_select_no_label"}}</a>
|
||||||
{{$previousExclusiveScope := "_no_scope"}}
|
{{$previousExclusiveScope := "_no_scope"}}
|
||||||
{{range .Labels}}
|
{{range .Labels}}
|
||||||
{{$exclusiveScope := .ExclusiveScope}}
|
{{$exclusiveScope := .ExclusiveScope}}
|
||||||
@ -32,7 +33,7 @@
|
|||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{$previousExclusiveScope = $exclusiveScope}}
|
{{$previousExclusiveScope = $exclusiveScope}}
|
||||||
<a class="item label-filter-item tw-flex tw-items-center" {{if .IsArchived}}data-is-archived{{end}} href="?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.QueryString}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}" data-label-id="{{.ID}}">
|
<a class="item label-filter-item tw-flex tw-items-center" {{if .IsArchived}}data-is-archived{{end}} href="{{QueryBuild $queryLink "labels" .QueryString}}" data-label-id="{{.ID}}">
|
||||||
{{if .IsExcluded}}
|
{{if .IsExcluded}}
|
||||||
{{svg "octicon-circle-slash"}}
|
{{svg "octicon-circle-slash"}}
|
||||||
{{else if .IsSelected}}
|
{{else if .IsSelected}}
|
||||||
@ -62,13 +63,13 @@
|
|||||||
<input type="text" placeholder="{{ctx.Locale.Tr "repo.issues.filter_milestone"}}">
|
<input type="text" placeholder="{{ctx.Locale.Tr "repo.issues.filter_milestone"}}">
|
||||||
</div>
|
</div>
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
<a class="{{if not $.MilestoneID}}active selected {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone=0&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_milestone_all"}}</a>
|
<a class="{{if not $.MilestoneID}}active selected {{end}}item" href="{{QueryBuild $queryLink "milestone" 0}}">{{ctx.Locale.Tr "repo.issues.filter_milestone_all"}}</a>
|
||||||
<a class="{{if $.MilestoneID}}{{if eq $.MilestoneID -1}}active selected {{end}}{{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone=-1&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_milestone_none"}}</a>
|
<a class="{{if $.MilestoneID}}{{if eq $.MilestoneID -1}}active selected {{end}}{{end}}item" href="{{QueryBuild $queryLink "milestone" -1}}">{{ctx.Locale.Tr "repo.issues.filter_milestone_none"}}</a>
|
||||||
{{if .OpenMilestones}}
|
{{if .OpenMilestones}}
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
<div class="header">{{ctx.Locale.Tr "repo.issues.filter_milestone_open"}}</div>
|
<div class="header">{{ctx.Locale.Tr "repo.issues.filter_milestone_open"}}</div>
|
||||||
{{range .OpenMilestones}}
|
{{range .OpenMilestones}}
|
||||||
<a class="{{if $.MilestoneID}}{{if eq $.MilestoneID .ID}}active selected {{end}}{{end}}item" href="?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{.ID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">
|
<a class="{{if $.MilestoneID}}{{if eq $.MilestoneID .ID}}active selected {{end}}{{end}}item" href="{{QueryBuild $queryLink "milestone" .ID}}">
|
||||||
{{svg "octicon-milestone" 16 "mr-2"}}
|
{{svg "octicon-milestone" 16 "mr-2"}}
|
||||||
{{.Name}}
|
{{.Name}}
|
||||||
</a>
|
</a>
|
||||||
@ -78,7 +79,7 @@
|
|||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
<div class="header">{{ctx.Locale.Tr "repo.issues.filter_milestone_closed"}}</div>
|
<div class="header">{{ctx.Locale.Tr "repo.issues.filter_milestone_closed"}}</div>
|
||||||
{{range .ClosedMilestones}}
|
{{range .ClosedMilestones}}
|
||||||
<a class="{{if $.MilestoneID}}{{if eq $.MilestoneID .ID}}active selected {{end}}{{end}}item" href="?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{.ID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">
|
<a class="{{if $.MilestoneID}}{{if eq $.MilestoneID .ID}}active selected {{end}}{{end}}item" href="{{QueryBuild $queryLink "milestone" .ID}}">
|
||||||
{{svg "octicon-milestone" 16 "mr-2"}}
|
{{svg "octicon-milestone" 16 "mr-2"}}
|
||||||
{{.Name}}
|
{{.Name}}
|
||||||
</a>
|
</a>
|
||||||
@ -99,15 +100,15 @@
|
|||||||
<i class="icon">{{svg "octicon-search" 16}}</i>
|
<i class="icon">{{svg "octicon-search" 16}}</i>
|
||||||
<input type="text" placeholder="{{ctx.Locale.Tr "repo.issues.filter_project"}}">
|
<input type="text" placeholder="{{ctx.Locale.Tr "repo.issues.filter_project"}}">
|
||||||
</div>
|
</div>
|
||||||
<a class="{{if not .ProjectID}}active selected {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_project_all"}}</a>
|
<a class="{{if not .ProjectID}}active selected {{end}}item" href="{{QueryBuild $queryLink "project" NIL}}">{{ctx.Locale.Tr "repo.issues.filter_project_all"}}</a>
|
||||||
<a class="{{if eq .ProjectID -1}}active selected {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&project=-1&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_project_none"}}</a>
|
<a class="{{if eq .ProjectID -1}}active selected {{end}}item" href="{{QueryBuild $queryLink "project" -1}}">{{ctx.Locale.Tr "repo.issues.filter_project_none"}}</a>
|
||||||
{{if .OpenProjects}}
|
{{if .OpenProjects}}
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{ctx.Locale.Tr "repo.issues.new.open_projects"}}
|
{{ctx.Locale.Tr "repo.issues.new.open_projects"}}
|
||||||
</div>
|
</div>
|
||||||
{{range .OpenProjects}}
|
{{range .OpenProjects}}
|
||||||
<a class="{{if $.ProjectID}}{{if eq $.ProjectID .ID}}active selected{{end}}{{end}} item tw-flex" href="?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{$.MilestoneID}}&project={{.ID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">
|
<a class="{{if $.ProjectID}}{{if eq $.ProjectID .ID}}active selected{{end}}{{end}} item tw-flex" href="{{QueryBuild $queryLink "project" .ID}}">
|
||||||
{{svg .IconName 18 "tw-mr-2 tw-shrink-0"}}<span class="gt-ellipsis">{{.Title}}</span>
|
{{svg .IconName 18 "tw-mr-2 tw-shrink-0"}}<span class="gt-ellipsis">{{.Title}}</span>
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
@ -118,7 +119,7 @@
|
|||||||
{{ctx.Locale.Tr "repo.issues.new.closed_projects"}}
|
{{ctx.Locale.Tr "repo.issues.new.closed_projects"}}
|
||||||
</div>
|
</div>
|
||||||
{{range .ClosedProjects}}
|
{{range .ClosedProjects}}
|
||||||
<a class="{{if $.ProjectID}}{{if eq $.ProjectID .ID}}active selected{{end}}{{end}} item" href="?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{$.MilestoneID}}&project={{.ID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">
|
<a class="{{if $.ProjectID}}{{if eq $.ProjectID .ID}}active selected{{end}}{{end}} item" href="{{QueryBuild $queryLink "project" .ID}}">
|
||||||
{{svg .IconName 18 "tw-mr-2"}}{{.Title}}
|
{{svg .IconName 18 "tw-mr-2"}}{{.Title}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
@ -130,7 +131,7 @@
|
|||||||
<div class="ui dropdown jump item user-remote-search" data-tooltip-content="{{ctx.Locale.Tr "repo.author_search_tooltip"}}"
|
<div class="ui dropdown jump item user-remote-search" data-tooltip-content="{{ctx.Locale.Tr "repo.author_search_tooltip"}}"
|
||||||
data-search-url="{{if .Milestone}}{{$.RepoLink}}/issues/posters{{else}}{{$.Link}}/posters{{end}}"
|
data-search-url="{{if .Milestone}}{{$.RepoLink}}/issues/posters{{else}}{{$.Link}}/posters{{end}}"
|
||||||
data-selected-user-id="{{$.PosterID}}"
|
data-selected-user-id="{{$.PosterID}}"
|
||||||
data-action-jump-url="?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={user_id}{{if $.ShowArchivedLabels}}&archived=true{{end}}"
|
data-action-jump-url="{{QueryBuild $queryLink "poster" NIL}}&poster={username}"
|
||||||
>
|
>
|
||||||
<span class="text">
|
<span class="text">
|
||||||
{{ctx.Locale.Tr "repo.issues.filter_poster"}}
|
{{ctx.Locale.Tr "repo.issues.filter_poster"}}
|
||||||
@ -156,11 +157,11 @@
|
|||||||
<i class="icon">{{svg "octicon-search" 16}}</i>
|
<i class="icon">{{svg "octicon-search" 16}}</i>
|
||||||
<input type="text" placeholder="{{ctx.Locale.Tr "repo.issues.filter_assignee"}}">
|
<input type="text" placeholder="{{ctx.Locale.Tr "repo.issues.filter_assignee"}}">
|
||||||
</div>
|
</div>
|
||||||
<a class="{{if not .AssigneeID}}active selected {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_assginee_no_select"}}</a>
|
<a class="{{if not .AssigneeID}}active selected {{end}}item" href="{{QueryBuild $queryLink "assignee" NIL}}">{{ctx.Locale.Tr "repo.issues.filter_assginee_no_select"}}</a>
|
||||||
<a class="{{if eq .AssigneeID -1}}active selected {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee=-1&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_assginee_no_assignee"}}</a>
|
<a class="{{if eq .AssigneeID -1}}active selected {{end}}item" href="{{QueryBuild $queryLink "assignee" -1}}">{{ctx.Locale.Tr "repo.issues.filter_assginee_no_assignee"}}</a>
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
{{range .Assignees}}
|
{{range .Assignees}}
|
||||||
<a class="{{if eq $.AssigneeID .ID}}active selected{{end}} item tw-flex" href="?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{.ID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">
|
<a class="{{if eq $.AssigneeID .ID}}active selected{{end}} item tw-flex" href="{{QueryBuild $queryLink "assignee" .ID}}">
|
||||||
{{ctx.AvatarUtils.Avatar . 20}}{{template "repo/search_name" .}}
|
{{ctx.AvatarUtils.Avatar . 20}}{{template "repo/search_name" .}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
@ -175,14 +176,14 @@
|
|||||||
</span>
|
</span>
|
||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<a class="{{if eq .ViewType "all"}}active {{end}}item" href="?q={{$.Keyword}}&type=all&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_type.all_issues"}}</a>
|
<a class="{{if eq .ViewType "all"}}active {{end}}item" href="{{QueryBuild $queryLink "type" "all"}}">{{ctx.Locale.Tr "repo.issues.filter_type.all_issues"}}</a>
|
||||||
<a class="{{if eq .ViewType "assigned"}}active {{end}}item" href="?q={{$.Keyword}}&type=assigned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_type.assigned_to_you"}}</a>
|
<a class="{{if eq .ViewType "assigned"}}active {{end}}item" href="{{QueryBuild $queryLink "type" "assigned"}}">{{ctx.Locale.Tr "repo.issues.filter_type.assigned_to_you"}}</a>
|
||||||
<a class="{{if eq .ViewType "created_by"}}active {{end}}item" href="?q={{$.Keyword}}&type=created_by&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_type.created_by_you"}}</a>
|
<a class="{{if eq .ViewType "created_by"}}active {{end}}item" href="{{QueryBuild $queryLink "type" "created_by"}}">{{ctx.Locale.Tr "repo.issues.filter_type.created_by_you"}}</a>
|
||||||
{{if .PageIsPullList}}
|
{{if .PageIsPullList}}
|
||||||
<a class="{{if eq .ViewType "review_requested"}}active {{end}}item" href="?q={{$.Keyword}}&type=review_requested&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_type.review_requested"}}</a>
|
<a class="{{if eq .ViewType "review_requested"}}active {{end}}item" href="{{QueryBuild $queryLink "type" "review_requested"}}">{{ctx.Locale.Tr "repo.issues.filter_type.review_requested"}}</a>
|
||||||
<a class="{{if eq .ViewType "reviewed_by"}}active {{end}}item" href="?q={{$.Keyword}}&type=reviewed_by&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_type.reviewed_by_you"}}</a>
|
<a class="{{if eq .ViewType "reviewed_by"}}active {{end}}item" href="{{QueryBuild $queryLink "type" "reviewed_by"}}">{{ctx.Locale.Tr "repo.issues.filter_type.reviewed_by_you"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
<a class="{{if eq .ViewType "mentioned"}}active {{end}}item" href="?q={{$.Keyword}}&type=mentioned&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_type.mentioning_you"}}</a>
|
<a class="{{if eq .ViewType "mentioned"}}active {{end}}item" href="{{QueryBuild $queryLink "type" "mentioned"}}">{{ctx.Locale.Tr "repo.issues.filter_type.mentioning_you"}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
@ -194,13 +195,13 @@
|
|||||||
</span>
|
</span>
|
||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<a class="{{if or (eq .SortType "latest") (not .SortType)}}active {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort=latest&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.latest"}}</a>
|
<a class="{{if or (eq .SortType "latest") (not .SortType)}}active {{end}}item" href="{{QueryBuild $queryLink "sort" "latest"}}">{{ctx.Locale.Tr "repo.issues.filter_sort.latest"}}</a>
|
||||||
<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort=oldest&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.oldest"}}</a>
|
<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="{{QueryBuild $queryLink "sort" "oldest"}}">{{ctx.Locale.Tr "repo.issues.filter_sort.oldest"}}</a>
|
||||||
<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort=recentupdate&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="{{QueryBuild $queryLink "sort" "recentupdate"}}">{{ctx.Locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
||||||
<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort=leastupdate&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="{{QueryBuild $queryLink "sort" "leastupdate"}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
||||||
<a class="{{if eq .SortType "mostcomment"}}active {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort=mostcomment&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.mostcomment"}}</a>
|
<a class="{{if eq .SortType "mostcomment"}}active {{end}}item" href="{{QueryBuild $queryLink "sort" "mostcomment"}}">{{ctx.Locale.Tr "repo.issues.filter_sort.mostcomment"}}</a>
|
||||||
<a class="{{if eq .SortType "leastcomment"}}active {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort=leastcomment&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastcomment"}}</a>
|
<a class="{{if eq .SortType "leastcomment"}}active {{end}}item" href="{{QueryBuild $queryLink "sort" "leastcomment"}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastcomment"}}</a>
|
||||||
<a class="{{if eq .SortType "nearduedate"}}active {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort=nearduedate&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.nearduedate"}}</a>
|
<a class="{{if eq .SortType "nearduedate"}}active {{end}}item" href="{{QueryBuild $queryLink "sort" "nearduedate"}}">{{ctx.Locale.Tr "repo.issues.filter_sort.nearduedate"}}</a>
|
||||||
<a class="{{if eq .SortType "farduedate"}}active {{end}}item" href="?q={{$.Keyword}}&type={{$.ViewType}}&sort=farduedate&state={{$.State}}&labels={{.SelectLabels}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}{{if $.ShowArchivedLabels}}&archived=true{{end}}">{{ctx.Locale.Tr "repo.issues.filter_sort.farduedate"}}</a>
|
<a class="{{if eq .SortType "farduedate"}}active {{end}}item" href="{{QueryBuild $queryLink "sort" "farduedate"}}">{{ctx.Locale.Tr "repo.issues.filter_sort.farduedate"}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<input type="hidden" name="milestone" value="{{$.MilestoneID}}">
|
<input type="hidden" name="milestone" value="{{$.MilestoneID}}">
|
||||||
<input type="hidden" name="project" value="{{$.ProjectID}}">
|
<input type="hidden" name="project" value="{{$.ProjectID}}">
|
||||||
<input type="hidden" name="assignee" value="{{$.AssigneeID}}">
|
<input type="hidden" name="assignee" value="{{$.AssigneeID}}">
|
||||||
<input type="hidden" name="poster" value="{{$.PosterID}}">
|
<input type="hidden" name="poster" value="{{$.PosterUsername}}">
|
||||||
{{end}}
|
{{end}}
|
||||||
{{template "shared/search/input" dict "Value" .Keyword}}
|
{{template "shared/search/input" dict "Value" .Keyword}}
|
||||||
{{if .PageIsIssueList}}
|
{{if .PageIsIssueList}}
|
||||||
|
@ -4,45 +4,48 @@
|
|||||||
<div class="ui container">
|
<div class="ui container">
|
||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
<div class="flex-container">
|
<div class="flex-container">
|
||||||
|
{{$queryLink := QueryBuild "?" "type" $.ViewType "sort" $.SortType "state" $.State "q" $.Keyword "fuzzy" $.IsFuzzy}}
|
||||||
<div class="flex-container-nav">
|
<div class="flex-container-nav">
|
||||||
<div class="ui secondary vertical filter menu tw-bg-transparent">
|
<div class="ui secondary vertical filter menu tw-bg-transparent">
|
||||||
<a class="{{if eq .ViewType "your_repositories"}}active{{end}} item" href="?type=your_repositories&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">
|
<a class="{{if eq .ViewType "your_repositories"}}active{{end}} item" href="{{QueryBuild $queryLink "type" "your_repositories"}}">
|
||||||
{{ctx.Locale.Tr "home.issues.in_your_repos"}}
|
{{ctx.Locale.Tr "home.issues.in_your_repos"}}
|
||||||
<strong>{{CountFmt .IssueStats.YourRepositoriesCount}}</strong>
|
<strong>{{CountFmt .IssueStats.YourRepositoriesCount}}</strong>
|
||||||
</a>
|
</a>
|
||||||
<a class="{{if eq .ViewType "assigned"}}active{{end}} item" href="?type=assigned&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">
|
<a class="{{if eq .ViewType "assigned"}}active{{end}} item" href="{{QueryBuild $queryLink "type" "assigned"}}">
|
||||||
{{ctx.Locale.Tr "repo.issues.filter_type.assigned_to_you"}}
|
{{ctx.Locale.Tr "repo.issues.filter_type.assigned_to_you"}}
|
||||||
<strong>{{CountFmt .IssueStats.AssignCount}}</strong>
|
<strong>{{CountFmt .IssueStats.AssignCount}}</strong>
|
||||||
</a>
|
</a>
|
||||||
<a class="{{if eq .ViewType "created_by"}}active{{end}} item" href="?type=created_by&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">
|
<a class="{{if eq .ViewType "created_by"}}active{{end}} item" href="{{QueryBuild $queryLink "type" "created_by"}}">
|
||||||
{{ctx.Locale.Tr "repo.issues.filter_type.created_by_you"}}
|
{{ctx.Locale.Tr "repo.issues.filter_type.created_by_you"}}
|
||||||
<strong>{{CountFmt .IssueStats.CreateCount}}</strong>
|
<strong>{{CountFmt .IssueStats.CreateCount}}</strong>
|
||||||
</a>
|
</a>
|
||||||
{{if .PageIsPulls}}
|
{{if .PageIsPulls}}
|
||||||
<a class="{{if eq .ViewType "review_requested"}}active{{end}} item" href="?type=review_requested&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">
|
<a class="{{if eq .ViewType "review_requested"}}active{{end}} item" href="{{QueryBuild $queryLink "type" "review_requested"}}">
|
||||||
{{ctx.Locale.Tr "repo.issues.filter_type.review_requested"}}
|
{{ctx.Locale.Tr "repo.issues.filter_type.review_requested"}}
|
||||||
<strong>{{CountFmt .IssueStats.ReviewRequestedCount}}</strong>
|
<strong>{{CountFmt .IssueStats.ReviewRequestedCount}}</strong>
|
||||||
</a>
|
</a>
|
||||||
<a class="{{if eq .ViewType "reviewed_by"}}active{{end}} item" href="?type=reviewed_by&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">
|
<a class="{{if eq .ViewType "reviewed_by"}}active{{end}} item" href="{{QueryBuild $queryLink "type" "reviewed_by"}}">
|
||||||
{{ctx.Locale.Tr "repo.issues.filter_type.reviewed_by_you"}}
|
{{ctx.Locale.Tr "repo.issues.filter_type.reviewed_by_you"}}
|
||||||
<strong>{{CountFmt .IssueStats.ReviewedCount}}</strong>
|
<strong>{{CountFmt .IssueStats.ReviewedCount}}</strong>
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
<a class="{{if eq .ViewType "mentioned"}}active{{end}} item" href="?type=mentioned&sort={{$.SortType}}&state={{.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">
|
<a class="{{if eq .ViewType "mentioned"}}active{{end}} item" href="{{QueryBuild $queryLink "type" "mentioned"}}">
|
||||||
{{ctx.Locale.Tr "repo.issues.filter_type.mentioning_you"}}
|
{{ctx.Locale.Tr "repo.issues.filter_type.mentioning_you"}}
|
||||||
<strong>{{CountFmt .IssueStats.MentionCount}}</strong>
|
<strong>{{CountFmt .IssueStats.MentionCount}}</strong>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{$queryLinkWithFilter := QueryBuild $queryLink "poster" $.SearchFilterPosterUsername "assignee" $.SearchFilterAssigneeID}}
|
||||||
<div class="flex-container-main content">
|
<div class="flex-container-main content">
|
||||||
<div class="list-header">
|
<div class="list-header">
|
||||||
<div class="small-menu-items ui compact tiny menu list-header-toggle">
|
<div class="small-menu-items ui compact tiny menu list-header-toggle flex-items-block">
|
||||||
<a class="item{{if not .IsShowClosed}} active{{end}}" href="?type={{$.ViewType}}&sort={{$.SortType}}&state=open&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">
|
<a class="item{{if not .IsShowClosed}} active{{end}}" href="{{QueryBuild $queryLink "state" "open"}}">
|
||||||
{{svg "octicon-issue-opened" 16 "tw-mr-2"}}
|
{{svg "octicon-issue-opened"}}
|
||||||
{{ctx.Locale.PrettyNumber .IssueStats.OpenCount}} {{ctx.Locale.Tr "repo.issues.open_title"}}
|
{{ctx.Locale.PrettyNumber .IssueStats.OpenCount}} {{ctx.Locale.Tr "repo.issues.open_title"}}
|
||||||
</a>
|
</a>
|
||||||
<a class="item{{if .IsShowClosed}} active{{end}}" href="?type={{$.ViewType}}&sort={{$.SortType}}&state=closed&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">
|
<a class="item{{if .IsShowClosed}} active{{end}}" href="{{QueryBuild $queryLink "state" "closed"}}">
|
||||||
{{svg "octicon-issue-closed" 16 "tw-mr-2"}}
|
{{svg "octicon-issue-closed"}}
|
||||||
{{ctx.Locale.PrettyNumber .IssueStats.ClosedCount}} {{ctx.Locale.Tr "repo.issues.closed_title"}}
|
{{ctx.Locale.PrettyNumber .IssueStats.ClosedCount}} {{ctx.Locale.Tr "repo.issues.closed_title"}}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@ -61,14 +64,14 @@
|
|||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
</span>
|
</span>
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="?type={{$.ViewType}}&sort=recentupdate&state={{$.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">{{ctx.Locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
<a class="{{if eq .SortType "recentupdate"}}active {{end}}item" href="{{QueryBuild $queryLinkWithFilter "sort" "recentupdate"}}">{{ctx.Locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
||||||
<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="?type={{$.ViewType}}&sort=leastupdate&state={{$.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
<a class="{{if eq .SortType "leastupdate"}}active {{end}}item" href="{{QueryBuild $queryLinkWithFilter "sort" "leastupdate"}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
||||||
<a class="{{if or (eq .SortType "latest") (not .SortType)}}active {{end}}item" href="?type={{$.ViewType}}&sort=latest&state={{$.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">{{ctx.Locale.Tr "repo.issues.filter_sort.latest"}}</a>
|
<a class="{{if eq .SortType "latest"}}active {{end}}item" href="{{QueryBuild $queryLinkWithFilter "sort" "latest"}}">{{ctx.Locale.Tr "repo.issues.filter_sort.latest"}}</a>
|
||||||
<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="?type={{$.ViewType}}&sort=oldest&state={{$.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">{{ctx.Locale.Tr "repo.issues.filter_sort.oldest"}}</a>
|
<a class="{{if eq .SortType "oldest"}}active {{end}}item" href="{{QueryBuild $queryLinkWithFilter "sort" "oldest"}}">{{ctx.Locale.Tr "repo.issues.filter_sort.oldest"}}</a>
|
||||||
<a class="{{if eq .SortType "mostcomment"}}active {{end}}item" href="?type={{$.ViewType}}&sort=mostcomment&state={{$.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">{{ctx.Locale.Tr "repo.issues.filter_sort.mostcomment"}}</a>
|
<a class="{{if eq .SortType "mostcomment"}}active {{end}}item" href="{{QueryBuild $queryLinkWithFilter "sort" "mostcomment"}}">{{ctx.Locale.Tr "repo.issues.filter_sort.mostcomment"}}</a>
|
||||||
<a class="{{if eq .SortType "leastcomment"}}active {{end}}item" href="?type={{$.ViewType}}&sort=leastcomment&state={{$.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastcomment"}}</a>
|
<a class="{{if eq .SortType "leastcomment"}}active {{end}}item" href="{{QueryBuild $queryLinkWithFilter "sort" "leastcomment"}}">{{ctx.Locale.Tr "repo.issues.filter_sort.leastcomment"}}</a>
|
||||||
<a class="{{if eq .SortType "nearduedate"}}active {{end}}item" href="?type={{$.ViewType}}&sort=nearduedate&state={{$.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">{{ctx.Locale.Tr "repo.issues.filter_sort.nearduedate"}}</a>
|
<a class="{{if eq .SortType "nearduedate"}}active {{end}}item" href="{{QueryBuild $queryLinkWithFilter "sort" "nearduedate"}}">{{ctx.Locale.Tr "repo.issues.filter_sort.nearduedate"}}</a>
|
||||||
<a class="{{if eq .SortType "farduedate"}}active {{end}}item" href="?type={{$.ViewType}}&sort=farduedate&state={{$.State}}&q={{$.Keyword}}&fuzzy={{.IsFuzzy}}">{{ctx.Locale.Tr "repo.issues.filter_sort.farduedate"}}</a>
|
<a class="{{if eq .SortType "farduedate"}}active {{end}}item" href="{{QueryBuild $queryLinkWithFilter "sort" "farduedate"}}">{{ctx.Locale.Tr "repo.issues.filter_sort.farduedate"}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
import $ from 'jquery';
|
|
||||||
import {updateIssuesMeta} from './repo-common.ts';
|
import {updateIssuesMeta} from './repo-common.ts';
|
||||||
import {toggleElem, hideElem, isElemHidden} from '../utils/dom.ts';
|
import {toggleElem, hideElem, isElemHidden, queryElems} from '../utils/dom.ts';
|
||||||
import {htmlEscape} from 'escape-goat';
|
import {htmlEscape} from 'escape-goat';
|
||||||
import {confirmModal} from './comp/ConfirmModal.ts';
|
import {confirmModal} from './comp/ConfirmModal.ts';
|
||||||
import {showErrorToast} from '../modules/toast.ts';
|
import {showErrorToast} from '../modules/toast.ts';
|
||||||
import {createSortable} from '../modules/sortable.ts';
|
import {createSortable} from '../modules/sortable.ts';
|
||||||
import {DELETE, POST} from '../modules/fetch.ts';
|
import {DELETE, POST} from '../modules/fetch.ts';
|
||||||
import {parseDom} from '../utils.ts';
|
import {parseDom} from '../utils.ts';
|
||||||
|
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
||||||
|
|
||||||
function initRepoIssueListCheckboxes() {
|
function initRepoIssueListCheckboxes() {
|
||||||
const issueSelectAll = document.querySelector('.issue-checkbox-all');
|
const issueSelectAll = document.querySelector<HTMLInputElement>('.issue-checkbox-all');
|
||||||
if (!issueSelectAll) return; // logged out state
|
if (!issueSelectAll) return; // logged out state
|
||||||
const issueCheckboxes = document.querySelectorAll('.issue-checkbox');
|
const issueCheckboxes = document.querySelectorAll<HTMLInputElement>('.issue-checkbox');
|
||||||
|
|
||||||
const syncIssueSelectionState = () => {
|
const syncIssueSelectionState = () => {
|
||||||
const checkedCheckboxes = Array.from(issueCheckboxes).filter((el) => el.checked);
|
const checkedCheckboxes = Array.from(issueCheckboxes).filter((el) => el.checked);
|
||||||
@ -29,8 +29,8 @@ function initRepoIssueListCheckboxes() {
|
|||||||
issueSelectAll.indeterminate = false;
|
issueSelectAll.indeterminate = false;
|
||||||
}
|
}
|
||||||
// if any issue is selected, show the action panel, otherwise show the filter panel
|
// if any issue is selected, show the action panel, otherwise show the filter panel
|
||||||
toggleElem($('#issue-filters'), !anyChecked);
|
toggleElem('#issue-filters', !anyChecked);
|
||||||
toggleElem($('#issue-actions'), anyChecked);
|
toggleElem('#issue-actions', anyChecked);
|
||||||
// there are two panels but only one select-all checkbox, so move the checkbox to the visible panel
|
// there are two panels but only one select-all checkbox, so move the checkbox to the visible panel
|
||||||
const panels = document.querySelectorAll('#issue-filters, #issue-actions');
|
const panels = document.querySelectorAll('#issue-filters, #issue-actions');
|
||||||
const visiblePanel = Array.from(panels).find((el) => !isElemHidden(el));
|
const visiblePanel = Array.from(panels).find((el) => !isElemHidden(el));
|
||||||
@ -49,56 +49,55 @@ function initRepoIssueListCheckboxes() {
|
|||||||
syncIssueSelectionState();
|
syncIssueSelectionState();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.issue-action').on('click', async function (e) {
|
queryElems(document, '.issue-action', (el) => el.addEventListener('click',
|
||||||
e.preventDefault();
|
async (e: MouseEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
const url = this.getAttribute('data-url');
|
const url = el.getAttribute('data-url');
|
||||||
let action = this.getAttribute('data-action');
|
let action = el.getAttribute('data-action');
|
||||||
let elementId = this.getAttribute('data-element-id');
|
let elementId = el.getAttribute('data-element-id');
|
||||||
let issueIDs = [];
|
const issueIDList: string[] = [];
|
||||||
for (const el of document.querySelectorAll('.issue-checkbox:checked')) {
|
for (const el of document.querySelectorAll('.issue-checkbox:checked')) {
|
||||||
issueIDs.push(el.getAttribute('data-issue-id'));
|
issueIDList.push(el.getAttribute('data-issue-id'));
|
||||||
}
|
|
||||||
issueIDs = issueIDs.join(',');
|
|
||||||
if (!issueIDs) return;
|
|
||||||
|
|
||||||
// for assignee
|
|
||||||
if (elementId === '0' && url.endsWith('/assignee')) {
|
|
||||||
elementId = '';
|
|
||||||
action = 'clear';
|
|
||||||
}
|
|
||||||
|
|
||||||
// for toggle
|
|
||||||
if (action === 'toggle' && e.altKey) {
|
|
||||||
action = 'toggle-alt';
|
|
||||||
}
|
|
||||||
|
|
||||||
// for delete
|
|
||||||
if (action === 'delete') {
|
|
||||||
const confirmText = e.target.getAttribute('data-action-delete-confirm');
|
|
||||||
if (!await confirmModal({content: confirmText, confirmButtonColor: 'red'})) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
const issueIDs = issueIDList.join(',');
|
||||||
|
if (!issueIDs) return;
|
||||||
|
|
||||||
try {
|
// for assignee
|
||||||
await updateIssuesMeta(url, action, issueIDs, elementId);
|
if (elementId === '0' && url.endsWith('/assignee')) {
|
||||||
window.location.reload();
|
elementId = '';
|
||||||
} catch (err) {
|
action = 'clear';
|
||||||
showErrorToast(err.responseJSON?.error ?? err.message);
|
}
|
||||||
}
|
|
||||||
});
|
// for toggle
|
||||||
|
if (action === 'toggle' && e.altKey) {
|
||||||
|
action = 'toggle-alt';
|
||||||
|
}
|
||||||
|
|
||||||
|
// for delete
|
||||||
|
if (action === 'delete') {
|
||||||
|
const confirmText = el.getAttribute('data-action-delete-confirm');
|
||||||
|
if (!await confirmModal({content: confirmText, confirmButtonColor: 'red'})) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await updateIssuesMeta(url, action, issueIDs, elementId);
|
||||||
|
window.location.reload();
|
||||||
|
} catch (err) {
|
||||||
|
showErrorToast(err.responseJSON?.error ?? err.message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
function initRepoIssueListAuthorDropdown() {
|
function initDropdownUserRemoteSearch(el: Element) {
|
||||||
const $searchDropdown = $('.user-remote-search');
|
let searchUrl = el.getAttribute('data-search-url');
|
||||||
if (!$searchDropdown.length) return;
|
const actionJumpUrl = el.getAttribute('data-action-jump-url');
|
||||||
|
const selectedUserId = el.getAttribute('data-selected-user-id');
|
||||||
let searchUrl = $searchDropdown[0].getAttribute('data-search-url');
|
|
||||||
const actionJumpUrl = $searchDropdown[0].getAttribute('data-action-jump-url');
|
|
||||||
const selectedUserId = $searchDropdown[0].getAttribute('data-selected-user-id');
|
|
||||||
if (!searchUrl.includes('?')) searchUrl += '?';
|
if (!searchUrl.includes('?')) searchUrl += '?';
|
||||||
|
const $searchDropdown = fomanticQuery(el);
|
||||||
$searchDropdown.dropdown('setting', {
|
$searchDropdown.dropdown('setting', {
|
||||||
fullTextSearch: true,
|
fullTextSearch: true,
|
||||||
selectOnKeydown: false,
|
selectOnKeydown: false,
|
||||||
@ -111,14 +110,14 @@ function initRepoIssueListAuthorDropdown() {
|
|||||||
for (const item of resp.results) {
|
for (const item of resp.results) {
|
||||||
let html = `<img class="ui avatar tw-align-middle" src="${htmlEscape(item.avatar_link)}" aria-hidden="true" alt="" width="20" height="20"><span class="gt-ellipsis">${htmlEscape(item.username)}</span>`;
|
let html = `<img class="ui avatar tw-align-middle" src="${htmlEscape(item.avatar_link)}" aria-hidden="true" alt="" width="20" height="20"><span class="gt-ellipsis">${htmlEscape(item.username)}</span>`;
|
||||||
if (item.full_name) html += `<span class="search-fullname tw-ml-2">${htmlEscape(item.full_name)}</span>`;
|
if (item.full_name) html += `<span class="search-fullname tw-ml-2">${htmlEscape(item.full_name)}</span>`;
|
||||||
processedResults.push({value: item.user_id, name: html});
|
processedResults.push({value: item.username, name: html});
|
||||||
}
|
}
|
||||||
resp.results = processedResults;
|
resp.results = processedResults;
|
||||||
return resp;
|
return resp;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
action: (_text, value) => {
|
action: (_text, value) => {
|
||||||
window.location.href = actionJumpUrl.replace('{user_id}', encodeURIComponent(value));
|
window.location.href = actionJumpUrl.replace('{username}', encodeURIComponent(value));
|
||||||
},
|
},
|
||||||
onShow: () => {
|
onShow: () => {
|
||||||
$searchDropdown.dropdown('filter', ' '); // trigger a search on first show
|
$searchDropdown.dropdown('filter', ' '); // trigger a search on first show
|
||||||
@ -160,7 +159,7 @@ function initRepoIssueListAuthorDropdown() {
|
|||||||
function initPinRemoveButton() {
|
function initPinRemoveButton() {
|
||||||
for (const button of document.querySelectorAll('.issue-card-unpin')) {
|
for (const button of document.querySelectorAll('.issue-card-unpin')) {
|
||||||
button.addEventListener('click', async (event) => {
|
button.addEventListener('click', async (event) => {
|
||||||
const el = event.currentTarget;
|
const el = event.currentTarget as HTMLElement;
|
||||||
const id = Number(el.getAttribute('data-issue-id'));
|
const id = Number(el.getAttribute('data-issue-id'));
|
||||||
|
|
||||||
// Send the unpin request
|
// Send the unpin request
|
||||||
@ -205,10 +204,8 @@ async function initIssuePinSort() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function initArchivedLabelFilter() {
|
function initArchivedLabelFilter() {
|
||||||
const archivedLabelEl = document.querySelector('#archived-filter-checkbox');
|
const archivedLabelEl = document.querySelector<HTMLInputElement>('#archived-filter-checkbox');
|
||||||
if (!archivedLabelEl) {
|
if (!archivedLabelEl) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const url = new URL(window.location.href);
|
const url = new URL(window.location.href);
|
||||||
const archivedLabels = document.querySelectorAll('[data-is-archived]');
|
const archivedLabels = document.querySelectorAll('[data-is-archived]');
|
||||||
@ -219,7 +216,7 @@ function initArchivedLabelFilter() {
|
|||||||
}
|
}
|
||||||
const selectedLabels = (url.searchParams.get('labels') || '')
|
const selectedLabels = (url.searchParams.get('labels') || '')
|
||||||
.split(',')
|
.split(',')
|
||||||
.map((id) => id < 0 ? `${~id + 1}` : id); // selectedLabels contains -ve ids, which are excluded so convert any -ve value id to +ve
|
.map((id) => parseInt(id) < 0 ? `${~id + 1}` : id); // selectedLabels contains -ve ids, which are excluded so convert any -ve value id to +ve
|
||||||
|
|
||||||
const archivedElToggle = () => {
|
const archivedElToggle = () => {
|
||||||
for (const label of archivedLabels) {
|
for (const label of archivedLabels) {
|
||||||
@ -241,9 +238,9 @@ function initArchivedLabelFilter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function initRepoIssueList() {
|
export function initRepoIssueList() {
|
||||||
if (!document.querySelectorAll('.page-content.repository.issue-list, .page-content.repository.milestone-issue-list').length) return;
|
if (!document.querySelector('.page-content.repository.issue-list, .page-content.repository.milestone-issue-list')) return;
|
||||||
initRepoIssueListCheckboxes();
|
initRepoIssueListCheckboxes();
|
||||||
initRepoIssueListAuthorDropdown();
|
queryElems(document, '.ui.dropdown.user-remote-search', (el) => initDropdownUserRemoteSearch(el));
|
||||||
initIssuePinSort();
|
initIssuePinSort();
|
||||||
initArchivedLabelFilter();
|
initArchivedLabelFilter();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user