convert project panel to use new struct

pull/392/head
Jesse Duffield 2 years ago
parent 5aea90c08b
commit 158ef68372

@ -0,0 +1,9 @@
package commands
type Project struct {
Name string
}
func (self *Project) GetDisplayStrings(isFocused bool) []string {
return []string{self.Name}
}

@ -42,32 +42,34 @@ func (gui *Gui) getContainersPanel() *SideListPanel[*commands.Container] {
contextIdx: 0,
noItemsMessge: gui.Tr.NoContainers,
gui: gui.intoInterface(),
contexts: []ContextConfig[*commands.Container]{
{
key: "logs",
title: gui.Tr.LogsTitle,
render: gui.renderContainerLogsToMain,
},
{
key: "stats",
title: gui.Tr.StatsTitle,
render: gui.renderContainerStats,
},
{
key: "env",
title: gui.Tr.EnvTitle,
render: gui.renderContainerEnv,
},
{
key: "config",
title: gui.Tr.ConfigTitle,
render: gui.renderContainerConfig,
},
{
key: "top",
title: gui.Tr.TopTitle,
render: gui.renderContainerTop,
},
getContexts: func() []ContextConfig[*commands.Container] {
return []ContextConfig[*commands.Container]{
{
key: "logs",
title: gui.Tr.LogsTitle,
render: gui.renderContainerLogsToMain,
},
{
key: "stats",
title: gui.Tr.StatsTitle,
render: gui.renderContainerStats,
},
{
key: "env",
title: gui.Tr.EnvTitle,
render: gui.renderContainerEnv,
},
{
key: "config",
title: gui.Tr.ConfigTitle,
render: gui.renderContainerConfig,
},
{
key: "top",
title: gui.Tr.TopTitle,
render: gui.renderContainerTop,
},
}
},
getSearchStrings: func(container *commands.Container) []string {
// TODO: think about more things to search on

@ -48,6 +48,7 @@ type Gui struct {
}
type Panels struct {
Projects *SideListPanel[*commands.Project]
Services *SideListPanel[*commands.Service]
Containers *SideListPanel[*commands.Container]
Images *SideListPanel[*commands.Image]
@ -239,6 +240,7 @@ func (gui *Gui) Run() error {
// TODO: see if we can avoid the circular dependency
gui.Panels = Panels{
Projects: gui.getProjectPanel(),
Services: gui.getServicesPanel(),
Containers: gui.getContainersPanel(),
Images: gui.getImagesPanel(),
@ -294,7 +296,11 @@ func (gui *Gui) rerenderContainersAndServices() error {
}
func (gui *Gui) refresh() {
go gui.refreshProject()
go func() {
if err := gui.refreshProject(); err != nil {
gui.Log.Error(err)
}
}()
go func() {
if err := gui.refreshContainersAndServices(); err != nil {
gui.Log.Error(err)

@ -25,14 +25,16 @@ func (gui *Gui) getImagesPanel() *SideListPanel[*commands.Image] {
contextIdx: 0,
noItemsMessge: gui.Tr.NoImages,
gui: gui.intoInterface(),
contexts: []ContextConfig[*commands.Image]{
{
key: "config",
title: gui.Tr.ConfigTitle,
render: func(image *commands.Image) error {
return gui.renderImageConfig(image)
getContexts: func() []ContextConfig[*commands.Image] {
return []ContextConfig[*commands.Image]{
{
key: "config",
title: gui.Tr.ConfigTitle,
render: func(image *commands.Image) error {
return gui.renderImageConfig(image)
},
},
},
}
},
getSearchStrings: func(image *commands.Image) []string {
return []string{image.Name, image.Tag}

@ -151,22 +151,16 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
ViewName: "project",
Key: '[',
Modifier: gocui.ModNone,
Handler: gui.handleProjectPrevContext,
Handler: wrappedHandler(gui.Panels.Projects.OnPrevContext),
Description: gui.Tr.PreviousContext,
},
{
ViewName: "project",
Key: ']',
Modifier: gocui.ModNone,
Handler: gui.handleProjectNextContext,
Handler: wrappedHandler(gui.Panels.Projects.OnNextContext),
Description: gui.Tr.NextContext,
},
{
ViewName: "project",
Key: gocui.MouseLeft,
Modifier: gocui.ModNone,
Handler: gui.handleProjectClick,
},
{
ViewName: "project",
Key: 'm',
@ -178,7 +172,7 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
ViewName: "project",
Key: gocui.MouseLeft,
Modifier: gocui.ModNone,
Handler: gui.handleProjectSelect,
Handler: wrappedHandler(gui.Panels.Projects.OnClick),
},
{
ViewName: "menu",
@ -603,9 +597,9 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
}...)
}
for _, viewName := range []string{"project", "services", "containers", "images", "volumes"} {
for _, sidePanel := range gui.allSidepanels() {
bindings = append(bindings, &Binding{
ViewName: viewName,
ViewName: sidePanel.View().Name(),
Key: gocui.KeyEnter,
Modifier: gocui.ModNone,
Handler: gui.handleEnterMain,

@ -49,28 +49,34 @@ func (self *ListPanel[T]) SelectPrevLine() {
// list panel at the side of the screen that renders content to the main panel
type SideListPanel[T comparable] struct {
contextKeyPrefix string
contextIdx int
// contexts []ContextConfig[T]
getContexts func() []ContextConfig[T]
// this tells us whether we need to re-render to the main panel
getContextCacheKey func(item T) string
ListPanel[T]
contextIdx int
noItemsMessge string
gui IGui
contexts []ContextConfig[T]
// returns strings that can be filtered on
getSearchStrings func(item T) []string
// this tells us whether we need to re-render to the main panel
getContextCacheKey func(item T) string
sort func(a, b T) bool
// this filter is applied on top of additional default filters
filter func(T) bool
sort func(a, b T) bool
}
type ISideListPanel interface {
SetContextIndex(int)
HandleSelect() error
View() *gocui.View
}
var _ ISideListPanel = &SideListPanel[int]{}
type ContextConfig[T any] struct {
key string
title string
@ -103,6 +109,10 @@ func (self *SideListPanel[T]) OnClick() error {
return self.gui.HandleClick(self.view, itemCount, selectedLine, handleSelect)
}
func (self *SideListPanel[T]) View() *gocui.View {
return self.view
}
func (self *SideListPanel[T]) HandleSelect() error {
item, err := self.GetSelectedItem()
if err != nil {
@ -115,7 +125,9 @@ func (self *SideListPanel[T]) HandleSelect() error {
self.Refocus()
key := self.contextKeyPrefix + "-" + self.getContextCacheKey(item) + "-" + self.contexts[self.contextIdx].key
contexts := self.getContexts()
key := self.contextKeyPrefix + "-" + self.getContextCacheKey(item) + "-" + contexts[self.contextIdx].key
if !self.gui.ShouldRefresh(key) {
return nil
}
@ -125,11 +137,11 @@ func (self *SideListPanel[T]) HandleSelect() error {
mainView.TabIndex = self.contextIdx
// now I have an item. What do I do with it?
return self.contexts[self.contextIdx].render(item)
return contexts[self.contextIdx].render(item)
}
func (self *SideListPanel[T]) GetContextTitles() []string {
return lo.Map(self.contexts, func(context ContextConfig[T], _ int) string {
return lo.Map(self.getContexts(), func(context ContextConfig[T], _ int) string {
return context.title
})
}
@ -171,13 +183,25 @@ func (self *SideListPanel[T]) ignoreKeypress() bool {
}
func (self *SideListPanel[T]) OnNextContext() error {
self.contextIdx = (self.contextIdx + 1) % len(self.contexts)
contexts := self.getContexts()
if len(contexts) == 0 {
return nil
}
self.contextIdx = (self.contextIdx + 1) % len(contexts)
return self.HandleSelect()
}
func (self *SideListPanel[T]) OnPrevContext() error {
self.contextIdx = (self.contextIdx - 1 + len(self.contexts)) % len(self.contexts)
contexts := self.getContexts()
if len(contexts) == 0 {
return nil
}
self.contextIdx = (self.contextIdx - 1 + len(contexts)) % len(contexts)
return self.HandleSelect()
}

@ -83,25 +83,14 @@ func (gui *Gui) onMainTabClick(tabIndex int) error {
viewName = mainView.ParentView.Name()
}
switch viewName {
case "project":
gui.State.Panels.Project.ContextIndex = tabIndex
return gui.handleProjectSelect(gui.g, gui.getProjectView())
case "services":
gui.Panels.Services.SetContextIndex(tabIndex)
return gui.Panels.Services.HandleSelect()
case "containers":
gui.Panels.Containers.SetContextIndex(tabIndex)
return gui.Panels.Containers.HandleSelect()
case "images":
gui.Panels.Images.SetContextIndex(tabIndex)
return gui.Panels.Images.HandleSelect()
case "volumes":
gui.Panels.Volumes.SetContextIndex(tabIndex)
return gui.Panels.Volumes.HandleSelect()
currentSidePanel, ok := gui.currentSidePanel()
if !ok {
return nil
}
return nil
currentSidePanel.SetContextIndex(tabIndex)
return currentSidePanel.HandleSelect()
}
func (gui *Gui) handleEnterMain(g *gocui.Gui, v *gocui.View) error {

@ -2,42 +2,73 @@ package gui
import (
"bytes"
"fmt"
"path"
"strings"
"github.com/fatih/color"
"github.com/go-errors/errors"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazydocker/pkg/commands"
"github.com/jesseduffield/lazydocker/pkg/utils"
"github.com/jesseduffield/yaml"
)
func (gui *Gui) getProjectContexts() []string {
if gui.DockerCommand.InDockerComposeProject {
return []string{"logs", "config", "credits"}
}
return []string{"credits"}
}
// Although at the moment we'll only have one project, in future we could have
// a list of projects in the project panel.
func (gui *Gui) getProjectPanel() *SideListPanel[*commands.Project] {
return &SideListPanel[*commands.Project]{
contextKeyPrefix: "project",
ListPanel: ListPanel[*commands.Project]{
list: NewFilteredList[*commands.Project](),
view: gui.Views.Project,
},
contextIdx: 0,
noItemsMessge: "no projects", // we don't expect to ever actually see this
gui: gui.intoInterface(),
getContexts: func() []ContextConfig[*commands.Project] {
if gui.DockerCommand.InDockerComposeProject {
return []ContextConfig[*commands.Project]{
{
key: "logs",
title: gui.Tr.LogsTitle,
render: gui.renderAllLogs,
},
{
key: "config",
title: gui.Tr.DockerComposeConfigTitle,
render: gui.renderDockerComposeConfig,
},
{
key: "credits",
title: gui.Tr.CreditsTitle,
render: gui.renderCredits,
},
}
}
func (gui *Gui) getProjectContextTitles() []string {
if gui.DockerCommand.InDockerComposeProject {
return []string{gui.Tr.LogsTitle, gui.Tr.DockerComposeConfigTitle, gui.Tr.CreditsTitle}
return []ContextConfig[*commands.Project]{
{
key: "credits",
title: gui.Tr.CreditsTitle,
render: gui.renderCredits,
},
}
},
getSearchStrings: func(project *commands.Project) []string {
return []string{project.Name}
},
getContextCacheKey: func(project *commands.Project) string {
return project.Name
},
sort: func(a *commands.Project, b *commands.Project) bool {
return false
},
}
return []string{gui.Tr.CreditsTitle}
}
func (gui *Gui) refreshProject() {
v := gui.getProjectView()
projectName := gui.getProjectName()
gui.g.Update(func(*gocui.Gui) error {
v.Clear()
fmt.Fprint(v, projectName)
return nil
})
func (gui *Gui) refreshProject() error {
gui.Panels.Projects.SetItems([]*commands.Project{{Name: gui.getProjectName()}})
return gui.Panels.Projects.RerenderList()
}
func (gui *Gui) getProjectName() string {
@ -54,55 +85,7 @@ func (gui *Gui) getProjectName() string {
return projectName
}
func (gui *Gui) handleProjectClick(g *gocui.Gui, v *gocui.View) error {
if gui.popupPanelFocused() {
return nil
}
if _, err := gui.g.SetCurrentView(v.Name()); err != nil {
return err
}
return gui.handleProjectSelect(g, v)
}
func (gui *Gui) handleProjectSelect(g *gocui.Gui, v *gocui.View) error {
if gui.popupPanelFocused() {
return nil
}
key := gui.getProjectContexts()[gui.State.Panels.Project.ContextIndex]
if !gui.shouldRefresh(key) {
return nil
}
gui.clearMainView()
mainView := gui.getMainView()
mainView.Tabs = gui.getProjectContextTitles()
mainView.TabIndex = gui.State.Panels.Project.ContextIndex
switch gui.getProjectContexts()[gui.State.Panels.Project.ContextIndex] {
case "credits":
if err := gui.renderCredits(); err != nil {
return err
}
case "logs":
if err := gui.renderAllLogs(); err != nil {
return err
}
case "config":
if err := gui.renderDockerComposeConfig(); err != nil {
return err
}
default:
return errors.New("Unknown context for status panel")
}
return nil
}
func (gui *Gui) renderCredits() error {
func (gui *Gui) renderCredits(_project *commands.Project) error {
return gui.T.NewTask(func(stop chan struct{}) {
mainView := gui.getMainView()
mainView.Autoscroll = false
@ -127,7 +110,7 @@ func (gui *Gui) renderCredits() error {
})
}
func (gui *Gui) renderAllLogs() error {
func (gui *Gui) renderAllLogs(_project *commands.Project) error {
return gui.T.NewTask(func(stop chan struct{}) {
mainView := gui.getMainView()
mainView.Autoscroll = true
@ -159,7 +142,7 @@ func (gui *Gui) renderAllLogs() error {
})
}
func (gui *Gui) renderDockerComposeConfig() error {
func (gui *Gui) renderDockerComposeConfig(_project *commands.Project) error {
return gui.T.NewTask(func(stop chan struct{}) {
mainView := gui.getMainView()
mainView.Autoscroll = false
@ -191,32 +174,6 @@ func lazydockerTitle() string {
`
}
func (gui *Gui) handleProjectNextContext(g *gocui.Gui, v *gocui.View) error {
contexts := gui.getProjectContexts()
if gui.State.Panels.Project.ContextIndex >= len(contexts)-1 {
gui.State.Panels.Project.ContextIndex = 0
} else {
gui.State.Panels.Project.ContextIndex++
}
_ = gui.handleProjectSelect(gui.g, v)
return nil
}
func (gui *Gui) handleProjectPrevContext(g *gocui.Gui, v *gocui.View) error {
contexts := gui.getProjectContexts()
if gui.State.Panels.Project.ContextIndex <= 0 {
gui.State.Panels.Project.ContextIndex = len(contexts) - 1
} else {
gui.State.Panels.Project.ContextIndex--
}
_ = gui.handleProjectSelect(gui.g, v)
return nil
}
// handleViewAllLogs switches to a subprocess viewing all the logs from docker-compose
func (gui *Gui) handleViewAllLogs(g *gocui.Gui, v *gocui.View) error {
c, err := gui.DockerCommand.ViewAllLogs()

@ -22,32 +22,34 @@ func (gui *Gui) getServicesPanel() *SideListPanel[*commands.Service] {
// TODO: i18n
noItemsMessge: "no service selected",
gui: gui.intoInterface(),
contexts: []ContextConfig[*commands.Service]{
{
key: "logs",
title: gui.Tr.LogsTitle,
render: gui.renderServiceLogs,
},
{
key: "stats",
title: gui.Tr.StatsTitle,
render: gui.renderServiceStats,
},
{
key: "container-env",
title: gui.Tr.ContainerEnvTitle,
render: gui.renderServiceContainerEnv,
},
{
key: "container-config",
title: gui.Tr.ContainerConfigTitle,
render: gui.renderServiceContainerConfig,
},
{
key: "top",
title: gui.Tr.TopTitle,
render: gui.renderServiceTop,
},
getContexts: func() []ContextConfig[*commands.Service] {
return []ContextConfig[*commands.Service]{
{
key: "logs",
title: gui.Tr.LogsTitle,
render: gui.renderServiceLogs,
},
{
key: "stats",
title: gui.Tr.StatsTitle,
render: gui.renderServiceStats,
},
{
key: "container-env",
title: gui.Tr.ContainerEnvTitle,
render: gui.renderServiceContainerEnv,
},
{
key: "container-config",
title: gui.Tr.ContainerConfigTitle,
render: gui.renderServiceContainerConfig,
},
{
key: "top",
title: gui.Tr.TopTitle,
render: gui.renderServiceTop,
},
}
},
getSearchStrings: func(service *commands.Service) []string {
// TODO: think about more things to search on

@ -71,19 +71,14 @@ func (gui *Gui) newLineFocused(v *gocui.View) error {
return nil
}
currentSidePanel, ok := gui.currentSidePanel()
if ok {
return currentSidePanel.HandleSelect()
}
switch v.Name() {
case "menu":
return gui.handleMenuSelect(gui.g, v)
case "project":
return gui.handleProjectSelect(gui.g, v)
case "services":
return gui.Panels.Services.HandleSelect()
case "containers":
return gui.Panels.Containers.HandleSelect()
case "images":
return gui.Panels.Images.HandleSelect()
case "volumes":
return gui.Panels.Volumes.HandleSelect()
case "confirmation":
return nil
case "main":
@ -501,3 +496,25 @@ func prevIntInCycle(sl []WindowMaximisation, current WindowMaximisation) WindowM
func (gui *Gui) CurrentView() *gocui.View {
return gui.g.CurrentView()
}
func (gui *Gui) currentSidePanel() (ISideListPanel, bool) {
viewName := gui.currentViewName()
for _, sidePanel := range gui.allSidepanels() {
if sidePanel.View().Name() == viewName {
return sidePanel, true
}
}
return nil, false
}
func (gui *Gui) allSidepanels() []ISideListPanel {
return []ISideListPanel{
gui.Panels.Projects,
gui.Panels.Services,
gui.Panels.Containers,
gui.Panels.Images,
gui.Panels.Volumes,
}
}

@ -20,12 +20,14 @@ func (gui *Gui) getVolumesPanel() *SideListPanel[*commands.Volume] {
contextIdx: 0,
noItemsMessge: gui.Tr.NoVolumes,
gui: gui.intoInterface(),
contexts: []ContextConfig[*commands.Volume]{
{
key: "config",
title: gui.Tr.ConfigTitle,
render: gui.renderVolumeConfig,
},
getContexts: func() []ContextConfig[*commands.Volume] {
return []ContextConfig[*commands.Volume]{
{
key: "config",
title: gui.Tr.ConfigTitle,
render: gui.renderVolumeConfig,
},
}
},
getSearchStrings: func(volume *commands.Volume) []string {
// TODO: think about more things to search on

Loading…
Cancel
Save