Eddited Settings View
Added Interactive Settings View
This commit is contained in:
215
main.go
215
main.go
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user