add:get and delete func

This commit is contained in:
2026-04-06 03:12:19 +09:00
parent 5e44a3a35c
commit e39ee1694d
7 changed files with 138 additions and 22 deletions

View File

@@ -41,7 +41,10 @@ type TUIInterface struct {
FileSelected int // cursor within StorageFiles
FileFocused bool // true = ↑↓ drives file list, false = action menu
// file action page
ActiveFile string
ActiveFile string
FileOpLoading bool
FileOpErr error
FileOpSuccess string
// send / file picker page
Picker picker
}

View File

@@ -28,6 +28,38 @@ type storageFilesMsg struct {
err error
}
type fileOpMsg struct {
op string // "get" or "delete"
err error
success string
}
func getFileCmd(store *services.ServicesStore, serverName, filename, destDir string) tea.Cmd {
return func() tea.Msg {
storage, err := store.NewStorageService(serverName)
if err != nil {
return fileOpMsg{op: "get", err: err}
}
if err := storage.Get(filename, destDir); err != nil {
return fileOpMsg{op: "get", err: err}
}
return fileOpMsg{op: "get", success: "✓ Downloaded \"" + filename + "\""}
}
}
func deleteFileCmd(store *services.ServicesStore, serverName, filename string) tea.Cmd {
return func() tea.Msg {
storage, err := store.NewStorageService(serverName)
if err != nil {
return fileOpMsg{op: "delete", err: err}
}
if err := storage.Delete(filename); err != nil {
return fileOpMsg{op: "delete", err: err}
}
return fileOpMsg{op: "delete", success: "✓ Deleted \"" + filename + "\""}
}
}
func checkStorageCmd(store *services.ServicesStore, serverName string) tea.Cmd {
return func() tea.Msg {
storage, err := store.NewStorageService(serverName)
@@ -115,6 +147,9 @@ func (m TUIInterface) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.ActiveFile = msg.Filename
m.MenuItems = pages.FileActionItems()
m.Selected = 0
m.FileOpLoading = false
m.FileOpErr = nil
m.FileOpSuccess = ""
return m, nil
case pages.SendPageMsg:
@@ -122,6 +157,19 @@ func (m TUIInterface) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.Picker = newPicker(m.LocalDir)
return m, nil
case fileOpMsg:
m.FileOpLoading = false
if msg.err != nil {
m.FileOpErr = msg.err
return m, nil
}
// on success: return to server actions and refresh file list
server := m.ActiveServer
return m, tea.Batch(
func() tea.Msg { return pages.ServerActionsPageMsg{ServerName: server} },
clearFlashAfter(0), // immediate clear of any stale flash
)
case storageFilesMsg:
m.StorageLoading = false
m.StorageFiles = msg.files
@@ -280,6 +328,15 @@ func (m TUIInterface) updateServerActions(msg tea.KeyPressMsg) (tea.Model, tea.C
}
func (m TUIInterface) updateFileAction(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
// block input while an operation is running
if m.FileOpLoading {
if msg.String() == "ctrl+c" {
m.Quitting = true
return m, tea.Quit
}
return m, nil
}
switch msg.String() {
case "up", "k":
if m.Selected > 0 {
@@ -294,13 +351,15 @@ func (m TUIInterface) updateFileAction(msg tea.KeyPressMsg) (tea.Model, tea.Cmd)
file := m.ActiveFile
switch m.MenuItems[m.Selected].Key {
case "get":
_ = server
_ = file
// TODO: implement get
m.FileOpLoading = true
m.FileOpErr = nil
m.FileOpSuccess = ""
return m, getFileCmd(m.Services, server, file, m.LocalDir)
case "delete":
_ = server
_ = file
// TODO: implement delete
m.FileOpLoading = true
m.FileOpErr = nil
m.FileOpSuccess = ""
return m, deleteFileCmd(m.Services, server, file)
}
case "ctrl+c":
m.Quitting = true

View File

@@ -207,11 +207,25 @@ func (m TUIInterface) viewFileAction() string {
var menuRows []string
for i, item := range m.MenuItems {
menuRows = append(menuRows, styles.MenuItemStyle(i == m.Selected, false).Render(item.Label))
disabled := m.FileOpLoading
active := !disabled && i == m.Selected
menuRows = append(menuRows, styles.MenuItemStyle(active, disabled).Render(item.Label))
}
menu := lipgloss.JoinVertical(lipgloss.Left, menuRows...)
return lipgloss.JoinVertical(lipgloss.Left, filenameLabel, menu)
var statusLine string
switch {
case m.FileOpLoading:
statusLine = styles.StatusWarnStyle.Render(" working…")
case m.FileOpErr != nil:
statusLine = styles.StatusErrStyle.Render("✗ " + m.FileOpErr.Error())
}
parts := []string{filenameLabel, menu}
if statusLine != "" {
parts = append(parts, statusLine)
}
return lipgloss.JoinVertical(lipgloss.Left, parts...)
}
func (m TUIInterface) viewSend() string {