Bladeren bron

Finish add new milestone

Unknown 10 jaren geleden
bovenliggende
commit
54e95fa367

+ 2 - 1
cmd/web.go

@@ -186,7 +186,8 @@ func runWeb(*cli.Context) {
 		r.Post("/issues/:index", bindIgnErr(auth.CreateIssueForm{}), repo.UpdateIssue)
 		r.Post("/issues/:index", bindIgnErr(auth.CreateIssueForm{}), repo.UpdateIssue)
 		r.Post("/issues/:index/assignee", repo.UpdateAssignee)
 		r.Post("/issues/:index/assignee", repo.UpdateAssignee)
 		r.Get("/issues/milestones", repo.Milestones)
 		r.Get("/issues/milestones", repo.Milestones)
-		r.Get("/issues/milestones/new", repo.NewMilestones)
+		r.Get("/issues/milestones/new", repo.NewMilestone)
+		r.Post("/issues/milestones/new", bindIgnErr(auth.CreateMilestoneForm{}), repo.NewMilestonePost)
 		r.Get("/issues/milestones/edit", repo.UpdateMilestones)
 		r.Get("/issues/milestones/edit", repo.UpdateMilestones)
 		r.Post("/comment/:action", repo.Comment)
 		r.Post("/comment/:action", repo.Comment)
 		r.Get("/releases/new", repo.ReleasesNew)
 		r.Get("/releases/new", repo.ReleasesNew)

+ 1 - 1
gogs.go

@@ -17,7 +17,7 @@ import (
 	"github.com/gogits/gogs/modules/base"
 	"github.com/gogits/gogs/modules/base"
 )
 )
 
 
-const APP_VER = "0.3.3.0511 Alpha"
+const APP_VER = "0.3.3.0512 Alpha"
 
 
 func init() {
 func init() {
 	base.AppVer = APP_VER
 	base.AppVer = APP_VER

+ 39 - 3
models/issue.go

@@ -20,9 +20,9 @@ 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
+	RepoId          int64 `xorm:"INDEX"`
 	Index           int64 // Index in one repository.
 	Index           int64 // Index in one repository.
 	Name            string
 	Name            string
-	RepoId          int64       `xorm:"INDEX"`
 	Repo            *Repository `xorm:"-"`
 	Repo            *Repository `xorm:"-"`
 	PosterId        int64
 	PosterId        int64
 	Poster          *User `xorm:"-"`
 	Poster          *User `xorm:"-"`
@@ -390,7 +390,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
-	Rid             int64 `xorm:"INDEX"`
+	RepoId          int64 `xorm:"INDEX"`
 	Name            string
 	Name            string
 	Color           string
 	Color           string
 	NumIssues       int
 	NumIssues       int
@@ -401,17 +401,53 @@ type Label struct {
 // Milestone represents a milestone of repository.
 // Milestone represents a milestone of repository.
 type Milestone struct {
 type Milestone struct {
 	Id              int64
 	Id              int64
-	Rid             int64 `xorm:"INDEX"`
+	RepoId          int64 `xorm:"INDEX"`
+	Index           int64
 	Name            string
 	Name            string
 	Content         string
 	Content         string
+	RenderedContent string `xorm:"-"`
 	IsClosed        bool
 	IsClosed        bool
 	NumIssues       int
 	NumIssues       int
 	NumClosedIssues int
 	NumClosedIssues int
+	NumOpenIssues   int `xorm:"-"`
 	Completeness    int // Percentage(1-100).
 	Completeness    int // Percentage(1-100).
 	Deadline        time.Time
 	Deadline        time.Time
 	ClosedDate      time.Time
 	ClosedDate      time.Time
 }
 }
 
 
+// CalOpenIssues calculates the open issues of milestone.
+func (m *Milestone) CalOpenIssues() {
+	m.NumOpenIssues = m.NumIssues - m.NumClosedIssues
+}
+
+// NewMilestone creates new milestone of repository.
+func NewMilestone(m *Milestone) (err error) {
+	sess := orm.NewSession()
+	defer sess.Close()
+	if err = sess.Begin(); err != nil {
+		return err
+	}
+
+	if _, err = sess.Insert(m); err != nil {
+		sess.Rollback()
+		return err
+	}
+
+	rawSql := "UPDATE `repository` SET num_milestones = num_milestones + 1 WHERE id = ?"
+	if _, err = sess.Exec(rawSql, m.RepoId); err != nil {
+		sess.Rollback()
+		return err
+	}
+	return sess.Commit()
+}
+
+// GetMilestones returns a list of milestones of given repository and status.
+func GetMilestones(repoId int64, isClosed bool) ([]*Milestone, error) {
+	miles := make([]*Milestone, 0, 10)
+	err := orm.Where("repo_id=?", repoId).And("is_closed=?", isClosed).Find(&miles)
+	return miles, err
+}
+
 // Issue types.
 // Issue types.
 const (
 const (
 	IT_PLAIN  = iota // Pure comment.
 	IT_PLAIN  = iota // Pure comment.

+ 4 - 2
models/models.go

@@ -34,7 +34,8 @@ var (
 func init() {
 func init() {
 	tables = append(tables, new(User), new(PublicKey), new(Repository), new(Watch),
 	tables = append(tables, new(User), new(PublicKey), new(Repository), new(Watch),
 		new(Action), new(Access), new(Issue), new(Comment), new(Oauth2), new(Follow),
 		new(Action), new(Access), new(Issue), new(Comment), new(Oauth2), new(Follow),
-		new(Mirror), new(Release), new(LoginSource), new(Webhook), new(IssueUser))
+		new(Mirror), new(Release), new(LoginSource), new(Webhook), new(IssueUser),
+		new(Milestone))
 }
 }
 
 
 func LoadModelsConfig() {
 func LoadModelsConfig() {
@@ -141,7 +142,7 @@ type Statistic struct {
 	Counter struct {
 	Counter struct {
 		User, PublicKey, Repo, Watch, Action, Access,
 		User, PublicKey, Repo, Watch, Action, Access,
 		Issue, Comment, Mirror, Oauth, Release,
 		Issue, Comment, Mirror, Oauth, Release,
-		LoginSource, Webhook int64
+		LoginSource, Webhook, Milestone int64
 	}
 	}
 }
 }
 
 
@@ -159,6 +160,7 @@ func GetStatistic() (stats Statistic) {
 	stats.Counter.Release, _ = orm.Count(new(Release))
 	stats.Counter.Release, _ = orm.Count(new(Release))
 	stats.Counter.LoginSource, _ = orm.Count(new(LoginSource))
 	stats.Counter.LoginSource, _ = orm.Count(new(LoginSource))
 	stats.Counter.Webhook, _ = orm.Count(new(Webhook))
 	stats.Counter.Webhook, _ = orm.Count(new(Webhook))
+	stats.Counter.Milestone, _ = orm.Count(new(Milestone))
 	return
 	return
 }
 }
 
 

+ 25 - 22
models/repo.go

@@ -92,28 +92,31 @@ func NewRepoContext() {
 
 
 // Repository represents a git repository.
 // Repository represents a git repository.
 type Repository struct {
 type Repository struct {
-	Id              int64
-	OwnerId         int64 `xorm:"unique(s)"`
-	Owner           *User `xorm:"-"`
-	ForkId          int64
-	LowerName       string `xorm:"unique(s) index not null"`
-	Name            string `xorm:"index not null"`
-	Description     string
-	Website         string
-	NumWatches      int
-	NumStars        int
-	NumForks        int
-	NumIssues       int
-	NumClosedIssues int
-	NumOpenIssues   int `xorm:"-"`
-	NumTags         int `xorm:"-"`
-	IsPrivate       bool
-	IsMirror        bool
-	IsBare          bool
-	IsGoget         bool
-	DefaultBranch   string
-	Created         time.Time `xorm:"created"`
-	Updated         time.Time `xorm:"updated"`
+	Id                  int64
+	OwnerId             int64 `xorm:"unique(s)"`
+	Owner               *User `xorm:"-"`
+	ForkId              int64
+	LowerName           string `xorm:"unique(s) index not null"`
+	Name                string `xorm:"index not null"`
+	Description         string
+	Website             string
+	NumWatches          int
+	NumStars            int
+	NumForks            int
+	NumIssues           int
+	NumClosedIssues     int
+	NumOpenIssues       int `xorm:"-"`
+	NumMilestones       int `xorm:"NOT NULL DEFAULT 0"`
+	NumClosedMilestones int `xorm:"NOT NULL DEFAULT 0"`
+	NumOpenMilestones   int `xorm:"-"`
+	NumTags             int `xorm:"-"`
+	IsPrivate           bool
+	IsMirror            bool
+	IsBare              bool
+	IsGoget             bool
+	DefaultBranch       string
+	Created             time.Time `xorm:"created"`
+	Updated             time.Time `xorm:"updated"`
 }
 }
 
 
 func (repo *Repository) GetOwner() (err error) {
 func (repo *Repository) GetOwner() (err error) {

+ 0 - 35
modules/auth/issue.go

@@ -1,35 +0,0 @@
-// Copyright 2014 The Gogs Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-package auth
-
-import (
-	"net/http"
-	"reflect"
-
-	"github.com/go-martini/martini"
-
-	"github.com/gogits/gogs/modules/base"
-	"github.com/gogits/gogs/modules/middleware/binding"
-)
-
-type CreateIssueForm struct {
-	IssueName   string `form:"title" binding:"Required;MaxSize(50)"`
-	MilestoneId int64  `form:"milestoneid"`
-	AssigneeId  int64  `form:"assigneeid"`
-	Labels      string `form:"labels"`
-	Content     string `form:"content"`
-}
-
-func (f *CreateIssueForm) Name(field string) string {
-	names := map[string]string{
-		"IssueName": "Issue name",
-	}
-	return names[field]
-}
-
-func (f *CreateIssueForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) {
-	data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData)
-	validate(errors, data, f)
-}

+ 0 - 0
modules/auth/setting.go → modules/auth/publickey.go


+ 0 - 36
modules/auth/release.go

@@ -1,36 +0,0 @@
-// Copyright 2014 The Gogs Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-package auth
-
-import (
-	"net/http"
-	"reflect"
-
-	"github.com/go-martini/martini"
-
-	"github.com/gogits/gogs/modules/base"
-	"github.com/gogits/gogs/modules/middleware/binding"
-)
-
-type NewReleaseForm struct {
-	TagName    string `form:"tag_name" binding:"Required"`
-	Title      string `form:"title" binding:"Required"`
-	Content    string `form:"content" binding:"Required"`
-	Prerelease bool   `form:"prerelease"`
-}
-
-func (f *NewReleaseForm) Name(field string) string {
-	names := map[string]string{
-		"TagName": "Tag name",
-		"Title":   "Release title",
-		"Content": "Release content",
-	}
-	return names[field]
-}
-
-func (f *NewReleaseForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) {
-	data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData)
-	validate(errors, data, f)
-}

+ 95 - 1
modules/auth/repo.go

@@ -14,6 +14,13 @@ import (
 	"github.com/gogits/gogs/modules/middleware/binding"
 	"github.com/gogits/gogs/modules/middleware/binding"
 )
 )
 
 
+// __________                           .__  __
+// \______   \ ____ ______   ____  _____|__|/  |_  ___________ ___.__.
+//  |       _// __ \\____ \ /  _ \/  ___/  \   __\/  _ \_  __ <   |  |
+//  |    |   \  ___/|  |_> >  <_> )___ \|  ||  | (  <_> )  | \/\___  |
+//  |____|_  /\___  >   __/ \____/____  >__||__|  \____/|__|   / ____|
+//         \/     \/|__|              \/                       \/
+
 type CreateRepoForm struct {
 type CreateRepoForm struct {
 	RepoName    string `form:"repo" binding:"Required;AlphaDash;MaxSize(100)"`
 	RepoName    string `form:"repo" binding:"Required;AlphaDash;MaxSize(100)"`
 	Private     bool   `form:"private"`
 	Private     bool   `form:"private"`
@@ -63,7 +70,7 @@ func (f *MigrateRepoForm) Validate(errors *binding.Errors, req *http.Request, co
 type RepoSettingForm struct {
 type RepoSettingForm struct {
 	RepoName    string `form:"name" binding:"Required;AlphaDash;MaxSize(100)"`
 	RepoName    string `form:"name" binding:"Required;AlphaDash;MaxSize(100)"`
 	Description string `form:"desc" binding:"MaxSize(100)"`
 	Description string `form:"desc" binding:"MaxSize(100)"`
-	Website     string `form:"url" binding:"Url;MaxSize(100)"`
+	Website     string `form:"site" binding:"Url;MaxSize(100)"`
 	Branch      string `form:"branch"`
 	Branch      string `form:"branch"`
 	Interval    int    `form:"interval"`
 	Interval    int    `form:"interval"`
 	Private     bool   `form:"private"`
 	Private     bool   `form:"private"`
@@ -84,6 +91,13 @@ func (f *RepoSettingForm) Validate(errors *binding.Errors, req *http.Request, co
 	validate(errors, data, f)
 	validate(errors, data, f)
 }
 }
 
 
+//  __      __      ___.   .__    .__            __
+// /  \    /  \ ____\_ |__ |  |__ |  |__   ____ |  | __
+// \   \/\/   // __ \| __ \|  |  \|  |  \ /  _ \|  |/ /
+//  \        /\  ___/| \_\ \   Y  \   Y  (  <_> )    <
+//   \__/\  /  \___  >___  /___|  /___|  /\____/|__|_ \
+//        \/       \/    \/     \/     \/            \/
+
 type NewWebhookForm struct {
 type NewWebhookForm struct {
 	Url         string `form:"url" binding:"Required;Url"`
 	Url         string `form:"url" binding:"Required;Url"`
 	ContentType string `form:"content_type" binding:"Required"`
 	ContentType string `form:"content_type" binding:"Required"`
@@ -104,3 +118,83 @@ func (f *NewWebhookForm) Validate(errors *binding.Errors, req *http.Request, con
 	data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData)
 	data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData)
 	validate(errors, data, f)
 	validate(errors, data, f)
 }
 }
+
+// .___
+// |   | ______ ________ __   ____
+// |   |/  ___//  ___/  |  \_/ __ \
+// |   |\___ \ \___ \|  |  /\  ___/
+// |___/____  >____  >____/  \___  >
+//          \/     \/            \/
+
+type CreateIssueForm struct {
+	IssueName   string `form:"title" binding:"Required;MaxSize(50)"`
+	MilestoneId int64  `form:"milestoneid"`
+	AssigneeId  int64  `form:"assigneeid"`
+	Labels      string `form:"labels"`
+	Content     string `form:"content"`
+}
+
+func (f *CreateIssueForm) Name(field string) string {
+	names := map[string]string{
+		"IssueName": "Issue name",
+	}
+	return names[field]
+}
+
+func (f *CreateIssueForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) {
+	data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData)
+	validate(errors, data, f)
+}
+
+//    _____  .__.__                   __
+//   /     \ |__|  |   ____   _______/  |_  ____   ____   ____
+//  /  \ /  \|  |  | _/ __ \ /  ___/\   __\/  _ \ /    \_/ __ \
+// /    Y    \  |  |_\  ___/ \___ \  |  | (  <_> )   |  \  ___/
+// \____|__  /__|____/\___  >____  > |__|  \____/|___|  /\___  >
+//         \/             \/     \/                   \/     \/
+
+type CreateMilestoneForm struct {
+	Title    string `form:"title" binding:"Required;MaxSize(50)"`
+	Content  string `form:"content"`
+	Deadline string `form:"due_date"`
+}
+
+func (f *CreateMilestoneForm) Name(field string) string {
+	names := map[string]string{
+		"Title": "Milestone name",
+	}
+	return names[field]
+}
+
+func (f *CreateMilestoneForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) {
+	data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData)
+	validate(errors, data, f)
+}
+
+// __________       .__
+// \______   \ ____ |  |   ____ _____    ______ ____
+//  |       _// __ \|  | _/ __ \\__  \  /  ___// __ \
+//  |    |   \  ___/|  |_\  ___/ / __ \_\___ \\  ___/
+//  |____|_  /\___  >____/\___  >____  /____  >\___  >
+//         \/     \/          \/     \/     \/     \/
+
+type NewReleaseForm struct {
+	TagName    string `form:"tag_name" binding:"Required"`
+	Title      string `form:"title" binding:"Required"`
+	Content    string `form:"content" binding:"Required"`
+	Prerelease bool   `form:"prerelease"`
+}
+
+func (f *NewReleaseForm) Name(field string) string {
+	names := map[string]string{
+		"TagName": "Tag name",
+		"Title":   "Release title",
+		"Content": "Release content",
+	}
+	return names[field]
+}
+
+func (f *NewReleaseForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) {
+	data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData)
+	validate(errors, data, f)
+}

+ 1 - 0
modules/middleware/repo.go

@@ -128,6 +128,7 @@ func RepoAssignment(redirect bool, args ...bool) martini.Handler {
 		}
 		}
 
 
 		repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
 		repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
+		repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones
 		ctx.Repo.Repository = repo
 		ctx.Repo.Repository = repo
 		ctx.Data["IsBareRepo"] = ctx.Repo.Repository.IsBare
 		ctx.Data["IsBareRepo"] = ctx.Repo.Repository.IsBare
 
 

+ 54 - 6
routers/repo/issue.go

@@ -8,6 +8,7 @@ import (
 	"fmt"
 	"fmt"
 	"net/url"
 	"net/url"
 	"strings"
 	"strings"
+	"time"
 
 
 	"github.com/Unknwon/com"
 	"github.com/Unknwon/com"
 	"github.com/go-martini/martini"
 	"github.com/go-martini/martini"
@@ -144,9 +145,9 @@ func CreateIssuePost(ctx *middleware.Context, params martini.Params, form auth.C
 		form.AssigneeId = 0
 		form.AssigneeId = 0
 	}
 	}
 	issue := &models.Issue{
 	issue := &models.Issue{
+		RepoId:      ctx.Repo.Repository.Id,
 		Index:       int64(ctx.Repo.Repository.NumIssues) + 1,
 		Index:       int64(ctx.Repo.Repository.NumIssues) + 1,
 		Name:        form.IssueName,
 		Name:        form.IssueName,
-		RepoId:      ctx.Repo.Repository.Id,
 		PosterId:    ctx.User.Id,
 		PosterId:    ctx.User.Id,
 		MilestoneId: form.MilestoneId,
 		MilestoneId: form.MilestoneId,
 		AssigneeId:  form.AssigneeId,
 		AssigneeId:  form.AssigneeId,
@@ -385,7 +386,6 @@ func Comment(ctx *middleware.Context, params martini.Params) {
 		return
 		return
 	}
 	}
 
 
-	// TODO: check collaborators
 	// Check if issue owner changes the status of issue.
 	// Check if issue owner changes the status of issue.
 	var newStatus string
 	var newStatus string
 	if ctx.Repo.IsOwner || issue.PosterId == ctx.User.Id {
 	if ctx.Repo.IsOwner || issue.PosterId == ctx.User.Id {
@@ -488,17 +488,66 @@ func Milestones(ctx *middleware.Context) {
 	ctx.Data["IsRepoToolbarIssues"] = true
 	ctx.Data["IsRepoToolbarIssues"] = true
 	ctx.Data["IsRepoToolbarIssuesList"] = true
 	ctx.Data["IsRepoToolbarIssuesList"] = true
 
 
+	isShowClosed := ctx.Query("state") == "closed"
+
+	miles, err := models.GetMilestones(ctx.Repo.Repository.Id, isShowClosed)
+	if err != nil {
+		ctx.Handle(500, "issue.Milestones(GetMilestones)", err)
+		return
+	}
+	for _, m := range miles {
+		m.RenderedContent = string(base.RenderSpecialLink([]byte(m.Content), ctx.Repo.RepoLink))
+		m.CalOpenIssues()
+	}
+	ctx.Data["Milestones"] = miles
+
+	if isShowClosed {
+		ctx.Data["State"] = "closed"
+	} else {
+		ctx.Data["State"] = "open"
+	}
 	ctx.HTML(200, "issue/milestone")
 	ctx.HTML(200, "issue/milestone")
 }
 }
 
 
-func NewMilestones(ctx *middleware.Context) {
-	ctx.Data["Title"] = "New Milestones"
+func NewMilestone(ctx *middleware.Context) {
+	ctx.Data["Title"] = "New Milestone"
 	ctx.Data["IsRepoToolbarIssues"] = true
 	ctx.Data["IsRepoToolbarIssues"] = true
 	ctx.Data["IsRepoToolbarIssuesList"] = true
 	ctx.Data["IsRepoToolbarIssuesList"] = true
-
 	ctx.HTML(200, "issue/milestone_new")
 	ctx.HTML(200, "issue/milestone_new")
 }
 }
 
 
+func NewMilestonePost(ctx *middleware.Context, form auth.CreateMilestoneForm) {
+	ctx.Data["Title"] = "New Milestone"
+	ctx.Data["IsRepoToolbarIssues"] = true
+	ctx.Data["IsRepoToolbarIssuesList"] = true
+
+	var deadline time.Time
+	var err error
+	if len(form.Deadline) == 0 {
+		deadline = time.Now().AddDate(100, 0, 0)
+	} else {
+		deadline, err = time.Parse("01/02/2006", form.Deadline)
+		if err != nil {
+			ctx.Handle(500, "issue.NewMilestonePost(time.Parse)", err)
+			return
+		}
+	}
+
+	m := &models.Milestone{
+		RepoId:   ctx.Repo.Repository.Id,
+		Index:    int64(ctx.Repo.Repository.NumMilestones) + 1,
+		Name:     form.Title,
+		Content:  form.Content,
+		Deadline: deadline,
+	}
+	if err = models.NewMilestone(m); err != nil {
+		ctx.Handle(500, "issue.NewMilestonePost(NewMilestone)", err)
+		return
+	}
+
+	ctx.Redirect(ctx.Repo.RepoLink + "/issues/milestones")
+}
+
 func UpdateMilestones(ctx *middleware.Context) {
 func UpdateMilestones(ctx *middleware.Context) {
 	ctx.Data["Title"] = "Update Milestones"
 	ctx.Data["Title"] = "Update Milestones"
 	ctx.Data["IsRepoToolbarIssues"] = true
 	ctx.Data["IsRepoToolbarIssues"] = true
@@ -506,4 +555,3 @@ func UpdateMilestones(ctx *middleware.Context) {
 
 
 	ctx.HTML(200, "issue/milestone_edit")
 	ctx.HTML(200, "issue/milestone_edit")
 }
 }
-

+ 1 - 1
templates/admin/dashboard.tmpl

@@ -10,7 +10,7 @@
             </div>
             </div>
 
 
             <div class="panel-body">
             <div class="panel-body">
-                Gogs database has <b>{{.Stats.Counter.User}}</b> users, <b>{{.Stats.Counter.PublicKey}}</b> SSH keys, <b>{{.Stats.Counter.Repo}}</b> repositories, <b>{{.Stats.Counter.Watch}}</b> watches, <b>{{.Stats.Counter.Action}}</b> actions, <b>{{.Stats.Counter.Access}}</b> accesses, <b>{{.Stats.Counter.Issue}}</b> issues, <b>{{.Stats.Counter.Comment}}</b> comments, <b>{{.Stats.Counter.Mirror}}</b> mirrors, <b>{{.Stats.Counter.Oauth}}</b> oauthes, <b>{{.Stats.Counter.Release}}</b> releases, <b>{{.Stats.Counter.LoginSource}}</b> login sources, <b>{{.Stats.Counter.Webhook}}</b> webhooks.
+                Gogs database has <b>{{.Stats.Counter.User}}</b> users, <b>{{.Stats.Counter.PublicKey}}</b> SSH keys, <b>{{.Stats.Counter.Repo}}</b> repositories, <b>{{.Stats.Counter.Watch}}</b> watches, <b>{{.Stats.Counter.Action}}</b> actions, <b>{{.Stats.Counter.Access}}</b> accesses, <b>{{.Stats.Counter.Issue}}</b> issues, <b>{{.Stats.Counter.Comment}}</b> comments, <b>{{.Stats.Counter.Mirror}}</b> mirrors, <b>{{.Stats.Counter.Oauth}}</b> oauthes, <b>{{.Stats.Counter.Release}}</b> releases, <b>{{.Stats.Counter.LoginSource}}</b> login sources, <b>{{.Stats.Counter.Webhook}}</b> webhooks, <b>{{.Stats.Counter.Milestone}}</b> milestones.
             </div>
             </div>
         </div>
         </div>
 
 

+ 13 - 27
templates/issue/milestone.tmpl

@@ -6,10 +6,8 @@
     <div id="issue">
     <div id="issue">
         <div class="col-md-3 filter-list">
         <div class="col-md-3 filter-list">
             <ul class="list-unstyled">
             <ul class="list-unstyled">
-                <li><a href="{{.RepoLink}}/issues/milestones" class="active">Open Milestones <strong class="pull-right">1</strong></a></li>
-                <!-- <li><a href="#">Assigned to you</a></li> -->
-                <li><a href="{{.RepoLink}}/issues/milestones">Close Milestones <strong class="pull-right">0</strong></a></li>
-                <!-- <li><a href="#">Mentioned</a></li> -->
+                <li><a href="{{.RepoLink}}/issues/milestones"{{if eq .State "open"}} class="active"{{end}}>Open Milestones <strong class="pull-right">{{.Repository.NumOpenMilestones}}</strong></a></li>
+                <li><a href="{{.RepoLink}}/issues/milestones?state=closed"{{if eq .State "closed"}} class="active"{{end}}>Close Milestones <strong class="pull-right">{{.Repository.NumClosedMilestones}}</strong></a></li>
             </ul>
             </ul>
             <hr/>
             <hr/>
             <a href="{{.RepoLink}}/issues/milestones/new" class="text-center">
             <a href="{{.RepoLink}}/issues/milestones/new" class="text-center">
@@ -18,34 +16,22 @@
         </div>
         </div>
         <div class="col-md-9">
         <div class="col-md-9">
             <div class="milestones list-group">
             <div class="milestones list-group">
+                {{range .Milestones}}
                 <div class="list-group-item milestone-item">
                 <div class="list-group-item milestone-item">
-                    <h4 class="title pull-left"><a href="#">Milestone Title</a></h4>
-                    <span class="issue-open label label-success">12</span>
-                    <span class="issue-close label label-warning">2</span>
+                    <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">{{.NumClosedIssues}}</span>
+                    <span class="issue-close label label-warning">{{.NumOpenIssues}}</span>
                     <p class="actions pull-right">
                     <p class="actions pull-right">
-                        <a href="{{.RepoLink}}/issues/milestones/edit">Edit</a>
-                        <a href="#">Open</a>
-                        <a href="#">Close</a>
-                        <a class="text-danger" href="#">Delete</a>
-                        <a href="#">Issues</a>
+                        <!-- <a href="{{$.RepoLink}}/issues/milestones/{{.Index}}/edit">Edit</a> -->
+                        <!-- <a href="#">Open</a>
+                        <a href="#">Close</a> -->
+                        <!-- <a class="text-danger" href="#">Delete</a> -->
+                        <a href="{{$.RepoLink}}/issues?milestone={{.Index}}{{if .IsClosed}}&state=closed{{end}}">Issues</a>
                     </p>
                     </p>
                     <hr/>
                     <hr/>
-                    <p class="description">In this version of release, users are able to register and log in/out on Gogs, setting up SSH keys and do most of Git operations through SSH with public repositories. And Web UI only for view of Git data, no extra features are supported.</p>
-                </div>
-                <div class="list-group-item milestone-item">
-                    <h4 class="title pull-left"><a href="#">Milestone Title</a></h4>
-                    <span class="issue-open label label-success">12</span>
-                    <span class="issue-close label label-warning">2</span>
-                    <p class="actions pull-right">
-                        <a href="{{.RepoLink}}/issues/milestones/edit">Edit</a>
-                        <a href="#">Open</a>
-                        <a href="#">Close</a>
-                        <a class="text-danger" href="#">Delete</a>
-                        <a href="#">Issues</a>
-                    </p>
-                    <hr/>
-                    <p class="description">In this version of release, users are able to register and log in/out on Gogs, setting up SSH keys and do most of Git operations through SSH with public repositories. And Web UI only for view of Git data, no extra features are supported.</p>
+                    <p class="description">{{.RenderedContent | str2html}}</p>
                 </div>
                 </div>
+                {{end}}
             </div>
             </div>
         </div>
         </div>
     </div>
     </div>

+ 1 - 1
templates/issue/milestone_new.tmpl

@@ -34,7 +34,7 @@
                 <div class="text-right panel-body">
                 <div class="text-right panel-body">
                     <div class="form-group">
                     <div class="form-group">
                         <input type="hidden" value="id" name="repo-id"/>
                         <input type="hidden" value="id" name="repo-id"/>
-                        <button class="btn-success btn">Create new issue</button>
+                        <button class="btn-success btn">Create new milestone</button>
                     </div>
                     </div>
                 </div>
                 </div>
             </div>
             </div>