main 6af0a61

progress.go RawHistoryFolder

1package models
2
3import (
4	"fmt"
5	"strings"
6
7	"github.com/bnema/archup/internal/application/dto"
8	tea "github.com/charmbracelet/bubbletea"
9	"github.com/charmbracelet/lipgloss"
10)
11
12// ProgressModelImpl implements ProgressModel interface
13type ProgressModelImpl struct {
14	BaseModel
15
16	currentPhase     string
17	phaseNumber      int
18	totalPhases      int
19	progressPercent  int
20	message          string
21	isError          bool
22	lastMessage      string
23	messageHistory   []string
24	maxHistoryLength int
25}
26
27// NewProgressModel creates a new progress model
28func NewProgressModel() *ProgressModelImpl {
29	return &ProgressModelImpl{
30		maxHistoryLength: 10,
31		messageHistory:   []string{},
32	}
33}
34
35// Init initializes the model
36func (pm *ProgressModelImpl) Init() tea.Cmd {
37	return nil
38}
39
40// UpdateProgress handles progress updates (called from app when progress updates arrive)
41func (pm *ProgressModelImpl) UpdateProgress(update *dto.ProgressUpdate) {
42	if update == nil {
43		return
44	}
45
46	pm.currentPhase = update.Phase
47	pm.phaseNumber = update.PhaseNumber
48	pm.totalPhases = update.TotalPhases
49	pm.progressPercent = update.ProgressPercent
50	pm.message = update.Message
51	pm.isError = update.IsError
52
53	// Add to history
54	if pm.message != "" && pm.message != pm.lastMessage {
55		pm.addToHistory(pm.message)
56		pm.lastMessage = pm.message
57	}
58}
59
60// Update handles tea.Msg (for tea.Model interface compatibility)
61func (pm *ProgressModelImpl) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
62	return pm, nil
63}
64
65// View renders the progress display
66// Deprecated: Use views.RenderProgress instead
67func (pm *ProgressModelImpl) View() string {
68	var b strings.Builder
69
70	b.WriteString("\n")
71	b.WriteString(lipgloss.NewStyle().
72		Bold(true).
73		Foreground(lipgloss.Color("12")).
74		Render("Installation Progress"))
75	b.WriteString("\n\n")
76
77	// Phase indicator
78	if pm.totalPhases > 0 {
79		phasePercent := int((float64(pm.phaseNumber) / float64(pm.totalPhases)) * 100)
80		b.WriteString(fmt.Sprintf("Phase %d/%d: %s [%d%%]\n", pm.phaseNumber, pm.totalPhases, pm.currentPhase, phasePercent))
81	}
82
83	// Progress bar
84	b.WriteString("\n")
85	b.WriteString(pm.renderProgressBar())
86	b.WriteString("\n\n")
87
88	// Current message
89	if pm.message != "" {
90		color := lipgloss.Color("11")
91		if pm.isError {
92			color = lipgloss.Color("1")
93		}
94		b.WriteString("Current: ")
95		b.WriteString(lipgloss.NewStyle().
96			Foreground(color).
97			Render(pm.message))
98		b.WriteString("\n\n")
99	}
100
101	// Message history
102	if len(pm.messageHistory) > 0 {
103		b.WriteString(lipgloss.NewStyle().
104			Faint(true).
105			Render("Recent activities:"))
106		b.WriteString("\n")
107
108		start := 0
109		if len(pm.messageHistory) > 5 {
110			start = len(pm.messageHistory) - 5
111		}
112		for _, msg := range pm.messageHistory[start:] {
113			b.WriteString(lipgloss.NewStyle().
114				Faint(true).
115				Render("  • " + msg))
116			b.WriteString("\n")
117		}
118	}
119
120	b.WriteString("\n")
121	b.WriteString(lipgloss.NewStyle().
122		Faint(true).
123		Render("Installation running... Press Ctrl+C to cancel"))
124
125	return b.String()
126}
127
128// GetPhaseProgress returns current and total phases
129func (pm *ProgressModelImpl) GetPhaseProgress() (int, int) {
130	return pm.phaseNumber, pm.totalPhases
131}
132
133// GetProgressPercent returns the overall progress percentage
134func (pm *ProgressModelImpl) GetProgressPercent() int {
135	return pm.progressPercent
136}
137
138// GetCurrentPhase returns the current phase name
139func (pm *ProgressModelImpl) GetCurrentPhase() string {
140	return pm.currentPhase
141}
142
143// GetMessage returns the current message
144func (pm *ProgressModelImpl) GetMessage() string {
145	return pm.message
146}
147
148// IsError returns whether the current message is an error
149func (pm *ProgressModelImpl) IsError() bool {
150	return pm.isError
151}
152
153// GetMessageHistory returns the message history
154func (pm *ProgressModelImpl) GetMessageHistory() []string {
155	return pm.messageHistory
156}
157
158// Helper methods
159
160func (pm *ProgressModelImpl) renderProgressBar() string {
161	width := 40
162	filled := (pm.progressPercent * width) / 100
163
164	bar := strings.Repeat("█", filled) + strings.Repeat("░", width-filled)
165
166	return fmt.Sprintf("[%s] %d%%", bar, pm.progressPercent)
167}
168
169func (pm *ProgressModelImpl) addToHistory(msg string) {
170	pm.messageHistory = append(pm.messageHistory, msg)
171	if len(pm.messageHistory) > pm.maxHistoryLength {
172		pm.messageHistory = pm.messageHistory[1:]
173	}
174}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 0

    ↑↓ moveenter openesc close