diff --git a/cmd/slackdump/internal/workspace/wiz_select.go b/cmd/slackdump/internal/workspace/wiz_select.go index 11157f6b..45231e6b 100644 --- a/cmd/slackdump/internal/workspace/wiz_select.go +++ b/cmd/slackdump/internal/workspace/wiz_select.go @@ -44,42 +44,46 @@ func wizSelect(ctx context.Context, cmd *base.Command, args []string) error { } // newWspSelectModel creates a new workspace selection model. -func newWspSelectModel(ctx context.Context, m manager) (tea.Model, error) { - wspList, err := m.List() +func newWspSelectModel(ctx context.Context, m *cache.Manager) (tea.Model, error) { + _, err := m.List() if err != nil { if errors.Is(err, cache.ErrNoWorkspaces) { if err := workspaceui.ShowUI(ctx, true); err != nil { return nil, err } - // retry - wspList, err = m.List() - if err != nil { - return nil, err - } } else { base.SetExitStatus(base.SUserError) return nil, err } } - current, err := m.Current() - if err != nil { + if _, err := m.Current(); err != nil { base.SetExitStatus(base.SWorkspaceError) return nil, fmt.Errorf("error getting the current workspace: %s", err) } - columns := []table.Column{ - {Title: "C", Width: 1}, - {Title: "Name", Width: 14}, - {Title: "Team", Width: 15}, - {Title: "User", Width: 15}, - {Title: "Status", Width: 30}, - } + var refreshFn = func() (cols []table.Column, rows []table.Row, err error) { + cols = []table.Column{ + {Title: "C", Width: 1}, + {Title: "Name", Width: 14}, + {Title: "Team", Width: 15}, + {Title: "User", Width: 15}, + {Title: "Status", Width: 30}, + } - var rows []table.Row - for _, w := range wspInfo(ctx, m, current, wspList) { - rows = append(rows, table.Row{w[0], w[1], w[4], w[5], w[6]}) + wspList, err := m.List() + if err != nil { + return + } + current, err := m.Current() + if err != nil { + return + } + for _, w := range wspInfo(ctx, m, current, wspList) { + rows = append(rows, table.Row{w[0], w[1], w[4], w[5], w[6]}) + } + return cols, rows, nil } - return workspaceui.NewSelectModel(columns, rows), nil + return workspaceui.NewSelectModel(m, refreshFn), nil } diff --git a/cmd/slackdump/internal/workspace/workspaceui/workspaceui.go b/cmd/slackdump/internal/workspace/workspaceui/new.go similarity index 98% rename from cmd/slackdump/internal/workspace/workspaceui/workspaceui.go rename to cmd/slackdump/internal/workspace/workspaceui/new.go index dce11ddd..98c088db 100644 --- a/cmd/slackdump/internal/workspace/workspaceui/workspaceui.go +++ b/cmd/slackdump/internal/workspace/workspaceui/new.go @@ -19,6 +19,8 @@ import ( //go:generate mockgen -package workspaceui -destination=test_mock_manager.go -source api.go manager type manager interface { CreateAndSelect(ctx context.Context, p auth.Provider) (string, error) + Select(name string) error + Delete(name string) error } func WorkspaceNew(ctx context.Context, _ *base.Command, _ []string) error { diff --git a/cmd/slackdump/internal/workspace/workspaceui/select.go b/cmd/slackdump/internal/workspace/workspaceui/select.go index a38f53c3..6fa4411a 100644 --- a/cmd/slackdump/internal/workspace/workspaceui/select.go +++ b/cmd/slackdump/internal/workspace/workspaceui/select.go @@ -1,6 +1,8 @@ package workspaceui import ( + "strings" + "github.com/charmbracelet/bubbles/help" "github.com/charmbracelet/bubbles/key" "github.com/charmbracelet/bubbles/table" @@ -10,16 +12,22 @@ import ( ) type SelectModel struct { - Selected string + Selected string + m manager + refreshFn TableRefreshFunc table table.Model finished bool style style keymap selKeymap help help.Model + lastErr error } -func NewSelectModel(columns []table.Column, rows []table.Row) SelectModel { +type TableRefreshFunc func() ([]table.Column, []table.Row, error) + +func NewSelectModel(m manager, refreshFn TableRefreshFunc) SelectModel { + columns, rows, err := refreshFn() t := table.New( table.WithColumns(columns), table.WithRows(rows), @@ -35,23 +43,33 @@ func NewSelectModel(columns []table.Column, rows []table.Row) SelectModel { t.SetStyles(s) t.Focus() return SelectModel{ - table: t, + table: t, + m: m, + refreshFn: refreshFn, style: style{ FocusedBorder: ui.DefaultTheme().Focused.Border, + Title: ui.DefaultTheme().Focused.Title, + Description: ui.DefaultTheme().Focused.Description, + Error: ui.DefaultTheme().Error, }, - keymap: defSelKeymap(), - help: help.New(), + keymap: defSelKeymap(), + help: help.New(), + lastErr: err, } } type style struct { FocusedBorder lipgloss.Style + Title lipgloss.Style + Description lipgloss.Style + Error lipgloss.Style } type selKeymap struct { - Select key.Binding - Delete key.Binding - Quit key.Binding + Select key.Binding + Delete key.Binding + Quit key.Binding + Refresh key.Binding } func (k selKeymap) Bindings() []key.Binding { @@ -60,27 +78,45 @@ func (k selKeymap) Bindings() []key.Binding { func defSelKeymap() selKeymap { return selKeymap{ - Select: key.NewBinding(key.WithKeys("enter"), key.WithHelp("Enter", "Select")), - Delete: key.NewBinding(key.WithKeys("x", "delete"), key.WithHelp("del", "Delete")), - Quit: key.NewBinding(key.WithKeys("q", "ctrl+c", "esc"), key.WithHelp("esc", "Quit")), + Select: key.NewBinding(key.WithKeys("enter"), key.WithHelp("Enter", "Select")), + Delete: key.NewBinding(key.WithKeys("x", "delete"), key.WithHelp("del", "Delete")), + Quit: key.NewBinding(key.WithKeys("q", "ctrl+c", "esc"), key.WithHelp("esc", "Quit")), + Refresh: key.NewBinding(key.WithKeys("ctrl+r"), key.WithHelp("^r", "Refresh")), } } func (m SelectModel) Init() tea.Cmd { return nil } func (m SelectModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + var refresh = func() { + columns, rows, err := m.refreshFn() + m.table.SetColumns(columns) + m.table.SetRows(rows) + m.lastErr = err + } + var cmd tea.Cmd var cmds []tea.Cmd switch msg := msg.(type) { case tea.KeyMsg: switch { - case key.Matches(msg, m.keymap.Quit): - m.finished = true - cmds = append(cmds, tea.Quit) case key.Matches(msg, m.keymap.Select): + if len(m.table.SelectedRow()) == 0 { + break + } m.Selected = m.table.SelectedRow()[1] + fallthrough + case key.Matches(msg, m.keymap.Quit): m.finished = true cmds = append(cmds, tea.Quit) + case key.Matches(msg, m.keymap.Delete): + if len(m.table.SelectedRow()) == 0 { + break + } + m.lastErr = m.m.Delete(m.table.SelectedRow()[1]) + refresh() + case key.Matches(msg, m.keymap.Refresh): + refresh() } } m.table, cmd = m.table.Update(msg) @@ -92,5 +128,15 @@ func (m SelectModel) View() string { if m.finished { return "" // don't render the table if we've selected a workspace } - return m.style.FocusedBorder.Render((m.table.View()) + "\n\n" + m.help.ShortHelpView(m.keymap.Bindings())) + var b strings.Builder + + b.WriteString(m.style.Title.Render("Slackdump Workspaces") + "\n") + b.WriteString(m.style.Description.Render("Select a workspace to work with") + "\n\n") + b.WriteString(m.table.View() + "\n") + if m.lastErr != nil { + b.WriteString(m.style.Error.Render(m.lastErr.Error()) + "\n") + } + b.WriteString(m.help.ShortHelpView(m.keymap.Bindings())) + + return m.style.FocusedBorder.Render(b.String()) }