1package rules
2
3import (
4 "github.com/The-Robin-Hood/ufWall/internal/ufw"
5 "github.com/The-Robin-Hood/ufWall/internal/ui"
6)
7
8type Table int
9
10const (
11 IPv4Table Table = iota
12 IPv6Table
13)
14
15type WizardStep int
16
17const (
18 StepAction WizardStep = iota
19 StepDirection
20 StepProtocol
21 StepPort
22 StepSource
23 StepDestination
24 StepInterface
25 StepConfirm
26)
27
28type AddWizard struct {
29 Step WizardStep
30 Params ufw.AddRuleParams
31 Input string
32 InputMode bool
33 Options []string
34 Cursor int
35 Interfaces []string
36 Error string
37}
38
39type MenuContext struct {
40 Action string
41 SelectedRule *ufw.Rule
42 TotalRules int
43 PendingSubmenu bool
44}
45
46type Model struct {
47 styles ui.Styles
48 cursorLine int
49 menu *ui.Menu
50 active bool
51
52 // Two-table navigation
53 activeTable Table // Which table (IPv4 or IPv6) is currently focused
54 ipv4CursorLine int
55 ipv6CursorLine int
56
57 // Scroll offsets for each table
58 ipv4ScrollOffset int
59 ipv6ScrollOffset int
60
61 // Detail view overlay
62 showDetails bool
63 detailRule *ufw.Rule
64
65 // Delete confirmation
66 showDeleteConfirm bool
67 deleteRule *ufw.Rule
68
69 // Multi-step menu operations
70 menuContext *MenuContext
71 addWizard *AddWizard
72}
73
74const MaxVisibleRules = 7
75
76func New(styles ui.Styles) Model {
77 return Model{
78 styles: styles,
79 cursorLine: 0,
80 menu: nil,
81 active: false,
82 activeTable: IPv4Table,
83 ipv4CursorLine: 0,
84 ipv6CursorLine: 0,
85 ipv4ScrollOffset: 0,
86 ipv6ScrollOffset: 0,
87 showDetails: false,
88 detailRule: nil,
89 showDeleteConfirm: false,
90 deleteRule: nil,
91 menuContext: nil,
92 addWizard: nil,
93 }
94}
95
96func (m *Model) Focus() {
97 m.active = true
98}
99
100func (m *Model) Blur() {
101 m.active = false
102 m.menu = nil
103 m.showDetails = false
104 m.showDeleteConfirm = false
105 m.menuContext = nil
106 m.addWizard = nil
107}
108
109func (m Model) HasOpenMenu() bool {
110 return m.menu != nil || m.showDetails || m.showDeleteConfirm || m.addWizard != nil
111}
112
113func (m Model) GetMenu() *ui.Menu {
114 return m.menu
115}
116
117func (m Model) ShowingDetails() bool {
118 return m.showDetails
119}
120
121func (m Model) GetDetailRule() *ufw.Rule {
122 return m.detailRule
123}
124
125func (m Model) ShowingDeleteConfirm() bool {
126 return m.showDeleteConfirm
127}
128
129func (m Model) GetDeleteRule() *ufw.Rule {
130 return m.deleteRule
131}
132
133func (m Model) ActiveTable() Table {
134 return m.activeTable
135}
136
137func (m Model) IPv4CursorLine() int {
138 return m.ipv4CursorLine
139}
140
141func (m Model) IPv6CursorLine() int {
142 return m.ipv6CursorLine
143}
144
145func (m Model) CurrentCursorLine() int {
146 if m.activeTable == IPv6Table {
147 return m.ipv6CursorLine
148 }
149 return m.ipv4CursorLine
150}
151
152func (m Model) CurrentScrollOffset() int {
153 if m.activeTable == IPv6Table {
154 return m.ipv6ScrollOffset
155 }
156 return m.ipv4ScrollOffset
157}
158
159func (m Model) ShowingAddWizard() bool {
160 return m.addWizard != nil
161}
162
163func (m Model) GetAddWizard() *AddWizard {
164 return m.addWizard
165}
166
167func NewAddWizard() *AddWizard {
168 return &AddWizard{
169 Step: StepAction,
170 Params: ufw.AddRuleParams{},
171 Input: "",
172 InputMode: false,
173 Options: ufw.Actions,
174 Cursor: 0,
175 Interfaces: ufw.GetInterfaces(),
176 Error: "",
177 }
178}