UI: basic label list

- create new label
This commit is contained in:
Unknwon 2015-07-24 21:02:49 +08:00
parent 86dbda0b42
commit ac95f6d50f
27 changed files with 3686 additions and 166 deletions

1
.gitignore vendored
View file

@ -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

View file

@ -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() {

View file

@ -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

1989
config.codekit Normal file

File diff suppressed because it is too large Load diff

View file

@ -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())

View file

@ -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
} }
} }

View file

@ -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
} }

View file

@ -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
} }
} }

View file

@ -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:

View file

@ -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

1144
public/css/gogs.min.css vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -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();
}); });

11
public/js/libs/jquery.minicolors.min.js vendored Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

View file

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

View file

@ -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;
}
}
}
}
} }

View file

@ -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")
} }

View file

@ -1 +1 @@
0.6.1.0724 Beta 0.6.2.0724 Beta

View file

@ -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>

View file

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

View file

@ -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" .}}

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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" .}}