From 9e9134f6591336067dd6f08a7158154e019c4540 Mon Sep 17 00:00:00 2001 From: kokopi-dev Date: Mon, 6 Apr 2026 03:36:51 +0900 Subject: [PATCH] add:remove server config func --- README.md | 18 ++++++++++ internal/pages/remove_server.go | 3 ++ internal/services/config.go | 8 +++++ internal/tui/tui.go | 1 + internal/tui/update.go | 63 ++++++++++++++++++++++++++++++++- internal/tui/view.go | 21 +++++++++++ 6 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 README.md create mode 100644 internal/pages/remove_server.go diff --git a/README.md b/README.md new file mode 100644 index 0000000..ad232a9 --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +# Main Repo is self-hosted on [Gitea](https://git.kokopi.dev/kokopi/filepass) +- This is a mirror + +# Filepass + +Originally hacked with bash, re-written in golang into a TUI. + +## Installation + +``` +./build.sh + +# restart shell or w.e +# should be able to just run: + +filepass +``` + diff --git a/internal/pages/remove_server.go b/internal/pages/remove_server.go new file mode 100644 index 0000000..d783622 --- /dev/null +++ b/internal/pages/remove_server.go @@ -0,0 +1,3 @@ +package pages + +type RemoveServerPageMsg struct{} diff --git a/internal/services/config.go b/internal/services/config.go index 93e9094..0aadac9 100644 --- a/internal/services/config.go +++ b/internal/services/config.go @@ -69,6 +69,14 @@ func (c *ConfigService) AddServer(name string, s Server) error { return c.flush() } +func (c *ConfigService) RemoveServer(name string) error { + if !c.HasServer(name) { + return fmt.Errorf("server %q not found", name) + } + delete(c.servers, name) + return c.flush() +} + func (c *ConfigService) flush() error { data, err := json.MarshalIndent(c.servers, "", " ") if err != nil { diff --git a/internal/tui/tui.go b/internal/tui/tui.go index 4023d67..41cb78c 100644 --- a/internal/tui/tui.go +++ b/internal/tui/tui.go @@ -18,6 +18,7 @@ const ( pageFileAction pageSend pageCleanAll + pageRemoveServer ) type TUIInterface struct { diff --git a/internal/tui/update.go b/internal/tui/update.go index d15f761..5ae33bb 100644 --- a/internal/tui/update.go +++ b/internal/tui/update.go @@ -22,6 +22,11 @@ type serverAddedMsg struct { servers map[string]services.Server } +type serverRemovedMsg struct { + name string + servers map[string]services.Server +} + type clearFlashMsg struct{} type storageFilesMsg struct { @@ -177,6 +182,21 @@ func (m TUIInterface) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.FileOpSuccess = "" return m, nil + case pages.RemoveServerPageMsg: + m.Page = pageRemoveServer + m.Selected = 0 + return m, nil + + case serverRemovedMsg: + m.Servers = msg.servers + m.ServerNames = sortedServerNames(msg.servers) + m.NoServers = len(msg.servers) == 0 + m.Page = pageConfig + m.MenuItems = pages.ConfigMenuItems() + m.Selected = 0 + m.FlashMsg = "✓ \"" + msg.name + "\" removed." + return m, clearFlashAfter(2 * time.Second) + case pages.CleanAllPageMsg: m.Page = pageCleanAll m.CleanInput = newCleanInput() @@ -266,6 +286,9 @@ func (m TUIInterface) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if m.Page == pageCleanAll { return m.updateCleanAll(msg) } + if m.Page == pageRemoveServer { + return m.updateRemoveServer(msg) + } switch msg.String() { case "up", "k": @@ -288,7 +311,9 @@ func (m TUIInterface) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, func() tea.Msg { return pages.AddServerPageMsg{} } case "server": return m, func() tea.Msg { return pages.SelectServerPageMsg{} } - // TODO: "edit", "remove" + case "remove": + return m, func() tea.Msg { return pages.RemoveServerPageMsg{} } + // TODO: "edit" } case "ctrl+c": m.Quitting = true @@ -473,6 +498,42 @@ func (m TUIInterface) updateSend(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) { return m, nil } +func (m TUIInterface) updateRemoveServer(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) { + last := len(m.ServerNames) - 1 + switch msg.String() { + case "up", "k": + if m.Selected > 0 { + m.Selected-- + } + case "down", "j": + if m.Selected < last { + m.Selected++ + } + case "enter": + if m.Selected >= 0 && m.Selected < len(m.ServerNames) { + name := m.ServerNames[m.Selected] + if err := m.Services.Config.RemoveServer(name); err != nil { + // surface error via flash on config page + m.Page = pageConfig + m.MenuItems = pages.ConfigMenuItems() + m.Selected = 0 + m.FlashMsg = "✗ " + err.Error() + return m, clearFlashAfter(3 * time.Second) + } + servers := m.Services.Config.Servers() + return m, func() tea.Msg { + return serverRemovedMsg{name: name, servers: servers} + } + } + case "ctrl+c": + m.Quitting = true + return m, tea.Quit + case "esc": + return m, func() tea.Msg { return pages.ConfigPageMsg{} } + } + return m, nil +} + func (m TUIInterface) updateCleanAll(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) { if m.CleanOpLoading { if msg.String() == "ctrl+c" { diff --git a/internal/tui/view.go b/internal/tui/view.go index 8c14196..243d4b5 100644 --- a/internal/tui/view.go +++ b/internal/tui/view.go @@ -38,6 +38,8 @@ func (m TUIInterface) subtitle() string { return "Send File" case pageCleanAll: return "Clean All" + case pageRemoveServer: + return "Remove Server" default: return "Secure file transfer" } @@ -71,6 +73,8 @@ func (m TUIInterface) View() tea.View { body = m.viewSend() case pageCleanAll: body = m.viewCleanAll() + case pageRemoveServer: + body = m.viewRemoveServer() default: body = m.viewMenu() } @@ -114,6 +118,12 @@ func (m TUIInterface) View() tea.View { footerHint("enter", "confirm") + footerSep() + footerHint("esc", "back") + case pageRemoveServer: + footerStr = footerHint("↑↓", "navigate") + + footerSep() + + footerHint("enter", "remove") + + footerSep() + + footerHint("esc", "back") case pageCleanAll: footerStr = footerHint("enter", "confirm") + footerSep() + @@ -262,6 +272,17 @@ func (m TUIInterface) viewSend() string { return lipgloss.JoinVertical(lipgloss.Left, crumb, queryLine, list) } +func (m TUIInterface) viewRemoveServer() string { + if len(m.ServerNames) == 0 { + return styles.StatusWarnStyle.Render("⚠ No servers configured.") + } + var rows []string + for i, name := range m.ServerNames { + rows = append(rows, styles.ServerRowStyle(i == m.Selected, name)) + } + return lipgloss.JoinVertical(lipgloss.Left, rows...) +} + func (m TUIInterface) viewCleanAll() string { fileCount := len(m.StorageFiles) warning := styles.CleanWarningStyle.Render(