From 79a58c8d48d1e0dcba1e102712b76a74870c47dd Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Wed, 19 Oct 2022 21:58:22 -0700 Subject: [PATCH] convert services panel to use new struct --- pkg/commands/docker.go | 35 +----- pkg/gui/containers_panel.go | 54 ++++----- pkg/gui/filtered_list.go | 7 ++ pkg/gui/gui.go | 31 +++--- pkg/gui/images_panel.go | 43 ++++++- pkg/gui/keybindings.go | 6 +- pkg/gui/layout.go | 3 +- pkg/gui/list_panel.go | 80 ++++--------- pkg/gui/main_panel.go | 4 +- pkg/gui/project_panel.go | 2 +- pkg/gui/services_panel.go | 216 +++++++++++++----------------------- pkg/gui/view_helpers.go | 2 +- 12 files changed, 194 insertions(+), 289 deletions(-) diff --git a/pkg/commands/docker.go b/pkg/commands/docker.go index 05a07e49..2e08c675 100644 --- a/pkg/commands/docker.go +++ b/pkg/commands/docker.go @@ -41,7 +41,6 @@ type DockerCommand struct { ContainerMutex sync.Mutex ServiceMutex sync.Mutex - Services []*Service Containers []*Container // DisplayContainers is the array of containers we will display in the containers panel. If Gui.ShowAllContainers is false, this will only be those containers which aren't based on a service. This reduces clutter and duplication in the UI DisplayContainers []*Container @@ -174,16 +173,13 @@ func (c *DockerCommand) createClientStatMonitor(container *Container) { container.MonitoringStats = false } -// RefreshContainersAndServices returns a slice of docker containers -func (c *DockerCommand) RefreshContainersAndServices() error { +func (c *DockerCommand) RefreshContainersAndServices(currentServices []*Service) ([]*Container, []*Service, error) { c.ServiceMutex.Lock() defer c.ServiceMutex.Unlock() - currentServices := c.Services - containers, err := c.GetContainers() if err != nil { - return err + return nil, nil, err } var services []*Service @@ -193,7 +189,7 @@ func (c *DockerCommand) RefreshContainersAndServices() error { } else { services, err = c.GetServices() if err != nil { - return err + return nil, nil, err } } @@ -204,27 +200,12 @@ func (c *DockerCommand) RefreshContainersAndServices() error { displayContainers = c.obtainStandaloneContainers(containers, services) } - // sort services first by whether they have a linked container, and second by alphabetical order - sort.Slice(services, func(i, j int) bool { - if services[i].Container != nil && services[j].Container == nil { - return true - } - - if services[i].Container == nil && services[j].Container != nil { - return false - } - - return services[i].Name < services[j].Name - }) - c.Containers = containers - c.Services = services - c.Services = c.filterOutIgnoredServices(c.Services) c.DisplayContainers = c.filterOutExited(displayContainers) c.DisplayContainers = c.filterOutIgnoredContainers(c.DisplayContainers) c.DisplayContainers = c.sortedContainers(c.DisplayContainers) - return nil + return c.DisplayContainers, services, nil } func (c *DockerCommand) assignContainersToServices(containers []*Container, services []*Service) { @@ -262,14 +243,6 @@ func (c *DockerCommand) filterOutIgnoredContainers(containers []*Container) []*C }) } -func (c *DockerCommand) filterOutIgnoredServices(services []*Service) []*Service { - return lo.Filter(services, func(service *Service, _ int) bool { - return !lo.SomeBy(c.Config.UserConfig.Ignore, func(ignore string) bool { - return strings.Contains(service.Name, ignore) - }) - }) -} - // sortedContainers returns containers sorted by state if c.SortContainersByState is true (follows 1- running, 2- exited, 3- created) // and sorted by name if c.SortContainersByState is false func (c *DockerCommand) sortedContainers(containers []*Container) []*Container { diff --git a/pkg/gui/containers_panel.go b/pkg/gui/containers_panel.go index 2b66fc36..e6b7d870 100644 --- a/pkg/gui/containers_panel.go +++ b/pkg/gui/containers_panel.go @@ -233,25 +233,27 @@ func (gui *Gui) refreshContainersAndServices() error { } // keep track of current service selected so that we can reposition our cursor if it moves position in the list - sl := gui.State.Panels.Services.SelectedLine - var selectedService *commands.Service - if len(gui.DockerCommand.Services) > 0 { - selectedService = gui.DockerCommand.Services[sl] - } + originalSelectedLineIdx := gui.Panels.Services.selectedIdx + selectedService, isServiceSelected := gui.Panels.Services.list.TryGet(originalSelectedLineIdx) - if err := gui.DockerCommand.RefreshContainersAndServices(); err != nil { + _, services, err := gui.DockerCommand.RefreshContainersAndServices( + gui.Panels.Services.list.GetAllItems(), + ) + if err != nil { return err } + gui.Panels.Services.SetItems(services) + // see if our selected service has moved - if selectedService != nil { - for i, service := range gui.DockerCommand.Services { + if isServiceSelected { + for i, service := range gui.Panels.Services.list.GetItems() { if service.ID == selectedService.ID { - if i == sl { + if i == originalSelectedLineIdx { break } - gui.State.Panels.Services.SelectedLine = i - gui.focusY(i, len(gui.DockerCommand.Services), gui.getServicesView()) + gui.Panels.Services.setSelectedLineIdx(i) + gui.Panels.Services.Refocus() } } } @@ -263,20 +265,18 @@ func (gui *Gui) refreshContainersAndServices() error { gui.State.Panels.Containers.SelectedLine = len(gui.DockerCommand.DisplayContainers) - 1 } - // doing the exact same thing for services - if len(gui.DockerCommand.Services) > 0 && gui.State.Panels.Services.SelectedLine == -1 { - gui.State.Panels.Services.SelectedLine = 0 - } - if len(gui.DockerCommand.Services)-1 < gui.State.Panels.Services.SelectedLine { - gui.State.Panels.Services.SelectedLine = len(gui.DockerCommand.Services) - 1 - } - gui.renderContainersAndServices() return nil } func (gui *Gui) renderContainersAndServices() { + if gui.DockerCommand.InDockerComposeProject { + if err := gui.Panels.Services.RerenderList(); err != nil { + gui.ErrorChan <- err + } + } + gui.g.Update(func(g *gocui.Gui) error { containersView := gui.getContainersView() containersView.Clear() @@ -294,22 +294,6 @@ func (gui *Gui) renderContainersAndServices() { } } - // doing the exact same thing for services - if !gui.DockerCommand.InDockerComposeProject { - return nil - } - servicesView := gui.getServicesView() - servicesView.Clear() - isFocused = gui.g.CurrentView().Name() == "services" - list, err = utils.RenderList(gui.DockerCommand.Services, utils.IsFocused(isFocused)) - if err != nil { - return err - } - fmt.Fprint(servicesView, list) - - if servicesView == g.CurrentView() { - return gui.handleServiceSelect(g, servicesView) - } return nil }) } diff --git a/pkg/gui/filtered_list.go b/pkg/gui/filtered_list.go index 925983fd..2cd2dda2 100644 --- a/pkg/gui/filtered_list.go +++ b/pkg/gui/filtered_list.go @@ -98,3 +98,10 @@ func (self *FilteredList[T]) GetItems() []T { } return result } + +func (self *FilteredList[T]) GetAllItems() []T { + self.mutex.RLock() + defer self.mutex.RUnlock() + + return self.allItems +} diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index a4b18da3..2d4b8409 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -75,7 +75,8 @@ type Gui struct { } type Panels struct { - Images *SideListPanel[*commands.Image] + Images *SideListPanel[*commands.Image] + Services *SideListPanel[*commands.Service] } type Mutexes struct { @@ -83,11 +84,6 @@ type Mutexes struct { ViewStackMutex sync.Mutex } -type servicePanelState struct { - SelectedLine int - ContextIndex int // for specifying if you are looking at logs/stats/config/etc -} - type containerPanelState struct { SelectedLine int ContextIndex int // for specifying if you are looking at logs/stats/config/etc @@ -113,7 +109,6 @@ type volumePanelState struct { } type panelStates struct { - Services *servicePanelState Containers *containerPanelState Menu *menuPanelState Main *mainPanelState @@ -168,7 +163,6 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand initialState := guiState{ Platform: *oSCommand.Platform, Panels: &panelStates{ - Services: &servicePanelState{SelectedLine: -1, ContextIndex: 0}, Containers: &containerPanelState{SelectedLine: -1, ContextIndex: 0}, Volumes: &volumePanelState{SelectedLine: -1, ContextIndex: 0}, Menu: &menuPanelState{SelectedLine: 0}, @@ -266,15 +260,6 @@ func (gui *Gui) Run() error { go gui.listenForEvents(ctx, throttledRefresh.Trigger) go gui.DockerCommand.MonitorContainerStats(ctx) - go func() { - throttledRefresh.Trigger() - - gui.goEvery(time.Millisecond*30, gui.reRenderMain) - gui.goEvery(time.Millisecond*1000, gui.DockerCommand.UpdateContainerDetails) - gui.goEvery(time.Millisecond*1000, gui.checkForContextChange) - gui.goEvery(time.Millisecond*1000, gui.rerenderContainersAndServices) - }() - go func() { for err := range gui.ErrorChan { if err == nil { @@ -297,7 +282,8 @@ func (gui *Gui) Run() error { // TODO: see if we can avoid the circular dependency gui.Panels = Panels{ - Images: gui.getImagePanel(), + Images: gui.getImagesPanel(), + Services: gui.getServicesPanel(), } if err = gui.keybindings(g); err != nil { @@ -316,6 +302,15 @@ func (gui *Gui) Run() error { } } + go func() { + throttledRefresh.Trigger() + + gui.goEvery(time.Millisecond*30, gui.reRenderMain) + gui.goEvery(time.Millisecond*1000, gui.DockerCommand.UpdateContainerDetails) + gui.goEvery(time.Millisecond*1000, gui.checkForContextChange) + gui.goEvery(time.Millisecond*1000, gui.rerenderContainersAndServices) + }() + err = g.MainLoop() if err == gocui.ErrQuit { return nil diff --git a/pkg/gui/images_panel.go b/pkg/gui/images_panel.go index c1444342..84e579d4 100644 --- a/pkg/gui/images_panel.go +++ b/pkg/gui/images_panel.go @@ -13,6 +13,47 @@ import ( "github.com/jesseduffield/lazydocker/pkg/utils" ) +func (gui *Gui) getImagesPanel() *SideListPanel[*commands.Image] { + noneLabel := "" + + return &SideListPanel[*commands.Image]{ + contextKeyPrefix: "images", + ListPanel: ListPanel[*commands.Image]{ + list: NewFilteredList[*commands.Image](), + view: gui.Views.Images, + }, + 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) + }, + }, + }, + getSearchStrings: func(image *commands.Image) []string { + return []string{image.Name, image.Tag} + }, + getContextCacheKey: func(image *commands.Image) string { + return image.ID + }, + sort: func(a *commands.Image, b *commands.Image) bool { + if a.Name == noneLabel && b.Name != noneLabel { + return false + } + + if a.Name != noneLabel && b.Name == noneLabel { + return true + } + + return a.Name < b.Name + }, + } +} + func (gui *Gui) renderImageConfig(image *commands.Image) error { return gui.T.NewTask(func(stop chan struct{}) { padding := 10 @@ -53,7 +94,7 @@ func (gui *Gui) refreshStateImages() error { } // TODO: think about also re-filtering/sorting - gui.Panels.Images.list.SetItems(images) + gui.Panels.Images.SetItems(images) return nil } diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 8ffa3051..ad22fa17 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -363,14 +363,14 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { ViewName: "services", Key: '[', Modifier: gocui.ModNone, - Handler: gui.handleServicesPrevContext, + Handler: wrappedHandler(gui.Panels.Services.OnPrevContext), Description: gui.Tr.PreviousContext, }, { ViewName: "services", Key: ']', Modifier: gocui.ModNone, - Handler: gui.handleServicesNextContext, + Handler: wrappedHandler(gui.Panels.Services.OnNextContext), Description: gui.Tr.NextContext, }, { @@ -584,7 +584,7 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { onClick func(*gocui.Gui, *gocui.View) error }{ "menu": {onKeyUpPress: gui.handleMenuPrevLine, onKeyDownPress: gui.handleMenuNextLine, onClick: gui.handleMenuClick}, - "services": {onKeyUpPress: gui.handleServicesPrevLine, onKeyDownPress: gui.handleServicesNextLine, onClick: gui.handleServicesClick}, + "services": {onKeyUpPress: wrappedHandler(gui.Panels.Services.OnPrevLine), onKeyDownPress: wrappedHandler(gui.Panels.Services.OnNextLine), onClick: wrappedHandler(gui.Panels.Services.OnClick)}, "containers": {onKeyUpPress: gui.handleContainersPrevLine, onKeyDownPress: gui.handleContainersNextLine, onClick: gui.handleContainersClick}, "images": {onKeyUpPress: wrappedHandler(gui.Panels.Images.OnPrevLine), onKeyDownPress: wrappedHandler(gui.Panels.Images.OnNextLine), onClick: wrappedHandler(gui.Panels.Images.OnClick)}, "volumes": {onKeyUpPress: gui.handleVolumesPrevLine, onKeyDownPress: gui.handleVolumesNextLine, onClick: gui.handleVolumesClick}, diff --git a/pkg/gui/layout.go b/pkg/gui/layout.go index b6f33cf9..ec7e81fc 100644 --- a/pkg/gui/layout.go +++ b/pkg/gui/layout.go @@ -128,7 +128,6 @@ func (gui *Gui) focusPointInView(view *gocui.View) { listViews := map[string]listViewState{ "containers": {selectedLine: gui.State.Panels.Containers.SelectedLine, lineCount: len(gui.DockerCommand.DisplayContainers)}, "volumes": {selectedLine: gui.State.Panels.Volumes.SelectedLine, lineCount: len(gui.DockerCommand.Volumes)}, - "services": {selectedLine: gui.State.Panels.Services.SelectedLine, lineCount: len(gui.DockerCommand.Services)}, "menu": {selectedLine: gui.State.Panels.Menu.SelectedLine, lineCount: gui.State.MenuItemCount}, } @@ -139,6 +138,8 @@ func (gui *Gui) focusPointInView(view *gocui.View) { switch view.Name() { case "images": gui.Panels.Images.Refocus() + case "services": + gui.Panels.Services.Refocus() } } diff --git a/pkg/gui/list_panel.go b/pkg/gui/list_panel.go index bf73813d..4736814c 100644 --- a/pkg/gui/list_panel.go +++ b/pkg/gui/list_panel.go @@ -6,14 +6,11 @@ import ( "github.com/go-errors/errors" "github.com/jesseduffield/gocui" - "github.com/jesseduffield/lazydocker/pkg/commands" "github.com/jesseduffield/lazydocker/pkg/utils" "github.com/samber/lo" ) type ListPanel[T comparable] struct { - toColumns func(T) []string - selectedIdx int list *FilteredList[T] view *gocui.View @@ -28,6 +25,14 @@ func (self *ListPanel[T]) setSelectedLineIdx(value int) { self.selectedIdx = clampedValue } +func (self *ListPanel[T]) clampSelectedLineIdx() { + clamped := utils.Clamp(self.selectedIdx, 0, self.list.Len()-1) + + if clamped != self.selectedIdx { + self.selectedIdx = clamped + } +} + // moves the cursor up or down by the given amount (up for negative values) func (self *ListPanel[T]) moveSelectedLine(delta int) { self.setSelectedLineIdx(self.selectedIdx + delta) @@ -57,7 +62,8 @@ type SideListPanel[T comparable] struct { // returns strings that can be filtered on getSearchStrings func(item T) []string - getId 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 } @@ -86,54 +92,6 @@ func (gui *Gui) intoInterface() IGui { return gui } -func (gui *Gui) getImagePanel() *SideListPanel[*commands.Image] { - noneLabel := "" - - return &SideListPanel[*commands.Image]{ - contextKeyPrefix: "images", - ListPanel: ListPanel[*commands.Image]{ - toColumns: func(image *commands.Image) []string { - return []string{ - image.Name, - image.Tag, - utils.FormatDecimalBytes(int(image.Image.Size)), - } - }, - list: NewFilteredList[*commands.Image](), - view: gui.Views.Images, - }, - 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) - }, - }, - }, - getSearchStrings: func(image *commands.Image) []string { - return []string{image.Name, image.Tag} - }, - getId: func(image *commands.Image) string { - return image.ID - }, - sort: func(a *commands.Image, b *commands.Image) bool { - if a.Name == noneLabel && b.Name != noneLabel { - return false - } - - if a.Name != noneLabel && b.Name == noneLabel { - return true - } - - return a.Name < b.Name - }, - } -} - func (self *SideListPanel[T]) OnClick() error { itemCount := self.list.Len() handleSelect := self.HandleSelect @@ -154,7 +112,7 @@ func (self *SideListPanel[T]) HandleSelect() error { self.Refocus() - key := self.contextKeyPrefix + "-" + self.getId(item) + "-" + self.contexts[self.contextIdx].key + key := self.contextKeyPrefix + "-" + self.getContextCacheKey(item) + "-" + self.contexts[self.contextIdx].key if !self.gui.ShouldRefresh(key) { return nil } @@ -225,7 +183,12 @@ func (self *SideListPanel[T]) Refocus() { self.gui.FocusY(self.selectedIdx, self.list.Len(), self.view) } -func (self *SideListPanel[T]) RerenderList() error { +func (self *SideListPanel[T]) SetItems(items []T) { + self.list.SetItems(items) + self.FilterAndSort() +} + +func (self *SideListPanel[T]) FilterAndSort() { filterString := self.gui.FilterString(self.view) self.list.Filter(func(item T, index int) bool { @@ -248,10 +211,11 @@ func (self *SideListPanel[T]) RerenderList() error { self.list.Sort(self.sort) - // TODO: use clamp? - if self.list.Len()-1 < self.selectedIdx { - self.selectedIdx = self.list.Len() - 1 - } + self.clampSelectedLineIdx() +} + +func (self *SideListPanel[T]) RerenderList() error { + self.FilterAndSort() self.gui.Update(func() error { self.view.Clear() diff --git a/pkg/gui/main_panel.go b/pkg/gui/main_panel.go index b95bdb6b..22834fd7 100644 --- a/pkg/gui/main_panel.go +++ b/pkg/gui/main_panel.go @@ -88,8 +88,8 @@ func (gui *Gui) onMainTabClick(tabIndex int) error { gui.State.Panels.Project.ContextIndex = tabIndex return gui.handleProjectSelect(gui.g, gui.getProjectView()) case "services": - gui.State.Panels.Services.ContextIndex = tabIndex - return gui.handleServiceSelect(gui.g, gui.getServicesView()) + gui.Panels.Services.SetContextIndex(tabIndex) + return gui.Panels.Services.HandleSelect() case "containers": gui.State.Panels.Containers.ContextIndex = tabIndex return gui.handleContainerSelect(gui.g, gui.getContainersView()) diff --git a/pkg/gui/project_panel.go b/pkg/gui/project_panel.go index 3a2922ab..ddc60b2f 100644 --- a/pkg/gui/project_panel.go +++ b/pkg/gui/project_panel.go @@ -43,7 +43,7 @@ func (gui *Gui) refreshProject() { func (gui *Gui) getProjectName() string { projectName := path.Base(gui.Config.ProjectDir) if gui.DockerCommand.InDockerComposeProject { - for _, service := range gui.DockerCommand.Services { + for _, service := range gui.Panels.Services.list.GetAllItems() { container := service.Container if container != nil && container.DetailsLoaded() { return container.Details.Config.Labels["com.docker.compose.project"] diff --git a/pkg/gui/services_panel.go b/pkg/gui/services_panel.go index c0361e1a..959ede0c 100644 --- a/pkg/gui/services_panel.go +++ b/pkg/gui/services_panel.go @@ -5,101 +5,89 @@ import ( "time" "github.com/fatih/color" - "github.com/go-errors/errors" "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazydocker/pkg/commands" "github.com/jesseduffield/lazydocker/pkg/config" "github.com/jesseduffield/lazydocker/pkg/utils" ) -// list panel functions +func (gui *Gui) getServicesPanel() *SideListPanel[*commands.Service] { + return &SideListPanel[*commands.Service]{ + contextKeyPrefix: "services", + ListPanel: ListPanel[*commands.Service]{ + list: NewFilteredList[*commands.Service](), + view: gui.Views.Services, + }, + contextIdx: 0, + // 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, + }, + }, + getSearchStrings: func(service *commands.Service) []string { + // TODO: think about more things to search on + return []string{service.Name} + }, + getContextCacheKey: func(service *commands.Service) string { + if service.Container == nil { + return service.ID + } + return service.ID + "-" + service.Container.ID + "-" + service.Container.Container.State + }, + // sort services first by whether they have a linked container, and second by alphabetical order + sort: func(a *commands.Service, b *commands.Service) bool { + if a.Container != nil && b.Container == nil { + return true + } -func (gui *Gui) getServiceContexts() []string { - return []string{"logs", "stats", "container-env", "container-config", "top"} -} + if a.Container == nil && b.Container != nil { + return false + } -func (gui *Gui) getServiceContextTitles() []string { - return []string{ - gui.Tr.LogsTitle, - gui.Tr.StatsTitle, - gui.Tr.ContainerEnvTitle, - gui.Tr.ContainerConfigTitle, - gui.Tr.TopTitle, + return a.Name < b.Name + }, } } -func (gui *Gui) getSelectedService() (*commands.Service, error) { - selectedLine := gui.State.Panels.Services.SelectedLine - if selectedLine == -1 { - return &commands.Service{}, errors.New("no service selected") +func (gui *Gui) renderServiceContainerConfig(service *commands.Service) error { + if service.Container == nil { + return gui.renderStringMain(gui.Tr.NoContainer) } - return gui.DockerCommand.Services[selectedLine], nil + return gui.renderContainerConfig(service.Container) } -func (gui *Gui) handleServicesClick(g *gocui.Gui, v *gocui.View) error { - itemCount := len(gui.DockerCommand.Services) - handleSelect := gui.handleServiceSelect - selectedLine := &gui.State.Panels.Services.SelectedLine - - return gui.handleClick(v, itemCount, selectedLine, handleSelect) -} - -func (gui *Gui) handleServiceSelect(g *gocui.Gui, v *gocui.View) error { - service, err := gui.getSelectedService() - if err != nil { - return nil +func (gui *Gui) renderServiceContainerEnv(service *commands.Service) error { + if service.Container == nil { + return gui.renderStringMain(gui.Tr.NoContainer) } - containerID := "" - if service.Container != nil { - containerID = service.Container.ID - } - - gui.focusY(gui.State.Panels.Services.SelectedLine, len(gui.DockerCommand.Services), v) - - key := "services-" + service.ID + "-" + containerID + "-" + gui.getServiceContexts()[gui.State.Panels.Services.ContextIndex] - if !gui.shouldRefresh(key) { - return nil - } - - mainView := gui.getMainView() - - mainView.Tabs = gui.getServiceContextTitles() - mainView.TabIndex = gui.State.Panels.Services.ContextIndex - - switch gui.getServiceContexts()[gui.State.Panels.Services.ContextIndex] { - case "logs": - if err := gui.renderServiceLogs(service); err != nil { - return err - } - case "stats": - if err := gui.renderServiceStats(service); err != nil { - return err - } - case "container-env": - if service.Container == nil { - return gui.renderString(gui.g, "main", gui.Tr.NoContainer) - } - if err := gui.renderContainerEnv(service.Container); err != nil { - return err - } - case "container-config": - if service.Container == nil { - return gui.renderString(gui.g, "main", gui.Tr.NoContainer) - } - if err := gui.renderContainerConfig(service.Container); err != nil { - return err - } - case "top": - if err := gui.renderServiceTop(service); err != nil { - return err - } - default: - return errors.New("Unknown context for services panel") - } - - return nil + return gui.renderContainerEnv(service.Container) } func (gui *Gui) renderServiceStats(service *commands.Service) error { @@ -135,54 +123,6 @@ func (gui *Gui) renderServiceLogs(service *commands.Service) error { return gui.renderContainerLogsToMain(service.Container) } -func (gui *Gui) handleServicesNextLine(g *gocui.Gui, v *gocui.View) error { - if gui.popupPanelFocused() || gui.g.CurrentView() != v { - return nil - } - - panelState := gui.State.Panels.Services - gui.changeSelectedLine(&panelState.SelectedLine, len(gui.DockerCommand.Services), false) - - return gui.handleServiceSelect(gui.g, v) -} - -func (gui *Gui) handleServicesPrevLine(g *gocui.Gui, v *gocui.View) error { - if gui.popupPanelFocused() || gui.g.CurrentView() != v { - return nil - } - - panelState := gui.State.Panels.Services - gui.changeSelectedLine(&panelState.SelectedLine, len(gui.DockerCommand.Services), true) - - return gui.handleServiceSelect(gui.g, v) -} - -func (gui *Gui) handleServicesNextContext(g *gocui.Gui, v *gocui.View) error { - contexts := gui.getServiceContexts() - if gui.State.Panels.Services.ContextIndex >= len(contexts)-1 { - gui.State.Panels.Services.ContextIndex = 0 - } else { - gui.State.Panels.Services.ContextIndex++ - } - - _ = gui.handleServiceSelect(gui.g, v) - - return nil -} - -func (gui *Gui) handleServicesPrevContext(g *gocui.Gui, v *gocui.View) error { - contexts := gui.getServiceContexts() - if gui.State.Panels.Services.ContextIndex <= 0 { - gui.State.Panels.Services.ContextIndex = len(contexts) - 1 - } else { - gui.State.Panels.Services.ContextIndex-- - } - - _ = gui.handleServiceSelect(gui.g, v) - - return nil -} - type commandOption struct { description string command string @@ -195,7 +135,7 @@ func (r *commandOption) GetDisplayStrings(isFocused bool) []string { } func (gui *Gui) handleServiceRemoveMenu(g *gocui.Gui, v *gocui.View) error { - service, err := gui.getSelectedService() + service, err := gui.Panels.Services.GetSelectedItem() if err != nil { return nil } @@ -220,7 +160,7 @@ func (gui *Gui) handleServiceRemoveMenu(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) handleServicePause(g *gocui.Gui, v *gocui.View) error { - service, err := gui.getSelectedService() + service, err := gui.Panels.Services.GetSelectedItem() if err != nil { return nil } @@ -232,7 +172,7 @@ func (gui *Gui) handleServicePause(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) handleServiceStop(g *gocui.Gui, v *gocui.View) error { - service, err := gui.getSelectedService() + service, err := gui.Panels.Services.GetSelectedItem() if err != nil { return nil } @@ -249,7 +189,7 @@ func (gui *Gui) handleServiceStop(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) handleServiceUp(g *gocui.Gui, v *gocui.View) error { - service, err := gui.getSelectedService() + service, err := gui.Panels.Services.GetSelectedItem() if err != nil { return nil } @@ -264,7 +204,7 @@ func (gui *Gui) handleServiceUp(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) handleServiceRestart(g *gocui.Gui, v *gocui.View) error { - service, err := gui.getSelectedService() + service, err := gui.Panels.Services.GetSelectedItem() if err != nil { return nil } @@ -279,7 +219,7 @@ func (gui *Gui) handleServiceRestart(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) handleServiceStart(g *gocui.Gui, v *gocui.View) error { - service, err := gui.getSelectedService() + service, err := gui.Panels.Services.GetSelectedItem() if err != nil { return nil } @@ -294,7 +234,7 @@ func (gui *Gui) handleServiceStart(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) handleServiceAttach(g *gocui.Gui, v *gocui.View) error { - service, err := gui.getSelectedService() + service, err := gui.Panels.Services.GetSelectedItem() if err != nil { return nil } @@ -312,7 +252,7 @@ func (gui *Gui) handleServiceAttach(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) handleServiceRenderLogsToMain(g *gocui.Gui, v *gocui.View) error { - service, err := gui.getSelectedService() + service, err := gui.Panels.Services.GetSelectedItem() if err != nil { return nil } @@ -389,7 +329,7 @@ func (gui *Gui) handleProjectDown(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) handleServiceRestartMenu(g *gocui.Gui, v *gocui.View) error { - service, err := gui.getSelectedService() + service, err := gui.Panels.Services.GetSelectedItem() if err != nil { return nil } @@ -474,7 +414,7 @@ func (gui *Gui) createServiceCommandMenu(options []*commandOption, status string } func (gui *Gui) handleServicesCustomCommand(g *gocui.Gui, v *gocui.View) error { - service, err := gui.getSelectedService() + service, err := gui.Panels.Services.GetSelectedItem() if err != nil { return nil } @@ -518,7 +458,7 @@ func (gui *Gui) handleServicesBulkCommand(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) handleServicesExecShell(g *gocui.Gui, v *gocui.View) error { - service, err := gui.getSelectedService() + service, err := gui.Panels.Services.GetSelectedItem() if err != nil { return nil } @@ -532,7 +472,7 @@ func (gui *Gui) handleServicesExecShell(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) handleServicesOpenInBrowserCommand(g *gocui.Gui, v *gocui.View) error { - service, err := gui.getSelectedService() + service, err := gui.Panels.Services.GetSelectedItem() if err != nil { return nil } diff --git a/pkg/gui/view_helpers.go b/pkg/gui/view_helpers.go index a68c0e00..5e5204d7 100644 --- a/pkg/gui/view_helpers.go +++ b/pkg/gui/view_helpers.go @@ -77,7 +77,7 @@ func (gui *Gui) newLineFocused(v *gocui.View) error { case "project": return gui.handleProjectSelect(gui.g, v) case "services": - return gui.handleServiceSelect(gui.g, v) + return gui.Panels.Services.HandleSelect() case "containers": return gui.handleContainerSelect(gui.g, v) case "images":