Skip to content

Commit dcd8d5d

Browse files
authored
Merge pull request #22 from flyhope/6-custom-for-format-table-field
custom for format table field
2 parents 8b6aee7 + ee3c6ca commit dcd8d5d

File tree

6 files changed

+149
-98
lines changed

6 files changed

+149
-98
lines changed

comm/config.go

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,17 @@ var ShowKubeteaConfig = sync.OnceValue(func() *KubeteaConfig {
5454

5555
// KubeteaConfig YAML配置定义
5656
type KubeteaConfig struct {
57-
PodCacheLivetime uint32 `yaml:"pod_cache_livetime_second"` // 缓存Pod过期时间,过期自动刷新
58-
Log KubeteaConfigLog `yaml:"log"` // 日志配置
59-
ClusterByLabel string `yaml:"cluster_by_label"` // 筛选显示cluster的Label的名称
60-
ClusterFilters []string `yaml:"cluster_filters"` // 筛选显示cluster的Label的值,支持glob
61-
Sort KubeteaConfigSort `yaml:"sort"` // 自定义排序
62-
Template KubeteaTemplate `yaml:"template"` // 显示模板定义
57+
PodCacheLivetime uint32 `yaml:"pod_cache_livetime_second"` // 缓存Pod过期时间,过期自动刷新
58+
Log KubeteaConfigLog `yaml:"log"` // 日志配置
59+
ClusterByLabel string `yaml:"cluster_by_label"` // 筛选显示cluster的Label的名称
60+
ClusterFilters []string `yaml:"cluster_filters"` // 筛选显示cluster的Label的值,支持glob
61+
Sort KubeteaConfigSort `yaml:"sort"` // 自定义排序
62+
Template map[ConfigTemplateName]*KubeteaTemplateTable `yaml:"template"` // 显示模板定义
63+
}
64+
65+
// ShowTemplateColumn 根据名称获取一个TableName
66+
func (k *KubeteaConfig) ShowTemplateColumn(name ConfigTemplateName) []table.Column {
67+
return k.Template[name].Column
6368
}
6469

6570
type KubeteaConfigLog struct {
@@ -71,12 +76,15 @@ type KubeteaConfigLog struct {
7176
type KubeteaConfigSort struct {
7277
Container SortMap `yaml:"container"`
7378
}
74-
75-
type KubeteaTemplate struct {
76-
Pod KubeteaTemplateTable `yaml:"pod"`
77-
}
78-
7979
type KubeteaTemplateTable struct {
8080
Column []table.Column `yaml:"column"`
8181
Body []string `yaml:"body"`
8282
}
83+
84+
type ConfigTemplateName string
85+
86+
const (
87+
ConfigTemplateCluster ConfigTemplateName = "cluster"
88+
ConfigTemplatePod ConfigTemplateName = "pod"
89+
ConfigTemplateContainer ConfigTemplateName = "container"
90+
)

comm/kubetea.yaml

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ sort:
2626

2727
# template view define
2828
template:
29+
cluster:
30+
column:
31+
- { title: "集群", width: 0 }
32+
- { title: "数量", width: 10 }
33+
body:
34+
# first cloume must be .Name
35+
- "{{ .Name }}"
36+
- "{{ len .Pods }}"
2937
pod:
3038
column:
3139
- { title: "名称", width: 0 }
@@ -40,4 +48,15 @@ template:
4048
- "{{ PodPhaseView . }}"
4149
- "{{ PodReadyView . }}"
4250
- "{{ if .Status.StartTime }}{{ FormatTime .Status.StartTime.Time }}{{else}}-{{end}}"
43-
51+
container:
52+
column:
53+
- { title: "容器名称", width: 0 }
54+
- { title: "镜像地址", width: 0 }
55+
- { title: "状态", width: 4 }
56+
- { title: "就绪", width: 4 }
57+
body:
58+
# first cloume must be .Name
59+
- "{{ .Name }}"
60+
- "{{ .Image }}"
61+
- "{{ ContainerStateView . }}"
62+
- "{{ BoolView .Ready }}"

view/cluster.go

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ import (
88
"github.com/flyhope/kubetea/k8s"
99
"github.com/flyhope/kubetea/ui"
1010
"github.com/sirupsen/logrus"
11+
v1 "k8s.io/api/core/v1"
1112
"path/filepath"
1213
"sort"
13-
"strconv"
1414
"time"
1515
)
1616

@@ -19,18 +19,24 @@ type clusterModel struct {
1919
*ui.TableFilter
2020
}
2121

22+
// 用于显示的集群每行数据
23+
type clusterRow struct {
24+
Name string
25+
Pods []*v1.Pod
26+
SortNum int
27+
}
28+
2229
// 更新数据
2330
func (c *clusterModel) updateData(force bool) {
2431
config := comm.ShowKubeteaConfig()
25-
groupLabels := make(map[string]int)
2632

2733
pods, err := k8s.PodCache().ShowList(force)
2834
if err != nil {
2935
return
3036
}
3137

3238
// 获取要展示的label
33-
labelTotal := make(map[string]int)
39+
clusterRows := make(map[string]*clusterRow, len(config.ClusterFilters))
3440
for _, pod := range pods.Items {
3541
groupLabelValue := pod.Labels[config.ClusterByLabel]
3642
for idx, filter := range config.ClusterFilters {
@@ -41,24 +47,31 @@ func (c *clusterModel) updateData(force bool) {
4147
}
4248

4349
if ok {
44-
groupLabels[groupLabelValue] = idx
45-
labelTotal[groupLabelValue]++
50+
row := clusterRows[groupLabelValue]
51+
if row == nil {
52+
row = &clusterRow{
53+
Name: groupLabelValue,
54+
SortNum: idx,
55+
}
56+
clusterRows[groupLabelValue] = row
57+
}
58+
row.Pods = append(row.Pods, &pod)
4659
break
4760
}
4861
}
4962
}
5063

5164
// 拼接UI列表数据
52-
rows := make([]table.Row, 0, len(groupLabels))
53-
for label := range groupLabels {
54-
rows = append(rows, table.Row{label, strconv.Itoa(labelTotal[label])})
65+
rows := make([]table.Row, 0, len(clusterRows))
66+
for _, row := range clusterRows {
67+
rows = append(rows, TemplateRender(comm.ConfigTemplateCluster, row))
5568
}
5669

70+
// 排序
5771
sort.Slice(rows, func(i, j int) bool {
58-
if groupLabels[rows[i][0]] != groupLabels[rows[j][0]] {
59-
return groupLabels[rows[i][0]] < groupLabels[rows[j][0]]
72+
if clusterRows[rows[i][0]].SortNum != clusterRows[rows[j][0]].SortNum {
73+
return clusterRows[rows[i][0]].SortNum < clusterRows[rows[j][0]].SortNum
6074
}
61-
6275
return rows[i][0] < rows[j][0]
6376
})
6477
c.Table.SetRows(rows)
@@ -71,10 +84,7 @@ func ShowCluster() (tea.Model, error) {
7184
m := &clusterModel{
7285
TableFilter: ui.NewTableFilter(),
7386
}
74-
m.TableFilter.Table = ui.NewTableWithData([]table.Column{
75-
{Title: "集群", Width: 0},
76-
{Title: "数量", Width: 10},
77-
}, nil)
87+
m.TableFilter.Table = ui.NewTableWithData(comm.ShowKubeteaConfig().ShowTemplateColumn(comm.ConfigTemplateCluster), nil)
7888
m.updateData(false)
7989

8090
m.UpdateEvent = func(msg tea.Msg) (tea.Model, tea.Cmd) {
@@ -104,3 +114,13 @@ func ShowCluster() (tea.Model, error) {
104114
}
105115
return m, nil
106116
}
117+
118+
// countByPodLabelKeyValue 根据Pod的Label标签,统计符合条件的POD的数量
119+
func countByPodLabelKeyValue(pods []*v1.Pod, key, value string) (result int) {
120+
for _, pod := range pods {
121+
if pod.Labels[key] == value {
122+
result++
123+
}
124+
}
125+
return result
126+
}

view/container.go

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -30,24 +30,14 @@ func (m *containerModel) updateData(force bool) {
3030
// 获取 container
3131
rows := make([]table.Row, 0, len(pod.Status.ContainerStatuses))
3232
for _, container := range pod.Status.ContainerStatuses {
33-
rows = append(rows, table.Row{
34-
container.Name,
35-
container.Image,
36-
getContainerState(container),
37-
getBoolString(container.Ready),
38-
})
33+
rows = append(rows, TemplateRender(comm.ConfigTemplateContainer, container))
3934
}
4035
ui.TableRowsSort(rows, comm.ShowKubeteaConfig().Sort.Container)
4136

4237
// 展示 init container
4338
initRows := make([]table.Row, 0, len(pod.Status.InitContainerStatuses))
4439
for _, container := range pod.Status.InitContainerStatuses {
45-
initRows = append(initRows, table.Row{
46-
container.Name,
47-
container.Image,
48-
getContainerState(container),
49-
getBoolString(container.Ready),
50-
})
40+
initRows = append(initRows, TemplateRender(comm.ConfigTemplateContainer, container))
5141
}
5242
ui.TableRowsSort(initRows, comm.ShowKubeteaConfig().Sort.Container)
5343
rows = append(rows, initRows...)
@@ -68,12 +58,7 @@ func ShowContainer(podName string, lastModel tea.Model) (tea.Model, error) {
6858
}
6959
m.Abstract.Model = m
7060

71-
m.Table = ui.NewTableWithData([]table.Column{
72-
{Title: "容器名称", Width: 0},
73-
{Title: "镜像地址", Width: 0},
74-
{Title: "状态", Width: 4},
75-
{Title: "就绪", Width: 4},
76-
}, nil)
61+
m.Table = ui.NewTableWithData(comm.ShowKubeteaConfig().ShowTemplateColumn(comm.ConfigTemplateContainer), nil)
7762
m.updateData(false)
7863

7964
m.UpdateEvent = func(msg tea.Msg) (tea.Model, tea.Cmd) {
@@ -134,16 +119,8 @@ func ShowContainer(podName string, lastModel tea.Model) (tea.Model, error) {
134119

135120
}
136121

137-
// 获取字符串输出的Bool值
138-
func getBoolString(val bool) string {
139-
if val {
140-
return "✔️"
141-
}
142-
return "❌️"
143-
}
144-
145122
// 获取容器的状态名称
146-
func getContainerState(status v1.ContainerStatus) string {
123+
func containerStateView(status v1.ContainerStatus) string {
147124
if status.State.Waiting != nil {
148125
return "♾️"
149126
} else if status.State.Terminated != nil {

view/pod.go

Lines changed: 8 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
package view
22

33
import (
4-
"bytes"
54
"fmt"
65
"github.com/charmbracelet/bubbles/table"
76
tea "github.com/charmbracelet/bubbletea"
87
"github.com/flyhope/kubetea/comm"
98
"github.com/flyhope/kubetea/k8s"
109
"github.com/flyhope/kubetea/ui"
1110
"github.com/sirupsen/logrus"
12-
"html/template"
1311
v1 "k8s.io/api/core/v1"
1412
"sort"
1513
"time"
@@ -19,8 +17,7 @@ import (
1917
type podModel struct {
2018
ui.Abstract
2119
*ui.TableFilter
22-
app string
23-
templates []*template.Template
20+
app string
2421
}
2522

2623
// 更新数据
@@ -31,39 +28,16 @@ func (c *podModel) updateData(force bool) {
3128
return
3229
}
3330

34-
rows := make([]table.Row, 0)
31+
rows := make([]table.Row, 0, len(pods.Items))
3532
for _, pod := range pods.Items {
3633
if pod.Labels["app"] == c.app {
37-
38-
row := make(table.Row, 0, len(c.templates))
39-
for _, tmpl := range c.templates {
40-
var buf bytes.Buffer
41-
if errExecute := tmpl.Execute(&buf, pod); errExecute != nil {
42-
logrus.Warnln(errExecute)
43-
}
44-
row = append(row, buf.String())
45-
}
46-
rows = append(rows, row)
34+
rows = append(rows, TemplateRender(comm.ConfigTemplatePod, pod))
4735

4836
//name := pod.Name
4937
////if strings.Index(name, app) == 0 {
5038
//// name = name[len(app):]
5139
//// name = strings.TrimLeft(name, "-_.")
5240
////}
53-
//
54-
//// 格式化时间输出
55-
//timeStr := "-"
56-
//if startTime := pod.Status.StartTime; startTime != nil {
57-
// timeStr = startTime.Format(time.DateTime)
58-
//}
59-
//
60-
//rows = append(rows, table.Row{
61-
// name,
62-
// pod.Status.PodIP,
63-
// PodPhaseView(pod),
64-
// PodReadyView(pod),
65-
// timeStr,
66-
//})
6741
}
6842
}
6943

@@ -80,21 +54,16 @@ func (c *podModel) updateData(force bool) {
8054

8155
// ShowPod 获取POD列表
8256
func ShowPod(app string, lastModel tea.Model) (tea.Model, error) {
83-
templates, errTmpl := NewTmplParseSlice(comm.ShowKubeteaConfig().Template.Pod.Body)
84-
if errTmpl != nil {
85-
return nil, errTmpl
86-
}
8757

8858
// 渲染UI
8959
m := &podModel{
9060
Abstract: ui.Abstract{LastModel: lastModel},
9161
TableFilter: ui.NewTableFilter(),
9262
app: app,
93-
templates: templates,
9463
}
9564
m.Abstract.Model = m
9665

97-
m.TableFilter.Table = ui.NewTableWithData(comm.ShowKubeteaConfig().Template.Pod.Column, nil)
66+
m.TableFilter.Table = ui.NewTableWithData(comm.ShowKubeteaConfig().ShowTemplateColumn(comm.ConfigTemplatePod), nil)
9867
m.TableFilter.Focus()
9968
m.updateData(false)
10069

@@ -154,8 +123,8 @@ var phaseAlias = map[v1.PodPhase]string{
154123
"Terminating": "✴️",
155124
}
156125

157-
// PodPhaseView 友好显示POD状态
158-
func PodPhaseView(pod v1.Pod) string {
126+
// podPhaseView 友好显示POD状态
127+
func podPhaseView(pod v1.Pod) string {
159128
phase := pod.Status.Phase
160129
if pod.DeletionTimestamp != nil {
161130
phase = "Terminating"
@@ -168,8 +137,8 @@ func PodPhaseView(pod v1.Pod) string {
168137
return result
169138
}
170139

171-
// PodReadyView 友好显示POD的Ready状态
172-
func PodReadyView(pod v1.Pod) string {
140+
// podReadyView 友好显示POD的Ready状态
141+
func podReadyView(pod v1.Pod) string {
173142
for _, condition := range pod.Status.Conditions {
174143
if condition.Type == v1.PodReady && condition.Status == v1.ConditionTrue {
175144
return "✔️"

0 commit comments

Comments
 (0)