diff --git a/cmd/environment.go b/cmd/environment.go index 458039e..3e978f3 100644 --- a/cmd/environment.go +++ b/cmd/environment.go @@ -31,6 +31,7 @@ var InteractiveEnvironment = func(ctx context.Context, input views.EnvironmentIn }, e.Name) }, tui.WithCustomOptions[*client.Environment]([]tui.CustomOption{ + WithCopyID(ctx, servicesCmd), WithWorkspaceSelection(ctx), }), )) diff --git a/cmd/logs.go b/cmd/logs.go index 15163bc..e0bb142 100644 --- a/cmd/logs.go +++ b/cmd/logs.go @@ -106,6 +106,7 @@ func InteractiveLogs(ctx context.Context, input views.LogInput, breadcrumb strin func getLogsOptions(ctx context.Context, breadcrumb string) []tui.CustomOption { return []tui.CustomOption{ + WithCopyID(ctx, servicesCmd), WithWorkspaceSelection(ctx), WithProjectFilter(ctx, servicesCmd, "Project Filter", &views.LogInput{}, func(ctx context.Context, project *client.Project) tea.Cmd { logInput := views.LogInput{} diff --git a/cmd/options.go b/cmd/options.go index 300c678..c65306d 100644 --- a/cmd/options.go +++ b/cmd/options.go @@ -2,7 +2,9 @@ package cmd import ( "context" + "fmt" + "github.com/atotto/clipboard" tea "github.com/charmbracelet/bubbletea" btable "github.com/evertras/bubble-table/table" "github.com/spf13/cobra" @@ -23,6 +25,32 @@ func WithWorkspaceSelection(ctx context.Context) tui.CustomOption { } } +func WithCopyID(ctx context.Context, cmd *cobra.Command) tui.CustomOption { + return tui.CustomOption{ + Key: "c", + Title: "Copy ID", + Function: func(row btable.Row) tea.Cmd { + return func() tea.Msg { + id, ok := row.Data["ID"] + if !ok { + return nil + } + + idstr, ok := id.(string) + if !ok { + return nil + } + + err := clipboard.WriteAll(idstr) + if err != nil { + return command.AddErrToStack(ctx, cmd, fmt.Errorf("could not copy to clipboard: %w", err)) + } + return nil + } + }, + } +} + type ProjectHandler func(ctx context.Context, project *client.Project) tea.Cmd func WithProjectFilter(ctx context.Context, cmd *cobra.Command, breadcrumb string, in any, h ProjectHandler) tui.CustomOption { diff --git a/cmd/pgcli.go b/cmd/pgcli.go index a15701c..f247df8 100644 --- a/cmd/pgcli.go +++ b/cmd/pgcli.go @@ -35,6 +35,7 @@ func InteractivePGCLIView(ctx context.Context, input *views.PSQLInput) tea.Cmd { func getPGCLITableOptions(ctx context.Context, input *views.PSQLInput) []tui.CustomOption { return []tui.CustomOption{ + WithCopyID(ctx, servicesCmd), WithWorkspaceSelection(ctx), WithProjectFilter(ctx, pgcliCmd, "pgcli", input, func(ctx context.Context, project *client.Project) tea.Cmd { if project != nil { diff --git a/cmd/project.go b/cmd/project.go index 61d1ae8..9c0b3d2 100644 --- a/cmd/project.go +++ b/cmd/project.go @@ -34,6 +34,7 @@ var InteractiveProjectList = func(ctx context.Context) { }, p.Name) }, tui.WithCustomOptions[*client.Project]([]tui.CustomOption{ + WithCopyID(ctx, servicesCmd), WithWorkspaceSelection(ctx), }), )) diff --git a/cmd/psql.go b/cmd/psql.go index 3c5ef2f..d060b12 100644 --- a/cmd/psql.go +++ b/cmd/psql.go @@ -35,6 +35,7 @@ func InteractivePSQLView(ctx context.Context, input *views.PSQLInput) tea.Cmd { func getPsqlTableOptions(ctx context.Context, input *views.PSQLInput) []tui.CustomOption { return []tui.CustomOption{ + WithCopyID(ctx, servicesCmd), WithWorkspaceSelection(ctx), WithProjectFilter(ctx, psqlCmd, "psql", input, func(ctx context.Context, project *client.Project) tea.Cmd { if project != nil { diff --git a/cmd/rediscli.go b/cmd/rediscli.go index 77a4441..7e03904 100644 --- a/cmd/rediscli.go +++ b/cmd/rediscli.go @@ -34,6 +34,7 @@ func InteractiveRedisView(ctx context.Context, input *views.RedisCLIInput) tea.C func getRedisTableOptions(ctx context.Context) []tui.CustomOption { return []tui.CustomOption{ + WithCopyID(ctx, servicesCmd), WithWorkspaceSelection(ctx), WithProjectFilter(ctx, redisCLICmd, "redisCLI", &views.RedisCLIInput{}, func(ctx context.Context, project *client.Project) tea.Cmd { input := &views.RedisCLIInput{} diff --git a/cmd/service.go b/cmd/service.go index f04ce33..ae939a4 100644 --- a/cmd/service.go +++ b/cmd/service.go @@ -189,6 +189,7 @@ func InteractiveServices(ctx context.Context, in views.ListResourceInput, breadc func getServiceTableOptions(ctx context.Context) []tui.CustomOption { return []tui.CustomOption{ + WithCopyID(ctx, servicesCmd), WithWorkspaceSelection(ctx), WithProjectFilter(ctx, servicesCmd, "Project Filter", &views.ListResourceInput{}, func(ctx context.Context, project *client.Project) tea.Cmd { listResourceInput := views.ListResourceInput{} diff --git a/cmd/ssh.go b/cmd/ssh.go index 89048e9..a5ef3e9 100644 --- a/cmd/ssh.go +++ b/cmd/ssh.go @@ -35,6 +35,7 @@ func InteractiveSSHView(ctx context.Context, input *views.SSHInput, breadcrumb s func getSSHTableOptions(ctx context.Context, breadcrumb string) []tui.CustomOption { return []tui.CustomOption{ + WithCopyID(ctx, servicesCmd), WithWorkspaceSelection(ctx), WithProjectFilter(ctx, servicesCmd, "Project Filter", &views.SSHInput{}, func(ctx context.Context, project *client.Project) tea.Cmd { input := views.SSHInput{} diff --git a/pkg/tui/stack.go b/pkg/tui/stack.go index e8b858b..7184fc8 100644 --- a/pkg/tui/stack.go +++ b/pkg/tui/stack.go @@ -88,6 +88,10 @@ func (m *StackModel) Push(model ModelWithCmd) tea.Cmd { return tea.Sequence(model.Model.Init(), tea.WindowSize()) } +func (m *StackModel) PushError(err error) tea.Cmd { + return m.Push(ModelWithCmd{Model: NewErrorModel(err)}) +} + func (m *StackModel) Pop() *ModelWithCmd { if len(m.stack) > 0 { popped := m.stack[len(m.stack)-1] @@ -138,7 +142,7 @@ func (m *StackModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if len(m.stack) > 0 { err := clipboard.WriteAll(m.stack[len(m.stack)-1].Cmd) if err != nil { - m.Push(ModelWithCmd{Model: NewErrorModel(fmt.Errorf("Failed to copy command to clipboard"))}) + m.PushError(fmt.Errorf("Failed to copy command to clipboard")) } } }