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)