Commit 694234d

Ansari <ping@ansari.wtf>
2026-03-02 19:36:00
Refactor model structure and update methods for clarity
1 parent 19aef7e
internal/app/model.go
@@ -9,10 +9,10 @@ import (
 )
 
 type model struct {
-	stats ufw.Stats
+	stats  ufw.Stats
 	policy ufw.Policy
-	rules []ufw.Rule
-  err error 
+	rules  []ufw.Rule
+	err    error
 
 	activeSection int
 
@@ -20,11 +20,9 @@ type model struct {
 	height int
 	styles ui.Styles
 
-	statsSection stats.Model	
+	statsSection  stats.Model
 	policySection policy.Model
 	rulesSection  rules.Model
-
-	openMenu bool
 }
 
 func InitialModel() model {
@@ -39,10 +37,8 @@ func InitialModel() model {
 		width:  87,
 		height: 30,
 
-		statsSection: stats.New(styles),
+		statsSection:  stats.New(styles),
 		policySection: policy.New(styles),
-		rulesSection: rules.New(styles),
-
-		openMenu : false,
+		rulesSection:  rules.New(styles),
 	}
 }
internal/app/update.go
@@ -58,7 +58,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 			return m, sectionCmd
 
 		case sections.RulesSection:
-			newRules, sectionCmd := m.rulesSection.Update(msg,m.rules)
+			newRules, sectionCmd := m.rulesSection.Update(msg, m.rules)
 			m.rulesSection = newRules
 			return m, sectionCmd
 		}
@@ -98,5 +98,5 @@ func (m *model) focusActiveSection() {
 }
 
 func (m *model) isMenuOpen() bool {
-	return m.statsSection.GetMenu() != nil || m.rulesSection.GetMenu() != nil
+	return m.statsSection.HasOpenMenu() || m.rulesSection.HasOpenMenu()
 }
internal/app/view.go
@@ -7,6 +7,15 @@ import (
 	"github.com/charmbracelet/lipgloss"
 )
 
+func (m model) renderCenteredOverlay(overlay, background string) string {
+	dimmed := "\x1b[2m" + lipgloss.NewStyle().Faint(true).Render(background) + "\x1b[0m"
+	overlayW := lipgloss.Width(overlay)
+	overlayH := lipgloss.Height(overlay)
+	x := (m.width - overlayW) / 2
+	y := (m.height - overlayH) / 2
+	return PlaceOverlay(x, y, overlay, dimmed)
+}
+
 func (m model) View() string {
 	const minWidth, minHeight = 87, 30
 	const containerWidth, containerHeight = minWidth - 5, minHeight - 3
@@ -81,25 +90,20 @@ func (m model) View() string {
 		layout,
 	)
 
-	var menuOpen *ui.Menu
-
-	if m.statsSection.GetMenu() != nil {
-		menuOpen = m.statsSection.GetMenu()
-	} else if m.rulesSection.GetMenu() != nil {
-		menuOpen = m.rulesSection.GetMenu()
+	if m.rulesSection.ShowingDeleteConfirm() {
+		return m.renderCenteredOverlay(m.rulesSection.DeleteConfirmView(), layout)
 	}
 
-	if menuOpen != nil {
-
-		dimmed := "\x1b[2m" + lipgloss.NewStyle().Faint(true).Render(layout) + "\x1b[0m"
-		menuView := menuOpen.View(m.styles)
+	if m.rulesSection.ShowingDetails() {
+		return m.renderCenteredOverlay(m.rulesSection.DetailView(), layout)
+	}
 
-		menuW := lipgloss.Width(menuView)
-		menuH := lipgloss.Height(menuView)
-		x := (m.width - menuW) / 2
-		y := (m.height - menuH) / 2
+	if menu := m.statsSection.GetMenu(); menu != nil {
+		return m.renderCenteredOverlay(menu.View(m.styles), layout)
+	}
 
-		return PlaceOverlay(x, y, menuView, dimmed)
+	if menu := m.rulesSection.GetMenu(); menu != nil {
+		return m.renderCenteredOverlay(menu.View(m.styles), layout)
 	}
 
 	return layout
internal/keys/keys.go
@@ -14,6 +14,8 @@ type KeyMap struct {
 	CursorUp    key.Binding
 	CursorDown  key.Binding
 	Execute     key.Binding
+	Info        key.Binding
+	Delete      key.Binding
 }
 
 var Bindings = KeyMap{
@@ -44,6 +46,14 @@ var Bindings = KeyMap{
 	Execute: key.NewBinding(
 		key.WithKeys(" ", "enter"),
 	),
+
+	Info: key.NewBinding(
+		key.WithKeys("i"),
+	),
+
+	Delete: key.NewBinding(
+		key.WithKeys("d"),
+	),
 }
 
 type RefreshMsg struct{}
internal/sections/policy/model.go
@@ -7,8 +7,7 @@ import (
 type Model struct {
 	styles     ui.Styles
 	totalOpts  int
-	cursorLine int 
-	showMenu   bool
+	cursorLine int
 	menu       *ui.Menu
 	active     bool
 }
@@ -17,7 +16,6 @@ func New(styles ui.Styles) Model {
 	return Model{
 		styles:     styles,
 		cursorLine: 0,
-		showMenu:   false,
 		menu:       nil,
 		active:     false,
 		totalOpts:  2,
@@ -31,7 +29,7 @@ func (m *Model) Focus() {
 
 func (m *Model) Blur() {
 	m.active = false
-	m.showMenu = false
+	m.menu = nil
 	m.cursorLine = 0
 }
 
internal/sections/policy/update.go
@@ -29,7 +29,8 @@ func (m Model) Update(msg tea.Msg, policy ufw.Policy) (Model, tea.Cmd) {
 			case 2:
 				ufw.DefaultRouted(!(policy.DefaultRouted == "ALLOW"))
 			}
+			return m, keys.Refresh()
 		}
 	}
-	return m, keys.Refresh()
+	return m, nil
 }
internal/sections/stats/model.go
@@ -7,8 +7,7 @@ import (
 type Model struct {
 	styles     ui.Styles
 	totalOpts  int
-	cursorLine int 
-	showMenu   bool
+	cursorLine int
 	menu       *ui.Menu
 	active     bool
 }
@@ -17,7 +16,6 @@ func New(styles ui.Styles) Model {
 	return Model{
 		styles:     styles,
 		cursorLine: 0,
-		showMenu:   false,
 		menu:       nil,
 		active:     true,
 		totalOpts:  2,
@@ -31,7 +29,7 @@ func (m *Model) Focus() {
 
 func (m *Model) Blur() {
 	m.active = false
-	m.showMenu = false
+	m.menu = nil
 	m.cursorLine = 0
 }
 
internal/sections/sections.go
@@ -5,3 +5,12 @@ const (
 	PolicySection
 	RulesSection
 )
+
+// All section models implement the following common methods:
+//   - Focus()         - activates the section and resets cursor position
+//   - Blur()          - deactivates the section and clears overlays/menus
+//   - HasOpenMenu()   - returns true if a menu overlay is displayed
+//   - GetMenu()       - returns the current menu or nil
+//
+// Note: Update() and View() have different signatures per section
+// because they depend on different data (stats, policy, or rules).