mirror of
https://github.com/jesseduffield/lazydocker.git
synced 2026-07-25 08:31:03 +00:00
Merge pull request #107 from jesseduffield/bulk-commands
Support bulk commands in each of the panels
This commit is contained in:
commit
4dc8f76083
12 changed files with 272 additions and 74 deletions
|
|
@ -6,8 +6,6 @@ A simple terminal UI for both docker and docker-compose, written in Go with the
|
||||||
|
|
||||||
[](https://circleci.com/gh/jesseduffield/lazydocker) [](https://goreportcard.com/report/github.com/jesseduffield/lazydocker) [](https://golangci.com) [](http://godoc.org/github.com/jesseduffield/lazydocker) []()
|
[](https://circleci.com/gh/jesseduffield/lazydocker) [](https://goreportcard.com/report/github.com/jesseduffield/lazydocker) [](https://golangci.com) [](http://godoc.org/github.com/jesseduffield/lazydocker) []()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
[Demo](https://youtu.be/NICqQPxwJWw)
|
[Demo](https://youtu.be/NICqQPxwJWw)
|
||||||
|
|
@ -31,7 +29,7 @@ Memorising docker commands is hard. Memorising aliases is slightly less hard. Ke
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- Docker >= **1.8** (API >= **1.20**)
|
- Docker >= **1.8** (API >= **1.25**)
|
||||||
- Docker-Compose >= **1.23.2** (optional)
|
- Docker-Compose >= **1.23.2** (optional)
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
@ -197,18 +195,23 @@ If you want to see what I (Jesse) am up to in terms of development, follow me on
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
### How do I edit my config?
|
### How do I edit my config?
|
||||||
|
|
||||||
By opening lazydocker, clicking on the 'project' panel in the top left, and pressing 'o' (or 'e' if your editor is vim). See [Config Docs](/docs/Config.md)
|
By opening lazydocker, clicking on the 'project' panel in the top left, and pressing 'o' (or 'e' if your editor is vim). See [Config Docs](/docs/Config.md)
|
||||||
|
|
||||||
### How do I get text to wrap in my main panel?
|
### How do I get text to wrap in my main panel?
|
||||||
|
|
||||||
In the future I want to make this the default, but for now there are some CPU issues that arise with wrapping. If you want to enable wrapping, use `gui.wrapMainPanel: true`
|
In the future I want to make this the default, but for now there are some CPU issues that arise with wrapping. If you want to enable wrapping, use `gui.wrapMainPanel: true`
|
||||||
|
|
||||||
### How do you select text?
|
### How do you select text?
|
||||||
|
|
||||||
Because we support mouse events, you will need to hold option while dragging the mouse to indicate you're trying to select text rather than click on something. Alternatively you can disable mouse events via the `gui.ignoreMouseEvents` config value
|
Because we support mouse events, you will need to hold option while dragging the mouse to indicate you're trying to select text rather than click on something. Alternatively you can disable mouse events via the `gui.ignoreMouseEvents` config value
|
||||||
|
|
||||||
### Does this work with Windows?
|
### Does this work with Windows?
|
||||||
|
|
||||||
Currently not unless you use WSL. Instructions for setting up docker for WSL can be found here [here](https://nickjanetakis.com/blog/setting-up-docker-for-windows-and-wsl-to-work-flawlessly)
|
Currently not unless you use WSL. Instructions for setting up docker for WSL can be found here [here](https://nickjanetakis.com/blog/setting-up-docker-for-windows-and-wsl-to-work-flawlessly)
|
||||||
|
|
||||||
### Why can't I see my container's logs?
|
### Why can't I see my container's logs?
|
||||||
|
|
||||||
By default we only show logs from the last hour, so that we're not putting too much strain on the machine. This may be why you can't see logs when you first start lazydocker. This can be overwritten in the config's `commandTemplates`
|
By default we only show logs from the last hour, so that we're not putting too much strain on the machine. This may be why you can't see logs when you first start lazydocker. This can be overwritten in the config's `commandTemplates`
|
||||||
|
|
||||||
## Alternatives
|
## Alternatives
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
APIVersion = "1.20"
|
APIVersion = "1.25"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DockerCommand is our main docker interface
|
// DockerCommand is our main docker interface
|
||||||
|
|
|
||||||
|
|
@ -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"`
|
||||||
|
|
||||||
|
|
@ -260,10 +264,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"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -289,6 +293,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
|
||||||
|
|
@ -345,6 +352,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{
|
||||||
DockerRefreshInterval: time.Millisecond * 100,
|
DockerRefreshInterval: time.Millisecond * 100,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -283,6 +284,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