mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-22 12:54:53 -05:00
Fix assigned issues dashboard (#920)
* Fix assigned/created issues in dashboard. (#3560) * Fix assigned/created issues in dashboard. * Use GetUserIssueStats for getting all Dashboard stats. * Use gofmt to format the file properly. * Replace &Issue{} with new(Issue). * Check if user has access to given repository. * Remove unnecessary filtering of issues. * Return 404 error if invalid repository is given. * Use correct number of issues in paginater. * fix issues on dashboard
This commit is contained in:
parent
3a91ac51a9
commit
7a9a5c8a69
4 changed files with 181 additions and 123 deletions
|
@ -1184,7 +1184,7 @@ func UpdateIssueMentions(e Engine, issueID int64, mentions []string) error {
|
||||||
// IssueStats represents issue statistic information.
|
// IssueStats represents issue statistic information.
|
||||||
type IssueStats struct {
|
type IssueStats struct {
|
||||||
OpenCount, ClosedCount int64
|
OpenCount, ClosedCount int64
|
||||||
AllCount int64
|
YourRepositoriesCount int64
|
||||||
AssignCount int64
|
AssignCount int64
|
||||||
CreateCount int64
|
CreateCount int64
|
||||||
MentionCount int64
|
MentionCount int64
|
||||||
|
@ -1210,6 +1210,7 @@ func parseCountResult(results []map[string][]byte) int64 {
|
||||||
|
|
||||||
// IssueStatsOptions contains parameters accepted by GetIssueStats.
|
// IssueStatsOptions contains parameters accepted by GetIssueStats.
|
||||||
type IssueStatsOptions struct {
|
type IssueStatsOptions struct {
|
||||||
|
FilterMode int
|
||||||
RepoID int64
|
RepoID int64
|
||||||
Labels string
|
Labels string
|
||||||
MilestoneID int64
|
MilestoneID int64
|
||||||
|
@ -1265,19 +1266,41 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
switch opts.FilterMode {
|
||||||
|
case FilterModeAll, FilterModeAssign:
|
||||||
stats.OpenCount, err = countSession(opts).
|
stats.OpenCount, err = countSession(opts).
|
||||||
And("is_closed = ?", false).
|
And("is_closed = ?", false).
|
||||||
Count(&Issue{})
|
Count(new(Issue))
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
stats.ClosedCount, err = countSession(opts).
|
stats.ClosedCount, err = countSession(opts).
|
||||||
And("is_closed = ?", true).
|
And("is_closed = ?", true).
|
||||||
Count(&Issue{})
|
Count(new(Issue))
|
||||||
if err != nil {
|
case FilterModeCreate:
|
||||||
return nil, err
|
stats.OpenCount, err = countSession(opts).
|
||||||
|
And("poster_id = ?", opts.PosterID).
|
||||||
|
And("is_closed = ?", false).
|
||||||
|
Count(new(Issue))
|
||||||
|
|
||||||
|
stats.ClosedCount, err = countSession(opts).
|
||||||
|
And("poster_id = ?", opts.PosterID).
|
||||||
|
And("is_closed = ?", true).
|
||||||
|
Count(new(Issue))
|
||||||
|
case FilterModeMention:
|
||||||
|
stats.OpenCount, err = countSession(opts).
|
||||||
|
Join("INNER", "issue_user", "issue.id = issue_user.issue_id").
|
||||||
|
And("issue_user.uid = ?", opts.PosterID).
|
||||||
|
And("issue_user.is_mentioned = ?", true).
|
||||||
|
And("issue.is_closed = ?", false).
|
||||||
|
Count(new(Issue))
|
||||||
|
|
||||||
|
stats.ClosedCount, err = countSession(opts).
|
||||||
|
Join("INNER", "issue_user", "issue.id = issue_user.issue_id").
|
||||||
|
And("issue_user.uid = ?", opts.PosterID).
|
||||||
|
And("issue_user.is_mentioned = ?", true).
|
||||||
|
And("issue.is_closed = ?", true).
|
||||||
|
Count(new(Issue))
|
||||||
}
|
}
|
||||||
return stats, nil
|
return stats, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserIssueStats returns issue statistic information for dashboard by given conditions.
|
// GetUserIssueStats returns issue statistic information for dashboard by given conditions.
|
||||||
|
@ -1298,29 +1321,39 @@ func GetUserIssueStats(repoID, uid int64, repoIDs []int64, filterMode int, isPul
|
||||||
return sess
|
return sess
|
||||||
}
|
}
|
||||||
|
|
||||||
stats.AssignCount, _ = countSession(false, isPull, repoID, repoIDs).
|
stats.AssignCount, _ = countSession(false, isPull, repoID, nil).
|
||||||
And("assignee_id = ?", uid).
|
And("assignee_id = ?", uid).
|
||||||
Count(&Issue{})
|
Count(new(Issue))
|
||||||
|
|
||||||
stats.CreateCount, _ = countSession(false, isPull, repoID, repoIDs).
|
stats.CreateCount, _ = countSession(false, isPull, repoID, nil).
|
||||||
And("poster_id = ?", uid).
|
And("poster_id = ?", uid).
|
||||||
Count(&Issue{})
|
Count(new(Issue))
|
||||||
|
|
||||||
openCountSession := countSession(false, isPull, repoID, repoIDs)
|
stats.YourRepositoriesCount, _ = countSession(false, isPull, repoID, repoIDs).
|
||||||
closedCountSession := countSession(true, isPull, repoID, repoIDs)
|
Count(new(Issue))
|
||||||
|
|
||||||
switch filterMode {
|
switch filterMode {
|
||||||
|
case FilterModeAll:
|
||||||
|
stats.OpenCount, _ = countSession(false, isPull, repoID, repoIDs).
|
||||||
|
Count(new(Issue))
|
||||||
|
stats.ClosedCount, _ = countSession(true, isPull, repoID, repoIDs).
|
||||||
|
Count(new(Issue))
|
||||||
case FilterModeAssign:
|
case FilterModeAssign:
|
||||||
openCountSession.And("assignee_id = ?", uid)
|
stats.OpenCount, _ = countSession(false, isPull, repoID, nil).
|
||||||
closedCountSession.And("assignee_id = ?", uid)
|
And("assignee_id = ?", uid).
|
||||||
|
Count(new(Issue))
|
||||||
|
stats.ClosedCount, _ = countSession(true, isPull, repoID, nil).
|
||||||
|
And("assignee_id = ?", uid).
|
||||||
|
Count(new(Issue))
|
||||||
case FilterModeCreate:
|
case FilterModeCreate:
|
||||||
openCountSession.And("poster_id = ?", uid)
|
stats.OpenCount, _ = countSession(false, isPull, repoID, nil).
|
||||||
closedCountSession.And("poster_id = ?", uid)
|
And("poster_id = ?", uid).
|
||||||
|
Count(new(Issue))
|
||||||
|
stats.ClosedCount, _ = countSession(true, isPull, repoID, nil).
|
||||||
|
And("poster_id = ?", uid).
|
||||||
|
Count(new(Issue))
|
||||||
}
|
}
|
||||||
|
|
||||||
stats.OpenCount, _ = openCountSession.Count(&Issue{})
|
|
||||||
stats.ClosedCount, _ = closedCountSession.Count(&Issue{})
|
|
||||||
|
|
||||||
return stats
|
return stats
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1347,8 +1380,8 @@ func GetRepoIssueStats(repoID, uid int64, filterMode int, isPull bool) (numOpen
|
||||||
closedCountSession.And("poster_id = ?", uid)
|
closedCountSession.And("poster_id = ?", uid)
|
||||||
}
|
}
|
||||||
|
|
||||||
openResult, _ := openCountSession.Count(&Issue{})
|
openResult, _ := openCountSession.Count(new(Issue))
|
||||||
closedResult, _ := closedCountSession.Count(&Issue{})
|
closedResult, _ := closedCountSession.Count(new(Issue))
|
||||||
|
|
||||||
return openResult, closedResult
|
return openResult, closedResult
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/url"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -108,37 +107,17 @@ func Issues(ctx *context.Context) {
|
||||||
|
|
||||||
viewType := ctx.Query("type")
|
viewType := ctx.Query("type")
|
||||||
sortType := ctx.Query("sort")
|
sortType := ctx.Query("sort")
|
||||||
types := []string{"assigned", "created_by", "mentioned"}
|
types := []string{"all", "assigned", "created_by", "mentioned"}
|
||||||
if !com.IsSliceContainsStr(types, viewType) {
|
if !com.IsSliceContainsStr(types, viewType) {
|
||||||
viewType = "all"
|
viewType = "all"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must sign in to see issues about you.
|
|
||||||
if viewType != "all" && !ctx.IsSigned {
|
|
||||||
ctx.SetCookie("redirect_to", "/"+url.QueryEscape(setting.AppSubURL+ctx.Req.RequestURI), 0, setting.AppSubURL)
|
|
||||||
ctx.Redirect(setting.AppSubURL + "/user/login")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
assigneeID = ctx.QueryInt64("assignee")
|
assigneeID = ctx.QueryInt64("assignee")
|
||||||
posterID int64
|
posterID int64
|
||||||
mentionedID int64
|
mentionedID int64
|
||||||
forceEmpty bool
|
forceEmpty bool
|
||||||
)
|
)
|
||||||
switch viewType {
|
|
||||||
case "assigned":
|
|
||||||
if assigneeID > 0 && ctx.User.ID != assigneeID {
|
|
||||||
// two different assignees, must be empty
|
|
||||||
forceEmpty = true
|
|
||||||
} else {
|
|
||||||
assigneeID = ctx.User.ID
|
|
||||||
}
|
|
||||||
case "created_by":
|
|
||||||
posterID = ctx.User.ID
|
|
||||||
case "mentioned":
|
|
||||||
mentionedID = ctx.User.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
repo := ctx.Repo.Repository
|
repo := ctx.Repo.Repository
|
||||||
selectLabels := ctx.Query("labels")
|
selectLabels := ctx.Query("labels")
|
||||||
|
|
|
@ -183,34 +183,39 @@ func Issues(ctx *context.Context) {
|
||||||
viewType string
|
viewType string
|
||||||
sortType = ctx.Query("sort")
|
sortType = ctx.Query("sort")
|
||||||
filterMode = models.FilterModeAll
|
filterMode = models.FilterModeAll
|
||||||
assigneeID int64
|
|
||||||
posterID int64
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if ctxUser.IsOrganization() {
|
if ctxUser.IsOrganization() {
|
||||||
viewType = "all"
|
viewType = "all"
|
||||||
} else {
|
} else {
|
||||||
viewType = ctx.Query("type")
|
viewType = ctx.Query("type")
|
||||||
types := []string{"assigned", "created_by"}
|
types := []string{"all", "assigned", "created_by"}
|
||||||
if !com.IsSliceContainsStr(types, viewType) {
|
if !com.IsSliceContainsStr(types, viewType) {
|
||||||
viewType = "all"
|
viewType = "all"
|
||||||
}
|
}
|
||||||
|
|
||||||
switch viewType {
|
switch viewType {
|
||||||
|
case "all":
|
||||||
|
filterMode = models.FilterModeAll
|
||||||
case "assigned":
|
case "assigned":
|
||||||
filterMode = models.FilterModeAssign
|
filterMode = models.FilterModeAssign
|
||||||
assigneeID = ctxUser.ID
|
|
||||||
case "created_by":
|
case "created_by":
|
||||||
filterMode = models.FilterModeCreate
|
filterMode = models.FilterModeCreate
|
||||||
posterID = ctxUser.ID
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
page := ctx.QueryInt("page")
|
||||||
|
if page <= 1 {
|
||||||
|
page = 1
|
||||||
|
}
|
||||||
|
|
||||||
repoID := ctx.QueryInt64("repo")
|
repoID := ctx.QueryInt64("repo")
|
||||||
isShowClosed := ctx.Query("state") == "closed"
|
isShowClosed := ctx.Query("state") == "closed"
|
||||||
|
|
||||||
// Get repositories.
|
// Get repositories.
|
||||||
var err error
|
var err error
|
||||||
var repos []*models.Repository
|
var repos []*models.Repository
|
||||||
|
userRepoIDs := make([]int64, 0, len(repos))
|
||||||
if ctxUser.IsOrganization() {
|
if ctxUser.IsOrganization() {
|
||||||
env, err := ctxUser.AccessibleReposEnv(ctx.User.ID)
|
env, err := ctxUser.AccessibleReposEnv(ctx.User.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -230,9 +235,6 @@ func Issues(ctx *context.Context) {
|
||||||
repos = ctxUser.Repos
|
repos = ctxUser.Repos
|
||||||
}
|
}
|
||||||
|
|
||||||
allCount := 0
|
|
||||||
repoIDs := make([]int64, 0, len(repos))
|
|
||||||
showRepos := make([]*models.Repository, 0, len(repos))
|
|
||||||
for _, repo := range repos {
|
for _, repo := range repos {
|
||||||
if (isPullList && repo.NumPulls == 0) ||
|
if (isPullList && repo.NumPulls == 0) ||
|
||||||
(!isPullList &&
|
(!isPullList &&
|
||||||
|
@ -240,85 +242,129 @@ func Issues(ctx *context.Context) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
repoIDs = append(repoIDs, repo.ID)
|
userRepoIDs = append(userRepoIDs, repo.ID)
|
||||||
|
|
||||||
if isPullList {
|
|
||||||
allCount += repo.NumOpenPulls
|
|
||||||
repo.NumOpenIssues = repo.NumOpenPulls
|
|
||||||
repo.NumClosedIssues = repo.NumClosedPulls
|
|
||||||
} else {
|
|
||||||
allCount += repo.NumOpenIssues
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if filterMode != models.FilterModeAll {
|
var issues []*models.Issue
|
||||||
// Calculate repository issue count with filter mode.
|
switch filterMode {
|
||||||
numOpen, numClosed := repo.IssueStats(ctxUser.ID, filterMode, isPullList)
|
case models.FilterModeAll:
|
||||||
repo.NumOpenIssues, repo.NumClosedIssues = int(numOpen), int(numClosed)
|
// Get all issues from repositories from this user.
|
||||||
|
issues, err = models.Issues(&models.IssuesOptions{
|
||||||
|
RepoIDs: userRepoIDs,
|
||||||
|
RepoID: repoID,
|
||||||
|
Page: page,
|
||||||
|
IsClosed: util.OptionalBoolOf(isShowClosed),
|
||||||
|
IsPull: util.OptionalBoolOf(isPullList),
|
||||||
|
SortType: sortType,
|
||||||
|
})
|
||||||
|
|
||||||
|
case models.FilterModeAssign:
|
||||||
|
// Get all issues assigned to this user.
|
||||||
|
issues, err = models.Issues(&models.IssuesOptions{
|
||||||
|
RepoID: repoID,
|
||||||
|
AssigneeID: ctxUser.ID,
|
||||||
|
Page: page,
|
||||||
|
IsClosed: util.OptionalBoolOf(isShowClosed),
|
||||||
|
IsPull: util.OptionalBoolOf(isPullList),
|
||||||
|
SortType: sortType,
|
||||||
|
})
|
||||||
|
|
||||||
|
case models.FilterModeCreate:
|
||||||
|
// Get all issues created by this user.
|
||||||
|
issues, err = models.Issues(&models.IssuesOptions{
|
||||||
|
RepoID: repoID,
|
||||||
|
PosterID: ctxUser.ID,
|
||||||
|
Page: page,
|
||||||
|
IsClosed: util.OptionalBoolOf(isShowClosed),
|
||||||
|
IsPull: util.OptionalBoolOf(isPullList),
|
||||||
|
SortType: sortType,
|
||||||
|
})
|
||||||
|
case models.FilterModeMention:
|
||||||
|
// Get all issues created by this user.
|
||||||
|
issues, err = models.Issues(&models.IssuesOptions{
|
||||||
|
RepoID: repoID,
|
||||||
|
MentionedID: ctxUser.ID,
|
||||||
|
Page: page,
|
||||||
|
IsClosed: util.OptionalBoolOf(isShowClosed),
|
||||||
|
IsPull: util.OptionalBoolOf(isPullList),
|
||||||
|
SortType: sortType,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if repo.ID == repoID ||
|
if err != nil {
|
||||||
(isShowClosed && repo.NumClosedIssues > 0) ||
|
ctx.Handle(500, "Issues", err)
|
||||||
(!isShowClosed && repo.NumOpenIssues > 0) {
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
showRepos := make([]*models.Repository, 0, len(issues))
|
||||||
|
showReposSet := make(map[int64]bool)
|
||||||
|
|
||||||
|
if repoID > 0 {
|
||||||
|
repo, err := models.GetRepositoryByID(repoID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(500, "GetRepositoryByID", fmt.Errorf("[#%d]%v", repoID, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = repo.GetOwner(); err != nil {
|
||||||
|
ctx.Handle(500, "GetOwner", fmt.Errorf("[#%d]%v", repoID, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if user has access to given repository.
|
||||||
|
if !repo.IsOwnedBy(ctxUser.ID) && !repo.HasAccess(ctxUser) {
|
||||||
|
ctx.Handle(404, "Issues", fmt.Errorf("#%d", repoID))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
showReposSet[repoID] = true
|
||||||
showRepos = append(showRepos, repo)
|
showRepos = append(showRepos, repo)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
ctx.Data["Repos"] = showRepos
|
for _, issue := range issues {
|
||||||
if len(repoIDs) == 0 {
|
// Get Repository data.
|
||||||
repoIDs = []int64{-1}
|
issue.Repo, err = models.GetRepositoryByID(issue.RepoID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(500, "GetRepositoryByID", fmt.Errorf("[#%d]%v", issue.RepoID, err))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
issueStats := models.GetUserIssueStats(repoID, ctxUser.ID, repoIDs, filterMode, isPullList)
|
// Get Owner data.
|
||||||
issueStats.AllCount = int64(allCount)
|
if err = issue.Repo.GetOwner(); err != nil {
|
||||||
|
ctx.Handle(500, "GetOwner", fmt.Errorf("[#%d]%v", issue.RepoID, err))
|
||||||
page := ctx.QueryInt("page")
|
return
|
||||||
if page <= 1 {
|
|
||||||
page = 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Append repo to list of shown repos
|
||||||
|
if filterMode == models.FilterModeAll {
|
||||||
|
// Use a map to make sure we don't add the same Repository twice.
|
||||||
|
_, ok := showReposSet[issue.RepoID]
|
||||||
|
if !ok {
|
||||||
|
showReposSet[issue.RepoID] = true
|
||||||
|
// Append to list of shown Repositories.
|
||||||
|
showRepos = append(showRepos, issue.Repo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issueStats := models.GetUserIssueStats(repoID, ctxUser.ID, userRepoIDs, filterMode, isPullList)
|
||||||
|
|
||||||
var total int
|
var total int
|
||||||
if !isShowClosed {
|
if !isShowClosed {
|
||||||
total = int(issueStats.OpenCount)
|
total = int(issueStats.OpenCount)
|
||||||
} else {
|
} else {
|
||||||
total = int(issueStats.ClosedCount)
|
total = int(issueStats.ClosedCount)
|
||||||
}
|
}
|
||||||
ctx.Data["Page"] = paginater.New(total, setting.UI.IssuePagingNum, page, 5)
|
|
||||||
|
|
||||||
// Get issues.
|
|
||||||
issues, err := models.Issues(&models.IssuesOptions{
|
|
||||||
AssigneeID: assigneeID,
|
|
||||||
RepoID: repoID,
|
|
||||||
PosterID: posterID,
|
|
||||||
RepoIDs: repoIDs,
|
|
||||||
Page: page,
|
|
||||||
IsClosed: util.OptionalBoolOf(isShowClosed),
|
|
||||||
IsPull: util.OptionalBoolOf(isPullList),
|
|
||||||
SortType: sortType,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
ctx.Handle(500, "Issues", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get posters and repository.
|
|
||||||
for i := range issues {
|
|
||||||
issues[i].Repo, err = models.GetRepositoryByID(issues[i].RepoID)
|
|
||||||
if err != nil {
|
|
||||||
ctx.Handle(500, "GetRepositoryByID", fmt.Errorf("[#%d]%v", issues[i].ID, err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = issues[i].Repo.GetOwner(); err != nil {
|
|
||||||
ctx.Handle(500, "GetOwner", fmt.Errorf("[#%d]%v", issues[i].ID, err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx.Data["Issues"] = issues
|
ctx.Data["Issues"] = issues
|
||||||
|
ctx.Data["Repos"] = showRepos
|
||||||
|
ctx.Data["Page"] = paginater.New(total, setting.UI.IssuePagingNum, page, 5)
|
||||||
ctx.Data["IssueStats"] = issueStats
|
ctx.Data["IssueStats"] = issueStats
|
||||||
ctx.Data["ViewType"] = viewType
|
ctx.Data["ViewType"] = viewType
|
||||||
ctx.Data["SortType"] = sortType
|
ctx.Data["SortType"] = sortType
|
||||||
ctx.Data["RepoID"] = repoID
|
ctx.Data["RepoID"] = repoID
|
||||||
ctx.Data["IsShowClosed"] = isShowClosed
|
ctx.Data["IsShowClosed"] = isShowClosed
|
||||||
|
|
||||||
if isShowClosed {
|
if isShowClosed {
|
||||||
ctx.Data["State"] = "closed"
|
ctx.Data["State"] = "closed"
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
<div class="ui grid">
|
<div class="ui grid">
|
||||||
<div class="four wide column">
|
<div class="four wide column">
|
||||||
<div class="ui secondary vertical filter menu">
|
<div class="ui secondary vertical filter menu">
|
||||||
<a class="{{if eq .ViewType "all"}}ui basic blue button{{end}} item" href="{{.Link}}?repo={{.RepoID}}&sort={{$.SortType}}&state={{.State}}">
|
<a class="{{if eq .ViewType "your_repositories"}}ui basic blue button{{end}} item" href="{{.Link}}?type=your_repositories&repo={{.RepoID}}&sort={{$.SortType}}&state={{.State}}">
|
||||||
{{.i18n.Tr "home.issues.in_your_repos"}}
|
{{.i18n.Tr "home.issues.in_your_repos"}}
|
||||||
<strong class="ui right">{{.IssueStats.AllCount}}</strong>
|
<strong class="ui right">{{.IssueStats.YourRepositoriesCount}}</strong>
|
||||||
</a>
|
</a>
|
||||||
{{if not .ContextUser.IsOrganization}}
|
{{if not .ContextUser.IsOrganization}}
|
||||||
<a class="{{if eq .ViewType "assigned"}}ui basic blue button{{end}} item" href="{{.Link}}?type=assigned&repo={{.RepoID}}&sort={{$.SortType}}&state={{.State}}">
|
<a class="{{if eq .ViewType "assigned"}}ui basic blue button{{end}} item" href="{{.Link}}?type=assigned&repo={{.RepoID}}&sort={{$.SortType}}&state={{.State}}">
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
{{range .Repos}}
|
{{range .Repos}}
|
||||||
<a class="{{if eq $.RepoID .ID}}ui basic blue button{{end}} repo name item" href="{{$.Link}}?type={{$.ViewType}}{{if not (eq $.RepoID .ID)}}&repo={{.ID}}{{end}}&sort={{$.SortType}}&state={{$.State}}">
|
<a class="{{if eq $.RepoID .ID}}ui basic blue button{{end}} repo name item" href="{{$.Link}}?type={{$.ViewType}}{{if not (eq $.RepoID .ID)}}&repo={{.ID}}{{end}}&sort={{$.SortType}}&state={{$.State}}">
|
||||||
<span class="text truncate">{{$.ContextUser.Name}}/{{.Name}}</span>
|
<span class="text truncate">{{.FullName}}</span>
|
||||||
<div class="floating ui {{if $.IsShowClosed}}red{{else}}green{{end}} label">{{if $.IsShowClosed}}{{.NumClosedIssues}}{{else}}{{.NumOpenIssues}}{{end}}</div>
|
<div class="floating ui {{if $.IsShowClosed}}red{{else}}green{{end}} label">{{if $.IsShowClosed}}{{.NumClosedIssues}}{{else}}{{.NumOpenIssues}}{{end}}</div>
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -61,7 +61,7 @@
|
||||||
{{range .Issues}}
|
{{range .Issues}}
|
||||||
{{ $timeStr:= TimeSince .Created $.Lang }}
|
{{ $timeStr:= TimeSince .Created $.Lang }}
|
||||||
<li class="item">
|
<li class="item">
|
||||||
<div class="ui label">{{if not $.RepoID}}{{.Repo.Name}}{{end}}#{{.Index}}</div>
|
<div class="ui label">{{if not $.RepoID}}{{.Repo.FullName}}{{end}}#{{.Index}}</div>
|
||||||
<a class="title has-emoji" href="{{AppSubUrl}}/{{.Repo.Owner.Name}}/{{.Repo.Name}}/issues/{{.Index}}">{{.Title}}</a>
|
<a class="title has-emoji" href="{{AppSubUrl}}/{{.Repo.Owner.Name}}/{{.Repo.Name}}/issues/{{.Index}}">{{.Title}}</a>
|
||||||
|
|
||||||
{{range .Labels}}
|
{{range .Labels}}
|
||||||
|
|
Loading…
Reference in a new issue