diff --git a/docs/keybindings/Keybindings_de.md b/docs/keybindings/Keybindings_de.md index da130058..7b680e86 100644 --- a/docs/keybindings/Keybindings_de.md +++ b/docs/keybindings/Keybindings_de.md @@ -16,7 +16,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Container
- : copy container id + y: copy container ID d: entfernen e: hide/show stopped containers p: pause diff --git a/docs/keybindings/Keybindings_en.md b/docs/keybindings/Keybindings_en.md index 09679c2d..1179da36 100644 --- a/docs/keybindings/Keybindings_en.md +++ b/docs/keybindings/Keybindings_en.md @@ -16,7 +16,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Containers- : copy container id + y: copy container ID d: remove e: hide/show stopped containers p: pause diff --git a/docs/keybindings/Keybindings_es.md b/docs/keybindings/Keybindings_es.md index 02065ea0..4c3e0138 100644 --- a/docs/keybindings/Keybindings_es.md +++ b/docs/keybindings/Keybindings_es.md @@ -16,7 +16,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Contenedores- : copy container id + y: copy container ID d: borrar e: esconder/mostrar contenedores parados p: pausa diff --git a/docs/keybindings/Keybindings_fr.md b/docs/keybindings/Keybindings_fr.md index c69006ce..c33a9275 100644 --- a/docs/keybindings/Keybindings_fr.md +++ b/docs/keybindings/Keybindings_fr.md @@ -16,7 +16,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Conteneurs- : copy container id + y: copy container ID d: supprimer e: cacher/montrer les conteneurs arrêtés p: pause diff --git a/docs/keybindings/Keybindings_nl.md b/docs/keybindings/Keybindings_nl.md index d17b91d3..f8963d88 100644 --- a/docs/keybindings/Keybindings_nl.md +++ b/docs/keybindings/Keybindings_nl.md @@ -16,7 +16,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Containers- : copy container id + y: copy container ID d: verwijder e: verberg gestopte containers p: pause diff --git a/docs/keybindings/Keybindings_pl.md b/docs/keybindings/Keybindings_pl.md index 974c52aa..533d8691 100644 --- a/docs/keybindings/Keybindings_pl.md +++ b/docs/keybindings/Keybindings_pl.md @@ -16,7 +16,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Kontenery- : copy container id + y: copy container ID d: usuń e: hide/show stopped containers p: pause diff --git a/docs/keybindings/Keybindings_pt.md b/docs/keybindings/Keybindings_pt.md index 079be7cd..76c73583 100644 --- a/docs/keybindings/Keybindings_pt.md +++ b/docs/keybindings/Keybindings_pt.md @@ -16,7 +16,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Contêineres- : copy container id + y: copy container ID d: remover e: ocultar/mostrar contêineres parados p: pausar diff --git a/docs/keybindings/Keybindings_tr.md b/docs/keybindings/Keybindings_tr.md index e9f5e1e2..9c012d48 100644 --- a/docs/keybindings/Keybindings_tr.md +++ b/docs/keybindings/Keybindings_tr.md @@ -16,7 +16,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Konteynerler- : copy container id + y: copy container ID d: kaldır e: hide/show stopped containers p: pause diff --git a/docs/keybindings/Keybindings_zh.md b/docs/keybindings/Keybindings_zh.md index 1c3553c0..57af67a8 100644 --- a/docs/keybindings/Keybindings_zh.md +++ b/docs/keybindings/Keybindings_zh.md @@ -16,7 +16,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## 容器- : copy container id + y: copy container ID d: 移除 e: 隐藏/显示已停止的容器 p: 暂停 diff --git a/pkg/commands/os.go b/pkg/commands/os.go index 5128b1bf..620de164 100644 --- a/pkg/commands/os.go +++ b/pkg/commands/os.go @@ -381,5 +381,13 @@ func (c *OSCommand) CopyToClipboard(str string) error { c.Log.Debug(utils.ResolvePlaceholderString("Copying '{{str}}' to clipboard", map[string]string{"str": truncated})) + // Not needed yet + //if c.UserConfig().OS.CopyToClipboardCmd != "" { + // cmdStr := utils.ResolvePlaceholderString(c.UserConfig().OS.CopyToClipboardCmd, map[string]string{ + // "text": c.Cmd.Quote(str), + // }) + // return c.Cmd.NewShell(cmdStr).Run() + //} + return clipboard.WriteAll(str) } diff --git a/pkg/gui/app_status_manager.go b/pkg/gui/app_status_manager.go index f58b6915..e6e4ec09 100644 --- a/pkg/gui/app_status_manager.go +++ b/pkg/gui/app_status_manager.go @@ -1,7 +1,6 @@ package gui import ( - "sync" "time" "github.com/jesseduffield/gocui" @@ -16,15 +15,14 @@ type appStatus struct { type statusManager struct { statuses []appStatus - lock *sync.Mutex } +const ( + TickIntervalMs = 50 +) + func (m *statusManager) removeStatus(name string) { newStatuses := []appStatus{} - - m.lock.Lock() - defer m.lock.Unlock() - for _, status := range m.statuses { if status.name != name { newStatuses = append(newStatuses, status) @@ -33,61 +31,40 @@ func (m *statusManager) removeStatus(name string) { m.statuses = newStatuses } -func (m *statusManager) addWaitingStatus(name string) { - m.lock.Lock() - defer m.lock.Unlock() - +func (m *statusManager) addStatus(name string, statusType string, duration int) { m.removeStatus(name) newStatus := appStatus{ name: name, - statusType: "waiting", - duration: 0, + statusType: statusType, + duration: duration, } m.statuses = append([]appStatus{newStatus}, m.statuses...) } func (m *statusManager) getStatusString() string { - m.lock.Lock() - defer m.lock.Unlock() - if len(m.statuses) == 0 { return "" } + topStatus := m.statuses[0] if topStatus.statusType == "waiting" { return topStatus.name + " " + utils.Loader() + } else if topStatus.statusType == "info" { + return topStatus.name } - return topStatus.name -} -// WithStaticWaitingStatus shows a waiting status for a specific duration -func (gui *Gui) WithStaticWaitingStatus(name string, duration time.Duration) error { - return gui.WithWaitingStatus(name, func() error { time.Sleep(duration); return nil }) + return topStatus.name } // WithWaitingStatus wraps a function and shows a waiting status while the function is still executing func (gui *Gui) WithWaitingStatus(name string, f func() error) error { go func() { - gui.statusManager.addWaitingStatus(name) + go gui.Notify(name, "waiting", 0)() defer func() { gui.statusManager.removeStatus(name) }() - go func() { - ticker := time.NewTicker(time.Millisecond * 50) - defer ticker.Stop() - for range ticker.C { - appStatus := gui.statusManager.getStatusString() - if appStatus == "" { - return - } - if err := gui.renderString(gui.g, "appStatus", appStatus); err != nil { - gui.Log.Warn(err) - } - } - }() - if err := f(); err != nil { gui.g.Update(func(g *gocui.Gui) error { return gui.createErrorPanel(err.Error()) @@ -97,3 +74,37 @@ func (gui *Gui) WithWaitingStatus(name string, f func() error) error { return nil } + +// Notify sends static notification to the user. +// duration of 0 will disable the self-cleaning of the notification +func (gui *Gui) Notify(name string, statusType string, duration int) func() { + return func() { + gui.statusManager.addStatus(name, statusType, duration) + + defer func() { + gui.statusManager.removeStatus(name) + }() + + ticker := time.NewTicker(time.Millisecond * TickIntervalMs) + tickCount := 0 + endTick := duration * 1000 / TickIntervalMs + + defer ticker.Stop() + for range ticker.C { + tickCount++ + // If no duration, don't terminate early + if duration > 0 && tickCount >= endTick { + return + } + + appStatus := gui.statusManager.getStatusString() + if appStatus == "" { + return + } + + if err := gui.renderString(gui.g, "appStatus", appStatus); err != nil { + gui.Log.Warn(err) + } + } + } +} diff --git a/pkg/gui/containers_panel.go b/pkg/gui/containers_panel.go index f8dc9b08..6006c467 100644 --- a/pkg/gui/containers_panel.go +++ b/pkg/gui/containers_panel.go @@ -252,8 +252,10 @@ 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 + gui.DockerCommand.ServiceMutex.Lock() originalSelectedLineIdx := gui.Panels.Services.SelectedIdx selectedService, isServiceSelected := gui.Panels.Services.List.TryGet(originalSelectedLineIdx) + gui.DockerCommand.ServiceMutex.Unlock() containers, services, err := gui.DockerCommand.RefreshContainersAndServices( gui.Panels.Services.List.GetAllItems(), @@ -364,10 +366,8 @@ func (gui *Gui) handleCopyContainerId(g *gocui.Gui, v *gocui.View) error { return nil } - err = gui.WithStaticWaitingStatus(fmt.Sprintf(gui.Tr.CopyContainerIdStatus, utils.TruncateWithEllipsis(ctr.ID, 10)), time.Second*2) - if err != nil { - return err - } + formattedStatusText := fmt.Sprintf("Copied %s to clipboard", utils.TruncateWithEllipsis(ctr.ID, 10)) + go gui.Notify(formattedStatusText, "info", 3)() return gui.OSCommand.CopyToClipboard(ctr.ID) } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 8bfebf76..fa6199f3 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -4,7 +4,6 @@ import ( "context" "os" "strings" - "sync" "time" "github.com/docker/docker/api/types/events" @@ -147,11 +146,9 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand State: initialState, Config: config, Tr: tr, - statusManager: &statusManager{ - lock: &sync.Mutex{}, - }, - taskManager: tasks.NewTaskManager(log, tr), - ErrorChan: errorChan, + statusManager: &statusManager{}, + taskManager: tasks.NewTaskManager(log, tr), + ErrorChan: errorChan, } deadlock.Opts.Disable = !gui.Config.Debug diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 56c37845..fda0de25 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -187,7 +187,7 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { }, { ViewName: "containers", - Key: gocui.KeyCtrlO, + Key: 'y', Modifier: gocui.ModNone, Handler: gui.handleCopyContainerId, Description: gui.Tr.CopyContainerId, diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 88828752..36ac5e68 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -67,8 +67,6 @@ type TranslationSet struct { ViewLogs string UpProject string DownProject string - CopyContainerId string - CopyContainerIdStatus string ServicesTitle string ContainersTitle string StandaloneContainersTitle string @@ -111,6 +109,7 @@ type TranslationSet struct { FilterList string OpenInBrowser string SortContainersByState string + CopyContainerId string LogsTitle string ConfigTitle string @@ -199,8 +198,6 @@ func englishSet() TranslationSet { ViewLogs: "view logs", UpProject: "up project", DownProject: "down project", - CopyContainerId: "copy container id", - CopyContainerIdStatus: "Copied %s to clipboard", RemoveImage: "remove image", RemoveVolume: "remove volume", RemoveNetwork: "remove network", @@ -220,6 +217,7 @@ func englishSet() TranslationSet { FilterList: "filter list", OpenInBrowser: "open in browser (first port is http)", SortContainersByState: "sort containers by state", + CopyContainerId: "copy container ID", GlobalTitle: "Global", MainTitle: "Main",