convert volumes panel to use new struct

pull/392/head
Jesse Duffield 2 years ago
parent 79a58c8d48
commit a4b4fee868

@ -44,7 +44,6 @@ type DockerCommand struct {
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
Volumes []*Volume
Closers []io.Closer
}

@ -2,13 +2,10 @@ package commands
import (
"context"
"sort"
"strings"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/client"
"github.com/samber/lo"
"github.com/sirupsen/logrus"
)
@ -28,29 +25,16 @@ func (v *Volume) GetDisplayStrings(isFocused bool) []string {
}
// RefreshVolumes gets the volumes and stores them
func (c *DockerCommand) RefreshVolumes() error {
func (c *DockerCommand) RefreshVolumes() ([]*Volume, error) {
result, err := c.Client.VolumeList(context.Background(), filters.Args{})
if err != nil {
return err
return nil, err
}
volumes := result.Volumes
ownVolumes := make([]*Volume, len(volumes))
// 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
sort.Slice(volumes, func(i, j int) bool {
if len(volumes[i].Labels) == 0 && len(volumes[j].Labels) > 0 {
return false
}
if len(volumes[i].Labels) > 0 && len(volumes[j].Labels) == 0 {
return true
}
return volumes[i].Name < volumes[j].Name
})
for i, volume := range volumes {
ownVolumes[i] = &Volume{
Name: volume.Name,
@ -62,15 +46,7 @@ func (c *DockerCommand) RefreshVolumes() error {
}
}
ownVolumes = lo.Filter(ownVolumes, func(volume *Volume, _ int) bool {
return !lo.SomeBy(c.Config.UserConfig.Ignore, func(ignore string) bool {
return strings.Contains(volume.Name, ignore)
})
})
c.Volumes = ownVolumes
return nil
return ownVolumes, nil
}
// PruneVolumes prunes volumes

@ -26,7 +26,6 @@ var OverlappingEdges = false
// by calling functions. The less of these, the better
type SentinelErrors struct {
ErrNoContainers error
ErrNoImages error
ErrNoVolumes error
}
@ -43,7 +42,6 @@ type SentinelErrors struct {
func (gui *Gui) GenerateSentinelErrors() {
gui.Errors = SentinelErrors{
ErrNoContainers: errors.New(gui.Tr.NoContainers),
ErrNoImages: errors.New(gui.Tr.NoImages),
ErrNoVolumes: errors.New(gui.Tr.NoVolumes),
}
}
@ -77,6 +75,7 @@ type Gui struct {
type Panels struct {
Images *SideListPanel[*commands.Image]
Services *SideListPanel[*commands.Service]
Volumes *SideListPanel[*commands.Volume]
}
type Mutexes struct {
@ -103,16 +102,10 @@ type mainPanelState struct {
ObjectKey string
}
type volumePanelState struct {
SelectedLine int
ContextIndex int
}
type panelStates struct {
Containers *containerPanelState
Menu *menuPanelState
Main *mainPanelState
Volumes *volumePanelState
Project *projectState
}
@ -164,7 +157,6 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand
Platform: *oSCommand.Platform,
Panels: &panelStates{
Containers: &containerPanelState{SelectedLine: -1, ContextIndex: 0},
Volumes: &volumePanelState{SelectedLine: -1, ContextIndex: 0},
Menu: &menuPanelState{SelectedLine: 0},
Main: &mainPanelState{
ObjectKey: "",
@ -284,6 +276,7 @@ func (gui *Gui) Run() error {
gui.Panels = Panels{
Images: gui.getImagesPanel(),
Services: gui.getServicesPanel(),
Volumes: gui.getVolumesPanel(),
}
if err = gui.keybindings(g); err != nil {
@ -332,7 +325,7 @@ func (gui *Gui) refresh() {
}
}()
go func() {
if err := gui.refreshVolumes(); err != nil {
if err := gui.reloadVolumes(); err != nil {
gui.Log.Error(err)
}
}()

@ -93,7 +93,6 @@ func (gui *Gui) refreshStateImages() error {
return err
}
// TODO: think about also re-filtering/sorting
gui.Panels.Images.SetItems(images)
return nil

@ -454,14 +454,14 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
ViewName: "volumes",
Key: '[',
Modifier: gocui.ModNone,
Handler: gui.handleVolumesPrevContext,
Handler: wrappedHandler(gui.Panels.Volumes.OnPrevContext),
Description: gui.Tr.PreviousContext,
},
{
ViewName: "volumes",
Key: ']',
Modifier: gocui.ModNone,
Handler: gui.handleVolumesNextContext,
Handler: wrappedHandler(gui.Panels.Volumes.OnNextContext),
Description: gui.Tr.NextContext,
},
{
@ -587,7 +587,7 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
"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},
"volumes": {onKeyUpPress: wrappedHandler(gui.Panels.Volumes.OnPrevLine), onKeyDownPress: wrappedHandler(gui.Panels.Volumes.OnNextLine), onClick: wrappedHandler(gui.Panels.Volumes.OnClick)},
"main": {onKeyUpPress: gui.scrollUpMain, onKeyDownPress: gui.scrollDownMain, onClick: gui.handleMainClick},
}

@ -127,7 +127,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)},
"menu": {selectedLine: gui.State.Panels.Menu.SelectedLine, lineCount: gui.State.MenuItemCount},
}
@ -140,6 +139,8 @@ func (gui *Gui) focusPointInView(view *gocui.View) {
gui.Panels.Images.Refocus()
case "services":
gui.Panels.Services.Refocus()
case "volumes":
gui.Panels.Volumes.Refocus()
}
}

@ -97,8 +97,8 @@ func (gui *Gui) onMainTabClick(tabIndex int) error {
gui.Panels.Images.SetContextIndex(tabIndex)
return gui.Panels.Images.HandleSelect()
case "volumes":
gui.State.Panels.Volumes.ContextIndex = tabIndex
return gui.handleVolumeSelect(gui.g, gui.getVolumesView())
gui.Panels.Volumes.SetContextIndex(tabIndex)
return gui.Panels.Volumes.HandleSelect()
}
return nil

@ -83,7 +83,7 @@ func (gui *Gui) newLineFocused(v *gocui.View) error {
case "images":
return gui.Panels.Images.HandleSelect()
case "volumes":
return gui.handleVolumeSelect(gui.g, v)
return gui.Panels.Volumes.HandleSelect()
case "confirmation":
return nil
case "main":

@ -4,74 +4,54 @@ import (
"fmt"
"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) getVolumeContexts() []string {
return []string{"config"}
}
func (gui *Gui) getVolumeContextTitles() []string {
return []string{gui.Tr.ConfigTitle}
}
func (gui *Gui) getSelectedVolume() (*commands.Volume, error) {
selectedLine := gui.State.Panels.Volumes.SelectedLine
if selectedLine == -1 {
return nil, gui.Errors.ErrNoVolumes
}
return gui.DockerCommand.Volumes[selectedLine], nil
}
func (gui *Gui) handleVolumesClick(g *gocui.Gui, v *gocui.View) error {
itemCount := len(gui.DockerCommand.Volumes)
handleSelect := gui.handleVolumeSelect
selectedLine := &gui.State.Panels.Volumes.SelectedLine
return gui.handleClick(v, itemCount, selectedLine, handleSelect)
}
func (gui *Gui) handleVolumeSelect(g *gocui.Gui, v *gocui.View) error {
volume, err := gui.getSelectedVolume()
if err != nil {
if err != gui.Errors.ErrNoVolumes {
return err
}
return gui.renderStringMain(gui.Tr.NoVolumes)
}
gui.focusY(gui.State.Panels.Volumes.SelectedLine, len(gui.DockerCommand.Volumes), v)
key := "volumes-" + volume.Name + "-" + gui.getVolumeContexts()[gui.State.Panels.Volumes.ContextIndex]
if !gui.shouldRefresh(key) {
return nil
}
mainView := gui.getMainView()
mainView.Tabs = gui.getVolumeContextTitles()
mainView.TabIndex = gui.State.Panels.Volumes.ContextIndex
switch gui.getVolumeContexts()[gui.State.Panels.Volumes.ContextIndex] {
case "config":
if err := gui.renderVolumeConfig(mainView, volume); err != nil {
return err
}
default:
return errors.New("Unknown context for Volumes panel")
func (gui *Gui) getVolumesPanel() *SideListPanel[*commands.Volume] {
return &SideListPanel[*commands.Volume]{
contextKeyPrefix: "volumes",
ListPanel: ListPanel[*commands.Volume]{
list: NewFilteredList[*commands.Volume](),
view: gui.Views.Volumes,
},
contextIdx: 0,
noItemsMessge: gui.Tr.NoVolumes,
gui: gui.intoInterface(),
contexts: []ContextConfig[*commands.Volume]{
{
key: "config",
title: gui.Tr.ConfigTitle,
render: gui.renderVolumeConfig,
},
},
getSearchStrings: func(volume *commands.Volume) []string {
// TODO: think about more things to search on
return []string{volume.Name}
},
getContextCacheKey: func(volume *commands.Volume) string {
return volume.Name
},
// 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
sort: func(a *commands.Volume, b *commands.Volume) bool {
if len(a.Volume.Labels) == 0 && len(b.Volume.Labels) > 0 {
return false
}
if len(a.Volume.Labels) > 0 && len(b.Volume.Labels) == 0 {
return true
}
return a.Name < b.Name
},
}
return nil
}
func (gui *Gui) renderVolumeConfig(mainView *gocui.View, volume *commands.Volume) error {
func (gui *Gui) renderVolumeConfig(volume *commands.Volume) error {
return gui.T.NewTask(func(stop chan struct{}) {
mainView := gui.Views.Main
mainView.Autoscroll = false
mainView.Wrap = gui.Config.UserConfig.Gui.WrapMainPanel
@ -103,85 +83,21 @@ func (gui *Gui) renderVolumeConfig(mainView *gocui.View, volume *commands.Volume
})
}
func (gui *Gui) refreshVolumes() error {
volumesView := gui.getVolumesView()
if volumesView == nil {
// if the volumesView hasn't been instantiated yet we just return
return nil
}
if err := gui.DockerCommand.RefreshVolumes(); err != nil {
func (gui *Gui) reloadVolumes() error {
if err := gui.refreshStateVolumes(); err != nil {
return err
}
if len(gui.DockerCommand.Volumes) > 0 && gui.State.Panels.Volumes.SelectedLine == -1 {
gui.State.Panels.Volumes.SelectedLine = 0
}
if len(gui.DockerCommand.Volumes)-1 < gui.State.Panels.Volumes.SelectedLine {
gui.State.Panels.Volumes.SelectedLine = len(gui.DockerCommand.Volumes) - 1
}
gui.g.Update(func(g *gocui.Gui) error {
volumesView.Clear()
isFocused := gui.g.CurrentView().Name() == "volumes"
list, err := utils.RenderList(gui.DockerCommand.Volumes, utils.IsFocused(isFocused))
if err != nil {
return err
}
fmt.Fprint(volumesView, list)
if volumesView == g.CurrentView() {
return gui.handleVolumeSelect(g, volumesView)
}
return nil
})
return nil
return gui.Panels.Volumes.RerenderList()
}
func (gui *Gui) handleVolumesNextLine(g *gocui.Gui, v *gocui.View) error {
if gui.popupPanelFocused() || gui.g.CurrentView() != v {
return nil
}
panelState := gui.State.Panels.Volumes
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.DockerCommand.Volumes), false)
return gui.handleVolumeSelect(gui.g, v)
}
func (gui *Gui) handleVolumesPrevLine(g *gocui.Gui, v *gocui.View) error {
if gui.popupPanelFocused() || gui.g.CurrentView() != v {
return nil
}
panelState := gui.State.Panels.Volumes
gui.changeSelectedLine(&panelState.SelectedLine, len(gui.DockerCommand.Volumes), true)
return gui.handleVolumeSelect(gui.g, v)
}
func (gui *Gui) handleVolumesNextContext(g *gocui.Gui, v *gocui.View) error {
contexts := gui.getVolumeContexts()
if gui.State.Panels.Volumes.ContextIndex >= len(contexts)-1 {
gui.State.Panels.Volumes.ContextIndex = 0
} else {
gui.State.Panels.Volumes.ContextIndex++
}
_ = gui.handleVolumeSelect(gui.g, v)
return nil
}
func (gui *Gui) handleVolumesPrevContext(g *gocui.Gui, v *gocui.View) error {
contexts := gui.getVolumeContexts()
if gui.State.Panels.Volumes.ContextIndex <= 0 {
gui.State.Panels.Volumes.ContextIndex = len(contexts) - 1
} else {
gui.State.Panels.Volumes.ContextIndex--
func (gui *Gui) refreshStateVolumes() error {
volumes, err := gui.DockerCommand.RefreshVolumes()
if err != nil {
return err
}
_ = gui.handleVolumeSelect(gui.g, v)
gui.Panels.Volumes.SetItems(volumes)
return nil
}
@ -199,7 +115,7 @@ func (r *removeVolumeOption) GetDisplayStrings(isFocused bool) []string {
}
func (gui *Gui) handleVolumesRemoveMenu(g *gocui.Gui, v *gocui.View) error {
volume, err := gui.getSelectedVolume()
volume, err := gui.Panels.Volumes.GetSelectedItem()
if err != nil {
return nil
}
@ -251,7 +167,7 @@ func (gui *Gui) handlePruneVolumes() error {
}
func (gui *Gui) handleVolumesCustomCommand(g *gocui.Gui, v *gocui.View) error {
volume, err := gui.getSelectedVolume()
volume, err := gui.Panels.Volumes.GetSelectedItem()
if err != nil {
return nil
}

Loading…
Cancel
Save