UI: create issue with title and content

This commit is contained in:
Unknwon 2015-08-09 15:23:02 +08:00
parent 43a87b0caf
commit 590c464c56
18 changed files with 971 additions and 174 deletions

View file

@ -419,8 +419,8 @@ func runWeb(ctx *cli.Context) {
m.Get("/action/:action", repo.Action) m.Get("/action/:action", repo.Action)
m.Group("/issues", func() { m.Group("/issues", func() {
m.Get("/new", repo.CreateIssue) m.Combo("/new").Get(repo.NewIssue).
m.Post("/new", bindIgnErr(auth.CreateIssueForm{}), repo.CreateIssuePost) Post(bindIgnErr(auth.CreateIssueForm{}), repo.NewIssuePost)
m.Post("/:index", bindIgnErr(auth.CreateIssueForm{}), repo.UpdateIssue) m.Post("/:index", bindIgnErr(auth.CreateIssueForm{}), repo.UpdateIssue)
m.Post("/:index/label", repo.UpdateIssueLabel) m.Post("/:index/label", repo.UpdateIssueLabel)
m.Post("/:index/milestone", repo.UpdateIssueMilestone) m.Post("/:index/milestone", repo.UpdateIssueMilestone)

View file

@ -367,6 +367,7 @@ commits.older = Older
commits.newer = Newer commits.newer = Newer
issues.new = New Issue issues.new = New Issue
issues.create = Create Issue
issues.new_label = New Label issues.new_label = New Label
issues.new_label_placeholder = Label name... issues.new_label_placeholder = Label name...
issues.open_tab = %d Open issues.open_tab = %d Open

View file

@ -388,6 +388,26 @@
"strictMath": 0, "strictMath": 0,
"strictUnits": 0 "strictUnits": 0
}, },
"\/public\/less\/_markdown.less": {
"allowInsecureImports": 0,
"createSourceMap": 0,
"disableJavascript": 0,
"fileType": 1,
"ieCompatibility": 1,
"ignore": 1,
"ignoreWasSetByUser": 0,
"inputAbbreviatedPath": "\/public\/less\/_markdown.less",
"outputAbbreviatedPath": "\/public\/css\/_markdown.css",
"outputPathIsOutsideProject": 0,
"outputPathIsSetByUser": 0,
"outputStyle": 0,
"relativeURLS": 0,
"shouldRunAutoprefixer": 0,
"shouldRunBless": 0,
"strictImports": 0,
"strictMath": 0,
"strictUnits": 0
},
"\/public\/less\/_octicons.less": { "\/public\/less\/_octicons.less": {
"allowInsecureImports": 0, "allowInsecureImports": 0,
"createSourceMap": 0, "createSourceMap": 0,

View file

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

View file

@ -38,7 +38,7 @@ type Issue struct {
Repo *Repository `xorm:"-"` Repo *Repository `xorm:"-"`
PosterID int64 PosterID int64
Poster *User `xorm:"-"` Poster *User `xorm:"-"`
LabelIds string `xorm:"TEXT"` LabelIDs string `xorm:"label_ids TEXT"`
Labels []*Label `xorm:"-"` Labels []*Label `xorm:"-"`
MilestoneID int64 MilestoneID int64
Milestone *Milestone `xorm:"-"` Milestone *Milestone `xorm:"-"`
@ -77,11 +77,11 @@ func (i *Issue) GetPoster() (err error) {
} }
func (i *Issue) GetLabels() error { func (i *Issue) GetLabels() error {
if len(i.LabelIds) < 3 { if len(i.LabelIDs) < 3 {
return nil return nil
} }
strIds := strings.Split(strings.TrimSuffix(i.LabelIds[1:], "|"), "|$") strIds := strings.Split(strings.TrimSuffix(i.LabelIDs[1:], "|"), "|$")
i.Labels = make([]*Label, 0, len(strIds)) i.Labels = make([]*Label, 0, len(strIds))
for _, strId := range strIds { for _, strId := range strIds {
id := com.StrTo(strId).MustInt64() id := com.StrTo(strId).MustInt64()
@ -296,14 +296,14 @@ type IssueUser struct {
// FIXME: organization // FIXME: organization
// NewIssueUserPairs adds new issue-user pairs for new issue of repository. // NewIssueUserPairs adds new issue-user pairs for new issue of repository.
func NewIssueUserPairs(repo *Repository, issueID, orgID, posterID, assigneeID int64) error { func NewIssueUserPairs(repo *Repository, issue *Issue) error {
users, err := repo.GetCollaborators() users, err := repo.GetCollaborators()
if err != nil { if err != nil {
return err return err
} }
iu := &IssueUser{ iu := &IssueUser{
IssueId: issueID, IssueId: issue.ID,
RepoId: repo.ID, RepoId: repo.ID,
} }
@ -311,30 +311,30 @@ func NewIssueUserPairs(repo *Repository, issueID, orgID, posterID, assigneeID in
for _, u := range users { for _, u := range users {
iu.Id = 0 iu.Id = 0
iu.Uid = u.Id iu.Uid = u.Id
iu.IsPoster = iu.Uid == posterID iu.IsPoster = iu.Uid == issue.PosterID
if isNeedAddPoster && iu.IsPoster { if isNeedAddPoster && iu.IsPoster {
isNeedAddPoster = false isNeedAddPoster = false
} }
iu.IsAssigned = iu.Uid == assigneeID iu.IsAssigned = iu.Uid == issue.AssigneeID
if _, err = x.Insert(iu); err != nil { if _, err = x.Insert(iu); err != nil {
return err return err
} }
} }
if isNeedAddPoster { if isNeedAddPoster {
iu.Id = 0 iu.Id = 0
iu.Uid = posterID iu.Uid = issue.PosterID
iu.IsPoster = true iu.IsPoster = true
iu.IsAssigned = iu.Uid == assigneeID iu.IsAssigned = iu.Uid == issue.AssigneeID
if _, err = x.Insert(iu); err != nil { if _, err = x.Insert(iu); err != nil {
return err return err
} }
} }
// Add owner's as well. // Add owner's as well.
if repo.OwnerID != posterID { if repo.OwnerID != issue.PosterID {
iu.Id = 0 iu.Id = 0
iu.Uid = repo.OwnerID iu.Uid = repo.OwnerID
iu.IsAssigned = iu.Uid == assigneeID iu.IsAssigned = iu.Uid == issue.AssigneeID
if _, err = x.Insert(iu); err != nil { if _, err = x.Insert(iu); err != nil {
return err return err
} }
@ -621,7 +621,7 @@ func DeleteLabel(repoID, labelID int64) error {
} }
for _, issue := range issues { for _, issue := range issues {
issue.LabelIds = strings.Replace(issue.LabelIds, "$"+com.ToStr(labelID)+"|", "", -1) issue.LabelIDs = strings.Replace(issue.LabelIDs, "$"+com.ToStr(labelID)+"|", "", -1)
if _, err = sess.Id(issue.ID).AllCols().Update(issue); err != nil { if _, err = sess.Id(issue.ID).AllCols().Update(issue); err != nil {
return err return err
} }

View file

@ -14,9 +14,9 @@ import (
) )
type MarkdownForm struct { type MarkdownForm struct {
Text string `form:"text"` Text string
Mode string `form:"mode"` Mode string
Context string `form:"context"` Context string
} }
func (f *MarkdownForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { func (f *MarkdownForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {

View file

@ -98,11 +98,11 @@ func (f *NewSlackHookForm) Validate(ctx *macaron.Context, errs binding.Errors) b
// \/ \/ \/ // \/ \/ \/
type CreateIssueForm struct { type CreateIssueForm struct {
IssueName string `form:"title" binding:"Required;MaxSize(255)"` Title string `binding:"Required;MaxSize(255)"`
MilestoneId int64 `form:"milestoneid"` LabelIDs []int64 `form:"label_id"`
AssigneeId int64 `form:"assigneeid"` MilestoneID int64
Labels string `form:"labels"` AssigneeID int64
Content string `form:"content"` Content string
} }
func (f *CreateIssueForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { func (f *CreateIssueForm) 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

View file

@ -123,6 +123,26 @@ $(document).ready(function () {
}); });
$('.poping.up').popup(); $('.poping.up').popup();
// Comment form
$('.comment.form .tabular.menu .item').tab();
$('.comment.form .tabular.menu .item[data-tab="preview"]').click(function () {
var $this = $(this);
console.log($('.comment.form .tab.segment[data-tab="write"] textarea').val())
console.log($('.comment.form .tab.segment[data-tab="preview"]').html())
$.post($this.data('url'), {
"_csrf": csrf,
"mode": "gfm",
"context": $this.data('context'),
"text": $('.comment.form .tab.segment[data-tab="write"] textarea').val()
},
function (data) {
console.log(data)
$('.comment.form .tab.segment[data-tab="preview"]').html(data);
}
)
;
})
// Helpers. // Helpers.
$('.delete-button').click(function () { $('.delete-button').click(function () {
var $this = $(this); var $this = $(this);

594
public/less/_markdown.less Normal file
View file

@ -0,0 +1,594 @@
.markdown {
overflow:hidden;
font-family:"Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;
font-size:16px;
line-height:1.6;
word-wrap:break-word;
>*:first-child {
margin-top:0 !important;
}
>*:last-child {
margin-bottom:0 !important;
}
a:not([href]) {
color:inherit;
text-decoration:none;
}
.absent {
color:#c00;
}
.anchor {
position:absolute;
top:0;
left:0;
display:block;
padding-right:6px;
padding-left:30px;
margin-left:-30px;
}
.anchor:focus {
outline:none;
}
h1,
h2,
h3,
h4,
h5,
h6 {
position:relative;
margin-top:1em;
margin-bottom:16px;
font-weight:bold;
line-height:1.4;
}
h1 .octicon-link,
h2 .octicon-link,
h3 .octicon-link,
h4 .octicon-link,
h5 .octicon-link,
h6 .octicon-link {
display:none;
color:#000;
vertical-align:middle;
}
h1:hover .anchor,
h2:hover .anchor,
h3:hover .anchor,
h4:hover .anchor,
h5:hover .anchor,
h6:hover .anchor {
padding-left:8px;
margin-left:-30px;
text-decoration:none;
}
h1:hover .anchor .octicon-link,
h2:hover .anchor .octicon-link,
h3:hover .anchor .octicon-link,
h4:hover .anchor .octicon-link,
h5:hover .anchor .octicon-link,
h6:hover .anchor .octicon-link {
display:inline-block;
}
h1 tt,
h1 code,
h2 tt,
h2 code,
h3 tt,
h3 code,
h4 tt,
h4 code,
h5 tt,
h5 code,
h6 tt,
h6 code {
font-size:inherit;
}
h1 {
padding-bottom:0.3em;
font-size:2.25em;
line-height:1.2;
border-bottom:1px solid #eee;
}
h1 .anchor {
line-height:1;
}
h2 {
padding-bottom:0.3em;
font-size:1.75em;
line-height:1.225;
border-bottom:1px solid #eee;
}
h2 .anchor {
line-height:1;
}
h3 {
font-size:1.5em;
line-height:1.43;
}
h3 .anchor {
line-height:1.2;
}
h4 {
font-size:1.25em;
}
h4 .anchor {
line-height:1.2;
}
h5 {
font-size:1em;
}
h5 .anchor {
line-height:1.1;
}
h6 {
font-size:1em;color:#777;
}
h6 .anchor {
line-height:1.1;
}
p,
blockquote,
ul,
ol,
dl,
table,
pre {
margin-top:0;
margin-bottom:16px;
}
hr {
height:4px;
padding:0;
margin:16px 0;
background-color:#e7e7e7;
border:0 none;
}
ul,
ol {
padding-left:2em;
}
ul.no-list,
ol.no-list {
padding:0;
list-style-type:none;
}
ul ul,
ul ol,
ol ol,
ol ul {
margin-top:0;
margin-bottom:0;
}
ol ol,
ul ol {
list-style-type: lower-roman;
}
li>p {
margin-top:16px;
}
dl {
padding:0;
}
dl dt {
padding:0;
margin-top:16px;
font-size:1em;
font-style:italic;
font-weight:bold;
}
dl dd {
padding:0 16px;
margin-bottom:16px;
}
blockquote {
padding:0 15px;
color:#777;
border-left:4px solid #ddd;
}
blockquote>:first-child {
margin-top:0;
}
blockquote>:last-child {
margin-bottom:0;
}
table {
display:block;
width:100%;
overflow:auto;
word-break:normal;
word-break:keep-all;
}
table th {
font-weight:bold;
}
table th,
table td {
padding:6px 13px !important;
border:1px solid #ddd;
}
table tr {
background-color:#fff;
border-top:1px solid #ccc;
}
table tr:nth-child(2n) {
background-color:#f8f8f8;
}
img {
max-width:100%;
box-sizing:border-box;
}
.emoji {
max-width:none;
}
span.frame {
display:block;
overflow:hidden;
}
span.frame>span {
display:block;
float:left;
width:auto;
padding:7px;
margin:13px 0 0;
overflow:hidden;
border:1px solid #ddd;
}
span.frame span img {
display:block;
float:left;
}
span.frame span span {
display:block;
padding:5px 0 0;
clear:both;
color:#333;
}
span.align-center {
display:block;
overflow:hidden;
clear:both;
}
span.align-center>span {
display:block;
margin:13px auto 0;
overflow:hidden;
text-align:center;
}
span.align-center span img {
margin:0 auto;
text-align:center;
}
span.align-right {
display:block;
overflow:hidden;
clear:both;
}
span.align-right>span {
display:block;
margin:13px 0 0;
overflow:hidden;
text-align:right;
}
span.align-right span img {
margin:0;
text-align:right;
}
span.float-left {
display:block;
float:left;
margin-right:13px;
overflow:hidden;
}
span.float-left span {
margin:13px 0 0;
}
span.float-right {
display:block;
float:right;
margin-left:13px;
overflow:hidden;
}
span.float-right>span {
display:block;
margin:13px auto 0;
overflow:hidden;
text-align:right;
}
code,
tt {
padding:0;
padding-top:0.2em;
padding-bottom:0.2em;
margin:0;
font-size:85%;
background-color:rgba(0,0,0,0.04);
border-radius:3px;
}
code:before,
code:after,
tt:before,
tt:after {
letter-spacing:-0.2em;
content:"\00a0";
}
code br,
tt br {
display:none;
}
del code {
text-decoration:inherit;
}
pre>code {
padding:0;
margin:0;
font-size:100%;
word-break:normal;
white-space:pre;
background:transparent;
border:0;
}
.highlight {
margin-bottom:16px;
}
.highlight pre,
pre {
padding:16px;
overflow:auto;
font-size:85%;
line-height:1.45;
background-color:#f7f7f7;
border-radius:3px;
}
.highlight pre {
margin-bottom:0;
word-break:normal;
}
pre {
word-wrap:normal;
}
pre code,
pre tt {
display:inline;
max-width:initial;
padding:0;
margin:0;
overflow:initial;
line-height:inherit;
word-wrap:normal;
background-color:transparent;
border:0;
}
pre code:before,
pre code:after,
pre tt:before,
pre tt:after {
content:normal;
}
kbd {
display:inline-block;
padding:3px 5px;
font-size:11px;
line-height:10px;
color:#555;
vertical-align:middle;
background-color:#fcfcfc;
border:solid 1px #ccc;
border-bottom-color:#bbb;
border-radius:3px;
box-shadow:inset 0 -1px 0 #bbb;
}
.csv-data td,
.csv-data th {
padding:5px;
overflow:hidden;
font-size:12px;
line-height:1;
text-align:left;
white-space:nowrap;
}
.csv-data .blob-num {
padding:10px 8px 9px;
text-align:right;
background:#fff;border:0;
}
.csv-data tr {
border-top:0;
}
.csv-data th {
font-weight:bold;
background:#f8f8f8;border-top:0;
}
}
/* Author: jmblog */
/* Project: https://github.com/jmblog/color-themes-for-google-code-prettify */
/* GitHub Theme */
/* Pretty printing styles. Used with prettify.js. */
/* SPAN elements with the classes below are added by prettyprint. */
/* plain text */
.pln {
color: #333333;
}
@media screen {
/* string content */
.str {
color: #dd1144;
}
/* a keyword */
.kwd {
color: #333333;
}
/* a comment */
.com {
color: #999988;
font-style: italic;
}
/* a type name */
.typ {
color: #445588;
}
/* a literal value */
.lit {
color: #445588;
}
/* punctuation */
.pun {
color: #333333;
}
/* lisp open bracket */
.opn {
color: #333333;
}
/* lisp close bracket */
.clo {
color: #333333;
}
/* a markup tag name */
.tag {
color: navy;
}
/* a markup attribute name */
.atn {
color: teal;
}
/* a markup attribute value */
.atv {
color: #dd1144;
}
/* a declaration */
.dec {
color: #333333;
}
/* a variable name */
.var {
color: teal;
}
/* a function name */
.fun {
color: #990000;
}
}
/* Use higher contrast and text-weight for printable form. */
@media print,
projection {
.str {
color: #006600;
}
.kwd {
color: #006;
font-weight: bold;
}
.com {
color: #600;
font-style: italic;
}
.typ {
color: #404;
font-weight: bold;
}
.lit {
color: #004444;
}
.pun,
.opn,
.clo {
color: #444400;
}
.tag {
color: #006;
font-weight: bold;
}
.atn {
color: #440044;
}
.atv {
color: #006600;
}
}
/* Specify class=linenums on a pre to get line numbering */
ol.linenums {
margin-top: 0;
margin-bottom: 0;
}

View file

@ -105,6 +105,7 @@
.page.buttons { .page.buttons {
padding-top: 15px; padding-top: 15px;
} }
.issue.list { .issue.list {
clear: both; clear: both;
list-style: none; list-style: none;
@ -138,6 +139,32 @@
} }
} }
} }
&.new.issue {
.comment.form {
.metas {
min-width: 220px;
}
}
}
.comment.form {
.ui.comments {
margin-top: -12px;
max-width: 750px!important;
}
.content {
.field:first-child {
clear: none;
}
.tab.segment {
border: none;
padding: 0;
padding-top: 10px;
}
textarea {
height: 200px;
}
}
}
.label.list { .label.list {
clear: both; clear: both;

View file

@ -1,5 +1,6 @@
@import "_octicons"; @import "_octicons";
@import "_base"; @import "_base";
@import "_markdown";
@import "_home"; @import "_home";
@import "_install"; @import "_install";
@import "_form"; @import "_form";

View file

@ -28,7 +28,7 @@ import (
const ( const (
ISSUES base.TplName = "repo/issue/list" ISSUES base.TplName = "repo/issue/list"
ISSUE_CREATE base.TplName = "repo/issue/create" ISSUE_NEW base.TplName = "repo/issue/new"
ISSUE_VIEW base.TplName = "repo/issue/view" ISSUE_VIEW base.TplName = "repo/issue/view"
LABELS base.TplName = "repo/issue/labels" LABELS base.TplName = "repo/issue/labels"
@ -174,167 +174,198 @@ func Issues(ctx *middleware.Context) {
ctx.HTML(200, ISSUES) ctx.HTML(200, ISSUES)
} }
func CreateIssue(ctx *middleware.Context) { func NewIssue(ctx *middleware.Context) {
ctx.Data["Title"] = "Create issue" ctx.Data["Title"] = ctx.Tr("repo.issues.new")
ctx.Data["IsRepoToolbarIssues"] = true ctx.Data["PageIsIssueList"] = true
ctx.Data["IsRepoToolbarIssuesList"] = false ctx.Data["IsAttachmentEnabled"] = setting.AttachmentEnabled
ctx.Data["AttachmentsEnabled"] = setting.AttachmentEnabled ctx.Data["AttachmentAllowedTypes"] = setting.AttachmentAllowedTypes
var ( // var (
repo = ctx.Repo.Repository // repo = ctx.Repo.Repository
err error // err error
) // )
// Get all milestones. // // Get all milestones.
ctx.Data["OpenMilestones"], err = models.GetMilestones(repo.ID, -1, false) // ctx.Data["OpenMilestones"], err = models.GetMilestones(repo.ID, -1, false)
if err != nil { // if err != nil {
ctx.Handle(500, "GetMilestones.1: %v", err) // ctx.Handle(500, "GetMilestones.1: %v", err)
return // return
} // }
ctx.Data["ClosedMilestones"], err = models.GetMilestones(repo.ID, -1, true) // ctx.Data["ClosedMilestones"], err = models.GetMilestones(repo.ID, -1, true)
if err != nil { // if err != nil {
ctx.Handle(500, "GetMilestones.2: %v", err) // ctx.Handle(500, "GetMilestones.2: %v", err)
return // return
// }
// us, err := repo.GetCollaborators()
// if err != nil {
// ctx.Handle(500, "GetCollaborators", err)
// return
// }
// ctx.Data["Collaborators"] = us
ctx.HTML(200, ISSUE_NEW)
} }
us, err := repo.GetCollaborators() func NewIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) {
if err != nil { ctx.Data["Title"] = ctx.Tr("repo.issues.new")
ctx.Handle(500, "GetCollaborators", err) ctx.Data["PageIsIssueList"] = true
return ctx.Data["IsAttachmentEnabled"] = setting.AttachmentEnabled
} ctx.Data["AttachmentAllowedTypes"] = setting.AttachmentAllowedTypes
ctx.Data["AllowedTypes"] = setting.AttachmentAllowedTypes
ctx.Data["Collaborators"] = us
ctx.HTML(200, ISSUE_CREATE)
}
func CreateIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) {
send := func(status int, data interface{}, err error) {
if err != nil {
log.Error(4, "issue.CreateIssuePost(?): %s", err)
ctx.JSON(status, map[string]interface{}{
"ok": false,
"status": status,
"error": err.Error(),
})
} else {
ctx.JSON(status, map[string]interface{}{
"ok": true,
"status": status,
"data": data,
})
}
}
var err error
// Get all milestones.
_, err = models.GetMilestones(ctx.Repo.Repository.ID, -1, false)
if err != nil {
send(500, nil, err)
return
}
_, err = models.GetMilestones(ctx.Repo.Repository.ID, -1, true)
if err != nil {
send(500, nil, err)
return
}
_, err = ctx.Repo.Repository.GetCollaborators()
if err != nil {
send(500, nil, err)
return
}
if ctx.HasError() { if ctx.HasError() {
send(400, nil, errors.New(ctx.Flash.ErrorMsg)) ctx.HTML(200, ISSUE_NEW)
return return
} }
// Only collaborators can assign.
if !ctx.Repo.IsOwner() {
form.AssigneeId = 0
}
issue := &models.Issue{ issue := &models.Issue{
RepoID: ctx.Repo.Repository.ID, RepoID: ctx.Repo.Repository.ID,
Index: int64(ctx.Repo.Repository.NumIssues) + 1, Index: int64(ctx.Repo.Repository.NumIssues) + 1,
Name: form.IssueName, Name: form.Title,
PosterID: ctx.User.Id, PosterID: ctx.User.Id,
MilestoneID: form.MilestoneId, // MilestoneID: form.MilestoneID,
AssigneeID: form.AssigneeId, // AssigneeID: form.AssigneeID,
LabelIds: form.Labels, // LabelIDs: "$" + strings.Join(form.LabelIDs, "|$") + "|",
Content: form.Content, Content: form.Content,
} }
if err := models.NewIssue(issue); err != nil { if err := models.NewIssue(issue); err != nil {
send(500, nil, err) ctx.Handle(500, "NewIssue", 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); err != nil {
ctx.User.Id, form.AssigneeId); err != nil { ctx.Handle(500, "NewIssue", err)
send(500, nil, err)
return return
} }
if setting.AttachmentEnabled { ctx.Redirect(ctx.Repo.RepoLink + "/issues/" + com.ToStr(issue.Index))
uploadFiles(ctx, issue.ID, 0)
} }
// Update mentions. func CreateIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) {
ms := base.MentionPattern.FindAllString(issue.Content, -1) // send := func(status int, data interface{}, err error) {
if len(ms) > 0 { // if err != nil {
for i := range ms { // log.Error(4, "issue.CreateIssuePost(?): %s", err)
ms[i] = ms[i][1:]
}
if err := models.UpdateMentions(ms, issue.ID); err != nil { // ctx.JSON(status, map[string]interface{}{
send(500, nil, err) // "ok": false,
return // "status": status,
} // "error": err.Error(),
} // })
// } else {
// ctx.JSON(status, map[string]interface{}{
// "ok": true,
// "status": status,
// "data": data,
// })
// }
// }
act := &models.Action{ // var err error
ActUserID: ctx.User.Id, // // Get all milestones.
ActUserName: ctx.User.Name, // _, err = models.GetMilestones(ctx.Repo.Repository.ID, -1, false)
ActEmail: ctx.User.Email, // if err != nil {
OpType: models.CREATE_ISSUE, // send(500, nil, err)
Content: fmt.Sprintf("%d|%s", issue.Index, issue.Name), // return
RepoID: ctx.Repo.Repository.ID, // }
RepoUserName: ctx.Repo.Owner.Name, // _, err = models.GetMilestones(ctx.Repo.Repository.ID, -1, true)
RepoName: ctx.Repo.Repository.Name, // if err != nil {
RefName: ctx.Repo.BranchName, // send(500, nil, err)
IsPrivate: ctx.Repo.Repository.IsPrivate, // return
} // }
// Notify watchers.
if err := models.NotifyWatchers(act); err != nil {
send(500, nil, err)
return
}
// Mail watchers and mentions. // _, err = ctx.Repo.Repository.GetCollaborators()
if setting.Service.EnableNotifyMail { // if err != nil {
tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue) // send(500, nil, err)
if err != nil { // return
send(500, nil, err) // }
return
}
tos = append(tos, ctx.User.LowerName) // if ctx.HasError() {
newTos := make([]string, 0, len(ms)) // send(400, nil, errors.New(ctx.Flash.ErrorMsg))
for _, m := range ms { // return
if com.IsSliceContainsStr(tos, m) { // }
continue
}
newTos = append(newTos, m) // // Only collaborators can assign.
} // if !ctx.Repo.IsOwner() {
if err = mailer.SendIssueMentionMail(ctx.Render, ctx.User, ctx.Repo.Owner, // form.AssigneeId = 0
ctx.Repo.Repository, issue, models.GetUserEmailsByNames(newTos)); err != nil { // }
send(500, nil, err) // issue := &models.Issue{
return // RepoID: ctx.Repo.Repository.ID,
} // Index: int64(ctx.Repo.Repository.NumIssues) + 1,
} // Name: form.IssueName,
log.Trace("%d Issue created: %d", ctx.Repo.Repository.ID, issue.ID) // PosterID: ctx.User.Id,
// MilestoneID: form.MilestoneId,
// AssigneeID: form.AssigneeId,
// LabelIds: form.Labels,
// Content: form.Content,
// }
// if err := models.NewIssue(issue); err != nil {
// send(500, nil, err)
// return
// } else if err := models.NewIssueUserPairs(ctx.Repo.Repository, issue.ID, ctx.Repo.Owner.Id,
// ctx.User.Id, form.AssigneeId); err != nil {
// send(500, nil, err)
// return
// }
send(200, fmt.Sprintf("%s/%s/%s/issues/%d", setting.AppSubUrl, ctx.Params(":username"), ctx.Params(":reponame"), issue.Index), nil) // if setting.AttachmentEnabled {
// uploadFiles(ctx, issue.ID, 0)
// }
// // Update mentions.
// ms := base.MentionPattern.FindAllString(issue.Content, -1)
// if len(ms) > 0 {
// for i := range ms {
// ms[i] = ms[i][1:]
// }
// if err := models.UpdateMentions(ms, issue.ID); err != nil {
// send(500, nil, err)
// return
// }
// }
// act := &models.Action{
// ActUserID: ctx.User.Id,
// ActUserName: ctx.User.Name,
// ActEmail: ctx.User.Email,
// OpType: models.CREATE_ISSUE,
// Content: fmt.Sprintf("%d|%s", issue.Index, issue.Name),
// RepoID: ctx.Repo.Repository.ID,
// RepoUserName: ctx.Repo.Owner.Name,
// RepoName: ctx.Repo.Repository.Name,
// RefName: ctx.Repo.BranchName,
// IsPrivate: ctx.Repo.Repository.IsPrivate,
// }
// // Notify watchers.
// if err := models.NotifyWatchers(act); err != nil {
// send(500, nil, err)
// return
// }
// // Mail watchers and mentions.
// if setting.Service.EnableNotifyMail {
// tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue)
// if err != nil {
// send(500, nil, err)
// return
// }
// tos = append(tos, ctx.User.LowerName)
// newTos := make([]string, 0, len(ms))
// for _, m := range ms {
// if com.IsSliceContainsStr(tos, m) {
// continue
// }
// newTos = append(newTos, m)
// }
// if err = mailer.SendIssueMentionMail(ctx.Render, ctx.User, ctx.Repo.Owner,
// ctx.Repo.Repository, issue, models.GetUserEmailsByNames(newTos)); err != nil {
// send(500, nil, err)
// return
// }
// }
// 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)
} }
func checkLabels(labels, allLabels []*models.Label) { func checkLabels(labels, allLabels []*models.Label) {
@ -484,7 +515,7 @@ func UpdateIssue(ctx *middleware.Context, form auth.CreateIssueForm) {
return return
} }
issue.Name = form.IssueName issue.Name = form.Title
//issue.MilestoneId = form.MilestoneId //issue.MilestoneId = form.MilestoneId
//issue.AssigneeId = form.AssigneeId //issue.AssigneeId = form.AssigneeId
//issue.LabelIds = form.Labels //issue.LabelIds = form.Labels
@ -540,16 +571,16 @@ func UpdateIssueLabel(ctx *middleware.Context) {
return return
} }
isHad := strings.Contains(issue.LabelIds, "$"+labelStrId+"|") isHad := strings.Contains(issue.LabelIDs, "$"+labelStrId+"|")
isNeedUpdate := false isNeedUpdate := false
if isAttach { if isAttach {
if !isHad { if !isHad {
issue.LabelIds += "$" + labelStrId + "|" issue.LabelIDs += "$" + labelStrId + "|"
isNeedUpdate = true isNeedUpdate = true
} }
} else { } else {
if isHad { if isHad {
issue.LabelIds = strings.Replace(issue.LabelIds, "$"+labelStrId+"|", "", -1) issue.LabelIDs = strings.Replace(issue.LabelIDs, "$"+labelStrId+"|", "", -1)
isNeedUpdate = true isNeedUpdate = true
} }
} }

View file

@ -1 +1 @@
0.6.4.0808 Beta 0.6.4.0809 Beta

View file

@ -0,0 +1,14 @@
{{template "base/head" .}}
<div class="repository new issue">
{{template "repo/header" .}}
<div class="ui middle page grid body">
<div class="navbar">
{{template "repo/issue/navbar" .}}
</div>
<div class="ui divider"></div>
<div class="sixteen wide column page grid">
{{template "repo/issue/new_form" .}}
</div>
</div>
</div>
{{template "base/footer" .}}

View file

@ -0,0 +1,88 @@
<form class="ui comment form grid" action="{{.Link}}" method="post">
{{.CsrfTokenHtml}}
{{if .Flash}}
<div class="sixteen wide column">
{{template "base/alert" .}}
</div>
{{end}}
<div class="twelve wide column">
<div class="ui comments">
<div class="comment">
<a class="avatar">
<img src="{{.SignedUser.AvatarLink}}">
</a>
<div class="ui segment content">
<div class="field">
<input name="title" placeholder="{{.i18n.Tr "repo.milestones.title"}}" value="{{.title}}" autofocus required>
</div>
<div class="field">
<div class="ui top attached tabular menu">
<a class="active item" data-tab="write">{{.i18n.Tr "repo.release.write"}}</a>
<a class="item" data-tab="preview" data-url="/api/v1/markdown" data-context="{{.RepoLink}}">{{.i18n.Tr "repo.release.preview"}}</a>
</div>
<div class="ui bottom attached active tab segment" data-tab="write">
<textarea name="content"></textarea>
</div>
<div class="ui bottom attached tab segment markdown" data-tab="preview">
{{.i18n.Tr "repo.release.loading"}}
</div>
</div>
<button class="ui right green button">
{{.i18n.Tr "repo.issues.create"}}
</button>
</div>
</div>
</div>
</div>
<div class="four wide column">
<div class="ui segment metas">
<div class="ui {{if .Labels}}disabled{{end}} pointing dropdown jump item">
<span class="text">
<strong>{{.i18n.Tr "repo.issues.new.labels"}}</strong>
<span class="octicon octicon-gear"></span>
</span>
<div class="menu">
<a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}&milestone={{$.MilestoneID}}">{{.i18n.Tr "repo.issues.filter_label_no_select"}}</a>
{{range .Labels}}
<a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}&milestone={{$.MilestoneID}}"><span class="octicon {{if eq $.SelectLabels .ID}}octicon-check{{end}}"></span><span class="label color" style="background-color: {{.Color}}"></span> {{.Name}}</a>
{{end}}
</div>
</div>
<div class="ui list">
<span class="item">filter_label_no_select</span>
</div>
<div class="ui divider"></div>
<div class="ui {{if .Labels}}disabled{{end}} pointing dropdown jump item">
<span class="text">
<strong>{{.i18n.Tr "repo.issues.new.labels"}}</strong>
<span class="octicon octicon-gear"></span>
</span>
<div class="menu">
<a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}&milestone={{$.MilestoneID}}">{{.i18n.Tr "repo.issues.filter_label_no_select"}}</a>
{{range .Labels}}
<a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}&milestone={{$.MilestoneID}}"><span class="octicon {{if eq $.SelectLabels .ID}}octicon-check{{end}}"></span><span class="label color" style="background-color: {{.Color}}"></span> {{.Name}}</a>
{{end}}
</div>
</div>
<div class="ui list">
<span class="item">filter_label_no_select</span>
</div>
<div class="ui divider"></div>
<div class="ui {{if .Labels}}disabled{{end}} pointing dropdown jump item">
<span class="text">
<strong>{{.i18n.Tr "repo.issues.new.labels"}}</strong>
<span class="octicon octicon-gear"></span>
</span>
<div class="menu">
<a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}&milestone={{$.MilestoneID}}">{{.i18n.Tr "repo.issues.filter_label_no_select"}}</a>
{{range .Labels}}
<a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}&milestone={{$.MilestoneID}}"><span class="octicon {{if eq $.SelectLabels .ID}}octicon-check{{end}}"></span><span class="label color" style="background-color: {{.Color}}"></span> {{.Name}}</a>
{{end}}
</div>
</div>
<div class="ui list">
<span class="item">filter_label_no_select</span>
</div>
</div>
</div>
</form>

View file

@ -45,6 +45,7 @@
</div> </div>
</div> </div>
</div> </div>
{{template "repo/issue/new_form" .}}
</div> </div>
</div> </div>
</div> </div>