mirror of
https://github.com/jesseduffield/lazydocker.git
synced 2026-07-25 08:31:03 +00:00
move context stuff into its own struct
This commit is contained in:
parent
c6d424e4a4
commit
5d498c796a
9 changed files with 281 additions and 257 deletions
|
|
@ -22,58 +22,58 @@ func (gui *Gui) getContainersPanel() *SideListPanel[*commands.Container] {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return !lo.SomeBy(gui.Panels.Services.list.GetAllItems(), func(service *commands.Service) bool {
|
return !lo.SomeBy(gui.Panels.Services.List.GetAllItems(), func(service *commands.Service) bool {
|
||||||
return service.Name == container.ServiceName
|
return service.Name == container.ServiceName
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return &SideListPanel[*commands.Container]{
|
return &SideListPanel[*commands.Container]{
|
||||||
contextKeyPrefix: "containers",
|
ContextState: &ContextState[*commands.Container]{
|
||||||
|
GetContexts: func() []ContextConfig[*commands.Container] {
|
||||||
|
return []ContextConfig[*commands.Container]{
|
||||||
|
{
|
||||||
|
key: "logs",
|
||||||
|
title: gui.Tr.LogsTitle,
|
||||||
|
render: gui.renderContainerLogsToMain,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "stats",
|
||||||
|
title: gui.Tr.StatsTitle,
|
||||||
|
render: gui.renderContainerStats,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "env",
|
||||||
|
title: gui.Tr.EnvTitle,
|
||||||
|
render: gui.renderContainerEnv,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "config",
|
||||||
|
title: gui.Tr.ConfigTitle,
|
||||||
|
render: gui.renderContainerConfig,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "top",
|
||||||
|
title: gui.Tr.TopTitle,
|
||||||
|
render: gui.renderContainerTop,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
GetContextCacheKey: func(container *commands.Container) string {
|
||||||
|
return "containers-" + container.ID + "-" + container.Container.State
|
||||||
|
},
|
||||||
|
},
|
||||||
ListPanel: ListPanel[*commands.Container]{
|
ListPanel: ListPanel[*commands.Container]{
|
||||||
list: NewFilteredList[*commands.Container](),
|
List: NewFilteredList[*commands.Container](),
|
||||||
view: gui.Views.Containers,
|
view: gui.Views.Containers,
|
||||||
},
|
},
|
||||||
contextIdx: 0,
|
NoItemsMessage: gui.Tr.NoContainers,
|
||||||
noItemsMessage: gui.Tr.NoContainers,
|
|
||||||
gui: gui.intoInterface(),
|
gui: gui.intoInterface(),
|
||||||
getContexts: func() []ContextConfig[*commands.Container] {
|
|
||||||
return []ContextConfig[*commands.Container]{
|
|
||||||
{
|
|
||||||
key: "logs",
|
|
||||||
title: gui.Tr.LogsTitle,
|
|
||||||
render: gui.renderContainerLogsToMain,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "stats",
|
|
||||||
title: gui.Tr.StatsTitle,
|
|
||||||
render: gui.renderContainerStats,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "env",
|
|
||||||
title: gui.Tr.EnvTitle,
|
|
||||||
render: gui.renderContainerEnv,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "config",
|
|
||||||
title: gui.Tr.ConfigTitle,
|
|
||||||
render: gui.renderContainerConfig,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "top",
|
|
||||||
title: gui.Tr.TopTitle,
|
|
||||||
render: gui.renderContainerTop,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getContextCacheKey: func(container *commands.Container) string {
|
|
||||||
return container.ID + "-" + container.Container.State
|
|
||||||
},
|
|
||||||
// sortedContainers returns containers sorted by state if c.SortContainersByState is true (follows 1- running, 2- exited, 3- created)
|
// 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
|
// and sorted by name if c.SortContainersByState is false
|
||||||
sort: func(a *commands.Container, b *commands.Container) bool {
|
Sort: func(a *commands.Container, b *commands.Container) bool {
|
||||||
return sortContainers(a, b, gui.Config.UserConfig.Gui.LegacySortContainers)
|
return sortContainers(a, b, gui.Config.UserConfig.Gui.LegacySortContainers)
|
||||||
},
|
},
|
||||||
filter: func(container *commands.Container) bool {
|
Filter: func(container *commands.Container) bool {
|
||||||
// Note that this is O(N*M) time complexity where N is the number of services
|
// Note that this is O(N*M) time complexity where N is the number of services
|
||||||
// and M is the number of containers. We expect N to be small but M may be large,
|
// and M is the number of containers. We expect N to be small but M may be large,
|
||||||
// so we will need to keep an eye on this.
|
// so we will need to keep an eye on this.
|
||||||
|
|
@ -87,7 +87,7 @@ func (gui *Gui) getContainersPanel() *SideListPanel[*commands.Container] {
|
||||||
|
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
getDisplayStrings: func(container *commands.Container) []string {
|
GetDisplayStrings: func(container *commands.Container) []string {
|
||||||
image := strings.TrimPrefix(container.Container.Image, "sha256:")
|
image := strings.TrimPrefix(container.Container.Image, "sha256:")
|
||||||
|
|
||||||
return []string{
|
return []string{
|
||||||
|
|
@ -261,12 +261,12 @@ func (gui *Gui) refreshContainersAndServices() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// keep track of current service selected so that we can reposition our cursor if it moves position in the list
|
// keep track of current service selected so that we can reposition our cursor if it moves position in the list
|
||||||
originalSelectedLineIdx := gui.Panels.Services.selectedIdx
|
originalSelectedLineIdx := gui.Panels.Services.SelectedIdx
|
||||||
selectedService, isServiceSelected := gui.Panels.Services.list.TryGet(originalSelectedLineIdx)
|
selectedService, isServiceSelected := gui.Panels.Services.List.TryGet(originalSelectedLineIdx)
|
||||||
|
|
||||||
containers, services, err := gui.DockerCommand.RefreshContainersAndServices(
|
containers, services, err := gui.DockerCommand.RefreshContainersAndServices(
|
||||||
gui.Panels.Services.list.GetAllItems(),
|
gui.Panels.Services.List.GetAllItems(),
|
||||||
gui.Panels.Containers.list.GetAllItems(),
|
gui.Panels.Containers.List.GetAllItems(),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -277,7 +277,7 @@ func (gui *Gui) refreshContainersAndServices() error {
|
||||||
|
|
||||||
// see if our selected service has moved
|
// see if our selected service has moved
|
||||||
if isServiceSelected {
|
if isServiceSelected {
|
||||||
for i, service := range gui.Panels.Services.list.GetItems() {
|
for i, service := range gui.Panels.Services.List.GetItems() {
|
||||||
if service.ID == selectedService.ID {
|
if service.ID == selectedService.ID {
|
||||||
if i == originalSelectedLineIdx {
|
if i == originalSelectedLineIdx {
|
||||||
break
|
break
|
||||||
|
|
@ -484,7 +484,7 @@ func (gui *Gui) handleContainersCustomCommand(g *gocui.Gui, v *gocui.View) error
|
||||||
func (gui *Gui) handleStopContainers() error {
|
func (gui *Gui) handleStopContainers() error {
|
||||||
return gui.createConfirmationPanel(gui.Tr.Confirm, gui.Tr.ConfirmStopContainers, func(g *gocui.Gui, v *gocui.View) error {
|
return gui.createConfirmationPanel(gui.Tr.Confirm, gui.Tr.ConfirmStopContainers, func(g *gocui.Gui, v *gocui.View) error {
|
||||||
return gui.WithWaitingStatus(gui.Tr.StoppingStatus, func() error {
|
return gui.WithWaitingStatus(gui.Tr.StoppingStatus, func() error {
|
||||||
for _, container := range gui.Panels.Containers.list.GetAllItems() {
|
for _, container := range gui.Panels.Containers.List.GetAllItems() {
|
||||||
if err := container.Stop(); err != nil {
|
if err := container.Stop(); err != nil {
|
||||||
gui.Log.Error(err)
|
gui.Log.Error(err)
|
||||||
}
|
}
|
||||||
|
|
@ -498,7 +498,7 @@ func (gui *Gui) handleStopContainers() error {
|
||||||
func (gui *Gui) handleRemoveContainers() error {
|
func (gui *Gui) handleRemoveContainers() error {
|
||||||
return gui.createConfirmationPanel(gui.Tr.Confirm, gui.Tr.ConfirmRemoveContainers, func(g *gocui.Gui, v *gocui.View) error {
|
return gui.createConfirmationPanel(gui.Tr.Confirm, gui.Tr.ConfirmRemoveContainers, func(g *gocui.Gui, v *gocui.View) error {
|
||||||
return gui.WithWaitingStatus(gui.Tr.RemovingStatus, func() error {
|
return gui.WithWaitingStatus(gui.Tr.RemovingStatus, func() error {
|
||||||
for _, container := range gui.Panels.Containers.list.GetAllItems() {
|
for _, container := range gui.Panels.Containers.List.GetAllItems() {
|
||||||
if err := container.Remove(types.ContainerRemoveOptions{Force: true}); err != nil {
|
if err := container.Remove(types.ContainerRemoveOptions{Force: true}); err != nil {
|
||||||
gui.Log.Error(err)
|
gui.Log.Error(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -269,7 +269,7 @@ func (gui *Gui) Run() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) updateContainerDetails() error {
|
func (gui *Gui) updateContainerDetails() error {
|
||||||
return gui.DockerCommand.UpdateContainerDetails(gui.Panels.Containers.list.GetAllItems())
|
return gui.DockerCommand.UpdateContainerDetails(gui.Panels.Containers.List.GetAllItems())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) refresh() {
|
func (gui *Gui) refresh() {
|
||||||
|
|
@ -455,7 +455,7 @@ func (gui *Gui) monitorContainerStats(ctx context.Context) {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return
|
return
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
for _, container := range gui.Panels.Containers.list.GetAllItems() {
|
for _, container := range gui.Panels.Containers.List.GetAllItems() {
|
||||||
if !container.MonitoringStats {
|
if !container.MonitoringStats {
|
||||||
go gui.DockerCommand.CreateClientStatMonitor(container)
|
go gui.DockerCommand.CreateClientStatMonitor(container)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,29 +18,29 @@ func (gui *Gui) getImagesPanel() *SideListPanel[*commands.Image] {
|
||||||
noneLabel := "<none>"
|
noneLabel := "<none>"
|
||||||
|
|
||||||
return &SideListPanel[*commands.Image]{
|
return &SideListPanel[*commands.Image]{
|
||||||
contextKeyPrefix: "images",
|
ContextState: &ContextState[*commands.Image]{
|
||||||
|
GetContexts: func() []ContextConfig[*commands.Image] {
|
||||||
|
return []ContextConfig[*commands.Image]{
|
||||||
|
{
|
||||||
|
key: "config",
|
||||||
|
title: gui.Tr.ConfigTitle,
|
||||||
|
render: func(image *commands.Image) error {
|
||||||
|
return gui.renderImageConfig(image)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
GetContextCacheKey: func(image *commands.Image) string {
|
||||||
|
return "images-" + image.ID
|
||||||
|
},
|
||||||
|
},
|
||||||
ListPanel: ListPanel[*commands.Image]{
|
ListPanel: ListPanel[*commands.Image]{
|
||||||
list: NewFilteredList[*commands.Image](),
|
List: NewFilteredList[*commands.Image](),
|
||||||
view: gui.Views.Images,
|
view: gui.Views.Images,
|
||||||
},
|
},
|
||||||
contextIdx: 0,
|
NoItemsMessage: gui.Tr.NoImages,
|
||||||
noItemsMessage: gui.Tr.NoImages,
|
|
||||||
gui: gui.intoInterface(),
|
gui: gui.intoInterface(),
|
||||||
getContexts: func() []ContextConfig[*commands.Image] {
|
Sort: func(a *commands.Image, b *commands.Image) bool {
|
||||||
return []ContextConfig[*commands.Image]{
|
|
||||||
{
|
|
||||||
key: "config",
|
|
||||||
title: gui.Tr.ConfigTitle,
|
|
||||||
render: func(image *commands.Image) error {
|
|
||||||
return gui.renderImageConfig(image)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getContextCacheKey: func(image *commands.Image) string {
|
|
||||||
return image.ID
|
|
||||||
},
|
|
||||||
sort: func(a *commands.Image, b *commands.Image) bool {
|
|
||||||
if a.Name == noneLabel && b.Name != noneLabel {
|
if a.Name == noneLabel && b.Name != noneLabel {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -59,7 +59,7 @@ func (gui *Gui) getImagesPanel() *SideListPanel[*commands.Image] {
|
||||||
|
|
||||||
return a.ID < b.ID
|
return a.ID < b.ID
|
||||||
},
|
},
|
||||||
getDisplayStrings: func(image *commands.Image) []string {
|
GetDisplayStrings: func(image *commands.Image) []string {
|
||||||
return []string{
|
return []string{
|
||||||
image.Name,
|
image.Name,
|
||||||
image.Tag,
|
image.Tag,
|
||||||
|
|
|
||||||
|
|
@ -514,7 +514,7 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, panel := range gui.allListPanels() {
|
for _, panel := range gui.allListPanels() {
|
||||||
setUpDownClickBindings(panel.View().Name(), panel.OnPrevLine, panel.OnNextLine, panel.OnClick)
|
setUpDownClickBindings(panel.View().Name(), panel.HandlePrevLine, panel.HandleNextLine, panel.HandleClick)
|
||||||
}
|
}
|
||||||
|
|
||||||
setUpDownClickBindings("main", gui.scrollUpMain, gui.scrollDownMain, gui.handleMainClick)
|
setUpDownClickBindings("main", gui.scrollUpMain, gui.scrollDownMain, gui.handleMainClick)
|
||||||
|
|
@ -532,14 +532,14 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
|
||||||
ViewName: panel.View().Name(),
|
ViewName: panel.View().Name(),
|
||||||
Key: '[',
|
Key: '[',
|
||||||
Modifier: gocui.ModNone,
|
Modifier: gocui.ModNone,
|
||||||
Handler: wrappedHandler(panel.OnPrevContext),
|
Handler: wrappedHandler(panel.HandlePrevContext),
|
||||||
Description: gui.Tr.PreviousContext,
|
Description: gui.Tr.PreviousContext,
|
||||||
},
|
},
|
||||||
&Binding{
|
&Binding{
|
||||||
ViewName: panel.View().Name(),
|
ViewName: panel.View().Name(),
|
||||||
Key: ']',
|
Key: ']',
|
||||||
Modifier: gocui.ModNone,
|
Modifier: gocui.ModNone,
|
||||||
Handler: wrappedHandler(panel.OnNextContext),
|
Handler: wrappedHandler(panel.HandleNextContext),
|
||||||
Description: gui.Tr.NextContext,
|
Description: gui.Tr.NextContext,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -12,31 +12,31 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type ListPanel[T comparable] struct {
|
type ListPanel[T comparable] struct {
|
||||||
selectedIdx int
|
SelectedIdx int
|
||||||
list *FilteredList[T]
|
List *FilteredList[T]
|
||||||
view *gocui.View
|
view *gocui.View
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ListPanel[T]) setSelectedLineIdx(value int) {
|
func (self *ListPanel[T]) setSelectedLineIdx(value int) {
|
||||||
clampedValue := 0
|
clampedValue := 0
|
||||||
if self.list.Len() > 0 {
|
if self.List.Len() > 0 {
|
||||||
clampedValue = lcUtils.Clamp(value, 0, self.list.Len()-1)
|
clampedValue = lcUtils.Clamp(value, 0, self.List.Len()-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.selectedIdx = clampedValue
|
self.SelectedIdx = clampedValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ListPanel[T]) clampSelectedLineIdx() {
|
func (self *ListPanel[T]) clampSelectedLineIdx() {
|
||||||
clamped := lcUtils.Clamp(self.selectedIdx, 0, self.list.Len()-1)
|
clamped := lcUtils.Clamp(self.SelectedIdx, 0, self.List.Len()-1)
|
||||||
|
|
||||||
if clamped != self.selectedIdx {
|
if clamped != self.SelectedIdx {
|
||||||
self.selectedIdx = clamped
|
self.SelectedIdx = clamped
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// moves the cursor up or down by the given amount (up for negative values)
|
// moves the cursor up or down by the given amount (up for negative values)
|
||||||
func (self *ListPanel[T]) moveSelectedLine(delta int) {
|
func (self *ListPanel[T]) moveSelectedLine(delta int) {
|
||||||
self.setSelectedLineIdx(self.selectedIdx + delta)
|
self.setSelectedLineIdx(self.SelectedIdx + delta)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ListPanel[T]) SelectNextLine() {
|
func (self *ListPanel[T]) SelectNextLine() {
|
||||||
|
|
@ -47,39 +47,42 @@ func (self *ListPanel[T]) SelectPrevLine() {
|
||||||
self.moveSelectedLine(-1)
|
self.moveSelectedLine(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ContextState[T any] struct {
|
||||||
|
contextIdx int
|
||||||
|
// contexts []ContextConfig[T]
|
||||||
|
GetContexts func() []ContextConfig[T]
|
||||||
|
// this tells us whether we need to re-render to the main panel
|
||||||
|
GetContextCacheKey func(item T) string
|
||||||
|
}
|
||||||
|
|
||||||
// list panel at the side of the screen that renders content to the main panel
|
// list panel at the side of the screen that renders content to the main panel
|
||||||
type SideListPanel[T comparable] struct {
|
type SideListPanel[T comparable] struct {
|
||||||
contextKeyPrefix string
|
ContextState *ContextState[T]
|
||||||
contextIdx int
|
|
||||||
// contexts []ContextConfig[T]
|
|
||||||
getContexts func() []ContextConfig[T]
|
|
||||||
// this tells us whether we need to re-render to the main panel
|
|
||||||
getContextCacheKey func(item T) string
|
|
||||||
|
|
||||||
ListPanel[T]
|
ListPanel[T]
|
||||||
|
|
||||||
// message to render in the main view if there are no items in the panel
|
// message to render in the main view if there are no items in the panel
|
||||||
// and it has focus. Leave empty if you don't want to render anything
|
// and it has focus. Leave empty if you don't want to render anything
|
||||||
noItemsMessage string
|
NoItemsMessage string
|
||||||
|
|
||||||
gui IGui
|
gui IGui
|
||||||
|
|
||||||
// this filter is applied on top of additional default filters
|
// this Filter is applied on top of additional default filters
|
||||||
filter func(T) bool
|
Filter func(T) bool
|
||||||
sort func(a, b T) bool
|
Sort func(a, b T) bool
|
||||||
|
|
||||||
onClick func(T) error
|
OnClick func(T) error
|
||||||
|
|
||||||
getDisplayStrings func(T) []string
|
GetDisplayStrings func(T) []string
|
||||||
|
|
||||||
// function to be called after re-rendering list. Can be nil
|
// function to be called after re-rendering list. Can be nil
|
||||||
onRerender func() error
|
OnRerender func() error
|
||||||
|
|
||||||
// set this to true if you don't want to allow manual filtering via '/'
|
// set this to true if you don't want to allow manual filtering via '/'
|
||||||
disableFilter bool
|
DisableFilter bool
|
||||||
|
|
||||||
// This can be nil if you want to always show the panel
|
// This can be nil if you want to always show the panel
|
||||||
hide func() bool
|
Hide func() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type ISideListPanel interface {
|
type ISideListPanel interface {
|
||||||
|
|
@ -90,11 +93,11 @@ type ISideListPanel interface {
|
||||||
RerenderList() error
|
RerenderList() error
|
||||||
IsFilterDisabled() bool
|
IsFilterDisabled() bool
|
||||||
IsHidden() bool
|
IsHidden() bool
|
||||||
OnNextLine() error
|
HandleNextLine() error
|
||||||
OnPrevLine() error
|
HandlePrevLine() error
|
||||||
OnClick() error
|
HandleClick() error
|
||||||
OnPrevContext() error
|
HandlePrevContext() error
|
||||||
OnNextContext() error
|
HandleNextContext() error
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ ISideListPanel = &SideListPanel[int]{}
|
var _ ISideListPanel = &SideListPanel[int]{}
|
||||||
|
|
@ -122,19 +125,19 @@ func (gui *Gui) intoInterface() IGui {
|
||||||
return gui
|
return gui
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SideListPanel[T]) OnClick() error {
|
func (self *SideListPanel[T]) HandleClick() error {
|
||||||
itemCount := self.list.Len()
|
itemCount := self.List.Len()
|
||||||
handleSelect := self.HandleSelect
|
handleSelect := self.HandleSelect
|
||||||
selectedLine := &self.selectedIdx
|
selectedLine := &self.SelectedIdx
|
||||||
|
|
||||||
if err := self.gui.HandleClick(self.view, itemCount, selectedLine, handleSelect); err != nil {
|
if err := self.gui.HandleClick(self.view, itemCount, selectedLine, handleSelect); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.onClick != nil {
|
if self.OnClick != nil {
|
||||||
selectedItem, err := self.GetSelectedItem()
|
selectedItem, err := self.GetSelectedItem()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return self.onClick(selectedItem)
|
return self.OnClick(selectedItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -148,12 +151,12 @@ func (self *SideListPanel[T]) View() *gocui.View {
|
||||||
func (self *SideListPanel[T]) HandleSelect() error {
|
func (self *SideListPanel[T]) HandleSelect() error {
|
||||||
item, err := self.GetSelectedItem()
|
item, err := self.GetSelectedItem()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err.Error() != self.noItemsMessage {
|
if err.Error() != self.NoItemsMessage {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.noItemsMessage != "" {
|
if self.NoItemsMessage != "" {
|
||||||
return self.gui.RenderStringMain(self.noItemsMessage)
|
return self.gui.RenderStringMain(self.NoItemsMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -165,97 +168,119 @@ func (self *SideListPanel[T]) HandleSelect() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SideListPanel[T]) renderContext(item T) error {
|
func (self *SideListPanel[T]) renderContext(item T) error {
|
||||||
contexts := self.getContexts()
|
if self.ContextState == nil {
|
||||||
|
|
||||||
if len(contexts) == 0 {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
key := self.contextKeyPrefix + "-" + self.getContextCacheKey(item) + "-" + contexts[self.contextIdx].key
|
key := self.ContextState.GetCurrentContextKey(item)
|
||||||
if !self.gui.ShouldRefresh(key) {
|
if !self.gui.ShouldRefresh(key) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
mainView := self.gui.GetMainView()
|
mainView := self.gui.GetMainView()
|
||||||
mainView.Tabs = self.GetContextTitles()
|
mainView.Tabs = self.ContextState.GetContextTitles()
|
||||||
mainView.TabIndex = self.contextIdx
|
mainView.TabIndex = self.ContextState.contextIdx
|
||||||
|
|
||||||
return contexts[self.contextIdx].render(item)
|
return self.ContextState.GetCurrentContext().render(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SideListPanel[T]) GetContextTitles() []string {
|
func (self *ContextState[T]) GetContextTitles() []string {
|
||||||
return lo.Map(self.getContexts(), func(context ContextConfig[T], _ int) string {
|
return lo.Map(self.GetContexts(), func(context ContextConfig[T], _ int) string {
|
||||||
return context.title
|
return context.title
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *ContextState[T]) GetCurrentContextKey(item T) string {
|
||||||
|
return self.GetContextCacheKey(item) + "-" + self.GetCurrentContext().key
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ContextState[T]) GetCurrentContext() ContextConfig[T] {
|
||||||
|
return self.GetContexts()[self.contextIdx]
|
||||||
|
}
|
||||||
|
|
||||||
func (self *SideListPanel[T]) GetSelectedItem() (T, error) {
|
func (self *SideListPanel[T]) GetSelectedItem() (T, error) {
|
||||||
var zero T
|
var zero T
|
||||||
|
|
||||||
item, ok := self.list.TryGet(self.selectedIdx)
|
item, ok := self.List.TryGet(self.SelectedIdx)
|
||||||
if !ok {
|
if !ok {
|
||||||
// could probably have a better error here
|
// could probably have a better error here
|
||||||
return zero, errors.New(self.noItemsMessage)
|
return zero, errors.New(self.NoItemsMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
return item, nil
|
return item, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SideListPanel[T]) OnNextLine() error {
|
func (self *SideListPanel[T]) HandleNextLine() error {
|
||||||
self.SelectNextLine()
|
self.SelectNextLine()
|
||||||
|
|
||||||
return self.HandleSelect()
|
return self.HandleSelect()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SideListPanel[T]) OnPrevLine() error {
|
func (self *SideListPanel[T]) HandlePrevLine() error {
|
||||||
self.SelectPrevLine()
|
self.SelectPrevLine()
|
||||||
|
|
||||||
return self.HandleSelect()
|
return self.HandleSelect()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SideListPanel[T]) OnNextContext() error {
|
func (self *ContextState[T]) HandleNextContext() {
|
||||||
contexts := self.getContexts()
|
contexts := self.GetContexts()
|
||||||
|
|
||||||
if len(contexts) == 0 {
|
if len(contexts) == 0 {
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
self.contextIdx = (self.contextIdx + 1) % len(contexts)
|
self.contextIdx = (self.contextIdx + 1) % len(contexts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ContextState[T]) HandlePrevContext() {
|
||||||
|
contexts := self.GetContexts()
|
||||||
|
|
||||||
|
if len(contexts) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.contextIdx = (self.contextIdx - 1 + len(contexts)) % len(contexts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SideListPanel[T]) HandleNextContext() error {
|
||||||
|
if self.ContextState == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ContextState.HandleNextContext()
|
||||||
|
|
||||||
return self.HandleSelect()
|
return self.HandleSelect()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SideListPanel[T]) OnPrevContext() error {
|
func (self *SideListPanel[T]) HandlePrevContext() error {
|
||||||
contexts := self.getContexts()
|
if self.ContextState == nil {
|
||||||
|
|
||||||
if len(contexts) == 0 {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
self.contextIdx = (self.contextIdx - 1 + len(contexts)) % len(contexts)
|
self.ContextState.HandlePrevContext()
|
||||||
|
|
||||||
return self.HandleSelect()
|
return self.HandleSelect()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SideListPanel[T]) Refocus() {
|
func (self *SideListPanel[T]) Refocus() {
|
||||||
self.gui.FocusY(self.selectedIdx, self.list.Len(), self.view)
|
self.gui.FocusY(self.SelectedIdx, self.List.Len(), self.view)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SideListPanel[T]) SetItems(items []T) {
|
func (self *SideListPanel[T]) SetItems(items []T) {
|
||||||
self.list.SetItems(items)
|
self.List.SetItems(items)
|
||||||
self.FilterAndSort()
|
self.FilterAndSort()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SideListPanel[T]) FilterAndSort() {
|
func (self *SideListPanel[T]) FilterAndSort() {
|
||||||
filterString := self.gui.FilterString(self.view)
|
filterString := self.gui.FilterString(self.view)
|
||||||
|
|
||||||
self.list.Filter(func(item T, index int) bool {
|
self.List.Filter(func(item T, index int) bool {
|
||||||
if self.filter != nil && !self.filter(item) {
|
if self.Filter != nil && !self.Filter(item) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if lo.SomeBy(self.gui.IgnoreStrings(), func(ignore string) bool {
|
if lo.SomeBy(self.gui.IgnoreStrings(), func(ignore string) bool {
|
||||||
return lo.SomeBy(self.getDisplayStrings(item), func(searchString string) bool {
|
return lo.SomeBy(self.GetDisplayStrings(item), func(searchString string) bool {
|
||||||
return strings.Contains(searchString, ignore)
|
return strings.Contains(searchString, ignore)
|
||||||
})
|
})
|
||||||
}) {
|
}) {
|
||||||
|
|
@ -263,7 +288,7 @@ func (self *SideListPanel[T]) FilterAndSort() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if filterString != "" {
|
if filterString != "" {
|
||||||
return lo.SomeBy(self.getDisplayStrings(item), func(searchString string) bool {
|
return lo.SomeBy(self.GetDisplayStrings(item), func(searchString string) bool {
|
||||||
return strings.Contains(searchString, filterString)
|
return strings.Contains(searchString, filterString)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -271,7 +296,7 @@ func (self *SideListPanel[T]) FilterAndSort() {
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
self.list.Sort(self.sort)
|
self.List.Sort(self.Sort)
|
||||||
|
|
||||||
self.clampSelectedLineIdx()
|
self.clampSelectedLineIdx()
|
||||||
}
|
}
|
||||||
|
|
@ -281,8 +306,8 @@ func (self *SideListPanel[T]) RerenderList() error {
|
||||||
|
|
||||||
self.gui.Update(func() error {
|
self.gui.Update(func() error {
|
||||||
self.view.Clear()
|
self.view.Clear()
|
||||||
table := lo.Map(self.list.GetItems(), func(item T, index int) []string {
|
table := lo.Map(self.List.GetItems(), func(item T, index int) []string {
|
||||||
return self.getDisplayStrings(item)
|
return self.GetDisplayStrings(item)
|
||||||
})
|
})
|
||||||
renderedTable, err := utils.RenderTable(table)
|
renderedTable, err := utils.RenderTable(table)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -290,8 +315,8 @@ func (self *SideListPanel[T]) RerenderList() error {
|
||||||
}
|
}
|
||||||
fmt.Fprint(self.view, renderedTable)
|
fmt.Fprint(self.view, renderedTable)
|
||||||
|
|
||||||
if self.onRerender != nil {
|
if self.OnRerender != nil {
|
||||||
if err := self.onRerender(); err != nil {
|
if err := self.OnRerender(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -306,17 +331,25 @@ func (self *SideListPanel[T]) RerenderList() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SideListPanel[T]) SetContextIndex(index int) {
|
func (self *SideListPanel[T]) SetContextIndex(index int) {
|
||||||
|
if self.ContextState == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ContextState.SetContextIndex(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ContextState[T]) SetContextIndex(index int) {
|
||||||
self.contextIdx = index
|
self.contextIdx = index
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SideListPanel[T]) IsFilterDisabled() bool {
|
func (self *SideListPanel[T]) IsFilterDisabled() bool {
|
||||||
return self.disableFilter
|
return self.DisableFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SideListPanel[T]) IsHidden() bool {
|
func (self *SideListPanel[T]) IsHidden() bool {
|
||||||
if self.hide == nil {
|
if self.Hide == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.hide()
|
return self.Hide()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,35 +25,24 @@ type CreateMenuOptions struct {
|
||||||
func (gui *Gui) getMenuPanel() *SideListPanel[*MenuItem] {
|
func (gui *Gui) getMenuPanel() *SideListPanel[*MenuItem] {
|
||||||
return &SideListPanel[*MenuItem]{
|
return &SideListPanel[*MenuItem]{
|
||||||
ListPanel: ListPanel[*MenuItem]{
|
ListPanel: ListPanel[*MenuItem]{
|
||||||
list: NewFilteredList[*MenuItem](),
|
List: NewFilteredList[*MenuItem](),
|
||||||
view: gui.Views.Menu,
|
view: gui.Views.Menu,
|
||||||
},
|
},
|
||||||
noItemsMessage: "",
|
NoItemsMessage: "",
|
||||||
gui: gui.intoInterface(),
|
gui: gui.intoInterface(),
|
||||||
onClick: gui.onMenuPress,
|
OnClick: gui.onMenuPress,
|
||||||
sort: nil,
|
Sort: nil,
|
||||||
getDisplayStrings: func(menuItem *MenuItem) []string {
|
GetDisplayStrings: func(menuItem *MenuItem) []string {
|
||||||
return menuItem.LabelColumns
|
return menuItem.LabelColumns
|
||||||
},
|
},
|
||||||
onRerender: func() error {
|
OnRerender: func() error {
|
||||||
return gui.resizePopupPanel(gui.Views.Menu)
|
return gui.resizePopupPanel(gui.Views.Menu)
|
||||||
},
|
},
|
||||||
// so that we can avoid some UI trickiness, the menu will not have filtering
|
// so that we can avoid some UI trickiness, the menu will not have filtering
|
||||||
// abillity yet. To support it, we would need to have filter state against
|
// abillity yet. To support it, we would need to have filter state against
|
||||||
// each panel (e.g. for when you filter the images panel, then bring up
|
// each panel (e.g. for when you filter the images panel, then bring up
|
||||||
// the options menu, then try to filter that too.
|
// the options menu, then try to filter that too.
|
||||||
disableFilter: true,
|
DisableFilter: true,
|
||||||
|
|
||||||
// the menu panel doesn't actually have any contexts to display on the main view
|
|
||||||
// so what follows are all dummy values
|
|
||||||
contextKeyPrefix: "menu",
|
|
||||||
contextIdx: 0,
|
|
||||||
getContextCacheKey: func(menuItem *MenuItem) string {
|
|
||||||
return ""
|
|
||||||
},
|
|
||||||
getContexts: func() []ContextConfig[*MenuItem] {
|
|
||||||
return []ContextConfig[*MenuItem]{}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,54 +17,56 @@ import (
|
||||||
|
|
||||||
func (gui *Gui) getProjectPanel() *SideListPanel[*commands.Project] {
|
func (gui *Gui) getProjectPanel() *SideListPanel[*commands.Project] {
|
||||||
return &SideListPanel[*commands.Project]{
|
return &SideListPanel[*commands.Project]{
|
||||||
contextKeyPrefix: "project",
|
ContextState: &ContextState[*commands.Project]{
|
||||||
ListPanel: ListPanel[*commands.Project]{
|
GetContexts: func() []ContextConfig[*commands.Project] {
|
||||||
list: NewFilteredList[*commands.Project](),
|
if gui.DockerCommand.InDockerComposeProject {
|
||||||
view: gui.Views.Project,
|
return []ContextConfig[*commands.Project]{
|
||||||
},
|
{
|
||||||
contextIdx: 0,
|
key: "logs",
|
||||||
noItemsMessage: "",
|
title: gui.Tr.LogsTitle,
|
||||||
gui: gui.intoInterface(),
|
render: gui.renderAllLogs,
|
||||||
getContexts: func() []ContextConfig[*commands.Project] {
|
},
|
||||||
if gui.DockerCommand.InDockerComposeProject {
|
{
|
||||||
|
key: "config",
|
||||||
|
title: gui.Tr.DockerComposeConfigTitle,
|
||||||
|
render: gui.renderDockerComposeConfig,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "credits",
|
||||||
|
title: gui.Tr.CreditsTitle,
|
||||||
|
render: gui.renderCredits,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return []ContextConfig[*commands.Project]{
|
return []ContextConfig[*commands.Project]{
|
||||||
{
|
|
||||||
key: "logs",
|
|
||||||
title: gui.Tr.LogsTitle,
|
|
||||||
render: gui.renderAllLogs,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "config",
|
|
||||||
title: gui.Tr.DockerComposeConfigTitle,
|
|
||||||
render: gui.renderDockerComposeConfig,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: "credits",
|
key: "credits",
|
||||||
title: gui.Tr.CreditsTitle,
|
title: gui.Tr.CreditsTitle,
|
||||||
render: gui.renderCredits,
|
render: gui.renderCredits,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
GetContextCacheKey: func(project *commands.Project) string {
|
||||||
|
return "projects-" + project.Name
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
return []ContextConfig[*commands.Project]{
|
ListPanel: ListPanel[*commands.Project]{
|
||||||
{
|
List: NewFilteredList[*commands.Project](),
|
||||||
key: "credits",
|
view: gui.Views.Project,
|
||||||
title: gui.Tr.CreditsTitle,
|
|
||||||
render: gui.renderCredits,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
getContextCacheKey: func(project *commands.Project) string {
|
NoItemsMessage: "",
|
||||||
return project.Name
|
gui: gui.intoInterface(),
|
||||||
},
|
|
||||||
sort: func(a *commands.Project, b *commands.Project) bool {
|
Sort: func(a *commands.Project, b *commands.Project) bool {
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
getDisplayStrings: func(project *commands.Project) []string {
|
GetDisplayStrings: func(project *commands.Project) []string {
|
||||||
return []string{project.Name}
|
return []string{project.Name}
|
||||||
},
|
},
|
||||||
// It doesn't make sense to filter a list of only one item.
|
// It doesn't make sense to filter a list of only one item.
|
||||||
disableFilter: true,
|
DisableFilter: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,7 +78,7 @@ func (gui *Gui) refreshProject() error {
|
||||||
func (gui *Gui) getProjectName() string {
|
func (gui *Gui) getProjectName() string {
|
||||||
projectName := path.Base(gui.Config.ProjectDir)
|
projectName := path.Base(gui.Config.ProjectDir)
|
||||||
if gui.DockerCommand.InDockerComposeProject {
|
if gui.DockerCommand.InDockerComposeProject {
|
||||||
for _, service := range gui.Panels.Services.list.GetAllItems() {
|
for _, service := range gui.Panels.Services.List.GetAllItems() {
|
||||||
container := service.Container
|
container := service.Container
|
||||||
if container != nil && container.DetailsLoaded() {
|
if container != nil && container.DetailsLoaded() {
|
||||||
return container.Details.Config.Labels["com.docker.compose.project"]
|
return container.Details.Config.Labels["com.docker.compose.project"]
|
||||||
|
|
|
||||||
|
|
@ -14,52 +14,52 @@ import (
|
||||||
|
|
||||||
func (gui *Gui) getServicesPanel() *SideListPanel[*commands.Service] {
|
func (gui *Gui) getServicesPanel() *SideListPanel[*commands.Service] {
|
||||||
return &SideListPanel[*commands.Service]{
|
return &SideListPanel[*commands.Service]{
|
||||||
contextKeyPrefix: "services",
|
ContextState: &ContextState[*commands.Service]{
|
||||||
|
GetContexts: func() []ContextConfig[*commands.Service] {
|
||||||
|
return []ContextConfig[*commands.Service]{
|
||||||
|
{
|
||||||
|
key: "logs",
|
||||||
|
title: gui.Tr.LogsTitle,
|
||||||
|
render: gui.renderServiceLogs,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "stats",
|
||||||
|
title: gui.Tr.StatsTitle,
|
||||||
|
render: gui.renderServiceStats,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "container-env",
|
||||||
|
title: gui.Tr.ContainerEnvTitle,
|
||||||
|
render: gui.renderServiceContainerEnv,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "container-config",
|
||||||
|
title: gui.Tr.ContainerConfigTitle,
|
||||||
|
render: gui.renderServiceContainerConfig,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "top",
|
||||||
|
title: gui.Tr.TopTitle,
|
||||||
|
render: gui.renderServiceTop,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
GetContextCacheKey: func(service *commands.Service) string {
|
||||||
|
if service.Container == nil {
|
||||||
|
return "services-" + service.ID
|
||||||
|
}
|
||||||
|
return "services-" + service.ID + "-" + service.Container.ID + "-" + service.Container.Container.State
|
||||||
|
},
|
||||||
|
},
|
||||||
ListPanel: ListPanel[*commands.Service]{
|
ListPanel: ListPanel[*commands.Service]{
|
||||||
list: NewFilteredList[*commands.Service](),
|
List: NewFilteredList[*commands.Service](),
|
||||||
view: gui.Views.Services,
|
view: gui.Views.Services,
|
||||||
},
|
},
|
||||||
contextIdx: 0,
|
|
||||||
// TODO: i18n
|
// TODO: i18n
|
||||||
noItemsMessage: "no service selected",
|
NoItemsMessage: "no service selected",
|
||||||
gui: gui.intoInterface(),
|
gui: gui.intoInterface(),
|
||||||
getContexts: func() []ContextConfig[*commands.Service] {
|
|
||||||
return []ContextConfig[*commands.Service]{
|
|
||||||
{
|
|
||||||
key: "logs",
|
|
||||||
title: gui.Tr.LogsTitle,
|
|
||||||
render: gui.renderServiceLogs,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "stats",
|
|
||||||
title: gui.Tr.StatsTitle,
|
|
||||||
render: gui.renderServiceStats,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "container-env",
|
|
||||||
title: gui.Tr.ContainerEnvTitle,
|
|
||||||
render: gui.renderServiceContainerEnv,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "container-config",
|
|
||||||
title: gui.Tr.ContainerConfigTitle,
|
|
||||||
render: gui.renderServiceContainerConfig,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "top",
|
|
||||||
title: gui.Tr.TopTitle,
|
|
||||||
render: gui.renderServiceTop,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getContextCacheKey: func(service *commands.Service) string {
|
|
||||||
if service.Container == nil {
|
|
||||||
return service.ID
|
|
||||||
}
|
|
||||||
return service.ID + "-" + service.Container.ID + "-" + service.Container.Container.State
|
|
||||||
},
|
|
||||||
// sort services first by whether they have a linked container, and second by alphabetical order
|
// sort services first by whether they have a linked container, and second by alphabetical order
|
||||||
sort: func(a *commands.Service, b *commands.Service) bool {
|
Sort: func(a *commands.Service, b *commands.Service) bool {
|
||||||
if a.Container != nil && b.Container == nil {
|
if a.Container != nil && b.Container == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -70,7 +70,7 @@ func (gui *Gui) getServicesPanel() *SideListPanel[*commands.Service] {
|
||||||
|
|
||||||
return a.Name < b.Name
|
return a.Name < b.Name
|
||||||
},
|
},
|
||||||
getDisplayStrings: func(service *commands.Service) []string {
|
GetDisplayStrings: func(service *commands.Service) []string {
|
||||||
if service.Container == nil {
|
if service.Container == nil {
|
||||||
return []string{
|
return []string{
|
||||||
utils.ColoredString("none", color.FgBlue),
|
utils.ColoredString("none", color.FgBlue),
|
||||||
|
|
@ -90,7 +90,7 @@ func (gui *Gui) getServicesPanel() *SideListPanel[*commands.Service] {
|
||||||
utils.ColoredString(cont.DisplayPorts(), color.FgYellow),
|
utils.ColoredString(cont.DisplayPorts(), color.FgYellow),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
hide: func() bool {
|
Hide: func() bool {
|
||||||
return !gui.DockerCommand.InDockerComposeProject
|
return !gui.DockerCommand.InDockerComposeProject
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,30 +13,30 @@ import (
|
||||||
|
|
||||||
func (gui *Gui) getVolumesPanel() *SideListPanel[*commands.Volume] {
|
func (gui *Gui) getVolumesPanel() *SideListPanel[*commands.Volume] {
|
||||||
return &SideListPanel[*commands.Volume]{
|
return &SideListPanel[*commands.Volume]{
|
||||||
contextKeyPrefix: "volumes",
|
ContextState: &ContextState[*commands.Volume]{
|
||||||
|
GetContexts: func() []ContextConfig[*commands.Volume] {
|
||||||
|
return []ContextConfig[*commands.Volume]{
|
||||||
|
{
|
||||||
|
key: "config",
|
||||||
|
title: gui.Tr.ConfigTitle,
|
||||||
|
render: gui.renderVolumeConfig,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
GetContextCacheKey: func(volume *commands.Volume) string {
|
||||||
|
return "volumes-" + volume.Name
|
||||||
|
},
|
||||||
|
},
|
||||||
ListPanel: ListPanel[*commands.Volume]{
|
ListPanel: ListPanel[*commands.Volume]{
|
||||||
list: NewFilteredList[*commands.Volume](),
|
List: NewFilteredList[*commands.Volume](),
|
||||||
view: gui.Views.Volumes,
|
view: gui.Views.Volumes,
|
||||||
},
|
},
|
||||||
contextIdx: 0,
|
NoItemsMessage: gui.Tr.NoVolumes,
|
||||||
noItemsMessage: gui.Tr.NoVolumes,
|
|
||||||
gui: gui.intoInterface(),
|
gui: gui.intoInterface(),
|
||||||
getContexts: func() []ContextConfig[*commands.Volume] {
|
|
||||||
return []ContextConfig[*commands.Volume]{
|
|
||||||
{
|
|
||||||
key: "config",
|
|
||||||
title: gui.Tr.ConfigTitle,
|
|
||||||
render: gui.renderVolumeConfig,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getContextCacheKey: func(volume *commands.Volume) string {
|
|
||||||
return volume.Name
|
|
||||||
},
|
|
||||||
// we're sorting these volumes based on whether they have labels defined,
|
// we're sorting these volumes based on whether they have labels defined,
|
||||||
// because those are the ones you typically care about.
|
// because those are the ones you typically care about.
|
||||||
// Within that, we also sort them alphabetically
|
// Within that, we also sort them alphabetically
|
||||||
sort: func(a *commands.Volume, b *commands.Volume) bool {
|
Sort: func(a *commands.Volume, b *commands.Volume) bool {
|
||||||
if len(a.Volume.Labels) == 0 && len(b.Volume.Labels) > 0 {
|
if len(a.Volume.Labels) == 0 && len(b.Volume.Labels) > 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -45,7 +45,7 @@ func (gui *Gui) getVolumesPanel() *SideListPanel[*commands.Volume] {
|
||||||
}
|
}
|
||||||
return a.Name < b.Name
|
return a.Name < b.Name
|
||||||
},
|
},
|
||||||
getDisplayStrings: func(volume *commands.Volume) []string {
|
GetDisplayStrings: func(volume *commands.Volume) []string {
|
||||||
return []string{volume.Volume.Driver, volume.Name}
|
return []string{volume.Volume.Driver, volume.Name}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue