add:clean all func

This commit is contained in:
2026-04-06 03:26:02 +09:00
parent e39ee1694d
commit 83aab9d943
7 changed files with 138 additions and 3 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
.env .env
dist

View File

@@ -0,0 +1,5 @@
package pages
type CleanAllPageMsg struct {
ServerName string
}

View File

@@ -77,6 +77,14 @@ func (s *StorageService) Send(localPaths []string) error {
// CleanAll removes all files from remote storage. // CleanAll removes all files from remote storage.
func (s *StorageService) CleanAll() error { func (s *StorageService) CleanAll() error {
// TODO: implement cmd := SSHCmd(s.server,
return fmt.Errorf("clean all: not yet implemented") "rm -f "+defaultStoragePath+"/*",
)
debugLog("CleanAll | args: %v", cmd.Args)
out, err := cmd.CombinedOutput()
debugLog("CleanAll | exit_err: %v | output: %q", err, strings.TrimSpace(string(out)))
if err != nil {
return fmt.Errorf("clean all failed: %w\n%s", err, strings.TrimSpace(string(out)))
}
return nil
} }

View File

@@ -86,6 +86,12 @@ var (
Foreground(lipgloss.Color("203")). Foreground(lipgloss.Color("203")).
MarginTop(1) MarginTop(1)
CleanWarningStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("203")).
Bold(true).
MarginBottom(1).
Width(44)
// Footer // Footer
FooterStyle = lipgloss.NewStyle(). FooterStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("240")). Foreground(lipgloss.Color("240")).

View File

@@ -3,6 +3,8 @@ package tui
import ( import (
"filepass/internal/pages" "filepass/internal/pages"
"filepass/internal/services" "filepass/internal/services"
"charm.land/bubbles/v2/textinput"
) )
type page int type page int
@@ -15,6 +17,7 @@ const (
pageServerActions pageServerActions
pageFileAction pageFileAction
pageSend pageSend
pageCleanAll
) )
type TUIInterface struct { type TUIInterface struct {
@@ -45,6 +48,10 @@ type TUIInterface struct {
FileOpLoading bool FileOpLoading bool
FileOpErr error FileOpErr error
FileOpSuccess string FileOpSuccess string
// clean all confirmation page
CleanInput textinput.Model
CleanOpLoading bool
CleanOpErr error
// send / file picker page // send / file picker page
Picker picker Picker picker
} }

View File

@@ -8,6 +8,7 @@ import (
"filepass/internal/pages" "filepass/internal/pages"
"filepass/internal/services" "filepass/internal/services"
"charm.land/bubbles/v2/textinput"
tea "charm.land/bubbletea/v2" tea "charm.land/bubbletea/v2"
) )
@@ -60,6 +61,30 @@ func deleteFileCmd(store *services.ServicesStore, serverName, filename string) t
} }
} }
type cleanAllMsg struct {
err error
}
func cleanAllCmd(store *services.ServicesStore, serverName string) tea.Cmd {
return func() tea.Msg {
storage, err := store.NewStorageService(serverName)
if err != nil {
return cleanAllMsg{err: err}
}
return cleanAllMsg{err: storage.CleanAll()}
}
}
func newCleanInput() textinput.Model {
ti := textinput.New()
ti.Placeholder = "yes"
ti.Prompt = ""
ti.CharLimit = 3
ti.SetWidth(10)
ti.Focus()
return ti
}
func checkStorageCmd(store *services.ServicesStore, serverName string) tea.Cmd { func checkStorageCmd(store *services.ServicesStore, serverName string) tea.Cmd {
return func() tea.Msg { return func() tea.Msg {
storage, err := store.NewStorageService(serverName) storage, err := store.NewStorageService(serverName)
@@ -152,6 +177,22 @@ func (m TUIInterface) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.FileOpSuccess = "" m.FileOpSuccess = ""
return m, nil return m, nil
case pages.CleanAllPageMsg:
m.Page = pageCleanAll
m.CleanInput = newCleanInput()
m.CleanOpLoading = false
m.CleanOpErr = nil
return m, nil
case cleanAllMsg:
m.CleanOpLoading = false
if msg.err != nil {
m.CleanOpErr = msg.err
return m, nil
}
server := m.ActiveServer
return m, func() tea.Msg { return pages.ServerActionsPageMsg{ServerName: server} }
case pages.SendPageMsg: case pages.SendPageMsg:
m.Page = pageSend m.Page = pageSend
m.Picker = newPicker(m.LocalDir) m.Picker = newPicker(m.LocalDir)
@@ -222,6 +263,9 @@ func (m TUIInterface) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if m.Page == pageSend { if m.Page == pageSend {
return m.updateSend(msg) return m.updateSend(msg)
} }
if m.Page == pageCleanAll {
return m.updateCleanAll(msg)
}
switch msg.String() { switch msg.String() {
case "up", "k": case "up", "k":
@@ -313,7 +357,7 @@ func (m TUIInterface) updateServerActions(msg tea.KeyPressMsg) (tea.Model, tea.C
case "send": case "send":
return m, func() tea.Msg { return pages.SendPageMsg{ServerName: server} } return m, func() tea.Msg { return pages.SendPageMsg{ServerName: server} }
case "clean": case "clean":
// TODO: navigate to clean all page return m, func() tea.Msg { return pages.CleanAllPageMsg{ServerName: server} }
} }
case "ctrl+c": case "ctrl+c":
@@ -429,6 +473,36 @@ func (m TUIInterface) updateSend(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
return m, nil return m, nil
} }
func (m TUIInterface) updateCleanAll(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
if m.CleanOpLoading {
if msg.String() == "ctrl+c" {
m.Quitting = true
return m, tea.Quit
}
return m, nil
}
switch msg.String() {
case "enter":
if m.CleanInput.Value() == "yes" {
m.CleanOpLoading = true
m.CleanOpErr = nil
return m, cleanAllCmd(m.Services, m.ActiveServer)
}
case "ctrl+c":
m.Quitting = true
return m, tea.Quit
case "esc":
server := m.ActiveServer
return m, func() tea.Msg { return pages.ServerActionsPageMsg{ServerName: server} }
}
// route all other keys to the text input
var cmd tea.Cmd
m.CleanInput, cmd = m.CleanInput.Update(msg)
return m, cmd
}
func (m TUIInterface) updateSelectServer(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) { func (m TUIInterface) updateSelectServer(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
last := len(m.ServerNames) - 1 last := len(m.ServerNames) - 1
switch msg.String() { switch msg.String() {

View File

@@ -1,6 +1,8 @@
package tui package tui
import ( import (
"fmt"
"filepass/internal/styles" "filepass/internal/styles"
tea "charm.land/bubbletea/v2" tea "charm.land/bubbletea/v2"
@@ -34,6 +36,8 @@ func (m TUIInterface) subtitle() string {
return m.ActiveFile return m.ActiveFile
case pageSend: case pageSend:
return "Send File" return "Send File"
case pageCleanAll:
return "Clean All"
default: default:
return "Secure file transfer" return "Secure file transfer"
} }
@@ -65,6 +69,8 @@ func (m TUIInterface) View() tea.View {
body = m.viewFileAction() body = m.viewFileAction()
case pageSend: case pageSend:
body = m.viewSend() body = m.viewSend()
case pageCleanAll:
body = m.viewCleanAll()
default: default:
body = m.viewMenu() body = m.viewMenu()
} }
@@ -108,6 +114,10 @@ func (m TUIInterface) View() tea.View {
footerHint("enter", "confirm") + footerHint("enter", "confirm") +
footerSep() + footerSep() +
footerHint("esc", "back") footerHint("esc", "back")
case pageCleanAll:
footerStr = footerHint("enter", "confirm") +
footerSep() +
footerHint("esc", "back")
case pageSend: case pageSend:
footerStr = footerHint("↑↓", "navigate") + footerStr = footerHint("↑↓", "navigate") +
footerSep() + footerSep() +
@@ -252,6 +262,30 @@ func (m TUIInterface) viewSend() string {
return lipgloss.JoinVertical(lipgloss.Left, crumb, queryLine, list) return lipgloss.JoinVertical(lipgloss.Left, crumb, queryLine, list)
} }
func (m TUIInterface) viewCleanAll() string {
fileCount := len(m.StorageFiles)
warning := styles.CleanWarningStyle.Render(
fmt.Sprintf("This will permanently delete all %d file(s) from remote storage.", fileCount),
)
promptLabel := styles.FieldLabelStyle(true).Render("Type \"yes\" to confirm")
input := m.CleanInput.View()
var statusLine string
switch {
case m.CleanOpLoading:
statusLine = styles.StatusWarnStyle.Render(" deleting…")
case m.CleanOpErr != nil:
statusLine = styles.StatusErrStyle.Render("✗ " + m.CleanOpErr.Error())
}
parts := []string{warning, promptLabel, input}
if statusLine != "" {
parts = append(parts, statusLine)
}
return lipgloss.JoinVertical(lipgloss.Left, parts...)
}
func (m TUIInterface) viewSelectServer() string { func (m TUIInterface) viewSelectServer() string {
if len(m.ServerNames) == 0 { if len(m.ServerNames) == 0 {
return styles.StatusWarnStyle.Render("⚠ No servers configured.") return styles.StatusWarnStyle.Render("⚠ No servers configured.")