more refactoring of list panels

pull/392/head
Jesse Duffield 2 years ago
parent 5d498c796a
commit fc592b5806

@ -2,6 +2,7 @@ package gui
import (
"github.com/jesseduffield/lazycore/pkg/boxlayout"
"github.com/jesseduffield/lazydocker/pkg/gui/panels"
"github.com/jesseduffield/lazydocker/pkg/utils"
"github.com/mattn/go-runewidth"
"github.com/samber/lo"
@ -129,12 +130,12 @@ func (gui *Gui) infoSectionChildren(informationStr string, appStatus string) []*
}
func (gui *Gui) sideViewNames() []string {
visibleSidePanels := lo.Filter(gui.allSidePanels(), func(panel ISideListPanel, _ int) bool {
visibleSidePanels := lo.Filter(gui.allSidePanels(), func(panel panels.ISideListPanel, _ int) bool {
return !panel.IsHidden()
})
return lo.Map(visibleSidePanels, func(panel ISideListPanel, _ int) string {
return panel.View().Name()
return lo.Map(visibleSidePanels, func(panel panels.ISideListPanel, _ int) string {
return panel.GetView().Name()
})
}

@ -11,11 +11,12 @@ import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazydocker/pkg/commands"
"github.com/jesseduffield/lazydocker/pkg/config"
"github.com/jesseduffield/lazydocker/pkg/gui/panels"
"github.com/jesseduffield/lazydocker/pkg/utils"
"github.com/samber/lo"
)
func (gui *Gui) getContainersPanel() *SideListPanel[*commands.Container] {
func (gui *Gui) getContainersPanel() *panels.SideListPanel[*commands.Container] {
// Standalone containers are containers which are either one-off containers, or whose service is not part of this docker-compose context.
isStandaloneContainer := func(container *commands.Container) bool {
if container.OneOff || container.ServiceName == "" {
@ -27,34 +28,34 @@ func (gui *Gui) getContainersPanel() *SideListPanel[*commands.Container] {
})
}
return &SideListPanel[*commands.Container]{
ContextState: &ContextState[*commands.Container]{
GetContexts: func() []ContextConfig[*commands.Container] {
return []ContextConfig[*commands.Container]{
return &panels.SideListPanel[*commands.Container]{
ContextState: &panels.ContextState[*commands.Container]{
GetContexts: func() []panels.ContextConfig[*commands.Container] {
return []panels.ContextConfig[*commands.Container]{
{
key: "logs",
title: gui.Tr.LogsTitle,
render: gui.renderContainerLogsToMain,
Key: "logs",
Title: gui.Tr.LogsTitle,
Render: gui.renderContainerLogsToMain,
},
{
key: "stats",
title: gui.Tr.StatsTitle,
render: gui.renderContainerStats,
Key: "stats",
Title: gui.Tr.StatsTitle,
Render: gui.renderContainerStats,
},
{
key: "env",
title: gui.Tr.EnvTitle,
render: gui.renderContainerEnv,
Key: "env",
Title: gui.Tr.EnvTitle,
Render: gui.renderContainerEnv,
},
{
key: "config",
title: gui.Tr.ConfigTitle,
render: gui.renderContainerConfig,
Key: "config",
Title: gui.Tr.ConfigTitle,
Render: gui.renderContainerConfig,
},
{
key: "top",
title: gui.Tr.TopTitle,
render: gui.renderContainerTop,
Key: "top",
Title: gui.Tr.TopTitle,
Render: gui.renderContainerTop,
},
}
},
@ -62,12 +63,12 @@ func (gui *Gui) getContainersPanel() *SideListPanel[*commands.Container] {
return "containers-" + container.ID + "-" + container.Container.State
},
},
ListPanel: ListPanel[*commands.Container]{
List: NewFilteredList[*commands.Container](),
view: gui.Views.Containers,
ListPanel: panels.ListPanel[*commands.Container]{
List: panels.NewFilteredList[*commands.Container](),
View: gui.Views.Containers,
},
NoItemsMessage: gui.Tr.NoContainers,
gui: gui.intoInterface(),
Gui: gui.intoInterface(),
// 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
Sort: func(a *commands.Container, b *commands.Container) bool {
@ -282,7 +283,7 @@ func (gui *Gui) refreshContainersAndServices() error {
if i == originalSelectedLineIdx {
break
}
gui.Panels.Services.setSelectedLineIdx(i)
gui.Panels.Services.SetSelectedLineIdx(i)
gui.Panels.Services.Refocus()
}
}

@ -24,7 +24,7 @@ func (gui *Gui) handleOpenFilter() error {
func (gui *Gui) onNewFilterNeedle(value string) error {
gui.State.Filter.needle = value
gui.ResetOrigin(gui.State.Filter.panel.View())
gui.ResetOrigin(gui.State.Filter.panel.GetView())
return gui.State.Filter.panel.RerenderList()
}
@ -59,7 +59,7 @@ func (gui *Gui) clearFilter() error {
return nil
}
gui.ResetOrigin(panel.View())
gui.ResetOrigin(panel.GetView())
return panel.RerenderList()
}

@ -52,7 +52,7 @@ func (gui *Gui) switchFocusAux(newView *gocui.View) error {
newViewStack := gui.State.ViewStack
if gui.State.Filter.panel != nil && !lo.Contains(newViewStack, gui.State.Filter.panel.View().Name()) {
if gui.State.Filter.panel != nil && !lo.Contains(newViewStack, gui.State.Filter.panel.GetView().Name()) {
if err := gui.clearFilter(); err != nil {
return err
}

@ -15,6 +15,7 @@ import (
lcUtils "github.com/jesseduffield/lazycore/pkg/utils"
"github.com/jesseduffield/lazydocker/pkg/commands"
"github.com/jesseduffield/lazydocker/pkg/config"
"github.com/jesseduffield/lazydocker/pkg/gui/panels"
"github.com/jesseduffield/lazydocker/pkg/i18n"
"github.com/jesseduffield/lazydocker/pkg/tasks"
"github.com/sasha-s/go-deadlock"
@ -49,12 +50,12 @@ type Gui struct {
}
type Panels struct {
Projects *SideListPanel[*commands.Project]
Services *SideListPanel[*commands.Service]
Containers *SideListPanel[*commands.Container]
Images *SideListPanel[*commands.Image]
Volumes *SideListPanel[*commands.Volume]
Menu *SideListPanel[*MenuItem]
Projects *panels.SideListPanel[*commands.Project]
Services *panels.SideListPanel[*commands.Service]
Containers *panels.SideListPanel[*commands.Container]
Images *panels.SideListPanel[*commands.Image]
Volumes *panels.SideListPanel[*commands.Volume]
Menu *panels.SideListPanel[*MenuItem]
}
type Mutexes struct {
@ -94,7 +95,7 @@ type filterState struct {
// or we've committed the filter and we're back in the list view
active bool
// The panel that we're filtering.
panel ISideListPanel
panel panels.ISideListPanel
// The string that we're filtering on
needle string
}

@ -10,21 +10,22 @@ import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazydocker/pkg/commands"
"github.com/jesseduffield/lazydocker/pkg/config"
"github.com/jesseduffield/lazydocker/pkg/gui/panels"
"github.com/jesseduffield/lazydocker/pkg/utils"
"github.com/samber/lo"
)
func (gui *Gui) getImagesPanel() *SideListPanel[*commands.Image] {
func (gui *Gui) getImagesPanel() *panels.SideListPanel[*commands.Image] {
noneLabel := "<none>"
return &SideListPanel[*commands.Image]{
ContextState: &ContextState[*commands.Image]{
GetContexts: func() []ContextConfig[*commands.Image] {
return []ContextConfig[*commands.Image]{
return &panels.SideListPanel[*commands.Image]{
ContextState: &panels.ContextState[*commands.Image]{
GetContexts: func() []panels.ContextConfig[*commands.Image] {
return []panels.ContextConfig[*commands.Image]{
{
key: "config",
title: gui.Tr.ConfigTitle,
render: func(image *commands.Image) error {
Key: "config",
Title: gui.Tr.ConfigTitle,
Render: func(image *commands.Image) error {
return gui.renderImageConfig(image)
},
},
@ -34,12 +35,12 @@ func (gui *Gui) getImagesPanel() *SideListPanel[*commands.Image] {
return "images-" + image.ID
},
},
ListPanel: ListPanel[*commands.Image]{
List: NewFilteredList[*commands.Image](),
view: gui.Views.Images,
ListPanel: panels.ListPanel[*commands.Image]{
List: panels.NewFilteredList[*commands.Image](),
View: gui.Views.Images,
},
NoItemsMessage: gui.Tr.NoImages,
gui: gui.intoInterface(),
Gui: gui.intoInterface(),
Sort: func(a *commands.Image, b *commands.Image) bool {
if a.Name == noneLabel && b.Name != noneLabel {
return false
@ -114,7 +115,7 @@ func (gui *Gui) refreshStateImages() error {
}
func (gui *Gui) FilterString(view *gocui.View) string {
if gui.State.Filter.panel != nil && gui.State.Filter.panel.View() != view {
if gui.State.Filter.panel != nil && gui.State.Filter.panel.GetView() != view {
return ""
}

@ -492,12 +492,12 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
for _, panel := range gui.allSidePanels() {
bindings = append(bindings, []*Binding{
{ViewName: panel.View().Name(), Key: gocui.KeyArrowLeft, Modifier: gocui.ModNone, Handler: gui.previousView},
{ViewName: panel.View().Name(), Key: gocui.KeyArrowRight, Modifier: gocui.ModNone, Handler: gui.nextView},
{ViewName: panel.View().Name(), Key: 'h', Modifier: gocui.ModNone, Handler: gui.previousView},
{ViewName: panel.View().Name(), Key: 'l', Modifier: gocui.ModNone, Handler: gui.nextView},
{ViewName: panel.View().Name(), Key: gocui.KeyTab, Modifier: gocui.ModNone, Handler: gui.nextView},
{ViewName: panel.View().Name(), Key: gocui.KeyBacktab, Modifier: gocui.ModNone, Handler: gui.previousView},
{ViewName: panel.GetView().Name(), Key: gocui.KeyArrowLeft, Modifier: gocui.ModNone, Handler: gui.previousView},
{ViewName: panel.GetView().Name(), Key: gocui.KeyArrowRight, Modifier: gocui.ModNone, Handler: gui.nextView},
{ViewName: panel.GetView().Name(), Key: 'h', Modifier: gocui.ModNone, Handler: gui.previousView},
{ViewName: panel.GetView().Name(), Key: 'l', Modifier: gocui.ModNone, Handler: gui.nextView},
{ViewName: panel.GetView().Name(), Key: gocui.KeyTab, Modifier: gocui.ModNone, Handler: gui.nextView},
{ViewName: panel.GetView().Name(), Key: gocui.KeyBacktab, Modifier: gocui.ModNone, Handler: gui.previousView},
}...)
}
@ -514,7 +514,7 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
}
for _, panel := range gui.allListPanels() {
setUpDownClickBindings(panel.View().Name(), panel.HandlePrevLine, panel.HandleNextLine, panel.HandleClick)
setUpDownClickBindings(panel.GetView().Name(), panel.HandlePrevLine, panel.HandleNextLine, panel.HandleClick)
}
setUpDownClickBindings("main", gui.scrollUpMain, gui.scrollDownMain, gui.handleMainClick)
@ -522,21 +522,21 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
for _, panel := range gui.allSidePanels() {
bindings = append(bindings,
&Binding{
ViewName: panel.View().Name(),
ViewName: panel.GetView().Name(),
Key: gocui.KeyEnter,
Modifier: gocui.ModNone,
Handler: gui.handleEnterMain,
Description: gui.Tr.FocusMain,
},
&Binding{
ViewName: panel.View().Name(),
ViewName: panel.GetView().Name(),
Key: '[',
Modifier: gocui.ModNone,
Handler: wrappedHandler(panel.HandlePrevContext),
Description: gui.Tr.PreviousContext,
},
&Binding{
ViewName: panel.View().Name(),
ViewName: panel.GetView().Name(),
Key: ']',
Modifier: gocui.ModNone,
Handler: wrappedHandler(panel.HandleNextContext),
@ -547,7 +547,7 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
for _, panel := range gui.allListPanels() {
bindings = append(bindings, &Binding{
ViewName: panel.View().Name(),
ViewName: panel.GetView().Name(),
Key: '/',
Modifier: gocui.ModNone,
Handler: wrappedHandler(gui.handleOpenFilter),

@ -1,6 +1,7 @@
package gui
import (
"github.com/jesseduffield/lazydocker/pkg/gui/panels"
"github.com/jesseduffield/lazydocker/pkg/utils"
)
@ -22,14 +23,14 @@ type CreateMenuOptions struct {
HideCancel bool
}
func (gui *Gui) getMenuPanel() *SideListPanel[*MenuItem] {
return &SideListPanel[*MenuItem]{
ListPanel: ListPanel[*MenuItem]{
List: NewFilteredList[*MenuItem](),
view: gui.Views.Menu,
func (gui *Gui) getMenuPanel() *panels.SideListPanel[*MenuItem] {
return &panels.SideListPanel[*MenuItem]{
ListPanel: panels.ListPanel[*MenuItem]{
List: panels.NewFilteredList[*MenuItem](),
View: gui.Views.Menu,
},
NoItemsMessage: "",
gui: gui.intoInterface(),
Gui: gui.intoInterface(),
OnClick: gui.onMenuPress,
Sort: nil,
GetDisplayStrings: func(menuItem *MenuItem) []string {
@ -101,7 +102,7 @@ func (gui *Gui) Menu(opts CreateMenuOptions) error {
}
gui.Panels.Menu.SetItems(opts.Items)
gui.Panels.Menu.setSelectedLineIdx(0)
gui.Panels.Menu.SetSelectedLineIdx(0)
if err := gui.Panels.Menu.RerenderList(); err != nil {
return err

@ -0,0 +1,7 @@
package gui
import "github.com/jesseduffield/lazydocker/pkg/gui/panels"
func (gui *Gui) intoInterface() panels.IGui {
return gui
}

@ -1,4 +1,4 @@
package gui
package panels
import (
"sort"

@ -1,4 +1,4 @@
package gui
package panels
import (
"testing"

@ -0,0 +1,42 @@
package panels
import (
"github.com/jesseduffield/gocui"
lcUtils "github.com/jesseduffield/lazycore/pkg/utils"
)
type ListPanel[T comparable] struct {
SelectedIdx int
List *FilteredList[T]
View *gocui.View
}
func (self *ListPanel[T]) SetSelectedLineIdx(value int) {
clampedValue := 0
if self.List.Len() > 0 {
clampedValue = lcUtils.Clamp(value, 0, self.List.Len()-1)
}
self.SelectedIdx = clampedValue
}
func (self *ListPanel[T]) clampSelectedLineIdx() {
clamped := lcUtils.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)
}
func (self *ListPanel[T]) SelectNextLine() {
self.moveSelectedLine(1)
}
func (self *ListPanel[T]) SelectPrevLine() {
self.moveSelectedLine(-1)
}

@ -1,4 +1,4 @@
package gui
package panels
import (
"fmt"
@ -6,53 +6,23 @@ import (
"github.com/go-errors/errors"
"github.com/jesseduffield/gocui"
lcUtils "github.com/jesseduffield/lazycore/pkg/utils"
"github.com/jesseduffield/lazydocker/pkg/utils"
"github.com/samber/lo"
)
type ListPanel[T comparable] struct {
SelectedIdx int
List *FilteredList[T]
view *gocui.View
}
func (self *ListPanel[T]) setSelectedLineIdx(value int) {
clampedValue := 0
if self.List.Len() > 0 {
clampedValue = lcUtils.Clamp(value, 0, self.List.Len()-1)
}
self.SelectedIdx = clampedValue
}
func (self *ListPanel[T]) clampSelectedLineIdx() {
clamped := lcUtils.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)
}
func (self *ListPanel[T]) SelectNextLine() {
self.moveSelectedLine(1)
}
func (self *ListPanel[T]) SelectPrevLine() {
self.moveSelectedLine(-1)
}
type ContextState[T any] struct {
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
type ISideListPanel interface {
SetContextIndex(int)
HandleSelect() error
GetView() *gocui.View
Refocus()
RerenderList() error
IsFilterDisabled() bool
IsHidden() bool
HandleNextLine() error
HandlePrevLine() error
HandleClick() error
HandlePrevContext() error
HandleNextContext() error
}
// list panel at the side of the screen that renders content to the main panel
@ -65,7 +35,7 @@ type SideListPanel[T comparable] struct {
// and it has focus. Leave empty if you don't want to render anything
NoItemsMessage string
gui IGui
Gui IGui
// this Filter is applied on top of additional default filters
Filter func(T) bool
@ -85,27 +55,20 @@ type SideListPanel[T comparable] struct {
Hide func() bool
}
type ISideListPanel interface {
SetContextIndex(int)
HandleSelect() error
View() *gocui.View
Refocus()
RerenderList() error
IsFilterDisabled() bool
IsHidden() bool
HandleNextLine() error
HandlePrevLine() error
HandleClick() error
HandlePrevContext() error
HandleNextContext() error
}
var _ ISideListPanel = &SideListPanel[int]{}
type ContextState[T any] struct {
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
}
type ContextConfig[T any] struct {
key string
title string
render func(item T) error
Key string
Title string
Render func(item T) error
}
type IGui interface {
@ -121,16 +84,12 @@ type IGui interface {
Update(func() error)
}
func (gui *Gui) intoInterface() IGui {
return gui
}
func (self *SideListPanel[T]) HandleClick() error {
itemCount := self.List.Len()
handleSelect := self.HandleSelect
selectedLine := &self.SelectedIdx
if err := self.gui.HandleClick(self.view, itemCount, selectedLine, handleSelect); err != nil {
if err := self.Gui.HandleClick(self.View, itemCount, selectedLine, handleSelect); err != nil {
return err
}
@ -144,8 +103,8 @@ func (self *SideListPanel[T]) HandleClick() error {
return nil
}
func (self *SideListPanel[T]) View() *gocui.View {
return self.view
func (self *SideListPanel[T]) GetView() *gocui.View {
return self.View
}
func (self *SideListPanel[T]) HandleSelect() error {
@ -156,7 +115,7 @@ func (self *SideListPanel[T]) HandleSelect() error {
}
if self.NoItemsMessage != "" {
return self.gui.RenderStringMain(self.NoItemsMessage)
return self.Gui.RenderStringMain(self.NoItemsMessage)
}
return nil
@ -173,25 +132,25 @@ func (self *SideListPanel[T]) renderContext(item T) error {
}
key := self.ContextState.GetCurrentContextKey(item)
if !self.gui.ShouldRefresh(key) {
if !self.Gui.ShouldRefresh(key) {
return nil
}
mainView := self.gui.GetMainView()
mainView := self.Gui.GetMainView()
mainView.Tabs = self.ContextState.GetContextTitles()
mainView.TabIndex = self.ContextState.contextIdx
return self.ContextState.GetCurrentContext().render(item)
return self.ContextState.GetCurrentContext().Render(item)
}
func (self *ContextState[T]) GetContextTitles() []string {
return lo.Map(self.GetContexts(), func(context ContextConfig[T], _ int) string {
return context.title
return context.Title
})
}
func (self *ContextState[T]) GetCurrentContextKey(item T) string {
return self.GetContextCacheKey(item) + "-" + self.GetCurrentContext().key
return self.GetContextCacheKey(item) + "-" + self.GetCurrentContext().Key
}
func (self *ContextState[T]) GetCurrentContext() ContextConfig[T] {
@ -263,7 +222,7 @@ func (self *SideListPanel[T]) HandlePrevContext() error {
}
func (self *SideListPanel[T]) Refocus() {
self.gui.FocusY(self.SelectedIdx, self.List.Len(), self.view)
self.Gui.FocusY(self.SelectedIdx, self.List.Len(), self.View)
}
func (self *SideListPanel[T]) SetItems(items []T) {
@ -272,14 +231,14 @@ func (self *SideListPanel[T]) SetItems(items []T) {
}
func (self *SideListPanel[T]) FilterAndSort() {
filterString := self.gui.FilterString(self.view)
filterString := self.Gui.FilterString(self.View)
self.List.Filter(func(item T, index int) bool {
if self.Filter != nil && !self.Filter(item) {
return false
}
if lo.SomeBy(self.gui.IgnoreStrings(), func(ignore string) bool {
if lo.SomeBy(self.Gui.IgnoreStrings(), func(ignore string) bool {
return lo.SomeBy(self.GetDisplayStrings(item), func(searchString string) bool {
return strings.Contains(searchString, ignore)
})
@ -304,8 +263,8 @@ func (self *SideListPanel[T]) FilterAndSort() {
func (self *SideListPanel[T]) RerenderList() error {
self.FilterAndSort()
self.gui.Update(func() error {
self.view.Clear()
self.Gui.Update(func() error {
self.View.Clear()
table := lo.Map(self.List.GetItems(), func(item T, index int) []string {
return self.GetDisplayStrings(item)
})
@ -313,7 +272,7 @@ func (self *SideListPanel[T]) RerenderList() error {
if err != nil {
return err
}
fmt.Fprint(self.view, renderedTable)
fmt.Fprint(self.View, renderedTable)
if self.OnRerender != nil {
if err := self.OnRerender(); err != nil {
@ -321,7 +280,7 @@ func (self *SideListPanel[T]) RerenderList() error {
}
}
if self.view == self.gui.CurrentView() {
if self.View == self.Gui.CurrentView() {
return self.HandleSelect()
}
return nil

@ -8,6 +8,7 @@ import (
"github.com/fatih/color"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazydocker/pkg/commands"
"github.com/jesseduffield/lazydocker/pkg/gui/panels"
"github.com/jesseduffield/lazydocker/pkg/utils"
"github.com/jesseduffield/yaml"
)
@ -15,35 +16,35 @@ import (
// 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]{
ContextState: &ContextState[*commands.Project]{
GetContexts: func() []ContextConfig[*commands.Project] {
func (gui *Gui) getProjectPanel() *panels.SideListPanel[*commands.Project] {
return &panels.SideListPanel[*commands.Project]{
ContextState: &panels.ContextState[*commands.Project]{
GetContexts: func() []panels.ContextConfig[*commands.Project] {
if gui.DockerCommand.InDockerComposeProject {
return []ContextConfig[*commands.Project]{
return []panels.ContextConfig[*commands.Project]{
{
key: "logs",
title: gui.Tr.LogsTitle,
render: gui.renderAllLogs,
Key: "logs",
Title: gui.Tr.LogsTitle,
Render: gui.renderAllLogs,
},
{
key: "config",
title: gui.Tr.DockerComposeConfigTitle,
render: gui.renderDockerComposeConfig,
Key: "config",
Title: gui.Tr.DockerComposeConfigTitle,
Render: gui.renderDockerComposeConfig,
},
{
key: "credits",
title: gui.Tr.CreditsTitle,
render: gui.renderCredits,
Key: "credits",
Title: gui.Tr.CreditsTitle,
Render: gui.renderCredits,
},
}
}
return []ContextConfig[*commands.Project]{
return []panels.ContextConfig[*commands.Project]{
{
key: "credits",
title: gui.Tr.CreditsTitle,
render: gui.renderCredits,
Key: "credits",
Title: gui.Tr.CreditsTitle,
Render: gui.renderCredits,
},
}
},
@ -52,12 +53,12 @@ func (gui *Gui) getProjectPanel() *SideListPanel[*commands.Project] {
},
},
ListPanel: ListPanel[*commands.Project]{
List: NewFilteredList[*commands.Project](),
view: gui.Views.Project,
ListPanel: panels.ListPanel[*commands.Project]{
List: panels.NewFilteredList[*commands.Project](),
View: gui.Views.Project,
},
NoItemsMessage: "",
gui: gui.intoInterface(),
Gui: gui.intoInterface(),
Sort: func(a *commands.Project, b *commands.Project) bool {
return false

@ -8,39 +8,40 @@ import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazydocker/pkg/commands"
"github.com/jesseduffield/lazydocker/pkg/config"
"github.com/jesseduffield/lazydocker/pkg/gui/panels"
"github.com/jesseduffield/lazydocker/pkg/utils"
"github.com/samber/lo"
)
func (gui *Gui) getServicesPanel() *SideListPanel[*commands.Service] {
return &SideListPanel[*commands.Service]{
ContextState: &ContextState[*commands.Service]{
GetContexts: func() []ContextConfig[*commands.Service] {
return []ContextConfig[*commands.Service]{
func (gui *Gui) getServicesPanel() *panels.SideListPanel[*commands.Service] {
return &panels.SideListPanel[*commands.Service]{
ContextState: &panels.ContextState[*commands.Service]{
GetContexts: func() []panels.ContextConfig[*commands.Service] {
return []panels.ContextConfig[*commands.Service]{
{
key: "logs",
title: gui.Tr.LogsTitle,
render: gui.renderServiceLogs,
Key: "logs",
Title: gui.Tr.LogsTitle,
Render: gui.renderServiceLogs,
},
{
key: "stats",
title: gui.Tr.StatsTitle,
render: gui.renderServiceStats,
Key: "stats",
Title: gui.Tr.StatsTitle,
Render: gui.renderServiceStats,
},
{
key: "container-env",
title: gui.Tr.ContainerEnvTitle,
render: gui.renderServiceContainerEnv,
Key: "container-env",
Title: gui.Tr.ContainerEnvTitle,
Render: gui.renderServiceContainerEnv,
},
{
key: "container-config",
title: gui.Tr.ContainerConfigTitle,
render: gui.renderServiceContainerConfig,
Key: "container-config",
Title: gui.Tr.ContainerConfigTitle,
Render: gui.renderServiceContainerConfig,
},
{
key: "top",
title: gui.Tr.TopTitle,
render: gui.renderServiceTop,
Key: "top",
Title: gui.Tr.TopTitle,
Render: gui.renderServiceTop,
},
}
},
@ -51,13 +52,12 @@ func (gui *Gui) getServicesPanel() *SideListPanel[*commands.Service] {
return "services-" + service.ID + "-" + service.Container.ID + "-" + service.Container.Container.State
},
},
ListPanel: ListPanel[*commands.Service]{
List: NewFilteredList[*commands.Service](),
view: gui.Views.Services,
ListPanel: panels.ListPanel[*commands.Service]{
List: panels.NewFilteredList[*commands.Service](),
View: gui.Views.Services,
},
// TODO: i18n
NoItemsMessage: "no service selected",
gui: gui.intoInterface(),
NoItemsMessage: gui.Tr.NoServices,
Gui: gui.intoInterface(),
// 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 {

@ -6,6 +6,7 @@ import (
"strings"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazydocker/pkg/gui/panels"
"github.com/jesseduffield/lazydocker/pkg/utils"
"github.com/samber/lo"
"github.com/spkg/bom"
@ -329,11 +330,11 @@ func (gui *Gui) CurrentView() *gocui.View {
return gui.g.CurrentView()
}
func (gui *Gui) currentSidePanel() (ISideListPanel, bool) {
func (gui *Gui) currentSidePanel() (panels.ISideListPanel, bool) {
viewName := gui.currentViewName()
for _, sidePanel := range gui.allSidePanels() {
if sidePanel.View().Name() == viewName {
if sidePanel.GetView().Name() == viewName {
return sidePanel, true
}
}
@ -342,11 +343,11 @@ func (gui *Gui) currentSidePanel() (ISideListPanel, bool) {
}
// returns the current list panel. If no list panel is focused, returns false.
func (gui *Gui) currentListPanel() (ISideListPanel, bool) {
func (gui *Gui) currentListPanel() (panels.ISideListPanel, bool) {
viewName := gui.currentViewName()
for _, sidePanel := range gui.allListPanels() {
if sidePanel.View().Name() == viewName {
if sidePanel.GetView().Name() == viewName {
return sidePanel, true
}
}
@ -354,8 +355,8 @@ func (gui *Gui) currentListPanel() (ISideListPanel, bool) {
return nil, false
}
func (gui *Gui) allSidePanels() []ISideListPanel {
return []ISideListPanel{
func (gui *Gui) allSidePanels() []panels.ISideListPanel {
return []panels.ISideListPanel{
gui.Panels.Projects,
gui.Panels.Services,
gui.Panels.Containers,
@ -364,6 +365,6 @@ func (gui *Gui) allSidePanels() []ISideListPanel {
}
}
func (gui *Gui) allListPanels() []ISideListPanel {
func (gui *Gui) allListPanels() []panels.ISideListPanel {
return append(gui.allSidePanels(), gui.Panels.Menu)
}

@ -7,19 +7,20 @@ import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazydocker/pkg/commands"
"github.com/jesseduffield/lazydocker/pkg/config"
"github.com/jesseduffield/lazydocker/pkg/gui/panels"
"github.com/jesseduffield/lazydocker/pkg/utils"
"github.com/samber/lo"
)
func (gui *Gui) getVolumesPanel() *SideListPanel[*commands.Volume] {
return &SideListPanel[*commands.Volume]{
ContextState: &ContextState[*commands.Volume]{
GetContexts: func() []ContextConfig[*commands.Volume] {
return []ContextConfig[*commands.Volume]{
func (gui *Gui) getVolumesPanel() *panels.SideListPanel[*commands.Volume] {
return &panels.SideListPanel[*commands.Volume]{
ContextState: &panels.ContextState[*commands.Volume]{
GetContexts: func() []panels.ContextConfig[*commands.Volume] {
return []panels.ContextConfig[*commands.Volume]{
{
key: "config",
title: gui.Tr.ConfigTitle,
render: gui.renderVolumeConfig,
Key: "config",
Title: gui.Tr.ConfigTitle,
Render: gui.renderVolumeConfig,
},
}
},
@ -27,12 +28,12 @@ func (gui *Gui) getVolumesPanel() *SideListPanel[*commands.Volume] {
return "volumes-" + volume.Name
},
},
ListPanel: ListPanel[*commands.Volume]{
List: NewFilteredList[*commands.Volume](),
view: gui.Views.Volumes,
ListPanel: panels.ListPanel[*commands.Volume]{
List: panels.NewFilteredList[*commands.Volume](),
View: gui.Views.Volumes,
},
NoItemsMessage: gui.Tr.NoVolumes,
gui: gui.intoInterface(),
Gui: gui.intoInterface(),
// we're sorting these volumes based on whether they have labels defined,
// because those are the ones you typically care about.
// Within that, we also sort them alphabetically

@ -76,6 +76,7 @@ type TranslationSet struct {
NoContainer string
NoImages string
NoVolumes string
NoServices string
RemoveImage string
RemoveVolume string
RemoveWithoutPrune string
@ -225,6 +226,7 @@ func englishSet() TranslationSet {
NoContainer: "No container",
NoImages: "No images",
NoVolumes: "No volumes",
NoServices: "No services",
ConfirmQuit: "Are you sure you want to quit?",
ConfirmUpProject: "Are you sure you want to 'up' your docker compose project?",

Loading…
Cancel
Save