mirror of
https://github.com/kubevela/kubevela.git
synced 2026-02-14 18:10:21 +00:00
Feat: Add more data field to application view and managed resource view in vela top (#4781)
* Fix: fix the bug of cluster list Signed-off-by: HanMengnan <1448189829@qq.com> * Feat: add some feature 1. add more column of application and managed resource 2. alter <ESC> to exist key and add <Q> as the back key Signed-off-by: HanMengnan <1448189829@qq.com> Signed-off-by: HanMengnan <1448189829@qq.com>
This commit is contained in:
@@ -18,7 +18,9 @@ package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
@@ -27,10 +29,13 @@ import (
|
||||
|
||||
// Application is the application resource object
|
||||
type Application struct {
|
||||
name string
|
||||
namespace string
|
||||
phase string
|
||||
createTime string
|
||||
name string
|
||||
namespace string
|
||||
phase string
|
||||
service string
|
||||
workflow string
|
||||
workflowMode string
|
||||
createTime string
|
||||
}
|
||||
|
||||
// ApplicationList is application resource list
|
||||
@@ -40,13 +45,13 @@ type ApplicationList []Application
|
||||
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}
|
||||
data[index] = []string{app.name, app.namespace, app.phase, app.workflowMode, app.workflow, app.service, app.createTime}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// ListApplications list all apps in all namespaces
|
||||
func ListApplications(ctx context.Context, c client.Reader) (ApplicationList, error) {
|
||||
func ListApplications(ctx context.Context, c client.Client) (ApplicationList, error) {
|
||||
apps := v1beta1.ApplicationList{}
|
||||
namespace := ctx.Value(&CtxKeyNamespace).(string)
|
||||
|
||||
@@ -55,7 +60,10 @@ func ListApplications(ctx context.Context, c client.Reader) (ApplicationList, er
|
||||
}
|
||||
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()}
|
||||
appList[index] = Application{name: app.Name, namespace: app.Namespace, phase: string(app.Status.Phase), createTime: app.CreationTimestamp.String()}
|
||||
appList[index].service = serviceNum(app)
|
||||
appList[index].workflow = workflowStepNum(app)
|
||||
appList[index].workflowMode = workflowMode(app)
|
||||
}
|
||||
return appList, nil
|
||||
}
|
||||
@@ -96,3 +104,27 @@ func runningApplicationNum(ctx context.Context, c client.Client) (int, error) {
|
||||
}
|
||||
return num, nil
|
||||
}
|
||||
|
||||
func serviceNum(app v1beta1.Application) string {
|
||||
total, healthy := len(app.Status.Services), 0
|
||||
for _, service := range app.Status.Services {
|
||||
if service.Healthy {
|
||||
healthy++
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("%d/%d", healthy, total)
|
||||
}
|
||||
|
||||
func workflowMode(app v1beta1.Application) string {
|
||||
return app.Status.Workflow.Mode
|
||||
}
|
||||
|
||||
func workflowStepNum(app v1beta1.Application) string {
|
||||
total, succeed := len(app.Status.Workflow.Steps), 0
|
||||
for _, step := range app.Status.Workflow.Steps {
|
||||
if step.Phase == workflowv1alpha1.WorkflowStepPhaseSucceeded {
|
||||
succeed++
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("%d/%d", succeed, total)
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ import (
|
||||
)
|
||||
|
||||
func TestApplicationList_ToTableBody(t *testing.T) {
|
||||
appList := &ApplicationList{{"Name", "Namespace", "Phase", "CreateTime"}}
|
||||
assert.Equal(t, appList.ToTableBody(), [][]string{{"Name", "Namespace", "Phase", "CreateTime"}})
|
||||
appList := &ApplicationList{{"Name", "Namespace", "Phase", "", "", "", "CreateTime"}}
|
||||
assert.Equal(t, appList.ToTableBody(), [][]string{{"Name", "Namespace", "Phase", "", "", "", "CreateTime"}})
|
||||
}
|
||||
|
||||
var _ = Describe("test Application", func() {
|
||||
|
||||
@@ -31,6 +31,7 @@ type ManagedResource struct {
|
||||
kind string
|
||||
apiVersion string
|
||||
cluster string
|
||||
component string
|
||||
status string
|
||||
}
|
||||
|
||||
@@ -48,7 +49,7 @@ func ListManagedResource(ctx context.Context, c client.Client) (ManagedResourceL
|
||||
}
|
||||
|
||||
collector := query.NewAppCollector(c, opt)
|
||||
appResList, err := collector.CollectResourceFromApp(ctx)
|
||||
appResList, err := collector.CollectResourceFromApp(context.Background())
|
||||
if err != nil {
|
||||
return ManagedResourceList{}, err
|
||||
}
|
||||
@@ -57,6 +58,7 @@ func ListManagedResource(ctx context.Context, c client.Client) (ManagedResourceL
|
||||
|
||||
for index, resource := range appResList {
|
||||
list[index] = LoadResourceDetail(resource)
|
||||
list[index].component = resource.Component
|
||||
}
|
||||
|
||||
cluster, ok := ctx.Value(&CtxKeyCluster).(string)
|
||||
@@ -73,10 +75,10 @@ func ListManagedResource(ctx context.Context, c client.Client) (ManagedResourceL
|
||||
}
|
||||
|
||||
// ToTableBody generate header of table in managed resource view
|
||||
func (l ManagedResourceList) ToTableBody() [][]string {
|
||||
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})
|
||||
for _, resource := range *l {
|
||||
data = append(data, []string{resource.name, resource.namespace, resource.kind, resource.apiVersion, resource.cluster, resource.component, resource.status})
|
||||
}
|
||||
return data
|
||||
}
|
||||
@@ -102,7 +104,7 @@ 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})
|
||||
data = append(data, ManagedResource{resource.name, resource.namespace, resource.kind, resource.apiVersion, resource.cluster, resource.component, resource.status})
|
||||
}
|
||||
}
|
||||
*l = data
|
||||
@@ -111,9 +113,9 @@ func (l *ManagedResourceList) FilterCluster(clusterName string) {
|
||||
// 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})
|
||||
for _, resource := range *l {
|
||||
if resource.namespace == clusterNS {
|
||||
data = append(data, ManagedResource{resource.name, resource.namespace, resource.kind, resource.apiVersion, resource.cluster, resource.component, resource.status})
|
||||
}
|
||||
}
|
||||
*l = data
|
||||
|
||||
@@ -26,14 +26,14 @@ import (
|
||||
)
|
||||
|
||||
func TestListManagedResource(t *testing.T) {
|
||||
list := ManagedResourceList{{"", "", "", "", "", ""}}
|
||||
assert.Equal(t, list.ToTableBody(), [][]string{{"", "", "", "", "", ""}})
|
||||
list := ManagedResourceList{{"", "", "", "", "", "", ""}}
|
||||
assert.Equal(t, list.ToTableBody(), [][]string{{"", "", "", "", "", "", ""}})
|
||||
}
|
||||
|
||||
func TestManagedResourceList_FilterCluster(t *testing.T) {
|
||||
list := ManagedResourceList{
|
||||
{"", "", "", "", "1", ""},
|
||||
{"", "", "", "", "2", ""},
|
||||
{"", "", "", "", "1", "", ""},
|
||||
{"", "", "", "", "2", "", ""},
|
||||
}
|
||||
list.FilterCluster("1")
|
||||
assert.Equal(t, len(list), 1)
|
||||
@@ -41,8 +41,8 @@ func TestManagedResourceList_FilterCluster(t *testing.T) {
|
||||
|
||||
func TestManagedResourceList_FilterClusterNamespace(t *testing.T) {
|
||||
list := ManagedResourceList{
|
||||
{"", "1", "", "", "1", ""},
|
||||
{"", "2", "", "", "2", ""},
|
||||
{"", "1", "", "", "1", "", ""},
|
||||
{"", "2", "", "", "2", "", ""},
|
||||
}
|
||||
list.FilterClusterNamespace("2")
|
||||
assert.Equal(t, len(list), 1)
|
||||
|
||||
@@ -23,12 +23,12 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
|
||||
"github.com/kubevela/workflow/api/v1alpha1"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/rest"
|
||||
@@ -91,6 +91,20 @@ var _ = BeforeSuite(func(done Done) {
|
||||
Expect(err).Should(BeNil())
|
||||
testApp.Status = common2.AppStatus{
|
||||
Phase: common2.ApplicationRunning,
|
||||
Workflow: &common2.WorkflowStatus{
|
||||
AppRevision: "",
|
||||
Mode: "DAG",
|
||||
Phase: "",
|
||||
Message: "",
|
||||
Suspend: false,
|
||||
SuspendState: "",
|
||||
Terminated: false,
|
||||
Finished: false,
|
||||
ContextBackend: nil,
|
||||
Steps: []v1alpha1.WorkflowStepStatus{},
|
||||
StartTime: metav1.Time{},
|
||||
EndTime: metav1.Time{},
|
||||
},
|
||||
AppliedResources: []common2.ClusterObjectReference{
|
||||
{
|
||||
Cluster: "",
|
||||
|
||||
@@ -146,7 +146,7 @@ func (a *App) inject(v model.View) {
|
||||
|
||||
func (a *App) bindKeys() {
|
||||
a.AddAction(model.KeyActions{
|
||||
tcell.KeyESC: model.KeyAction{Description: "Back", Action: a.Back, Visible: true, Shared: true},
|
||||
component.KeyQ: model.KeyAction{Description: "Back", Action: a.Back, Visible: true, Shared: true},
|
||||
component.KeyHelp: model.KeyAction{Description: "Help", Action: a.helpView, Visible: true, Shared: true},
|
||||
})
|
||||
}
|
||||
@@ -183,3 +183,9 @@ func (a *App) Back(_ *tcell.EventKey) *tcell.EventKey {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Exist the app
|
||||
func (a *App) Exist(_ *tcell.EventKey) *tcell.EventKey {
|
||||
a.Stop()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/references/cli/top/component"
|
||||
)
|
||||
|
||||
func TestApp(t *testing.T) {
|
||||
@@ -45,7 +46,7 @@ func TestApp(t *testing.T) {
|
||||
t.Run("init", func(t *testing.T) {
|
||||
app.Init()
|
||||
assert.Equal(t, app.Main.HasPage("main"), true)
|
||||
_, ok := app.HasAction(tcell.KeyESC)
|
||||
_, ok := app.HasAction(component.KeyQ)
|
||||
assert.Equal(t, ok, true)
|
||||
app.content.Stack.RemoveListener(app.Crumbs())
|
||||
assert.NotEmpty(t, app.content.Stack.TopView())
|
||||
@@ -53,7 +54,7 @@ func TestApp(t *testing.T) {
|
||||
assert.Equal(t, app.content.Stack.IsLastView(), true)
|
||||
})
|
||||
t.Run("keyboard", func(t *testing.T) {
|
||||
evt1 := tcell.NewEventKey(tcell.KeyEsc, '/', 0)
|
||||
evt1 := tcell.NewEventKey(component.KeyQ, '/', 0)
|
||||
assert.Empty(t, app.keyboard(evt1))
|
||||
evt2 := tcell.NewEventKey(tcell.KeyTAB, '/', 0)
|
||||
assert.NotEmpty(t, app.keyboard(evt2))
|
||||
|
||||
@@ -87,7 +87,7 @@ func (v *ApplicationView) Update() {
|
||||
|
||||
// BuildHeader render the header of table
|
||||
func (v *ApplicationView) BuildHeader() {
|
||||
header := []string{"Name", "Namespace", "Phase", "CreateTime"}
|
||||
header := []string{"Name", "Namespace", "Phase", "WorkflowMode", "Workflow", "Service", "CreateTime"}
|
||||
v.CommonResourceView.BuildHeader(header)
|
||||
}
|
||||
|
||||
@@ -134,6 +134,7 @@ func (v *ApplicationView) Title() string {
|
||||
func (v *ApplicationView) bindKeys() {
|
||||
v.Actions().Delete([]tcell.Key{tcell.KeyEnter})
|
||||
v.Actions().Add(model.KeyActions{
|
||||
tcell.KeyESC: model.KeyAction{Description: "Exist", Action: v.app.Exist, Visible: true, Shared: true},
|
||||
tcell.KeyEnter: model.KeyAction{Description: "Enter", Action: v.managedResourceView, Visible: true, Shared: true},
|
||||
component.KeyN: model.KeyAction{Description: "Select Namespace", Action: v.namespaceView, Visible: true, Shared: true},
|
||||
component.KeyY: model.KeyAction{Description: "Yaml", Action: v.yamlView, Visible: true, Shared: true},
|
||||
|
||||
@@ -88,7 +88,7 @@ func TestApplicationView(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("hint", func(t *testing.T) {
|
||||
assert.Equal(t, len(appView.Hint()), 6)
|
||||
assert.Equal(t, len(appView.Hint()), 7)
|
||||
})
|
||||
|
||||
t.Run("managed resource view", func(t *testing.T) {
|
||||
|
||||
@@ -19,8 +19,6 @@ package view
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
|
||||
"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"
|
||||
@@ -56,7 +54,7 @@ func (v *HelpView) Name() string {
|
||||
|
||||
func (v *HelpView) bindKeys() {
|
||||
v.Actions().Add(model.KeyActions{
|
||||
tcell.KeyESC: model.KeyAction{Description: "Back", Action: v.app.Back, Visible: true, Shared: true},
|
||||
component.KeyQ: model.KeyAction{Description: "Back", Action: v.app.Back, Visible: true, Shared: true},
|
||||
component.KeyHelp: model.KeyAction{Description: "Back", Action: v.app.Back, Visible: true, Shared: true},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ func (v *ManagedResourceView) Update() {
|
||||
|
||||
// BuildHeader render the header of table
|
||||
func (v *ManagedResourceView) BuildHeader() {
|
||||
header := []string{"Name", "Namespace", "Kind", "APIVersion", "Cluster", "Status"}
|
||||
header := []string{"Name", "Namespace", "Kind", "APIVersion", "Cluster", "Component", "Status"}
|
||||
v.CommonResourceView.BuildHeader(header)
|
||||
}
|
||||
|
||||
|
||||
@@ -139,8 +139,9 @@ func (v *CommonResourceView) AutoRefresh(update func()) {
|
||||
}
|
||||
|
||||
func (v *CommonResourceView) bindKeys() {
|
||||
v.Actions().Delete([]tcell.Key{tcell.KeyESC})
|
||||
v.Actions().Add(model.KeyActions{
|
||||
tcell.KeyESC: model.KeyAction{Description: "Back", Action: v.app.Back, Visible: true, Shared: true},
|
||||
component.KeyQ: model.KeyAction{Description: "Back", Action: v.app.Back, Visible: true, Shared: true},
|
||||
component.KeyHelp: model.KeyAction{Description: "Help", Action: v.app.helpView, Visible: true, Shared: true},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ func (v *YamlView) keyboard(event *tcell.EventKey) *tcell.EventKey {
|
||||
func (v *YamlView) bindKeys() {
|
||||
v.actions.Delete([]tcell.Key{tcell.KeyEnter})
|
||||
v.actions.Add(model.KeyActions{
|
||||
tcell.KeyESC: model.KeyAction{Description: "Back", Action: v.app.Back, Visible: true, Shared: true},
|
||||
component.KeyQ: model.KeyAction{Description: "Back", Action: v.app.Back, Visible: true, Shared: true},
|
||||
component.KeyHelp: model.KeyAction{Description: "Help", Action: v.app.helpView, Visible: true, Shared: true},
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user