Eddited Settings View

Added Interactive Settings View
This commit is contained in:
2026-05-03 20:27:14 +02:00
parent e9a6c57ff5
commit 904d5702f5

215
main.go
View File

@@ -2,20 +2,20 @@ package main
import ( import (
"fmt" "fmt"
"net"
"os" "os"
"os/exec" "os/exec"
"strconv" "strconv"
"strings" "strings"
"net"
"time" "time"
"pulsegate/internal/config" "pulsegate/internal/config"
"pulsegate/internal/models" "pulsegate/internal/models"
"pulsegate/internal/secret" "pulsegate/internal/secret"
"github.com/charmbracelet/bubbles/textinput"
tea "github.com/charmbracelet/bubbletea" tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/bubbles/textinput"
"golang.org/x/term" "golang.org/x/term"
) )
@@ -28,7 +28,7 @@ const (
ViewAddServer viewMode = "add_server" ViewAddServer viewMode = "add_server"
ViewEditServer viewMode = "edit_server" ViewEditServer viewMode = "edit_server"
ViewDeleteConfirm viewMode = "delete_confirm" ViewDeleteConfirm viewMode = "delete_confirm"
ViewCommands viewMode = "commands" ViewCommands viewMode = "commands"
ViewCommandOutput viewMode = "command_output" ViewCommandOutput viewMode = "command_output"
) )
@@ -41,25 +41,28 @@ type model struct {
height int height int
err error err error
addInputs []textinput.Model addInputs []textinput.Model
addFocus int addFocus int
editIndex int editIndex int
commandSelected int commandSelected int
commandOutput string commandOutput string
commandTitle string commandTitle string
commandError string commandError string
serverStatus map[int]string serverStatus map[int]string
settingsSelected int
settingsEditingTerm bool
settingsTermInput textinput.Model
} }
var ( var (
green = lipgloss.Color("#00ff99") green = lipgloss.Color("#00ff99")
cyan = lipgloss.Color("#33ccff") cyan = lipgloss.Color("#33ccff")
gray = lipgloss.Color("#777777") gray = lipgloss.Color("#777777")
text = lipgloss.Color("#d7ffe9") text = lipgloss.Color("#d7ffe9")
dimText = lipgloss.Color("#8aa99b") dimText = lipgloss.Color("#8aa99b")
panelBg = lipgloss.Color("#07110d") panelBg = lipgloss.Color("#07110d")
border = lipgloss.Color("#00aa66") border = lipgloss.Color("#00aa66")
warn = lipgloss.Color("#ffaa00") warn = lipgloss.Color("#ffaa00")
baseStyle = lipgloss.NewStyle(). baseStyle = lipgloss.NewStyle().
Foreground(text) Foreground(text)
@@ -109,14 +112,15 @@ func initialModel() model {
} }
m := model{ m := model{
cfg: cfg, cfg: cfg,
servers: cfg.Servers, servers: cfg.Servers,
selected: 0, selected: 0,
view: ViewServers, view: ViewServers,
serverStatus: make(map[int]string), serverStatus: make(map[int]string),
} }
m.initAddInputs() m.initAddInputs()
m.initSettingsInput()
return m return m
} }
@@ -161,6 +165,16 @@ func (m *model) initAddInputs() {
} }
} }
func (m *model) initSettingsInput() {
input := textinput.New()
input.Placeholder = "TERM Override"
input.CharLimit = 80
input.Width = 32
input.SetValue(m.cfg.Settings.Terminal.Term)
m.settingsTermInput = input
}
func (m *model) saveNewServer() error { func (m *model) saveNewServer() error {
port, err := strconv.Atoi(m.addInputs[3].Value()) port, err := strconv.Atoi(m.addInputs[3].Value())
if err != nil { if err != nil {
@@ -240,7 +254,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
} }
m.serverStatus[msg.Index] = msg.Status m.serverStatus[msg.Index] = msg.Status
return m, nil return m, nil
case tea.KeyMsg: case tea.KeyMsg:
@@ -271,7 +285,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.addFocus = (m.addFocus + 1) % len(m.addInputs) m.addFocus = (m.addFocus + 1) % len(m.addInputs)
m.addInputs[m.addFocus].Focus() m.addInputs[m.addFocus].Focus()
return m, nil return m, nil
case "r": case "r":
return m, checkAllServerStatus(m.servers) return m, checkAllServerStatus(m.servers)
@@ -326,6 +340,74 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
} }
} }
if m.view == ViewSettings {
if m.settingsEditingTerm {
switch msg.String() {
case "ctrl+c":
return m, tea.Quit
case "esc":
m.settingsEditingTerm = false
m.settingsTermInput.Blur()
m.settingsTermInput.SetValue(m.cfg.Settings.Terminal.Term)
return m, nil
case "enter":
m.cfg.Settings.Terminal.Term = strings.TrimSpace(m.settingsTermInput.Value())
if err := m.saveSettings(); err != nil {
m.err = err
}
m.settingsEditingTerm = false
m.settingsTermInput.Blur()
return m, nil
}
var cmd tea.Cmd
m.settingsTermInput, cmd = m.settingsTermInput.Update(msg)
return m, cmd
}
switch msg.String() {
case "ctrl+c":
return m, tea.Quit
case "q", "esc":
m.view = ViewServers
return m, nil
case "up", "k":
if m.settingsSelected > 0 {
m.settingsSelected--
}
return m, nil
case "down", "j":
if m.settingsSelected < settingsOptionCount()-1 {
m.settingsSelected++
}
return m, nil
case "enter", " ":
switch m.settingsSelected {
case 0:
m.cfg.Settings.Terminal.EnableKittyFix = !m.cfg.Settings.Terminal.EnableKittyFix
if err := m.saveSettings(); err != nil {
m.err = err
}
case 1:
m.settingsEditingTerm = true
m.settingsTermInput.SetValue(m.cfg.Settings.Terminal.Term)
m.settingsTermInput.Focus()
case 2:
m.cfg.Settings.Theme = nextTheme(m.cfg.Settings.Theme)
if err := m.saveSettings(); err != nil {
m.err = err
}
}
return m, nil
}
}
// Normale Navigation // Normale Navigation
switch msg.String() { switch msg.String() {
case "ctrl+c": case "ctrl+c":
@@ -370,6 +452,8 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case "s": case "s":
m.view = ViewSettings m.view = ViewSettings
m.settingsEditingTerm = false
m.settingsTermInput.Blur()
return m, nil return m, nil
case "h": case "h":
@@ -451,7 +535,7 @@ func (m model) View() string {
case ViewCommands: case ViewCommands:
right = m.renderCommandsContent() right = m.renderCommandsContent()
case ViewCommandOutput: case ViewCommandOutput:
right = m.renderCommandOutputContent() right = m.renderCommandOutputContent()
default: default:
right = m.renderServerList() right = m.renderServerList()
} }
@@ -586,19 +670,57 @@ func (m model) renderServerList() string {
} }
func (m model) renderSettingsContent() string { func (m model) renderSettingsContent() string {
kittyValue := "aus"
if m.cfg.Settings.Terminal.EnableKittyFix {
kittyValue = "an"
}
termValue := m.cfg.Settings.Terminal.Term
if termValue == "" {
termValue = "xterm-256color"
}
themeValue := m.cfg.Settings.Theme
if themeValue == "" {
themeValue = "neon-green"
}
options := []string{
fmt.Sprintf("Kitty Fix global: %s", kittyValue),
fmt.Sprintf("TERM Override: %s", termValue),
fmt.Sprintf("Theme: %s", themeValue),
}
lines := []string{ lines := []string{
badgeStyle.Render(" SETTINGS "), badgeStyle.Render(" SETTINGS "),
"", "",
selectedStyle.Render("Terminal"), selectedStyle.Render("Terminal"),
fmt.Sprintf(" Kitty Fix global: %v", m.cfg.Settings.Terminal.EnableKittyFix), }
fmt.Sprintf(" TERM Override: %s", m.cfg.Settings.Terminal.Term),
for i, option := range options {
if i == 1 && m.settingsEditingTerm {
option = "TERM Override: " + m.settingsTermInput.View()
}
if i == m.settingsSelected {
lines = append(lines, selectedStyle.Render("> "+option))
} else {
lines = append(lines, normalStyle.Render(" "+option))
}
}
lines = append(lines,
"", "",
selectedStyle.Render("Hinweis"), selectedStyle.Render("Hinweis"),
" Wenn Kitty Fix aktiv ist, startet SSH mit TERM=xterm-256color.", " Wenn Kitty Fix aktiv ist, startet SSH mit dem gewählten TERM-Wert.",
" Das verhindert auf Ubuntu/Debian oft:", " Das verhindert auf Ubuntu/Debian oft:",
" 'Error opening terminal: xterm-kitty'", " 'Error opening terminal: xterm-kitty'",
"", "",
mutedStyle.Render("Später bauen wir hier Toggle-Optionen mit Enter ein."), mutedStyle.Render("↑/↓ Auswahl Enter/Space ändern Esc/q zurück"),
)
if m.settingsEditingTerm {
lines = append(lines, mutedStyle.Render("TERM bearbeiten: Enter speichern Esc abbrechen"))
} }
return panelStyle. return panelStyle.
@@ -607,6 +729,35 @@ func (m model) renderSettingsContent() string {
Render(strings.Join(lines, "\n")) Render(strings.Join(lines, "\n"))
} }
func settingsOptionCount() int {
return 3
}
func nextTheme(current string) string {
themes := []string{"neon-green", "cyan", "plain"}
for i, theme := range themes {
if current == theme {
return themes[(i+1)%len(themes)]
}
}
return themes[0]
}
func (m *model) saveSettings() error {
if m.cfg.Settings.Terminal.Term == "" {
m.cfg.Settings.Terminal.Term = "xterm-256color"
m.settingsTermInput.SetValue(m.cfg.Settings.Terminal.Term)
}
if m.cfg.Settings.Theme == "" {
m.cfg.Settings.Theme = "neon-green"
}
return config.SaveConfig(getConfigPath(), m.cfg)
}
func (m model) renderHelpContent() string { func (m model) renderHelpContent() string {
lines := []string{ lines := []string{
badgeStyle.Render(" HELP "), badgeStyle.Render(" HELP "),
@@ -731,7 +882,6 @@ func max(a, b int) int {
return b return b
} }
func (m *model) loadServerIntoForm(server models.Server) { func (m *model) loadServerIntoForm(server models.Server) {
m.initAddInputs() m.initAddInputs()
@@ -822,7 +972,6 @@ func (m *model) deleteSelectedServer() error {
return nil return nil
} }
func (m model) renderEditServerContent() string { func (m model) renderEditServerContent() string {
return m.renderServerFormContent(" EDIT SERVER ", "Server bearbeiten") return m.renderServerFormContent(" EDIT SERVER ", "Server bearbeiten")
} }
@@ -1154,4 +1303,4 @@ func main() {
fmt.Println("Fehler:", err) fmt.Println("Fehler:", err)
os.Exit(1) os.Exit(1)
} }
} }