diff --git a/README.md b/README.md index 17cf82e4..db7cd1e9 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,6 @@ A simple terminal UI for both docker and docker-compose, written in Go with the [![CircleCI](https://circleci.com/gh/jesseduffield/lazydocker.svg?style=svg)](https://circleci.com/gh/jesseduffield/lazydocker) [![Go Report Card](https://goreportcard.com/badge/github.com/jesseduffield/lazydocker)](https://goreportcard.com/report/github.com/jesseduffield/lazydocker) [![GolangCI](https://golangci.com/badges/github.com/jesseduffield/lazydocker.svg)](https://golangci.com) [![GoDoc](https://godoc.org/github.com/jesseduffield/lazydocker?status.svg)](http://godoc.org/github.com/jesseduffield/lazydocker) [![GitHub tag](https://img.shields.io/github/tag/jesseduffield/lazydocker.svg)]() - - ![Gif](/docs/resources/demo3.gif) [Demo](https://youtu.be/NICqQPxwJWw) @@ -31,7 +29,7 @@ Memorising docker commands is hard. Memorising aliases is slightly less hard. Ke ## Requirements -- Docker >= **1.8** (API >= **1.20**) +- Docker >= **1.8** (API >= **1.25**) - Docker-Compose >= **1.23.2** (optional) ## Installation @@ -197,18 +195,23 @@ If you want to see what I (Jesse) am up to in terms of development, follow me on ## FAQ ### 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) ### 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` ### 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 ### 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) ### 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` ## Alternatives diff --git a/pkg/commands/container.go b/pkg/commands/container.go index 137fc25c..c7faa01e 100644 --- a/pkg/commands/container.go +++ b/pkg/commands/container.go @@ -2,12 +2,14 @@ package commands import ( "context" - "github.com/docker/docker/api/types/container" + "fmt" "os/exec" "strconv" "strings" "time" + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/client" @@ -317,6 +319,7 @@ func (c *Container) GetColor() color.Attribute { // Remove removes the container 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 strings.Contains(err.Error(), "Stop the container before attempting removal or force remove") { return ComplexError{ @@ -333,16 +336,20 @@ func (c *Container) Remove(options types.ContainerRemoveOptions) error { // Stop stops the container func (c *Container) Stop() error { + c.Log.Warn(fmt.Sprintf("stopping container %s", c.Name)) return c.Client.ContainerStop(context.Background(), c.ID, nil) } // Restart restarts the container func (c *Container) Restart() error { + c.Log.Warn(fmt.Sprintf("restarting container %s", c.Name)) return c.Client.ContainerRestart(context.Background(), c.ID, nil) } // Attach attaches the container 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 if !c.Details.Config.OpenStdin { return nil, errors.New(c.Tr.UnattachableContainerError) diff --git a/pkg/commands/docker.go b/pkg/commands/docker.go index 86a70f90..53b7d13a 100644 --- a/pkg/commands/docker.go +++ b/pkg/commands/docker.go @@ -22,7 +22,7 @@ import ( ) const ( - APIVersion = "1.20" + APIVersion = "1.25" ) // DockerCommand is our main docker interface diff --git a/pkg/config/app_config.go b/pkg/config/app_config.go index d334e80b..a420b7f7 100644 --- a/pkg/config/app_config.go +++ b/pkg/config/app_config.go @@ -50,6 +50,10 @@ type UserConfig struct { // those are found in the commands package 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 OSConfig `yaml:"oS,omitempty"` @@ -260,10 +264,10 @@ type CustomCommands struct { // Services contains the custom commands for services Services []CustomCommand `yaml:"services,omitempty"` - // Services contains the custom commands for services + // Images contains the custom commands for images Images []CustomCommand `yaml:"images,omitempty"` - // Services contains the custom commands for services + // Volumes contains the custom commands for volumes Volumes []CustomCommand `yaml:"volumes,omitempty"` } @@ -289,6 +293,9 @@ type CustomCommand struct { // field has no effect on customcommands under the 'communications' part of // the customCommand config. 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 @@ -345,6 +352,52 @@ func GetDefaultConfig() UserConfig { Images: []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(), Update: UpdateConfig{ DockerRefreshInterval: time.Millisecond * 100, diff --git a/pkg/gui/containers_panel.go b/pkg/gui/containers_panel.go index d1c61f5e..65a74e4a 100644 --- a/pkg/gui/containers_panel.go +++ b/pkg/gui/containers_panel.go @@ -11,6 +11,7 @@ import ( "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" ) @@ -476,8 +477,8 @@ func (gui *Gui) handleContainerAttach(g *gocui.Gui, v *gocui.View) error { return gui.Errors.ErrSubProcess } -func (gui *Gui) handlePruneContainers(g *gocui.Gui, v *gocui.View) error { - return gui.createConfirmationPanel(gui.g, v, gui.Tr.Confirm, gui.Tr.ConfirmPruneContainers, func(g *gocui.Gui, v *gocui.View) error { +func (gui *Gui) handlePruneContainers() 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 { err := gui.DockerCommand.PruneContainers() if err != nil { @@ -517,3 +518,51 @@ func (gui *Gui) handleContainersCustomCommand(g *gocui.Gui, v *gocui.View) error 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) +} diff --git a/pkg/gui/custom_commands.go b/pkg/gui/custom_commands.go index 7d858d2e..1a23b719 100644 --- a/pkg/gui/custom_commands.go +++ b/pkg/gui/custom_commands.go @@ -21,7 +21,7 @@ func (r *customCommandOption) GetDisplayStrings(isFocused bool) []string { 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) for i, command := range customCommands { resolvedCommand := utils.ApplyTemplate(command.Command, commandObject) @@ -46,6 +46,10 @@ func (gui *Gui) createCustomCommandMenu(customCommands []config.CustomCommand, c 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 option.customCommand.Attach { cmd := gui.OSCommand.ExecutableFromString(option.command) @@ -53,7 +57,7 @@ func (gui *Gui) createCustomCommandMenu(customCommands []config.CustomCommand, c 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 { 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) } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 1eaaa7c7..1655420a 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -225,6 +225,7 @@ func (gui *Gui) renderGlobalOptions() error { "PgUp/PgDn": gui.Tr.Scroll, "← → ↑ ↓": gui.Tr.Navigate, "esc/q": gui.Tr.Close, + "b": gui.Tr.ViewBulkCommands, "x": gui.Tr.Menu, }) } @@ -283,6 +284,9 @@ func (gui *Gui) Run() error { go func() { for err := range gui.ErrorChan { + if err == nil { + continue + } 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 gui.Log.Warn(err) diff --git a/pkg/gui/images_panel.go b/pkg/gui/images_panel.go index 1e2c2b74..878ce1ac 100644 --- a/pkg/gui/images_panel.go +++ b/pkg/gui/images_panel.go @@ -10,6 +10,7 @@ import ( "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" ) @@ -23,7 +24,7 @@ func (gui *Gui) getImageContextTitles() []string { 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 if selectedLine == -1 { 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 { - Image, err := gui.getSelectedImage(g) + Image, err := gui.getSelectedImage() if err != nil { if err != gui.Errors.ErrNoImages { return err @@ -207,7 +208,7 @@ func (r *removeImageOption) GetDisplayStrings(isFocused bool) []string { } func (gui *Gui) handleImagesRemoveMenu(g *gocui.Gui, v *gocui.View) error { - Image, err := gui.getSelectedImage(g) + Image, err := gui.getSelectedImage() if err != 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) } -func (gui *Gui) handlePruneImages(g *gocui.Gui, v *gocui.View) error { - return gui.createConfirmationPanel(gui.g, v, gui.Tr.Confirm, gui.Tr.ConfirmPruneImages, func(g *gocui.Gui, v *gocui.View) error { +func (gui *Gui) handlePruneImages() 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 { err := gui.DockerCommand.PruneImages() 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 { - image, err := gui.getSelectedImage(g) + image, err := gui.getSelectedImage() if err != nil { return nil } - commandObject := gui.DockerCommand.NewCommandObject( - commands.CommandObject{ - Image: image, - }) + commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{ + Image: image, + }) customCommands := gui.Config.UserConfig.CustomCommands.Images 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) +} diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 898a9ba9..24fe83d8 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -239,13 +239,6 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { Handler: gui.handleContainerAttach, Description: gui.Tr.Attach, }, - { - ViewName: "containers", - Key: 'D', - Modifier: gocui.ModNone, - Handler: gui.handlePruneContainers, - Description: gui.Tr.PruneContainers, - }, { ViewName: "containers", Key: 'm', @@ -260,6 +253,13 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { Handler: gui.handleContainersCustomCommand, Description: gui.Tr.RunCustomCommand, }, + { + ViewName: "containers", + Key: 'b', + Modifier: gocui.ModNone, + Handler: gui.handleContainersBulkCommand, + Description: gui.Tr.ViewBulkCommands, + }, { ViewName: "services", Key: 'd', @@ -323,6 +323,13 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { Handler: gui.handleServicesCustomCommand, Description: gui.Tr.RunCustomCommand, }, + { + ViewName: "services", + Key: 'b', + Modifier: gocui.ModNone, + Handler: gui.handleServicesBulkCommand, + Description: gui.Tr.ViewBulkCommands, + }, { ViewName: "images", Key: '[', @@ -353,10 +360,17 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { }, { ViewName: "images", - Key: 'D', + Key: 'b', Modifier: gocui.ModNone, - Handler: gui.handlePruneImages, - Description: gui.Tr.PruneImages, + Handler: gui.handleImagesBulkCommand, + Description: gui.Tr.ViewBulkCommands, + }, + { + ViewName: "images", + Key: 'c', + Modifier: gocui.ModNone, + Handler: gui.handleImagesCustomCommand, + Description: gui.Tr.RunCustomCommand, }, { ViewName: "volumes", @@ -388,10 +402,17 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { }, { ViewName: "volumes", - Key: 'D', + Key: 'b', Modifier: gocui.ModNone, - Handler: gui.handlePruneVolumes, - Description: gui.Tr.PruneVolumes, + Handler: gui.handleVolumesBulkCommand, + Description: gui.Tr.ViewBulkCommands, + }, + { + ViewName: "volumes", + Key: 'c', + Modifier: gocui.ModNone, + Handler: gui.handleVolumesCustomCommand, + Description: gui.Tr.RunCustomCommand, }, { ViewName: "main", diff --git a/pkg/gui/services_panel.go b/pkg/gui/services_panel.go index 0c1e7a43..460a3a07 100644 --- a/pkg/gui/services_panel.go +++ b/pkg/gui/services_panel.go @@ -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 { @@ -349,7 +349,7 @@ func (gui *Gui) handleServiceRestartMenu(g *gocui.Gui, v *gocui.View) error { 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 { if options[index].command == "" { return nil @@ -402,3 +402,10 @@ L: 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) +} diff --git a/pkg/gui/volumes_panel.go b/pkg/gui/volumes_panel.go index 1c2a4878..721c5169 100644 --- a/pkg/gui/volumes_panel.go +++ b/pkg/gui/volumes_panel.go @@ -7,6 +7,7 @@ import ( "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" ) @@ -239,8 +240,8 @@ func (gui *Gui) handleVolumesRemoveMenu(g *gocui.Gui, v *gocui.View) error { return gui.createMenu("", options, len(options), handleMenuPress) } -func (gui *Gui) handlePruneVolumes(g *gocui.Gui, v *gocui.View) error { - return gui.createConfirmationPanel(gui.g, v, gui.Tr.Confirm, gui.Tr.ConfirmPruneVolumes, func(g *gocui.Gui, v *gocui.View) error { +func (gui *Gui) handlePruneVolumes() 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 { err := gui.DockerCommand.PruneVolumes() if err != nil { @@ -257,12 +258,25 @@ func (gui *Gui) handleVolumesCustomCommand(g *gocui.Gui, v *gocui.View) error { return nil } - commandObject := gui.DockerCommand.NewCommandObject( - commands.CommandObject{ - Volume: volume, - }) + commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{ + Volume: volume, + }) customCommands := gui.Config.UserConfig.CustomCommands.Volumes 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) +} diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 3c2fc413..87d86336 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -28,6 +28,7 @@ type TranslationSet struct { Donate string Cancel string CustomCommandTitle string + BulkCommandTitle string Remove string HideStopped string ForceRemove string @@ -41,6 +42,7 @@ type TranslationSet struct { StoppingStatus string RemovingStatus string RunningCustomCommandStatus string + RunningBulkCommandStatus string RemoveService string Stop string Restart string @@ -67,13 +69,18 @@ type TranslationSet struct { PruneContainers string PruneVolumes string ConfirmPruneContainers string + ConfirmStopContainers string + ConfirmRemoveContainers string ConfirmPruneImages string ConfirmPruneVolumes string PruningStatus string StopService string PressEnterToReturn string + StopAllContainers string + RemoveAllContainers string ViewRestartOptions string RunCustomCommand string + ViewBulkCommands string LogsTitle string ConfigTitle string @@ -93,6 +100,7 @@ func englishSet() TranslationSet { RestartingStatus: "restarting", StoppingStatus: "stopping", RunningCustomCommandStatus: "running custom command", + RunningBulkCommandStatus: "running bulk command", RunningSubprocess: "running subprocess", NoViewMachingNewLineFocusedSwitchStatement: "No view matching newLineFocused switch statement", @@ -106,37 +114,40 @@ func englishSet() TranslationSet { Donate: "Donate", Confirm: "Confirm", - Return: "return", - FocusMain: "focus main panel", - Navigate: "navigate", - Execute: "execute", - Close: "close", - Menu: "menu", - Scroll: "scroll", - OpenConfig: "open lazydocker config", - EditConfig: "edit lazydocker config", - Cancel: "cancel", - Remove: "remove", - HideStopped: "Hide/Show stopped containers", - ForceRemove: "force remove", - RemoveWithVolumes: "remove with volumes", - RemoveService: "remove containers", - Stop: "stop", - Restart: "restart", - Rebuild: "rebuild", - Recreate: "recreate", - PreviousContext: "previous tab", - NextContext: "next tab", - Attach: "attach", - ViewLogs: "view logs", - RemoveImage: "remove image", - RemoveVolume: "remove volume", - RemoveWithoutPrune: "remove without deleting untagged parents", - PruneContainers: "prune exited containers", - PruneVolumes: "prune unused volumes", - PruneImages: "prune unused images", - ViewRestartOptions: "view restart options", - RunCustomCommand: "run predefined custom command", + Return: "return", + FocusMain: "focus main panel", + Navigate: "navigate", + Execute: "execute", + Close: "close", + Menu: "menu", + Scroll: "scroll", + OpenConfig: "open lazydocker config", + EditConfig: "edit lazydocker config", + Cancel: "cancel", + Remove: "remove", + HideStopped: "Hide/Show stopped containers", + ForceRemove: "force remove", + RemoveWithVolumes: "remove with volumes", + RemoveService: "remove containers", + Stop: "stop", + Restart: "restart", + Rebuild: "rebuild", + Recreate: "recreate", + PreviousContext: "previous tab", + NextContext: "next tab", + Attach: "attach", + ViewLogs: "view logs", + RemoveImage: "remove image", + RemoveVolume: "remove volume", + RemoveWithoutPrune: "remove without deleting untagged parents", + PruneContainers: "prune exited containers", + PruneVolumes: "prune unused volumes", + PruneImages: "prune unused images", + StopAllContainers: "stop all containers", + RemoveAllContainers: "remove all containers (forced)", + ViewRestartOptions: "view restart options", + RunCustomCommand: "run predefined custom command", + ViewBulkCommands: "view bulk commands", AnonymousReportingTitle: "Help make lazydocker better", AnonymousReportingPrompt: "Would you like to enable anonymous reporting data to help improve lazydocker?", @@ -150,6 +161,7 @@ func englishSet() TranslationSet { ImagesTitle: "Images", VolumesTitle: "Volumes", CustomCommandTitle: "Custom Command:", + BulkCommandTitle: "Bulk Command:", ErrorTitle: "Error", LogsTitle: "Logs", ConfigTitle: "Config", @@ -169,6 +181,8 @@ func englishSet() TranslationSet { NotEnoughSpace: "Not enough space to render panels", ConfirmPruneImages: "Are you sure you want to prune all unused images?", 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?", StopService: "Are you sure you want to stop this service's containers?", StopContainer: "Are you sure you want to stop this container?",