UI: basic label list

- create new label
forgejo
Unknwon 9 years ago
parent 86dbda0b42
commit ac95f6d50f

1
.gitignore vendored

@ -29,7 +29,6 @@ profile/
__pycache__ __pycache__
*.pem *.pem
output* output*
config.codekit
.brackets.json .brackets.json
docker/fig.yml docker/fig.yml
docker/docker/Dockerfile docker/docker/Dockerfile

@ -80,7 +80,7 @@ func checkVersion() {
// Check dependency version. // Check dependency version.
checkers := []VerChecker{ checkers := []VerChecker{
{"github.com/Unknwon/macaron", macaron.Version, "0.5.4"}, {"github.com/Unknwon/macaron", macaron.Version, "0.5.4"},
{"github.com/macaron-contrib/binding", binding.Version, "0.0.6"}, {"github.com/macaron-contrib/binding", binding.Version, "0.1.0"},
{"github.com/macaron-contrib/cache", cache.Version, "0.0.7"}, {"github.com/macaron-contrib/cache", cache.Version, "0.0.7"},
{"github.com/macaron-contrib/csrf", csrf.Version, "0.0.3"}, {"github.com/macaron-contrib/csrf", csrf.Version, "0.0.3"},
{"github.com/macaron-contrib/i18n", i18n.Version, "0.0.7"}, {"github.com/macaron-contrib/i18n", i18n.Version, "0.0.7"},
@ -442,15 +442,14 @@ func runWeb(ctx *cli.Context) {
m.Group("/:username/:reponame", func() { m.Group("/:username/:reponame", func() {
m.Get("/releases", middleware.RepoRef(), repo.Releases) m.Get("/releases", middleware.RepoRef(), repo.Releases)
m.Get("/issues", repo.Issues) m.Get("/issues", repo.RetrieveLabels, repo.Issues)
m.Get("/issues/:index", repo.ViewIssue) m.Get("/issues/:index", repo.ViewIssue)
m.Get("/labels/", repo.RetrieveLabels, repo.Labels)
m.Get("/milestones", repo.Milestones) m.Get("/milestones", repo.Milestones)
m.Get("/pulls", repo.Pulls) m.Get("/pulls", repo.Pulls)
m.Get("/branches", repo.Branches) m.Get("/branches", repo.Branches)
m.Get("/archive/*", repo.Download) m.Get("/archive/*", repo.Download)
m.Get("/issues2/", repo.Issues2)
m.Get("/pulls2/", repo.PullRequest2) m.Get("/pulls2/", repo.PullRequest2)
m.Get("/labels2/", repo.Labels2)
m.Get("/milestone2/", repo.Milestones2) m.Get("/milestone2/", repo.Milestones2)
m.Group("", func() { m.Group("", func() {

@ -159,6 +159,7 @@ AdminEmail = Admin E-mail
require_error = ` cannot be empty.` require_error = ` cannot be empty.`
alpha_dash_error = ` must be valid alpha or numeric or dash(-_) characters.` alpha_dash_error = ` must be valid alpha or numeric or dash(-_) characters.`
alpha_dash_dot_error = ` must be valid alpha or numeric or dash(-_) or dot characters.` alpha_dash_dot_error = ` must be valid alpha or numeric or dash(-_) or dot characters.`
size_error = ` must be size %s.`
min_size_error = ` must contain at least %s characters.` min_size_error = ` must contain at least %s characters.`
max_size_error = ` must contain at most %s characters.` max_size_error = ` must contain at most %s characters.`
email_error = ` is not a valid e-mail address.` email_error = ` is not a valid e-mail address.`
@ -358,6 +359,8 @@ commits.older = Older
commits.newer = Newer commits.newer = Newer
issues.new = New Issue issues.new = New Issue
issues.new_label = New Label
issues.new_label_placeholder = Label name...
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
@ -369,6 +372,12 @@ issues.filter_type.assigned_to_you = Assigned to you
issues.filter_type.created_by_you = Created by you issues.filter_type.created_by_you = Created by you
issues.filter_type.mentioning_you = Mentioning you issues.filter_type.mentioning_you = Mentioning you
issues.opened_by = opened %s by <a href="/%[2]s">%[2]s</a> issues.opened_by = opened %s by <a href="/%[2]s">%[2]s</a>
issues.label_title = Label name
issues.label_color = Label color
issues.label_count = %d labels
issues.label_open_issues = %d open issues
issues.label_edit = Edit
issues.label_delete = Delete
issues.previous = Previous Page issues.previous = Previous Page
issues.next = Next Page issues.next = Next Page

File diff suppressed because it is too large Load Diff

@ -17,7 +17,7 @@ import (
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )
const APP_VER = "0.6.1.0724 Beta" const APP_VER = "0.6.2.0724 Beta"
func init() { func init() {
runtime.GOMAXPROCS(runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU())

@ -153,7 +153,7 @@ func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, com
url := fmt.Sprintf("%s/%s/%s/commit/%s", setting.AppSubUrl, repoUserName, repoName, c.Sha1) url := fmt.Sprintf("%s/%s/%s/commit/%s", setting.AppSubUrl, repoUserName, repoName, c.Sha1)
message := fmt.Sprintf(`<a href="%s">%s</a>`, url, c.Message) message := fmt.Sprintf(`<a href="%s">%s</a>`, url, c.Message)
if _, err = CreateComment(userId, issue.RepoId, issue.Id, 0, 0, COMMENT_TYPE_COMMIT, message, nil); err != nil { if _, err = CreateComment(userId, issue.RepoId, issue.ID, 0, 0, COMMENT_TYPE_COMMIT, message, nil); err != nil {
return err return err
} }
} }
@ -202,7 +202,7 @@ func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, com
if err = UpdateIssue(issue); err != nil { if err = UpdateIssue(issue); err != nil {
return err return err
} else if err = UpdateIssueUserPairsByStatus(issue.Id, issue.IsClosed); err != nil { } else if err = UpdateIssueUserPairsByStatus(issue.ID, issue.IsClosed); err != nil {
return err return err
} }
@ -211,7 +211,7 @@ func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, com
} }
// If commit happened in the referenced repository, it means the issue can be closed. // If commit happened in the referenced repository, it means the issue can be closed.
if _, err = CreateComment(userId, repoId, issue.Id, 0, 0, COMMENT_TYPE_CLOSE, "", nil); err != nil { if _, err = CreateComment(userId, repoId, issue.ID, 0, 0, COMMENT_TYPE_CLOSE, "", nil); err != nil {
return err return err
} }
} }
@ -261,7 +261,7 @@ func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, com
if err = UpdateIssue(issue); err != nil { if err = UpdateIssue(issue); err != nil {
return err return err
} else if err = UpdateIssueUserPairsByStatus(issue.Id, issue.IsClosed); err != nil { } else if err = UpdateIssueUserPairsByStatus(issue.ID, issue.IsClosed); err != nil {
return err return err
} }
@ -270,7 +270,7 @@ func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, com
} }
// If commit happened in the referenced repository, it means the issue can be closed. // If commit happened in the referenced repository, it means the issue can be closed.
if _, err = CreateComment(userId, repoId, issue.Id, 0, 0, COMMENT_TYPE_REOPEN, "", nil); err != nil { if _, err = CreateComment(userId, repoId, issue.ID, 0, 0, COMMENT_TYPE_REOPEN, "", nil); err != nil {
return err return err
} }
} }

@ -32,7 +32,7 @@ var (
// Issue represents an issue or pull request of repository. // Issue represents an issue or pull request of repository.
type Issue struct { type Issue struct {
Id int64 ID int64 `xorm:"pk autoincr"`
RepoId int64 `xorm:"INDEX"` RepoId int64 `xorm:"INDEX"`
Index int64 // Index in one repository. Index int64 // Index in one repository.
Name string Name string
@ -100,15 +100,15 @@ func (i *Issue) GetAssignee() (err error) {
} }
func (i *Issue) Attachments() []*Attachment { func (i *Issue) Attachments() []*Attachment {
a, _ := GetAttachmentsForIssue(i.Id) a, _ := GetAttachmentsForIssue(i.ID)
return a return a
} }
func (i *Issue) AfterDelete() { func (i *Issue) AfterDelete() {
_, err := DeleteAttachmentsByIssue(i.Id, true) _, err := DeleteAttachmentsByIssue(i.ID, true)
if err != nil { if err != nil {
log.Info("Could not delete files for issue #%d: %s", i.Id, err) log.Info("Could not delete files for issue #%d: %s", i.ID, err)
} }
} }
@ -175,7 +175,7 @@ func GetIssueByIndex(rid, index int64) (*Issue, error) {
// GetIssueById returns an issue by ID. // GetIssueById returns an issue by ID.
func GetIssueById(id int64) (*Issue, error) { func GetIssueById(id int64) (*Issue, error) {
issue := &Issue{Id: id} issue := &Issue{ID: id}
has, err := x.Get(issue) has, err := x.Get(issue)
if err != nil { if err != nil {
return nil, err return nil, err
@ -456,7 +456,7 @@ func GetUserIssueStats(uid int64, filterMode int) *IssueStats {
// UpdateIssue updates information of issue. // UpdateIssue updates information of issue.
func UpdateIssue(issue *Issue) error { func UpdateIssue(issue *Issue) error {
_, err := x.Id(issue.Id).AllCols().Update(issue) _, err := x.Id(issue.ID).AllCols().Update(issue)
if err != nil { if err != nil {
return err return err
@ -526,7 +526,7 @@ func UpdateIssueUserPairsByMentions(uids []int64, iid int64) error {
// Label represents a label of repository for issues. // Label represents a label of repository for issues.
type Label struct { type Label struct {
Id int64 ID int64 `xorm:"pk autoincr"`
RepoId int64 `xorm:"INDEX"` RepoId int64 `xorm:"INDEX"`
Name string Name string
Color string `xorm:"VARCHAR(7)"` Color string `xorm:"VARCHAR(7)"`
@ -553,7 +553,7 @@ func GetLabelById(id int64) (*Label, error) {
return nil, ErrLabelNotExist return nil, ErrLabelNotExist
} }
l := &Label{Id: id} l := &Label{ID: id}
has, err := x.Get(l) has, err := x.Get(l)
if err != nil { if err != nil {
return nil, err return nil, err
@ -572,7 +572,7 @@ func GetLabels(repoId int64) ([]*Label, error) {
// UpdateLabel updates label information. // UpdateLabel updates label information.
func UpdateLabel(l *Label) error { func UpdateLabel(l *Label) error {
_, err := x.Id(l.Id).AllCols().Update(l) _, err := x.Id(l.ID).AllCols().Update(l)
return err return err
} }
@ -600,7 +600,7 @@ func DeleteLabel(repoId int64, strId string) error {
for _, issue := range issues { for _, issue := range issues {
issue.LabelIds = strings.Replace(issue.LabelIds, "$"+strId+"|", "", -1) issue.LabelIds = strings.Replace(issue.LabelIds, "$"+strId+"|", "", -1)
if _, err = sess.Id(issue.Id).AllCols().Update(issue); err != nil { if _, err = sess.Id(issue.ID).AllCols().Update(issue); err != nil {
sess.Rollback() sess.Rollback()
return err return err
} }
@ -788,7 +788,7 @@ func ChangeMilestoneAssign(oldMid, mid int64, issue *Issue) (err error) {
} }
rawSql := "UPDATE `issue_user` SET milestone_id = 0 WHERE issue_id = ?" rawSql := "UPDATE `issue_user` SET milestone_id = 0 WHERE issue_id = ?"
if _, err = sess.Exec(rawSql, issue.Id); err != nil { if _, err = sess.Exec(rawSql, issue.ID); err != nil {
sess.Rollback() sess.Rollback()
return err return err
} }
@ -816,7 +816,7 @@ func ChangeMilestoneAssign(oldMid, mid int64, issue *Issue) (err error) {
} }
rawSql := "UPDATE `issue_user` SET milestone_id = ? WHERE issue_id = ?" rawSql := "UPDATE `issue_user` SET milestone_id = ? WHERE issue_id = ?"
if _, err = sess.Exec(rawSql, m.Id, issue.Id); err != nil { if _, err = sess.Exec(rawSql, m.Id, issue.ID); err != nil {
sess.Rollback() sess.Rollback()
return err return err
} }

@ -876,7 +876,7 @@ func DeleteRepository(uid, repoID int64, userName string) error {
return err return err
} }
for i := range issues { for i := range issues {
if _, err = sess.Delete(&Comment{IssueId: issues[i].Id}); err != nil { if _, err = sess.Delete(&Comment{IssueId: issues[i].ID}); err != nil {
return err return err
} }
} }

@ -171,12 +171,16 @@ func AssignForm(form interface{}, data map[string]interface{}) {
func getSize(field reflect.StructField, prefix string) string { func getSize(field reflect.StructField, prefix string) string {
for _, rule := range strings.Split(field.Tag.Get("binding"), ";") { for _, rule := range strings.Split(field.Tag.Get("binding"), ";") {
if strings.HasPrefix(rule, prefix) { if strings.HasPrefix(rule, prefix) {
return rule[8 : len(rule)-1] return rule[len(prefix) : len(rule)-1]
} }
} }
return "" return ""
} }
func GetSize(field reflect.StructField) string {
return getSize(field, "Size(")
}
func GetMinSize(field reflect.StructField) string { func GetMinSize(field reflect.StructField) string {
return getSize(field, "MinSize(") return getSize(field, "MinSize(")
} }
@ -227,6 +231,8 @@ func validate(errs binding.Errors, data map[string]interface{}, f Form, l macaro
data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_error") data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_error")
case binding.ERR_ALPHA_DASH_DOT: case binding.ERR_ALPHA_DASH_DOT:
data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_dot_error") data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_dot_error")
case binding.ERR_SIZE:
data["ErrorMsg"] = trName + l.Tr("form.size_error", GetSize(field))
case binding.ERR_MIN_SIZE: case binding.ERR_MIN_SIZE:
data["ErrorMsg"] = trName + l.Tr("form.min_size_error", GetMinSize(field)) data["ErrorMsg"] = trName + l.Tr("form.min_size_error", GetMinSize(field))
case binding.ERR_MAX_SIZE: case binding.ERR_MAX_SIZE:

@ -134,8 +134,8 @@ func (f *CreateMilestoneForm) Validate(ctx *macaron.Context, errs binding.Errors
// \/ \/ \/ \/ // \/ \/ \/ \/
type CreateLabelForm struct { type CreateLabelForm struct {
Title string `form:"title" binding:"Required;MaxSize(50)"` Title string `binding:"Required;MaxSize(50)" locale:"repo.issues.label_name"`
Color string `form:"color" binding:"Required;Size(7)"` Color string `binding:"Required;Size(7)" locale:"repo.issues.label_color"`
} }
func (f *CreateLabelForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { func (f *CreateLabelForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -32,6 +32,24 @@ function initInstall() {
}); });
}; };
function initRepository(){
if ($('.repository').length == 0) {
return;
}
if ($('.labels').length == 0) {
return;
}
$('.color-picker').each( function() {
$(this).minicolors();
});
$('.precolors .color').click(function(){
var color_hex = $(this).data('color-hex')
$('.color-picker').val(color_hex);
$('.minicolors-swatch-color').css("background-color", color_hex);
});
};
$(document).ready(function () { $(document).ready(function () {
// Semantic UI modules. // Semantic UI modules.
$('.dropdown').dropdown(); $('.dropdown').dropdown();
@ -46,4 +64,5 @@ $(document).ready(function () {
$('.poping.up').popup(); $('.poping.up').popup();
initInstall(); initInstall();
initRepository();
}); });

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

@ -1 +0,0 @@
$(document).ready(function(){$(".dropdown").dropdown({transition:"slide up"})});

@ -41,6 +41,42 @@
.navbar { .navbar {
height: 60px; height: 60px;
padding-top: 20px; padding-top: 20px;
.ui.secondary.menu .item {
margin-left: -10px;
margin-top: -7px;
&>.input {
.new-label-input,
.color-picker {
background-color: white;
border: 1px solid rgba(0,0,0,.15);
}
}
.new-label-input {
width: 150px;
}
.color-picker {
height: 35px;
width: auto;
padding-left: 30px;
}
.minicolors-swatch.minicolors-sprite {
top: 10px;
left: 10px;
width: 15px;
height: 15px;
}
&.precolors {
padding-left: 0;
padding-right: 0;
margin-right: 10px;
width: 120px;
.color {
float: left;
width: 15px;
height: 15px;
}
}
}
} }
.filter.menu .label.color { .filter.menu .label.color {
padding: 0 8px; padding: 0 8px;
@ -50,9 +86,10 @@
left: auto!important; left: auto!important;
} }
.issue.list { .issue.list {
clear: both;
list-style: none; list-style: none;
font-size: 13px; font-size: 13px;
padding-top: 45px; padding-top: 15px;
.item { .item {
padding-top: 15px; padding-top: 15px;
padding-bottom: 10px; padding-bottom: 10px;
@ -79,4 +116,25 @@
padding-top: 15px; padding-top: 15px;
} }
} }
.label.list {
clear: both;
padding-top: 15px;
.item {
padding-top: 10px;
padding-bottom: 10px;
border-bottom: 1px dashed #AAA;
a {
font-size: 15px;
padding-top: 5px;
padding-right: 10px;
color: #666;
&:hover {
color: #000;
}
&.open-issues {
margin-right: 30px;
}
}
}
}
} }

@ -30,6 +30,8 @@ const (
ISSUE_CREATE base.TplName = "repo/issue/create" ISSUE_CREATE base.TplName = "repo/issue/create"
ISSUE_VIEW base.TplName = "repo/issue/view" ISSUE_VIEW base.TplName = "repo/issue/view"
LABELS base.TplName = "repo/issue/labels"
MILESTONE base.TplName = "repo/issue/milestone" MILESTONE base.TplName = "repo/issue/milestone"
MILESTONE_NEW base.TplName = "repo/issue/milestone_new" MILESTONE_NEW base.TplName = "repo/issue/milestone_new"
MILESTONE_EDIT base.TplName = "repo/issue/milestone_edit" MILESTONE_EDIT base.TplName = "repo/issue/milestone_edit"
@ -40,6 +42,19 @@ var (
ErrTooManyFiles = errors.New("Maximum number of files to upload exceeded") ErrTooManyFiles = errors.New("Maximum number of files to upload exceeded")
) )
func RetrieveLabels(ctx *middleware.Context) {
labels, err := models.GetLabels(ctx.Repo.Repository.Id)
if err != nil {
ctx.Handle(500, "RetrieveLabels.GetLabels: %v", err)
return
}
for _, l := range labels {
l.CalOpenIssues()
}
ctx.Data["Labels"] = labels
ctx.Data["NumLabels"] = len(labels)
}
func Issues(ctx *middleware.Context) { func Issues(ctx *middleware.Context) {
ctx.Data["Title"] = ctx.Tr("repo.issues") ctx.Data["Title"] = ctx.Tr("repo.issues")
ctx.Data["PageIsIssueList"] = true ctx.Data["PageIsIssueList"] = true
@ -85,17 +100,6 @@ func Issues(ctx *middleware.Context) {
mid = mile.Id mid = mile.Id
} }
selectLabels := ctx.Query("labels")
labels, err := models.GetLabels(repo.Id)
if err != nil {
ctx.Handle(500, "GetLabels: %v", err)
return
}
for _, l := range labels {
l.CalOpenIssues()
}
ctx.Data["Labels"] = labels
page := ctx.QueryInt("page") page := ctx.QueryInt("page")
if page <= 1 { if page <= 1 {
page = 1 page = 1
@ -107,6 +111,8 @@ func Issues(ctx *middleware.Context) {
ctx.Data["NextPage"] = page + 1 ctx.Data["NextPage"] = page + 1
} }
selectLabels := ctx.Query("labels")
// Get issues. // Get issues.
issues, err := models.GetIssues(assigneeId, repo.Id, posterId, mid, page, issues, err := models.GetIssues(assigneeId, repo.Id, posterId, mid, page,
isShowClosed, selectLabels, ctx.Query("sortType")) isShowClosed, selectLabels, ctx.Query("sortType"))
@ -125,24 +131,26 @@ func Issues(ctx *middleware.Context) {
// Get posters. // Get posters.
for i := range issues { for i := range issues {
if err = issues[i].GetLabels(); err != nil { if err = issues[i].GetLabels(); err != nil {
ctx.Handle(500, "GetLabels", fmt.Errorf("[#%d]%v", issues[i].Id, err)) ctx.Handle(500, "GetLabels", fmt.Errorf("[#%d]%v", issues[i].ID, err))
return return
} }
idx := models.PairsContains(pairs, issues[i].Id, ctx.User.Id) if ctx.IsSigned {
idx := models.PairsContains(pairs, issues[i].ID, ctx.User.Id)
if filterMode == models.FM_MENTION && (idx == -1 || !pairs[idx].IsMentioned) { if filterMode == models.FM_MENTION && (idx == -1 || !pairs[idx].IsMentioned) {
continue continue
} }
if idx > -1 { if idx > -1 {
issues[i].IsRead = pairs[idx].IsRead issues[i].IsRead = pairs[idx].IsRead
} else { } else {
issues[i].IsRead = true issues[i].IsRead = true
}
} }
if err = issues[i].GetPoster(); err != nil { if err = issues[i].GetPoster(); err != nil {
ctx.Handle(500, "GetPoster", fmt.Errorf("[#%d]%v", issues[i].Id, err)) ctx.Handle(500, "GetPoster", fmt.Errorf("[#%d]%v", issues[i].ID, err))
return return
} }
} }
@ -257,14 +265,14 @@ func CreateIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) {
if err := models.NewIssue(issue); err != nil { if err := models.NewIssue(issue); err != nil {
send(500, nil, err) send(500, nil, err)
return return
} else if err := models.NewIssueUserPairs(ctx.Repo.Repository, issue.Id, ctx.Repo.Owner.Id, } else if err := models.NewIssueUserPairs(ctx.Repo.Repository, issue.ID, ctx.Repo.Owner.Id,
ctx.User.Id, form.AssigneeId); err != nil { ctx.User.Id, form.AssigneeId); err != nil {
send(500, nil, err) send(500, nil, err)
return return
} }
if setting.AttachmentEnabled { if setting.AttachmentEnabled {
uploadFiles(ctx, issue.Id, 0) uploadFiles(ctx, issue.ID, 0)
} }
// Update mentions. // Update mentions.
@ -274,7 +282,7 @@ func CreateIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) {
ms[i] = ms[i][1:] ms[i] = ms[i][1:]
} }
if err := models.UpdateMentions(ms, issue.Id); err != nil { if err := models.UpdateMentions(ms, issue.ID); err != nil {
send(500, nil, err) send(500, nil, err)
return return
} }
@ -321,7 +329,7 @@ func CreateIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) {
return return
} }
} }
log.Trace("%d Issue created: %d", ctx.Repo.Repository.Id, issue.Id) log.Trace("%d Issue created: %d", ctx.Repo.Repository.Id, issue.ID)
send(200, fmt.Sprintf("%s/%s/%s/issues/%d", setting.AppSubUrl, ctx.Params(":username"), ctx.Params(":reponame"), issue.Index), nil) send(200, fmt.Sprintf("%s/%s/%s/issues/%d", setting.AppSubUrl, ctx.Params(":username"), ctx.Params(":reponame"), issue.Index), nil)
} }
@ -329,7 +337,7 @@ func CreateIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) {
func checkLabels(labels, allLabels []*models.Label) { func checkLabels(labels, allLabels []*models.Label) {
for _, l := range labels { for _, l := range labels {
for _, l2 := range allLabels { for _, l2 := range allLabels {
if l.Id == l2.Id { if l.ID == l2.ID {
l2.IsChecked = true l2.IsChecked = true
break break
} }
@ -403,7 +411,7 @@ func ViewIssue(ctx *middleware.Context) {
if ctx.IsSigned { if ctx.IsSigned {
// Update issue-user. // Update issue-user.
if err = models.UpdateIssueUserPairByRead(ctx.User.Id, issue.Id); err != nil { if err = models.UpdateIssueUserPairByRead(ctx.User.Id, issue.ID); err != nil {
ctx.Handle(500, "issue.ViewIssue(UpdateIssueUserPairByRead): %v", err) ctx.Handle(500, "issue.ViewIssue(UpdateIssueUserPairByRead): %v", err)
return return
} }
@ -420,7 +428,7 @@ func ViewIssue(ctx *middleware.Context) {
issue.RenderedContent = string(base.RenderMarkdown([]byte(issue.Content), ctx.Repo.RepoLink)) issue.RenderedContent = string(base.RenderMarkdown([]byte(issue.Content), ctx.Repo.RepoLink))
// Get comments. // Get comments.
comments, err := models.GetIssueComments(issue.Id) comments, err := models.GetIssueComments(issue.ID)
if err != nil { if err != nil {
ctx.Handle(500, "issue.ViewIssue(GetIssueComments): %v", err) ctx.Handle(500, "issue.ViewIssue(GetIssueComments): %v", err)
return return
@ -642,7 +650,7 @@ func UpdateAssignee(ctx *middleware.Context) {
aid := com.StrTo(ctx.Query("assigneeid")).MustInt64() aid := com.StrTo(ctx.Query("assigneeid")).MustInt64()
// Not check for invalid assignee id and give responsibility to owners. // Not check for invalid assignee id and give responsibility to owners.
issue.AssigneeId = aid issue.AssigneeId = aid
if err = models.UpdateIssueUserPairByAssignee(aid, issue.Id); err != nil { if err = models.UpdateIssueUserPairByAssignee(aid, issue.ID); err != nil {
ctx.Handle(500, "UpdateIssueUserPairByAssignee: %v", err) ctx.Handle(500, "UpdateIssueUserPairByAssignee: %v", err)
return return
} else if err = models.UpdateIssue(issue); err != nil { } else if err = models.UpdateIssue(issue); err != nil {
@ -774,7 +782,7 @@ func Comment(ctx *middleware.Context) {
if err = models.UpdateIssue(issue); err != nil { if err = models.UpdateIssue(issue); err != nil {
send(500, nil, err) send(500, nil, err)
return return
} else if err = models.UpdateIssueUserPairsByStatus(issue.Id, issue.IsClosed); err != nil { } else if err = models.UpdateIssueUserPairsByStatus(issue.ID, issue.IsClosed); err != nil {
send(500, nil, err) send(500, nil, err)
return return
} }
@ -809,11 +817,11 @@ func Comment(ctx *middleware.Context) {
cmtType = models.COMMENT_TYPE_REOPEN cmtType = models.COMMENT_TYPE_REOPEN
} }
if _, err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, cmtType, "", nil); err != nil { if _, err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.ID, 0, 0, cmtType, "", nil); err != nil {
send(200, nil, err) send(200, nil, err)
return return
} }
log.Trace("%s Issue(%d) status changed: %v", ctx.Req.RequestURI, issue.Id, !issue.IsClosed) log.Trace("%s Issue(%d) status changed: %v", ctx.Req.RequestURI, issue.ID, !issue.IsClosed)
} }
} }
@ -825,7 +833,7 @@ func Comment(ctx *middleware.Context) {
if len(content) > 0 || len(ctx.Req.MultipartForm.File["attachments"]) > 0 { if len(content) > 0 || len(ctx.Req.MultipartForm.File["attachments"]) > 0 {
switch ctx.Params(":action") { switch ctx.Params(":action") {
case "new": case "new":
if comment, err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, models.COMMENT_TYPE_COMMENT, content, nil); err != nil { if comment, err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.ID, 0, 0, models.COMMENT_TYPE_COMMENT, content, nil); err != nil {
send(500, nil, err) send(500, nil, err)
return return
} }
@ -837,13 +845,13 @@ func Comment(ctx *middleware.Context) {
ms[i] = ms[i][1:] ms[i] = ms[i][1:]
} }
if err := models.UpdateMentions(ms, issue.Id); err != nil { if err := models.UpdateMentions(ms, issue.ID); err != nil {
send(500, nil, err) send(500, nil, err)
return return
} }
} }
log.Trace("%s Comment created: %d", ctx.Req.RequestURI, issue.Id) log.Trace("%s Comment created: %d", ctx.Req.RequestURI, issue.ID)
default: default:
ctx.Handle(404, "issue.Comment", err) ctx.Handle(404, "issue.Comment", err)
return return
@ -851,7 +859,7 @@ func Comment(ctx *middleware.Context) {
} }
if comment != nil { if comment != nil {
uploadFiles(ctx, issue.Id, comment.Id) uploadFiles(ctx, issue.ID, comment.Id)
} }
// Notify watchers. // Notify watchers.
@ -899,9 +907,19 @@ func Comment(ctx *middleware.Context) {
send(200, fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, index), nil) send(200, fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, index), nil)
} }
func Labels(ctx *middleware.Context) {
ctx.Data["Title"] = ctx.Tr("repo.labels")
ctx.Data["PageIsLabels"] = true
ctx.HTML(200, LABELS)
}
func NewLabel(ctx *middleware.Context, form auth.CreateLabelForm) { func NewLabel(ctx *middleware.Context, form auth.CreateLabelForm) {
ctx.Data["Title"] = ctx.Tr("repo.labels")
ctx.Data["PageIsLabels"] = true
if ctx.HasError() { if ctx.HasError() {
Issues(ctx) ctx.Flash.Error(ctx.Data["ErrorMsg"].(string))
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
return return
} }
@ -911,10 +929,10 @@ func NewLabel(ctx *middleware.Context, form auth.CreateLabelForm) {
Color: form.Color, Color: form.Color,
} }
if err := models.NewLabel(l); err != nil { if err := models.NewLabel(l); err != nil {
ctx.Handle(500, "issue.NewLabel(NewLabel)", err) ctx.Handle(500, "NewLabel", err)
return return
} }
ctx.Redirect(ctx.Repo.RepoLink + "/issues") ctx.Redirect(ctx.Repo.RepoLink + "/labels")
} }
func UpdateLabel(ctx *middleware.Context, form auth.CreateLabelForm) { func UpdateLabel(ctx *middleware.Context, form auth.CreateLabelForm) {
@ -925,7 +943,7 @@ func UpdateLabel(ctx *middleware.Context, form auth.CreateLabelForm) {
} }
l := &models.Label{ l := &models.Label{
Id: id, ID: id,
Name: form.Title, Name: form.Title,
Color: form.Color, Color: form.Color,
} }
@ -1151,20 +1169,10 @@ func IssueGetAttachment(ctx *middleware.Context) {
ctx.ServeFile(attachment.Path, "\""+attachment.Name+"\"") ctx.ServeFile(attachment.Path, "\""+attachment.Name+"\"")
} }
// testing route handler for new issue ui page
// todo : move to Issue() function
func Issues2(ctx *middleware.Context) {
ctx.HTML(200, "repo/issue2/list")
}
func PullRequest2(ctx *middleware.Context) { func PullRequest2(ctx *middleware.Context) {
ctx.HTML(200, "repo/pr2/list") ctx.HTML(200, "repo/pr2/list")
} }
func Labels2(ctx *middleware.Context) {
ctx.HTML(200, "repo/issue2/labels")
}
func Milestones2(ctx *middleware.Context) { func Milestones2(ctx *middleware.Context) {
ctx.HTML(200, "repo/milestone2/list") ctx.HTML(200, "repo/milestone2/list")
} }

@ -1 +1 @@
0.6.1.0724 Beta 0.6.2.0724 Beta

@ -29,6 +29,12 @@
<script src="{{AppSubUrl}}/js/semantic.min.js?v={{AppVer}}"></script> <script src="{{AppSubUrl}}/js/semantic.min.js?v={{AppVer}}"></script>
<script src="{{AppSubUrl}}/js/gogs.js?v={{AppVer}}"></script> <script src="{{AppSubUrl}}/js/gogs.js?v={{AppVer}}"></script>
<!-- Third-party libraries -->
{{if .PageIsLabels}}
<link rel="stylesheet" href="{{AppSubUrl}}/css/jquery.minicolors.css?v={{AppVer}}">
<script src="{{AppSubUrl}}/js/libs/jquery.minicolors.min.js?v={{AppVer}}"></script>
{{end}}
<title>{{if .Title}}{{.Title}} - {{end}}{{AppName}}</title> <title>{{if .Title}}{{.Title}} - {{end}}{{AppName}}</title>
</head> </head>
<body> <body>

@ -0,0 +1,5 @@
{{if .Flash}}
<div class="sixteen wide center aligned centered column">
{{template "base/alert" .}}
</div>
{{end}}

@ -0,0 +1,64 @@
{{template "base/head" .}}
<div class="repository labels">
{{template "repo/header" .}}
<div class="ui middle page grid body">
<div class="navbar">
{{template "repo/issue/navbar" .}}
{{if .IsRepositoryAdmin}}
<form class="ui right form" action="{{$.RepoLink}}/labels/new" method="post">
{{.CsrfTokenHtml}}
<div class="ui right floated secondary menu">
<div class="item">
<div class="ui large input">
<input class="new-label-input" name="title" placeholder="{{.i18n.Tr "repo.issues.new_label_placeholder"}}" required>
</div>
</div>
<div class="item">
<div class="ui large input">
<input class="color-picker" name="color" value="#70c24a" required>
</div>
</div>
<div class="item precolors">
<a class="color" style="background-color:#e11d21" data-color-hex="#e11d21"></a>
<a class="color" style="background-color:#eb6420" data-color-hex="#eb6420"></a>
<a class="color" style="background-color:#fbca04" data-color-hex="#fbca04"></a>
<a class="color" style="background-color:#009800" data-color-hex="#009800"></a>
<a class="color" style="background-color:#006b75" data-color-hex="#006b75"></a>
<a class="color" style="background-color:#207de5" data-color-hex="#207de5"></a>
<a class="color" style="background-color:#0052cc" data-color-hex="#0052cc"></a>
<a class="color" style="background-color:#53e917" data-color-hex="#53e917"></a>
<a class="color" style="background-color:#f6c6c7" data-color-hex="#f6c6c7"></a>
<a class="color" style="background-color:#fad8c7" data-color-hex="#fad8c7"></a>
<a class="color" style="background-color:#fef2c0" data-color-hex="#fef2c0"></a>
<a class="color" style="background-color:#bfe5bf" data-color-hex="#bfe5bf"></a>
<a class="color" style="background-color:#bfdadc" data-color-hex="#bfdadc"></a>
<a class="color" style="background-color:#c7def8" data-color-hex="#c7def8"></a>
<a class="color" style="background-color:#bfd4f2" data-color-hex="#bfd4f2"></a>
<a class="color" style="background-color:#d4c5f9" data-color-hex="#d4c5f9"></a>
</div>
<button class="ui green button">{{.i18n.Tr "repo.issues.new_label"}}</button>
</div>
</form>
{{end}}
</div>
<div class="ui divider"></div>
{{template "repo/issue/alert" .}}
<div class="ui left">
<div class="ui black label">{{.i18n.Tr "repo.issues.label_count" .NumLabels}}</div>
</div>
<div class="label list">
{{range .Labels}}
<li class="item">
<div class="ui label" style="background-color: {{.Color}}"><i class="octicon octicon-tag"></i> {{.Name}}</div>
{{if $.IsRepositoryAdmin}}
<a class="ui right" href="#"><i class="octicon octicon-x"></i> {{$.i18n.Tr "repo.issues.label_delete"}}</a>
<a class="ui right" href="#"><i class="octicon octicon-pencil"></i> {{$.i18n.Tr "repo.issues.label_edit"}}</a>
{{end}}
<a class="ui right open-issues" href="{{$.RepoLink}}/issues?labels={{.ID}}"><i class="octicon octicon-issue-opened"></i> {{$.i18n.Tr "repo.issues.label_open_issues" .NumOpenIssues}}</a>
</li>
{{end}}
</div>
</div>
</div>
{{template "base/footer" .}}

@ -4,9 +4,11 @@
<div class="ui middle page grid body"> <div class="ui middle page grid body">
<div class="navbar"> <div class="navbar">
{{template "repo/issue/navbar" .}} {{template "repo/issue/navbar" .}}
{{if .IsRepositoryAdmin}}
<div class="ui right floated secondary menu"> <div class="ui right floated secondary menu">
<a class="ui green button" href="{{$.RepoLink}}/issues/new">{{.i18n.Tr "repo.issues.new"}}</a> <a class="ui green button" href="{{$.RepoLink}}/issues/new">{{.i18n.Tr "repo.issues.new"}}</a>
</div> </div>
{{end}}
</div> </div>
<div class="ui divider"></div> <div class="ui divider"></div>
<div class="ui left"> <div class="ui left">
@ -29,7 +31,7 @@
</span> </span>
<div class="menu"> <div class="menu">
{{range .Labels}} {{range .Labels}}
<a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}&labels={{.Id}}"><span class="label color" style="background-color: {{.Color}}"></span> {{.Name}}</a> <a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}"><span class="label color" style="background-color: {{.Color}}"></span> {{.Name}}</a>
{{end}} {{end}}
</div> </div>
</div> </div>
@ -73,7 +75,7 @@
{{range .Issues}} {{range .Issues}}
{{ $timeStr:= TimeSince .Created $.Lang }} {{ $timeStr:= TimeSince .Created $.Lang }}
<li class="item"> <li class="item">
<div class="ui {{if .IsRead}}black{{else}}green{{end}} label">#{{.Id}}</div> <div class="ui {{if .IsRead}}black{{else}}green{{end}} label">#{{.Index}}</div>
<a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Name}}</a> <a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Name}}</a>
{{if .NumComments}}<span class="comment ui right"><i class="octicon octicon-comment"></i> {{.NumComments}}</span>{{end}} {{if .NumComments}}<span class="comment ui right"><i class="octicon octicon-comment"></i> {{.NumComments}}</span>{{end}}
<p class="desc">{{$.i18n.Tr "repo.issues.opened_by" $timeStr .Poster.Name|Str2html}}</p> <p class="desc">{{$.i18n.Tr "repo.issues.opened_by" $timeStr .Poster.Name|Str2html}}</p>

@ -1,7 +1,7 @@
<div class="ui left"> <div class="ui left">
<div class="ui compact menu"> <div class="ui compact menu">
<a class="{{if .PageIsIssueList}}active{{end}} item" href="{{.RepoLink}}/issues">{{.i18n.Tr "repo.issues"}}</a> <a class="{{if .PageIsIssueList}}active{{end}} item" href="{{.RepoLink}}/issues">{{.i18n.Tr "repo.issues"}}</a>
<a class="item" href="{{.RepoLink}}/labels">{{.i18n.Tr "repo.labels"}}</a> <a class="{{if .PageIsLabels}}active{{end}} item" href="{{.RepoLink}}/labels">{{.i18n.Tr "repo.labels"}}</a>
<a class="item" href="{{.RepoLink}}/milestones">{{.i18n.Tr "repo.milestones"}}</a> <a class="item" href="{{.RepoLink}}/milestones">{{.i18n.Tr "repo.milestones"}}</a>
</div> </div>
</div> </div>

@ -3,15 +3,15 @@
{{template "repo/nav" .}} {{template "repo/nav" .}}
{{template "repo/toolbar" .}} {{template "repo/toolbar" .}}
<div id="body" class="container"> <div id="body" class="container">
<div id="issue" data-id="{{.Issue.Id}}"> <div id="issue" data-id="{{.Issue.ID}}">
<div id="issue-{{.Issue.Id}}" class="issue-whole issue-is-opening"> <div id="issue-{{.Issue.ID}}" class="issue-whole issue-is-opening">
<div class="issue-wrap col-md-10"> <div class="issue-wrap col-md-10">
<div class="issue-head clearfix"> <div class="issue-head clearfix">
<div class="number pull-right">#{{.Issue.Index}}</div> <div class="number pull-right">#{{.Issue.Index}}</div>
<a class="author pull-left" href="{{AppSubUrl}}/{{.Issue.Poster.Name}}"><img class="avatar" src="{{.Issue.Poster.AvatarLink}}" alt="" width="30"/></a> <a class="author pull-left" href="{{AppSubUrl}}/{{.Issue.Poster.Name}}"><img class="avatar" src="{{.Issue.Poster.AvatarLink}}" alt="" width="30"/></a>
<h1 class="title pull-left">{{.Issue.Name}}</h1> <h1 class="title pull-left">{{.Issue.Name}}</h1>
<input id="issue-edit-title" class="form-control input-lg pull-left hidden" type="text" value="{{.Issue.Name}}" data-ajax-rel="issue-edit-save" data-ajax-val="val" data-ajax-field="title"/> <input id="issue-edit-title" class="form-control input-lg pull-left hidden" type="text" value="{{.Issue.Name}}" data-ajax-rel="issue-edit-save" data-ajax-val="val" data-ajax-field="title"/>
<input type="hidden" value="{{.Issue.Id}}" data-ajax-rel="issue-edit-save" data-ajax-val="val" data-ajax-field="issue_id"/> <input type="hidden" value="{{.Issue.ID}}" data-ajax-rel="issue-edit-save" data-ajax-val="val" data-ajax-field="issue_id"/>
<p class="info pull-left"> <p class="info pull-left">
{{if .IsIssueOwner}}<a class="btn btn-default pull-right issue-edit" href="#" id="issue-edit-btn">Edit</a> {{if .IsIssueOwner}}<a class="btn btn-default pull-right issue-edit" href="#" id="issue-edit-btn">Edit</a>
<a class="btn btn-danger pull-right issue-edit-cancel hidden" href="#">Cancel</a> <a class="btn btn-danger pull-right issue-edit-cancel hidden" href="#">Cancel</a>
@ -178,7 +178,7 @@
<div class="dropdown-menu dropdown-menu-right no"> <div class="dropdown-menu dropdown-menu-right no">
<ul class="list-unstyled"> <ul class="list-unstyled">
{{range .Labels}} {{range .Labels}}
<li class="{{if not .IsChecked}}no-{{end}}checked" data-id="{{.Id}}"> <li class="{{if not .IsChecked}}no-{{end}}checked" data-id="{{.ID}}">
{{if .IsChecked}}<span class="check pull-left"><i class="fa fa-check"></i></span>{{end}} {{if .IsChecked}}<span class="check pull-left"><i class="fa fa-check"></i></span>{{end}}
<span class="color" style="background-color: {{.Color}}"></span> <span class="color" style="background-color: {{.Color}}"></span>
<span class="name">{{.Name}}</span> <span class="name">{{.Name}}</span>
@ -191,7 +191,7 @@
<h4>Labels</h4> <h4>Labels</h4>
{{if .Issue.Labels}} {{if .Issue.Labels}}
{{range .Issue.Labels}} {{range .Issue.Labels}}
<p id="label-{{.Id}}" class="label-item label-white" style="background-color: {{.Color}}"><strong>{{.Name}}</strong></p> <p id="label-{{.ID}}" class="label-item label-white" style="background-color: {{.Color}}"><strong>{{.Name}}</strong></p>
{{end}} {{end}}
{{else}} {{else}}
<p>None yet</p> <p>None yet</p>

@ -1,74 +0,0 @@
{{template "ng/base/head" .}}
{{template "ng/base/header" .}}
<div id="repo-wrapper">
{{template "repo/header_old" .}}
<div class="issue-main container repo-wide-wrapper">
<ul id="issue-list-nav" class="menu menu-line">
<li><a href="#">Issue</a></li>
<li><a href="#">Pull Request</a></li>
<li class="current"><a href="#">Labels</a></li>
<li><a href="#">Milestones</a></li>
<li class="right" id="label-new"><a href="#"><button id="label-new-btn" class="btn btn-green text-bold">New Label</button></a></li>
</ul>
<form id="label-add-form" action="#" class="form clear hidden">
<input type="text" class="ipt" name="name" placeholder="label name" id="label-add-name"/>
<div class="inline down drop label-color-drop">
<label for="label-add-color"></label>
<input class="ipt" name="color" type="text" placeholder="color" id="label-add-color"/>
<div class="drop-down">
<a href="#" class="color" style="background: red"></a>
<a href="#" class="color" style="background: green"></a>
</div>
</div>
<button class="btn btn-gray right" type="button" id="label-cancel-btn">Cancel</button>
<button class="btn btn-green right" id="label-add-btn">Create</button>
</form>
<div id="issue-list-container">
<div id="issue-list-menu">
<div class="left"><span class="label label-black" id="labels-num">6</span><strong>Labels</strong></div>
<div class="clear"></div>
</div>
<ul id="label-list" class="list-no-style">
<li class="item" id="label-id">
<a class="right delete" href="#"><i class="octicon octicon-x"></i>Delete</a>
<a class="right edit" href="#"><i class="octicon octicon-pencil"></i>Edit</a>
<a class="right issue-num" href="#"><i class="octicon octicon-issue-opened"></i><strong class="num">12</strong>Issues</a>
<a class="left label clear" href="#" style="background-color: #0052cc" data-color-hex="#0052cc"><i class="octicon octicon-tag"></i><strong>bug</strong></a>
</li>
<li class="item" id="label-id">
<a class="right" href="#"><i class="octicon octicon-x"></i>Delete</a>
<a class="right" href="#"><i class="octicon octicon-pencil"></i>Edit</a>
<a class="right issue-num" href="#"><i class="octicon octicon-issue-opened"></i><strong class="num">12</strong>Issues</a>
<a class="left label clear" href="#" style="background-color: red"><i class="octicon octicon-tag"></i><strong>bug</strong></a>
</li>
</ul>
</div>
</div>
</div>
<div id="label-edit-form-tpl" class="hidden">
<li class="item"><form id="label-edit-form" action="#" class="form clear">
<input type="text" class="ipt" name="name" placeholder="label name" id="label-edit-name"/>
<input type="hidden" name="id" value="id"/>
<div class="inline down drop label-color-drop">
<label for="label-add-color"></label>
<input class="ipt" name="color" type="text" placeholder="color" id="label-edit-color"/>
<div class="drop-down">
<a href="#" class="color" style="background: red"></a>
<a href="#" class="color" style="background: green"></a>
</div>
</div>
<button class="btn btn-gray right" type="button" id="label-edit-cancel-btn">Cancel</button>
<button class="btn btn-green right" id="label-edit-btn">Save Changes</button>
</form></li>
</div>
<div id="label-delete-form-tpl" class="hidden">
<li class="item">
<form id="label-delete-form" action="#">
<input type="hidden" name="id" value="id"/>
<span><strong class="text-red">Are you sure?</strong> Deleting a label will remove it from all issues and pull requests.</span>
<button class="btn btn-gray right" type="button" id="label-del-cancel-btn">Cancel</button>
<button class="btn btn-red right" id="label-del-btn">Delete</button>
</form>
</li>
</div>
{{template "ng/base/footer" .}}
Loading…
Cancel
Save