Skip to content

Commit

Permalink
feat(themes): add themes support
Browse files Browse the repository at this point in the history
  • Loading branch information
AnatolyRugalev committed Sep 13, 2020
1 parent 85c275f commit 9e5918c
Show file tree
Hide file tree
Showing 37 changed files with 1,175 additions and 500 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,9 @@ kubecom --log-pager="jq -c | some_other_command"

### Configuration file

You can edit configuration file at `~/.kubecom.yaml` which currently stores menu configuration. Themes support is
coming soon. Configuration schema defined as protobuf in [pb](./pb) directory.
You can edit configuration file at `~/.kubecom.yaml` to modify resource menu titles and themes. Usually you don't need
to edit config manually: it updates automatically when you change resource menu items or switch theme. You can get
familiar with configuration capabilities inspecting [pb/config.proto](pb/config.proto) protobuf file.

### Hotkeys

Expand Down Expand Up @@ -175,6 +176,7 @@ The most of hotkeys you can find on help dialog. Here they are:
| S | Enter to container `/bin/sh` shell |
| + (plus) | Add resource type to the menu |
| F6, F7 | Move resource type up/down in menu |
| F10, F11 | Cycle through themes |

## Contribution

Expand Down
16 changes: 8 additions & 8 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"github.com/AnatolyRugalev/kube-commander/app/ui"
"github.com/AnatolyRugalev/kube-commander/app/ui/status"
"github.com/AnatolyRugalev/kube-commander/app/ui/theme"
"github.com/AnatolyRugalev/kube-commander/app/ui/workspace"
"github.com/AnatolyRugalev/kube-commander/commander"
"github.com/AnatolyRugalev/kube-commander/config"
Expand Down Expand Up @@ -123,13 +124,17 @@ func (a *app) Run() error {
return fmt.Errorf("could not initialize screen: %w", err)
}
a.workspace = workspace.NewWorkspace(a, a.defaultNamespace)
a.screen.SetWorkspace(a.workspace)

a.status = status.NewStatus(a.screen)
themeManager := theme.NewManager(a.screen, a.status, a)
a.Register(themeManager)

a.screen.Init(a.status, themeManager)
err = a.workspace.Init()
if err != nil {
return err
}
a.status = status.NewStatus(a.screen)
a.screen.SetWorkspace(a.workspace)
a.screen.SetStatus(a.status)
a.tApp.Start()

go a.watchConfig()
Expand All @@ -141,16 +146,11 @@ func (a *app) Run() error {
}

func (a *app) watchConfig() {
firstTime := true
for event := range a.configCh {
if event.Err != nil {
a.status.Error(fmt.Errorf("config: %w", event.Err))
continue
}
if !firstTime {
a.status.Info("Configuration was updated!")
}
firstTime = false
for _, c := range a.configurables {
c.ConfigUpdated(event.Config)
}
Expand Down
36 changes: 3 additions & 33 deletions app/client/default.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,20 @@
package client

import (
"fmt"
"k8s.io/client-go/rest"
cmd "k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
)

type defaultConfig struct {
kubeconfig string
namespace string
context string
}

func (d defaultConfig) Context() string {
func (d *defaultConfig) Context() string {
return d.context
}

func (d defaultConfig) Kubeconfig() string {
func (d *defaultConfig) Kubeconfig() string {
return d.kubeconfig
}

func (d defaultConfig) Namespace() string {
func (d *defaultConfig) Namespace() string {
return d.namespace
}

Expand All @@ -32,26 +25,3 @@ func NewDefaultConfig(kubeconfig string, context string, namespace string) *defa
namespace: namespace,
}
}

func (d *defaultConfig) ClientConfig() (*rest.Config, error) {
rules := cmd.NewDefaultClientConfigLoadingRules()
config, err := rules.Load()
if err != nil {
return nil, fmt.Errorf("error loading config: %w", err)
}
if d.context == "" {
d.context = config.CurrentContext
}
if ctx, ok := config.Contexts[config.CurrentContext]; ok && d.namespace == "" {
d.namespace = ctx.Namespace
}
if d.namespace == "" {
d.namespace = "default"
}
clientConfig := cmd.NewNonInteractiveClientConfig(*config, d.Context(), &cmd.ConfigOverrides{
Context: clientcmdapi.Context{
Namespace: d.namespace,
},
}, rules)
return clientConfig.ClientConfig()
}
39 changes: 21 additions & 18 deletions app/ui/border/border.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package border

import (
"github.com/AnatolyRugalev/kube-commander/commander"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/views"
)

Expand Down Expand Up @@ -31,29 +30,31 @@ type BorderedWidget struct {
commander.MaxSizeWidget
title string
view views.View
style tcell.Style
titleStyle tcell.Style
theme commander.ThemeManager
style string
titleStyle string
borders Borders
}

func (b Borders) Has(flag Borders) bool {
return b&flag == flag
}

func NewBorderedWidget(widget commander.MaxSizeWidget, title string, style tcell.Style, titleStyle tcell.Style, borders Borders) *BorderedWidget {
func NewBorderedWidget(widget commander.MaxSizeWidget, title string, theme commander.ThemeManager, style string, titleStyle string, borders Borders) *BorderedWidget {
if borders == 0 {
borders = All
}
return &BorderedWidget{
MaxSizeWidget: widget,
title: title,
theme: theme,
style: style,
titleStyle: titleStyle,
borders: borders,
}
}

func (b BorderedWidget) Draw() {
func (b *BorderedWidget) Draw() {
w, h := b.view.Size()

x0 := 0
Expand All @@ -65,47 +66,49 @@ func (b BorderedWidget) Draw() {
y0++
}

style := b.theme.GetStyle(b.style)
titleStyle := b.theme.GetStyle(b.titleStyle)
for y := 1; y < h-1; y++ {
if b.borders.Has(Left) {
b.view.SetContent(0, y, vertical, nil, b.style)
b.view.SetContent(0, y, vertical, nil, style)
}
if b.borders.Has(Right) {
b.view.SetContent(w-1, y, vertical, nil, b.style)
b.view.SetContent(w-1, y, vertical, nil, style)
}
}

for x := 1; x < w-1; x++ {
if b.borders.Has(Top) {
b.view.SetContent(x, 0, horizontal, nil, b.style)
b.view.SetContent(x, 0, horizontal, nil, style)
}
if b.borders.Has(Bottom) {
b.view.SetContent(x, h-1, horizontal, nil, b.style)
b.view.SetContent(x, h-1, horizontal, nil, style)
}
}
if b.title != "" && b.borders.Has(Top) {
b.view.SetContent(x0, 0, titleLeft, nil, b.style)
b.view.SetContent(x0, 0, titleLeft, nil, style)
for i, r := range b.title {
b.view.SetContent(i+x0+1, 0, r, nil, b.titleStyle)
b.view.SetContent(i+x0+1, 0, r, nil, titleStyle)
}
b.view.SetContent(x0+len(b.title)+1, 0, titleRight, nil, b.style)
b.view.SetContent(x0+len(b.title)+1, 0, titleRight, nil, style)
}

if b.borders.Has(Top | Left) {
b.view.SetContent(0, 0, cornerTopLeft, nil, b.style)
b.view.SetContent(0, 0, cornerTopLeft, nil, style)
}
if b.borders.Has(Top | Right) {
b.view.SetContent(w-1, 0, cornerTopRight, nil, b.style)
b.view.SetContent(w-1, 0, cornerTopRight, nil, style)
}
if b.borders.Has(Bottom | Left) {
b.view.SetContent(0, h-1, cornerBottomLeft, nil, b.style)
b.view.SetContent(0, h-1, cornerBottomLeft, nil, style)
}
if b.borders.Has(Bottom | Right) {
b.view.SetContent(w-1, h-1, cornerBottomRight, nil, b.style)
b.view.SetContent(w-1, h-1, cornerBottomRight, nil, style)
}
b.MaxSizeWidget.Draw()
}

func (b BorderedWidget) offsets() (int, int) {
func (b *BorderedWidget) offsets() (int, int) {
offsetH := 0
offsetW := 0
if b.borders.Has(Top) {
Expand Down Expand Up @@ -146,7 +149,7 @@ func (b *BorderedWidget) SetView(view views.View) {
b.MaxSizeWidget.SetView(viewport)
}

func (b BorderedWidget) MaxSize() (int, int) {
func (b *BorderedWidget) MaxSize() (int, int) {
w, h := b.MaxSizeWidget.MaxSize()
offsetW, offsetH := b.offsets()
if b.title != "" && len(b.title)+2 > w {
Expand Down
9 changes: 5 additions & 4 deletions app/ui/border/line.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package border

import (
"github.com/AnatolyRugalev/kube-commander/app/focus"
"github.com/AnatolyRugalev/kube-commander/commander"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/views"
)
Expand All @@ -11,18 +12,18 @@ type VerticalLine struct {
views.WidgetWatchers

view views.View
style tcell.Style
theme commander.ThemeManager
}

func NewVerticalLine(style tcell.Style) *VerticalLine {
func NewVerticalLine(theme commander.ThemeManager) *VerticalLine {
return &VerticalLine{
Focusable: focus.NewFocusable(),
style: style,
theme: theme,
}
}

func (l VerticalLine) Draw() {
l.view.Fill(vertical, l.style)
l.view.Fill(vertical, l.theme.GetStyle("screen"))
}

func (l VerticalLine) Resize() {
Expand Down
34 changes: 0 additions & 34 deletions app/ui/err/error.go

This file was deleted.

17 changes: 11 additions & 6 deletions app/ui/help/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ package help

import (
"github.com/AnatolyRugalev/kube-commander/app/focus"
"github.com/AnatolyRugalev/kube-commander/app/ui/theme"
"github.com/AnatolyRugalev/kube-commander/commander"
"github.com/gdamore/tcell/views"
)

type widget struct {
*views.Text
*focus.Focusable
theme commander.ThemeManager
}

func (w widget) MaxSize() (int, int) {
Expand All @@ -21,13 +21,13 @@ func (w widget) Size() (int, int) {
return width, 1
}

var text = `kube-commander - browse your Kubernetes cluster in a casual way!
var text = `kubecom - browse your Kubernetes cluster in a casual way!
Global:
D: Describe selected resource ?: Shows help dialog
E: Edit selected resource Q: Quit
C: Copy resource name to the clipboard Ctrl+N or F2: Switch namespace
Del: Delete resource (with confirmation)
Del: Delete resource (with confirmation) F10, F11: Cycle through themes
Navigation:
↑↓→←: List navigation /: Filter resources
Expand All @@ -43,17 +43,22 @@ Pods:
S: Shell into selected pod
`

func NewHelpWidget() *widget {
func NewHelpWidget(theme commander.ThemeManager) *widget {
widget := widget{
Text: views.NewText(),
Focusable: focus.NewFocusable(),
theme: theme,
}
widget.Text.SetText(text)
widget.Text.SetStyle(theme.Default)
return &widget
}

func (w *widget) Draw() {
w.Text.SetStyle(w.theme.GetStyle("screen"))
w.Text.Draw()
}

func ShowHelpPopup(workspace commander.Workspace) {
help := NewHelpWidget()
help := NewHelpWidget(workspace.Theme())
workspace.ShowPopup("Help", help)
}
6 changes: 4 additions & 2 deletions app/ui/resourceMenu/resource_menu.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ func newItemFromPb(res *pb.Resource) *resourceItem {

func NewResourcesMenu(workspace commander.Workspace, onSelect SelectFunc, selectNamespace func(), resourceProvider commander.ResourceProvider) (*ResourceMenu, error) {
prov := make(commander.RowProvider)
lt := listTable.NewListTable(prov, listTable.NoHorizontalScroll|listTable.WithFilter, workspace.ScreenUpdater())
lt := listTable.NewListTable(prov, listTable.NoHorizontalScroll|listTable.WithFilter, workspace.ScreenHandler())
r := &ResourceMenu{
ListTable: lt,
onSelect: onSelect,
Expand Down Expand Up @@ -237,14 +237,16 @@ func (r *ResourceMenu) OnKeyPress(row commander.Row, event *tcell.EventKey) bool
return true
} else if event.Key() == tcell.KeyDelete {
go func() {
if r.workspace.Status().Confirm("Do you want to hide this resource? (y/n)") {
if r.workspace.Status().Confirm("Do you want to hide this resource? (y/N)") {
for i, item := range r.items {
if item.Id() == row.Id() {
r.items = append(r.items[:i], r.items[i+1:]...)
break
}
}
r.saveItems()
} else {
r.workspace.Status().Info("Cancelled.")
}
}()
return true
Expand Down
2 changes: 1 addition & 1 deletion app/ui/resourceMenu/resource_picker.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func newResourcePicker(container commander.ResourceContainer, f GroupKindFunc) (
}, true))
resMap[res.Gk.String()] = res
}
lt := listTable.NewStaticListTable(columns, rows, listTable.NoHorizontalScroll|listTable.WithFilter|listTable.WithHeaders)
lt := listTable.NewStaticListTable(columns, rows, listTable.NoHorizontalScroll|listTable.WithFilter|listTable.WithHeaders, container.ScreenHandler())
lt.BindOnKeyPress(func(row commander.Row, event *tcell.EventKey) bool {
if row == nil {
return false
Expand Down
Loading

0 comments on commit 9e5918c

Please sign in to comment.