mirror of
https://github.com/anotherhadi/usbguard-tui.git
synced 2026-05-11 22:02:34 +02:00
+4
-14
@@ -2,7 +2,6 @@ package ui
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"image/color"
|
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"charm.land/bubbles/v2/list"
|
"charm.land/bubbles/v2/list"
|
||||||
@@ -11,7 +10,6 @@ import (
|
|||||||
"github.com/anotherhadi/usbguard-tui/internal/guard"
|
"github.com/anotherhadi/usbguard-tui/internal/guard"
|
||||||
)
|
)
|
||||||
|
|
||||||
// deviceDelegate renders device list items with status colors.
|
|
||||||
type deviceDelegate struct{}
|
type deviceDelegate struct{}
|
||||||
|
|
||||||
func (d deviceDelegate) Height() int { return 2 }
|
func (d deviceDelegate) Height() int { return 2 }
|
||||||
@@ -26,20 +24,14 @@ func (d deviceDelegate) Render(w io.Writer, m list.Model, index int, item list.I
|
|||||||
|
|
||||||
selected := index == m.Index()
|
selected := index == m.Index()
|
||||||
|
|
||||||
var clr color.Color
|
colorMap := statusColors
|
||||||
if selected {
|
if selected {
|
||||||
var ok bool
|
colorMap = statusColorsSelected
|
||||||
clr, ok = statusColorsSelected[dev.Status]
|
}
|
||||||
|
clr, ok := colorMap[dev.Status]
|
||||||
if !ok {
|
if !ok {
|
||||||
clr = colorMuted
|
clr = colorMuted
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
var ok bool
|
|
||||||
clr, ok = statusColors[dev.Status]
|
|
||||||
if !ok {
|
|
||||||
clr = colorMuted
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var nameStyle, descStyle lipgloss.Style
|
var nameStyle, descStyle lipgloss.Style
|
||||||
if selected {
|
if selected {
|
||||||
@@ -69,7 +61,6 @@ func (d deviceDelegate) Render(w io.Writer, m list.Model, index int, item list.I
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// actionItem represents a device policy action in the select popup.
|
|
||||||
type actionItem struct {
|
type actionItem struct {
|
||||||
label string
|
label string
|
||||||
fn func(int, bool) error
|
fn func(int, bool) error
|
||||||
@@ -81,7 +72,6 @@ func (a actionItem) Title() string { return a.label }
|
|||||||
func (a actionItem) Description() string { return "" }
|
func (a actionItem) Description() string { return "" }
|
||||||
func (a actionItem) FilterValue() string { return a.label }
|
func (a actionItem) FilterValue() string { return a.label }
|
||||||
|
|
||||||
// actionDelegate renders single-line action items.
|
|
||||||
type actionDelegate struct{}
|
type actionDelegate struct{}
|
||||||
|
|
||||||
func (d actionDelegate) Height() int { return 1 }
|
func (d actionDelegate) Height() int { return 1 }
|
||||||
|
|||||||
+53
-30
@@ -79,12 +79,14 @@ func New() Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func makeActionList(rulesManaged bool) list.Model {
|
func makeActionList(rulesManaged bool) list.Model {
|
||||||
items := []list.Item{
|
var items []list.Item
|
||||||
|
if rulesManaged {
|
||||||
|
items = []list.Item{
|
||||||
actionItem{"allow", guard.AllowDevice, false, guard.Allowed},
|
actionItem{"allow", guard.AllowDevice, false, guard.Allowed},
|
||||||
actionItem{"block", guard.BlockDevice, false, guard.Blocked},
|
actionItem{"block", guard.BlockDevice, false, guard.Blocked},
|
||||||
actionItem{"reject", guard.RejectDevice, false, guard.Rejected},
|
actionItem{"reject", guard.RejectDevice, false, guard.Rejected},
|
||||||
}
|
}
|
||||||
if !rulesManaged {
|
} else {
|
||||||
items = []list.Item{
|
items = []list.Item{
|
||||||
actionItem{"allow", guard.AllowDevice, false, guard.Allowed},
|
actionItem{"allow", guard.AllowDevice, false, guard.Allowed},
|
||||||
actionItem{"allow (permanent)", guard.AllowDevice, true, guard.Allowed},
|
actionItem{"allow (permanent)", guard.AllowDevice, true, guard.Allowed},
|
||||||
@@ -164,22 +166,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case tea.MouseWheelMsg:
|
case tea.MouseWheelMsg:
|
||||||
if m.state == statePopup {
|
return m.updateMouseWheel(msg)
|
||||||
switch msg.Button {
|
|
||||||
case tea.MouseWheelUp:
|
|
||||||
m.actionList.CursorUp()
|
|
||||||
case tea.MouseWheelDown:
|
|
||||||
m.actionList.CursorDown()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch msg.Button {
|
|
||||||
case tea.MouseWheelUp:
|
|
||||||
m.list.CursorUp()
|
|
||||||
case tea.MouseWheelDown:
|
|
||||||
m.list.CursorDown()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.state == stateList {
|
if m.state == stateList {
|
||||||
@@ -216,18 +203,11 @@ func (m Model) updateList(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
|
|||||||
m.state = statePopup
|
m.state = statePopup
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
case id >= 0 && key.Matches(msg, listKeys.Allow):
|
}
|
||||||
return m, doAction(id, guard.AllowDevice, false)
|
if id >= 0 {
|
||||||
case id >= 0 && !m.rulesManaged && key.Matches(msg, listKeys.AllowPerm):
|
if cmd := m.deviceActionCmd(msg, id); cmd != nil {
|
||||||
return m, doAction(id, guard.AllowDevice, true)
|
return m, cmd
|
||||||
case id >= 0 && key.Matches(msg, listKeys.Block):
|
}
|
||||||
return m, doAction(id, guard.BlockDevice, false)
|
|
||||||
case id >= 0 && !m.rulesManaged && key.Matches(msg, listKeys.BlockPerm):
|
|
||||||
return m, doAction(id, guard.BlockDevice, true)
|
|
||||||
case id >= 0 && key.Matches(msg, listKeys.Reject):
|
|
||||||
return m, doAction(id, guard.RejectDevice, false)
|
|
||||||
case id >= 0 && !m.rulesManaged && key.Matches(msg, listKeys.RejectPerm):
|
|
||||||
return m, doAction(id, guard.RejectDevice, true)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var cmd tea.Cmd
|
var cmd tea.Cmd
|
||||||
@@ -391,3 +371,46 @@ func doAction(id int, fn func(int, bool) error, permanent bool) tea.Cmd {
|
|||||||
return actionMsg{err: fn(id, permanent)}
|
return actionMsg{err: fn(id, permanent)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type actionBinding struct {
|
||||||
|
binding key.Binding
|
||||||
|
fn func(int, bool) error
|
||||||
|
perm bool
|
||||||
|
needsWritable bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var deviceActionBindings = []actionBinding{
|
||||||
|
{listKeys.Allow, guard.AllowDevice, false, false},
|
||||||
|
{listKeys.AllowPerm, guard.AllowDevice, true, true},
|
||||||
|
{listKeys.Block, guard.BlockDevice, false, false},
|
||||||
|
{listKeys.BlockPerm, guard.BlockDevice, true, true},
|
||||||
|
{listKeys.Reject, guard.RejectDevice, false, false},
|
||||||
|
{listKeys.RejectPerm, guard.RejectDevice, true, true},
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Model) deviceActionCmd(msg tea.KeyPressMsg, id int) tea.Cmd {
|
||||||
|
for _, b := range deviceActionBindings {
|
||||||
|
if (!b.needsWritable || !m.rulesManaged) && key.Matches(msg, b.binding) {
|
||||||
|
return doAction(id, b.fn, b.perm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Model) updateMouseWheel(msg tea.MouseWheelMsg) (tea.Model, tea.Cmd) {
|
||||||
|
switch msg.Button {
|
||||||
|
case tea.MouseWheelUp:
|
||||||
|
if m.state == statePopup {
|
||||||
|
m.actionList.CursorUp()
|
||||||
|
} else {
|
||||||
|
m.list.CursorUp()
|
||||||
|
}
|
||||||
|
case tea.MouseWheelDown:
|
||||||
|
if m.state == statePopup {
|
||||||
|
m.actionList.CursorDown()
|
||||||
|
} else {
|
||||||
|
m.list.CursorDown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -48,7 +48,5 @@ var (
|
|||||||
|
|
||||||
popupTitleStyle = lipgloss.NewStyle().Bold(true).MarginBottom(1)
|
popupTitleStyle = lipgloss.NewStyle().Bold(true).MarginBottom(1)
|
||||||
|
|
||||||
keyHintStyle = lipgloss.NewStyle().Foreground(colorAccent).Bold(true)
|
|
||||||
warnStyle = lipgloss.NewStyle().Foreground(colorRejected)
|
warnStyle = lipgloss.NewStyle().Foreground(colorRejected)
|
||||||
errStyle = lipgloss.NewStyle().Foreground(colorBlocked).Bold(true)
|
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user