diff --git a/internal/resources/orchestration/stackevents/commands.go b/internal/resources/orchestration/stackevents/commands.go index d807b56..5d4c351 100644 --- a/internal/resources/orchestration/stackevents/commands.go +++ b/internal/resources/orchestration/stackevents/commands.go @@ -20,14 +20,7 @@ func (r *Resource) show(row resource.Row) tea.Cmd { stackID := row.Fields["stack_id"] resourceName := row.Fields["resource"] - event, err := stackevents.Get( - context.Background(), - client, - stackName, - stackID, - resourceName, - row.ID, - ).Extract() + event, err := stackevents.Get(context.Background(), client, stackName, stackID, resourceName, row.ID).Extract() if err != nil { return resource.DetailsMsg{ Err: fmt.Errorf("getting stack event %q: %w", row.ID, err), @@ -40,3 +33,17 @@ func (r *Resource) show(row resource.Row) tea.Cmd { } } } + +func (r *Resource) reason(row resource.Row) tea.Cmd { + reason := row.Fields["reason"] + if len(reason) < ReasonColumnLength { + return r.show(row) + } + + return func() tea.Msg { + return resource.DetailsMsg{ + ID: row.ID, + Content: reason, + } + } +} diff --git a/internal/resources/orchestration/stackevents/stackevents.go b/internal/resources/orchestration/stackevents/stackevents.go index 241cd37..68984e0 100644 --- a/internal/resources/orchestration/stackevents/stackevents.go +++ b/internal/resources/orchestration/stackevents/stackevents.go @@ -32,12 +32,14 @@ func (r *Resource) Aliases() []string { } } +const ReasonColumnLength = 50 + func (r *Resource) Columns() []resource.Column { return []resource.Column{ {Key: "id", Title: "ID", MinWidth: 40, Flex: 0}, {Key: "resource", Title: "RESOURCE", MinWidth: 24, Flex: 1}, {Key: "status", Title: "STATUS", MinWidth: 20, Flex: 0}, - {Key: "reason", Title: "REASON", MinWidth: 50, Flex: 1}, + {Key: "reason", Title: "REASON", MinWidth: ReasonColumnLength, Flex: 1}, {Key: "physical_id", Title: "PHYSICAL ID", MinWidth: 40, Flex: 0}, {Key: "time", Title: "TIME", MinWidth: 24, Flex: 1}, } @@ -45,7 +47,8 @@ func (r *Resource) Columns() []resource.Column { func (r *Resource) Commands() []resource.Command { return []resource.Command{ - {Key: "s", Description: "Show", Default: true}, + {Key: "s", Description: "Show"}, + {Key: "z", Description: "Reason", Default: true}, } } @@ -99,6 +102,8 @@ func (r *Resource) Execute(command resource.Command, row resource.Row) tea.Cmd { switch command.Key { case "s": return r.show(row) + case "z": + return r.reason(row) } return nil diff --git a/internal/ui/app.go b/internal/ui/app.go index f9a0fb6..81a5ba6 100644 --- a/internal/ui/app.go +++ b/internal/ui/app.go @@ -71,11 +71,12 @@ type Model struct { filter *resourceFilter scope resourceScope - detailMode bool - detailViewport viewport.Model - detailID string - detailContent string - detailLabel string + detailMode bool + detailViewport viewport.Model + detailID string + detailContent string + detailContentIsJson bool + detailLabel string commandMode bool command textinput.Model @@ -257,6 +258,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if keyMsg, ok := msg.(tea.KeyMsg); ok && keyMsg.String() == "esc" { if m.detailMode { + m.detailContentIsJson = false m.detailMode = false m.detailContent = "" m.detailID = "" @@ -629,6 +631,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { displayContent = colorizeJSON(data) } + m.detailContentIsJson = isJson m.detailMode = true m.detailID = msg.ID m.detailViewport.SetContent(displayContent) @@ -848,9 +851,18 @@ func (m *Model) Resize() { m.table.SetHeight(contentHeight) + wasAtBottom := m.detailViewport.AtBottom() m.detailViewport.Width = max(m.width-2, 1) m.detailViewport.Height = contentHeight + if m.detailMode { + m.wrapDetailContent() + + if !m.detailContentIsJson && wasAtBottom { + m.detailViewport.GotoBottom() + } + } + if m.resource == nil { return } diff --git a/internal/ui/helpers.go b/internal/ui/helpers.go index 59bd884..e413811 100644 --- a/internal/ui/helpers.go +++ b/internal/ui/helpers.go @@ -167,3 +167,18 @@ func preserveBackground(content string, background lipgloss.Color) string { return sequence + prefix }) } + +func (m *Model) wrapDetailContent() { + content := m.detailContent + + if m.detailContentIsJson { + m.detailViewport.SetContent(colorizeJSON([]byte(content))) + return + } + + wrapped := lipgloss.NewStyle(). + Width(max(m.detailViewport.Width, 1)). + Render(content) + + m.detailViewport.SetContent(wrapped) +} diff --git a/internal/ui/render.go b/internal/ui/render.go index 433ba3c..afe6f84 100644 --- a/internal/ui/render.go +++ b/internal/ui/render.go @@ -333,6 +333,7 @@ func (m Model) renderDetails() string { innerWidth := max(m.width-2, 1) + title = ansi.Truncate(title, innerWidth, "…") titleWidth := lipgloss.Width(title) remaining := max(innerWidth-titleWidth, 0) @@ -368,6 +369,7 @@ func (m Model) renderDetails() string { } for i, line := range bodyLines { + line = ansi.Truncate(line, innerWidth, "") lineWidth := lipgloss.Width(line) if lineWidth < innerWidth {