feat(tui): upgrade users tab with lipgloss table, edit support, role select
Users tab now matches sites/alerts quality: lipgloss bordered table, click-to-select zones, edit form with role picker, and UpdateUser support across both store backends.
This commit is contained in:
+100
-15
@@ -7,38 +7,113 @@ import (
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/huh"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/charmbracelet/lipgloss/table"
|
||||
)
|
||||
|
||||
var (
|
||||
userHeaderStyle = lipgloss.NewStyle().
|
||||
Foreground(lipgloss.Color("#7D56F4")).
|
||||
Bold(true).
|
||||
Padding(0, 1)
|
||||
|
||||
userCellStyle = lipgloss.NewStyle().Padding(0, 1)
|
||||
|
||||
userSelectedStyle = lipgloss.NewStyle().
|
||||
Padding(0, 1).
|
||||
Bold(true).
|
||||
Foreground(lipgloss.Color("#ffffff")).
|
||||
Background(lipgloss.Color("#3b3b5c"))
|
||||
|
||||
userBorderStyle = lipgloss.NewStyle().
|
||||
Foreground(lipgloss.Color("#444"))
|
||||
|
||||
userColWidths = []int{4, 16, 10, 44}
|
||||
)
|
||||
|
||||
type userFormData struct {
|
||||
Username string
|
||||
PublicKey string
|
||||
Role string
|
||||
}
|
||||
|
||||
func fmtRole(role string) string {
|
||||
if role == "admin" {
|
||||
return specialStyle.Render(role)
|
||||
}
|
||||
return role
|
||||
}
|
||||
|
||||
func fmtKey(key string) string {
|
||||
if len(key) > 40 {
|
||||
return key[:20] + "..." + key[len(key)-17:]
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
func (m Model) viewUsersTab() string {
|
||||
var content string
|
||||
content += fmt.Sprintf("\n%-3s %-15s %-10s %s\n", "ID", "USER", "ROLE", "KEY")
|
||||
content += subtleStyle.Render("----------------------------------------------------------------") + "\n"
|
||||
if len(m.users) == 0 {
|
||||
return "\n No users configured. Press [n] to add one."
|
||||
}
|
||||
|
||||
end := m.tableOffset + m.maxTableRows
|
||||
if end > len(m.users) {
|
||||
end = len(m.users)
|
||||
}
|
||||
|
||||
selectedVisual := m.cursor - m.tableOffset
|
||||
|
||||
var rows [][]string
|
||||
for i := m.tableOffset; i < end; i++ {
|
||||
u := m.users[i]
|
||||
cursor := " "
|
||||
if m.cursor == i {
|
||||
cursor = ">"
|
||||
}
|
||||
row := fmt.Sprintf("%s %-3d %-15s %-10s %s", cursor, u.ID, limitStr(u.Username, 15), u.Role, limitStr(u.PublicKey, 40))
|
||||
if m.cursor == i {
|
||||
row = lipgloss.NewStyle().Bold(true).Render(row)
|
||||
}
|
||||
content += row + "\n"
|
||||
rows = append(rows, []string{
|
||||
fmt.Sprintf("%d", u.ID),
|
||||
m.zones.Mark(fmt.Sprintf("user-%d", i), limitStr(u.Username, 15)),
|
||||
fmtRole(u.Role),
|
||||
fmtKey(u.PublicKey),
|
||||
})
|
||||
}
|
||||
return content
|
||||
|
||||
t := table.New().
|
||||
Border(lipgloss.RoundedBorder()).
|
||||
BorderStyle(userBorderStyle).
|
||||
Headers("ID", "USERNAME", "ROLE", "PUBLIC KEY").
|
||||
Rows(rows...).
|
||||
StyleFunc(func(row, col int) lipgloss.Style {
|
||||
if row == table.HeaderRow {
|
||||
s := userHeaderStyle
|
||||
if col < len(userColWidths) {
|
||||
s = s.Width(userColWidths[col])
|
||||
}
|
||||
return s
|
||||
}
|
||||
s := userCellStyle
|
||||
if row == selectedVisual {
|
||||
s = userSelectedStyle
|
||||
}
|
||||
if col < len(userColWidths) {
|
||||
s = s.Width(userColWidths[col])
|
||||
}
|
||||
return s
|
||||
})
|
||||
|
||||
return "\n" + t.Render()
|
||||
}
|
||||
|
||||
func (m *Model) initUserHuhForm() tea.Cmd {
|
||||
m.userFormData = &userFormData{}
|
||||
m.userFormData = &userFormData{
|
||||
Role: "user",
|
||||
}
|
||||
|
||||
if m.editID > 0 {
|
||||
for _, u := range m.users {
|
||||
if u.ID == m.editID {
|
||||
m.userFormData.Username = u.Username
|
||||
m.userFormData.PublicKey = u.PublicKey
|
||||
m.userFormData.Role = u.Role
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m.huhForm = huh.NewForm(
|
||||
huh.NewGroup(
|
||||
@@ -60,6 +135,11 @@ func (m *Model) initUserHuhForm() tea.Cmd {
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
huh.NewSelect[string]().Title("Role").
|
||||
Options(
|
||||
huh.NewOption("User", "user"),
|
||||
huh.NewOption("Admin", "admin"),
|
||||
).Value(&m.userFormData.Role),
|
||||
).Title("SSH Access"),
|
||||
).WithTheme(huh.ThemeDracula())
|
||||
|
||||
@@ -67,6 +147,11 @@ func (m *Model) initUserHuhForm() tea.Cmd {
|
||||
}
|
||||
|
||||
func (m *Model) submitUserForm() {
|
||||
store.Get().AddUser(m.userFormData.Username, m.userFormData.PublicKey, "user")
|
||||
d := m.userFormData
|
||||
if m.editID > 0 {
|
||||
store.Get().UpdateUser(m.editID, d.Username, d.PublicKey, d.Role)
|
||||
} else {
|
||||
store.Get().AddUser(d.Username, d.PublicKey, d.Role)
|
||||
}
|
||||
m.state = stateUsers
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user