Merge pull request #272 from lpessoa/lp-order-by-status

This commit is contained in:
Jesse Duffield 2022-01-18 12:28:09 +11:00 committed by GitHub
commit 9fad29449c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 241 additions and 40 deletions

View file

@ -258,6 +258,7 @@ func (c *DockerCommand) RefreshContainersAndServices() error {
c.Containers = containers c.Containers = containers
c.Services = services c.Services = services
c.DisplayContainers = c.filterOutExited(displayContainers) c.DisplayContainers = c.filterOutExited(displayContainers)
c.DisplayContainers = c.sortedContainers(c.DisplayContainers)
return nil return nil
} }
@ -289,6 +290,27 @@ func (c *DockerCommand) filterOutExited(containers []*Container) []*Container {
return toReturn return toReturn
} }
// sortedContainers returns containers sorted by state if c.SortContainersByState is true (follows 1- running, 2- exited, 3- created)
// and sorted by name if c.SortContainersByState is false
func (c *DockerCommand) sortedContainers(containers []*Container) []*Container {
if !c.Config.UserConfig.Gui.LegacySortContainers {
states := map[string]int{
"running": 1,
"exited": 2,
"created": 3,
}
sort.Slice(containers, func(i, j int) bool {
stateLeft := states[containers[i].Container.State]
stateRight := states[containers[j].Container.State]
if stateLeft == stateRight {
return containers[i].Name < containers[j].Name
}
return states[containers[i].Container.State] < states[containers[j].Container.State]
})
}
return containers
}
// obtainStandaloneContainers returns standalone containers. Standalone containers are containers which are either one-off containers, or whose service is not part of this docker-compose context // obtainStandaloneContainers returns standalone containers. Standalone containers are containers which are either one-off containers, or whose service is not part of this docker-compose context
func (c *DockerCommand) obtainStandaloneContainers(containers []*Container, services []*Service) []*Container { func (c *DockerCommand) obtainStandaloneContainers(containers []*Container, services []*Service) []*Container {
standaloneContainers := []*Container{} standaloneContainers := []*Container{}

View file

@ -0,0 +1,171 @@
package commands
import (
"github.com/docker/docker/api/types"
"github.com/jesseduffield/lazydocker/pkg/config"
"github.com/stretchr/testify/assert"
"testing"
)
func sampleContainers(userConfig *config.AppConfig) []*Container {
return []*Container{
{
ID: "1",
Name: "1",
Container: types.Container{
State: "exited",
},
Config: userConfig,
},
{
ID: "2",
Name: "2",
Container: types.Container{
State: "running",
},
Config: userConfig,
},
{
ID: "3",
Name: "3",
Container: types.Container{
State: "running",
},
Config: userConfig,
},
{
ID: "4",
Name: "4",
Container: types.Container{
State: "created",
},
Config: userConfig,
},
}
}
func expectedPerStatusContainers(appConfig *config.AppConfig) []*Container {
return []*Container{
{
ID: "2",
Name: "2",
Container: types.Container{
State: "running",
},
Config: appConfig,
},
{
ID: "3",
Name: "3",
Container: types.Container{
State: "running",
},
Config: appConfig,
},
{
ID: "1",
Name: "1",
Container: types.Container{
State: "exited",
},
Config: appConfig,
},
{
ID: "4",
Name: "4",
Container: types.Container{
State: "created",
},
Config: appConfig,
},
}
}
func expectedLegacySortedContainers(appConfig *config.AppConfig) []*Container {
return []*Container{
{
ID: "1",
Name: "1",
Container: types.Container{
State: "exited",
},
Config: appConfig,
},
{
ID: "2",
Name: "2",
Container: types.Container{
State: "running",
},
Config: appConfig,
},
{
ID: "3",
Name: "3",
Container: types.Container{
State: "running",
},
Config: appConfig,
},
{
ID: "4",
Name: "4",
Container: types.Container{
State: "created",
},
Config: appConfig,
},
}
}
func assertEqualContainers(t *testing.T, left *Container, right *Container) {
assert.Equal(t, left.Container.State, right.Container.State)
assert.Equal(t, left.Container.ID, right.Container.ID)
assert.Equal(t, left.Name, right.Name)
}
func TestSortContainers(t *testing.T) {
appConfig := NewDummyAppConfig()
appConfig.UserConfig = &config.UserConfig{
Gui: config.GuiConfig{
LegacySortContainers: false,
},
}
command := &DockerCommand{
Config: appConfig,
}
containers := sampleContainers(appConfig)
sorted := expectedPerStatusContainers(appConfig)
ct := command.sortedContainers(containers)
assert.Equal(t, len(ct), len(sorted))
for i := 0; i < len(ct); i++ {
assertEqualContainers(t, sorted[i], ct[i])
}
}
func TestLegacySortedContainers(t *testing.T) {
appConfig := NewDummyAppConfig()
appConfig.UserConfig = &config.UserConfig{
Gui: config.GuiConfig{
LegacySortContainers: true,
},
}
command := &DockerCommand{
Config: appConfig,
}
containers := sampleContainers(appConfig)
sorted := expectedLegacySortedContainers(appConfig)
ct := command.sortedContainers(containers)
for i := 0; i < len(ct); i++ {
assertEqualContainers(t, sorted[i], ct[i])
}
}

View file

@ -20,7 +20,7 @@ import (
"time" "time"
"github.com/OpenPeeDeeP/xdg" "github.com/OpenPeeDeeP/xdg"
yaml "github.com/jesseduffield/yaml" "github.com/jesseduffield/yaml"
) )
// UserConfig holds all of the user-configurable options // UserConfig holds all of the user-configurable options
@ -106,6 +106,11 @@ type GuiConfig struct {
// WrapMainPanel determines whether we use word wrap on the main panel // WrapMainPanel determines whether we use word wrap on the main panel
WrapMainPanel bool `yaml:"wrapMainPanel,omitempty"` WrapMainPanel bool `yaml:"wrapMainPanel,omitempty"`
// LegacySortContainers determines if containers should be sorted using legacy approach.
// By default, containers are now sorted by status. This setting allows users to
// use legacy behaviour instead.
LegacySortContainers bool `yaml:"legacySortContainers,omitempty"`
} }
// CommandTemplatesConfig determines what commands actually get called when we // CommandTemplatesConfig determines what commands actually get called when we
@ -319,6 +324,7 @@ func GetDefaultConfig() UserConfig {
ShowAllContainers: false, ShowAllContainers: false,
ReturnImmediately: false, ReturnImmediately: false,
WrapMainPanel: false, WrapMainPanel: false,
LegacySortContainers: false,
}, },
ConfirmOnQuit: false, ConfirmOnQuit: false,
CommandTemplates: CommandTemplatesConfig{ CommandTemplates: CommandTemplatesConfig{

View file

@ -82,6 +82,7 @@ type TranslationSet struct {
RunCustomCommand string RunCustomCommand string
ViewBulkCommands string ViewBulkCommands string
OpenInBrowser string OpenInBrowser string
SortContainersByState string
LogsTitle string LogsTitle string
ConfigTitle string ConfigTitle string
@ -152,6 +153,7 @@ func englishSet() TranslationSet {
RunCustomCommand: "run predefined custom command", RunCustomCommand: "run predefined custom command",
ViewBulkCommands: "view bulk commands", ViewBulkCommands: "view bulk commands",
OpenInBrowser: "open in browser (first port is http)", OpenInBrowser: "open in browser (first port is http)",
SortContainersByState: "sort containers by state",
GlobalTitle: "Global", GlobalTitle: "Global",
MainTitle: "Main", MainTitle: "Main",