update:wip
This commit is contained in:
@@ -1,14 +1,69 @@
|
||||
package tui
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"filepass/internal/pages"
|
||||
"filepass/internal/services"
|
||||
|
||||
tea "charm.land/bubbletea/v2"
|
||||
)
|
||||
|
||||
type configLoadedMsg struct {
|
||||
servers map[string]services.Server
|
||||
err error
|
||||
}
|
||||
|
||||
type serverAddedMsg struct {
|
||||
name string
|
||||
servers map[string]services.Server
|
||||
}
|
||||
|
||||
type clearFlashMsg struct{}
|
||||
|
||||
func clearFlashAfter(d time.Duration) tea.Cmd {
|
||||
return tea.Tick(d, func(time.Time) tea.Msg {
|
||||
return clearFlashMsg{}
|
||||
})
|
||||
}
|
||||
|
||||
// isDisabled reports whether a menu item is non-interactive given current state.
|
||||
func (m TUIInterface) isDisabled(i int) bool {
|
||||
return m.MenuItems[i].RequiresServers && m.NoServers
|
||||
}
|
||||
|
||||
// nextSelectable finds the next non-disabled index in direction (+1 or -1).
|
||||
func (m TUIInterface) nextSelectable(from, dir int) int {
|
||||
i := from + dir
|
||||
for i >= 0 && i < len(m.MenuItems) {
|
||||
if !m.isDisabled(i) {
|
||||
return i
|
||||
}
|
||||
i += dir
|
||||
}
|
||||
return from
|
||||
}
|
||||
|
||||
func (m TUIInterface) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
|
||||
case pages.HomePageMsg:
|
||||
m.Page = pageHome
|
||||
m.MenuItems = pages.HomeMenuItems()
|
||||
m.Selected = 0
|
||||
return m, nil
|
||||
|
||||
case pages.ConfigPageMsg:
|
||||
m.Page = pageConfig
|
||||
m.MenuItems = pages.ConfigMenuItems()
|
||||
m.Selected = 0
|
||||
return m, nil
|
||||
|
||||
case pages.AddServerPageMsg:
|
||||
m.Page = pageAddServer
|
||||
m.Form = newAddServerForm()
|
||||
m.FormErr = ""
|
||||
return m, nil
|
||||
|
||||
case configLoadedMsg:
|
||||
@@ -20,28 +75,58 @@ func (m TUIInterface) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
m.NoServers = len(msg.servers) == 0
|
||||
return m, nil
|
||||
|
||||
case serverAddedMsg:
|
||||
m.Servers = msg.servers
|
||||
m.NoServers = len(msg.servers) == 0
|
||||
m.Page = pageConfig
|
||||
m.MenuItems = pages.ConfigMenuItems()
|
||||
m.Selected = 0
|
||||
m.FlashMsg = "✓ \"" + msg.name + "\" added successfully."
|
||||
return m, clearFlashAfter(2 * time.Second)
|
||||
|
||||
case clearFlashMsg:
|
||||
m.FlashMsg = ""
|
||||
return m, nil
|
||||
|
||||
case tea.WindowSizeMsg:
|
||||
m.WindowWidth = msg.Width
|
||||
m.WindowHeight = msg.Height
|
||||
return m, nil
|
||||
|
||||
case tea.KeyPressMsg:
|
||||
// add server form has its own key handling
|
||||
if m.Page == pageAddServer {
|
||||
return m.updateAddServer(msg)
|
||||
}
|
||||
|
||||
switch msg.String() {
|
||||
case "up", "k":
|
||||
if m.Selected > 0 {
|
||||
m.Selected--
|
||||
}
|
||||
m.Selected = m.nextSelectable(m.Selected, -1)
|
||||
case "down", "j":
|
||||
if m.Selected < len(m.MenuItems)-1 {
|
||||
m.Selected++
|
||||
}
|
||||
m.Selected = m.nextSelectable(m.Selected, +1)
|
||||
case "enter":
|
||||
if m.MenuItems[m.Selected].Key == "exit" {
|
||||
if m.isDisabled(m.Selected) {
|
||||
return m, nil
|
||||
}
|
||||
switch m.MenuItems[m.Selected].Key {
|
||||
case "exit":
|
||||
m.Quitting = true
|
||||
return m, tea.Quit
|
||||
case "config":
|
||||
return m, func() tea.Msg { return pages.ConfigPageMsg{} }
|
||||
case "back":
|
||||
return m, func() tea.Msg { return pages.HomePageMsg{} }
|
||||
case "add":
|
||||
return m, func() tea.Msg { return pages.AddServerPageMsg{} }
|
||||
// TODO: "server", "edit", "remove"
|
||||
}
|
||||
case "ctrl+c":
|
||||
m.Quitting = true
|
||||
return m, tea.Quit
|
||||
case "esc":
|
||||
if m.Page == pageConfig {
|
||||
return m, func() tea.Msg { return pages.HomePageMsg{} }
|
||||
}
|
||||
// TODO: dispatch to server/config pages
|
||||
case "ctrl+c", "esc":
|
||||
m.Quitting = true
|
||||
return m, tea.Quit
|
||||
}
|
||||
@@ -49,3 +134,83 @@ func (m TUIInterface) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m TUIInterface) updateAddServer(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
|
||||
f := m.Form
|
||||
|
||||
switch msg.String() {
|
||||
case "tab", "down":
|
||||
m.Form = f.focusNext()
|
||||
return m, nil
|
||||
|
||||
case "shift+tab", "up":
|
||||
m.Form = f.focusPrev()
|
||||
return m, nil
|
||||
|
||||
case "enter":
|
||||
// on an input field, advance to next
|
||||
if f.focused < fieldSave {
|
||||
m.Form = f.focusNext()
|
||||
return m, nil
|
||||
}
|
||||
// on save button
|
||||
if f.focused == fieldSave {
|
||||
return m.submitAddServer()
|
||||
}
|
||||
// on back button
|
||||
if f.focused == fieldBack {
|
||||
return m, func() tea.Msg { return pages.ConfigPageMsg{} }
|
||||
}
|
||||
|
||||
case "ctrl+c":
|
||||
m.Quitting = true
|
||||
return m, tea.Quit
|
||||
|
||||
case "esc":
|
||||
return m, func() tea.Msg { return pages.ConfigPageMsg{} }
|
||||
}
|
||||
|
||||
// route keystrokes to the focused input
|
||||
if f.focused < len(f.inputs) {
|
||||
var cmd tea.Cmd
|
||||
f.inputs[f.focused], cmd = f.inputs[f.focused].Update(msg)
|
||||
// clear duplicate-name error when user edits the name field
|
||||
if f.focused == fieldName {
|
||||
m.FormErr = ""
|
||||
}
|
||||
m.Form = f
|
||||
return m, cmd
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m TUIInterface) submitAddServer() (tea.Model, tea.Cmd) {
|
||||
f := m.Form
|
||||
name := strings.TrimSpace(f.inputs[fieldName].Value())
|
||||
|
||||
if !f.canSave() {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
if m.Services.Config.HasServer(name) {
|
||||
m.FormErr = "✗ \"" + name + "\" already exists."
|
||||
return m, nil
|
||||
}
|
||||
|
||||
s := services.Server{
|
||||
Host: strings.TrimSpace(f.inputs[fieldHost].Value()),
|
||||
User: strings.TrimSpace(f.inputs[fieldUser].Value()),
|
||||
PrivateKey: strings.TrimSpace(f.inputs[fieldPrivateKey].Value()),
|
||||
Port: strings.TrimSpace(f.inputs[fieldPort].Value()),
|
||||
}
|
||||
|
||||
if err := m.Services.Config.AddServer(name, s); err != nil {
|
||||
m.FormErr = "✗ " + err.Error()
|
||||
return m, nil
|
||||
}
|
||||
|
||||
return m, func() tea.Msg {
|
||||
return serverAddedMsg{name: name, servers: m.Services.Config.Servers()}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user