mirror of
https://github.com/kubevela/kubevela.git
synced 2026-02-14 18:10:21 +00:00
Refactor: refactor the source of all kinds of views, use the "Factory Method" design patterns to rewrite the code to upgrade the quality of code (#4679)
* Fix: refactor the source of all kinds of views, use the "Factory Method" design patterns to rewrite the code to upgrade the quality of code Signed-off-by: HanMengnan <1448189829@qq.com> * Fix: fix test case of the refactored code and some bugs Signed-off-by: HanMengnan <1448189829@qq.com> * Fix: rename the interface of ResourceView Signed-off-by: HanMengnan <1448189829@qq.com> Signed-off-by: HanMengnan <1448189829@qq.com>
This commit is contained in:
@@ -56,6 +56,7 @@ func (t *Table) Start() {
|
||||
|
||||
// Stop table component
|
||||
func (t *Table) Stop() {
|
||||
t.Clear()
|
||||
}
|
||||
|
||||
// Hint return key action menu hints of the component
|
||||
|
||||
@@ -43,6 +43,10 @@ const (
|
||||
ApplicationWorkflowTerminatedPhaseColor = "[red::]"
|
||||
// ApplicationRunningPhaseColor application Running phase text color
|
||||
ApplicationRunningPhaseColor = "[green::]"
|
||||
// NamespaceActiveStatusColor is namespace active status text color
|
||||
NamespaceActiveStatusColor = "[green::]"
|
||||
// NamespaceTerminateStatusColor is namespace terminate status text color
|
||||
NamespaceTerminateStatusColor = "[red::]"
|
||||
// ObjectHealthyStatusColor is object Healthy status text color
|
||||
ObjectHealthyStatusColor = "[green::]"
|
||||
// ObjectUnhealthyStatusColor is object Unhealthy status text color
|
||||
|
||||
@@ -34,38 +34,30 @@ type Application struct {
|
||||
}
|
||||
|
||||
// ApplicationList is application resource list
|
||||
type ApplicationList struct {
|
||||
title []string
|
||||
data []Application
|
||||
}
|
||||
type ApplicationList []Application
|
||||
|
||||
// Header generate header of table in application view
|
||||
func (l *ApplicationList) Header() []string {
|
||||
return l.title
|
||||
}
|
||||
|
||||
// Body generate body of table in application view
|
||||
func (l *ApplicationList) Body() [][]string {
|
||||
data := make([][]string, 0)
|
||||
for _, app := range l.data {
|
||||
data = append(data, []string{app.name, app.namespace, app.phase, app.createTime})
|
||||
// ToTableBody generate body of table in application view
|
||||
func (l ApplicationList) ToTableBody() [][]string {
|
||||
data := make([][]string, len(l))
|
||||
for index, app := range l {
|
||||
data[index] = []string{app.name, app.namespace, app.phase, app.createTime}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// ListApplications list all apps in all namespaces
|
||||
func ListApplications(ctx context.Context, c client.Reader) (*ApplicationList, error) {
|
||||
list := &ApplicationList{title: []string{"Name", "Namespace", "Phase", "CreateTime"}}
|
||||
func ListApplications(ctx context.Context, c client.Reader) (ApplicationList, error) {
|
||||
apps := v1beta1.ApplicationList{}
|
||||
namespace := ctx.Value(&CtxKeyNamespace).(string)
|
||||
|
||||
if err := c.List(ctx, &apps, client.InNamespace(namespace)); err != nil {
|
||||
return list, err
|
||||
return ApplicationList{}, err
|
||||
}
|
||||
for _, app := range apps.Items {
|
||||
list.data = append(list.data, Application{app.Name, app.Namespace, string(app.Status.Phase), app.CreationTimestamp.String()})
|
||||
appList := make(ApplicationList, len(apps.Items))
|
||||
for index, app := range apps.Items {
|
||||
appList[index] = Application{app.Name, app.Namespace, string(app.Status.Phase), app.CreationTimestamp.String()}
|
||||
}
|
||||
return list, nil
|
||||
return appList, nil
|
||||
}
|
||||
|
||||
// LoadApplication load the corresponding application according to name and namespace
|
||||
|
||||
@@ -25,15 +25,9 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestApplicationList_Header(t *testing.T) {
|
||||
appList := &ApplicationList{title: []string{"Name", "Namespace", "Phase", "CreateTime"}}
|
||||
assert.Equal(t, appList.Header(), []string{"Name", "Namespace", "Phase", "CreateTime"})
|
||||
}
|
||||
|
||||
func TestApplicationList_Body(t *testing.T) {
|
||||
appList := &ApplicationList{data: []Application{{"name", "namespace", "phase", "createTime"}}}
|
||||
assert.Equal(t, len(appList.data), 1)
|
||||
assert.Equal(t, appList.Body()[0], []string{"name", "namespace", "phase", "createTime"})
|
||||
func TestApplicationList_ToTableBody(t *testing.T) {
|
||||
appList := &ApplicationList{{"Name", "Namespace", "Phase", "CreateTime"}}
|
||||
assert.Equal(t, appList.ToTableBody(), [][]string{{"Name", "Namespace", "Phase", "CreateTime"}})
|
||||
}
|
||||
|
||||
var _ = Describe("test Application", func() {
|
||||
@@ -57,8 +51,7 @@ var _ = Describe("test Application", func() {
|
||||
It("list applications", func() {
|
||||
applicationsList, err := ListApplications(ctx, k8sClient)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(applicationsList.Header()).To(Equal([]string{"Name", "Namespace", "Phase", "CreateTime"}))
|
||||
Expect(len(applicationsList.Body())).To(Equal(1))
|
||||
Expect(len(applicationsList)).To(Equal(1))
|
||||
})
|
||||
It("load application info", func() {
|
||||
application, err := LoadApplication(k8sClient, "first-vela-app", "default")
|
||||
|
||||
@@ -38,36 +38,15 @@ type Cluster struct {
|
||||
}
|
||||
|
||||
// ClusterList is cluster resource list
|
||||
type ClusterList struct {
|
||||
title []string
|
||||
data []Cluster
|
||||
}
|
||||
|
||||
// Header generate header of table in application view
|
||||
func (l *ClusterList) Header() []string {
|
||||
return l.title
|
||||
}
|
||||
|
||||
// Body generate body of table in application view
|
||||
func (l *ClusterList) Body() [][]string {
|
||||
data := make([][]string, 0)
|
||||
for _, cluster := range l.data {
|
||||
data = append(data, []string{cluster.name, cluster.alias, cluster.clusterType, cluster.endpoint, cluster.labels})
|
||||
}
|
||||
return data
|
||||
}
|
||||
type ClusterList []Cluster
|
||||
|
||||
// ListClusters list clusters where application deploys resource
|
||||
func ListClusters(ctx context.Context, c client.Client) (*ClusterList, error) {
|
||||
list := &ClusterList{
|
||||
title: []string{"Name", "Alias", "Type", "EndPoint", "Labels"},
|
||||
data: []Cluster{{"all", "*", "*", "*", "*"}},
|
||||
}
|
||||
func ListClusters(ctx context.Context, c client.Client) (ClusterList, error) {
|
||||
name := ctx.Value(&CtxKeyAppName).(string)
|
||||
ns := ctx.Value(&CtxKeyNamespace).(string)
|
||||
app, err := LoadApplication(c, name, ns)
|
||||
if err != nil {
|
||||
return list, err
|
||||
return ClusterList{}, err
|
||||
}
|
||||
clusterSet := make(map[string]interface{})
|
||||
|
||||
@@ -80,8 +59,8 @@ func ListClusters(ctx context.Context, c client.Client) (*ClusterList, error) {
|
||||
}
|
||||
|
||||
clusters, _ := prismclusterv1alpha1.NewClusterClient(c).List(context.Background())
|
||||
|
||||
for _, cluster := range clusters.Items {
|
||||
list := make(ClusterList, len(clusters.Items))
|
||||
for index, cluster := range clusters.Items {
|
||||
if _, ok := clusterSet[cluster.Name]; ok {
|
||||
clusterInfo := Cluster{
|
||||
name: cluster.Name,
|
||||
@@ -96,8 +75,18 @@ func ListClusters(ctx context.Context, c client.Client) (*ClusterList, error) {
|
||||
}
|
||||
}
|
||||
clusterInfo.labels = strings.Join(labels, ",")
|
||||
list.data = append(list.data, clusterInfo)
|
||||
list[index] = clusterInfo
|
||||
}
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
|
||||
// ToTableBody generate body of table in cluster view
|
||||
func (l ClusterList) ToTableBody() [][]string {
|
||||
data := make([][]string, len(l)+1)
|
||||
data[0] = []string{AllCluster, "*", "*", "*", "*"}
|
||||
for index, cluster := range l {
|
||||
data[index+1] = []string{cluster.name, cluster.alias, cluster.clusterType, cluster.endpoint, cluster.labels}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
@@ -27,23 +27,13 @@ import (
|
||||
"github.com/oam-dev/kubevela/references/cli/top/utils"
|
||||
)
|
||||
|
||||
// NamespaceList is namespace list
|
||||
type NamespaceList struct {
|
||||
title []string
|
||||
data []Namespace
|
||||
}
|
||||
|
||||
// ListClusterNamespaces return namespace of application's resource
|
||||
func ListClusterNamespaces(ctx context.Context, c client.Client) (*NamespaceList, error) {
|
||||
list := &NamespaceList{
|
||||
title: []string{"Name", "Status", "Age"},
|
||||
data: []Namespace{{"all", "*", "*"}},
|
||||
}
|
||||
func ListClusterNamespaces(ctx context.Context, c client.Client) (NamespaceList, error) {
|
||||
name := ctx.Value(&CtxKeyAppName).(string)
|
||||
ns := ctx.Value(&CtxKeyNamespace).(string)
|
||||
app, err := LoadApplication(c, name, ns)
|
||||
if err != nil {
|
||||
return list, err
|
||||
return NamespaceList{}, err
|
||||
}
|
||||
clusterNSSet := make(map[string]interface{})
|
||||
for _, svc := range app.Status.AppliedResources {
|
||||
@@ -51,20 +41,22 @@ func ListClusterNamespaces(ctx context.Context, c client.Client) (*NamespaceList
|
||||
clusterNSSet[svc.Namespace] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
nsList := make(NamespaceList, len(clusterNSSet))
|
||||
index := 0
|
||||
for clusterNS := range clusterNSSet {
|
||||
namespaceInfo, err := LoadNamespaceDetail(ctx, c, clusterNS)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
list.data = append(list.data, Namespace{
|
||||
Name: namespaceInfo.Name,
|
||||
Status: string(namespaceInfo.Status.Phase),
|
||||
Age: utils.TimeFormat(time.Since(namespaceInfo.CreationTimestamp.Time)),
|
||||
})
|
||||
nsList[index] = Namespace{
|
||||
name: namespaceInfo.Name,
|
||||
status: string(namespaceInfo.Status.Phase),
|
||||
age: utils.TimeFormat(time.Since(namespaceInfo.CreationTimestamp.Time)),
|
||||
}
|
||||
index++
|
||||
}
|
||||
|
||||
return list, nil
|
||||
return nsList, nil
|
||||
}
|
||||
|
||||
// LoadNamespaceDetail query detail info of a namespace by name
|
||||
|
||||
@@ -30,10 +30,8 @@ var _ = Describe("test cluster namespace", func() {
|
||||
It("list cluster namespace", func() {
|
||||
cnsList, err := ListClusterNamespaces(ctx, k8sClient)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(len(cnsList.Header())).To(Equal(3))
|
||||
Expect(cnsList.Header()).To(Equal([]string{"Name", "Status", "Age"}))
|
||||
Expect(len(cnsList.Body())).To(Equal(2))
|
||||
Expect(cnsList.Body()[1][0]).To(Equal("default"))
|
||||
Expect(len(cnsList.ToTableBody())).To(Equal(2))
|
||||
Expect(cnsList.ToTableBody()[1]).To(Equal([]string{"default", "Active", ""}))
|
||||
})
|
||||
It("load cluster namespace detail info", func() {
|
||||
ns, err := LoadNamespaceDetail(ctx, k8sClient, "default")
|
||||
|
||||
@@ -25,28 +25,20 @@ import (
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestClusterList_Header(t *testing.T) {
|
||||
clusterList := &ClusterList{title: []string{"Name", "Alias", "Type", "EndPoint", "Labels"}}
|
||||
assert.Equal(t, len(clusterList.Header()), 5)
|
||||
assert.Equal(t, clusterList.Header(), []string{"Name", "Alias", "Type", "EndPoint", "Labels"})
|
||||
func TestClusterList_ToTableBody(t *testing.T) {
|
||||
clusterList := &ClusterList{{"local", "", "", "", ""}}
|
||||
assert.Equal(t, len(clusterList.ToTableBody()), 2)
|
||||
assert.Equal(t, clusterList.ToTableBody()[1], []string{"local", "", "", "", ""})
|
||||
}
|
||||
|
||||
func TestClusterList_Body(t *testing.T) {
|
||||
clusterList := &ClusterList{data: []Cluster{{"local", "", "", "", ""}}}
|
||||
assert.Equal(t, len(clusterList.Body()), 1)
|
||||
assert.Equal(t, clusterList.Body()[0], []string{"local", "", "", "", ""})
|
||||
}
|
||||
|
||||
var _ = Describe("test cluster", func() {
|
||||
var _ = Describe("test cluster list", func() {
|
||||
ctx := context.WithValue(context.Background(), &CtxKeyAppName, "first-vela-app")
|
||||
ctx = context.WithValue(ctx, &CtxKeyNamespace, "default")
|
||||
|
||||
It("list clusters", func() {
|
||||
clusterList, err := ListClusters(ctx, k8sClient)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(len(clusterList.Header())).To(Equal(5))
|
||||
Expect(clusterList.Header()).To(Equal([]string{"Name", "Alias", "Type", "EndPoint", "Labels"}))
|
||||
Expect(len(clusterList.Body())).To(Equal(2))
|
||||
Expect(clusterList.Body()[1]).To(Equal([]string{"local", "", "Internal", "-", ""}))
|
||||
Expect(len(clusterList.ToTableBody())).To(Equal(2))
|
||||
Expect(clusterList.ToTableBody()[1]).To(Equal([]string{"local", "", "Internal", "-", ""}))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -34,56 +34,13 @@ type ManagedResource struct {
|
||||
status string
|
||||
}
|
||||
|
||||
// ManagedResourceList is k8s struct resource list
|
||||
type ManagedResourceList struct {
|
||||
title []string
|
||||
data []ManagedResource
|
||||
}
|
||||
|
||||
// Header generate header of table in k8s object view
|
||||
func (l *ManagedResourceList) Header() []string {
|
||||
return l.title
|
||||
}
|
||||
|
||||
// Body generate header of table in k8s object view
|
||||
func (l *ManagedResourceList) Body() [][]string {
|
||||
data := make([][]string, 0)
|
||||
for _, app := range l.data {
|
||||
data = append(data, []string{app.name, app.namespace, app.kind, app.apiVersion, app.cluster, app.status})
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// FilterCluster filter out objects that belong to the target cluster
|
||||
func (l *ManagedResourceList) FilterCluster(cluster string) {
|
||||
data := make([]ManagedResource, 0)
|
||||
for _, app := range l.data {
|
||||
if app.cluster == cluster {
|
||||
data = append(data, ManagedResource{app.name, app.namespace, app.kind, app.apiVersion, app.cluster, app.status})
|
||||
}
|
||||
}
|
||||
l.data = data
|
||||
}
|
||||
|
||||
// FilterClusterNamespace filter out objects that belong to the target namespace
|
||||
func (l *ManagedResourceList) FilterClusterNamespace(clusterNS string) {
|
||||
data := make([]ManagedResource, 0)
|
||||
for _, app := range l.data {
|
||||
if app.namespace == clusterNS {
|
||||
data = append(data, ManagedResource{app.name, app.namespace, app.kind, app.apiVersion, app.cluster, app.status})
|
||||
}
|
||||
}
|
||||
l.data = data
|
||||
}
|
||||
// ManagedResourceList is managed resource list
|
||||
type ManagedResourceList []ManagedResource
|
||||
|
||||
// ListManagedResource return managed resources of application
|
||||
func ListManagedResource(ctx context.Context, c client.Client) (*ManagedResourceList, error) {
|
||||
list := &ManagedResourceList{
|
||||
title: []string{"Name", "Namespace", "Kind", "APIVersion", "Cluster", "Status"},
|
||||
}
|
||||
func ListManagedResource(ctx context.Context, c client.Client) (ManagedResourceList, error) {
|
||||
name := ctx.Value(&CtxKeyAppName).(string)
|
||||
namespace := ctx.Value(&CtxKeyNamespace).(string)
|
||||
|
||||
opt := query.Option{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
@@ -92,19 +49,21 @@ func ListManagedResource(ctx context.Context, c client.Client) (*ManagedResource
|
||||
|
||||
collector := query.NewAppCollector(c, opt)
|
||||
appResList, err := collector.CollectResourceFromApp(ctx)
|
||||
|
||||
if err != nil {
|
||||
return list, err
|
||||
return ManagedResourceList{}, err
|
||||
}
|
||||
|
||||
for _, resource := range appResList {
|
||||
list.data = append(list.data, LoadResourceDetail(resource))
|
||||
list := make(ManagedResourceList, len(appResList))
|
||||
|
||||
for index, resource := range appResList {
|
||||
list[index] = LoadResourceDetail(resource)
|
||||
}
|
||||
|
||||
cluster, ok := ctx.Value(&CtxKeyCluster).(string)
|
||||
if ok && cluster != "" {
|
||||
list.FilterCluster(cluster)
|
||||
}
|
||||
|
||||
clusterNamespace, ok := ctx.Value(&CtxKeyClusterNamespace).(string)
|
||||
if ok && clusterNamespace != "" {
|
||||
list.FilterClusterNamespace(clusterNamespace)
|
||||
@@ -113,6 +72,15 @@ func ListManagedResource(ctx context.Context, c client.Client) (*ManagedResource
|
||||
return list, nil
|
||||
}
|
||||
|
||||
// ToTableBody generate header of table in managed resource view
|
||||
func (l ManagedResourceList) ToTableBody() [][]string {
|
||||
data := make([][]string, 0)
|
||||
for _, resource := range l {
|
||||
data = append(data, []string{resource.name, resource.namespace, resource.kind, resource.apiVersion, resource.cluster, resource.status})
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// LoadResourceDetail return the aim resource detail info
|
||||
func LoadResourceDetail(resource query.Resource) ManagedResource {
|
||||
object := ManagedResource{
|
||||
@@ -128,3 +96,25 @@ func LoadResourceDetail(resource query.Resource) ManagedResource {
|
||||
}
|
||||
return object
|
||||
}
|
||||
|
||||
// FilterCluster filter out objects that belong to the target cluster
|
||||
func (l *ManagedResourceList) FilterCluster(clusterName string) {
|
||||
data := make([]ManagedResource, 0)
|
||||
for _, resource := range *l {
|
||||
if resource.cluster == clusterName {
|
||||
data = append(data, ManagedResource{resource.name, resource.namespace, resource.kind, resource.apiVersion, resource.cluster, resource.status})
|
||||
}
|
||||
}
|
||||
*l = data
|
||||
}
|
||||
|
||||
// FilterClusterNamespace filter out objects that belong to the target namespace
|
||||
func (l *ManagedResourceList) FilterClusterNamespace(clusterNS string) {
|
||||
data := make([]ManagedResource, 0)
|
||||
for _, app := range *l {
|
||||
if app.namespace == clusterNS {
|
||||
data = append(data, ManagedResource{app.name, app.namespace, app.kind, app.apiVersion, app.cluster, app.status})
|
||||
}
|
||||
}
|
||||
*l = data
|
||||
}
|
||||
|
||||
@@ -25,16 +25,27 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestManagedResource_Header(t *testing.T) {
|
||||
list := ManagedResourceList{title: []string{"name", "namespace", "kind", "APIVersion", "cluster", "status"}}
|
||||
assert.Equal(t, len(list.Header()), 6)
|
||||
assert.Equal(t, list.Header(), []string{"name", "namespace", "kind", "APIVersion", "cluster", "status"})
|
||||
func TestListManagedResource(t *testing.T) {
|
||||
list := ManagedResourceList{{"", "", "", "", "", ""}}
|
||||
assert.Equal(t, list.ToTableBody(), [][]string{{"", "", "", "", "", ""}})
|
||||
}
|
||||
|
||||
func TestManagedResource_Body(t *testing.T) {
|
||||
list := ManagedResourceList{data: []ManagedResource{{"", "", "", "", "", ""}}}
|
||||
assert.Equal(t, len(list.Body()), 1)
|
||||
assert.Equal(t, list.Body(), [][]string{{"", "", "", "", "", ""}})
|
||||
func TestManagedResourceList_FilterCluster(t *testing.T) {
|
||||
list := ManagedResourceList{
|
||||
{"", "", "", "", "1", ""},
|
||||
{"", "", "", "", "2", ""},
|
||||
}
|
||||
list.FilterCluster("1")
|
||||
assert.Equal(t, len(list), 1)
|
||||
}
|
||||
|
||||
func TestManagedResourceList_FilterClusterNamespace(t *testing.T) {
|
||||
list := ManagedResourceList{
|
||||
{"", "1", "", "", "1", ""},
|
||||
{"", "2", "", "", "2", ""},
|
||||
}
|
||||
list.FilterClusterNamespace("2")
|
||||
assert.Equal(t, len(list), 1)
|
||||
}
|
||||
|
||||
var _ = Describe("test managed resource", func() {
|
||||
@@ -46,7 +57,6 @@ var _ = Describe("test managed resource", func() {
|
||||
It("list managed resource", func() {
|
||||
list, err := ListManagedResource(ctx, k8sClient)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(len(list.Header())).To(Equal(6))
|
||||
Expect(len(list.Body())).To(Equal(4))
|
||||
Expect(len(list.ToTableBody())).To(Equal(4))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -28,41 +28,37 @@ import (
|
||||
|
||||
// Namespace is namespace struct
|
||||
type Namespace struct {
|
||||
Name string
|
||||
Status string
|
||||
Age string
|
||||
name string
|
||||
status string
|
||||
age string
|
||||
}
|
||||
|
||||
// AllNamespace is the key which represents all namespaces
|
||||
const AllNamespace = "all"
|
||||
// NamespaceList is namespace list
|
||||
type NamespaceList []Namespace
|
||||
|
||||
// ListNamespaces return all namespaces
|
||||
func ListNamespaces(ctx context.Context, c client.Reader) *NamespaceList {
|
||||
list := &NamespaceList{title: []string{"Name", "Status", "Age"}, data: []Namespace{{Name: AllNamespace, Status: "*", Age: "*"}}}
|
||||
func ListNamespaces(ctx context.Context, c client.Client) (NamespaceList, error) {
|
||||
var nsList v1.NamespaceList
|
||||
if err := c.List(ctx, &nsList); err != nil {
|
||||
return list
|
||||
return NamespaceList{}, err
|
||||
}
|
||||
for _, ns := range nsList.Items {
|
||||
list.data = append(list.data, Namespace{
|
||||
Name: ns.Name,
|
||||
Status: string(ns.Status.Phase),
|
||||
Age: utils.TimeFormat(time.Since(ns.CreationTimestamp.Time)),
|
||||
})
|
||||
nsInfoList := make(NamespaceList, len(nsList.Items))
|
||||
for index, ns := range nsList.Items {
|
||||
nsInfoList[index] = Namespace{
|
||||
name: ns.Name,
|
||||
status: string(ns.Status.Phase),
|
||||
age: utils.TimeFormat(time.Since(ns.CreationTimestamp.Time)),
|
||||
}
|
||||
}
|
||||
return list
|
||||
return nsInfoList, nil
|
||||
}
|
||||
|
||||
// Header generate header of table in namespace view
|
||||
func (l *NamespaceList) Header() []string {
|
||||
return l.title
|
||||
}
|
||||
|
||||
// Body generate body of table in namespace view
|
||||
func (l *NamespaceList) Body() [][]string {
|
||||
data := make([][]string, 0)
|
||||
for _, ns := range l.data {
|
||||
data = append(data, []string{ns.Name, ns.Status, ns.Age})
|
||||
// ToTableBody generate body of table in namespace view
|
||||
func (l NamespaceList) ToTableBody() [][]string {
|
||||
data := make([][]string, len(l)+1)
|
||||
data[0] = []string{"all", "*", "*"}
|
||||
for index, ns := range l {
|
||||
data[index+1] = []string{ns.name, ns.status, ns.age}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
@@ -25,30 +25,18 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNamespaceList_Header(t *testing.T) {
|
||||
nsList := NamespaceList{
|
||||
title: []string{"Name", "Status", "Age"},
|
||||
data: []Namespace{{Name: AllNamespace, Status: "*", Age: "*"}},
|
||||
}
|
||||
assert.Equal(t, nsList.Header(), []string{"Name", "Status", "Age"})
|
||||
}
|
||||
|
||||
func TestNamespaceList_Body(t *testing.T) {
|
||||
nsList := NamespaceList{
|
||||
title: []string{"Name", "Status", "Age"},
|
||||
data: []Namespace{{Name: AllNamespace, Status: "*", Age: "*"}},
|
||||
}
|
||||
assert.Equal(t, len(nsList.Body()), 1)
|
||||
assert.Equal(t, nsList.Body()[0], []string{AllNamespace, "*", "*"})
|
||||
nsList := NamespaceList{}
|
||||
assert.Equal(t, len(nsList.ToTableBody()), 1)
|
||||
assert.Equal(t, nsList.ToTableBody()[0], []string{AllNamespace, "*", "*"})
|
||||
}
|
||||
|
||||
var _ = Describe("test namespace", func() {
|
||||
ctx := context.Background()
|
||||
It("list namespace", func() {
|
||||
nsList := ListNamespaces(ctx, k8sClient)
|
||||
Expect(len(nsList.Header())).To(Equal(3))
|
||||
Expect(nsList.Header()).To(Equal([]string{"Name", "Status", "Age"}))
|
||||
Expect(len(nsList.Body())).To(Equal(6))
|
||||
Expect(nsList.Body()[0]).To(Equal([]string{"all", "*", "*"}))
|
||||
nsList, err := ListNamespaces(ctx, k8sClient)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(len(nsList.ToTableBody())).To(Equal(6))
|
||||
Expect(nsList.ToTableBody()[0]).To(Equal([]string{"all", "*", "*"}))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -49,14 +49,10 @@ type Pod struct {
|
||||
}
|
||||
|
||||
// PodList is pod list
|
||||
type PodList struct {
|
||||
title []string
|
||||
data []Pod
|
||||
}
|
||||
type PodList []Pod
|
||||
|
||||
// ListPods return pod list of component
|
||||
func ListPods(ctx context.Context, cfg *rest.Config, c client.Client) (*PodList, error) {
|
||||
list := &PodList{title: []string{"Name", "Namespace", "Ready", "Status", "CPU", "MEM", "%CPU/R", "%CPU/L", "%MEM/R", "%MEM/L", "IP", "Node", "Age"}, data: []Pod{}}
|
||||
func ListPods(ctx context.Context, cfg *rest.Config, c client.Client) (PodList, error) {
|
||||
appName := ctx.Value(&CtxKeyAppName).(string)
|
||||
appNamespace := ctx.Value(&CtxKeyNamespace).(string)
|
||||
compCluster := ctx.Value(&CtxKeyCluster).(string)
|
||||
@@ -76,16 +72,18 @@ func ListPods(ctx context.Context, cfg *rest.Config, c client.Client) (*PodList,
|
||||
WithTree: true,
|
||||
}
|
||||
resource, err := collectResource(ctx, c, opt)
|
||||
|
||||
if err != nil {
|
||||
return list, err
|
||||
return PodList{}, err
|
||||
}
|
||||
for _, object := range resource {
|
||||
list := make(PodList, len(resource))
|
||||
for index, object := range resource {
|
||||
pod := &v1.Pod{}
|
||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(object.UnstructuredContent(), pod)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
list.data = append(list.data, LoadPodDetail(cfg, pod))
|
||||
list[index] = LoadPodDetail(cfg, pod)
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
@@ -127,16 +125,11 @@ func readyContainerNum(pod *v1.Pod) string {
|
||||
return fmt.Sprintf("%d/%d", ready, total)
|
||||
}
|
||||
|
||||
// Header generate header of table in pod view
|
||||
func (l *PodList) Header() []string {
|
||||
return l.title
|
||||
}
|
||||
|
||||
// Body generate body of table in pod view
|
||||
func (l *PodList) Body() [][]string {
|
||||
data := make([][]string, 0)
|
||||
for _, pod := range l.data {
|
||||
data = append(data, []string{pod.Name, pod.Namespace, pod.Ready, pod.Status, pod.CPU, pod.Mem, pod.CPUR, pod.MemR, pod.CPUL, pod.MemL, pod.IP, pod.NodeName, pod.Age})
|
||||
// ToTableBody generate body of table in pod view
|
||||
func (l PodList) ToTableBody() [][]string {
|
||||
data := make([][]string, len(l))
|
||||
for index, pod := range l {
|
||||
data[index] = []string{pod.Name, pod.Namespace, pod.Ready, pod.Status, pod.CPU, pod.Mem, pod.CPUR, pod.MemR, pod.CPUL, pod.MemL, pod.IP, pod.NodeName, pod.Age}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestPod(t *testing.T) {
|
||||
func TestPodList_ToTableBody(t *testing.T) {
|
||||
pod := Pod{
|
||||
Name: "",
|
||||
Namespace: "",
|
||||
@@ -44,10 +44,8 @@ func TestPod(t *testing.T) {
|
||||
NodeName: "",
|
||||
Age: "",
|
||||
}
|
||||
podList := &PodList{title: []string{"Name", "Namespace", "Ready", "Status", "CPU", "MEM", "%CPU/R", "%CPU/L", "%MEM/R", "%MEM/L", "IP", "Node", "Age"}, data: []Pod{pod}}
|
||||
assert.Equal(t, len(podList.Header()), 13)
|
||||
assert.Equal(t, podList.Header()[0], "Name")
|
||||
assert.Equal(t, len(podList.Body()), 1)
|
||||
podList := &PodList{pod}
|
||||
assert.Equal(t, len(podList.ToTableBody()), 1)
|
||||
}
|
||||
|
||||
var _ = Describe("test pod", func() {
|
||||
@@ -61,7 +59,7 @@ var _ = Describe("test pod", func() {
|
||||
It("list pods", func() {
|
||||
podList, err := ListPods(ctx, cfg, k8sClient)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(len(podList.Body())).To(Equal(1))
|
||||
Expect(len(podList.ToTableBody())).To(Equal(1))
|
||||
})
|
||||
|
||||
It("load pod detail", func() {
|
||||
|
||||
@@ -65,6 +65,8 @@ var (
|
||||
)
|
||||
|
||||
const (
|
||||
// AllNamespace represent all namespaces
|
||||
AllNamespace = "all"
|
||||
// AllClusterNamespace represent all cluster namespace
|
||||
AllClusterNamespace = "all"
|
||||
// AllCluster represent all cluster
|
||||
|
||||
@@ -19,7 +19,6 @@ package view
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
|
||||
@@ -31,40 +30,75 @@ import (
|
||||
|
||||
// ApplicationView is the application view, this view display info of application of KubeVela
|
||||
type ApplicationView struct {
|
||||
*ResourceView
|
||||
*CommonResourceView
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// NewApplicationView return a new application view
|
||||
func NewApplicationView(ctx context.Context, app *App) model.Component {
|
||||
v := &ApplicationView{
|
||||
ResourceView: NewResourceView(app),
|
||||
ctx: ctx,
|
||||
}
|
||||
return v
|
||||
// Name return application view name
|
||||
func (v *ApplicationView) Name() string {
|
||||
return "Application"
|
||||
}
|
||||
|
||||
// Init the application view
|
||||
func (v *ApplicationView) Init() {
|
||||
// set title of view
|
||||
title := fmt.Sprintf("[ %s ]", v.Title())
|
||||
v.SetTitle(title).SetTitleColor(config.ResourceTableTitleColor)
|
||||
v.CommonResourceView.Init()
|
||||
v.SetTitle(fmt.Sprintf("[ %s ]", v.Title()))
|
||||
v.BuildHeader()
|
||||
v.bindKeys()
|
||||
}
|
||||
|
||||
// ListApplications list all applications
|
||||
func (v *ApplicationView) ListApplications() model.ResourceList {
|
||||
list, err := model.ListApplications(v.ctx, v.app.client)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
// Start the application view
|
||||
func (v *ApplicationView) Start() {
|
||||
v.Update()
|
||||
}
|
||||
|
||||
// Stop the application view
|
||||
func (v *ApplicationView) Stop() {
|
||||
v.Table.Stop()
|
||||
}
|
||||
|
||||
// Hint return key action menu hints of the application view
|
||||
func (v *ApplicationView) Hint() []model.MenuHint {
|
||||
return v.Actions().Hint()
|
||||
}
|
||||
|
||||
// InitView return a new application view
|
||||
func (v *ApplicationView) InitView(ctx context.Context, app *App) {
|
||||
if v.CommonResourceView == nil {
|
||||
v.CommonResourceView = NewCommonView(app)
|
||||
v.ctx = ctx
|
||||
} else {
|
||||
v.ctx = ctx
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// Update refresh the content of body of view
|
||||
func (v *ApplicationView) Update() {
|
||||
v.BuildBody()
|
||||
}
|
||||
|
||||
// BuildHeader render the header of table
|
||||
func (v *ApplicationView) BuildHeader() {
|
||||
header := []string{"Name", "Namespace", "Phase", "CreateTime"}
|
||||
v.CommonResourceView.BuildHeader(header)
|
||||
}
|
||||
|
||||
// BuildBody render the body of table
|
||||
func (v *ApplicationView) BuildBody() {
|
||||
apps, err := model.ListApplications(v.ctx, v.app.client)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
appInfos := apps.ToTableBody()
|
||||
v.CommonResourceView.BuildBody(appInfos)
|
||||
rowNum := len(appInfos)
|
||||
v.ColorizeStatusText(rowNum)
|
||||
}
|
||||
|
||||
// ColorizeStatusText colorize the status column text
|
||||
func (v *ApplicationView) ColorizeStatusText(rowNum int) {
|
||||
for i := 1; i < rowNum+1; i++ {
|
||||
status := v.Table.GetCell(i, 2).Text
|
||||
for i := 0; i < rowNum; i++ {
|
||||
status := v.Table.GetCell(i+1, 2).Text
|
||||
switch common.ApplicationPhase(status) {
|
||||
case common.ApplicationRendering, common.ApplicationStarting:
|
||||
status = config.ApplicationStartingAndRenderingPhaseColor + status
|
||||
@@ -76,7 +110,7 @@ func (v *ApplicationView) ColorizeStatusText(rowNum int) {
|
||||
status = config.ApplicationRunningPhaseColor + status
|
||||
default:
|
||||
}
|
||||
v.Table.GetCell(i, 2).SetText(status)
|
||||
v.Table.GetCell(i+1, 2).SetText(status)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,28 +123,6 @@ func (v *ApplicationView) Title() string {
|
||||
return fmt.Sprintf("Application"+" (%s)", namespace)
|
||||
}
|
||||
|
||||
// Name return application view name
|
||||
func (v *ApplicationView) Name() string {
|
||||
return "Application"
|
||||
}
|
||||
|
||||
// Start the application view
|
||||
func (v *ApplicationView) Start() {
|
||||
resourceList := v.ListApplications()
|
||||
v.ResourceView.Init(resourceList)
|
||||
v.ColorizeStatusText(len(resourceList.Body()))
|
||||
}
|
||||
|
||||
// Stop the application view
|
||||
func (v *ApplicationView) Stop() {
|
||||
v.Table.Stop()
|
||||
}
|
||||
|
||||
// Hint return key action menu hints of the application view
|
||||
func (v *ApplicationView) Hint() []model.MenuHint {
|
||||
return v.Actions().Hint()
|
||||
}
|
||||
|
||||
func (v *ApplicationView) bindKeys() {
|
||||
v.Actions().Delete([]tcell.Key{tcell.KeyEnter})
|
||||
v.Actions().Add(model.KeyActions{
|
||||
@@ -127,6 +139,7 @@ func (v *ApplicationView) managedResourceView(event *tcell.EventKey) *tcell.Even
|
||||
if row == 0 {
|
||||
return event
|
||||
}
|
||||
|
||||
name, namespace := v.GetCell(row, 0).Text, v.GetCell(row, 1).Text
|
||||
v.ctx = context.WithValue(v.ctx, &model.CtxKeyAppName, name)
|
||||
v.ctx = context.WithValue(v.ctx, &model.CtxKeyNamespace, namespace)
|
||||
|
||||
@@ -43,22 +43,30 @@ func TestApplicationView(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
app := NewApp(testClient, cfg, "")
|
||||
assert.Equal(t, len(app.Components()), 4)
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = context.WithValue(ctx, &model.CtxKeyNamespace, "")
|
||||
view := NewApplicationView(ctx, app)
|
||||
appView, ok := (view).(*ApplicationView)
|
||||
assert.Equal(t, ok, true)
|
||||
appView := new(ApplicationView)
|
||||
|
||||
t.Run("init view", func(t *testing.T) {
|
||||
assert.Empty(t, appView.CommonResourceView)
|
||||
appView.InitView(ctx, app)
|
||||
assert.NotEmpty(t, appView.CommonResourceView)
|
||||
})
|
||||
|
||||
t.Run("init", func(t *testing.T) {
|
||||
appView.Init()
|
||||
assert.Equal(t, appView.Table.GetTitle(), "[ Application (all) ]")
|
||||
})
|
||||
t.Run("start", func(t *testing.T) {
|
||||
appView.Start()
|
||||
assert.Equal(t, appView.GetCell(0, 0).Text, "Name")
|
||||
})
|
||||
|
||||
t.Run("start", func(t *testing.T) {
|
||||
appView.Start()
|
||||
})
|
||||
|
||||
t.Run("stop", func(t *testing.T) {
|
||||
appView.Stop()
|
||||
assert.Equal(t, appView.GetCell(0, 0).Text, "")
|
||||
})
|
||||
|
||||
t.Run("colorize text", func(t *testing.T) {
|
||||
@@ -79,7 +87,17 @@ func TestApplicationView(t *testing.T) {
|
||||
assert.Equal(t, len(appView.Hint()), 5)
|
||||
})
|
||||
|
||||
t.Run("object view", func(t *testing.T) {
|
||||
t.Run("managed resource view", func(t *testing.T) {
|
||||
appView.Table.Table = appView.Table.Select(1, 1)
|
||||
assert.Empty(t, appView.managedResourceView(nil))
|
||||
})
|
||||
|
||||
t.Run("namespace view", func(t *testing.T) {
|
||||
appView.Table.Table = appView.Table.Select(1, 1)
|
||||
assert.Empty(t, appView.namespaceView(nil))
|
||||
})
|
||||
|
||||
t.Run("yaml view", func(t *testing.T) {
|
||||
appView.Table.Table = appView.Table.Select(1, 1)
|
||||
assert.Empty(t, appView.managedResourceView(nil))
|
||||
})
|
||||
|
||||
@@ -19,9 +19,9 @@ package view
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
|
||||
"github.com/oam-dev/kubevela/references/cli/top/component"
|
||||
"github.com/oam-dev/kubevela/references/cli/top/config"
|
||||
@@ -30,44 +30,26 @@ import (
|
||||
|
||||
// ClusterNamespaceView is the cluster namespace, which display the namespace info of application's resource
|
||||
type ClusterNamespaceView struct {
|
||||
*ResourceView
|
||||
*CommonResourceView
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// NewClusterNamespaceView return a new cluster namespace view
|
||||
func NewClusterNamespaceView(ctx context.Context, app *App) model.Component {
|
||||
v := &ClusterNamespaceView{
|
||||
ResourceView: NewResourceView(app),
|
||||
ctx: ctx,
|
||||
}
|
||||
return v
|
||||
// Name return cluster namespace view name
|
||||
func (v *ClusterNamespaceView) Name() string {
|
||||
return "ClusterNamespace"
|
||||
}
|
||||
|
||||
// Init the cluster namespace view
|
||||
func (v *ClusterNamespaceView) Init() {
|
||||
title := fmt.Sprintf("[ %s ]", v.Name())
|
||||
v.SetTitle(title).SetTitleColor(config.ResourceTableTitleColor)
|
||||
v.CommonResourceView.Init()
|
||||
v.SetTitle(fmt.Sprintf("[ %s ]", v.Name())).SetTitleColor(config.ResourceTableTitleColor)
|
||||
v.BuildHeader()
|
||||
v.bindKeys()
|
||||
}
|
||||
|
||||
// ListClusterNamespaces return the namespace of application's resource
|
||||
func (v *ClusterNamespaceView) ListClusterNamespaces() model.ResourceList {
|
||||
list, err := model.ListClusterNamespaces(v.ctx, v.app.client)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// Hint return key action menu hints of the cluster namespace view
|
||||
func (v *ClusterNamespaceView) Hint() []model.MenuHint {
|
||||
return v.Actions().Hint()
|
||||
}
|
||||
|
||||
// Start the cluster namespace view
|
||||
func (v *ClusterNamespaceView) Start() {
|
||||
resourceList := v.ListClusterNamespaces()
|
||||
v.ResourceView.Init(resourceList)
|
||||
v.Update()
|
||||
}
|
||||
|
||||
// Stop the cluster namespace view
|
||||
@@ -75,9 +57,56 @@ func (v *ClusterNamespaceView) Stop() {
|
||||
v.Table.Stop()
|
||||
}
|
||||
|
||||
// Name return cluster namespace view name
|
||||
func (v *ClusterNamespaceView) Name() string {
|
||||
return "ClusterNamespace"
|
||||
// Hint return key action menu hints of the cluster namespace view
|
||||
func (v *ClusterNamespaceView) Hint() []model.MenuHint {
|
||||
return v.Actions().Hint()
|
||||
}
|
||||
|
||||
// InitView init a new cluster namespace view
|
||||
func (v *ClusterNamespaceView) InitView(ctx context.Context, app *App) {
|
||||
if v.CommonResourceView == nil {
|
||||
v.CommonResourceView = NewCommonView(app)
|
||||
v.ctx = ctx
|
||||
} else {
|
||||
v.ctx = ctx
|
||||
}
|
||||
}
|
||||
|
||||
// Update refresh the content of body of view
|
||||
func (v *ClusterNamespaceView) Update() {
|
||||
v.BuildBody()
|
||||
}
|
||||
|
||||
// BuildHeader render the header of table
|
||||
func (v *ClusterNamespaceView) BuildHeader() {
|
||||
header := []string{"Name", "Status", "Age"}
|
||||
v.CommonResourceView.BuildHeader(header)
|
||||
}
|
||||
|
||||
// BuildBody render the body of table
|
||||
func (v *ClusterNamespaceView) BuildBody() {
|
||||
cnList, err := model.ListClusterNamespaces(v.ctx, v.app.client)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cnInfos := cnList.ToTableBody()
|
||||
v.CommonResourceView.BuildBody(cnInfos)
|
||||
rowNum := len(cnInfos)
|
||||
v.ColorizeStatusText(rowNum)
|
||||
}
|
||||
|
||||
// ColorizeStatusText colorize the status column text
|
||||
func (v *ClusterNamespaceView) ColorizeStatusText(rowNum int) {
|
||||
for i := 0; i < rowNum; i++ {
|
||||
status := v.Table.GetCell(i+1, 2).Text
|
||||
switch v1.NamespacePhase(status) {
|
||||
case v1.NamespaceActive:
|
||||
status = config.NamespaceActiveStatusColor + status
|
||||
case v1.NamespaceTerminating:
|
||||
status = config.NamespaceTerminateStatusColor + status
|
||||
}
|
||||
v.Table.GetCell(i+1, 2).SetText(status)
|
||||
}
|
||||
}
|
||||
|
||||
func (v *ClusterNamespaceView) bindKeys() {
|
||||
@@ -95,11 +124,12 @@ func (v *ClusterNamespaceView) managedResourceView(event *tcell.EventKey) *tcell
|
||||
if row == 0 {
|
||||
return event
|
||||
}
|
||||
v.app.content.PopComponent()
|
||||
|
||||
clusterNamespace := v.GetCell(row, 0).Text
|
||||
if clusterNamespace == model.AllClusterNamespace {
|
||||
clusterNamespace = ""
|
||||
}
|
||||
v.app.content.PopComponent()
|
||||
v.ctx = context.WithValue(v.ctx, &model.CtxKeyClusterNamespace, clusterNamespace)
|
||||
v.app.command.run(v.ctx, "resource")
|
||||
return event
|
||||
|
||||
@@ -42,31 +42,39 @@ func TestClusterNamespaceView(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
app := NewApp(testClient, cfg, "")
|
||||
assert.Equal(t, len(app.Components()), 4)
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = context.WithValue(ctx, &model.CtxKeyAppName, "")
|
||||
ctx = context.WithValue(ctx, &model.CtxKeyNamespace, "")
|
||||
cnsView, ok := NewClusterNamespaceView(ctx, app).(*ClusterNamespaceView)
|
||||
assert.Equal(t, ok, true)
|
||||
|
||||
cnsView := new(ClusterNamespaceView)
|
||||
|
||||
t.Run("init view", func(t *testing.T) {
|
||||
assert.Empty(t, cnsView.CommonResourceView)
|
||||
cnsView.InitView(ctx, app)
|
||||
assert.NotEmpty(t, cnsView.CommonResourceView)
|
||||
})
|
||||
|
||||
t.Run("init", func(t *testing.T) {
|
||||
cnsView.Init()
|
||||
assert.Equal(t, cnsView.GetTitle(), "[ ClusterNamespace ]")
|
||||
assert.Equal(t, cnsView.GetCell(0, 0).Text, "Name")
|
||||
})
|
||||
|
||||
t.Run("start", func(t *testing.T) {
|
||||
cnsView.Start()
|
||||
assert.Equal(t, cnsView.GetCell(0, 0).Text, "Name")
|
||||
assert.Equal(t, cnsView.GetCell(1, 0).Text, "all")
|
||||
})
|
||||
|
||||
t.Run("stop", func(t *testing.T) {
|
||||
cnsView.Stop()
|
||||
assert.Equal(t, cnsView.GetCell(0, 0).Text, "")
|
||||
})
|
||||
|
||||
t.Run("hint", func(t *testing.T) {
|
||||
assert.Equal(t, len(cnsView.Hint()), 3)
|
||||
})
|
||||
|
||||
t.Run("object view", func(t *testing.T) {
|
||||
t.Run("managed resource view", func(t *testing.T) {
|
||||
cnsView.Table.Table = cnsView.Table.Select(1, 1)
|
||||
assert.Empty(t, cnsView.managedResourceView(nil))
|
||||
})
|
||||
|
||||
@@ -19,7 +19,6 @@ package view
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
|
||||
@@ -30,36 +29,18 @@ import (
|
||||
|
||||
// ClusterView is the cluster view, this view display info of cluster where selected application deployed
|
||||
type ClusterView struct {
|
||||
*ResourceView
|
||||
*CommonResourceView
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// NewClusterView return a new cluster view
|
||||
func NewClusterView(ctx context.Context, app *App) model.Component {
|
||||
v := &ClusterView{
|
||||
ResourceView: NewResourceView(app),
|
||||
ctx: ctx,
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Init cluster view init
|
||||
func (v *ClusterView) Init() {
|
||||
// set title of view
|
||||
title := fmt.Sprintf("[ %s ]", v.Name())
|
||||
v.SetTitle(title).SetTitleColor(config.ResourceTableTitleColor)
|
||||
v.CommonResourceView.Init()
|
||||
v.SetTitle(fmt.Sprintf("[ %s ]", v.Name())).SetTitleColor(config.ResourceTableTitleColor)
|
||||
v.BuildHeader()
|
||||
v.bindKeys()
|
||||
}
|
||||
|
||||
// ListClusters list clusters where application deployed
|
||||
func (v *ClusterView) ListClusters() model.ResourceList {
|
||||
list, err := model.ListClusters(v.ctx, v.app.client)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// Name return cluster view name
|
||||
func (v *ClusterView) Name() string {
|
||||
return "Cluster"
|
||||
@@ -67,8 +48,7 @@ func (v *ClusterView) Name() string {
|
||||
|
||||
// Start the cluster view
|
||||
func (v *ClusterView) Start() {
|
||||
resourceList := v.ListClusters()
|
||||
v.ResourceView.Init(resourceList)
|
||||
v.Update()
|
||||
}
|
||||
|
||||
// Stop the cluster view
|
||||
@@ -81,6 +61,37 @@ func (v *ClusterView) Hint() []model.MenuHint {
|
||||
return v.Actions().Hint()
|
||||
}
|
||||
|
||||
// InitView init a new cluster view
|
||||
func (v *ClusterView) InitView(ctx context.Context, app *App) {
|
||||
if v.CommonResourceView == nil {
|
||||
v.CommonResourceView = NewCommonView(app)
|
||||
v.ctx = ctx
|
||||
} else {
|
||||
v.ctx = ctx
|
||||
}
|
||||
}
|
||||
|
||||
// Update refresh the content of body of view
|
||||
func (v *ClusterView) Update() {
|
||||
v.BuildBody()
|
||||
}
|
||||
|
||||
// BuildHeader render the header of table
|
||||
func (v *ClusterView) BuildHeader() {
|
||||
header := []string{"Name", "Alias", "Type", "EndPoint", "Labels"}
|
||||
v.CommonResourceView.BuildHeader(header)
|
||||
}
|
||||
|
||||
// BuildBody render the body of table
|
||||
func (v *ClusterView) BuildBody() {
|
||||
clusterList, err := model.ListClusters(v.ctx, v.app.client)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
clusterInfos := clusterList.ToTableBody()
|
||||
v.CommonResourceView.BuildBody(clusterInfos)
|
||||
}
|
||||
|
||||
func (v *ClusterView) bindKeys() {
|
||||
v.Actions().Delete([]tcell.Key{tcell.KeyEnter})
|
||||
v.Actions().Add(model.KeyActions{
|
||||
@@ -96,11 +107,11 @@ func (v *ClusterView) managedResourceView(event *tcell.EventKey) *tcell.EventKey
|
||||
if row == 0 {
|
||||
return event
|
||||
}
|
||||
v.app.content.PopComponent()
|
||||
clusterName := v.GetCell(row, 0).Text
|
||||
if clusterName == model.AllCluster {
|
||||
clusterName = ""
|
||||
}
|
||||
v.app.content.PopComponent()
|
||||
v.ctx = context.WithValue(v.ctx, &model.CtxKeyCluster, clusterName)
|
||||
v.app.command.run(v.ctx, "resource")
|
||||
return event
|
||||
|
||||
@@ -43,16 +43,23 @@ func TestClusterView(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
app := NewApp(testClient, cfg, "")
|
||||
assert.Equal(t, len(app.Components()), 4)
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = context.WithValue(ctx, &model.CtxKeyAppName, "")
|
||||
ctx = context.WithValue(ctx, &model.CtxKeyNamespace, "")
|
||||
view := NewClusterView(ctx, app)
|
||||
clusterView, ok := (view).(*ClusterView)
|
||||
assert.Equal(t, ok, true)
|
||||
|
||||
clusterView := new(ClusterView)
|
||||
|
||||
t.Run("init view", func(t *testing.T) {
|
||||
assert.Empty(t, clusterView.CommonResourceView)
|
||||
clusterView.InitView(ctx, app)
|
||||
assert.NotEmpty(t, clusterView.CommonResourceView)
|
||||
})
|
||||
|
||||
t.Run("init", func(t *testing.T) {
|
||||
clusterView.Init()
|
||||
assert.Equal(t, clusterView.Table.GetTitle(), "[ Cluster ]")
|
||||
assert.Equal(t, clusterView.GetCell(0, 0).Text, "Name")
|
||||
})
|
||||
|
||||
t.Run("hint", func(t *testing.T) {
|
||||
@@ -61,14 +68,14 @@ func TestClusterView(t *testing.T) {
|
||||
|
||||
t.Run("start", func(t *testing.T) {
|
||||
clusterView.Start()
|
||||
assert.Equal(t, clusterView.GetCell(0, 0).Text, "Name")
|
||||
})
|
||||
|
||||
t.Run("stop", func(t *testing.T) {
|
||||
clusterView.Stop()
|
||||
assert.Equal(t, clusterView.GetCell(0, 0).Text, "")
|
||||
})
|
||||
|
||||
t.Run("managedResourceView", func(t *testing.T) {
|
||||
t.Run("managed resource view", func(t *testing.T) {
|
||||
testData := []string{"local", "", "", "", ""}
|
||||
for j := 0; j < 5; j++ {
|
||||
clusterView.Table.SetCell(1, j, tview.NewTableCell(testData[j]))
|
||||
|
||||
@@ -52,8 +52,9 @@ func (c *Command) run(ctx context.Context, cmd string) {
|
||||
case cmd == "yaml":
|
||||
component = NewYamlView(ctx, c.app)
|
||||
default:
|
||||
if resource, ok := ResourceMap[cmd]; ok {
|
||||
component = resource.viewFunc(ctx, c.app)
|
||||
if resourceView, ok := ResourceViewMap[cmd]; ok {
|
||||
resourceView.InitView(ctx, c.app)
|
||||
component = resourceView
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ package view
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
|
||||
@@ -31,34 +30,37 @@ import (
|
||||
|
||||
// ManagedResourceView is a view which displays info of application's managed resource including CRDs and k8s objects
|
||||
type ManagedResourceView struct {
|
||||
*ResourceView
|
||||
*CommonResourceView
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// NewManagedResourceView return a new managed resource view
|
||||
func NewManagedResourceView(ctx context.Context, app *App) model.Component {
|
||||
v := &ManagedResourceView{
|
||||
ResourceView: NewResourceView(app),
|
||||
ctx: ctx,
|
||||
}
|
||||
return v
|
||||
// Name return managed resource view name
|
||||
func (v *ManagedResourceView) Name() string {
|
||||
return "Managed Resource"
|
||||
}
|
||||
|
||||
// Init managed resource view
|
||||
func (v *ManagedResourceView) Init() {
|
||||
v.CommonResourceView.Init()
|
||||
// set title of view
|
||||
title := fmt.Sprintf("[ %s ]", v.Title())
|
||||
v.SetTitle(title).SetTitleColor(config.ResourceTableTitleColor)
|
||||
v.SetTitle(fmt.Sprintf("[ %s ]", v.Title())).SetTitleColor(config.ResourceTableTitleColor)
|
||||
v.BuildHeader()
|
||||
v.bindKeys()
|
||||
}
|
||||
|
||||
// ListManagedResources return managed resource of the aimed application
|
||||
func (v *ManagedResourceView) ListManagedResources() model.ResourceList {
|
||||
list, err := model.ListManagedResource(v.ctx, v.app.client)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
return list
|
||||
// Start the managed resource view
|
||||
func (v *ManagedResourceView) Start() {
|
||||
v.Update()
|
||||
}
|
||||
|
||||
// Stop the managed resource view
|
||||
func (v *ManagedResourceView) Stop() {
|
||||
v.Table.Stop()
|
||||
}
|
||||
|
||||
// Hint return key action menu hints of the managed resource view
|
||||
func (v *ManagedResourceView) Hint() []model.MenuHint {
|
||||
return v.Actions().Hint()
|
||||
}
|
||||
|
||||
// Title return the table title of managed resource view
|
||||
@@ -74,26 +76,37 @@ func (v *ManagedResourceView) Title() string {
|
||||
return fmt.Sprintf("Managed Resource"+" (%s/%s)", namespace, clusterNS)
|
||||
}
|
||||
|
||||
// Name return managed resource view name
|
||||
func (v *ManagedResourceView) Name() string {
|
||||
return "Managed Resource"
|
||||
// InitView init a new managed resource view
|
||||
func (v *ManagedResourceView) InitView(ctx context.Context, app *App) {
|
||||
if v.CommonResourceView == nil {
|
||||
v.CommonResourceView = NewCommonView(app)
|
||||
v.ctx = ctx
|
||||
} else {
|
||||
v.ctx = ctx
|
||||
}
|
||||
}
|
||||
|
||||
// Start the managed resource view
|
||||
func (v *ManagedResourceView) Start() {
|
||||
resourceList := v.ListManagedResources()
|
||||
v.ResourceView.Init(resourceList)
|
||||
v.ColorizeStatusText(len(resourceList.Body()))
|
||||
// Update refresh the content of body of view
|
||||
func (v *ManagedResourceView) Update() {
|
||||
v.BuildBody()
|
||||
}
|
||||
|
||||
// Stop the managed resource view
|
||||
func (v *ManagedResourceView) Stop() {
|
||||
v.Table.Stop()
|
||||
// BuildHeader render the header of table
|
||||
func (v *ManagedResourceView) BuildHeader() {
|
||||
header := []string{"Name", "Namespace", "Kind", "APIVersion", "Cluster", "Status"}
|
||||
v.CommonResourceView.BuildHeader(header)
|
||||
}
|
||||
|
||||
// Hint return key action menu hints of the managed resource view
|
||||
func (v *ManagedResourceView) Hint() []model.MenuHint {
|
||||
return v.Actions().Hint()
|
||||
// BuildBody render the body of table
|
||||
func (v *ManagedResourceView) BuildBody() {
|
||||
resourceList, err := model.ListManagedResource(v.ctx, v.app.client)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resourceInfos := resourceList.ToTableBody()
|
||||
v.CommonResourceView.BuildBody(resourceInfos)
|
||||
rowNum := len(resourceInfos)
|
||||
v.ColorizeStatusText(rowNum)
|
||||
}
|
||||
|
||||
// ColorizeStatusText colorize the status column text
|
||||
|
||||
@@ -43,28 +43,33 @@ func TestManagedResourceView(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
app := NewApp(testClient, cfg, "")
|
||||
assert.Equal(t, len(app.Components()), 4)
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = context.WithValue(ctx, &model.CtxKeyAppName, "")
|
||||
ctx = context.WithValue(ctx, &model.CtxKeyNamespace, "")
|
||||
ctx = context.WithValue(ctx, &model.CtxKeyCluster, "")
|
||||
|
||||
view := NewManagedResourceView(ctx, app)
|
||||
resourceView, ok := (view).(*ManagedResourceView)
|
||||
assert.Equal(t, ok, true)
|
||||
resourceView := new(ManagedResourceView)
|
||||
|
||||
t.Run("init view", func(t *testing.T) {
|
||||
assert.Empty(t, resourceView.CommonResourceView)
|
||||
resourceView.InitView(ctx, app)
|
||||
assert.NotEmpty(t, resourceView.CommonResourceView)
|
||||
})
|
||||
|
||||
t.Run("init", func(t *testing.T) {
|
||||
resourceView.Init()
|
||||
assert.Equal(t, resourceView.Table.GetTitle(), "[ Managed Resource (all/all) ]")
|
||||
|
||||
assert.Equal(t, resourceView.GetCell(0, 0).Text, "Name")
|
||||
})
|
||||
|
||||
t.Run("start", func(t *testing.T) {
|
||||
resourceView.Start()
|
||||
assert.Equal(t, resourceView.GetCell(0, 0).Text, "Name")
|
||||
})
|
||||
|
||||
t.Run("stop", func(t *testing.T) {
|
||||
resourceView.Stop()
|
||||
assert.Equal(t, resourceView.GetCell(0, 0).Text, "")
|
||||
})
|
||||
|
||||
t.Run("colorize text", func(t *testing.T) {
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
|
||||
"github.com/oam-dev/kubevela/references/cli/top/component"
|
||||
"github.com/oam-dev/kubevela/references/cli/top/config"
|
||||
@@ -29,31 +30,18 @@ import (
|
||||
|
||||
// NamespaceView is namespace view struct
|
||||
type NamespaceView struct {
|
||||
*ResourceView
|
||||
*CommonResourceView
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// NewNamespaceView return a new namespace view
|
||||
func NewNamespaceView(ctx context.Context, app *App) model.Component {
|
||||
v := &NamespaceView{
|
||||
ResourceView: NewResourceView(app),
|
||||
ctx: ctx,
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Init a namespace view
|
||||
func (v *NamespaceView) Init() {
|
||||
title := fmt.Sprintf("[ %s ]", v.Name())
|
||||
v.SetTitle(title).SetTitleColor(config.ResourceTableTitleColor)
|
||||
v.CommonResourceView.Init()
|
||||
v.SetTitle(fmt.Sprintf("[ %s ]", v.Name())).SetTitleColor(config.ResourceTableTitleColor)
|
||||
v.BuildHeader()
|
||||
v.bindKeys()
|
||||
}
|
||||
|
||||
// ListNamespaces return all namespaces
|
||||
func (v *NamespaceView) ListNamespaces() model.ResourceList {
|
||||
return model.ListNamespaces(v.ctx, v.app.client)
|
||||
}
|
||||
|
||||
// Name return k8s view name
|
||||
func (v *NamespaceView) Name() string {
|
||||
return "Namespace"
|
||||
@@ -61,8 +49,7 @@ func (v *NamespaceView) Name() string {
|
||||
|
||||
// Start the managed namespace view
|
||||
func (v *NamespaceView) Start() {
|
||||
resourceList := v.ListNamespaces()
|
||||
v.ResourceView.Init(resourceList)
|
||||
v.Update()
|
||||
}
|
||||
|
||||
// Stop the managed namespace view
|
||||
@@ -75,6 +62,53 @@ func (v *NamespaceView) Hint() []model.MenuHint {
|
||||
return v.Actions().Hint()
|
||||
}
|
||||
|
||||
// InitView init a new namespace view
|
||||
func (v *NamespaceView) InitView(ctx context.Context, app *App) {
|
||||
if v.CommonResourceView == nil {
|
||||
v.CommonResourceView = NewCommonView(app)
|
||||
v.ctx = ctx
|
||||
} else {
|
||||
v.ctx = ctx
|
||||
}
|
||||
}
|
||||
|
||||
// Update refresh the content of body of view
|
||||
func (v *NamespaceView) Update() {
|
||||
v.BuildBody()
|
||||
}
|
||||
|
||||
// BuildHeader render the header of table
|
||||
func (v *NamespaceView) BuildHeader() {
|
||||
header := []string{"Name", "Status", "Age"}
|
||||
v.CommonResourceView.BuildHeader(header)
|
||||
}
|
||||
|
||||
// BuildBody render the body of table
|
||||
func (v *NamespaceView) BuildBody() {
|
||||
nsList, err := model.ListNamespaces(v.ctx, v.app.client)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
nsInfos := nsList.ToTableBody()
|
||||
v.CommonResourceView.BuildBody(nsInfos)
|
||||
rowNum := len(nsInfos)
|
||||
v.ColorizeStatusText(rowNum)
|
||||
}
|
||||
|
||||
// ColorizeStatusText colorize the status column text
|
||||
func (v *NamespaceView) ColorizeStatusText(rowNum int) {
|
||||
for i := 0; i < rowNum; i++ {
|
||||
status := v.Table.GetCell(i+1, 2).Text
|
||||
switch v1.NamespacePhase(status) {
|
||||
case v1.NamespaceActive:
|
||||
status = config.NamespaceActiveStatusColor + status
|
||||
case v1.NamespaceTerminating:
|
||||
status = config.NamespaceTerminateStatusColor + status
|
||||
}
|
||||
v.Table.GetCell(i+1, 2).SetText(status)
|
||||
}
|
||||
}
|
||||
|
||||
func (v *NamespaceView) bindKeys() {
|
||||
v.Actions().Delete([]tcell.Key{tcell.KeyEnter})
|
||||
v.Actions().Add(model.KeyActions{
|
||||
@@ -89,13 +123,12 @@ func (v *NamespaceView) applicationView(event *tcell.EventKey) *tcell.EventKey {
|
||||
if row == 0 {
|
||||
return event
|
||||
}
|
||||
v.app.content.PopComponent()
|
||||
ns := v.Table.GetCell(row, 0).Text
|
||||
if ns == model.AllNamespace {
|
||||
ns = ""
|
||||
}
|
||||
v.app.content.PopComponent()
|
||||
v.ctx = context.WithValue(v.ctx, &model.CtxKeyNamespace, ns)
|
||||
v.app.command.run(v.ctx, "app")
|
||||
|
||||
return event
|
||||
}
|
||||
|
||||
@@ -43,16 +43,23 @@ func TestNamespaceView(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
app := NewApp(testClient, cfg, "")
|
||||
assert.Equal(t, len(app.Components()), 4)
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = context.WithValue(ctx, &model.CtxKeyAppName, "")
|
||||
ctx = context.WithValue(ctx, &model.CtxKeyNamespace, "")
|
||||
view := NewNamespaceView(ctx, app)
|
||||
nsView, ok := (view).(*NamespaceView)
|
||||
assert.Equal(t, ok, true)
|
||||
|
||||
nsView := new(NamespaceView)
|
||||
|
||||
t.Run("init view", func(t *testing.T) {
|
||||
assert.Empty(t, nsView.CommonResourceView)
|
||||
nsView.InitView(ctx, app)
|
||||
assert.NotEmpty(t, nsView.CommonResourceView)
|
||||
})
|
||||
|
||||
t.Run("init", func(t *testing.T) {
|
||||
nsView.Init()
|
||||
assert.Equal(t, nsView.Table.GetTitle(), "[ Namespace ]")
|
||||
assert.Equal(t, nsView.GetCell(0, 0).Text, "Name")
|
||||
})
|
||||
|
||||
t.Run("hint", func(t *testing.T) {
|
||||
@@ -61,14 +68,14 @@ func TestNamespaceView(t *testing.T) {
|
||||
|
||||
t.Run("start", func(t *testing.T) {
|
||||
nsView.Start()
|
||||
assert.Equal(t, nsView.GetCell(0, 0).Text, "Name")
|
||||
})
|
||||
|
||||
t.Run("stop", func(t *testing.T) {
|
||||
nsView.Stop()
|
||||
assert.Equal(t, nsView.GetCell(0, 0).Text, "")
|
||||
})
|
||||
|
||||
t.Run("appView", func(t *testing.T) {
|
||||
t.Run("app view", func(t *testing.T) {
|
||||
testData := []string{"local", "", "", "", ""}
|
||||
for j := 0; j < 5; j++ {
|
||||
nsView.Table.SetCell(1, j, tview.NewTableCell(testData[j]))
|
||||
|
||||
@@ -48,6 +48,7 @@ func (ps *PageStack) StackPop(old, new model.Component) {
|
||||
if new == nil {
|
||||
return
|
||||
}
|
||||
new.Start()
|
||||
ps.app.SetFocus(new)
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ package view
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
@@ -31,34 +30,69 @@ import (
|
||||
|
||||
// PodView is the pod view, this view display info of pod belonging to component
|
||||
type PodView struct {
|
||||
*ResourceView
|
||||
*CommonResourceView
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// NewPodView return a new pod view
|
||||
func NewPodView(ctx context.Context, app *App) model.Component {
|
||||
v := &PodView{
|
||||
ResourceView: NewResourceView(app),
|
||||
ctx: ctx,
|
||||
}
|
||||
return v
|
||||
// Name return pod view name
|
||||
func (v *PodView) Name() string {
|
||||
return "Pod"
|
||||
}
|
||||
|
||||
// Start the pod view
|
||||
func (v *PodView) Start() {
|
||||
v.Update()
|
||||
}
|
||||
|
||||
// Stop the pod view
|
||||
func (v *PodView) Stop() {
|
||||
v.Table.Stop()
|
||||
}
|
||||
|
||||
// Hint return key action menu hints of the pod view
|
||||
func (v *PodView) Hint() []model.MenuHint {
|
||||
return v.Actions().Hint()
|
||||
}
|
||||
|
||||
// Init cluster view init
|
||||
func (v *PodView) Init() {
|
||||
// set title of view
|
||||
title := fmt.Sprintf("[ %s ]", v.Name())
|
||||
v.SetTitle(title).SetTitleColor(config.ResourceTableTitleColor)
|
||||
v.CommonResourceView.Init()
|
||||
v.SetTitle(fmt.Sprintf("[ %s ]", v.Name()))
|
||||
v.BuildHeader()
|
||||
v.bindKeys()
|
||||
}
|
||||
|
||||
// ListPods list pods of component
|
||||
func (v *PodView) ListPods() model.ResourceList {
|
||||
list, err := model.ListPods(v.ctx, v.app.config.RestConfig, v.app.client)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
// InitView init a new pod view
|
||||
func (v *PodView) InitView(ctx context.Context, app *App) {
|
||||
if v.CommonResourceView == nil {
|
||||
v.CommonResourceView = NewCommonView(app)
|
||||
v.ctx = ctx
|
||||
} else {
|
||||
v.ctx = ctx
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// Update refresh the content of body of view
|
||||
func (v *PodView) Update() {
|
||||
v.BuildBody()
|
||||
}
|
||||
|
||||
// BuildHeader render the header of table
|
||||
func (v *PodView) BuildHeader() {
|
||||
header := []string{"Name", "Namespace", "Ready", "Status", "CPU", "MEM", "%CPU/R", "%CPU/L", "%MEM/R", "%MEM/L", "IP", "Node", "Age"}
|
||||
v.CommonResourceView.BuildHeader(header)
|
||||
}
|
||||
|
||||
// BuildBody render the body of table
|
||||
func (v *PodView) BuildBody() {
|
||||
podList, err := model.ListPods(v.ctx, v.app.config.RestConfig, v.app.client)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
podInfos := podList.ToTableBody()
|
||||
v.CommonResourceView.BuildBody(podInfos)
|
||||
rowNum := len(podInfos)
|
||||
v.ColorizePhaseText(rowNum)
|
||||
}
|
||||
|
||||
// ColorizePhaseText colorize the phase column text
|
||||
@@ -80,28 +114,6 @@ func (v *PodView) ColorizePhaseText(rowNum int) {
|
||||
}
|
||||
}
|
||||
|
||||
// Name return pod view name
|
||||
func (v *PodView) Name() string {
|
||||
return "Pod"
|
||||
}
|
||||
|
||||
// Start the pod view
|
||||
func (v *PodView) Start() {
|
||||
resourceList := v.ListPods()
|
||||
v.ResourceView.Init(resourceList)
|
||||
v.ColorizePhaseText(len(resourceList.Body()))
|
||||
}
|
||||
|
||||
// Stop the pod view
|
||||
func (v *PodView) Stop() {
|
||||
v.Table.Stop()
|
||||
}
|
||||
|
||||
// Hint return key action menu hints of the pod view
|
||||
func (v *PodView) Hint() []model.MenuHint {
|
||||
return v.Actions().Hint()
|
||||
}
|
||||
|
||||
func (v *PodView) bindKeys() {
|
||||
v.Actions().Delete([]tcell.Key{tcell.KeyEnter})
|
||||
v.Actions().Add(model.KeyActions{
|
||||
|
||||
@@ -44,6 +44,7 @@ func TestPodView(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
app := NewApp(testClient, cfg, "")
|
||||
assert.Equal(t, len(app.Components()), 4)
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = context.WithValue(ctx, &model.CtxKeyAppName, "")
|
||||
ctx = context.WithValue(ctx, &model.CtxKeyNamespace, "")
|
||||
@@ -51,20 +52,26 @@ func TestPodView(t *testing.T) {
|
||||
ctx = context.WithValue(ctx, &model.CtxKeyClusterNamespace, "")
|
||||
ctx = context.WithValue(ctx, &model.CtxKeyComponentName, "")
|
||||
|
||||
view, ok := NewPodView(ctx, app).(*PodView)
|
||||
assert.Equal(t, ok, true)
|
||||
podView := new(PodView)
|
||||
|
||||
t.Run("init view", func(t *testing.T) {
|
||||
assert.Empty(t, podView.CommonResourceView)
|
||||
podView.InitView(ctx, app)
|
||||
assert.NotEmpty(t, podView.CommonResourceView)
|
||||
})
|
||||
|
||||
t.Run("init", func(t *testing.T) {
|
||||
view.Init()
|
||||
assert.Equal(t, view.Table.GetTitle(), "[ Pod ]")
|
||||
podView.Init()
|
||||
assert.Equal(t, podView.Table.GetTitle(), "[ Pod ]")
|
||||
assert.Equal(t, podView.GetCell(0, 0).Text, "Name")
|
||||
})
|
||||
t.Run("start", func(t *testing.T) {
|
||||
view.Start()
|
||||
assert.Equal(t, view.GetCell(0, 0).Text, "Name")
|
||||
podView.Start()
|
||||
})
|
||||
|
||||
t.Run("stop", func(t *testing.T) {
|
||||
view.Stop()
|
||||
podView.Stop()
|
||||
assert.Equal(t, podView.GetCell(0, 0).Text, "")
|
||||
})
|
||||
|
||||
t.Run("colorize text", func(t *testing.T) {
|
||||
@@ -76,17 +83,17 @@ func TestPodView(t *testing.T) {
|
||||
}
|
||||
for i := 0; i < len(testData); i++ {
|
||||
for j := 0; j < len(testData[i]); j++ {
|
||||
view.Table.SetCell(1+i, j, tview.NewTableCell(testData[i][j]))
|
||||
podView.Table.SetCell(1+i, j, tview.NewTableCell(testData[i][j]))
|
||||
}
|
||||
}
|
||||
view.ColorizePhaseText(5)
|
||||
assert.Equal(t, view.GetCell(1, 3).Text, "[green::]Running")
|
||||
assert.Equal(t, view.GetCell(2, 3).Text, "[yellow::]Pending")
|
||||
assert.Equal(t, view.GetCell(3, 3).Text, "[purple::]Succeeded")
|
||||
assert.Equal(t, view.GetCell(4, 3).Text, "[red::]Failed")
|
||||
podView.ColorizePhaseText(5)
|
||||
assert.Equal(t, podView.GetCell(1, 3).Text, "[green::]Running")
|
||||
assert.Equal(t, podView.GetCell(2, 3).Text, "[yellow::]Pending")
|
||||
assert.Equal(t, podView.GetCell(3, 3).Text, "[purple::]Succeeded")
|
||||
assert.Equal(t, podView.GetCell(4, 3).Text, "[red::]Failed")
|
||||
})
|
||||
|
||||
t.Run("hint", func(t *testing.T) {
|
||||
assert.Equal(t, len(view.Hint()), 3)
|
||||
assert.Equal(t, len(podView.Hint()), 3)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -19,81 +19,77 @@ package view
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/oam-dev/kubevela/references/cli/top/component"
|
||||
|
||||
"github.com/rivo/tview"
|
||||
|
||||
"github.com/oam-dev/kubevela/references/cli/top/component"
|
||||
|
||||
"github.com/oam-dev/kubevela/references/cli/top/config"
|
||||
"github.com/oam-dev/kubevela/references/cli/top/model"
|
||||
)
|
||||
|
||||
// ResourceView is an abstract of resource view
|
||||
type ResourceView struct {
|
||||
// ResourceView is the interface to abstract resource view
|
||||
type ResourceView interface {
|
||||
model.Component
|
||||
InitView(ctx context.Context, app *App)
|
||||
Update()
|
||||
BuildHeader()
|
||||
BuildBody()
|
||||
}
|
||||
|
||||
// ResourceViewMap is a map from resource name to resource view
|
||||
var ResourceViewMap = map[string]ResourceView{
|
||||
"app": new(ApplicationView),
|
||||
"cluster": new(ClusterView),
|
||||
"resource": new(ManagedResourceView),
|
||||
"ns": new(NamespaceView),
|
||||
"cns": new(ClusterNamespaceView),
|
||||
"pod": new(PodView),
|
||||
}
|
||||
|
||||
// CommonResourceView is an abstract of resource view
|
||||
type CommonResourceView struct {
|
||||
*component.Table
|
||||
app *App
|
||||
}
|
||||
|
||||
// ResourceViewer is resource's renderer
|
||||
type ResourceViewer struct {
|
||||
viewFunc func(context.Context, *App) model.Component
|
||||
}
|
||||
|
||||
// ResourceMap is a map from resource name to resource's renderer
|
||||
var ResourceMap = map[string]ResourceViewer{
|
||||
"app": {
|
||||
viewFunc: NewApplicationView,
|
||||
},
|
||||
"cluster": {
|
||||
viewFunc: NewClusterView,
|
||||
},
|
||||
"resource": {
|
||||
viewFunc: NewManagedResourceView,
|
||||
},
|
||||
"ns": {
|
||||
viewFunc: NewNamespaceView,
|
||||
},
|
||||
"cns": {
|
||||
viewFunc: NewClusterNamespaceView,
|
||||
},
|
||||
"pod": {
|
||||
viewFunc: NewPodView,
|
||||
},
|
||||
}
|
||||
|
||||
// NewResourceView return a new resource view
|
||||
func NewResourceView(app *App) *ResourceView {
|
||||
v := &ResourceView{
|
||||
// NewCommonView return a new common view
|
||||
func NewCommonView(app *App) *CommonResourceView {
|
||||
v := &CommonResourceView{
|
||||
Table: component.NewTable(),
|
||||
app: app,
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Init the resource view
|
||||
func (v *ResourceView) Init(list model.ResourceList) {
|
||||
v.SetSelectable(true, false)
|
||||
v.buildTable(list)
|
||||
}
|
||||
|
||||
func (v *ResourceView) buildTable(list model.ResourceList) {
|
||||
// Init the common resource view
|
||||
func (v *CommonResourceView) Init() {
|
||||
v.Table.Init()
|
||||
v.buildTableHeader(list.Header())
|
||||
v.buildTableBody(list.Body())
|
||||
v.SetBorder(true)
|
||||
v.SetTitleColor(config.ResourceTableTitleColor)
|
||||
v.SetSelectable(true, false)
|
||||
}
|
||||
|
||||
// buildTableHeader render the resource table header
|
||||
func (v *ResourceView) buildTableHeader(header []string) {
|
||||
// Name return the name of common view
|
||||
func (v *CommonResourceView) Name() string {
|
||||
return "Resource"
|
||||
}
|
||||
|
||||
// BuildHeader render the header of table
|
||||
func (v *CommonResourceView) BuildHeader(header []string) {
|
||||
for i := 0; i < len(header); i++ {
|
||||
c := tview.NewTableCell(header[i]).SetTextColor(config.ResourceTableHeaderColor)
|
||||
c := tview.NewTableCell(header[i])
|
||||
c.SetTextColor(config.ResourceTableHeaderColor)
|
||||
c.SetExpansion(3)
|
||||
v.SetCell(0, i, c)
|
||||
}
|
||||
}
|
||||
|
||||
// buildTableBody render the resource table body
|
||||
func (v *ResourceView) buildTableBody(body [][]string) {
|
||||
for i := 0; i < len(body); i++ {
|
||||
for j := 0; j < len(body[i]); j++ {
|
||||
// BuildBody render the body of table
|
||||
func (v *CommonResourceView) BuildBody(body [][]string) {
|
||||
rowNum := len(body)
|
||||
for i := 0; i < rowNum; i++ {
|
||||
columnNum := len(body[i])
|
||||
for j := 0; j < columnNum; j++ {
|
||||
c := tview.NewTableCell(body[i][j])
|
||||
c.SetTextColor(config.ResourceTableBodyColor)
|
||||
c.SetExpansion(3)
|
||||
@@ -101,8 +97,3 @@ func (v *ResourceView) buildTableBody(body [][]string) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Name return the name of view
|
||||
func (v *ResourceView) Name() string {
|
||||
return "Resource"
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestResourceView(t *testing.T) {
|
||||
view := NewResourceView(nil)
|
||||
func TestResourceView_Name(t *testing.T) {
|
||||
view := NewCommonView(nil)
|
||||
assert.Equal(t, view.Name(), "Resource")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user