Browse Source

UI: create issue with title and content

pull/1466/head
Unknwon 10 years ago
parent
commit
590c464c56
  1. 4
      cmd/web.go
  2. 1
      conf/locale/locale_en-US.ini
  3. 20
      config.codekit
  4. 2
      gogs.go
  5. 26
      models/issue.go
  6. 6
      modules/auth/apiv1/miscellaneous.go
  7. 10
      modules/auth/repo_form.go
  8. 6
      modules/bindata/bindata.go
  9. 2
      public/css/gogs.min.css
  10. 20
      public/js/gogs.js
  11. 594
      public/less/_markdown.less
  12. 27
      public/less/_repository.less
  13. 1
      public/less/gogs.less
  14. 325
      routers/repo/issue.go
  15. 2
      templates/.VERSION
  16. 14
      templates/repo/issue/new.tmpl
  17. 88
      templates/repo/issue/new_form.tmpl
  18. 1
      templates/repo/pulls/compare.tmpl

4
cmd/web.go

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

1
conf/locale/locale_en-US.ini

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

20
config.codekit

@ -388,6 +388,26 @@
"strictMath": 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": {
"allowInsecureImports": 0,
"createSourceMap": 0,

2
gogs.go

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

26
models/issue.go

@ -38,7 +38,7 @@ type Issue struct {
Repo *Repository `xorm:"-"`
PosterID int64
Poster *User `xorm:"-"`
LabelIds string `xorm:"TEXT"`
LabelIDs string `xorm:"label_ids TEXT"`
Labels []*Label `xorm:"-"`
MilestoneID int64
Milestone *Milestone `xorm:"-"`
@ -77,11 +77,11 @@ func (i *Issue) GetPoster() (err error) {
}
func (i *Issue) GetLabels() error {
if len(i.LabelIds) < 3 {
if len(i.LabelIDs) < 3 {
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))
for _, strId := range strIds {
id := com.StrTo(strId).MustInt64()
@ -134,7 +134,7 @@ func NewIssue(issue *Issue) (err error) {
if _, err = sess.Insert(issue); err != nil {
return err
} else if _, err = sess.Exec("UPDATE `repository` SET num_issues = num_issues + 1 WHERE id = ?", issue.RepoID); err != nil {
} else if _, err = sess.Exec("UPDATE `repository` SET num_issues=num_issues+1 WHERE id=?", issue.RepoID); err != nil {
return err
}
@ -296,14 +296,14 @@ type IssueUser struct {
// FIXME: organization
// 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()
if err != nil {
return err
}
iu := &IssueUser{
IssueId: issueID,
IssueId: issue.ID,
RepoId: repo.ID,
}
@ -311,30 +311,30 @@ func NewIssueUserPairs(repo *Repository, issueID, orgID, posterID, assigneeID in
for _, u := range users {
iu.Id = 0
iu.Uid = u.Id
iu.IsPoster = iu.Uid == posterID
iu.IsPoster = iu.Uid == issue.PosterID
if isNeedAddPoster && iu.IsPoster {
isNeedAddPoster = false
}
iu.IsAssigned = iu.Uid == assigneeID
iu.IsAssigned = iu.Uid == issue.AssigneeID
if _, err = x.Insert(iu); err != nil {
return err
}
}
if isNeedAddPoster {
iu.Id = 0
iu.Uid = posterID
iu.Uid = issue.PosterID
iu.IsPoster = true
iu.IsAssigned = iu.Uid == assigneeID
iu.IsAssigned = iu.Uid == issue.AssigneeID
if _, err = x.Insert(iu); err != nil {
return err
}
}
// Add owner's as well.
if repo.OwnerID != posterID {
if repo.OwnerID != issue.PosterID {
iu.Id = 0
iu.Uid = repo.OwnerID
iu.IsAssigned = iu.Uid == assigneeID
iu.IsAssigned = iu.Uid == issue.AssigneeID
if _, err = x.Insert(iu); err != nil {
return err
}
@ -621,7 +621,7 @@ func DeleteLabel(repoID, labelID int64) error {
}
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 {
return err
}

6
modules/auth/apiv1/miscellaneous.go

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

10
modules/auth/repo_form.go

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

6
modules/bindata/bindata.go

File diff suppressed because one or more lines are too long

2
public/css/gogs.min.css vendored

File diff suppressed because one or more lines are too long

20
public/js/gogs.js

@ -123,6 +123,26 @@ $(document).ready(function () {
});
$('.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.
$('.delete-button').click(function () {
var $this = $(this);

594
public/less/_markdown.less

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

27
public/less/_repository.less

@ -105,6 +105,7 @@
.page.buttons {
padding-top: 15px;
}
.issue.list {
clear: both;
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 {
clear: both;

1
public/less/gogs.less

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

325
routers/repo/issue.go

@ -28,7 +28,7 @@ import (
const (
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"
LABELS base.TplName = "repo/issue/labels"
@ -174,167 +174,198 @@ func Issues(ctx *middleware.Context) {
ctx.HTML(200, ISSUES)
}
func CreateIssue(ctx *middleware.Context) {
ctx.Data["Title"] = "Create issue"
ctx.Data["IsRepoToolbarIssues"] = true
ctx.Data["IsRepoToolbarIssuesList"] = false
ctx.Data["AttachmentsEnabled"] = setting.AttachmentEnabled
var (
repo = ctx.Repo.Repository
err error
)
// Get all milestones.
ctx.Data["OpenMilestones"], err = models.GetMilestones(repo.ID, -1, false)
if err != nil {
ctx.Handle(500, "GetMilestones.1: %v", err)
return
}
ctx.Data["ClosedMilestones"], err = models.GetMilestones(repo.ID, -1, true)
if err != nil {
ctx.Handle(500, "GetMilestones.2: %v", err)
return
}
us, err := repo.GetCollaborators()
if err != nil {
ctx.Handle(500, "GetCollaborators", err)
return
}
ctx.Data["AllowedTypes"] = setting.AttachmentAllowedTypes
ctx.Data["Collaborators"] = us
ctx.HTML(200, ISSUE_CREATE)
func NewIssue(ctx *middleware.Context) {
ctx.Data["Title"] = ctx.Tr("repo.issues.new")
ctx.Data["PageIsIssueList"] = true
ctx.Data["IsAttachmentEnabled"] = setting.AttachmentEnabled
ctx.Data["AttachmentAllowedTypes"] = setting.AttachmentAllowedTypes
// var (
// repo = ctx.Repo.Repository
// err error
// )
// // Get all milestones.
// ctx.Data["OpenMilestones"], err = models.GetMilestones(repo.ID, -1, false)
// if err != nil {
// ctx.Handle(500, "GetMilestones.1: %v", err)
// return
// }
// ctx.Data["ClosedMilestones"], err = models.GetMilestones(repo.ID, -1, true)
// if err != nil {
// ctx.Handle(500, "GetMilestones.2: %v", err)
// return
// }
// us, err := repo.GetCollaborators()
// if err != nil {
// ctx.Handle(500, "GetCollaborators", err)
// return
// }
// ctx.Data["Collaborators"] = us
ctx.HTML(200, ISSUE_NEW)
}
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
}
func NewIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) {
ctx.Data["Title"] = ctx.Tr("repo.issues.new")
ctx.Data["PageIsIssueList"] = true
ctx.Data["IsAttachmentEnabled"] = setting.AttachmentEnabled
ctx.Data["AttachmentAllowedTypes"] = setting.AttachmentAllowedTypes
if ctx.HasError() {
send(400, nil, errors.New(ctx.Flash.ErrorMsg))
ctx.HTML(200, ISSUE_NEW)
return
}
// Only collaborators can assign.
if !ctx.Repo.IsOwner() {
form.AssigneeId = 0
}
issue := &models.Issue{
RepoID: ctx.Repo.Repository.ID,
Index: int64(ctx.Repo.Repository.NumIssues) + 1,
Name: form.IssueName,
Name: form.Title,
PosterID: ctx.User.Id,
MilestoneID: form.MilestoneId,
AssigneeID: form.AssigneeId,
LabelIds: form.Labels,
// MilestoneID: form.MilestoneID,
// AssigneeID: form.AssigneeID,
// LabelIDs: "$" + strings.Join(form.LabelIDs, "|$") + "|",
Content: form.Content,
}
if err := models.NewIssue(issue); err != nil {
send(500, nil, err)
ctx.Handle(500, "NewIssue", 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
}
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)
} else if err := models.NewIssueUserPairs(ctx.Repo.Repository, issue); err != nil {
ctx.Handle(500, "NewIssue", 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)
ctx.Redirect(ctx.Repo.RepoLink + "/issues/" + com.ToStr(issue.Index))
}
send(200, fmt.Sprintf("%s/%s/%s/issues/%d", setting.AppSubUrl, ctx.Params(":username"), ctx.Params(":reponame"), issue.Index), nil)
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() {
// send(400, nil, errors.New(ctx.Flash.ErrorMsg))
// return
// }
// // Only collaborators can assign.
// if !ctx.Repo.IsOwner() {
// form.AssigneeId = 0
// }
// issue := &models.Issue{
// RepoID: ctx.Repo.Repository.ID,
// Index: int64(ctx.Repo.Repository.NumIssues) + 1,
// Name: form.IssueName,
// 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
// }
// 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) {
@ -484,7 +515,7 @@ func UpdateIssue(ctx *middleware.Context, form auth.CreateIssueForm) {
return
}
issue.Name = form.IssueName
issue.Name = form.Title
//issue.MilestoneId = form.MilestoneId
//issue.AssigneeId = form.AssigneeId
//issue.LabelIds = form.Labels
@ -540,16 +571,16 @@ func UpdateIssueLabel(ctx *middleware.Context) {
return
}
isHad := strings.Contains(issue.LabelIds, "$"+labelStrId+"|")
isHad := strings.Contains(issue.LabelIDs, "$"+labelStrId+"|")
isNeedUpdate := false
if isAttach {
if !isHad {
issue.LabelIds += "$" + labelStrId + "|"
issue.LabelIDs += "$" + labelStrId + "|"
isNeedUpdate = true
}
} else {
if isHad {
issue.LabelIds = strings.Replace(issue.LabelIds, "$"+labelStrId+"|", "", -1)
issue.LabelIDs = strings.Replace(issue.LabelIDs, "$"+labelStrId+"|", "", -1)
isNeedUpdate = true
}
}

2
templates/.VERSION

@ -1 +1 @@
0.6.4.0808 Beta
0.6.4.0809 Beta

14
templates/repo/issue/new.tmpl

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

88
templates/repo/issue/new_form.tmpl

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

1
templates/repo/pulls/compare.tmpl

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

Loading…
Cancel
Save