Skip to content

Commit

Permalink
Merge pull request vmware-archive#176 from bryanl/119-add-loading-ind…
Browse files Browse the repository at this point in the history
…icators

119 add loading indicators
  • Loading branch information
bryanl authored Aug 19, 2019
2 parents 49cf41a + 2f62d85 commit daae17a
Show file tree
Hide file tree
Showing 94 changed files with 573 additions and 482 deletions.
1 change: 1 addition & 0 deletions changelogs/unreleased/176-bryanl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add loading indicators to objects in nav when their informer has not synced
2 changes: 1 addition & 1 deletion internal/api/navigation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func Test_navigation_handler(t *testing.T) {
name: "in general",
nav: newNavigationHandler(validSections, logger),
statusCode: http.StatusOK,
body: []byte("{\"sections\":[{}]}\n"),
body: []byte("{\"sections\":[{\"isLoading\":false}]}\n"),
},
{
name: "no section generator",
Expand Down
21 changes: 9 additions & 12 deletions internal/describer/crd_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ type crdListPrinter func(
crdName string,
crd *apiextv1beta1.CustomResourceDefinition,
objects *unstructured.UnstructuredList,
linkGenerator link.Interface) (component.Component, error)
linkGenerator link.Interface,
isLoading bool) (component.Component, error)

type crdListDescriptionOption func(*crdList)

Expand Down Expand Up @@ -61,12 +62,12 @@ func (cld *crdList) Describe(ctx context.Context, prefix, namespace string, opti
return EmptyContentResponse, err
}

objects, err := ListCustomResources(ctx, crd, namespace, objectStore, options.LabelSet)
objects, isLoading, err := ListCustomResources(ctx, crd, namespace, objectStore, options.LabelSet)
if err != nil {
return EmptyContentResponse, err
}

table, err := cld.printer(cld.name, crd, objects, options.Link)
table, err := cld.printer(cld.name, crd, objects, options.Link, isLoading)
if err != nil {
return EmptyContentResponse, err
}
Expand All @@ -88,9 +89,9 @@ func ListCustomResources(
crd *apiextv1beta1.CustomResourceDefinition,
namespace string,
o store.Store,
selector *labels.Set) (*unstructured.UnstructuredList, error) {
selector *labels.Set) (*unstructured.UnstructuredList, bool, error) {
if crd == nil {
return nil, errors.New("crd is nil")
return nil, false, errors.New("crd is nil")
}
gvk := schema.GroupVersionKind{
Group: crd.Spec.Group,
Expand All @@ -107,16 +108,12 @@ func ListCustomResources(
Selector: selector,
}

if err := o.HasAccess(ctx, key, "list"); err != nil {
return nil, nil
}

objects, err := o.List(ctx, key)
objects, isLoading, err := o.List(ctx, key)
if err != nil {
return nil, errors.Wrapf(err, "listing custom resources for %q", crd.Name)
return nil, false, errors.Wrapf(err, "listing custom resources for %q", crd.Name)
}

return objects, nil
return objects, isLoading, nil
}

func (cld *crdList) PathFilters() []PathFilter {
Expand Down
5 changes: 2 additions & 3 deletions internal/describer/crd_list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ func Test_crdListDescriber(t *testing.T) {
Name: crd.Name,
}

o.EXPECT().HasAccess(gomock.Any(), gomock.Any(), "list").Return(nil)
o.EXPECT().Get(gomock.Any(), gomock.Eq(crdKey)).Return(testutil.ToUnstructured(t, crd), nil)

crKey := store.Key{
Expand All @@ -50,10 +49,10 @@ func Test_crdListDescriber(t *testing.T) {
}

objects := &unstructured.UnstructuredList{}
o.EXPECT().List(gomock.Any(), gomock.Eq(crKey)).Return(objects, nil)
o.EXPECT().List(gomock.Any(), gomock.Eq(crKey)).Return(objects, false, nil)

listPrinter := func(cld *crdList) {
cld.printer = func(name string, crd *apiextv1beta1.CustomResourceDefinition, objects *unstructured.UnstructuredList, linkGenerator link.Interface) (component.Component, error) {
cld.printer = func(name string, crd *apiextv1beta1.CustomResourceDefinition, objects *unstructured.UnstructuredList, linkGenerator link.Interface, loading bool) (component.Component, error) {
return component.NewText("crd list"), nil
}
}
Expand Down
3 changes: 2 additions & 1 deletion internal/describer/customresource.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/vmware/octant/pkg/store"
)

// TODO: delete me
func CustomResourceDefinitionNames(ctx context.Context, o store.Store) ([]string, error) {
key := store.Key{
APIVersion: "apiextensions.k8s.io/v1beta1",
Expand All @@ -28,7 +29,7 @@ func CustomResourceDefinitionNames(ctx context.Context, o store.Store) ([]string
return []string{}, nil
}

rawList, err := o.List(ctx, key)
rawList, _, err := o.List(ctx, key)
if err != nil {
return nil, errors.Wrap(err, "listing CRDs")
}
Expand Down
2 changes: 1 addition & 1 deletion internal/describer/customresource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func Test_customResourceDefinitionNames(t *testing.T) {
Kind: "CustomResourceDefinition",
}
o.EXPECT().HasAccess(gomock.Any(), gomock.Any(), "list").Return(nil)
o.EXPECT().List(gomock.Any(), gomock.Eq(crdKey)).Return(crdList, nil)
o.EXPECT().List(gomock.Any(), gomock.Eq(crdKey)).Return(crdList, false, nil)

ctx := context.Background()
got, err := CustomResourceDefinitionNames(ctx, o)
Expand Down
2 changes: 1 addition & 1 deletion internal/describer/describer.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func LoadObjects(ctx context.Context, objectStore store.Store, namespace string,
objectStoreKey.Name = name
}

storedObjects, err := objectStore.List(ctx, objectStoreKey)
storedObjects, _, err := objectStore.List(ctx, objectStoreKey)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion internal/describer/describer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (c emptyComponent) MarshalJSON() ([]byte, error) {

func createPodTable(pods ...corev1.Pod) *component.Table {
tableCols := component.NewTableCols("Name", "Labels", "Age")
table := component.NewTable("/v1, Kind=PodList", tableCols)
table := component.NewTable("/v1, Kind=PodList", "placeholder", tableCols)
for _, pod := range pods {
table.Add(component.TableRow{
"Age": component.NewTimestamp(pod.CreationTimestamp.Time),
Expand Down
12 changes: 6 additions & 6 deletions internal/describer/section.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,16 @@ func NewSection(p, title string, describers ...Describer) *Section {
func (d *Section) Describe(ctx context.Context, prefix, namespace string, options Options) (component.ContentResponse, error) {
list := component.NewList(d.title, nil)

for _, child := range d.describers {
cResponse, err := child.Describe(ctx, prefix, namespace, options)
for describerIndex := range d.describers {
cResponse, err := d.describers[describerIndex].Describe(ctx, prefix, namespace, options)
if err != nil {
return EmptyContentResponse, err
}

for _, vc := range cResponse.Components {
if nestedList, ok := vc.(*component.List); ok {
for i := range nestedList.Config.Items {
item := nestedList.Config.Items[i]
for componentIndex := range cResponse.Components {
if nestedList, ok := cResponse.Components[componentIndex].(*component.List); ok {
for itemIndex := range nestedList.Config.Items {
item := nestedList.Config.Items[itemIndex]
if !item.IsEmpty() {
list.Add(item)
}
Expand Down
23 changes: 23 additions & 0 deletions internal/loading/loading.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package loading

import (
"context"

"github.com/vmware/octant/internal/describer"
"github.com/vmware/octant/internal/log"
"github.com/vmware/octant/pkg/store"
)

func IsObjectLoading(ctx context.Context, namespace string, resource *describer.Resource, objectStore store.Store) bool {
logger := log.From(ctx)

if resource == nil {
logger.Debugf("can't determine if a nil object is loading")
return false
}

key := resource.ObjectStoreKey
key.Namespace = namespace

return objectStore.IsLoading(ctx, key)
}
16 changes: 12 additions & 4 deletions internal/modules/clusteroverview/clusteroverview.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/vmware/octant/internal/config"
"github.com/vmware/octant/internal/describer"
"github.com/vmware/octant/internal/link"
"github.com/vmware/octant/internal/loading"
"github.com/vmware/octant/internal/log"
"github.com/vmware/octant/internal/module"
"github.com/vmware/octant/internal/modules/overview/printer"
Expand Down Expand Up @@ -227,12 +228,19 @@ func (co *ClusterOverview) Generators() []octant.Generator {
return []octant.Generator{}
}

func rbacEntries(_ context.Context, prefix, _ string, _ store.Store, _ bool) ([]navigation.Navigation, error) {
func rbacEntries(ctx context.Context, prefix, namespace string, objectStore store.Store, _ bool) ([]navigation.Navigation, bool, error) {
neh := navigation.EntriesHelper{}
neh.Add("Cluster Roles", "cluster-roles", icon.ClusterOverviewClusterRole)
neh.Add("Cluster Role Bindings", "cluster-role-bindings", icon.ClusterOverviewClusterRoleBinding)
neh.Add("Cluster Roles", "cluster-roles", icon.ClusterOverviewClusterRole,
loading.IsObjectLoading(ctx, namespace, rbacClusterRoles, objectStore))
neh.Add("Cluster Role Bindings", "cluster-role-bindings", icon.ClusterOverviewClusterRoleBinding,
loading.IsObjectLoading(ctx, namespace, rbacClusterRoleBindings, objectStore))

return neh.Generate(prefix)
children, err := neh.Generate(prefix)
if err != nil {
return nil, false, err
}

return children, false, nil
}

func (co *ClusterOverview) SetContext(ctx context.Context, contextName string) error {
Expand Down
2 changes: 1 addition & 1 deletion internal/modules/clusteroverview/port_forward_describer.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func (d *PortForwardListDescriber) Describe(ctx context.Context, prefix, namespa
list := component.NewList("Port Forwards", nil)

tblCols := component.NewTableCols("Name", "Namespace", "Ports", "Age")
tbl := component.NewTable("Port Forwards", tblCols)
tbl := component.NewTable("Port Forwards", "There are no port forwards!", tblCols)
list.Add(tbl)

for _, pf := range portForwarder.List() {
Expand Down
2 changes: 1 addition & 1 deletion internal/modules/configuration/plugin_describer.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func (d *PluginListDescriber) Describe(ctx context.Context, prefix, namespace st

list := component.NewList("Plugins", nil)
tableCols := component.NewTableCols("Name", "Description", "Capabilities")
tbl := component.NewTable("Plugins", tableCols)
tbl := component.NewTable("Plugins", "There are no plugins!", tableCols)
list.Add(tbl)

for _, n := range pluginStore.ClientNames() {
Expand Down
2 changes: 1 addition & 1 deletion internal/modules/configuration/plugin_describer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func TestPluginDescriber(t *testing.T) {

list := component.NewList("Plugins", nil)
tableCols := component.NewTableCols("Name", "Description", "Capabilities")
table := component.NewTable("Plugins", tableCols)
table := component.NewTable("Plugins", "There are no plugins!", tableCols)
table.Add(component.TableRow{
"Name": component.NewText(name),
"Description": component.NewText("this is a test"),
Expand Down
2 changes: 1 addition & 1 deletion internal/modules/localcontent/localcontent.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func (l *LocalContent) list() (component.ContentResponse, error) {
var out component.ContentResponse

cols := component.NewTableCols("Title", "File")
table := component.NewTable("Local Components", cols)
table := component.NewTable("Local Components", "We couldn't find any local content!", cols)

err := l.walk(func(name, base string, content component.ContentResponse) error {
title, err := l.titleToText(content.Title)
Expand Down
6 changes: 3 additions & 3 deletions internal/modules/overview/content_handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func Test_loadObjects(t *testing.T) {

o.EXPECT().
List(gomock.Any(), gomock.Eq(key)).
Return(sampleObjects, nil)
Return(sampleObjects, false, nil)
},
fields: map[string]string{},
keys: []store.Key{{APIVersion: "v1", Kind: "kind"}},
Expand All @@ -77,7 +77,7 @@ func Test_loadObjects(t *testing.T) {

o.EXPECT().
List(gomock.Any(), gomock.Eq(key)).
Return(&unstructured.UnstructuredList{}, nil)
Return(&unstructured.UnstructuredList{}, false, nil)

},
fields: map[string]string{"name": "name"},
Expand All @@ -94,7 +94,7 @@ func Test_loadObjects(t *testing.T) {

o.EXPECT().
List(gomock.Any(), gomock.Eq(key)).
Return(nil, errors.New("error"))
Return(nil, false, errors.New("error"))
},
fields: map[string]string{},
keys: []store.Key{{APIVersion: "v1", Kind: "kind"}},
Expand Down
88 changes: 63 additions & 25 deletions internal/modules/overview/navigation.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package overview
import (
"context"

"github.com/vmware/octant/internal/loading"
"github.com/vmware/octant/pkg/icon"
"github.com/vmware/octant/pkg/navigation"
"github.com/vmware/octant/pkg/store"
Expand All @@ -24,43 +25,80 @@ var (
}
)

func workloadEntries(_ context.Context, prefix, _ string, _ store.Store, _ bool) ([]navigation.Navigation, error) {
func workloadEntries(ctx context.Context, prefix, namespace string, objectStore store.Store, _ bool) ([]navigation.Navigation, bool, error) {
neh := navigation.EntriesHelper{}
neh.Add("Cron Jobs", "cron-jobs", icon.OverviewCronJob)
neh.Add("Daemon Sets", "daemon-sets", icon.OverviewDaemonSet)
neh.Add("Deployments", "deployments", icon.OverviewDeployment)
neh.Add("Jobs", "jobs", icon.OverviewJob)
neh.Add("Pods", "pods", icon.OverviewPod)
neh.Add("Replica Sets", "replica-sets", icon.OverviewReplicaSet)
neh.Add("Replication Controllers", "replication-controllers", icon.OverviewReplicationController)
neh.Add("Stateful Sets", "stateful-sets", icon.OverviewStatefulSet)

return neh.Generate(prefix)

neh.Add("Cron Jobs", "cron-jobs", icon.OverviewCronJob,
loading.IsObjectLoading(ctx, namespace, workloadsCronJobs, objectStore))
neh.Add("Daemon Sets", "daemon-sets", icon.OverviewDaemonSet,
loading.IsObjectLoading(ctx, namespace, workloadsDaemonSets, objectStore))
neh.Add("Deployments", "deployments", icon.OverviewDeployment,
loading.IsObjectLoading(ctx, namespace, workloadsDeployments, objectStore))
neh.Add("Jobs", "jobs", icon.OverviewJob,
loading.IsObjectLoading(ctx, namespace, workloadsJobs, objectStore))
neh.Add("Pods", "pods", icon.OverviewPod,
loading.IsObjectLoading(ctx, namespace, workloadsPods, objectStore))
neh.Add("Replica Sets", "replica-sets", icon.OverviewReplicaSet,
loading.IsObjectLoading(ctx, namespace, workloadsReplicaSets, objectStore))
neh.Add("Replication Controllers", "replication-controllers", icon.OverviewReplicationController,
loading.IsObjectLoading(ctx, namespace, workloadsReplicationControllers, objectStore))
neh.Add("Stateful Sets", "stateful-sets", icon.OverviewStatefulSet,
loading.IsObjectLoading(ctx, namespace, workloadsStatefulSets, objectStore))

children, err := neh.Generate(prefix)
if err != nil {
return nil, false, err
}

return children, false, nil
}

func discoAndLBEntries(_ context.Context, prefix, _ string, _ store.Store, _ bool) ([]navigation.Navigation, error) {
func discoAndLBEntries(ctx context.Context, prefix, namespace string, objectStore store.Store, _ bool) ([]navigation.Navigation, bool, error) {
neh := navigation.EntriesHelper{}
neh.Add("Ingresses", "ingresses", icon.OverviewIngress)
neh.Add("Services", "services", icon.OverviewService)
neh.Add("Ingresses", "ingresses", icon.OverviewIngress,
loading.IsObjectLoading(ctx, namespace, dlbIngresses, objectStore))
neh.Add("Services", "services", icon.OverviewService,
loading.IsObjectLoading(ctx, namespace, dlbServices, objectStore))

children, err := neh.Generate(prefix)
if err != nil {
return nil, false, err
}

return neh.Generate(prefix)
return children, false, nil
}

func configAndStorageEntries(_ context.Context, prefix, _ string, _ store.Store, _ bool) ([]navigation.Navigation, error) {
func configAndStorageEntries(ctx context.Context, prefix, namespace string, objectStore store.Store, _ bool) ([]navigation.Navigation, bool, error) {
neh := navigation.EntriesHelper{}
neh.Add("Config Maps", "config-maps", icon.OverviewConfigMap)
neh.Add("Persistent Volume Claims", "persistent-volume-claims", icon.OverviewPersistentVolumeClaim)
neh.Add("Secrets", "secrets", icon.OverviewSecret)
neh.Add("Service Accounts", "service-accounts", icon.OverviewServiceAccount)
neh.Add("Config Maps", "config-maps", icon.OverviewConfigMap,
loading.IsObjectLoading(ctx, namespace, csConfigMaps, objectStore))
neh.Add("Persistent Volume Claims", "persistent-volume-claims", icon.OverviewPersistentVolumeClaim,
loading.IsObjectLoading(ctx, namespace, csPVCs, objectStore))
neh.Add("Secrets", "secrets", icon.OverviewSecret,
loading.IsObjectLoading(ctx, namespace, csSecrets, objectStore))
neh.Add("Service Accounts", "service-accounts", icon.OverviewServiceAccount,
loading.IsObjectLoading(ctx, namespace, csServiceAccounts, objectStore))

children, err := neh.Generate(prefix)
if err != nil {
return nil, false, err
}

return neh.Generate(prefix)
return children, false, nil
}

func rbacEntries(_ context.Context, prefix, _ string, _ store.Store, _ bool) ([]navigation.Navigation, error) {
func rbacEntries(ctx context.Context, prefix, namespace string, objectStore store.Store, _ bool) ([]navigation.Navigation, bool, error) {
neh := navigation.EntriesHelper{}

neh.Add("Roles", "roles", icon.OverviewRole)
neh.Add("Role Bindings", "role-bindings", icon.OverviewRoleBinding)
neh.Add("Roles", "roles", icon.OverviewRole,
loading.IsObjectLoading(ctx, namespace, rbacRoles, objectStore))
neh.Add("Role Bindings", "role-bindings", icon.OverviewRoleBinding,
loading.IsObjectLoading(ctx, namespace, rbacRoleBindings, objectStore))

children, err := neh.Generate(prefix)
if err != nil {
return nil, false, err
}

return neh.Generate(prefix)
return children, false, nil
}
3 changes: 2 additions & 1 deletion internal/modules/overview/printer/affinity.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ type affinityDescriber struct {
func (ad *affinityDescriber) Create() (*component.Table, error) {

cols := component.NewTableCols("Type", "Description")
table := component.NewTable("Affinities and Anti-Affinities", cols)
table := component.NewTable("Affinities and Anti-Affinities",
"There are no affinities or anti-affinities!", cols)

if affinity := ad.podSpec.Affinity; affinity != nil {
for _, nodeAffinity := range ad.nodeAffinity(*affinity) {
Expand Down
Loading

0 comments on commit daae17a

Please sign in to comment.