Skip to content

Commit 5fc72d7

Browse files
committed
Updated cv and sv views and interactions
1 parent 29bff6d commit 5fc72d7

File tree

3 files changed

+233
-63
lines changed

3 files changed

+233
-63
lines changed

tui/cvarchived.go

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
// Copyright (c) Tom Straub (github.com/straubt1) 2025
2+
// SPDX-License-Identifier: MIT
3+
4+
package tui
5+
6+
import (
7+
"strings"
8+
9+
"charm.land/lipgloss/v2"
10+
tea "charm.land/bubbletea/v2"
11+
tfe "github.com/hashicorp/go-tfe"
12+
)
13+
14+
// renderCVArchivedModal renders a small modal explaining that the selected
15+
// configuration version has been archived and is no longer available.
16+
func (m Model) renderCVArchivedModal() string {
17+
cv := m.cvArchivedCV
18+
19+
innerW := 52
20+
if innerW > m.width-6 {
21+
innerW = m.width - 6
22+
}
23+
if innerW < 30 {
24+
innerW = 30
25+
}
26+
27+
labelW := 10
28+
29+
dimStyle := lipgloss.NewStyle().Foreground(colorDim)
30+
accentStyle := lipgloss.NewStyle().Foreground(colorAccent)
31+
errorStyle := lipgloss.NewStyle().Foreground(colorError)
32+
33+
renderKV := func(label, value string) string {
34+
l := dimStyle.Render(label + ":")
35+
pad := labelW - len([]rune(label+":"))
36+
if pad < 1 {
37+
pad = 1
38+
}
39+
return " " + l + strings.Repeat(" ", pad) + accentStyle.Render(value)
40+
}
41+
42+
// ── Body rows ─────────────────────────────────────────────────────────────
43+
var rows []string
44+
45+
rows = append(rows, "")
46+
rows = append(rows, " "+errorStyle.Render("✗ This configuration version is archived"))
47+
rows = append(rows, " and its contents are no longer available.")
48+
rows = append(rows, "")
49+
50+
rows = append(rows, renderKV("ID", cv.ID))
51+
52+
// Archived-at timestamp
53+
if cv.StatusTimestamps != nil && !cv.StatusTimestamps.ArchivedAt.IsZero() {
54+
rows = append(rows, renderKV("Archived", timestampWithRelative(cv.StatusTimestamps.ArchivedAt)))
55+
}
56+
57+
// Source / means
58+
if cv.Source != "" {
59+
rows = append(rows, renderKV("Source", cvSourceLabel(cv.Source)))
60+
}
61+
62+
rows = append(rows, "")
63+
rows = append(rows, " "+dimStyle.Render("Press Esc or Enter to dismiss."))
64+
rows = append(rows, "")
65+
66+
body := strings.Join(rows, "\n")
67+
68+
borderStyle := lipgloss.NewStyle().
69+
Border(lipgloss.RoundedBorder()).
70+
BorderForeground(colorError).
71+
Width(innerW).
72+
Padding(0, 1)
73+
74+
return borderStyle.Render(body)
75+
}
76+
77+
// cvSourceLabel returns a human-readable label for a ConfigurationSource.
78+
func cvSourceLabel(src tfe.ConfigurationSource) string {
79+
switch src {
80+
case tfe.ConfigurationSourceGithub:
81+
return "GitHub"
82+
case tfe.ConfigurationSourceGitlab:
83+
return "GitLab"
84+
case tfe.ConfigurationSourceBitbucket:
85+
return "Bitbucket"
86+
case tfe.ConfigurationSourceAdo:
87+
return "Azure DevOps"
88+
case tfe.ConfigurationSourceTerraform:
89+
return "Terraform CLI"
90+
default:
91+
if string(src) == "" {
92+
return "unknown"
93+
}
94+
return string(src)
95+
}
96+
}
97+
98+
// overlayCVArchivedModal composites the CV archived modal centered over the
99+
// already-rendered full-screen base content.
100+
func (m Model) overlayCVArchivedModal(base string) string {
101+
modal := m.renderCVArchivedModal()
102+
mw := lipgloss.Width(modal)
103+
mh := lipgloss.Height(modal)
104+
105+
x := (m.width - mw) / 2
106+
y := (m.height - mh) / 2
107+
if x < 0 {
108+
x = 0
109+
}
110+
if y < 0 {
111+
y = 0
112+
}
113+
114+
baseLayer := lipgloss.NewLayer(base).Z(0)
115+
modalLayer := lipgloss.NewLayer(modal).X(x).Y(y).Z(1)
116+
117+
compositor := lipgloss.NewCompositor(baseLayer, modalLayer)
118+
canvas := lipgloss.NewCanvas(m.width, m.height)
119+
canvas.Compose(compositor)
120+
return canvas.Render()
121+
}
122+
123+
// handleCVArchivedModalKey processes keys while the CV archived modal is open.
124+
func (m Model) handleCVArchivedModalKey(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
125+
switch msg.String() {
126+
case "esc", "enter", "q":
127+
m.showCVArchivedModal = false
128+
m.cvArchivedCV = nil
129+
}
130+
return m, nil
131+
}

tui/cvfiles.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,9 @@ func (m Model) renderConfigVersionFilesContent() string {
285285

286286
// Build connector string and measure its width (all ASCII → byte len).
287287
connStr := buildTreeConnector(m.cvFiles, i)
288-
connW := len(connStr)
288+
// Box-drawing chars (├ └ │ ─) are multi-byte UTF-8 but 1 terminal cell wide each;
289+
// lipgloss.Width is required — len() would overcount and shift the SIZE column left.
290+
connW := lipgloss.Width(connStr)
289291

290292
// Icon lookup (Nerd Font glyph + hex color for this file/dir type).
291293
iconGlyph, iconColor := cvFileIcon(f)

0 commit comments

Comments
 (0)