* Added progressbar for issues (#1146). * Updated the generated index.css. Signed-off-by: modmew8 <modmew8@gmail.com> * Removed stored progress percentage and changed it to css calc. Also added the issue task progress to the user/dashboard/issues. Signed-off-by: modmew8 <modmew8@gmail.com> * Removed unnecessary blanks. Signed-off-by: modmew8 <modmew8@gmail.com> * Formatted the files correctly, fmt-check terminates now without errors. Signed-off-by: modmew8 <modmew8@gmail.com> * Removed variables, made computing the tasks on demand with precompiled regexp. Signed-off-by: modmew8 <modmew8@gmail.com>
This commit is contained in:
parent
22a7a7ec9b
commit
d996da6bab
5 changed files with 50 additions and 1 deletions
|
@ -7,6 +7,7 @@ package models
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path"
|
"path"
|
||||||
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -54,6 +55,19 @@ type Issue struct {
|
||||||
Reactions ReactionList `xorm:"-"`
|
Reactions ReactionList `xorm:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
issueTasksPat *regexp.Regexp
|
||||||
|
issueTasksDonePat *regexp.Regexp
|
||||||
|
)
|
||||||
|
|
||||||
|
const issueTasksRegexpStr = `(^\s*-\s\[[\sx]\]\s)|(\n\s*-\s\[[\sx]\]\s)`
|
||||||
|
const issueTasksDoneRegexpStr = `(^\s*-\s\[[x]\]\s)|(\n\s*-\s\[[x]\]\s)`
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
issueTasksPat = regexp.MustCompile(issueTasksRegexpStr)
|
||||||
|
issueTasksDonePat = regexp.MustCompile(issueTasksDoneRegexpStr)
|
||||||
|
}
|
||||||
|
|
||||||
func (issue *Issue) loadRepo(e Engine) (err error) {
|
func (issue *Issue) loadRepo(e Engine) (err error) {
|
||||||
if issue.Repo == nil {
|
if issue.Repo == nil {
|
||||||
issue.Repo, err = getRepositoryByID(e, issue.RepoID)
|
issue.Repo, err = getRepositoryByID(e, issue.RepoID)
|
||||||
|
@ -741,6 +755,7 @@ func AddDeletePRBranchComment(doer *User, repo *Repository, issueID int64, branc
|
||||||
func (issue *Issue) ChangeContent(doer *User, content string) (err error) {
|
func (issue *Issue) ChangeContent(doer *User, content string) (err error) {
|
||||||
oldContent := issue.Content
|
oldContent := issue.Content
|
||||||
issue.Content = content
|
issue.Content = content
|
||||||
|
|
||||||
if err = UpdateIssueCols(issue, "content"); err != nil {
|
if err = UpdateIssueCols(issue, "content"); err != nil {
|
||||||
return fmt.Errorf("UpdateIssueCols: %v", err)
|
return fmt.Errorf("UpdateIssueCols: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -818,6 +833,16 @@ func (issue *Issue) ChangeAssignee(doer *User, assigneeID int64) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTasks returns the amount of tasks in the issues content
|
||||||
|
func (issue *Issue) GetTasks() int {
|
||||||
|
return len(issueTasksPat.FindAllStringIndex(issue.Content, -1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTasksDone returns the amount of completed tasks in the issues content
|
||||||
|
func (issue *Issue) GetTasksDone() int {
|
||||||
|
return len(issueTasksDonePat.FindAllStringIndex(issue.Content, -1))
|
||||||
|
}
|
||||||
|
|
||||||
// NewIssueOptions represents the options of a new issue.
|
// NewIssueOptions represents the options of a new issue.
|
||||||
type NewIssueOptions struct {
|
type NewIssueOptions struct {
|
||||||
Repo *Repository
|
Repo *Repository
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1491,6 +1491,20 @@
|
||||||
.desc {
|
.desc {
|
||||||
padding-top: 5px;
|
padding-top: 5px;
|
||||||
color: #999;
|
color: #999;
|
||||||
|
.progress-bar {
|
||||||
|
width: 80px;
|
||||||
|
height: 6px;
|
||||||
|
display: inline-block;
|
||||||
|
background-color: #eee;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 3px;
|
||||||
|
vertical-align: middle !important;
|
||||||
|
.progress {
|
||||||
|
background-color: #ccc;
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
a.milestone {
|
a.milestone {
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
color: #999!important;
|
color: #999!important;
|
||||||
|
|
|
@ -200,6 +200,11 @@
|
||||||
|
|
||||||
<p class="desc">
|
<p class="desc">
|
||||||
{{$.i18n.Tr "repo.issues.opened_by" $timeStr .Poster.HomeLink .Poster.Name | Safe}}
|
{{$.i18n.Tr "repo.issues.opened_by" $timeStr .Poster.HomeLink .Poster.Name | Safe}}
|
||||||
|
{{$tasks := .GetTasks}}
|
||||||
|
{{if gt $tasks 0}}
|
||||||
|
{{$tasksDone := .GetTasksDone}}
|
||||||
|
<span class="octicon octicon-checklist"></span> {{$tasksDone}} / {{$tasks}} <span class="progress-bar"><span class="progress" style="width:calc(100% * {{$tasksDone}} / {{$tasks}});"></span></span>
|
||||||
|
{{end}}
|
||||||
{{if .Milestone}}
|
{{if .Milestone}}
|
||||||
<a class="milestone" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{.Milestone.ID}}&assignee={{$.AssigneeID}}">
|
<a class="milestone" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{.Milestone.ID}}&assignee={{$.AssigneeID}}">
|
||||||
<span class="octicon octicon-milestone"></span> {{.Milestone.Name}}
|
<span class="octicon octicon-milestone"></span> {{.Milestone.Name}}
|
||||||
|
|
|
@ -87,6 +87,11 @@
|
||||||
<img class="ui avatar image" src="{{.Assignee.RelAvatarLink}}">
|
<img class="ui avatar image" src="{{.Assignee.RelAvatarLink}}">
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
{{$tasks := .GetTasks}}
|
||||||
|
{{if gt $tasks 0}}
|
||||||
|
{{$tasksDone := .GetTasksDone}}
|
||||||
|
<span class="octicon octicon-checklist"></span> {{$tasksDone}} / {{$tasks}} <span class="progress-bar"><span class="progress" style="width:calc(100% * {{$tasksDone}} / {{$tasks}});"></span></span>
|
||||||
|
{{end}}
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
Reference in a new issue