Skip to content

add filter by author/assignee in /issues (#25979) #26643

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions models/repo/user_repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,22 @@ func GetIssuePostersWithSearch(ctx context.Context, repo *Repository, isPull boo
Limit(30).
Find(&users)
}

// GetIssuePostersWithSearchWithoutRepo clone of GetIssuePostersWithSearch without repo
func GetIssuePostersWithSearchWithoutRepo(ctx context.Context, search string, isShowFullName bool) ([]*user_model.User, error) {
users := make([]*user_model.User, 0, 30)
var prefixCond builder.Cond = builder.Like{"name", search + "%"}
if isShowFullName {
prefixCond = prefixCond.Or(builder.Like{"full_name", "%" + search + "%"})
}

cond := builder.In("`user`.id",
builder.Select("poster_id").From("issue").GroupBy("poster_id")).And(prefixCond)

return users, db.GetEngine(ctx).
Where(cond).
Cols("id", "name", "full_name", "avatar", "avatar_email", "use_custom_avatar").
OrderBy("name").
Limit(30).
Find(&users)
}
34 changes: 34 additions & 0 deletions routers/web/repo/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -3581,6 +3581,11 @@ func IssuePosters(ctx *context.Context) {
issuePosters(ctx, false)
}

// IssuePostersWithoutRepo clone of IssuePosters but without repo
func IssuePostersWithoutRepo(ctx *context.Context) {
issuePostersWithoutRepo(ctx)
}

func PullPosters(ctx *context.Context) {
issuePosters(ctx, true)
}
Expand Down Expand Up @@ -3614,3 +3619,32 @@ func issuePosters(ctx *context.Context, isPullList bool) {
}
ctx.JSON(http.StatusOK, resp)
}

func issuePostersWithoutRepo(ctx *context.Context) {
search := strings.TrimSpace(ctx.FormString("q"))
posters, err := repo_model.GetIssuePostersWithSearchWithoutRepo(ctx, search, setting.UI.DefaultShowFullName)
if err != nil {
ctx.JSON(http.StatusInternalServerError, err)
return
}

if search == "" && ctx.Doer != nil {
// the returned posters slice only contains limited number of users,
// to make the current user (doer) can quickly filter their own issues, always add doer to the posters slice
if !util.SliceContainsFunc(posters, func(user *user_model.User) bool { return user.ID == ctx.Doer.ID }) {
posters = append(posters, ctx.Doer)
}
}

posters = MakeSelfOnTop(ctx, posters)

resp := &userSearchResponse{}
resp.Results = make([]*userSearchInfo, len(posters))
for i, user := range posters {
resp.Results[i] = &userSearchInfo{UserID: user.ID, UserName: user.Name, AvatarLink: user.AvatarLink(ctx)}
if setting.UI.DefaultShowFullName {
resp.Results[i].FullName = user.FullName
}
}
ctx.JSON(http.StatusOK, resp)
}
13 changes: 13 additions & 0 deletions routers/web/user/home.go
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,18 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
opts.ReviewedID = ctx.Doer.ID
}

// Get filter by author id
filterByAuthorID, errorParsingAuthorID := strconv.ParseInt(ctx.FormString("author"), 10, 64)
if errorParsingAuthorID == nil {
opts.PosterID = filterByAuthorID
}

// Get filter by assignee id
filterByAssigneeID, errorParsingAssigneeID := strconv.ParseInt(ctx.FormString("assignee"), 10, 64)
if errorParsingAssigneeID == nil {
opts.AssigneeID = filterByAssigneeID
}

// keyword holds the search term entered into the search field.
keyword := strings.Trim(ctx.FormString("q"), " ")
ctx.Data["Keyword"] = keyword
Expand Down Expand Up @@ -746,6 +758,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
pager.AddParam(ctx, "labels", "SelectLabels")
pager.AddParam(ctx, "milestone", "MilestoneID")
pager.AddParam(ctx, "assignee", "AssigneeID")
pager.AddParam(ctx, "author", "AuthorID")
ctx.Data["Page"] = pager

ctx.HTML(http.StatusOK, tplIssues)
Expand Down
2 changes: 2 additions & 0 deletions routers/web/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,8 @@ func registerRoutes(m *web.Route) {
}, ignExploreSignIn)
m.Group("/issues", func() {
m.Get("", user.Issues)
m.Get("/posters", repo.IssuePostersWithoutRepo)
m.Get("/filter", user.Issues)
m.Get("/search", repo.SearchIssues)
}, reqSignIn)

Expand Down
47 changes: 46 additions & 1 deletion templates/user/dashboard/issues.tmpl
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{{template "base/head" .}}
<div role="main" aria-label="{{.Title}}" class="page-content dashboard issues">
{{template "user/dashboard/navbar" .}}
<div class="ui container">

<div class="ui container filteredIssues" >
<div class="ui stackable grid">
<div class="four wide column">
<div class="ui secondary vertical filter menu gt-bg-transparent">
Expand Down Expand Up @@ -107,6 +108,50 @@
{{end}}
{{end}}
</div>

<div id="issue-filters" class="issue-list-toolbar">
<div></div>
<div class="issue-list-toolbar-right">
<div class="ui secondary filter menu labels">
<!-- Author -->
<div id="authorDropdown" class="ui dropdown jump item user-remote-search" data-tooltip-content="{{.locale.Tr "repo.author_search_tooltip"}}"
data-search-url="{{$.Link}}/posters"
data-selected-user-id="{{$.PosterID}}"
data-action-jump-url="{{$.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&assignee={{$.AssigneeID}}&author={user_id}"
>
<span class="text">
{{.locale.Tr "repo.issues.filter_poster"}}
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</span>
<div class="menu">
<div class="ui icon search input">
<i class="icon gt-df gt-ac gt-jc">{{svg "octicon-search" 16}}</i>
<input type="text" placeholder="{{.locale.Tr "repo.issues.filter_poster"}}">
</div>
<a class="item" data-value="0">{{.locale.Tr "repo.issues.filter_poster_no_select"}}</a>
</div>
</div>
<!-- Assignee -->
<div id="assigneeDropdown" class="ui dropdown jump item user-remote-search" data-tooltip-content="{{.locale.Tr "repo.author_search_tooltip"}}"
data-search-url="{{$.Link}}/posters"
data-selected-user-id="{{$.PosterID}}"
data-action-jump-url="{{$.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&assignee={user_id}&author={{$.AuthorID}}"
>
<span class="text">
{{.locale.Tr "repo.issues.filter_assignee"}}
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</span>
<div class="menu">
<div class="ui icon search input">
<i class="icon gt-df gt-ac gt-jc">{{svg "octicon-search" 16}}</i>
<input type="text" placeholder="{{.locale.Tr "repo.issues.filter_assignee"}}">
</div>
<a class="item" data-value="0">{{.locale.Tr "repo.issues.filter_assginee_no_select"}}</a>
</div>
</div>
</div>
</div>
</div>
{{template "shared/issuelist" dict "." . "listType" "dashboard"}}
</div>
</div>
Expand Down
9 changes: 5 additions & 4 deletions web_src/js/features/repo-issue-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ function initRepoIssueListCheckboxes() {
});
}

function initRepoIssueListAuthorDropdown() {
const $searchDropdown = $('.user-remote-search');
function initRepoIssueListUserDropdown(which) {
const $searchDropdown = $(`${which}.user-remote-search`);
if (!$searchDropdown.length) return;

let searchUrl = $searchDropdown.attr('data-search-url');
Expand Down Expand Up @@ -198,8 +198,9 @@ async function initIssuePinSort() {
}

export function initRepoIssueList() {
if (!document.querySelectorAll('.page-content.repository.issue-list, .page-content.repository.milestone-issue-list').length) return;
if (!document.querySelectorAll('.page-content.repository.issue-list, .page-content.repository.milestone-issue-list, .page-content.dashboard.issues').length) return;
initRepoIssueListCheckboxes();
initRepoIssueListAuthorDropdown();
initRepoIssueListUserDropdown('#authorDropdown');
initRepoIssueListUserDropdown('#assigneeDropdown');
initIssuePinSort();
}