mirror of
https://github.com/jesseduffield/lazydocker.git
synced 2026-07-23 15:41:02 +00:00
POC filtering on images panel
This commit is contained in:
parent
023370e357
commit
be347a7216
9 changed files with 125 additions and 8 deletions
|
|
@ -103,7 +103,7 @@ func (i *Image) RenderHistory() (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RefreshImages returns a slice of docker images
|
// RefreshImages returns a slice of docker images
|
||||||
func (c *DockerCommand) RefreshImages() ([]*Image, error) {
|
func (c *DockerCommand) RefreshImages(filterString string) ([]*Image, error) {
|
||||||
images, err := c.Client.ImageList(context.Background(), types.ImageListOptions{})
|
images, err := c.Client.ImageList(context.Background(), types.ImageListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -151,6 +151,12 @@ func (c *DockerCommand) RefreshImages() ([]*Image, error) {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if filterString != "" {
|
||||||
|
ownImages = lo.Filter(ownImages, func(image *Image, _ int) bool {
|
||||||
|
return strings.Contains(image.Name, filterString)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
noneLabel := "<none>"
|
noneLabel := "<none>"
|
||||||
|
|
||||||
sort.Slice(ownImages, func(i, j int) bool {
|
sort.Slice(ownImages, func(i, j int) bool {
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ func (gui *Gui) getWindowDimensions(informationStr string, appStatus string) map
|
||||||
sidePanelsDirection = boxlayout.ROW
|
sidePanelsDirection = boxlayout.ROW
|
||||||
}
|
}
|
||||||
|
|
||||||
showInfoSection := gui.Config.UserConfig.Gui.ShowBottomLine
|
showInfoSection := gui.Config.UserConfig.Gui.ShowBottomLine || gui.State.Searching.isSearching
|
||||||
infoSectionSize := 0
|
infoSectionSize := 0
|
||||||
if showInfoSection {
|
if showInfoSection {
|
||||||
infoSectionSize = 1
|
infoSectionSize = 1
|
||||||
|
|
@ -87,6 +87,19 @@ func (gui *Gui) getMidSectionWeights() (int, int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) infoSectionChildren(informationStr string, appStatus string) []*boxlayout.Box {
|
func (gui *Gui) infoSectionChildren(informationStr string, appStatus string) []*boxlayout.Box {
|
||||||
|
if gui.State.Searching.isSearching {
|
||||||
|
return []*boxlayout.Box{
|
||||||
|
{
|
||||||
|
Window: "searchPrefix",
|
||||||
|
Size: runewidth.StringWidth(SEARCH_PREFIX),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Window: "search",
|
||||||
|
Weight: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
result := []*boxlayout.Box{}
|
result := []*boxlayout.Box{}
|
||||||
|
|
||||||
if len(appStatus) > 0 {
|
if len(appStatus) > 0 {
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,14 @@ type guiState struct {
|
||||||
Stats map[string]commands.ContainerStats
|
Stats map[string]commands.ContainerStats
|
||||||
|
|
||||||
ScreenMode WindowMaximisation
|
ScreenMode WindowMaximisation
|
||||||
|
|
||||||
|
Searching searchingState
|
||||||
|
}
|
||||||
|
|
||||||
|
type searchingState struct {
|
||||||
|
view *gocui.View
|
||||||
|
isSearching bool
|
||||||
|
searchString string
|
||||||
}
|
}
|
||||||
|
|
||||||
// screen sizing determines how much space your selected window takes up (window
|
// screen sizing determines how much space your selected window takes up (window
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@ func (gui *Gui) refreshImages() error {
|
||||||
|
|
||||||
// TODO: leave this to DockerCommand
|
// TODO: leave this to DockerCommand
|
||||||
func (gui *Gui) refreshStateImages() error {
|
func (gui *Gui) refreshStateImages() error {
|
||||||
Images, err := gui.DockerCommand.RefreshImages()
|
Images, err := gui.DockerCommand.RefreshImages(gui.filterString(gui.Views.Images))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -144,6 +144,14 @@ func (gui *Gui) refreshStateImages() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) filterString(view *gocui.View) string {
|
||||||
|
if gui.State.Searching.view != view {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return gui.State.Searching.searchString
|
||||||
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleImagesNextLine(g *gocui.Gui, v *gocui.View) error {
|
func (gui *Gui) handleImagesNextLine(g *gocui.Gui, v *gocui.View) error {
|
||||||
if gui.popupPanelFocused() || gui.g.CurrentView() != v {
|
if gui.popupPanelFocused() || gui.g.CurrentView() != v {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -443,6 +443,13 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||||
Handler: gui.handleImagesBulkCommand,
|
Handler: gui.handleImagesBulkCommand,
|
||||||
Description: gui.Tr.ViewBulkCommands,
|
Description: gui.Tr.ViewBulkCommands,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
ViewName: "images",
|
||||||
|
Key: '/',
|
||||||
|
Modifier: gocui.ModNone,
|
||||||
|
Handler: wrappedHandler(gui.handleOpenImageSearch),
|
||||||
|
Description: gui.Tr.FilterList,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
ViewName: "volumes",
|
ViewName: "volumes",
|
||||||
Key: '[',
|
Key: '[',
|
||||||
|
|
|
||||||
32
pkg/gui/searching.go
Normal file
32
pkg/gui/searching.go
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
package gui
|
||||||
|
|
||||||
|
import "github.com/jesseduffield/gocui"
|
||||||
|
|
||||||
|
func (gui *Gui) handleOpenImageSearch() error {
|
||||||
|
return gui.handleOpenSearch(gui.Views.Images)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) handleOpenSearch(view *gocui.View) error {
|
||||||
|
gui.State.Searching.isSearching = true
|
||||||
|
gui.State.Searching.view = view
|
||||||
|
|
||||||
|
gui.Views.Search.ClearTextArea()
|
||||||
|
|
||||||
|
return gui.switchFocus(gui.Views.Search)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) onNewSearchString(value string) error {
|
||||||
|
// need to refresh the right list panel.
|
||||||
|
gui.State.Searching.searchString = value
|
||||||
|
return gui.refreshImages()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) wrapEditor(f func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool) func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool {
|
||||||
|
return func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool {
|
||||||
|
matched := f(v, key, ch, mod)
|
||||||
|
if matched {
|
||||||
|
gui.onNewSearchString(v.TextArea.GetContent())
|
||||||
|
}
|
||||||
|
return matched
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -89,6 +89,8 @@ func (gui *Gui) newLineFocused(v *gocui.View) error {
|
||||||
case "main":
|
case "main":
|
||||||
v.Highlight = false
|
v.Highlight = false
|
||||||
return nil
|
return nil
|
||||||
|
case "search":
|
||||||
|
return nil
|
||||||
default:
|
default:
|
||||||
panic(gui.Tr.NoViewMachingNewLineFocusedSwitchStatement)
|
panic(gui.Tr.NoViewMachingNewLineFocusedSwitchStatement)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,21 +5,34 @@ import (
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const SEARCH_PREFIX = "filter: "
|
||||||
|
|
||||||
type Views struct {
|
type Views struct {
|
||||||
|
// side panels
|
||||||
Project *gocui.View
|
Project *gocui.View
|
||||||
Services *gocui.View
|
Services *gocui.View
|
||||||
Containers *gocui.View
|
Containers *gocui.View
|
||||||
Images *gocui.View
|
Images *gocui.View
|
||||||
Volumes *gocui.View
|
Volumes *gocui.View
|
||||||
|
|
||||||
|
// main panel
|
||||||
Main *gocui.View
|
Main *gocui.View
|
||||||
|
|
||||||
Options *gocui.View
|
// bottom line
|
||||||
|
Options *gocui.View
|
||||||
|
Information *gocui.View
|
||||||
|
AppStatus *gocui.View
|
||||||
|
// text that prompts you to enter text in the Search view
|
||||||
|
SearchPrefix *gocui.View
|
||||||
|
// appears next to the SearchPrefix view, it's where you type in the search string
|
||||||
|
Search *gocui.View
|
||||||
|
|
||||||
|
// popups
|
||||||
Confirmation *gocui.View
|
Confirmation *gocui.View
|
||||||
Menu *gocui.View
|
Menu *gocui.View
|
||||||
Information *gocui.View
|
|
||||||
AppStatus *gocui.View
|
// will cover everything when it appears
|
||||||
Limit *gocui.View
|
Limit *gocui.View
|
||||||
}
|
}
|
||||||
|
|
||||||
type viewNameMapping struct {
|
type viewNameMapping struct {
|
||||||
|
|
@ -43,6 +56,8 @@ func (gui *Gui) orderedViewNameMappings() []viewNameMapping {
|
||||||
{viewPtr: &gui.Views.Options, name: "options"},
|
{viewPtr: &gui.Views.Options, name: "options"},
|
||||||
{viewPtr: &gui.Views.AppStatus, name: "appStatus"},
|
{viewPtr: &gui.Views.AppStatus, name: "appStatus"},
|
||||||
{viewPtr: &gui.Views.Information, name: "information"},
|
{viewPtr: &gui.Views.Information, name: "information"},
|
||||||
|
{viewPtr: &gui.Views.Search, name: "search"},
|
||||||
|
{viewPtr: &gui.Views.SearchPrefix, name: "searchPrefix"},
|
||||||
|
|
||||||
// popups.
|
// popups.
|
||||||
{viewPtr: &gui.Views.Menu, name: "menu"},
|
{viewPtr: &gui.Views.Menu, name: "menu"},
|
||||||
|
|
@ -113,6 +128,17 @@ func (gui *Gui) createAllViews() error {
|
||||||
gui.Views.Limit.Title = gui.Tr.NotEnoughSpace
|
gui.Views.Limit.Title = gui.Tr.NotEnoughSpace
|
||||||
gui.Views.Limit.Wrap = true
|
gui.Views.Limit.Wrap = true
|
||||||
|
|
||||||
|
gui.Views.SearchPrefix.BgColor = gocui.ColorDefault
|
||||||
|
gui.Views.SearchPrefix.FgColor = gocui.ColorGreen
|
||||||
|
gui.Views.SearchPrefix.Frame = false
|
||||||
|
_ = gui.setViewContent(gui.Views.SearchPrefix, SEARCH_PREFIX)
|
||||||
|
|
||||||
|
gui.Views.Search.BgColor = gocui.ColorDefault
|
||||||
|
gui.Views.Search.FgColor = gocui.ColorGreen
|
||||||
|
gui.Views.Search.Editable = true
|
||||||
|
gui.Views.Search.Frame = false
|
||||||
|
// gui.Views.Search.Editor = gocui.EditorFunc(gui.wrapEditor(gocui.SimpleEditor))
|
||||||
|
|
||||||
gui.waitForIntro.Done()
|
gui.waitForIntro.Done()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -134,5 +160,18 @@ func (gui *Gui) popupViewNames() []string {
|
||||||
|
|
||||||
// these views have their position and size determined by arrangement.go
|
// these views have their position and size determined by arrangement.go
|
||||||
func (gui *Gui) controlledBoundsViewNames() []string {
|
func (gui *Gui) controlledBoundsViewNames() []string {
|
||||||
return []string{"project", "services", "containers", "images", "volumes", "options", "information", "appStatus", "main", "limit"}
|
return []string{
|
||||||
|
"project",
|
||||||
|
"services",
|
||||||
|
"containers",
|
||||||
|
"images",
|
||||||
|
"volumes",
|
||||||
|
"options",
|
||||||
|
"information",
|
||||||
|
"appStatus",
|
||||||
|
"main",
|
||||||
|
"limit",
|
||||||
|
"searchPrefix",
|
||||||
|
"search",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,7 @@ type TranslationSet struct {
|
||||||
ExecShell string
|
ExecShell string
|
||||||
RunCustomCommand string
|
RunCustomCommand string
|
||||||
ViewBulkCommands string
|
ViewBulkCommands string
|
||||||
|
FilterList string
|
||||||
OpenInBrowser string
|
OpenInBrowser string
|
||||||
SortContainersByState string
|
SortContainersByState string
|
||||||
|
|
||||||
|
|
@ -190,6 +191,7 @@ func englishSet() TranslationSet {
|
||||||
ExecShell: "exec shell",
|
ExecShell: "exec shell",
|
||||||
RunCustomCommand: "run predefined custom command",
|
RunCustomCommand: "run predefined custom command",
|
||||||
ViewBulkCommands: "view bulk commands",
|
ViewBulkCommands: "view bulk commands",
|
||||||
|
FilterList: "filter list",
|
||||||
OpenInBrowser: "open in browser (first port is http)",
|
OpenInBrowser: "open in browser (first port is http)",
|
||||||
SortContainersByState: "sort containers by state",
|
SortContainersByState: "sort containers by state",
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue