milestone: edit

release/v0.9
Unknwon 9 years ago
parent cf90312b8f
commit 74bd6b939c

@ -427,8 +427,8 @@ func runWeb(ctx *cli.Context) {
m.Group("/milestones", func() {
m.Get("/new", repo.NewMilestone)
m.Post("/new", bindIgnErr(auth.CreateMilestoneForm{}), repo.NewMilestonePost)
m.Get("/:index/edit", repo.MilestoneActions)
m.Post("/:index/edit", bindIgnErr(auth.CreateMilestoneForm{}), repo.UpdateMilestonePost)
m.Get("/:index/edit", repo.EditMilestone)
m.Post("/:index/edit", bindIgnErr(auth.CreateMilestoneForm{}), repo.EditMilestonePost)
m.Get("/:index/:action", repo.MilestoneActions)
}, reqRepoAdmin)

@ -404,9 +404,14 @@ milestones.create = Create Milestone
milestones.title = Title
milestones.desc = Description
milestones.due_date = Due Date (optional)
milestones.clear = clear
milestones.clear = Clear
milestones.invalid_due_date_format = Due date format is invalid, must be 'mm/dd/year'.
milestones.create_success = Milestone '%s' has been created successfully!
milestones.edit = Edit Milestone
milestones.edit_subheader = Use better description for milestones so people won't be confused.
milestones.cancel = Cancel
milestones.modify = Modify Milestone
milestones.edit_success = Changes of milestone '%s' has been saved successfully!
settings = Settings
settings.options = Options

@ -134,3 +134,24 @@ func IsErrRepoNotExist(err error) bool {
func (err ErrRepoNotExist) Error() string {
return fmt.Sprintf("repository does not exist [id: %d, uid: %d, name: %s]", err.ID, err.UID, err.Name)
}
// _____ .__.__ __
// / \ |__| | ____ _______/ |_ ____ ____ ____
// / \ / \| | | _/ __ \ / ___/\ __\/ _ \ / \_/ __ \
// / Y \ | |_\ ___/ \___ \ | | ( <_> ) | \ ___/
// \____|__ /__|____/\___ >____ > |__| \____/|___| /\___ >
// \/ \/ \/ \/ \/
type ErrMilestoneNotExist struct {
ID int64
Index int64
}
func IsErrMilestoneNotExist(err error) bool {
_, ok := err.(ErrMilestoneNotExist)
return ok
}
func (err ErrMilestoneNotExist) Error() string {
return fmt.Sprintf("milestone does not exist [id: %d, index: %d]", err.ID, err.Index)
}

@ -23,7 +23,6 @@ import (
var (
ErrIssueNotExist = errors.New("Issue does not exist")
ErrLabelNotExist = errors.New("Label does not exist")
ErrMilestoneNotExist = errors.New("Milestone does not exist")
ErrWrongIssueCounter = errors.New("Invalid number of issues for this milestone")
ErrAttachmentNotExist = errors.New("Attachment does not exist")
ErrAttachmentNotLinked = errors.New("Attachment does not belong to this issue")
@ -691,7 +690,7 @@ func MilestoneById(id int64) (*Milestone, error) {
if err != nil {
return nil, err
} else if !has {
return nil, ErrMilestoneNotExist
return nil, ErrMilestoneNotExist{id, 0}
}
return m, nil
}
@ -703,7 +702,7 @@ func GetMilestoneByIndex(repoId, idx int64) (*Milestone, error) {
if err != nil {
return nil, err
} else if !has {
return nil, ErrMilestoneNotExist
return nil, ErrMilestoneNotExist{0, idx}
}
return m, nil
}

File diff suppressed because one or more lines are too long

@ -88,9 +88,9 @@ function initRepository() {
inline: true,
timepicker: false,
startDate: $datepicker.data('start-date'),
formatDate: 'm/d/Y',
formatDate: 'Y-m-d',
onSelectDate: function (ct) {
$('#deadline').val(ct.dateFormat('m/d/Y'));
$('#deadline').val(ct.dateFormat('Y-m-d'));
}
});
$('#clear-date').click(function () {

@ -351,21 +351,21 @@ func ViewIssue(ctx *middleware.Context) {
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, idx)
if err != nil {
if err == models.ErrIssueNotExist {
ctx.Handle(404, "issue.ViewIssue(GetIssueByIndex)", err)
ctx.Handle(404, "GetIssueByIndex", err)
} else {
ctx.Handle(500, "issue.ViewIssue(GetIssueByIndex)", err)
ctx.Handle(500, "GetIssueByIndex", err)
}
return
}
// Get labels.
if err = issue.GetLabels(); err != nil {
ctx.Handle(500, "issue.ViewIssue(GetLabels)", err)
ctx.Handle(500, "GetLabels", err)
return
}
labels, err := models.GetLabels(ctx.Repo.Repository.Id)
if err != nil {
ctx.Handle(500, "issue.ViewIssue(GetLabels.2)", err)
ctx.Handle(500, "GetLabels.2", err)
return
}
checkLabels(issue.Labels, labels)
@ -375,10 +375,10 @@ func ViewIssue(ctx *middleware.Context) {
if issue.MilestoneId > 0 {
ctx.Data["Milestone"], err = models.MilestoneById(issue.MilestoneId)
if err != nil {
if err == models.ErrMilestoneNotExist {
log.Warn("issue.ViewIssue(GetMilestoneById): %v", err)
if models.IsErrMilestoneNotExist(err) {
log.Warn("GetMilestoneById: %v", err)
} else {
ctx.Handle(500, "issue.ViewIssue(GetMilestoneById)", err)
ctx.Handle(500, "GetMilestoneById", err)
return
}
}
@ -387,36 +387,36 @@ func ViewIssue(ctx *middleware.Context) {
// Get all milestones.
ctx.Data["OpenMilestones"], err = models.GetMilestones(ctx.Repo.Repository.Id, -1, false)
if err != nil {
ctx.Handle(500, "issue.ViewIssue(GetMilestones.1): %v", err)
ctx.Handle(500, "GetMilestones.1: %v", err)
return
}
ctx.Data["ClosedMilestones"], err = models.GetMilestones(ctx.Repo.Repository.Id, -1, true)
if err != nil {
ctx.Handle(500, "issue.ViewIssue(GetMilestones.2): %v", err)
ctx.Handle(500, "GetMilestones.2: %v", err)
return
}
// Get all collaborators.
ctx.Data["Collaborators"], err = ctx.Repo.Repository.GetCollaborators()
if err != nil {
ctx.Handle(500, "issue.CreateIssue(GetCollaborators)", err)
ctx.Handle(500, "GetCollaborators", err)
return
}
if ctx.IsSigned {
// Update issue-user.
if err = models.UpdateIssueUserPairByRead(ctx.User.Id, issue.ID); err != nil {
ctx.Handle(500, "issue.ViewIssue(UpdateIssueUserPairByRead): %v", err)
ctx.Handle(500, "UpdateIssueUserPairByRead: %v", err)
return
}
}
// Get poster and Assignee.
if err = issue.GetPoster(); err != nil {
ctx.Handle(500, "issue.ViewIssue(GetPoster): %v", err)
ctx.Handle(500, "GetPoster: %v", err)
return
} else if err = issue.GetAssignee(); err != nil {
ctx.Handle(500, "issue.ViewIssue(GetAssignee): %v", err)
ctx.Handle(500, "GetAssignee: %v", err)
return
}
issue.RenderedContent = string(base.RenderMarkdown([]byte(issue.Content), ctx.Repo.RepoLink))
@ -424,7 +424,7 @@ func ViewIssue(ctx *middleware.Context) {
// Get comments.
comments, err := models.GetIssueComments(issue.ID)
if err != nil {
ctx.Handle(500, "issue.ViewIssue(GetIssueComments): %v", err)
ctx.Handle(500, "GetIssueComments: %v", err)
return
}
@ -432,7 +432,7 @@ func ViewIssue(ctx *middleware.Context) {
for i := range comments {
u, err := models.GetUserById(comments[i].PosterId)
if err != nil {
ctx.Handle(500, "issue.ViewIssue(GetUserById.2): %v", err)
ctx.Handle(500, "GetUserById.2: %v", err)
return
}
comments[i].Poster = u
@ -1051,8 +1051,70 @@ func NewMilestonePost(ctx *middleware.Context, form auth.CreateMilestoneForm) {
ctx.Redirect(ctx.Repo.RepoLink + "/milestones")
}
func EditMilestone(ctx *middleware.Context) {}
func EditMilestonePost(ctx *middleware.Context) {}
func EditMilestone(ctx *middleware.Context) {
ctx.Data["Title"] = ctx.Tr("repo.milestones.edit")
ctx.Data["PageIsMilestones"] = true
ctx.Data["PageIsEditMilestone"] = true
ctx.Data["DateLang"] = setting.DateLang(ctx.Locale.Language())
m, err := models.GetMilestoneByIndex(ctx.Repo.Repository.Id, ctx.ParamsInt64(":index"))
if err != nil {
if models.IsErrMilestoneNotExist(err) {
ctx.Handle(404, "GetMilestoneByIndex", nil)
} else {
ctx.Handle(500, "GetMilestoneByIndex", err)
}
return
}
ctx.Data["title"] = m.Name
ctx.Data["content"] = m.Content
if len(m.DeadlineString) > 0 {
ctx.Data["deadline"] = m.DeadlineString
}
ctx.HTML(200, MILESTONE_NEW)
}
func EditMilestonePost(ctx *middleware.Context, form auth.CreateMilestoneForm) {
ctx.Data["Title"] = ctx.Tr("repo.milestones.edit")
ctx.Data["PageIsMilestones"] = true
ctx.Data["PageIsEditMilestone"] = true
ctx.Data["DateLang"] = setting.DateLang(ctx.Locale.Language())
if ctx.HasError() {
ctx.HTML(200, MILESTONE_NEW)
return
}
if len(form.Deadline) == 0 {
form.Deadline = "9999-12-31"
}
deadline, err := time.Parse("2006-01-02", form.Deadline)
if err != nil {
ctx.Data["Err_Deadline"] = true
ctx.RenderWithErr(ctx.Tr("repo.milestones.invalid_due_date_format"), MILESTONE_NEW, &form)
return
}
m, err := models.GetMilestoneByIndex(ctx.Repo.Repository.Id, ctx.ParamsInt64(":index"))
if err != nil {
if models.IsErrMilestoneNotExist(err) {
ctx.Handle(404, "GetMilestoneByIndex", nil)
} else {
ctx.Handle(500, "GetMilestoneByIndex", err)
}
return
}
m.Name = form.Title
m.Content = form.Content
m.Deadline = deadline
if err = models.UpdateMilestone(m); err != nil {
ctx.Handle(500, "UpdateMilestone", err)
return
}
ctx.Flash.Success(ctx.Tr("repo.milestones.edit_success", m.Name))
ctx.Redirect(ctx.Repo.RepoLink + "/milestones")
}
func MilestoneActions(ctx *middleware.Context) {
ctx.Data["Title"] = "Update Milestone"
@ -1067,7 +1129,7 @@ func MilestoneActions(ctx *middleware.Context) {
mile, err := models.GetMilestoneByIndex(ctx.Repo.Repository.Id, idx)
if err != nil {
if err == models.ErrMilestoneNotExist {
if models.IsErrMilestoneNotExist(err) {
ctx.Handle(404, "GetMilestoneByIndex", err)
} else {
ctx.Handle(500, "GetMilestoneByIndex", err)
@ -1125,7 +1187,7 @@ func UpdateMilestonePost(ctx *middleware.Context, form auth.CreateMilestoneForm)
mile, err := models.GetMilestoneByIndex(ctx.Repo.Repository.Id, idx)
if err != nil {
if err == models.ErrMilestoneNotExist {
if models.IsErrMilestoneNotExist(err) {
ctx.Handle(404, "GetMilestoneByIndex", err)
} else {
ctx.Handle(500, "GetMilestoneByIndex", err)

@ -8,8 +8,13 @@
<div class="ui divider"></div>
<div class="sixteen wide column page grid">
<h2 class="ui dividing header">
{{if .PageIsEditMilestone}}
{{.i18n.Tr "repo.milestones.edit"}}
<div class="sub header">{{.i18n.Tr "repo.milestones.edit_subheader"}}</div>
{{else}}
{{.i18n.Tr "repo.milestones.new"}}
<div class="sub header">{{.i18n.Tr "repo.milestones.new_subheader"}}</div>
{{end}}
</h2>
<form class="ui form grid" action="{{.Link}}" method="post">
{{.CsrfTokenHtml}}
@ -21,7 +26,7 @@
<div class="eleven wide column">
<div class="field {{if .Err_Title}}error{{end}}">
<label>{{.i18n.Tr "repo.milestones.title"}}</label>
<input name="title" placeholder="{{.i18n.Tr "repo.milestones.title"}}" value="{{.title}}" required>
<input name="title" placeholder="{{.i18n.Tr "repo.milestones.title"}}" value="{{.title}}" autofocus required>
</div>
<div class="field">
<label>{{.i18n.Tr "repo.milestones.desc"}}</label>
@ -41,9 +46,18 @@
</div>
</div>
<div class="ui divider"></div>
{{if .PageIsEditMilestone}}
<button class="ui right green button">
{{.i18n.Tr "repo.milestones.modify"}}
</button>
<a class="ui right blue basic button" href="{{.RepoLink}}/milestones">
{{.i18n.Tr "repo.milestones.cancel"}}
</a>
{{else}}
<button class="ui right green button">
{{.i18n.Tr "repo.milestones.create"}}
</button>
{{end}}
</form>
</div>
</div>

@ -1,43 +0,0 @@
{{template "base/head_old" .}}
{{template "base/navbar" .}}
{{template "repo/nav" .}}
{{template "repo/toolbar" .}}
<div id="body" class="container">
<div id="issue">
<div class="col-md-3 filter-list">
<ul class="list-unstyled">
<li><a href="{{.RepoLink}}/milestones"{{if eq .State "open"}} class="active"{{end}}>Open Milestones <strong class="pull-right">{{.Repository.NumOpenMilestones}}</strong></a></li>
<li><a href="{{.RepoLink}}/milestones?state=closed"{{if eq .State "closed"}} class="active"{{end}}>Close Milestones <strong class="pull-right">{{.Repository.NumClosedMilestones}}</strong></a></li>
</ul>
<hr/>
<a href="{{.RepoLink}}/milestones/new" class="text-center">
<button class="btn btn-default btn-block">Create new milestone</button>
</a>
</div>
<div class="col-md-9">
<div class="milestones list-group">
{{range .Milestones}}
<div class="list-group-item milestone-item">
<h4 class="title pull-left"><a href="{{$.RepoLink}}/issues?milestone={{.Index}}{{if .IsClosed}}&state=closed{{end}}">{{.Name}}</a></h4>
<span class="issue-open label label-success">{{.NumOpenIssues}}</span>
<span class="issue-close label label-warning">{{.NumClosedIssues}}</span>
<p class="actions pull-right">
<a href="{{$.RepoLink}}/milestones/{{.Index}}/edit">Edit</a>
{{if .IsClosed}}
<a href="{{$.RepoLink}}/milestones/{{.Index}}/open">Open</a>
{{else}}
<a href="{{$.RepoLink}}/milestones/{{.Index}}/close">Close</a>
{{end}}
<a class="text-danger" href="{{$.RepoLink}}/milestones/{{.Index}}/delete">Delete</a>
<a href="{{$.RepoLink}}/issues?milestone={{.Index}}{{if .IsClosed}}&state=closed{{end}}">Issues</a>
</p>
<hr/>
<p class="description">{{.RenderedContent | Str2html}}</p>
</div>
{{end}}
</div>
</div>
</div>
</div>
</div>
{{template "base/footer_old" .}}
Loading…
Cancel
Save