refactor side list panel some more

This commit is contained in:
Jesse Duffield 2022-10-31 12:25:45 -07:00
parent 02a03ed18d
commit d6ad538426
10 changed files with 104 additions and 96 deletions

View file

@ -100,18 +100,6 @@ func getBindingSections(mApp *app.App) []*bindingSection {
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
}

View file

@ -32,8 +32,8 @@ func (gui *Gui) getContainersPanel() *panels.SideListPanel[*commands.Container]
return &panels.SideListPanel[*commands.Container]{
ContextState: &panels.ContextState[*commands.Container]{
GetContexts: func() []panels.ContextConfig[*commands.Container] {
return []panels.ContextConfig[*commands.Container]{
GetMainTabs: func() []panels.MainTab[*commands.Container] {
return []panels.MainTab[*commands.Container]{
{
Key: "logs",
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
},
},

View file

@ -22,8 +22,8 @@ func (gui *Gui) getImagesPanel() *panels.SideListPanel[*commands.Image] {
return &panels.SideListPanel[*commands.Image]{
ContextState: &panels.ContextState[*commands.Image]{
GetContexts: func() []panels.ContextConfig[*commands.Image] {
return []panels.ContextConfig[*commands.Image]{
GetMainTabs: func() []panels.MainTab[*commands.Image] {
return []panels.MainTab[*commands.Image]{
{
Key: "config",
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
},
},

View file

@ -532,14 +532,14 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
ViewName: panel.GetView().Name(),
Key: '[',
Modifier: gocui.ModNone,
Handler: wrappedHandler(panel.HandlePrevContext),
Handler: wrappedHandler(panel.HandlePrevMainTab),
Description: gui.Tr.PreviousContext,
},
&Binding{
ViewName: panel.GetView().Name(),
Key: ']',
Modifier: gocui.ModNone,
Handler: wrappedHandler(panel.HandleNextContext),
Handler: wrappedHandler(panel.HandleNextMainTab),
Description: gui.Tr.NextContext,
},
)

View file

@ -89,7 +89,7 @@ func (gui *Gui) onMainTabClick(tabIndex int) error {
return nil
}
currentSidePanel.SetContextIndex(tabIndex)
currentSidePanel.SetMainTabIndex(tabIndex)
return currentSidePanel.HandleSelect()
}

View 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
}

View file

@ -11,7 +11,7 @@ import (
)
type ISideListPanel interface {
SetContextIndex(int)
SetMainTabIndex(int)
HandleSelect() error
GetView() *gocui.View
Refocus()
@ -21,8 +21,8 @@ type ISideListPanel interface {
HandleNextLine() error
HandlePrevLine() error
HandleClick() error
HandlePrevContext() error
HandleNextContext() error
HandlePrevMainTab() error
HandleNextMainTab() error
}
// 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
// returns the columns that we render to the view in a table formats
GetDisplayStrings func(T) []string
// function to be called after re-rendering list. Can be nil
@ -57,25 +58,11 @@ type SideListPanel[T comparable] struct {
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 {
HandleClick(v *gocui.View, itemCount int, selectedLine *int, handleSelect func() error) error
RenderStringMain(message string) error
FocusY(selectedLine int, itemCount int, view *gocui.View)
ShouldRefresh(key string) bool
ShouldRefresh(contextKey string) bool
GetMainView() *gocui.View
// TODO: replace with IsCurrentView() bool
CurrentView() *gocui.View
@ -137,24 +124,10 @@ func (self *SideListPanel[T]) renderContext(item T) error {
}
mainView := self.Gui.GetMainView()
mainView.Tabs = self.ContextState.GetContextTitles()
mainView.TabIndex = self.ContextState.contextIdx
mainView.Tabs = self.ContextState.GetMainTabTitles()
mainView.TabIndex = self.ContextState.mainTabIdx
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
})
}
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]
return self.ContextState.GetCurrentMainTab().Render(item)
}
func (self *SideListPanel[T]) GetSelectedItem() (T, error) {
@ -181,42 +154,22 @@ func (self *SideListPanel[T]) HandlePrevLine() error {
return self.HandleSelect()
}
func (self *ContextState[T]) HandleNextContext() {
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 {
func (self *SideListPanel[T]) HandleNextMainTab() error {
if self.ContextState == nil {
return nil
}
self.ContextState.HandleNextContext()
self.ContextState.HandleNextMainTab()
return self.HandleSelect()
}
func (self *SideListPanel[T]) HandlePrevContext() error {
func (self *SideListPanel[T]) HandlePrevMainTab() error {
if self.ContextState == nil {
return nil
}
self.ContextState.HandlePrevContext()
self.ContextState.HandlePrevMainTab()
return self.HandleSelect()
}
@ -289,16 +242,12 @@ func (self *SideListPanel[T]) RerenderList() error {
return nil
}
func (self *SideListPanel[T]) SetContextIndex(index int) {
func (self *SideListPanel[T]) SetMainTabIndex(index int) {
if self.ContextState == nil {
return
}
self.ContextState.SetContextIndex(index)
}
func (self *ContextState[T]) SetContextIndex(index int) {
self.contextIdx = index
self.ContextState.SetMainTabIndex(index)
}
func (self *SideListPanel[T]) IsFilterDisabled() bool {

View file

@ -20,9 +20,9 @@ import (
func (gui *Gui) getProjectPanel() *panels.SideListPanel[*commands.Project] {
return &panels.SideListPanel[*commands.Project]{
ContextState: &panels.ContextState[*commands.Project]{
GetContexts: func() []panels.ContextConfig[*commands.Project] {
GetMainTabs: func() []panels.MainTab[*commands.Project] {
if gui.DockerCommand.InDockerComposeProject {
return []panels.ContextConfig[*commands.Project]{
return []panels.MainTab[*commands.Project]{
{
Key: "logs",
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",
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
},
},

View file

@ -18,8 +18,8 @@ import (
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]{
GetMainTabs: func() []panels.MainTab[*commands.Service] {
return []panels.MainTab[*commands.Service]{
{
Key: "logs",
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 {
return "services-" + service.ID
}

View file

@ -17,8 +17,8 @@ import (
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]{
GetMainTabs: func() []panels.MainTab[*commands.Volume] {
return []panels.MainTab[*commands.Volume]{
{
Key: "config",
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
},
},