完成分页显示代码仓库列表

This commit is contained in:
巴拉迪维 2022-04-18 19:19:46 +08:00
parent 9cc66a05f4
commit 80143f8309
13 changed files with 217 additions and 38 deletions

View File

@ -67,6 +67,27 @@ $(document).ready(function() {
}); });
}); });
function successToast(message) {
$('body').toast({
class: 'success',
displayTime: 2500,
message: message,
showIcon:'exclamation circle',
showProgress: 'bottom',
onHidden: function() {location.reload()}
});
}
function errorToast(message) {
$('body').toast({
class: 'error',
displayTime: 2500,
message: message,
showIcon:'exclamation circle',
showProgress: 'bottom'
});
}
function GetGiteeToken(form) { function GetGiteeToken(form) {
authForm = $('#form-gitee-authorize'); authForm = $('#form-gitee-authorize');
var data = JSON.stringify( { var data = JSON.stringify( {

View File

@ -8,8 +8,52 @@
package controller package controller
import "github.com/gin-gonic/gin" import (
"log"
"net/http"
"repostats/storage"
gitee_storage "repostats/storage/gitee"
"strconv"
"github.com/gin-gonic/gin"
)
func ReposPage(ctx *gin.Context) { func ReposPage(ctx *gin.Context) {
strPage := ctx.DefaultQuery("page", strconv.Itoa(storage.DEFAULT_PAGE_NUMBER))
strSize := ctx.DefaultQuery("size", strconv.Itoa(storage.DEFAULT_PAGE_SIZE))
page, err := strconv.Atoi(strPage)
if err != nil || page < storage.DEFAULT_PAGE_NUMBER {
page = storage.DEFAULT_PAGE_NUMBER
}
size, err := strconv.Atoi(strSize)
if err != nil || size < storage.DEFAULT_PAGE_SIZE || size > storage.DEFAULT_MAX_PAGE_SIZE {
size = storage.DEFAULT_PAGE_SIZE
}
count, err1 := gitee_storage.FindTotalReposCount()
repos, err2 := gitee_storage.FindPagedRepos(page, size)
if err1 != nil || err2 != nil {
log.Printf("error1 %s \t error2 %s", err1, err2)
ctx.HTML(http.StatusOK, "repos.html", gin.H{
"title": "代码仓库列表 - RepoStats",
"current_url": ctx.Request.URL.Path,
"error": "内部错误,请联系管理员",
})
return
}
ctx.HTML(http.StatusOK, "repos.html", gin.H{
"title": "代码仓库列表 - RepoStats",
"current_url": ctx.Request.URL.Path,
"repos": repos,
"total_item": count,
"current_page": page,
"page_size": size,
"first_page": page == 1,
"last_page": page >= (count/size)+1,
})
} }

15
go.mod
View File

@ -3,9 +3,16 @@ module repostats
go 1.16 go 1.16
require ( require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver v1.5.0 // indirect
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
github.com/gin-gonic/gin v1.7.7 github.com/gin-gonic/gin v1.7.7
github.com/go-resty/resty/v2 v2.7.0 github.com/go-resty/resty/v2 v2.7.0
github.com/jmoiron/sqlx v1.3.4 github.com/google/uuid v1.3.0 // indirect
github.com/lib/pq v1.10.5 github.com/huandu/xstrings v1.3.2 // indirect
gopkg.in/ini.v1 v1.66.4 github.com/imdario/mergo v0.3.12 // indirect
github.com/jmoiron/sqlx v1.3.4
github.com/lib/pq v1.10.5
github.com/mitchellh/copystructure v1.2.0 // indirect
gopkg.in/ini.v1 v1.66.4
) )

21
go.sum
View File

@ -1,3 +1,9 @@
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
@ -14,11 +20,20 @@ github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn
github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/jmoiron/sqlx v1.3.4 h1:wv+0IJZfL5z0uZoUjlpKgHkgaFSYD+r9CfrXjEXsO7w= github.com/jmoiron/sqlx v1.3.4 h1:wv+0IJZfL5z0uZoUjlpKgHkgaFSYD+r9CfrXjEXsO7w=
github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
@ -29,6 +44,10 @@ github.com/lib/pq v1.10.5/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
@ -65,3 +84,5 @@ gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -9,7 +9,6 @@
package gitee package gitee
import ( import (
"errors"
"reflect" "reflect"
"time" "time"
) )
@ -41,16 +40,16 @@ func (r Repository) isNilOrEmpty() bool {
return reflect.DeepEqual(r, Repository{}) return reflect.DeepEqual(r, Repository{})
} }
func (r *Repository) Scan(src interface{}) error { // func (r *Repository) Scan(src interface{}) error {
var repoID int // var repoID int
switch src.(type) { // switch src.(type) {
case int64: // case int64:
repoID = int(src.(int64)) // repoID = int(src.(int64))
case int32: // case int32:
repoID = int(src.(int32)) // repoID = int(src.(int32))
default: // default:
return errors.New("can not find any valid user") // return errors.New("can not find any valid user")
} // }
*r = Repository{ID: repoID} // *r = Repository{ID: repoID}
return nil // return nil
} // }

View File

@ -9,7 +9,6 @@
package gitee package gitee
import ( import (
"errors"
"reflect" "reflect"
"time" "time"
) )
@ -30,16 +29,16 @@ func (u User) isNilOrEmpty() bool {
return reflect.DeepEqual(u, User{}) return reflect.DeepEqual(u, User{})
} }
func (r *User) Scan(src interface{}) error { // func (r *User) Scan(src interface{}) error {
var userId int // var userId int
switch src.(type) { // switch src.(type) {
case int64: // case int64:
userId = int(src.(int64)) // userId = int(src.(int64))
case int32: // case int32:
userId = int(src.(int32)) // userId = int(src.(int32))
default: // default:
return errors.New("can not find any valid user") // return errors.New("can not find any valid user")
} // }
*r = User{ID: userId} // *r = User{ID: userId}
return nil // return nil
} // }

View File

@ -21,6 +21,7 @@ import (
"repostats/storage" "repostats/storage"
"repostats/utils" "repostats/utils"
"github.com/Masterminds/sprig"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@ -66,7 +67,7 @@ func initRouter(router *gin.Engine) {
router.StaticFS("/assets", http.FS(sub)) router.StaticFS("/assets", http.FS(sub))
tmpl, err := template.New("").ParseFS(FS, "templates/*.html") tmpl, err := template.New("").Funcs(sprig.FuncMap()).ParseFS(FS, "templates/*.html")
utils.ExitOnError(err) utils.ExitOnError(err)
router.GET("/login", controller.Login) router.GET("/login", controller.Login)

View File

@ -17,6 +17,12 @@ import (
_ "github.com/lib/pq" _ "github.com/lib/pq"
) )
const (
DEFAULT_PAGE_NUMBER = 1
DEFAULT_PAGE_SIZE = 15
DEFAULT_MAX_PAGE_SIZE = 50
)
var dbService = &DatabaseService{} var dbService = &DatabaseService{}
type DatabaseService struct { type DatabaseService struct {

View File

@ -13,7 +13,7 @@ import (
"repostats/storage" "repostats/storage"
) )
var issueQueryPrefix = `SELECT iss.repo_id AS "repository", iss.user_id AS "user", iss.* FROM gitee.issues iss ` var issueQueryPrefix = `SELECT iss.repo_id AS "repository.id", iss.user_id AS "user.id", iss.* FROM gitee.issues iss `
func BulkSaveIssues(iss []gitee_model.Issue) error { func BulkSaveIssues(iss []gitee_model.Issue) error {
query := `INSERT INTO gitee.issues (id, html_url, "number", state, title, user_id, repo_id, finished_at, created_at, query := `INSERT INTO gitee.issues (id, html_url, "number", state, title, user_id, repo_id, finished_at, created_at,

View File

@ -13,8 +13,8 @@ import (
"repostats/storage" "repostats/storage"
) )
var prQueryPrefix = `SELECT pr.user_id AS "user", pr.head_label AS "head.label", pr.head_ref AS "head.ref", pr.head_sha AS "head.sha", var prQueryPrefix = `SELECT pr.user_id AS "user.id", pr.head_label AS "head.label", pr.head_ref AS "head.ref", pr.head_sha AS "head.sha",
pr.head_user_id AS "head.user", pr.head_repo_id AS "head.repo",pr.* FROM gitee.pull_requests pr ` pr.head_user_id AS "head.user.id", pr.head_repo_id AS "head.repo.id",pr.* FROM gitee.pull_requests pr `
func BulkSavePullRequests(prs []gitee_mode.PullRequest) error { func BulkSavePullRequests(prs []gitee_mode.PullRequest) error {
query := `INSERT INTO gitee.pull_requests (id, repo_id, user_id, html_url, diff_url, patch_url, "number", query := `INSERT INTO gitee.pull_requests (id, repo_id, user_id, html_url, diff_url, patch_url, "number",

View File

@ -13,7 +13,7 @@ import (
"repostats/storage" "repostats/storage"
) )
var repoQueryPrefix = `SELECT r.owner_id AS "owner", r.assigner_id AS "assigner",r.* FROM gitee.repos ` var repoQueryPrefix = `SELECT r.owner_id AS "owner.id", r.assigner_id AS "assigner.id", r.* FROM gitee.repos r `
func BulkSaveRepos(repos []gitee_model.Repository) error { func BulkSaveRepos(repos []gitee_model.Repository) error {
query := `INSERT INTO gitee.repos (id, full_name, human_name, path,name, url, owner_id,assigner_id, description, query := `INSERT INTO gitee.repos (id, full_name, human_name, path,name, url, owner_id,assigner_id, description,
@ -35,6 +35,16 @@ func FindRepos() ([]gitee_model.Repository, error) {
return repos, err return repos, err
} }
func FindPagedRepos(page, size int) ([]gitee_model.Repository, error) {
if page < 1 {
page = 1
}
repos := []gitee_model.Repository{}
query := repoQueryPrefix + ` ORDER BY r.id DESC LIMIT $1 OFFSET $2`
offset := (page - 1) * size
return repos, storage.DbSelect(query, &repos, size, offset)
}
func FindRepoByID(repoID int) (gitee_model.Repository, error) { func FindRepoByID(repoID int) (gitee_model.Repository, error) {
found := gitee_model.Repository{} found := gitee_model.Repository{}
query := repoQueryPrefix + ` WHERE r.id = $1` query := repoQueryPrefix + ` WHERE r.id = $1`
@ -46,3 +56,9 @@ func DeleteRepo(repoID int) error {
query := `DELETE FROM gitee.repos WHERE id = $1` query := `DELETE FROM gitee.repos WHERE id = $1`
return storage.DbNamedExec(query, repoID) return storage.DbNamedExec(query, repoID)
} }
func FindTotalReposCount() (int, error) {
var count int
query := `SELECT count(r.id) FROM gitee.repos r`
return count, storage.DbGet(query, &count)
}

View File

@ -18,4 +18,5 @@
</head> </head>
<body> <body>
<div class="push"> <div class="push">
{{if .error}}<script>errorToast('{{.error}}')</script>{{end}}
{{end -}} {{end -}}

64
templates/repos.html Normal file
View File

@ -0,0 +1,64 @@
{{define "repos.html" -}}
{{template "header.html" .}}
{{template "admin-left-menu.html" .}}
<div id="admin-right-content">
<div class="ui basic segment">
<h3 class="ui header">代码仓库列表</h3>
<div class="ui grid stackable padded">
<div class="column">
<table class="ui celled striped small table">
<div class="ui positive message">
<p>当前共计 {{.total_item}} 个代码仓库,每页显示 {{.page_size}} 条数据</p>
</div>
<thead>
<tr>
<th class="center aligned collapsing">序号</th>
<th class="center aligned collapsing">仓库ID</th>
<th class="center aligned collapsing">仓库名</th>
<th class="center aligned collapsing">Star数</th>
<th class="center aligned collapsing">Fork数</th>
<th class="center aligned collapsing">Watch数</th>
<th class="center aligned collapsing">开放协议</th>
<th class="center aligned">创建时间</th>
<th class="center aligned">更新时间</th>
<th class="center aligned">Push时间</th>
<th class="center aligned">操作</th>
</tr>
</thead>
<tbody>
{{range $i,$r := .repos}}
<tr>
<td class="center aligned collapsing">{{add $i 1}}</td>
<td class="center aligned collapsing">{{$r.ID}}</td>
<td><a href="{{$r.HTMLURL}}" target="_blank">{{$r.HumanName}}</a></td>
<td class="center aligned collapsing">{{$r.StargazersCount}}</td>
<td class="center aligned collapsing">{{$r.ForksCount}}</td>
<td class="center aligned collapsing">{{$r.WatchersCount}}</td>
<td class="center aligned collapsing">{{$r.License}}</td>
<td class="center aligned collapsing">{{$r.CreatedAt | date "2006-01-02 15:04:05"}}</td>
<td class="center aligned collapsing">{{$r.UpdatedAt | date "2006-01-02 15:04:05"}}</td>
<td class="center aligned collapsing">{{$r.PushedAt | date "2006-01-02 15:04:05"}}</td>
<td>hello | world</td>
</tr>
{{end}}
</tbody>
<tfoot>
{{if .total_item}}
<tr>
<td colspan="11" class="center aligned">
<div class="ui pagination menu">
<a class="{{if .first_page}}disabled{{end}} item" target="_self" href="{{.current_url}}?page={{sub .current_page 1}}&size={{.page_size}}"><<</a>
<div class="active item">{{.current_page}}</div>
<a class="{{if .last_page}}disabled{{end}} item" target="_self" href="{{.current_url}}?page={{add .current_page 1}}&size={{.page_size}}">>></a>
</div>
</td>
</tr>
{{end}}
</tfoot>
</table>
</div>
</div><!--end fo grid-->
</div> <!--end of basic segment-->
</div><!--end of admin-right-content-->
{{template "footer.html" .}}
{{end -}}