mirror of
https://github.com/jesseduffield/lazydocker.git
synced 2026-07-25 08:31:03 +00:00
refactor side list panel some more
This commit is contained in:
parent
02a03ed18d
commit
d6ad538426
10 changed files with 104 additions and 96 deletions
|
|
@ -100,18 +100,6 @@ func getBindingSections(mApp *app.App) []*bindingSection {
|
||||||
bindingSections = addBinding(titleMap[viewName], bindingSections, binding)
|
bindingSections = addBinding(titleMap[viewName], bindingSections, binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
// for view, contexts := range mApp.Gui.GetContextMap() {
|
|
||||||
// for contextName, contextBindings := range contexts {
|
|
||||||
// translatedView := localisedTitle(mApp, view)
|
|
||||||
// translatedContextName := localisedTitle(mApp, contextName)
|
|
||||||
// title := fmt.Sprintf("%s (%s)", translatedView, translatedContextName)
|
|
||||||
|
|
||||||
// for _, binding := range contextBindings {
|
|
||||||
// bindingSections = addBinding(title, bindingSections, binding)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
return bindingSections
|
return bindingSections
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,8 @@ func (gui *Gui) getContainersPanel() *panels.SideListPanel[*commands.Container]
|
||||||
|
|
||||||
return &panels.SideListPanel[*commands.Container]{
|
return &panels.SideListPanel[*commands.Container]{
|
||||||
ContextState: &panels.ContextState[*commands.Container]{
|
ContextState: &panels.ContextState[*commands.Container]{
|
||||||
GetContexts: func() []panels.ContextConfig[*commands.Container] {
|
GetMainTabs: func() []panels.MainTab[*commands.Container] {
|
||||||
return []panels.ContextConfig[*commands.Container]{
|
return []panels.MainTab[*commands.Container]{
|
||||||
{
|
{
|
||||||
Key: "logs",
|
Key: "logs",
|
||||||
Title: gui.Tr.LogsTitle,
|
Title: gui.Tr.LogsTitle,
|
||||||
|
|
@ -61,7 +61,12 @@ func (gui *Gui) getContainersPanel() *panels.SideListPanel[*commands.Container]
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
GetContextCacheKey: func(container *commands.Container) string {
|
GetItemContextCacheKey: func(container *commands.Container) string {
|
||||||
|
// Including the container state in the cache key so that if the container
|
||||||
|
// restarts we re-read the logs. In the past we've had some glitchiness
|
||||||
|
// where a container restarts but the new logs don't get read.
|
||||||
|
// Note that this might be jarring if we have a lot of logs and the container
|
||||||
|
// restarts a lot, so let's keep an eye on it.
|
||||||
return "containers-" + container.ID + "-" + container.Container.State
|
return "containers-" + container.ID + "-" + container.Container.State
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ func (gui *Gui) getImagesPanel() *panels.SideListPanel[*commands.Image] {
|
||||||
|
|
||||||
return &panels.SideListPanel[*commands.Image]{
|
return &panels.SideListPanel[*commands.Image]{
|
||||||
ContextState: &panels.ContextState[*commands.Image]{
|
ContextState: &panels.ContextState[*commands.Image]{
|
||||||
GetContexts: func() []panels.ContextConfig[*commands.Image] {
|
GetMainTabs: func() []panels.MainTab[*commands.Image] {
|
||||||
return []panels.ContextConfig[*commands.Image]{
|
return []panels.MainTab[*commands.Image]{
|
||||||
{
|
{
|
||||||
Key: "config",
|
Key: "config",
|
||||||
Title: gui.Tr.ConfigTitle,
|
Title: gui.Tr.ConfigTitle,
|
||||||
|
|
@ -33,7 +33,7 @@ func (gui *Gui) getImagesPanel() *panels.SideListPanel[*commands.Image] {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
GetContextCacheKey: func(image *commands.Image) string {
|
GetItemContextCacheKey: func(image *commands.Image) string {
|
||||||
return "images-" + image.ID
|
return "images-" + image.ID
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -532,14 +532,14 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||||
ViewName: panel.GetView().Name(),
|
ViewName: panel.GetView().Name(),
|
||||||
Key: '[',
|
Key: '[',
|
||||||
Modifier: gocui.ModNone,
|
Modifier: gocui.ModNone,
|
||||||
Handler: wrappedHandler(panel.HandlePrevContext),
|
Handler: wrappedHandler(panel.HandlePrevMainTab),
|
||||||
Description: gui.Tr.PreviousContext,
|
Description: gui.Tr.PreviousContext,
|
||||||
},
|
},
|
||||||
&Binding{
|
&Binding{
|
||||||
ViewName: panel.GetView().Name(),
|
ViewName: panel.GetView().Name(),
|
||||||
Key: ']',
|
Key: ']',
|
||||||
Modifier: gocui.ModNone,
|
Modifier: gocui.ModNone,
|
||||||
Handler: wrappedHandler(panel.HandleNextContext),
|
Handler: wrappedHandler(panel.HandleNextMainTab),
|
||||||
Description: gui.Tr.NextContext,
|
Description: gui.Tr.NextContext,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ func (gui *Gui) onMainTabClick(tabIndex int) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
currentSidePanel.SetContextIndex(tabIndex)
|
currentSidePanel.SetMainTabIndex(tabIndex)
|
||||||
return currentSidePanel.HandleSelect()
|
return currentSidePanel.HandleSelect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
66
pkg/gui/panels/context_state.go
Normal file
66
pkg/gui/panels/context_state.go
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
package panels
|
||||||
|
|
||||||
|
import "github.com/samber/lo"
|
||||||
|
|
||||||
|
// A 'context' generally corresponds to an item and the tab in the main panel that we're
|
||||||
|
// displaying. So if we switch to a new item, or change the tab in the panel panel
|
||||||
|
// for the current item, we end up with a new context. When we have a new context,
|
||||||
|
// we render new content to the main panel.
|
||||||
|
type ContextState[T any] struct {
|
||||||
|
// index of the currently selected tab in the main view.
|
||||||
|
mainTabIdx int
|
||||||
|
// this function returns the tabs that we can display for an item (the tabs
|
||||||
|
// are shown on the main view)
|
||||||
|
GetMainTabs func() []MainTab[T]
|
||||||
|
// This tells us whether we need to re-render to the main panel for a given item.
|
||||||
|
// This should include the item's ID and if you want to invalidate the cache for
|
||||||
|
// some other reason, you can add that to the key as well (e.g. the container's state).
|
||||||
|
GetItemContextCacheKey func(item T) string
|
||||||
|
}
|
||||||
|
|
||||||
|
type MainTab[T any] struct {
|
||||||
|
// key used as part of the context cache key
|
||||||
|
Key string
|
||||||
|
// title of the tab, rendered in the main view
|
||||||
|
Title string
|
||||||
|
// function to render the content of the tab
|
||||||
|
Render func(item T) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ContextState[T]) GetMainTabTitles() []string {
|
||||||
|
return lo.Map(self.GetMainTabs(), func(tab MainTab[T], _ int) string {
|
||||||
|
return tab.Title
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ContextState[T]) GetCurrentContextKey(item T) string {
|
||||||
|
return self.GetItemContextCacheKey(item) + "-" + self.GetCurrentMainTab().Key
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ContextState[T]) GetCurrentMainTab() MainTab[T] {
|
||||||
|
return self.GetMainTabs()[self.mainTabIdx]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ContextState[T]) HandleNextMainTab() {
|
||||||
|
tabs := self.GetMainTabs()
|
||||||
|
|
||||||
|
if len(tabs) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.mainTabIdx = (self.mainTabIdx + 1) % len(tabs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ContextState[T]) HandlePrevMainTab() {
|
||||||
|
tabs := self.GetMainTabs()
|
||||||
|
|
||||||
|
if len(tabs) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.mainTabIdx = (self.mainTabIdx - 1 + len(tabs)) % len(tabs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ContextState[T]) SetMainTabIndex(index int) {
|
||||||
|
self.mainTabIdx = index
|
||||||
|
}
|
||||||
|
|
@ -11,7 +11,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type ISideListPanel interface {
|
type ISideListPanel interface {
|
||||||
SetContextIndex(int)
|
SetMainTabIndex(int)
|
||||||
HandleSelect() error
|
HandleSelect() error
|
||||||
GetView() *gocui.View
|
GetView() *gocui.View
|
||||||
Refocus()
|
Refocus()
|
||||||
|
|
@ -21,8 +21,8 @@ type ISideListPanel interface {
|
||||||
HandleNextLine() error
|
HandleNextLine() error
|
||||||
HandlePrevLine() error
|
HandlePrevLine() error
|
||||||
HandleClick() error
|
HandleClick() error
|
||||||
HandlePrevContext() error
|
HandlePrevMainTab() error
|
||||||
HandleNextContext() error
|
HandleNextMainTab() error
|
||||||
}
|
}
|
||||||
|
|
||||||
// list panel at the side of the screen that renders content to the main panel
|
// list panel at the side of the screen that renders content to the main panel
|
||||||
|
|
@ -43,6 +43,7 @@ type SideListPanel[T comparable] struct {
|
||||||
|
|
||||||
OnClick func(T) error
|
OnClick func(T) error
|
||||||
|
|
||||||
|
// returns the columns that we render to the view in a table formats
|
||||||
GetDisplayStrings func(T) []string
|
GetDisplayStrings func(T) []string
|
||||||
|
|
||||||
// function to be called after re-rendering list. Can be nil
|
// function to be called after re-rendering list. Can be nil
|
||||||
|
|
@ -57,25 +58,11 @@ type SideListPanel[T comparable] struct {
|
||||||
|
|
||||||
var _ ISideListPanel = &SideListPanel[int]{}
|
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
|
|
||||||
}
|
|
||||||
|
|
||||||
type IGui interface {
|
type IGui interface {
|
||||||
HandleClick(v *gocui.View, itemCount int, selectedLine *int, handleSelect func() error) error
|
HandleClick(v *gocui.View, itemCount int, selectedLine *int, handleSelect func() error) error
|
||||||
RenderStringMain(message string) error
|
RenderStringMain(message string) error
|
||||||
FocusY(selectedLine int, itemCount int, view *gocui.View)
|
FocusY(selectedLine int, itemCount int, view *gocui.View)
|
||||||
ShouldRefresh(key string) bool
|
ShouldRefresh(contextKey string) bool
|
||||||
GetMainView() *gocui.View
|
GetMainView() *gocui.View
|
||||||
// TODO: replace with IsCurrentView() bool
|
// TODO: replace with IsCurrentView() bool
|
||||||
CurrentView() *gocui.View
|
CurrentView() *gocui.View
|
||||||
|
|
@ -137,24 +124,10 @@ func (self *SideListPanel[T]) renderContext(item T) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
mainView := self.Gui.GetMainView()
|
mainView := self.Gui.GetMainView()
|
||||||
mainView.Tabs = self.ContextState.GetContextTitles()
|
mainView.Tabs = self.ContextState.GetMainTabTitles()
|
||||||
mainView.TabIndex = self.ContextState.contextIdx
|
mainView.TabIndex = self.ContextState.mainTabIdx
|
||||||
|
|
||||||
return self.ContextState.GetCurrentContext().Render(item)
|
return self.ContextState.GetCurrentMainTab().Render(item)
|
||||||
}
|
|
||||||
|
|
||||||
func (self *ContextState[T]) GetContextTitles() []string {
|
|
||||||
return lo.Map(self.GetContexts(), func(context ContextConfig[T], _ int) string {
|
|
||||||
return context.Title
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *ContextState[T]) GetCurrentContextKey(item T) string {
|
|
||||||
return self.GetContextCacheKey(item) + "-" + self.GetCurrentContext().Key
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *ContextState[T]) GetCurrentContext() ContextConfig[T] {
|
|
||||||
return self.GetContexts()[self.contextIdx]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SideListPanel[T]) GetSelectedItem() (T, error) {
|
func (self *SideListPanel[T]) GetSelectedItem() (T, error) {
|
||||||
|
|
@ -181,42 +154,22 @@ func (self *SideListPanel[T]) HandlePrevLine() error {
|
||||||
return self.HandleSelect()
|
return self.HandleSelect()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ContextState[T]) HandleNextContext() {
|
func (self *SideListPanel[T]) HandleNextMainTab() error {
|
||||||
contexts := self.GetContexts()
|
|
||||||
|
|
||||||
if len(contexts) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
self.contextIdx = (self.contextIdx + 1) % len(contexts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *ContextState[T]) HandlePrevContext() {
|
|
||||||
contexts := self.GetContexts()
|
|
||||||
|
|
||||||
if len(contexts) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
self.contextIdx = (self.contextIdx - 1 + len(contexts)) % len(contexts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *SideListPanel[T]) HandleNextContext() error {
|
|
||||||
if self.ContextState == nil {
|
if self.ContextState == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
self.ContextState.HandleNextContext()
|
self.ContextState.HandleNextMainTab()
|
||||||
|
|
||||||
return self.HandleSelect()
|
return self.HandleSelect()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SideListPanel[T]) HandlePrevContext() error {
|
func (self *SideListPanel[T]) HandlePrevMainTab() error {
|
||||||
if self.ContextState == nil {
|
if self.ContextState == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
self.ContextState.HandlePrevContext()
|
self.ContextState.HandlePrevMainTab()
|
||||||
|
|
||||||
return self.HandleSelect()
|
return self.HandleSelect()
|
||||||
}
|
}
|
||||||
|
|
@ -289,16 +242,12 @@ func (self *SideListPanel[T]) RerenderList() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SideListPanel[T]) SetContextIndex(index int) {
|
func (self *SideListPanel[T]) SetMainTabIndex(index int) {
|
||||||
if self.ContextState == nil {
|
if self.ContextState == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
self.ContextState.SetContextIndex(index)
|
self.ContextState.SetMainTabIndex(index)
|
||||||
}
|
|
||||||
|
|
||||||
func (self *ContextState[T]) SetContextIndex(index int) {
|
|
||||||
self.contextIdx = index
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SideListPanel[T]) IsFilterDisabled() bool {
|
func (self *SideListPanel[T]) IsFilterDisabled() bool {
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,9 @@ import (
|
||||||
func (gui *Gui) getProjectPanel() *panels.SideListPanel[*commands.Project] {
|
func (gui *Gui) getProjectPanel() *panels.SideListPanel[*commands.Project] {
|
||||||
return &panels.SideListPanel[*commands.Project]{
|
return &panels.SideListPanel[*commands.Project]{
|
||||||
ContextState: &panels.ContextState[*commands.Project]{
|
ContextState: &panels.ContextState[*commands.Project]{
|
||||||
GetContexts: func() []panels.ContextConfig[*commands.Project] {
|
GetMainTabs: func() []panels.MainTab[*commands.Project] {
|
||||||
if gui.DockerCommand.InDockerComposeProject {
|
if gui.DockerCommand.InDockerComposeProject {
|
||||||
return []panels.ContextConfig[*commands.Project]{
|
return []panels.MainTab[*commands.Project]{
|
||||||
{
|
{
|
||||||
Key: "logs",
|
Key: "logs",
|
||||||
Title: gui.Tr.LogsTitle,
|
Title: gui.Tr.LogsTitle,
|
||||||
|
|
@ -41,7 +41,7 @@ func (gui *Gui) getProjectPanel() *panels.SideListPanel[*commands.Project] {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return []panels.ContextConfig[*commands.Project]{
|
return []panels.MainTab[*commands.Project]{
|
||||||
{
|
{
|
||||||
Key: "credits",
|
Key: "credits",
|
||||||
Title: gui.Tr.CreditsTitle,
|
Title: gui.Tr.CreditsTitle,
|
||||||
|
|
@ -49,7 +49,7 @@ func (gui *Gui) getProjectPanel() *panels.SideListPanel[*commands.Project] {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
GetContextCacheKey: func(project *commands.Project) string {
|
GetItemContextCacheKey: func(project *commands.Project) string {
|
||||||
return "projects-" + project.Name
|
return "projects-" + project.Name
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ import (
|
||||||
func (gui *Gui) getServicesPanel() *panels.SideListPanel[*commands.Service] {
|
func (gui *Gui) getServicesPanel() *panels.SideListPanel[*commands.Service] {
|
||||||
return &panels.SideListPanel[*commands.Service]{
|
return &panels.SideListPanel[*commands.Service]{
|
||||||
ContextState: &panels.ContextState[*commands.Service]{
|
ContextState: &panels.ContextState[*commands.Service]{
|
||||||
GetContexts: func() []panels.ContextConfig[*commands.Service] {
|
GetMainTabs: func() []panels.MainTab[*commands.Service] {
|
||||||
return []panels.ContextConfig[*commands.Service]{
|
return []panels.MainTab[*commands.Service]{
|
||||||
{
|
{
|
||||||
Key: "logs",
|
Key: "logs",
|
||||||
Title: gui.Tr.LogsTitle,
|
Title: gui.Tr.LogsTitle,
|
||||||
|
|
@ -47,7 +47,7 @@ func (gui *Gui) getServicesPanel() *panels.SideListPanel[*commands.Service] {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
GetContextCacheKey: func(service *commands.Service) string {
|
GetItemContextCacheKey: func(service *commands.Service) string {
|
||||||
if service.Container == nil {
|
if service.Container == nil {
|
||||||
return "services-" + service.ID
|
return "services-" + service.ID
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ import (
|
||||||
func (gui *Gui) getVolumesPanel() *panels.SideListPanel[*commands.Volume] {
|
func (gui *Gui) getVolumesPanel() *panels.SideListPanel[*commands.Volume] {
|
||||||
return &panels.SideListPanel[*commands.Volume]{
|
return &panels.SideListPanel[*commands.Volume]{
|
||||||
ContextState: &panels.ContextState[*commands.Volume]{
|
ContextState: &panels.ContextState[*commands.Volume]{
|
||||||
GetContexts: func() []panels.ContextConfig[*commands.Volume] {
|
GetMainTabs: func() []panels.MainTab[*commands.Volume] {
|
||||||
return []panels.ContextConfig[*commands.Volume]{
|
return []panels.MainTab[*commands.Volume]{
|
||||||
{
|
{
|
||||||
Key: "config",
|
Key: "config",
|
||||||
Title: gui.Tr.ConfigTitle,
|
Title: gui.Tr.ConfigTitle,
|
||||||
|
|
@ -26,7 +26,7 @@ func (gui *Gui) getVolumesPanel() *panels.SideListPanel[*commands.Volume] {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
GetContextCacheKey: func(volume *commands.Volume) string {
|
GetItemContextCacheKey: func(volume *commands.Volume) string {
|
||||||
return "volumes-" + volume.Name
|
return "volumes-" + volume.Name
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue