mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-21 12:44:49 -05:00
* track labels changed on issue view & resolved #542 * add missing head comment & sort & fix refresh
This commit is contained in:
parent
d078aa30d6
commit
f94869d2d1
10 changed files with 366 additions and 195 deletions
127
models/issue.go
127
models/issue.go
|
@ -7,6 +7,7 @@ package models
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -103,11 +104,17 @@ func (issue *Issue) GetPullRequest() (pr *PullRequest, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (issue *Issue) loadAttributes(e Engine) (err error) {
|
func (issue *Issue) loadLabels(e Engine) (err error) {
|
||||||
if err := issue.loadRepo(e); err != nil {
|
if issue.Labels == nil {
|
||||||
return err
|
issue.Labels, err = getLabelsByIssueID(e, issue.ID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("getLabelsByIssueID [%d]: %v", issue.ID, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (issue *Issue) loadPoster(e Engine) (err error) {
|
||||||
if issue.Poster == nil {
|
if issue.Poster == nil {
|
||||||
issue.Poster, err = getUserByID(e, issue.PosterID)
|
issue.Poster, err = getUserByID(e, issue.PosterID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -120,12 +127,20 @@ func (issue *Issue) loadAttributes(e Engine) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if issue.Labels == nil {
|
func (issue *Issue) loadAttributes(e Engine) (err error) {
|
||||||
issue.Labels, err = getLabelsByIssueID(e, issue.ID)
|
if err = issue.loadRepo(e); err != nil {
|
||||||
if err != nil {
|
return
|
||||||
return fmt.Errorf("getLabelsByIssueID [%d]: %v", issue.ID, err)
|
}
|
||||||
}
|
|
||||||
|
if err = issue.loadPoster(e); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = issue.loadLabels(e); err != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if issue.Milestone == nil && issue.MilestoneID > 0 {
|
if issue.Milestone == nil && issue.MilestoneID > 0 {
|
||||||
|
@ -289,13 +304,13 @@ func (issue *Issue) sendLabelUpdatedWebhook(doer *User) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (issue *Issue) addLabel(e *xorm.Session, label *Label) error {
|
func (issue *Issue) addLabel(e *xorm.Session, label *Label, doer *User) error {
|
||||||
return newIssueLabel(e, issue, label)
|
return newIssueLabel(e, issue, label, doer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddLabel adds a new label to the issue.
|
// AddLabel adds a new label to the issue.
|
||||||
func (issue *Issue) AddLabel(doer *User, label *Label) error {
|
func (issue *Issue) AddLabel(doer *User, label *Label) error {
|
||||||
if err := NewIssueLabel(issue, label); err != nil {
|
if err := NewIssueLabel(issue, label, doer); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,13 +318,13 @@ func (issue *Issue) AddLabel(doer *User, label *Label) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (issue *Issue) addLabels(e *xorm.Session, labels []*Label) error {
|
func (issue *Issue) addLabels(e *xorm.Session, labels []*Label, doer *User) error {
|
||||||
return newIssueLabels(e, issue, labels)
|
return newIssueLabels(e, issue, labels, doer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddLabels adds a list of new labels to the issue.
|
// AddLabels adds a list of new labels to the issue.
|
||||||
func (issue *Issue) AddLabels(doer *User, labels []*Label) error {
|
func (issue *Issue) AddLabels(doer *User, labels []*Label) error {
|
||||||
if err := NewIssueLabels(issue, labels); err != nil {
|
if err := NewIssueLabels(issue, labels, doer); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,8 +344,8 @@ func (issue *Issue) getLabels(e Engine) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (issue *Issue) removeLabel(e *xorm.Session, label *Label) error {
|
func (issue *Issue) removeLabel(e *xorm.Session, doer *User, label *Label) error {
|
||||||
return deleteIssueLabel(e, issue, label)
|
return deleteIssueLabel(e, doer, issue, label)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveLabel removes a label from issue by given ID.
|
// RemoveLabel removes a label from issue by given ID.
|
||||||
|
@ -345,7 +360,7 @@ func (issue *Issue) RemoveLabel(doer *User, label *Label) error {
|
||||||
return ErrLabelNotExist{}
|
return ErrLabelNotExist{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := DeleteIssueLabel(issue, label); err != nil {
|
if err := DeleteIssueLabel(issue, doer, label); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,13 +368,13 @@ func (issue *Issue) RemoveLabel(doer *User, label *Label) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (issue *Issue) clearLabels(e *xorm.Session) (err error) {
|
func (issue *Issue) clearLabels(e *xorm.Session, doer *User) (err error) {
|
||||||
if err = issue.getLabels(e); err != nil {
|
if err = issue.getLabels(e); err != nil {
|
||||||
return fmt.Errorf("getLabels: %v", err)
|
return fmt.Errorf("getLabels: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range issue.Labels {
|
for i := range issue.Labels {
|
||||||
if err = issue.removeLabel(e, issue.Labels[i]); err != nil {
|
if err = issue.removeLabel(e, doer, issue.Labels[i]); err != nil {
|
||||||
return fmt.Errorf("removeLabel: %v", err)
|
return fmt.Errorf("removeLabel: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -386,7 +401,7 @@ func (issue *Issue) ClearLabels(doer *User) (err error) {
|
||||||
return ErrLabelNotExist{}
|
return ErrLabelNotExist{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = issue.clearLabels(sess); err != nil {
|
if err = issue.clearLabels(sess, doer); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,19 +432,75 @@ func (issue *Issue) ClearLabels(doer *User) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type labelSorter []*Label
|
||||||
|
|
||||||
|
func (ts labelSorter) Len() int {
|
||||||
|
return len([]*Label(ts))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts labelSorter) Less(i, j int) bool {
|
||||||
|
return []*Label(ts)[i].ID < []*Label(ts)[j].ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts labelSorter) Swap(i, j int) {
|
||||||
|
[]*Label(ts)[i], []*Label(ts)[j] = []*Label(ts)[j], []*Label(ts)[i]
|
||||||
|
}
|
||||||
|
|
||||||
// ReplaceLabels removes all current labels and add new labels to the issue.
|
// ReplaceLabels removes all current labels and add new labels to the issue.
|
||||||
// Triggers appropriate WebHooks, if any.
|
// Triggers appropriate WebHooks, if any.
|
||||||
func (issue *Issue) ReplaceLabels(labels []*Label) (err error) {
|
func (issue *Issue) ReplaceLabels(labels []*Label, doer *User) (err error) {
|
||||||
sess := x.NewSession()
|
sess := x.NewSession()
|
||||||
defer sessionRelease(sess)
|
defer sessionRelease(sess)
|
||||||
if err = sess.Begin(); err != nil {
|
if err = sess.Begin(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = issue.clearLabels(sess); err != nil {
|
if err = issue.loadLabels(sess); err != nil {
|
||||||
return fmt.Errorf("clearLabels: %v", err)
|
return err
|
||||||
} else if err = issue.addLabels(sess, labels); err != nil {
|
}
|
||||||
return fmt.Errorf("addLabels: %v", err)
|
|
||||||
|
sort.Sort(labelSorter(labels))
|
||||||
|
sort.Sort(labelSorter(issue.Labels))
|
||||||
|
|
||||||
|
var toAdd, toRemove []*Label
|
||||||
|
for _, l := range labels {
|
||||||
|
var exist bool
|
||||||
|
for _, oriLabel := range issue.Labels {
|
||||||
|
if oriLabel.ID == l.ID {
|
||||||
|
exist = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !exist {
|
||||||
|
toAdd = append(toAdd, l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, oriLabel := range issue.Labels {
|
||||||
|
var exist bool
|
||||||
|
for _, l := range labels {
|
||||||
|
if oriLabel.ID == l.ID {
|
||||||
|
exist = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !exist {
|
||||||
|
toRemove = append(toRemove, oriLabel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(toAdd) > 0 {
|
||||||
|
if err = issue.addLabels(sess, toAdd, doer); err != nil {
|
||||||
|
return fmt.Errorf("addLabels: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(toRemove) > 0 {
|
||||||
|
for _, l := range toRemove {
|
||||||
|
if err = issue.removeLabel(sess, doer, l); err != nil {
|
||||||
|
return fmt.Errorf("removeLabel: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sess.Commit()
|
return sess.Commit()
|
||||||
|
@ -731,13 +802,17 @@ func newIssue(e *xorm.Session, opts NewIssueOptions) (err error) {
|
||||||
return fmt.Errorf("find all labels [label_ids: %v]: %v", opts.LableIDs, err)
|
return fmt.Errorf("find all labels [label_ids: %v]: %v", opts.LableIDs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = opts.Issue.loadPoster(e); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
for _, label := range labels {
|
for _, label := range labels {
|
||||||
// Silently drop invalid labels.
|
// Silently drop invalid labels.
|
||||||
if label.RepoID != opts.Repo.ID {
|
if label.RepoID != opts.Repo.ID {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = opts.Issue.addLabel(e, label); err != nil {
|
if err = opts.Issue.addLabel(e, label, opts.Issue.Poster); err != nil {
|
||||||
return fmt.Errorf("addLabel [id: %d]: %v", label.ID, err)
|
return fmt.Errorf("addLabel [id: %d]: %v", label.ID, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,8 @@ const (
|
||||||
CommentTypeCommentRef
|
CommentTypeCommentRef
|
||||||
// Reference from a pull request
|
// Reference from a pull request
|
||||||
CommentTypePullRef
|
CommentTypePullRef
|
||||||
|
// Labels changed
|
||||||
|
CommentTypeLabel
|
||||||
)
|
)
|
||||||
|
|
||||||
// CommentTag defines comment tag type
|
// CommentTag defines comment tag type
|
||||||
|
@ -57,6 +59,8 @@ type Comment struct {
|
||||||
Poster *User `xorm:"-"`
|
Poster *User `xorm:"-"`
|
||||||
IssueID int64 `xorm:"INDEX"`
|
IssueID int64 `xorm:"INDEX"`
|
||||||
CommitID int64
|
CommitID int64
|
||||||
|
LabelID int64
|
||||||
|
Label *Label `xorm:"-"`
|
||||||
Line int64
|
Line int64
|
||||||
Content string `xorm:"TEXT"`
|
Content string `xorm:"TEXT"`
|
||||||
RenderedContent string `xorm:"-"`
|
RenderedContent string `xorm:"-"`
|
||||||
|
@ -185,6 +189,21 @@ func (c *Comment) EventTag() string {
|
||||||
return "event-" + com.ToStr(c.ID)
|
return "event-" + com.ToStr(c.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadLabel if comment.Type is CommentTypeLabel, then load Label
|
||||||
|
func (c *Comment) LoadLabel() error {
|
||||||
|
var label Label
|
||||||
|
has, err := x.ID(c.LabelID).Get(&label)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if !has {
|
||||||
|
return ErrLabelNotExist{
|
||||||
|
LabelID: c.LabelID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.Label = &label
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// MailParticipants sends new comment emails to repository watchers
|
// MailParticipants sends new comment emails to repository watchers
|
||||||
// and mentioned people.
|
// and mentioned people.
|
||||||
func (c *Comment) MailParticipants(e Engine, opType ActionType, issue *Issue) (err error) {
|
func (c *Comment) MailParticipants(e Engine, opType ActionType, issue *Issue) (err error) {
|
||||||
|
@ -209,11 +228,16 @@ func (c *Comment) MailParticipants(e Engine, opType ActionType, issue *Issue) (e
|
||||||
}
|
}
|
||||||
|
|
||||||
func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err error) {
|
func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err error) {
|
||||||
|
var LabelID int64
|
||||||
|
if opts.Label != nil {
|
||||||
|
LabelID = opts.Label.ID
|
||||||
|
}
|
||||||
comment := &Comment{
|
comment := &Comment{
|
||||||
Type: opts.Type,
|
Type: opts.Type,
|
||||||
PosterID: opts.Doer.ID,
|
PosterID: opts.Doer.ID,
|
||||||
Poster: opts.Doer,
|
Poster: opts.Doer,
|
||||||
IssueID: opts.Issue.ID,
|
IssueID: opts.Issue.ID,
|
||||||
|
LabelID: LabelID,
|
||||||
CommitID: opts.CommitID,
|
CommitID: opts.CommitID,
|
||||||
CommitSHA: opts.CommitSHA,
|
CommitSHA: opts.CommitSHA,
|
||||||
Line: opts.LineNum,
|
Line: opts.LineNum,
|
||||||
|
@ -223,6 +247,10 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = opts.Repo.getOwner(e); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// Compose comment action, could be plain comment, close or reopen issue/pull request.
|
// Compose comment action, could be plain comment, close or reopen issue/pull request.
|
||||||
// This object will be used to notify watchers in the end of function.
|
// This object will be used to notify watchers in the end of function.
|
||||||
act := &Action{
|
act := &Action{
|
||||||
|
@ -324,12 +352,28 @@ func createStatusComment(e *xorm.Session, doer *User, repo *Repository, issue *I
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createLabelComment(e *xorm.Session, doer *User, repo *Repository, issue *Issue, label *Label, add bool) (*Comment, error) {
|
||||||
|
var content string
|
||||||
|
if add {
|
||||||
|
content = "1"
|
||||||
|
}
|
||||||
|
return createComment(e, &CreateCommentOptions{
|
||||||
|
Type: CommentTypeLabel,
|
||||||
|
Doer: doer,
|
||||||
|
Repo: repo,
|
||||||
|
Issue: issue,
|
||||||
|
Label: label,
|
||||||
|
Content: content,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// CreateCommentOptions defines options for creating comment
|
// CreateCommentOptions defines options for creating comment
|
||||||
type CreateCommentOptions struct {
|
type CreateCommentOptions struct {
|
||||||
Type CommentType
|
Type CommentType
|
||||||
Doer *User
|
Doer *User
|
||||||
Repo *Repository
|
Repo *Repository
|
||||||
Issue *Issue
|
Issue *Issue
|
||||||
|
Label *Label
|
||||||
|
|
||||||
CommitID int64
|
CommitID int64
|
||||||
CommitSHA string
|
CommitSHA string
|
||||||
|
|
|
@ -276,7 +276,7 @@ func HasIssueLabel(issueID, labelID int64) bool {
|
||||||
return hasIssueLabel(x, issueID, labelID)
|
return hasIssueLabel(x, issueID, labelID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newIssueLabel(e *xorm.Session, issue *Issue, label *Label) (err error) {
|
func newIssueLabel(e *xorm.Session, issue *Issue, label *Label, doer *User) (err error) {
|
||||||
if _, err = e.Insert(&IssueLabel{
|
if _, err = e.Insert(&IssueLabel{
|
||||||
IssueID: issue.ID,
|
IssueID: issue.ID,
|
||||||
LabelID: label.ID,
|
LabelID: label.ID,
|
||||||
|
@ -284,6 +284,14 @@ func newIssueLabel(e *xorm.Session, issue *Issue, label *Label) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = issue.loadRepo(e); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = createLabelComment(e, doer, issue.Repo, issue, label, true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
label.NumIssues++
|
label.NumIssues++
|
||||||
if issue.IsClosed {
|
if issue.IsClosed {
|
||||||
label.NumClosedIssues++
|
label.NumClosedIssues++
|
||||||
|
@ -292,7 +300,7 @@ func newIssueLabel(e *xorm.Session, issue *Issue, label *Label) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewIssueLabel creates a new issue-label relation.
|
// NewIssueLabel creates a new issue-label relation.
|
||||||
func NewIssueLabel(issue *Issue, label *Label) (err error) {
|
func NewIssueLabel(issue *Issue, label *Label, doer *User) (err error) {
|
||||||
if HasIssueLabel(issue.ID, label.ID) {
|
if HasIssueLabel(issue.ID, label.ID) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -303,20 +311,20 @@ func NewIssueLabel(issue *Issue, label *Label) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = newIssueLabel(sess, issue, label); err != nil {
|
if err = newIssueLabel(sess, issue, label, doer); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return sess.Commit()
|
return sess.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func newIssueLabels(e *xorm.Session, issue *Issue, labels []*Label) (err error) {
|
func newIssueLabels(e *xorm.Session, issue *Issue, labels []*Label, doer *User) (err error) {
|
||||||
for i := range labels {
|
for i := range labels {
|
||||||
if hasIssueLabel(e, issue.ID, labels[i].ID) {
|
if hasIssueLabel(e, issue.ID, labels[i].ID) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = newIssueLabel(e, issue, labels[i]); err != nil {
|
if err = newIssueLabel(e, issue, labels[i], doer); err != nil {
|
||||||
return fmt.Errorf("newIssueLabel: %v", err)
|
return fmt.Errorf("newIssueLabel: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -325,14 +333,14 @@ func newIssueLabels(e *xorm.Session, issue *Issue, labels []*Label) (err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewIssueLabels creates a list of issue-label relations.
|
// NewIssueLabels creates a list of issue-label relations.
|
||||||
func NewIssueLabels(issue *Issue, labels []*Label) (err error) {
|
func NewIssueLabels(issue *Issue, labels []*Label, doer *User) (err error) {
|
||||||
sess := x.NewSession()
|
sess := x.NewSession()
|
||||||
defer sessionRelease(sess)
|
defer sessionRelease(sess)
|
||||||
if err = sess.Begin(); err != nil {
|
if err = sess.Begin(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = newIssueLabels(sess, issue, labels); err != nil {
|
if err = newIssueLabels(sess, issue, labels, doer); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,7 +360,7 @@ func GetIssueLabels(issueID int64) ([]*IssueLabel, error) {
|
||||||
return getIssueLabels(x, issueID)
|
return getIssueLabels(x, issueID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteIssueLabel(e *xorm.Session, issue *Issue, label *Label) (err error) {
|
func deleteIssueLabel(e *xorm.Session, doer *User, issue *Issue, label *Label) (err error) {
|
||||||
if _, err = e.Delete(&IssueLabel{
|
if _, err = e.Delete(&IssueLabel{
|
||||||
IssueID: issue.ID,
|
IssueID: issue.ID,
|
||||||
LabelID: label.ID,
|
LabelID: label.ID,
|
||||||
|
@ -360,6 +368,14 @@ func deleteIssueLabel(e *xorm.Session, issue *Issue, label *Label) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = issue.loadRepo(e); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = createLabelComment(e, doer, issue.Repo, issue, label, false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
label.NumIssues--
|
label.NumIssues--
|
||||||
if issue.IsClosed {
|
if issue.IsClosed {
|
||||||
label.NumClosedIssues--
|
label.NumClosedIssues--
|
||||||
|
@ -368,14 +384,14 @@ func deleteIssueLabel(e *xorm.Session, issue *Issue, label *Label) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteIssueLabel deletes issue-label relation.
|
// DeleteIssueLabel deletes issue-label relation.
|
||||||
func DeleteIssueLabel(issue *Issue, label *Label) (err error) {
|
func DeleteIssueLabel(issue *Issue, doer *User, label *Label) (err error) {
|
||||||
sess := x.NewSession()
|
sess := x.NewSession()
|
||||||
defer sessionRelease(sess)
|
defer sessionRelease(sess)
|
||||||
if err = sess.Begin(); err != nil {
|
if err = sess.Begin(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = deleteIssueLabel(sess, issue, label); err != nil {
|
if err = deleteIssueLabel(sess, doer, issue, label); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -541,6 +541,8 @@ issues.label_templates.info = There aren't any labels yet. You can click on the
|
||||||
issues.label_templates.helper = Select a label set
|
issues.label_templates.helper = Select a label set
|
||||||
issues.label_templates.use = Use this label set
|
issues.label_templates.use = Use this label set
|
||||||
issues.label_templates.fail_to_load_file = Failed to load label template file '%s': %v
|
issues.label_templates.fail_to_load_file = Failed to load label template file '%s': %v
|
||||||
|
issues.add_label_at = `added the <div class="ui label" style="color: %s; background-color: %s">%s</div> label %s`
|
||||||
|
issues.remove_label_at = `removed the <div class="ui label" style="color: %s; background-color: %s">%s</div> label %s`
|
||||||
issues.open_tab = %d Open
|
issues.open_tab = %d Open
|
||||||
issues.close_tab = %d Closed
|
issues.close_tab = %d Closed
|
||||||
issues.filter_label = Label
|
issues.filter_label = Label
|
||||||
|
|
|
@ -501,6 +501,8 @@ issues.label_templates.info=此仓库还未创建任何标签,您可以通过
|
||||||
issues.label_templates.helper=选择标签模板
|
issues.label_templates.helper=选择标签模板
|
||||||
issues.label_templates.use=加载标签模板
|
issues.label_templates.use=加载标签模板
|
||||||
issues.label_templates.fail_to_load_file=加载标签模板文件 '%s' 时发生错误:%v
|
issues.label_templates.fail_to_load_file=加载标签模板文件 '%s' 时发生错误:%v
|
||||||
|
issues.add_label_at = ` %[4]s 添加了标签 <div class="ui label" style="color: %[1]s; background-color: %[2]s">%[3]s</div>`
|
||||||
|
issues.remove_label_at = ` %[4]s 删除了标签 <div class="ui label" style="color: %[1]s; background-color: %[2]s">%[3]s</div>`
|
||||||
issues.open_tab=%d 个开启中
|
issues.open_tab=%d 个开启中
|
||||||
issues.close_tab=%d 个已关闭
|
issues.close_tab=%d 个已关闭
|
||||||
issues.filter_label=标签筛选
|
issues.filter_label=标签筛选
|
||||||
|
|
|
@ -108,6 +108,10 @@ function initCommentForm() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$('.select-label').dropdown('setting', 'onHide', function(){
|
||||||
|
location.reload();
|
||||||
|
});
|
||||||
|
|
||||||
$labelMenu.find('.item:not(.no-select)').click(function () {
|
$labelMenu.find('.item:not(.no-select)').click(function () {
|
||||||
if ($(this).hasClass('checked')) {
|
if ($(this).hasClass('checked')) {
|
||||||
$(this).removeClass('checked');
|
$(this).removeClass('checked');
|
||||||
|
|
|
@ -98,7 +98,7 @@ func DeleteIssueLabel(ctx *context.APIContext) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := models.DeleteIssueLabel(issue, label); err != nil {
|
if err := models.DeleteIssueLabel(issue, ctx.User, label); err != nil {
|
||||||
ctx.Error(500, "DeleteIssueLabel", err)
|
ctx.Error(500, "DeleteIssueLabel", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,7 @@ func ReplaceIssueLabels(ctx *context.APIContext, form api.IssueLabelsOption) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := issue.ReplaceLabels(labels); err != nil {
|
if err := issue.ReplaceLabels(labels, ctx.User); err != nil {
|
||||||
ctx.Error(500, "ReplaceLabels", err)
|
ctx.Error(500, "ReplaceLabels", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,8 +34,6 @@ const (
|
||||||
tplIssueNew base.TplName = "repo/issue/new"
|
tplIssueNew base.TplName = "repo/issue/new"
|
||||||
tplIssueView base.TplName = "repo/issue/view"
|
tplIssueView base.TplName = "repo/issue/view"
|
||||||
|
|
||||||
tplLabels base.TplName = "repo/issue/labels"
|
|
||||||
|
|
||||||
tplMilestone base.TplName = "repo/issue/milestones"
|
tplMilestone base.TplName = "repo/issue/milestones"
|
||||||
tplMilestoneNew base.TplName = "repo/issue/milestone_new"
|
tplMilestoneNew base.TplName = "repo/issue/milestone_new"
|
||||||
tplMilestoneEdit base.TplName = "repo/issue/milestone_edit"
|
tplMilestoneEdit base.TplName = "repo/issue/milestone_edit"
|
||||||
|
@ -86,21 +84,6 @@ func MustAllowPulls(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RetrieveLabels find all the labels of a repository
|
|
||||||
func RetrieveLabels(ctx *context.Context) {
|
|
||||||
labels, err := models.GetLabelsByRepoID(ctx.Repo.Repository.ID, ctx.Query("sort"))
|
|
||||||
if err != nil {
|
|
||||||
ctx.Handle(500, "RetrieveLabels.GetLabels", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, l := range labels {
|
|
||||||
l.CalOpenIssues()
|
|
||||||
}
|
|
||||||
ctx.Data["Labels"] = labels
|
|
||||||
ctx.Data["NumLabels"] = len(labels)
|
|
||||||
ctx.Data["SortType"] = ctx.Query("sort")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Issues render issues page
|
// Issues render issues page
|
||||||
func Issues(ctx *context.Context) {
|
func Issues(ctx *context.Context) {
|
||||||
isPullList := ctx.Params(":type") == "pulls"
|
isPullList := ctx.Params(":type") == "pulls"
|
||||||
|
@ -629,6 +612,11 @@ func ViewIssue(ctx *context.Context) {
|
||||||
if !isAdded && !issue.IsPoster(comment.Poster.ID) {
|
if !isAdded && !issue.IsPoster(comment.Poster.ID) {
|
||||||
participants = append(participants, comment.Poster)
|
participants = append(participants, comment.Poster)
|
||||||
}
|
}
|
||||||
|
} else if comment.Type == models.CommentTypeLabel {
|
||||||
|
if err = comment.LoadLabel(); err != nil {
|
||||||
|
ctx.Handle(500, "LoadLabel", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -723,48 +711,6 @@ func UpdateIssueContent(ctx *context.Context) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateIssueLabel change issue's labels
|
|
||||||
func UpdateIssueLabel(ctx *context.Context) {
|
|
||||||
issue := getActionIssue(ctx)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if ctx.Query("action") == "clear" {
|
|
||||||
if err := issue.ClearLabels(ctx.User); err != nil {
|
|
||||||
ctx.Handle(500, "ClearLabels", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
isAttach := ctx.Query("action") == "attach"
|
|
||||||
label, err := models.GetLabelByID(ctx.QueryInt64("id"))
|
|
||||||
if err != nil {
|
|
||||||
if models.IsErrLabelNotExist(err) {
|
|
||||||
ctx.Error(404, "GetLabelByID")
|
|
||||||
} else {
|
|
||||||
ctx.Handle(500, "GetLabelByID", err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if isAttach && !issue.HasLabel(label.ID) {
|
|
||||||
if err = issue.AddLabel(ctx.User, label); err != nil {
|
|
||||||
ctx.Handle(500, "AddLabel", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else if !isAttach && issue.HasLabel(label.ID) {
|
|
||||||
if err = issue.RemoveLabel(ctx.User, label); err != nil {
|
|
||||||
ctx.Handle(500, "RemoveLabel", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.JSON(200, map[string]interface{}{
|
|
||||||
"ok": true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateIssueMilestone change issue's milestone
|
// UpdateIssueMilestone change issue's milestone
|
||||||
func UpdateIssueMilestone(ctx *context.Context) {
|
func UpdateIssueMilestone(ctx *context.Context) {
|
||||||
issue := getActionIssue(ctx)
|
issue := getActionIssue(ctx)
|
||||||
|
@ -966,103 +912,6 @@ func DeleteComment(ctx *context.Context) {
|
||||||
ctx.Status(200)
|
ctx.Status(200)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Labels render issue's labels page
|
|
||||||
func Labels(ctx *context.Context) {
|
|
||||||
ctx.Data["Title"] = ctx.Tr("repo.labels")
|
|
||||||
ctx.Data["PageIsIssueList"] = true
|
|
||||||
ctx.Data["PageIsLabels"] = true
|
|
||||||
ctx.Data["RequireMinicolors"] = true
|
|
||||||
ctx.Data["LabelTemplates"] = models.LabelTemplates
|
|
||||||
ctx.HTML(200, tplLabels)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InitializeLabels init labels for a repository
|
|
||||||
func InitializeLabels(ctx *context.Context, form auth.InitializeLabelsForm) {
|
|
||||||
if ctx.HasError() {
|
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
list, err := models.GetLabelTemplateFile(form.TemplateName)
|
|
||||||
if err != nil {
|
|
||||||
ctx.Flash.Error(ctx.Tr("repo.issues.label_templates.fail_to_load_file", form.TemplateName, err))
|
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
labels := make([]*models.Label, len(list))
|
|
||||||
for i := 0; i < len(list); i++ {
|
|
||||||
labels[i] = &models.Label{
|
|
||||||
RepoID: ctx.Repo.Repository.ID,
|
|
||||||
Name: list[i][0],
|
|
||||||
Color: list[i][1],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := models.NewLabels(labels...); err != nil {
|
|
||||||
ctx.Handle(500, "NewLabels", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewLabel create new label for repository
|
|
||||||
func NewLabel(ctx *context.Context, form auth.CreateLabelForm) {
|
|
||||||
ctx.Data["Title"] = ctx.Tr("repo.labels")
|
|
||||||
ctx.Data["PageIsLabels"] = true
|
|
||||||
|
|
||||||
if ctx.HasError() {
|
|
||||||
ctx.Flash.Error(ctx.Data["ErrorMsg"].(string))
|
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
l := &models.Label{
|
|
||||||
RepoID: ctx.Repo.Repository.ID,
|
|
||||||
Name: form.Title,
|
|
||||||
Color: form.Color,
|
|
||||||
}
|
|
||||||
if err := models.NewLabels(l); err != nil {
|
|
||||||
ctx.Handle(500, "NewLabel", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateLabel update a label's name and color
|
|
||||||
func UpdateLabel(ctx *context.Context, form auth.CreateLabelForm) {
|
|
||||||
l, err := models.GetLabelByID(form.ID)
|
|
||||||
if err != nil {
|
|
||||||
switch {
|
|
||||||
case models.IsErrLabelNotExist(err):
|
|
||||||
ctx.Error(404)
|
|
||||||
default:
|
|
||||||
ctx.Handle(500, "UpdateLabel", err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
l.Name = form.Title
|
|
||||||
l.Color = form.Color
|
|
||||||
if err := models.UpdateLabel(l); err != nil {
|
|
||||||
ctx.Handle(500, "UpdateLabel", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteLabel delete a label
|
|
||||||
func DeleteLabel(ctx *context.Context) {
|
|
||||||
if err := models.DeleteLabel(ctx.Repo.Repository.ID, ctx.QueryInt64("id")); err != nil {
|
|
||||||
ctx.Flash.Error("DeleteLabel: " + err.Error())
|
|
||||||
} else {
|
|
||||||
ctx.Flash.Success(ctx.Tr("repo.issues.label_deletion_success"))
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.JSON(200, map[string]interface{}{
|
|
||||||
"redirect": ctx.Repo.RepoLink + "/labels",
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Milestones render milestones page
|
// Milestones render milestones page
|
||||||
func Milestones(ctx *context.Context) {
|
func Milestones(ctx *context.Context) {
|
||||||
ctx.Data["Title"] = ctx.Tr("repo.milestones")
|
ctx.Data["Title"] = ctx.Tr("repo.milestones")
|
||||||
|
|
170
routers/repo/issue_label.go
Normal file
170
routers/repo/issue_label.go
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"code.gitea.io/gitea/models"
|
||||||
|
"code.gitea.io/gitea/modules/auth"
|
||||||
|
"code.gitea.io/gitea/modules/base"
|
||||||
|
"code.gitea.io/gitea/modules/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
tplLabels base.TplName = "repo/issue/labels"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Labels render issue's labels page
|
||||||
|
func Labels(ctx *context.Context) {
|
||||||
|
ctx.Data["Title"] = ctx.Tr("repo.labels")
|
||||||
|
ctx.Data["PageIsIssueList"] = true
|
||||||
|
ctx.Data["PageIsLabels"] = true
|
||||||
|
ctx.Data["RequireMinicolors"] = true
|
||||||
|
ctx.Data["LabelTemplates"] = models.LabelTemplates
|
||||||
|
ctx.HTML(200, tplLabels)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitializeLabels init labels for a repository
|
||||||
|
func InitializeLabels(ctx *context.Context, form auth.InitializeLabelsForm) {
|
||||||
|
if ctx.HasError() {
|
||||||
|
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
list, err := models.GetLabelTemplateFile(form.TemplateName)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Flash.Error(ctx.Tr("repo.issues.label_templates.fail_to_load_file", form.TemplateName, err))
|
||||||
|
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
labels := make([]*models.Label, len(list))
|
||||||
|
for i := 0; i < len(list); i++ {
|
||||||
|
labels[i] = &models.Label{
|
||||||
|
RepoID: ctx.Repo.Repository.ID,
|
||||||
|
Name: list[i][0],
|
||||||
|
Color: list[i][1],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := models.NewLabels(labels...); err != nil {
|
||||||
|
ctx.Handle(500, "NewLabels", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetrieveLabels find all the labels of a repository
|
||||||
|
func RetrieveLabels(ctx *context.Context) {
|
||||||
|
labels, err := models.GetLabelsByRepoID(ctx.Repo.Repository.ID, ctx.Query("sort"))
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(500, "RetrieveLabels.GetLabels", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, l := range labels {
|
||||||
|
l.CalOpenIssues()
|
||||||
|
}
|
||||||
|
ctx.Data["Labels"] = labels
|
||||||
|
ctx.Data["NumLabels"] = len(labels)
|
||||||
|
ctx.Data["SortType"] = ctx.Query("sort")
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLabel create new label for repository
|
||||||
|
func NewLabel(ctx *context.Context, form auth.CreateLabelForm) {
|
||||||
|
ctx.Data["Title"] = ctx.Tr("repo.labels")
|
||||||
|
ctx.Data["PageIsLabels"] = true
|
||||||
|
|
||||||
|
if ctx.HasError() {
|
||||||
|
ctx.Flash.Error(ctx.Data["ErrorMsg"].(string))
|
||||||
|
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l := &models.Label{
|
||||||
|
RepoID: ctx.Repo.Repository.ID,
|
||||||
|
Name: form.Title,
|
||||||
|
Color: form.Color,
|
||||||
|
}
|
||||||
|
if err := models.NewLabels(l); err != nil {
|
||||||
|
ctx.Handle(500, "NewLabel", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateLabel update a label's name and color
|
||||||
|
func UpdateLabel(ctx *context.Context, form auth.CreateLabelForm) {
|
||||||
|
l, err := models.GetLabelByID(form.ID)
|
||||||
|
if err != nil {
|
||||||
|
switch {
|
||||||
|
case models.IsErrLabelNotExist(err):
|
||||||
|
ctx.Error(404)
|
||||||
|
default:
|
||||||
|
ctx.Handle(500, "UpdateLabel", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Name = form.Title
|
||||||
|
l.Color = form.Color
|
||||||
|
if err := models.UpdateLabel(l); err != nil {
|
||||||
|
ctx.Handle(500, "UpdateLabel", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteLabel delete a label
|
||||||
|
func DeleteLabel(ctx *context.Context) {
|
||||||
|
if err := models.DeleteLabel(ctx.Repo.Repository.ID, ctx.QueryInt64("id")); err != nil {
|
||||||
|
ctx.Flash.Error("DeleteLabel: " + err.Error())
|
||||||
|
} else {
|
||||||
|
ctx.Flash.Success(ctx.Tr("repo.issues.label_deletion_success"))
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(200, map[string]interface{}{
|
||||||
|
"redirect": ctx.Repo.RepoLink + "/labels",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateIssueLabel change issue's labels
|
||||||
|
func UpdateIssueLabel(ctx *context.Context) {
|
||||||
|
issue := getActionIssue(ctx)
|
||||||
|
if ctx.Written() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.Query("action") == "clear" {
|
||||||
|
if err := issue.ClearLabels(ctx.User); err != nil {
|
||||||
|
ctx.Handle(500, "ClearLabels", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
isAttach := ctx.Query("action") == "attach"
|
||||||
|
label, err := models.GetLabelByID(ctx.QueryInt64("id"))
|
||||||
|
if err != nil {
|
||||||
|
if models.IsErrLabelNotExist(err) {
|
||||||
|
ctx.Error(404, "GetLabelByID")
|
||||||
|
} else {
|
||||||
|
ctx.Handle(500, "GetLabelByID", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if isAttach && !issue.HasLabel(label.ID) {
|
||||||
|
if err = issue.AddLabel(ctx.User, label); err != nil {
|
||||||
|
ctx.Handle(500, "AddLabel", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if !isAttach && issue.HasLabel(label.ID) {
|
||||||
|
if err = issue.RemoveLabel(ctx.User, label); err != nil {
|
||||||
|
ctx.Handle(500, "RemoveLabel", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(200, map[string]interface{}{
|
||||||
|
"ok": true,
|
||||||
|
})
|
||||||
|
}
|
|
@ -58,7 +58,7 @@
|
||||||
{{range .Issue.Comments}}
|
{{range .Issue.Comments}}
|
||||||
{{ $createdStr:= TimeSince .Created $.Lang }}
|
{{ $createdStr:= TimeSince .Created $.Lang }}
|
||||||
|
|
||||||
<!-- 0 = COMMENT, 1 = REOPEN, 2 = CLOSE, 3 = ISSUE_REF, 4 = COMMIT_REF, 5 = COMMENT_REF, 6 = PULL_REF -->
|
<!-- 0 = COMMENT, 1 = REOPEN, 2 = CLOSE, 3 = ISSUE_REF, 4 = COMMIT_REF, 5 = COMMENT_REF, 6 = PULL_REF, 7 = COMMENT_LABEL -->
|
||||||
{{if eq .Type 0}}
|
{{if eq .Type 0}}
|
||||||
<div class="comment" id="{{.HashTag}}">
|
<div class="comment" id="{{.HashTag}}">
|
||||||
<a class="avatar" {{if gt .Poster.ID 0}}href="{{.Poster.HomeLink}}"{{end}}>
|
<a class="avatar" {{if gt .Poster.ID 0}}href="{{.Poster.HomeLink}}"{{end}}>
|
||||||
|
@ -144,6 +144,15 @@
|
||||||
<span class="text grey">{{.Content | Str2html}}</span>
|
<span class="text grey">{{.Content | Str2html}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{else if eq .Type 7}}
|
||||||
|
<div class="event">
|
||||||
|
<span class="octicon octicon-primitive-dot"></span>
|
||||||
|
<a class="ui avatar image" href="{{.Poster.HomeLink}}">
|
||||||
|
<img src="{{.Poster.RelAvatarLink}}">
|
||||||
|
</a>
|
||||||
|
<span class="text grey"><a href="{{.Poster.HomeLink}}">{{.Poster.Name}}</a>
|
||||||
|
{{if .Content}}{{$.i18n.Tr "repo.issues.add_label_at" .Label.ForegroundColor .Label.Color .Label.Name $createdStr | Safe}}{{else}}{{$.i18n.Tr "repo.issues.remove_label_at" .Label.ForegroundColor .Label.Color .Label.Name $createdStr | Safe}}{{end}}</span>
|
||||||
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
Loading…
Reference in a new issue