mirror of
https://github.com/jesseduffield/lazydocker.git
synced 2026-07-25 08:31:03 +00:00
convert images panel to use new struct
This commit is contained in:
parent
e46b908006
commit
b80c8edcd0
9 changed files with 55 additions and 231 deletions
|
|
@ -59,14 +59,10 @@ type Gui struct {
|
||||||
Tr *i18n.TranslationSet
|
Tr *i18n.TranslationSet
|
||||||
Errors SentinelErrors
|
Errors SentinelErrors
|
||||||
statusManager *statusManager
|
statusManager *statusManager
|
||||||
waitForIntro sync.WaitGroup
|
|
||||||
T *tasks.TaskManager
|
T *tasks.TaskManager
|
||||||
ErrorChan chan error
|
ErrorChan chan error
|
||||||
CyclableViews []string
|
CyclableViews []string
|
||||||
Views Views
|
Views Views
|
||||||
// returns true if our views have been created and assigned to gui.Views.
|
|
||||||
// Views are setup only once, upon application start.
|
|
||||||
ViewsSetup bool
|
|
||||||
|
|
||||||
// if we've suspended the gui (e.g. because we've switched to a subprocess)
|
// if we've suspended the gui (e.g. because we've switched to a subprocess)
|
||||||
// we typically want to pause some things that are running like background
|
// we typically want to pause some things that are running like background
|
||||||
|
|
@ -111,11 +107,6 @@ type mainPanelState struct {
|
||||||
ObjectKey string
|
ObjectKey string
|
||||||
}
|
}
|
||||||
|
|
||||||
type imagePanelState struct {
|
|
||||||
SelectedLine int
|
|
||||||
ContextIndex int // for specifying if you are looking at logs/stats/config/etc
|
|
||||||
}
|
|
||||||
|
|
||||||
type volumePanelState struct {
|
type volumePanelState struct {
|
||||||
SelectedLine int
|
SelectedLine int
|
||||||
ContextIndex int
|
ContextIndex int
|
||||||
|
|
@ -126,7 +117,6 @@ type panelStates struct {
|
||||||
Containers *containerPanelState
|
Containers *containerPanelState
|
||||||
Menu *menuPanelState
|
Menu *menuPanelState
|
||||||
Main *mainPanelState
|
Main *mainPanelState
|
||||||
Images *imagePanelState
|
|
||||||
Volumes *volumePanelState
|
Volumes *volumePanelState
|
||||||
Project *projectState
|
Project *projectState
|
||||||
}
|
}
|
||||||
|
|
@ -180,7 +170,6 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand
|
||||||
Panels: &panelStates{
|
Panels: &panelStates{
|
||||||
Services: &servicePanelState{SelectedLine: -1, ContextIndex: 0},
|
Services: &servicePanelState{SelectedLine: -1, ContextIndex: 0},
|
||||||
Containers: &containerPanelState{SelectedLine: -1, ContextIndex: 0},
|
Containers: &containerPanelState{SelectedLine: -1, ContextIndex: 0},
|
||||||
Images: &imagePanelState{SelectedLine: -1, ContextIndex: 0},
|
|
||||||
Volumes: &volumePanelState{SelectedLine: -1, ContextIndex: 0},
|
Volumes: &volumePanelState{SelectedLine: -1, ContextIndex: 0},
|
||||||
Menu: &menuPanelState{SelectedLine: 0},
|
Menu: &menuPanelState{SelectedLine: 0},
|
||||||
Main: &mainPanelState{
|
Main: &mainPanelState{
|
||||||
|
|
@ -216,11 +205,6 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand
|
||||||
CyclableViews: cyclableViews,
|
CyclableViews: cyclableViews,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: see if we can avoid the circular dependency
|
|
||||||
gui.Panels = Panels{
|
|
||||||
Images: gui.getImagePanel(),
|
|
||||||
}
|
|
||||||
|
|
||||||
gui.GenerateSentinelErrors()
|
gui.GenerateSentinelErrors()
|
||||||
|
|
||||||
return gui, nil
|
return gui, nil
|
||||||
|
|
@ -273,8 +257,6 @@ func (gui *Gui) Run() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
gui.waitForIntro.Add(1)
|
|
||||||
|
|
||||||
throttledRefresh := throttle.ThrottleFunc(time.Millisecond*50, true, gui.refresh)
|
throttledRefresh := throttle.ThrottleFunc(time.Millisecond*50, true, gui.refresh)
|
||||||
defer throttledRefresh.Stop()
|
defer throttledRefresh.Stop()
|
||||||
|
|
||||||
|
|
@ -285,7 +267,6 @@ func (gui *Gui) Run() error {
|
||||||
go gui.DockerCommand.MonitorContainerStats(ctx)
|
go gui.DockerCommand.MonitorContainerStats(ctx)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
gui.waitForIntro.Wait()
|
|
||||||
throttledRefresh.Trigger()
|
throttledRefresh.Trigger()
|
||||||
|
|
||||||
gui.goEvery(time.Millisecond*30, gui.reRenderMain)
|
gui.goEvery(time.Millisecond*30, gui.reRenderMain)
|
||||||
|
|
@ -310,10 +291,31 @@ func (gui *Gui) Run() error {
|
||||||
|
|
||||||
g.SetManager(gocui.ManagerFunc(gui.layout), gocui.ManagerFunc(gui.getFocusLayout()))
|
g.SetManager(gocui.ManagerFunc(gui.layout), gocui.ManagerFunc(gui.getFocusLayout()))
|
||||||
|
|
||||||
|
if err := gui.createAllViews(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: see if we can avoid the circular dependency
|
||||||
|
gui.Panels = Panels{
|
||||||
|
Images: gui.getImagePanel(),
|
||||||
|
}
|
||||||
|
|
||||||
if err = gui.keybindings(g); err != nil {
|
if err = gui.keybindings(g); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if gui.g.CurrentView() == nil {
|
||||||
|
viewName := gui.initiallyFocusedViewName()
|
||||||
|
view, err := gui.g.View(viewName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := gui.switchFocus(view); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = g.MainLoop()
|
err = g.MainLoop()
|
||||||
if err == gocui.ErrQuit {
|
if err == gocui.ErrQuit {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -7,73 +7,12 @@ import (
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
"github.com/go-errors/errors"
|
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
"github.com/jesseduffield/lazydocker/pkg/commands"
|
"github.com/jesseduffield/lazydocker/pkg/commands"
|
||||||
"github.com/jesseduffield/lazydocker/pkg/config"
|
"github.com/jesseduffield/lazydocker/pkg/config"
|
||||||
"github.com/jesseduffield/lazydocker/pkg/utils"
|
"github.com/jesseduffield/lazydocker/pkg/utils"
|
||||||
"github.com/samber/lo"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// list panel functions
|
|
||||||
|
|
||||||
func (gui *Gui) getImageContexts() []string {
|
|
||||||
return []string{"config"}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) getImageContextTitles() []string {
|
|
||||||
return []string{gui.Tr.ConfigTitle}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) getSelectedImage() (*commands.Image, error) {
|
|
||||||
selectedLine := gui.State.Panels.Images.SelectedLine
|
|
||||||
if selectedLine == -1 {
|
|
||||||
return &commands.Image{}, gui.Errors.ErrNoImages
|
|
||||||
}
|
|
||||||
|
|
||||||
return gui.State.Lists.Images.Get(selectedLine), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) handleImagesClick(g *gocui.Gui, v *gocui.View) error {
|
|
||||||
itemCount := gui.State.Lists.Images.Len()
|
|
||||||
handleSelect := gui.handleImageSelect
|
|
||||||
selectedLine := &gui.State.Panels.Images.SelectedLine
|
|
||||||
|
|
||||||
return gui.handleClick(v, itemCount, selectedLine, handleSelect)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) handleImageSelect(g *gocui.Gui, v *gocui.View) error {
|
|
||||||
image, err := gui.getSelectedImage()
|
|
||||||
if err != nil {
|
|
||||||
if err != gui.Errors.ErrNoImages {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return gui.renderStringMain(gui.Tr.NoImages)
|
|
||||||
}
|
|
||||||
|
|
||||||
gui.focusY(gui.State.Panels.Images.SelectedLine, gui.State.Lists.Images.Len(), v)
|
|
||||||
|
|
||||||
key := "images-" + image.ID + "-" + gui.getImageContexts()[gui.State.Panels.Images.ContextIndex]
|
|
||||||
if !gui.shouldRefresh(key) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
mainView := gui.getMainView()
|
|
||||||
mainView.Tabs = gui.getImageContextTitles()
|
|
||||||
mainView.TabIndex = gui.State.Panels.Images.ContextIndex
|
|
||||||
|
|
||||||
switch gui.getImageContexts()[gui.State.Panels.Images.ContextIndex] {
|
|
||||||
case "config":
|
|
||||||
if err := gui.renderImageConfig(image); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return errors.New("Unknown context for Images panel")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) renderImageConfig(image *commands.Image) error {
|
func (gui *Gui) renderImageConfig(image *commands.Image) error {
|
||||||
return gui.T.NewTask(func(stop chan struct{}) {
|
return gui.T.NewTask(func(stop chan struct{}) {
|
||||||
padding := 10
|
padding := 10
|
||||||
|
|
@ -104,63 +43,7 @@ func (gui *Gui) reloadImages() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return gui.rerenderImages()
|
return gui.Panels.Images.RerenderList()
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) rerenderImages() error {
|
|
||||||
filterString := gui.filterString(gui.Views.Images)
|
|
||||||
|
|
||||||
gui.State.Lists.Images.Filter(func(image *commands.Image, index int) bool {
|
|
||||||
if lo.SomeBy(gui.Config.UserConfig.Ignore, func(ignore string) bool {
|
|
||||||
return strings.Contains(image.Name, ignore)
|
|
||||||
}) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if filterString != "" {
|
|
||||||
return strings.Contains(image.Name, filterString)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
noneLabel := "<none>"
|
|
||||||
|
|
||||||
gui.State.Lists.Images.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
|
|
||||||
})
|
|
||||||
|
|
||||||
if gui.State.Lists.Images.Len() > 0 && gui.State.Panels.Images.SelectedLine == -1 {
|
|
||||||
gui.State.Panels.Images.SelectedLine = 0
|
|
||||||
}
|
|
||||||
if gui.State.Lists.Images.Len()-1 < gui.State.Panels.Images.SelectedLine {
|
|
||||||
gui.State.Panels.Images.SelectedLine = gui.State.Lists.Images.Len() - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
gui.g.Update(func(g *gocui.Gui) error {
|
|
||||||
gui.Views.Images.Clear()
|
|
||||||
isFocused := gui.g.CurrentView() == gui.Views.Images
|
|
||||||
list, err := utils.RenderList(gui.State.Lists.Images.GetItems(), utils.IsFocused(isFocused))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Fprint(gui.Views.Images, list)
|
|
||||||
|
|
||||||
if gui.Views.Images == g.CurrentView() {
|
|
||||||
return gui.handleImageSelect(g, gui.Views.Images)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) refreshStateImages() error {
|
func (gui *Gui) refreshStateImages() error {
|
||||||
|
|
@ -170,7 +53,7 @@ func (gui *Gui) refreshStateImages() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: think about also re-filtering/sorting
|
// TODO: think about also re-filtering/sorting
|
||||||
gui.State.Lists.Images.SetItems(images)
|
gui.Panels.Images.list.SetItems(images)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -188,54 +71,6 @@ func (gui *Gui) FilterString(view *gocui.View) string {
|
||||||
return gui.filterString(view)
|
return gui.filterString(view)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleImagesNextLine(g *gocui.Gui, v *gocui.View) error {
|
|
||||||
if gui.popupPanelFocused() || gui.g.CurrentView() != v {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
panelState := gui.State.Panels.Images
|
|
||||||
gui.changeSelectedLine(&panelState.SelectedLine, gui.State.Lists.Images.Len(), false)
|
|
||||||
|
|
||||||
return gui.handleImageSelect(gui.g, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) handleImagesPrevLine(g *gocui.Gui, v *gocui.View) error {
|
|
||||||
if gui.popupPanelFocused() || gui.g.CurrentView() != v {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
panelState := gui.State.Panels.Images
|
|
||||||
gui.changeSelectedLine(&panelState.SelectedLine, gui.State.Lists.Images.Len(), true)
|
|
||||||
|
|
||||||
return gui.handleImageSelect(gui.g, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) handleImagesNextContext(g *gocui.Gui, v *gocui.View) error {
|
|
||||||
contexts := gui.getImageContexts()
|
|
||||||
if gui.State.Panels.Images.ContextIndex >= len(contexts)-1 {
|
|
||||||
gui.State.Panels.Images.ContextIndex = 0
|
|
||||||
} else {
|
|
||||||
gui.State.Panels.Images.ContextIndex++
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = gui.handleImageSelect(gui.g, v)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) handleImagesPrevContext(g *gocui.Gui, v *gocui.View) error {
|
|
||||||
contexts := gui.getImageContexts()
|
|
||||||
if gui.State.Panels.Images.ContextIndex <= 0 {
|
|
||||||
gui.State.Panels.Images.ContextIndex = len(contexts) - 1
|
|
||||||
} else {
|
|
||||||
gui.State.Panels.Images.ContextIndex--
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = gui.handleImageSelect(gui.g, v)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type removeImageOption struct {
|
type removeImageOption struct {
|
||||||
description string
|
description string
|
||||||
command string
|
command string
|
||||||
|
|
@ -249,12 +84,12 @@ func (r *removeImageOption) GetDisplayStrings(isFocused bool) []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleImagesRemoveMenu(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handleImagesRemoveMenu(g *gocui.Gui, v *gocui.View) error {
|
||||||
Image, err := gui.getSelectedImage()
|
image, err := gui.Panels.Images.GetSelectedItem()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
shortSha := Image.ID[7:17]
|
shortSha := image.ID[7:17]
|
||||||
|
|
||||||
// TODO: have a way of toggling in a menu instead of showing each permutation as a separate menu item
|
// TODO: have a way of toggling in a menu instead of showing each permutation as a separate menu item
|
||||||
options := []*removeImageOption{
|
options := []*removeImageOption{
|
||||||
|
|
@ -293,7 +128,7 @@ func (gui *Gui) handleImagesRemoveMenu(g *gocui.Gui, v *gocui.View) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
configOptions := options[index].configOptions
|
configOptions := options[index].configOptions
|
||||||
if cerr := Image.Remove(configOptions); cerr != nil {
|
if cerr := image.Remove(configOptions); cerr != nil {
|
||||||
return gui.createErrorPanel(cerr.Error())
|
return gui.createErrorPanel(cerr.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -316,7 +151,7 @@ func (gui *Gui) handlePruneImages() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleImagesCustomCommand(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handleImagesCustomCommand(g *gocui.Gui, v *gocui.View) error {
|
||||||
image, err := gui.getSelectedImage()
|
image, err := gui.Panels.Images.GetSelectedItem()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -412,14 +412,14 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||||
ViewName: "images",
|
ViewName: "images",
|
||||||
Key: '[',
|
Key: '[',
|
||||||
Modifier: gocui.ModNone,
|
Modifier: gocui.ModNone,
|
||||||
Handler: gui.handleImagesPrevContext,
|
Handler: wrappedHandler(gui.Panels.Images.OnPrevContext),
|
||||||
Description: gui.Tr.PreviousContext,
|
Description: gui.Tr.PreviousContext,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "images",
|
ViewName: "images",
|
||||||
Key: ']',
|
Key: ']',
|
||||||
Modifier: gocui.ModNone,
|
Modifier: gocui.ModNone,
|
||||||
Handler: gui.handleImagesNextContext,
|
Handler: wrappedHandler(gui.Panels.Images.OnNextContext),
|
||||||
Description: gui.Tr.NextContext,
|
Description: gui.Tr.NextContext,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -59,14 +59,6 @@ func (gui *Gui) onFocus(v *gocui.View) {
|
||||||
|
|
||||||
// layout is called for every screen re-render e.g. when the screen is resized
|
// layout is called for every screen re-render e.g. when the screen is resized
|
||||||
func (gui *Gui) layout(g *gocui.Gui) error {
|
func (gui *Gui) layout(g *gocui.Gui) error {
|
||||||
if !gui.ViewsSetup {
|
|
||||||
if err := gui.createAllViews(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
gui.ViewsSetup = true
|
|
||||||
}
|
|
||||||
|
|
||||||
g.Highlight = true
|
g.Highlight = true
|
||||||
width, height := g.Size()
|
width, height := g.Size()
|
||||||
|
|
||||||
|
|
@ -116,18 +108,6 @@ func (gui *Gui) layout(g *gocui.Gui) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if gui.g.CurrentView() == nil {
|
|
||||||
viewName := gui.initiallyFocusedViewName()
|
|
||||||
view, err := gui.g.View(viewName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := gui.switchFocus(view); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// here is a good place log some stuff
|
// here is a good place log some stuff
|
||||||
// if you download humanlog and do tail -f development.log | humanlog
|
// if you download humanlog and do tail -f development.log | humanlog
|
||||||
// this will let you see these branches as prettified json
|
// this will let you see these branches as prettified json
|
||||||
|
|
@ -147,7 +127,6 @@ func (gui *Gui) focusPointInView(view *gocui.View) {
|
||||||
|
|
||||||
listViews := map[string]listViewState{
|
listViews := map[string]listViewState{
|
||||||
"containers": {selectedLine: gui.State.Panels.Containers.SelectedLine, lineCount: len(gui.DockerCommand.DisplayContainers)},
|
"containers": {selectedLine: gui.State.Panels.Containers.SelectedLine, lineCount: len(gui.DockerCommand.DisplayContainers)},
|
||||||
"images": {selectedLine: gui.State.Panels.Images.SelectedLine, lineCount: gui.State.Lists.Images.Len()},
|
|
||||||
"volumes": {selectedLine: gui.State.Panels.Volumes.SelectedLine, lineCount: len(gui.DockerCommand.Volumes)},
|
"volumes": {selectedLine: gui.State.Panels.Volumes.SelectedLine, lineCount: len(gui.DockerCommand.Volumes)},
|
||||||
"services": {selectedLine: gui.State.Panels.Services.SelectedLine, lineCount: len(gui.DockerCommand.Services)},
|
"services": {selectedLine: gui.State.Panels.Services.SelectedLine, lineCount: len(gui.DockerCommand.Services)},
|
||||||
"menu": {selectedLine: gui.State.Panels.Menu.SelectedLine, lineCount: gui.State.MenuItemCount},
|
"menu": {selectedLine: gui.State.Panels.Menu.SelectedLine, lineCount: gui.State.MenuItemCount},
|
||||||
|
|
@ -156,6 +135,11 @@ func (gui *Gui) focusPointInView(view *gocui.View) {
|
||||||
if state, ok := listViews[view.Name()]; ok {
|
if state, ok := listViews[view.Name()]; ok {
|
||||||
gui.focusY(state.selectedLine, state.lineCount, view)
|
gui.focusY(state.selectedLine, state.lineCount, view)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch view.Name() {
|
||||||
|
case "images":
|
||||||
|
gui.Panels.Images.Refocus()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) prepareView(viewName string) (*gocui.View, error) {
|
func (gui *Gui) prepareView(viewName string) (*gocui.View, error) {
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ type ListPanel[T comparable] struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ListPanel[T]) setSelectedLineIdx(value int) {
|
func (self *ListPanel[T]) setSelectedLineIdx(value int) {
|
||||||
clampedValue := -1
|
clampedValue := 0
|
||||||
if self.list.Len() > 0 {
|
if self.list.Len() > 0 {
|
||||||
clampedValue = utils.Clamp(value, 0, self.list.Len()-1)
|
clampedValue = utils.Clamp(value, 0, self.list.Len()-1)
|
||||||
}
|
}
|
||||||
|
|
@ -57,6 +57,7 @@ type SideListPanel[T comparable] struct {
|
||||||
|
|
||||||
// returns strings that can be filtered on
|
// returns strings that can be filtered on
|
||||||
getSearchStrings func(item T) []string
|
getSearchStrings func(item T) []string
|
||||||
|
getId func(item T) string
|
||||||
|
|
||||||
sort func(a, b T) bool
|
sort func(a, b T) bool
|
||||||
}
|
}
|
||||||
|
|
@ -101,7 +102,7 @@ func (gui *Gui) getImagePanel() *SideListPanel[*commands.Image] {
|
||||||
list: NewFilteredList[*commands.Image](),
|
list: NewFilteredList[*commands.Image](),
|
||||||
view: gui.Views.Images,
|
view: gui.Views.Images,
|
||||||
},
|
},
|
||||||
contextIdx: -1, // TODO: see if this should be 0
|
contextIdx: 0,
|
||||||
noItemsMessge: gui.Tr.NoImages,
|
noItemsMessge: gui.Tr.NoImages,
|
||||||
gui: gui.intoInterface(),
|
gui: gui.intoInterface(),
|
||||||
contexts: []ContextConfig[*commands.Image]{
|
contexts: []ContextConfig[*commands.Image]{
|
||||||
|
|
@ -116,6 +117,9 @@ func (gui *Gui) getImagePanel() *SideListPanel[*commands.Image] {
|
||||||
getSearchStrings: func(image *commands.Image) []string {
|
getSearchStrings: func(image *commands.Image) []string {
|
||||||
return []string{image.Name, image.Tag}
|
return []string{image.Name, image.Tag}
|
||||||
},
|
},
|
||||||
|
getId: func(image *commands.Image) string {
|
||||||
|
return image.ID
|
||||||
|
},
|
||||||
sort: func(a *commands.Image, b *commands.Image) bool {
|
sort: func(a *commands.Image, b *commands.Image) bool {
|
||||||
if a.Name == noneLabel && b.Name != noneLabel {
|
if a.Name == noneLabel && b.Name != noneLabel {
|
||||||
return false
|
return false
|
||||||
|
|
@ -148,9 +152,9 @@ func (self *SideListPanel[T]) HandleSelect() error {
|
||||||
return self.gui.RenderStringMain(self.noItemsMessge)
|
return self.gui.RenderStringMain(self.noItemsMessge)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.gui.FocusY(self.selectedIdx, self.list.Len(), self.view)
|
self.Refocus()
|
||||||
|
|
||||||
key := self.contextKeyPrefix + "-" + self.contexts[self.contextIdx].key
|
key := self.contextKeyPrefix + "-" + self.getId(item) + "-" + self.contexts[self.contextIdx].key
|
||||||
if !self.gui.ShouldRefresh(key) {
|
if !self.gui.ShouldRefresh(key) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -172,10 +176,6 @@ func (self *SideListPanel[T]) GetContextTitles() []string {
|
||||||
func (self *SideListPanel[T]) GetSelectedItem() (T, error) {
|
func (self *SideListPanel[T]) GetSelectedItem() (T, error) {
|
||||||
var zero T
|
var zero T
|
||||||
|
|
||||||
if self.selectedIdx == -1 {
|
|
||||||
return zero, errors.New(self.noItemsMessge)
|
|
||||||
}
|
|
||||||
|
|
||||||
item, ok := self.list.TryGet(self.selectedIdx)
|
item, ok := self.list.TryGet(self.selectedIdx)
|
||||||
if !ok {
|
if !ok {
|
||||||
// could probably have a better error here
|
// could probably have a better error here
|
||||||
|
|
@ -221,6 +221,10 @@ func (self *SideListPanel[T]) OnPrevContext() error {
|
||||||
return self.HandleSelect()
|
return self.HandleSelect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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]) RerenderList() error {
|
||||||
filterString := self.gui.FilterString(self.view)
|
filterString := self.gui.FilterString(self.view)
|
||||||
|
|
||||||
|
|
@ -245,9 +249,6 @@ func (self *SideListPanel[T]) RerenderList() error {
|
||||||
self.list.Sort(self.sort)
|
self.list.Sort(self.sort)
|
||||||
|
|
||||||
// TODO: use clamp?
|
// TODO: use clamp?
|
||||||
if self.list.Len() > 0 && self.selectedIdx == -1 {
|
|
||||||
self.selectedIdx = 0
|
|
||||||
}
|
|
||||||
if self.list.Len()-1 < self.selectedIdx {
|
if self.list.Len()-1 < self.selectedIdx {
|
||||||
self.selectedIdx = self.list.Len() - 1
|
self.selectedIdx = self.list.Len() - 1
|
||||||
}
|
}
|
||||||
|
|
@ -269,3 +270,7 @@ func (self *SideListPanel[T]) RerenderList() error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *SideListPanel[T]) SetContextIndex(index int) {
|
||||||
|
self.contextIdx = index
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -94,8 +94,8 @@ func (gui *Gui) onMainTabClick(tabIndex int) error {
|
||||||
gui.State.Panels.Containers.ContextIndex = tabIndex
|
gui.State.Panels.Containers.ContextIndex = tabIndex
|
||||||
return gui.handleContainerSelect(gui.g, gui.getContainersView())
|
return gui.handleContainerSelect(gui.g, gui.getContainersView())
|
||||||
case "images":
|
case "images":
|
||||||
gui.State.Panels.Images.ContextIndex = tabIndex
|
gui.Panels.Images.SetContextIndex(tabIndex)
|
||||||
return gui.handleImageSelect(gui.g, gui.getImagesView())
|
return gui.Panels.Images.HandleSelect()
|
||||||
case "volumes":
|
case "volumes":
|
||||||
gui.State.Panels.Volumes.ContextIndex = tabIndex
|
gui.State.Panels.Volumes.ContextIndex = tabIndex
|
||||||
return gui.handleVolumeSelect(gui.g, gui.getVolumesView())
|
return gui.handleVolumeSelect(gui.g, gui.getVolumesView())
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ func (gui *Gui) handleOpenSearch(view *gocui.View) error {
|
||||||
func (gui *Gui) onNewSearchString(value string) error {
|
func (gui *Gui) onNewSearchString(value string) error {
|
||||||
// need to refresh the right list panel.
|
// need to refresh the right list panel.
|
||||||
gui.State.Searching.searchString = value
|
gui.State.Searching.searchString = value
|
||||||
return gui.rerenderImages()
|
return gui.Panels.Images.RerenderList()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) wrapEditor(f func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool) func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool {
|
func (gui *Gui) wrapEditor(f func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool) func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool {
|
||||||
|
|
@ -46,7 +46,7 @@ func (gui *Gui) clearSearch() error {
|
||||||
gui.State.Searching.view = nil
|
gui.State.Searching.view = nil
|
||||||
gui.Views.Search.ClearTextArea()
|
gui.Views.Search.ClearTextArea()
|
||||||
|
|
||||||
return gui.rerenderImages()
|
return gui.Panels.Images.RerenderList()
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns to the list view with the filter still applied
|
// returns to the list view with the filter still applied
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ func (gui *Gui) newLineFocused(v *gocui.View) error {
|
||||||
case "containers":
|
case "containers":
|
||||||
return gui.handleContainerSelect(gui.g, v)
|
return gui.handleContainerSelect(gui.g, v)
|
||||||
case "images":
|
case "images":
|
||||||
return gui.handleImageSelect(gui.g, v)
|
return gui.Panels.Images.HandleSelect()
|
||||||
case "volumes":
|
case "volumes":
|
||||||
return gui.handleVolumeSelect(gui.g, v)
|
return gui.handleVolumeSelect(gui.g, v)
|
||||||
case "confirmation":
|
case "confirmation":
|
||||||
|
|
|
||||||
|
|
@ -139,8 +139,6 @@ func (gui *Gui) createAllViews() error {
|
||||||
gui.Views.Search.Frame = false
|
gui.Views.Search.Frame = false
|
||||||
gui.Views.Search.Editor = gocui.EditorFunc(gui.wrapEditor(gocui.SimpleEditor))
|
gui.Views.Search.Editor = gocui.EditorFunc(gui.wrapEditor(gocui.SimpleEditor))
|
||||||
|
|
||||||
gui.waitForIntro.Done()
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue