Commit fd957d87 authored by Eric's avatar Eric

[update] pagination

parent f2079123
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"strings" "strings"
"sync"
"github.com/olekukonko/tablewriter" "github.com/olekukonko/tablewriter"
...@@ -19,29 +20,49 @@ const ( ...@@ -19,29 +20,49 @@ const (
CommentColumnMinSize = 2 CommentColumnMinSize = 2
) )
func NewAssetPagination(term *utils.Terminal, assets []model.Asset) *AssetPagination {
fields := []string{"ID", "Hostname", "IP", "LoginAs", "Comment"}
wtable := WrapperTable{
Fields: fields,
DataBulk: make([][]string, 0),
ColumnSize: make([]int, len(fields)),
}
var interfaceSlice = make([]interface{}, len(assets))
for i, d := range assets {
interfaceSlice[i] = d
}
page := &Pagination{
data: interfaceSlice,
lock: new(sync.RWMutex),
currentPage: 1,
}
assetPage := &AssetPagination{term: term,
tableWriter: &wtable,
page: page,
}
assetPage.Initial()
return assetPage
}
type AssetPagination struct { type AssetPagination struct {
term *utils.Terminal term *utils.Terminal
CurrentPage int tableWriter *WrapperTable
TotalPage int page *Pagination
PageSize int currentData []model.Asset
TotalNumber int
Data []model.Asset
dataBulk [][]string
columnSize [5]int
} }
func (p *AssetPagination) Initial() { func (p *AssetPagination) Initial() {
var ( var (
pageSize int pageSize int
totalPage int
) )
_, height := p.term.GetSize() _, height := p.term.GetSize()
switch config.Conf.AssetListPageSize { switch config.Conf.AssetListPageSize {
case "auto": case "auto":
pageSize = height - 7 pageSize = height - 7
case "all": case "all":
pageSize = p.TotalNumber pageSize = len(p.page.data)
default: default:
if value, err := strconv.Atoi(config.Conf.AssetListPageSize); err == nil { if value, err := strconv.Atoi(config.Conf.AssetListPageSize); err == nil {
pageSize = value pageSize = value
...@@ -52,18 +73,14 @@ func (p *AssetPagination) Initial() { ...@@ -52,18 +73,14 @@ func (p *AssetPagination) Initial() {
if pageSize <= 0 { if pageSize <= 0 {
pageSize = 1 pageSize = 1
} }
p.page.SetPageSize(pageSize)
tmpdata := p.page.GetPageData(1)
p.currentData = make([]model.Asset, len(tmpdata))
if p.TotalNumber%pageSize == 0 { for i, item := range tmpdata {
totalPage = p.TotalNumber / pageSize p.currentData[i] = item.(model.Asset)
} else {
totalPage = p.TotalNumber/pageSize + 1
} }
p.CurrentPage = 1
p.PageSize = pageSize
p.TotalPage = totalPage
p.dataBulk = make([][]string, 0)
} }
func (p *AssetPagination) setPageSize() { func (p *AssetPagination) setPageSize() {
...@@ -76,14 +93,8 @@ func (p *AssetPagination) setPageSize() { ...@@ -76,14 +93,8 @@ func (p *AssetPagination) setPageSize() {
} else { } else {
pageSize = 1 pageSize = 1
} }
if p.PageSize != pageSize { if p.page.GetPageSize() != pageSize {
p.PageSize = pageSize p.page.SetPageSize(pageSize)
p.CurrentPage = 1
if p.TotalNumber%pageSize == 0 {
p.TotalPage = p.TotalNumber / pageSize
} else {
p.TotalPage = p.TotalNumber/pageSize + 1
}
} }
} }
} }
...@@ -95,22 +106,16 @@ func (p *AssetPagination) getColumnMaxSize() { ...@@ -95,22 +106,16 @@ func (p *AssetPagination) getColumnMaxSize() {
systemUserSize int systemUserSize int
CommentSize int CommentSize int
) )
p.setPageSize()
IDSize = IDColumnMinSize IDSize = IDColumnMinSize
CommentSize = CommentColumnMinSize CommentSize = CommentColumnMinSize
endIndex := p.CurrentPage * p.PageSize
startIndex := endIndex - p.PageSize if len(strconv.Itoa(len(p.currentData))) > IDColumnMinSize {
if endIndex > len(p.Data) { IDSize = len(strconv.Itoa(len(p.currentData)))
endIndex = len(p.Data)
}
if len(strconv.Itoa(endIndex)) > IDColumnMinSize {
IDSize = len(strconv.Itoa(endIndex))
} }
p.dataBulk = p.dataBulk[:0] p.tableWriter.DataBulk = p.tableWriter.DataBulk[:0]
for i, item := range p.Data[startIndex:endIndex] { for i, item := range p.currentData {
tmpDat := make([]string, 5) tmpDat := make([]string, 5)
var tmpSystemUserArray []string var tmpSystemUserArray []string
result := selectHighestPrioritySystemUsers(item.SystemUsers) result := selectHighestPrioritySystemUsers(item.SystemUsers)
tmpSystemUserArray = make([]string, len(result)) tmpSystemUserArray = make([]string, len(result))
for index, sysUser := range result { for index, sysUser := range result {
...@@ -134,10 +139,10 @@ func (p *AssetPagination) getColumnMaxSize() { ...@@ -134,10 +139,10 @@ func (p *AssetPagination) getColumnMaxSize() {
if len(item.Comment) > CommentSize { if len(item.Comment) > CommentSize {
CommentSize = len(item.Comment) CommentSize = len(item.Comment)
} }
tmpDat[0] = strconv.Itoa(startIndex + i + 1) tmpDat[0] = strconv.Itoa(i + 1)
tmpDat[2] = item.Ip tmpDat[2] = item.Ip
tmpDat[3] = tmpSystemUserStr tmpDat[3] = tmpSystemUserStr
p.dataBulk = append(p.dataBulk, tmpDat) p.tableWriter.DataBulk = append(p.tableWriter.DataBulk, tmpDat)
} }
// table writer 空白空间占用宽度 4 + (columnNum - 1) * 4 // table writer 空白空间占用宽度 4 + (columnNum - 1) * 4
width, _ := p.term.GetSize() width, _ := p.term.GetSize()
...@@ -145,21 +150,23 @@ func (p *AssetPagination) getColumnMaxSize() { ...@@ -145,21 +150,23 @@ func (p *AssetPagination) getColumnMaxSize() {
if remainSize > 0 && CommentSize < remainSize { if remainSize > 0 && CommentSize < remainSize {
CommentSize = remainSize CommentSize = remainSize
} }
for i, item := range p.Data[startIndex:endIndex] { for i, item := range p.currentData {
if len(item.Comment) > CommentSize { if len(item.Comment) > CommentSize {
p.dataBulk[i][4] = item.Comment[:CommentSize] p.tableWriter.DataBulk[i][4] = item.Comment[:CommentSize]
} else { } else {
p.dataBulk[i][4] = item.Comment p.tableWriter.DataBulk[i][4] = item.Comment
} }
} }
p.columnSize = [5]int{IDSize, HostNameSize, IPColumnSize, systemUserSize, CommentSize} currentCapMsg := fmt.Sprintf("Page: %d, Count: %d, Total Page: %d, Total Count:%d\n",
fmt.Println(p.columnSize) p.page.CurrentPage(), p.page.GetPageSize(), p.page.TotalPage(), p.page.TotalCount())
msg := utils.WrapperString(currentCapMsg, utils.Green)
p.tableWriter.SetCaption(msg)
p.tableWriter.SetColumnSize(IDSize, HostNameSize, IPColumnSize, systemUserSize, CommentSize)
} }
func (p *AssetPagination) PaginationState() []model.Asset { func (p *AssetPagination) PaginationState() []model.Asset {
done := make(chan struct{}) if !p.page.HasNextPage() {
defer close(done)
if p.PageSize > p.TotalNumber {
p.displayAssets() p.displayAssets()
return []model.Asset{} return []model.Asset{}
} }
...@@ -168,6 +175,7 @@ func (p *AssetPagination) PaginationState() []model.Asset { ...@@ -168,6 +175,7 @@ func (p *AssetPagination) PaginationState() []model.Asset {
p.displayAssets() p.displayAssets()
p.displayTipsInfo() p.displayTipsInfo()
line, err := p.term.ReadLine() line, err := p.term.ReadLine()
p.setPageSize()
if err != nil { if err != nil {
return []model.Asset{} return []model.Asset{}
} }
...@@ -176,26 +184,35 @@ func (p *AssetPagination) PaginationState() []model.Asset { ...@@ -176,26 +184,35 @@ func (p *AssetPagination) PaginationState() []model.Asset {
case 0, 1: case 0, 1:
switch strings.ToLower(line) { switch strings.ToLower(line) {
case "p": case "p":
p.CurrentPage-- tmpData := p.page.GetPrePageData()
if p.CurrentPage <= 0 { if len(p.currentData) != len(tmpData) {
p.CurrentPage = 1 p.currentData = make([]model.Asset, len(tmpData))
}
for i, item := range tmpData {
p.currentData[i] = item.(model.Asset)
} }
continue
case "", "n": case "", "n":
p.CurrentPage++ tmpData := p.page.GetNextPageData()
if p.CurrentPage >= p.TotalPage { if len(p.currentData) != len(tmpData) {
p.CurrentPage = p.TotalPage p.currentData = make([]model.Asset, len(tmpData))
}
for i, item := range tmpData {
p.currentData[i] = item.(model.Asset)
} }
continue
case "b": case "b":
return []model.Asset{} return []model.Asset{}
} }
} }
if indexID, err := strconv.Atoi(line); err == nil { if indexID, err := strconv.Atoi(line); err == nil {
if indexID > 0 && indexID <= p.TotalNumber { if indexID > 0 && indexID <= p.page.TotalCount() {
return []model.Asset{p.Data[indexID-1]} return []model.Asset{p.currentData[indexID-1]}
}
} }
if p.page.CurrentPage() == 1 && p.page.GetPageSize() > len(p.currentData) {
p.displayAssets()
return []model.Asset{}
} }
} }
} }
...@@ -204,42 +221,160 @@ func (p *AssetPagination) displayAssets() { ...@@ -204,42 +221,160 @@ func (p *AssetPagination) displayAssets() {
p.getColumnMaxSize() p.getColumnMaxSize()
_, _ = p.term.Write([]byte(utils.CharClear)) _, _ = p.term.Write([]byte(utils.CharClear))
_, _ = p.term.Write([]byte(p.tableWriter.Display()))
}
func (p *AssetPagination) displayTipsInfo() {
tips := []string{
"\nTips: Enter the asset ID and log directly into the asset.\n",
"\nPage up: P/p Page down: Enter|N/n BACK: b.\n",
}
for _, tip := range tips {
_, _ = p.term.Write([]byte(tip))
}
}
type WrapperTable struct {
Fields []string
DataBulk [][]string
ColumnSize []int
Caption string
}
func (w *WrapperTable) SetColumnSize(columnSizes ...int) {
if len(columnSizes) != len(w.Fields) {
panic("fields' number could not match column size")
}
for i, size := range columnSizes {
w.ColumnSize[i] = size
}
}
func (w *WrapperTable) SetCaption(cap string) {
w.Caption = cap
}
table := tablewriter.NewWriter(p.term) func (w *WrapperTable) Display() string {
table.SetHeader([]string{"ID", "Hostname", "IP", "LoginAs", "Comment"}) tableString := &strings.Builder{}
table.AppendBulk(p.dataBulk) table := tablewriter.NewWriter(tableString)
table.SetBorder(false) table.SetBorder(false)
greens := tablewriter.Colors{tablewriter.Normal, tablewriter.FgGreenColor} table.SetHeader(w.Fields)
table.SetHeaderColor(greens, greens, greens, greens, greens) colors := make([]tablewriter.Colors, len(w.Fields))
for i := 0; i < len(w.Fields); i++ {
colors[i] = tablewriter.Colors{tablewriter.Bold, tablewriter.FgGreenColor}
}
table.SetHeaderColor(colors...)
table.AppendBulk(w.DataBulk)
table.SetHeaderAlignment(tablewriter.ALIGN_LEFT) table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
table.SetAlignment(tablewriter.ALIGN_LEFT) table.SetAlignment(tablewriter.ALIGN_LEFT)
for i, value := range p.columnSize { for i, value := range w.ColumnSize {
table.SetColMinWidth(i, value) table.SetColMinWidth(i, value)
} }
currentCapMsg := fmt.Sprintf("Page: %d, Count: %d, Total Page: %d, Total Count:%d\n", if w.Caption != "" {
p.CurrentPage, p.PageSize, p.TotalPage, p.TotalNumber) table.SetCaption(true, w.Caption)
table.SetCaption(true, utils.WrapperString(currentCapMsg, utils.Green)) }
table.Render() table.Render()
return tableString.String()
} }
func (p *AssetPagination) displayTipsInfo() { type Pagination struct {
tips := []string{ data []interface{}
"\nTips: Enter the asset ID and log directly into the asset.\n", currentPage int
"\nPage up: P/p Page down: Enter|N/n BACK: b.\n", pageSize int
totalPage int
lock *sync.RWMutex
}
func (p *Pagination) GetNextPageData() []interface{} {
if p.HasNextPage() {
p.lock.Lock()
p.currentPage++
p.lock.Unlock()
} }
for _, tip := range tips { return p.GetPageData(p.currentPage)
_, _ = p.term.Write([]byte(tip))
}
func (p *Pagination) GetPrePageData() []interface{} {
if p.HasPrePage() {
p.lock.Lock()
p.currentPage--
p.lock.Unlock()
}
return p.GetPageData(p.currentPage)
}
func (p *Pagination) GetPageData(pageIndex int) []interface{} {
p.lock.RLock()
defer p.lock.RUnlock()
var (
endIndex int
startIndex int
)
endIndex = p.pageSize * pageIndex
startIndex = endIndex - p.pageSize
if endIndex > len(p.data) {
endIndex = len(p.data)
}
return p.data[startIndex:endIndex]
}
func (p *Pagination) CurrentPage() int {
p.lock.RLock()
defer p.lock.RUnlock()
return p.currentPage
}
func (p *Pagination) TotalCount() int {
p.lock.RLock()
defer p.lock.RUnlock()
return len(p.data)
}
func (p *Pagination) TotalPage() int {
p.lock.RLock()
defer p.lock.RUnlock()
return p.totalPage
}
func (p *Pagination) SetPageSize(size int) {
if size <= 0 {
panic("Pagination size should be larger than zero")
}
p.lock.Lock()
defer p.lock.Unlock()
if p.pageSize == size {
return
} }
p.pageSize = size
if len(p.data)%size == 0 {
p.totalPage = len(p.data) / size
} else {
p.totalPage = len(p.data)/size + 1
}
p.currentPage = 1
}
func (p *Pagination) GetPageSize() int {
p.lock.RLock()
defer p.lock.RUnlock()
return p.pageSize
}
func (p *Pagination) HasNextPage() bool {
p.lock.RLock()
defer p.lock.RUnlock()
return p.currentPage < p.totalPage
} }
type Pagination interface { func (p *Pagination) HasPrePage() bool {
GetNextPageData() []interface{} p.lock.RLock()
GetPrePageData() []interface{} defer p.lock.RUnlock()
GetPageData(p int) []interface{} return p.currentPage > 1
CurrentPage() int
TotalCount() int
TotalPage() int
SetPageSize(int)
GetPageSize() int
} }
...@@ -230,11 +230,8 @@ func (h *interactiveHandler) displayAssets(assets model.AssetList) { ...@@ -230,11 +230,8 @@ func (h *interactiveHandler) displayAssets(assets model.AssetList) {
if len(assets) == 0 { if len(assets) == 0 {
_, _ = io.WriteString(h.term, "\r\n No Assets\r\n\r") _, _ = io.WriteString(h.term, "\r\n No Assets\r\n\r")
} else { } else {
pag := AssetPagination{ h.term.SetPrompt(": ")
term: h.term, pag := NewAssetPagination(h.term, assets)
TotalNumber: len(assets),
Data: assets,
}
pag.Initial() pag.Initial()
selectOneAssets := pag.PaginationState() selectOneAssets := pag.PaginationState()
if len(selectOneAssets) == 1 { if len(selectOneAssets) == 1 {
...@@ -243,6 +240,7 @@ func (h *interactiveHandler) displayAssets(assets model.AssetList) { ...@@ -243,6 +240,7 @@ func (h *interactiveHandler) displayAssets(assets model.AssetList) {
h.systemUserSelect = &systemUser h.systemUserSelect = &systemUser
h.Proxy(context.TODO()) h.Proxy(context.TODO())
} }
h.term.SetPrompt("Opt> ")
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment