cleanup.go RawHistoryFolder

1package model
2
3import (
4	"context"
5
6	tea "github.com/charmbracelet/bubbletea"
7	"github.com/charmbracelet/lipgloss"
8
9	"github.com/bnema/dumber/internal/application/usecase"
10	"github.com/bnema/dumber/internal/cli/styles"
11)
12
13// CleanupModel wraps styles.CleanupModel for standalone use.
14type CleanupModel struct {
15	cleanup  styles.CleanupModel
16	cleaned  bool
17	cleaning bool
18	err      error
19
20	historyUC *usecase.SearchHistoryUseCase
21	theme     *styles.Theme
22}
23
24// NewCleanupModel creates a new cleanup command model.
25func NewCleanupModel(theme *styles.Theme, historyUC *usecase.SearchHistoryUseCase) CleanupModel {
26	return CleanupModel{
27		cleanup:   styles.NewCleanup(theme),
28		historyUC: historyUC,
29		theme:     theme,
30	}
31}
32
33// cleanupCompleteMsg is sent when cleanup is done.
34type cleanupCompleteMsg struct {
35	err error
36}
37
38// Init implements tea.Model.
39func (m CleanupModel) Init() tea.Cmd {
40	if m.theme == nil {
41		return nil
42	}
43	return nil
44}
45
46// Update implements tea.Model.
47func (m CleanupModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
48	switch msg := msg.(type) {
49	case cleanupCompleteMsg:
50		m.cleaning = false
51		if msg.err != nil {
52			m.err = msg.err
53		} else {
54			m.cleaned = true
55		}
56		return m, nil
57
58	case tea.KeyMsg:
59		// If cleaned, any key exits
60		if m.cleaned || m.err != nil {
61			return m, tea.Quit
62		}
63
64		// If cleaning, ignore input
65		if m.cleaning {
66			return m, nil
67		}
68	}
69
70	// Update inner cleanup model
71	cleanup, cmd := m.cleanup.Update(msg)
72	m.cleanup = cleanup
73
74	if m.cleanup.Done() {
75		if m.cleanup.Canceled {
76			return m, tea.Quit
77		}
78		if m.cleanup.Confirmed {
79			m.cleaning = true
80			return m, m.performCleanup(m.cleanup.SelectedRange())
81		}
82	}
83
84	return m, cmd
85}
86
87// performCleanup executes the cleanup operation.
88func (m CleanupModel) performCleanup(cleanupRange styles.CleanupRange) tea.Cmd {
89	return func() tea.Msg {
90		ctx := context.Background()
91		cutoff := cleanupRange.CutoffTime()
92
93		var err error
94		if cutoff.IsZero() {
95			err = m.historyUC.ClearAll(ctx)
96		} else {
97			err = m.historyUC.ClearOlderThan(ctx, cutoff)
98		}
99
100		return cleanupCompleteMsg{err: err}
101	}
102}
103
104// View implements tea.Model.
105func (m CleanupModel) View() string {
106	t := m.theme
107
108	if m.cleaning {
109		spinner := styles.NewLoading(t, "Cleaning up...")
110		return t.Box.Render(spinner.View())
111	}
112
113	if m.err != nil {
114		content := lipgloss.JoinVertical(
115			lipgloss.Left,
116			t.ErrorStyle.Render("Error: "+m.err.Error()),
117			"",
118			t.Subtle.Render("Press any key to exit"),
119		)
120		return t.Box.Render(content)
121	}
122
123	if m.cleaned {
124		content := lipgloss.JoinVertical(
125			lipgloss.Left,
126			t.SuccessStyle.Render("History cleaned successfully!"),
127			"",
128			t.Subtle.Render("Press any key to exit"),
129		)
130		return t.Box.Render(content)
131	}
132
133	return m.cleanup.View()
134}
135
136// Ensure interface compliance.
137var _ tea.Model = (*CleanupModel)(nil)

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 8

Tags 42

↑↓ moveenter openesc close