Skip to content
Permalink
Browse files

Make UI activable using --ui or MONDAY_ENABLE_UI env var

  • Loading branch information...
eko committed Aug 29, 2019
1 parent 23fd98b commit 7203c942e5c0997a2615c6809bda5a2b6db457c8
Showing with 108 additions and 26 deletions.
  1. +4 −2 README.md
  2. +26 −11 cmd/main.go
  3. +5 −0 cmd/run.go
  4. +3 −0 pkg/runner/logstreamer.go
  5. +23 −6 pkg/ui/layout.go
  6. +30 −7 pkg/ui/layout_test.go
  7. +17 −0 pkg/ui/view.go
@@ -101,13 +101,15 @@ $ monday init
Once your configuration file is ready, you can simply run Monday:

```bash
$ monday
$ monday [--ui]
```

Note the `--ui` option that will allow you to enable the user interface (you can also define a `MONDAY_ENABLE_UI` environment variable to enable it).

Or, you can run a specific project directly by running:

```bash
$ monday run <project name>
$ monday run [--ui] <project name>
```

When you want to edit your configuration again, simply run this command to open it in your favorite editor:
@@ -5,6 +5,7 @@ import (
"os"
"os/signal"
"runtime"
"strconv"
"syscall"

"github.com/eko/monday/pkg/config"
@@ -33,13 +34,19 @@ var (
watcherComponent *watcher.Watcher

openerCommand string

uiEnabled = len(os.Getenv("MONDAY_ENABLE_UI")) > 0
)

func main() {
initRuntimeEnvironment()

rootCmd := &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
if !uiEnabled {
uiEnabled, _ = strconv.ParseBool(cmd.Flag("ui").Value.String())
}

conf, err := config.Load()
if err != nil {
fmt.Printf("%v", err)
@@ -53,6 +60,10 @@ func main() {
},
}

// UI-enable flag (for both root and run commands)
runCmd.Flags().Bool("ui", false, "Enable the terminal UI")
rootCmd.Flags().Bool("ui", false, "Enable the terminal UI")

rootCmd.AddCommand(completionCmd)
rootCmd.AddCommand(editCmd)
rootCmd.AddCommand(initCmd)
@@ -94,16 +105,10 @@ func selectProject(conf *config.Config) string {
}

func run(conf *config.Config, choice string) {
layout := ui.NewLayout()
layout := ui.NewLayout(uiEnabled)
layout.Init()
defer layout.GetGui().Close()

if err := layout.GetGui().SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
panic(err)
}

layout.GetStatusView().Writef("%s | Commands: ←/→: select view | ↑/↓: scroll up/down | a: toggle autoscroll | f: toggle fullscreen", choice)

// Retrieve selected project configuration by its name
project, err := conf.GetProjectByName(choice)
if err != nil {
panic(err)
@@ -122,9 +127,19 @@ func run(conf *config.Config, choice string) {
watcherComponent = watcher.NewWatcher(runnerComponent, forwarderComponent, conf.Watcher, project)
watcherComponent.Watch()

if err := layout.GetGui().MainLoop(); err != nil && err != gocui.ErrQuit {
fmt.Println(err)
stopAll()
if uiEnabled {
defer layout.GetGui().Close()

if err := layout.GetGui().SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
panic(err)
}

layout.GetStatusView().Writef("%s | Commands: ←/→: select view | ↑/↓: scroll up/down | a: toggle autoscroll | f: toggle fullscreen", choice)

if err := layout.GetGui().MainLoop(); err != nil && err != gocui.ErrQuit {
fmt.Println(err)
stopAll()
}
}
}

@@ -2,6 +2,7 @@ package main

import (
"fmt"
"strconv"

"github.com/eko/monday/pkg/config"
"github.com/spf13/cobra"
@@ -13,6 +14,10 @@ var runCmd = &cobra.Command{
Long: `In case you already have the project name you want to launch, you can launch it directly by using the run command
and passing it as an argument`,
Run: func(cmd *cobra.Command, args []string) {
if !uiEnabled {
uiEnabled, _ = strconv.ParseBool(cmd.Flag("ui").Value.String())
}

conf, err := config.Load()
if err != nil {
fmt.Printf("%v", err)
@@ -53,6 +53,9 @@ func (l *Logstreamer) Write(p []byte) (n int, err error) {
}

err = l.output()
if err != nil {
panic(err)
}
return
}

@@ -9,6 +9,7 @@ import (

// Layout is the structure of the gui layout
type Layout struct {
uiEnabled bool
gui *gocui.Gui
highlighted *View
statusView *View
@@ -20,19 +21,35 @@ type Layout struct {
}

// NewLayout returns a new layout instance
func NewLayout() *Layout {
gui, err := gocui.NewGui(gocui.OutputNormal)
if err != nil {
panic(err)
func NewLayout(uiEnabled bool) *Layout {
layout := &Layout{
uiEnabled: uiEnabled,
}

return &Layout{
gui: gui,
if uiEnabled {
gui, err := gocui.NewGui(gocui.OutputNormal)
if err != nil {
panic(err)
}

layout.gui = gui
}

return layout
}

// Init initializes the gui layout
func (l *Layout) Init() {
if !l.uiEnabled {
l.statusView = NewEmptyView("status")
l.fullscreenView = NewEmptyView("fullscreen")
l.logsView = NewEmptyView("logs")
l.forwardsView = NewEmptyView("forwards")
l.proxyView = NewEmptyView("proxy")

return
}

maxX, maxY := l.gui.Size()

statusView, err := l.setStatusView("status", 0, 0, maxX-1, 2)
@@ -10,7 +10,7 @@ import (

func TestNewLayout(t *testing.T) {
// When
layout := NewLayout()
layout := NewLayout(true)
layout.gui.Close()

// Then
@@ -20,7 +20,7 @@ func TestNewLayout(t *testing.T) {

func TestInit(t *testing.T) {
// Given
layout := NewLayout()
layout := NewLayout(true)
layout.gui.Close()

// When
@@ -34,9 +34,32 @@ func TestInit(t *testing.T) {
assert.IsType(t, new(View), layout.proxyView)
}

func TestTestInitWhenUINotEnabled(t *testing.T) {
// When
layout := NewLayout(false)
layout.Init()

// Then
assert.IsType(t, new(Layout), layout)

assert.Nil(t, layout.gui)

assert.IsType(t, new(View), layout.statusView)
assert.IsType(t, new(View), layout.fullscreenView)
assert.IsType(t, new(View), layout.logsView)
assert.IsType(t, new(View), layout.forwardsView)
assert.IsType(t, new(View), layout.proxyView)

assert.Nil(t, layout.statusView.GetView())
assert.Nil(t, layout.fullscreenView.GetView())
assert.Nil(t, layout.logsView.GetView())
assert.Nil(t, layout.forwardsView.GetView())
assert.Nil(t, layout.proxyView.GetView())
}

func TestGetGui(t *testing.T) {
// Given
layout := NewLayout()
layout := NewLayout(true)
layout.gui.Close()

layout.Init()
@@ -50,7 +73,7 @@ func TestGetGui(t *testing.T) {

func TestGetLogsView(t *testing.T) {
// Given
layout := NewLayout()
layout := NewLayout(true)
layout.gui.Close()

layout.Init()
@@ -67,7 +90,7 @@ func TestGetLogsView(t *testing.T) {

func TestGetForwardsView(t *testing.T) {
// Given
layout := NewLayout()
layout := NewLayout(true)
layout.gui.Close()

layout.Init()
@@ -84,7 +107,7 @@ func TestGetForwardsView(t *testing.T) {

func TestGetProxyView(t *testing.T) {
// Given
layout := NewLayout()
layout := NewLayout(true)
layout.gui.Close()

layout.Init()
@@ -101,7 +124,7 @@ func TestGetProxyView(t *testing.T) {

func TestGetStatusView(t *testing.T) {
// Given
layout := NewLayout()
layout := NewLayout(true)
layout.gui.Close()

layout.Init()
@@ -28,6 +28,13 @@ func NewView(name, title string, view *gocui.View) *View {
}
}

// NewEmptyView returns a new instance of an empty view
func NewEmptyView(name string) *View {
return &View{
name: name,
}
}

// GetName returns the name of the view
func (v *View) GetName() string {
return v.name
@@ -45,10 +52,20 @@ func (v *View) GetView() *gocui.View {

// Write allows to write a string to the view
func (v *View) Write(str string) {
if v.view == nil {
fmt.Print(str)
return
}

v.view.Write([]byte(str))
}

// Writef allows to write a string to the view with some given arguments
func (v *View) Writef(str string, args ...interface{}) {
if v.view == nil {
fmt.Print(fmt.Sprintf(str, args...))
return
}

v.view.Write([]byte(fmt.Sprintf(str, args...)))
}

0 comments on commit 7203c94

Please sign in to comment.
You can’t perform that action at this time.