mirror of
https://github.com/jesseduffield/lazydocker.git
synced 2026-07-25 08:31:03 +00:00
support bulk commands in each of the panels
This commit is contained in:
parent
c99bdaa5ff
commit
1f9f82601b
10 changed files with 265 additions and 70 deletions
|
|
@ -2,12 +2,14 @@ package commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/docker/docker/api/types/container"
|
"fmt"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types/container"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
|
|
@ -317,6 +319,7 @@ func (c *Container) GetColor() color.Attribute {
|
||||||
|
|
||||||
// Remove removes the container
|
// Remove removes the container
|
||||||
func (c *Container) Remove(options types.ContainerRemoveOptions) error {
|
func (c *Container) Remove(options types.ContainerRemoveOptions) error {
|
||||||
|
c.Log.Warn(fmt.Sprintf("removing container %s", c.Name))
|
||||||
if err := c.Client.ContainerRemove(context.Background(), c.ID, options); err != nil {
|
if err := c.Client.ContainerRemove(context.Background(), c.ID, options); err != nil {
|
||||||
if strings.Contains(err.Error(), "Stop the container before attempting removal or force remove") {
|
if strings.Contains(err.Error(), "Stop the container before attempting removal or force remove") {
|
||||||
return ComplexError{
|
return ComplexError{
|
||||||
|
|
@ -333,16 +336,20 @@ func (c *Container) Remove(options types.ContainerRemoveOptions) error {
|
||||||
|
|
||||||
// Stop stops the container
|
// Stop stops the container
|
||||||
func (c *Container) Stop() error {
|
func (c *Container) Stop() error {
|
||||||
|
c.Log.Warn(fmt.Sprintf("stopping container %s", c.Name))
|
||||||
return c.Client.ContainerStop(context.Background(), c.ID, nil)
|
return c.Client.ContainerStop(context.Background(), c.ID, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restart restarts the container
|
// Restart restarts the container
|
||||||
func (c *Container) Restart() error {
|
func (c *Container) Restart() error {
|
||||||
|
c.Log.Warn(fmt.Sprintf("restarting container %s", c.Name))
|
||||||
return c.Client.ContainerRestart(context.Background(), c.ID, nil)
|
return c.Client.ContainerRestart(context.Background(), c.ID, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attach attaches the container
|
// Attach attaches the container
|
||||||
func (c *Container) Attach() (*exec.Cmd, error) {
|
func (c *Container) Attach() (*exec.Cmd, error) {
|
||||||
|
c.Log.Warn(fmt.Sprintf("attaching to container %s", c.Name))
|
||||||
|
|
||||||
// verify that we can in fact attach to this container
|
// verify that we can in fact attach to this container
|
||||||
if !c.Details.Config.OpenStdin {
|
if !c.Details.Config.OpenStdin {
|
||||||
return nil, errors.New(c.Tr.UnattachableContainerError)
|
return nil, errors.New(c.Tr.UnattachableContainerError)
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,10 @@ type UserConfig struct {
|
||||||
// those are found in the commands package
|
// those are found in the commands package
|
||||||
CustomCommands CustomCommands `yaml:"customCommands,omitempty"`
|
CustomCommands CustomCommands `yaml:"customCommands,omitempty"`
|
||||||
|
|
||||||
|
// BulkCommands are commands that apply to all items in a panel e.g.
|
||||||
|
// killing all containers, stopping all services, or pruning all images
|
||||||
|
BulkCommands CustomCommands `yaml:"bulkCommands,omitempty"`
|
||||||
|
|
||||||
// OS determines what defaults are set for opening files and links
|
// OS determines what defaults are set for opening files and links
|
||||||
OS OSConfig `yaml:"oS,omitempty"`
|
OS OSConfig `yaml:"oS,omitempty"`
|
||||||
|
|
||||||
|
|
@ -259,10 +263,10 @@ type CustomCommands struct {
|
||||||
// Services contains the custom commands for services
|
// Services contains the custom commands for services
|
||||||
Services []CustomCommand `yaml:"services,omitempty"`
|
Services []CustomCommand `yaml:"services,omitempty"`
|
||||||
|
|
||||||
// Services contains the custom commands for services
|
// Images contains the custom commands for images
|
||||||
Images []CustomCommand `yaml:"images,omitempty"`
|
Images []CustomCommand `yaml:"images,omitempty"`
|
||||||
|
|
||||||
// Services contains the custom commands for services
|
// Volumes contains the custom commands for volumes
|
||||||
Volumes []CustomCommand `yaml:"volumes,omitempty"`
|
Volumes []CustomCommand `yaml:"volumes,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -288,6 +292,9 @@ type CustomCommand struct {
|
||||||
// field has no effect on customcommands under the 'communications' part of
|
// field has no effect on customcommands under the 'communications' part of
|
||||||
// the customCommand config.
|
// the customCommand config.
|
||||||
ServiceNames []string `yaml:"serviceNames"`
|
ServiceNames []string `yaml:"serviceNames"`
|
||||||
|
|
||||||
|
// InternalFunction is the name of a function inside lazydocker that we want to run, as opposed to a command-line command. This is only used internally and can't be configured by the user
|
||||||
|
InternalFunction func() error `yaml:"internalFunction"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDefaultConfig returns the application default configuration NOTE (to
|
// GetDefaultConfig returns the application default configuration NOTE (to
|
||||||
|
|
@ -344,6 +351,52 @@ func GetDefaultConfig() UserConfig {
|
||||||
Images: []CustomCommand{},
|
Images: []CustomCommand{},
|
||||||
Volumes: []CustomCommand{},
|
Volumes: []CustomCommand{},
|
||||||
},
|
},
|
||||||
|
BulkCommands: CustomCommands{
|
||||||
|
Services: []CustomCommand{
|
||||||
|
{
|
||||||
|
Name: "up",
|
||||||
|
Command: "{{ .DockerCompose }} up -d",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "up (attached)",
|
||||||
|
Command: "{{ .DockerCompose }} up",
|
||||||
|
Attach: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "stop",
|
||||||
|
Command: "{{ .DockerCompose }} stop",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "pull",
|
||||||
|
Command: "{{ .DockerCompose }} pull",
|
||||||
|
Attach: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "build",
|
||||||
|
Command: "{{ .DockerCompose }} build --parallel --force-rm",
|
||||||
|
Attach: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "down",
|
||||||
|
Command: "{{ .DockerCompose }} down",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "down with volumes",
|
||||||
|
Command: "{{ .DockerCompose }} down --volumes",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "down with images",
|
||||||
|
Command: "{{ .DockerCompose }} down --rmi all",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "down with volumes and images",
|
||||||
|
Command: "{{ .DockerCompose }} down --volumes --rmi all",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Containers: []CustomCommand{},
|
||||||
|
Images: []CustomCommand{},
|
||||||
|
Volumes: []CustomCommand{},
|
||||||
|
},
|
||||||
OS: GetPlatformDefaultConfig(),
|
OS: GetPlatformDefaultConfig(),
|
||||||
Update: UpdateConfig{
|
Update: UpdateConfig{
|
||||||
Method: "never",
|
Method: "never",
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/go-errors/errors"
|
"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/utils"
|
"github.com/jesseduffield/lazydocker/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -476,8 +477,8 @@ func (gui *Gui) handleContainerAttach(g *gocui.Gui, v *gocui.View) error {
|
||||||
return gui.Errors.ErrSubProcess
|
return gui.Errors.ErrSubProcess
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handlePruneContainers(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handlePruneContainers() error {
|
||||||
return gui.createConfirmationPanel(gui.g, v, gui.Tr.Confirm, gui.Tr.ConfirmPruneContainers, func(g *gocui.Gui, v *gocui.View) error {
|
return gui.createConfirmationPanel(gui.g, gui.getContainersView(), gui.Tr.Confirm, gui.Tr.ConfirmPruneContainers, func(g *gocui.Gui, v *gocui.View) error {
|
||||||
return gui.WithWaitingStatus(gui.Tr.PruningStatus, func() error {
|
return gui.WithWaitingStatus(gui.Tr.PruningStatus, func() error {
|
||||||
err := gui.DockerCommand.PruneContainers()
|
err := gui.DockerCommand.PruneContainers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -517,3 +518,51 @@ func (gui *Gui) handleContainersCustomCommand(g *gocui.Gui, v *gocui.View) error
|
||||||
|
|
||||||
return gui.createCustomCommandMenu(customCommands, commandObject)
|
return gui.createCustomCommandMenu(customCommands, commandObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleStopContainers() error {
|
||||||
|
return gui.createConfirmationPanel(gui.g, gui.getContainersView(), gui.Tr.Confirm, gui.Tr.ConfirmStopContainers, func(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
return gui.WithWaitingStatus(gui.Tr.StoppingStatus, func() error {
|
||||||
|
|
||||||
|
for _, container := range gui.DockerCommand.Containers {
|
||||||
|
_ = container.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleRemoveContainers() error {
|
||||||
|
return gui.createConfirmationPanel(gui.g, gui.getContainersView(), gui.Tr.Confirm, gui.Tr.ConfirmRemoveContainers, func(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
return gui.WithWaitingStatus(gui.Tr.RemovingStatus, func() error {
|
||||||
|
|
||||||
|
for _, container := range gui.DockerCommand.Containers {
|
||||||
|
_ = container.Remove(types.ContainerRemoveOptions{Force: true})
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleContainersBulkCommand(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
baseBulkCommands := []config.CustomCommand{
|
||||||
|
{
|
||||||
|
Name: gui.Tr.StopAllContainers,
|
||||||
|
InternalFunction: gui.handleStopContainers,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: gui.Tr.RemoveAllContainers,
|
||||||
|
InternalFunction: gui.handleRemoveContainers,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: gui.Tr.PruneContainers,
|
||||||
|
InternalFunction: gui.handlePruneContainers,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
bulkCommands := append(baseBulkCommands, gui.Config.UserConfig.BulkCommands.Containers...)
|
||||||
|
commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{})
|
||||||
|
|
||||||
|
return gui.createBulkCommandMenu(bulkCommands, commandObject)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ func (r *customCommandOption) GetDisplayStrings(isFocused bool) []string {
|
||||||
return []string{r.name, utils.ColoredString(r.description, color.FgCyan)}
|
return []string{r.name, utils.ColoredString(r.description, color.FgCyan)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) createCustomCommandMenu(customCommands []config.CustomCommand, commandObject commands.CommandObject) error {
|
func (gui *Gui) createCommandMenu(customCommands []config.CustomCommand, commandObject commands.CommandObject, title string, waitingStatus string) error {
|
||||||
options := make([]*customCommandOption, len(customCommands)+1)
|
options := make([]*customCommandOption, len(customCommands)+1)
|
||||||
for i, command := range customCommands {
|
for i, command := range customCommands {
|
||||||
resolvedCommand := utils.ApplyTemplate(command.Command, commandObject)
|
resolvedCommand := utils.ApplyTemplate(command.Command, commandObject)
|
||||||
|
|
@ -46,6 +46,10 @@ func (gui *Gui) createCustomCommandMenu(customCommands []config.CustomCommand, c
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if option.customCommand.InternalFunction != nil {
|
||||||
|
return option.customCommand.InternalFunction()
|
||||||
|
}
|
||||||
|
|
||||||
// if we have a command for attaching, we attach and return the subprocess error
|
// if we have a command for attaching, we attach and return the subprocess error
|
||||||
if option.customCommand.Attach {
|
if option.customCommand.Attach {
|
||||||
cmd := gui.OSCommand.ExecutableFromString(option.command)
|
cmd := gui.OSCommand.ExecutableFromString(option.command)
|
||||||
|
|
@ -53,7 +57,7 @@ func (gui *Gui) createCustomCommandMenu(customCommands []config.CustomCommand, c
|
||||||
return gui.Errors.ErrSubProcess
|
return gui.Errors.ErrSubProcess
|
||||||
}
|
}
|
||||||
|
|
||||||
return gui.WithWaitingStatus(gui.Tr.RunningCustomCommandStatus, func() error {
|
return gui.WithWaitingStatus(waitingStatus, func() error {
|
||||||
if err := gui.OSCommand.RunCommand(option.command); err != nil {
|
if err := gui.OSCommand.RunCommand(option.command); err != nil {
|
||||||
return gui.createErrorPanel(gui.g, err.Error())
|
return gui.createErrorPanel(gui.g, err.Error())
|
||||||
}
|
}
|
||||||
|
|
@ -61,5 +65,13 @@ func (gui *Gui) createCustomCommandMenu(customCommands []config.CustomCommand, c
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return gui.createMenu("", options, len(options), handleMenuPress)
|
return gui.createMenu(title, options, len(options), handleMenuPress)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) createCustomCommandMenu(customCommands []config.CustomCommand, commandObject commands.CommandObject) error {
|
||||||
|
return gui.createCommandMenu(customCommands, commandObject, gui.Tr.CustomCommandTitle, gui.Tr.RunningCustomCommandStatus)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) createBulkCommandMenu(customCommands []config.CustomCommand, commandObject commands.CommandObject) error {
|
||||||
|
return gui.createCommandMenu(customCommands, commandObject, gui.Tr.BulkCommandTitle, gui.Tr.RunningBulkCommandStatus)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -225,6 +225,7 @@ func (gui *Gui) renderGlobalOptions() error {
|
||||||
"PgUp/PgDn": gui.Tr.Scroll,
|
"PgUp/PgDn": gui.Tr.Scroll,
|
||||||
"← → ↑ ↓": gui.Tr.Navigate,
|
"← → ↑ ↓": gui.Tr.Navigate,
|
||||||
"esc/q": gui.Tr.Close,
|
"esc/q": gui.Tr.Close,
|
||||||
|
"b": gui.Tr.ViewBulkCommands,
|
||||||
"x": gui.Tr.Menu,
|
"x": gui.Tr.Menu,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -282,6 +283,9 @@ func (gui *Gui) Run() error {
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for err := range gui.ErrorChan {
|
for err := range gui.ErrorChan {
|
||||||
|
if err == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if strings.Contains(err.Error(), "No such container") {
|
if strings.Contains(err.Error(), "No such container") {
|
||||||
// this happens all the time when e.g. restarting containers so we won't worry about it
|
// this happens all the time when e.g. restarting containers so we won't worry about it
|
||||||
gui.Log.Warn(err)
|
gui.Log.Warn(err)
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/go-errors/errors"
|
"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/utils"
|
"github.com/jesseduffield/lazydocker/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -23,7 +24,7 @@ func (gui *Gui) getImageContextTitles() []string {
|
||||||
return []string{gui.Tr.ConfigTitle}
|
return []string{gui.Tr.ConfigTitle}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) getSelectedImage(g *gocui.Gui) (*commands.Image, error) {
|
func (gui *Gui) getSelectedImage() (*commands.Image, error) {
|
||||||
selectedLine := gui.State.Panels.Images.SelectedLine
|
selectedLine := gui.State.Panels.Images.SelectedLine
|
||||||
if selectedLine == -1 {
|
if selectedLine == -1 {
|
||||||
return &commands.Image{}, gui.Errors.ErrNoImages
|
return &commands.Image{}, gui.Errors.ErrNoImages
|
||||||
|
|
@ -41,7 +42,7 @@ func (gui *Gui) handleImagesClick(g *gocui.Gui, v *gocui.View) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleImageSelect(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handleImageSelect(g *gocui.Gui, v *gocui.View) error {
|
||||||
Image, err := gui.getSelectedImage(g)
|
Image, err := gui.getSelectedImage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != gui.Errors.ErrNoImages {
|
if err != gui.Errors.ErrNoImages {
|
||||||
return err
|
return err
|
||||||
|
|
@ -207,7 +208,7 @@ 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(g)
|
Image, err := gui.getSelectedImage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -248,8 +249,8 @@ func (gui *Gui) handleImagesRemoveMenu(g *gocui.Gui, v *gocui.View) error {
|
||||||
return gui.createMenu("", options, len(options), handleMenuPress)
|
return gui.createMenu("", options, len(options), handleMenuPress)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handlePruneImages(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handlePruneImages() error {
|
||||||
return gui.createConfirmationPanel(gui.g, v, gui.Tr.Confirm, gui.Tr.ConfirmPruneImages, func(g *gocui.Gui, v *gocui.View) error {
|
return gui.createConfirmationPanel(gui.g, gui.getImagesView(), gui.Tr.Confirm, gui.Tr.ConfirmPruneImages, func(g *gocui.Gui, v *gocui.View) error {
|
||||||
return gui.WithWaitingStatus(gui.Tr.PruningStatus, func() error {
|
return gui.WithWaitingStatus(gui.Tr.PruningStatus, func() error {
|
||||||
err := gui.DockerCommand.PruneImages()
|
err := gui.DockerCommand.PruneImages()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -261,17 +262,30 @@ func (gui *Gui) handlePruneImages(g *gocui.Gui, v *gocui.View) 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(g)
|
image, err := gui.getSelectedImage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
commandObject := gui.DockerCommand.NewCommandObject(
|
commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{
|
||||||
commands.CommandObject{
|
Image: image,
|
||||||
Image: image,
|
})
|
||||||
})
|
|
||||||
|
|
||||||
customCommands := gui.Config.UserConfig.CustomCommands.Images
|
customCommands := gui.Config.UserConfig.CustomCommands.Images
|
||||||
|
|
||||||
return gui.createCustomCommandMenu(customCommands, commandObject)
|
return gui.createCustomCommandMenu(customCommands, commandObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleImagesBulkCommand(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
baseBulkCommands := []config.CustomCommand{
|
||||||
|
{
|
||||||
|
Name: gui.Tr.PruneImages,
|
||||||
|
InternalFunction: gui.handlePruneImages,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
bulkCommands := append(baseBulkCommands, gui.Config.UserConfig.BulkCommands.Images...)
|
||||||
|
commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{})
|
||||||
|
|
||||||
|
return gui.createBulkCommandMenu(bulkCommands, commandObject)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -239,13 +239,6 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||||
Handler: gui.handleContainerAttach,
|
Handler: gui.handleContainerAttach,
|
||||||
Description: gui.Tr.Attach,
|
Description: gui.Tr.Attach,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
ViewName: "containers",
|
|
||||||
Key: 'D',
|
|
||||||
Modifier: gocui.ModNone,
|
|
||||||
Handler: gui.handlePruneContainers,
|
|
||||||
Description: gui.Tr.PruneContainers,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
ViewName: "containers",
|
ViewName: "containers",
|
||||||
Key: 'm',
|
Key: 'm',
|
||||||
|
|
@ -260,6 +253,13 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||||
Handler: gui.handleContainersCustomCommand,
|
Handler: gui.handleContainersCustomCommand,
|
||||||
Description: gui.Tr.RunCustomCommand,
|
Description: gui.Tr.RunCustomCommand,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
ViewName: "containers",
|
||||||
|
Key: 'b',
|
||||||
|
Modifier: gocui.ModNone,
|
||||||
|
Handler: gui.handleContainersBulkCommand,
|
||||||
|
Description: gui.Tr.ViewBulkCommands,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
ViewName: "services",
|
ViewName: "services",
|
||||||
Key: 'd',
|
Key: 'd',
|
||||||
|
|
@ -323,6 +323,13 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||||
Handler: gui.handleServicesCustomCommand,
|
Handler: gui.handleServicesCustomCommand,
|
||||||
Description: gui.Tr.RunCustomCommand,
|
Description: gui.Tr.RunCustomCommand,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
ViewName: "services",
|
||||||
|
Key: 'b',
|
||||||
|
Modifier: gocui.ModNone,
|
||||||
|
Handler: gui.handleServicesBulkCommand,
|
||||||
|
Description: gui.Tr.ViewBulkCommands,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
ViewName: "images",
|
ViewName: "images",
|
||||||
Key: '[',
|
Key: '[',
|
||||||
|
|
@ -353,10 +360,17 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "images",
|
ViewName: "images",
|
||||||
Key: 'D',
|
Key: 'b',
|
||||||
Modifier: gocui.ModNone,
|
Modifier: gocui.ModNone,
|
||||||
Handler: gui.handlePruneImages,
|
Handler: gui.handleImagesBulkCommand,
|
||||||
Description: gui.Tr.PruneImages,
|
Description: gui.Tr.ViewBulkCommands,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ViewName: "images",
|
||||||
|
Key: 'c',
|
||||||
|
Modifier: gocui.ModNone,
|
||||||
|
Handler: gui.handleImagesCustomCommand,
|
||||||
|
Description: gui.Tr.RunCustomCommand,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "volumes",
|
ViewName: "volumes",
|
||||||
|
|
@ -388,10 +402,17 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "volumes",
|
ViewName: "volumes",
|
||||||
Key: 'D',
|
Key: 'b',
|
||||||
Modifier: gocui.ModNone,
|
Modifier: gocui.ModNone,
|
||||||
Handler: gui.handlePruneVolumes,
|
Handler: gui.handleVolumesBulkCommand,
|
||||||
Description: gui.Tr.PruneVolumes,
|
Description: gui.Tr.ViewBulkCommands,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ViewName: "volumes",
|
||||||
|
Key: 'c',
|
||||||
|
Modifier: gocui.ModNone,
|
||||||
|
Handler: gui.handleVolumesCustomCommand,
|
||||||
|
Description: gui.Tr.RunCustomCommand,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ViewName: "main",
|
ViewName: "main",
|
||||||
|
|
|
||||||
|
|
@ -210,7 +210,7 @@ func (gui *Gui) handleServiceRemoveMenu(g *gocui.Gui, v *gocui.View) error {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return gui.createCommandMenu(options, gui.Tr.RemovingStatus)
|
return gui.createServiceCommandMenu(options, gui.Tr.RemovingStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleServiceStop(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handleServiceStop(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
|
@ -349,7 +349,7 @@ func (gui *Gui) handleServiceRestartMenu(g *gocui.Gui, v *gocui.View) error {
|
||||||
return gui.createMenu("", options, len(options), handleMenuPress)
|
return gui.createMenu("", options, len(options), handleMenuPress)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) createCommandMenu(options []*commandOption, status string) error {
|
func (gui *Gui) createServiceCommandMenu(options []*commandOption, status string) error {
|
||||||
handleMenuPress := func(index int) error {
|
handleMenuPress := func(index int) error {
|
||||||
if options[index].command == "" {
|
if options[index].command == "" {
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -402,3 +402,10 @@ L:
|
||||||
|
|
||||||
return gui.createCustomCommandMenu(customCommands, commandObject)
|
return gui.createCustomCommandMenu(customCommands, commandObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleServicesBulkCommand(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
bulkCommands := gui.Config.UserConfig.BulkCommands.Services
|
||||||
|
commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{})
|
||||||
|
|
||||||
|
return gui.createBulkCommandMenu(bulkCommands, commandObject)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/go-errors/errors"
|
"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/utils"
|
"github.com/jesseduffield/lazydocker/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -239,8 +240,8 @@ func (gui *Gui) handleVolumesRemoveMenu(g *gocui.Gui, v *gocui.View) error {
|
||||||
return gui.createMenu("", options, len(options), handleMenuPress)
|
return gui.createMenu("", options, len(options), handleMenuPress)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) handlePruneVolumes(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handlePruneVolumes() error {
|
||||||
return gui.createConfirmationPanel(gui.g, v, gui.Tr.Confirm, gui.Tr.ConfirmPruneVolumes, func(g *gocui.Gui, v *gocui.View) error {
|
return gui.createConfirmationPanel(gui.g, gui.getVolumesView(), gui.Tr.Confirm, gui.Tr.ConfirmPruneVolumes, func(g *gocui.Gui, v *gocui.View) error {
|
||||||
return gui.WithWaitingStatus(gui.Tr.PruningStatus, func() error {
|
return gui.WithWaitingStatus(gui.Tr.PruningStatus, func() error {
|
||||||
err := gui.DockerCommand.PruneVolumes()
|
err := gui.DockerCommand.PruneVolumes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -257,12 +258,25 @@ func (gui *Gui) handleVolumesCustomCommand(g *gocui.Gui, v *gocui.View) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
commandObject := gui.DockerCommand.NewCommandObject(
|
commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{
|
||||||
commands.CommandObject{
|
Volume: volume,
|
||||||
Volume: volume,
|
})
|
||||||
})
|
|
||||||
|
|
||||||
customCommands := gui.Config.UserConfig.CustomCommands.Volumes
|
customCommands := gui.Config.UserConfig.CustomCommands.Volumes
|
||||||
|
|
||||||
return gui.createCustomCommandMenu(customCommands, commandObject)
|
return gui.createCustomCommandMenu(customCommands, commandObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleVolumesBulkCommand(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
baseBulkCommands := []config.CustomCommand{
|
||||||
|
{
|
||||||
|
Name: gui.Tr.PruneVolumes,
|
||||||
|
InternalFunction: gui.handlePruneVolumes,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
bulkCommands := append(baseBulkCommands, gui.Config.UserConfig.BulkCommands.Volumes...)
|
||||||
|
commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{})
|
||||||
|
|
||||||
|
return gui.createBulkCommandMenu(bulkCommands, commandObject)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ type TranslationSet struct {
|
||||||
Donate string
|
Donate string
|
||||||
Cancel string
|
Cancel string
|
||||||
CustomCommandTitle string
|
CustomCommandTitle string
|
||||||
|
BulkCommandTitle string
|
||||||
Remove string
|
Remove string
|
||||||
HideStopped string
|
HideStopped string
|
||||||
ForceRemove string
|
ForceRemove string
|
||||||
|
|
@ -41,6 +42,7 @@ type TranslationSet struct {
|
||||||
StoppingStatus string
|
StoppingStatus string
|
||||||
RemovingStatus string
|
RemovingStatus string
|
||||||
RunningCustomCommandStatus string
|
RunningCustomCommandStatus string
|
||||||
|
RunningBulkCommandStatus string
|
||||||
RemoveService string
|
RemoveService string
|
||||||
Stop string
|
Stop string
|
||||||
Restart string
|
Restart string
|
||||||
|
|
@ -67,13 +69,18 @@ type TranslationSet struct {
|
||||||
PruneContainers string
|
PruneContainers string
|
||||||
PruneVolumes string
|
PruneVolumes string
|
||||||
ConfirmPruneContainers string
|
ConfirmPruneContainers string
|
||||||
|
ConfirmStopContainers string
|
||||||
|
ConfirmRemoveContainers string
|
||||||
ConfirmPruneImages string
|
ConfirmPruneImages string
|
||||||
ConfirmPruneVolumes string
|
ConfirmPruneVolumes string
|
||||||
PruningStatus string
|
PruningStatus string
|
||||||
StopService string
|
StopService string
|
||||||
PressEnterToReturn string
|
PressEnterToReturn string
|
||||||
|
StopAllContainers string
|
||||||
|
RemoveAllContainers string
|
||||||
ViewRestartOptions string
|
ViewRestartOptions string
|
||||||
RunCustomCommand string
|
RunCustomCommand string
|
||||||
|
ViewBulkCommands string
|
||||||
|
|
||||||
LogsTitle string
|
LogsTitle string
|
||||||
ConfigTitle string
|
ConfigTitle string
|
||||||
|
|
@ -93,6 +100,7 @@ func englishSet() TranslationSet {
|
||||||
RestartingStatus: "restarting",
|
RestartingStatus: "restarting",
|
||||||
StoppingStatus: "stopping",
|
StoppingStatus: "stopping",
|
||||||
RunningCustomCommandStatus: "running custom command",
|
RunningCustomCommandStatus: "running custom command",
|
||||||
|
RunningBulkCommandStatus: "running bulk command",
|
||||||
|
|
||||||
RunningSubprocess: "running subprocess",
|
RunningSubprocess: "running subprocess",
|
||||||
NoViewMachingNewLineFocusedSwitchStatement: "No view matching newLineFocused switch statement",
|
NoViewMachingNewLineFocusedSwitchStatement: "No view matching newLineFocused switch statement",
|
||||||
|
|
@ -106,37 +114,40 @@ func englishSet() TranslationSet {
|
||||||
Donate: "Donate",
|
Donate: "Donate",
|
||||||
Confirm: "Confirm",
|
Confirm: "Confirm",
|
||||||
|
|
||||||
Return: "return",
|
Return: "return",
|
||||||
FocusMain: "focus main panel",
|
FocusMain: "focus main panel",
|
||||||
Navigate: "navigate",
|
Navigate: "navigate",
|
||||||
Execute: "execute",
|
Execute: "execute",
|
||||||
Close: "close",
|
Close: "close",
|
||||||
Menu: "menu",
|
Menu: "menu",
|
||||||
Scroll: "scroll",
|
Scroll: "scroll",
|
||||||
OpenConfig: "open lazydocker config",
|
OpenConfig: "open lazydocker config",
|
||||||
EditConfig: "edit lazydocker config",
|
EditConfig: "edit lazydocker config",
|
||||||
Cancel: "cancel",
|
Cancel: "cancel",
|
||||||
Remove: "remove",
|
Remove: "remove",
|
||||||
HideStopped: "Hide/Show stopped containers",
|
HideStopped: "Hide/Show stopped containers",
|
||||||
ForceRemove: "force remove",
|
ForceRemove: "force remove",
|
||||||
RemoveWithVolumes: "remove with volumes",
|
RemoveWithVolumes: "remove with volumes",
|
||||||
RemoveService: "remove containers",
|
RemoveService: "remove containers",
|
||||||
Stop: "stop",
|
Stop: "stop",
|
||||||
Restart: "restart",
|
Restart: "restart",
|
||||||
Rebuild: "rebuild",
|
Rebuild: "rebuild",
|
||||||
Recreate: "recreate",
|
Recreate: "recreate",
|
||||||
PreviousContext: "previous tab",
|
PreviousContext: "previous tab",
|
||||||
NextContext: "next tab",
|
NextContext: "next tab",
|
||||||
Attach: "attach",
|
Attach: "attach",
|
||||||
ViewLogs: "view logs",
|
ViewLogs: "view logs",
|
||||||
RemoveImage: "remove image",
|
RemoveImage: "remove image",
|
||||||
RemoveVolume: "remove volume",
|
RemoveVolume: "remove volume",
|
||||||
RemoveWithoutPrune: "remove without deleting untagged parents",
|
RemoveWithoutPrune: "remove without deleting untagged parents",
|
||||||
PruneContainers: "prune exited containers",
|
PruneContainers: "prune exited containers",
|
||||||
PruneVolumes: "prune unused volumes",
|
PruneVolumes: "prune unused volumes",
|
||||||
PruneImages: "prune unused images",
|
PruneImages: "prune unused images",
|
||||||
ViewRestartOptions: "view restart options",
|
StopAllContainers: "stop all containers",
|
||||||
RunCustomCommand: "run predefined custom command",
|
RemoveAllContainers: "remove all containers (forced)",
|
||||||
|
ViewRestartOptions: "view restart options",
|
||||||
|
RunCustomCommand: "run predefined custom command",
|
||||||
|
ViewBulkCommands: "view bulk commands",
|
||||||
|
|
||||||
AnonymousReportingTitle: "Help make lazydocker better",
|
AnonymousReportingTitle: "Help make lazydocker better",
|
||||||
AnonymousReportingPrompt: "Would you like to enable anonymous reporting data to help improve lazydocker?",
|
AnonymousReportingPrompt: "Would you like to enable anonymous reporting data to help improve lazydocker?",
|
||||||
|
|
@ -150,6 +161,7 @@ func englishSet() TranslationSet {
|
||||||
ImagesTitle: "Images",
|
ImagesTitle: "Images",
|
||||||
VolumesTitle: "Volumes",
|
VolumesTitle: "Volumes",
|
||||||
CustomCommandTitle: "Custom Command:",
|
CustomCommandTitle: "Custom Command:",
|
||||||
|
BulkCommandTitle: "Bulk Command:",
|
||||||
ErrorTitle: "Error",
|
ErrorTitle: "Error",
|
||||||
LogsTitle: "Logs",
|
LogsTitle: "Logs",
|
||||||
ConfigTitle: "Config",
|
ConfigTitle: "Config",
|
||||||
|
|
@ -169,6 +181,8 @@ func englishSet() TranslationSet {
|
||||||
NotEnoughSpace: "Not enough space to render panels",
|
NotEnoughSpace: "Not enough space to render panels",
|
||||||
ConfirmPruneImages: "Are you sure you want to prune all unused images?",
|
ConfirmPruneImages: "Are you sure you want to prune all unused images?",
|
||||||
ConfirmPruneContainers: "Are you sure you want to prune all stopped containers?",
|
ConfirmPruneContainers: "Are you sure you want to prune all stopped containers?",
|
||||||
|
ConfirmStopContainers: "Are you sure you want to stop all containers?",
|
||||||
|
ConfirmRemoveContainers: "Are you sure you want to remove all containers?",
|
||||||
ConfirmPruneVolumes: "Are you sure you want to prune all unused volumes?",
|
ConfirmPruneVolumes: "Are you sure you want to prune all unused volumes?",
|
||||||
StopService: "Are you sure you want to stop this service's containers?",
|
StopService: "Are you sure you want to stop this service's containers?",
|
||||||
StopContainer: "Are you sure you want to stop this container?",
|
StopContainer: "Are you sure you want to stop this container?",
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue