diff --git a/cmd/slackdump/internal/workspace/wiz_select.go b/cmd/slackdump/internal/workspace/wiz_select.go index cd0f1201..11157f6b 100644 --- a/cmd/slackdump/internal/workspace/wiz_select.go +++ b/cmd/slackdump/internal/workspace/wiz_select.go @@ -23,14 +23,11 @@ func wizSelect(ctx context.Context, cmd *base.Command, args []string) error { return err } - sm, err := workspaceSelectModel(ctx, m) + sm, err := newWspSelectModel(ctx, m) if err != nil { return err } - if sm == nil { - // TODO: handle this case - return nil - } + mod, err := tea.NewProgram(sm).Run() if err != nil { return fmt.Errorf("workspace select wizard error: %w", err) @@ -46,7 +43,8 @@ func wizSelect(ctx context.Context, cmd *base.Command, args []string) error { return nil } -func workspaceSelectModel(ctx context.Context, m manager) (tea.Model, error) { +// newWspSelectModel creates a new workspace selection model. +func newWspSelectModel(ctx context.Context, m manager) (tea.Model, error) { wspList, err := m.List() if err != nil { if errors.Is(err, cache.ErrNoWorkspaces) { diff --git a/cmd/slackdump/internal/workspace/workspaceui/select.go b/cmd/slackdump/internal/workspace/workspaceui/select.go index 49eac98b..a38f53c3 100644 --- a/cmd/slackdump/internal/workspace/workspaceui/select.go +++ b/cmd/slackdump/internal/workspace/workspaceui/select.go @@ -1,6 +1,8 @@ package workspaceui import ( + "github.com/charmbracelet/bubbles/help" + "github.com/charmbracelet/bubbles/key" "github.com/charmbracelet/bubbles/table" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" @@ -13,6 +15,8 @@ type SelectModel struct { table table.Model finished bool style style + keymap selKeymap + help help.Model } func NewSelectModel(columns []table.Column, rows []table.Row) SelectModel { @@ -35,6 +39,8 @@ func NewSelectModel(columns []table.Column, rows []table.Row) SelectModel { style: style{ FocusedBorder: ui.DefaultTheme().Focused.Border, }, + keymap: defSelKeymap(), + help: help.New(), } } @@ -42,6 +48,24 @@ type style struct { FocusedBorder lipgloss.Style } +type selKeymap struct { + Select key.Binding + Delete key.Binding + Quit key.Binding +} + +func (k selKeymap) Bindings() []key.Binding { + return []key.Binding{k.Select, k.Delete, k.Quit} +} + +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")), + } +} + func (m SelectModel) Init() tea.Cmd { return nil } func (m SelectModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { @@ -49,11 +73,11 @@ func (m SelectModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmds []tea.Cmd switch msg := msg.(type) { case tea.KeyMsg: - switch msg.String() { - case "q", "ctrl+c", "esc": + switch { + case key.Matches(msg, m.keymap.Quit): m.finished = true cmds = append(cmds, tea.Quit) - case "enter": + case key.Matches(msg, m.keymap.Select): m.Selected = m.table.SelectedRow()[1] m.finished = true cmds = append(cmds, tea.Quit) @@ -68,5 +92,5 @@ 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" + ui.HuhTheme().Help.Ellipsis.Render("Select the workspace with arrow keys, press [Enter] to confirm, [Esc] to cancel.")) + return m.style.FocusedBorder.Render((m.table.View()) + "\n\n" + m.help.ShortHelpView(m.keymap.Bindings())) } diff --git a/internal/network/limits.go b/internal/network/limits.go index c8a4286c..3abe285b 100644 --- a/internal/network/limits.go +++ b/internal/network/limits.go @@ -1,8 +1,6 @@ package network import ( - "reflect" - "github.com/go-playground/locales/en" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" @@ -11,39 +9,39 @@ import ( type Limits struct { // number of file-saving workers - Workers int `json:"workers,omitempty" yaml:"workers,omitempty" validate:"gte=1,lte=128"` + Workers int `json:"workers,omitempty" yaml:"workers,omitempty" toml:"workers,omitempty" validate:"gte=1,lte=128"` // if we get rate limited on file downloads, this is how many times we're // going to retry - DownloadRetries int `json:"download_retries,omitempty" yaml:"download_retries,omitempty"` + DownloadRetries int `json:"download_retries,omitempty" yaml:"download_retries,omitempty" toml:"download_retries,omitempty"` // Tier-2 limits - Tier2 TierLimit `json:"tier_2,omitempty" yaml:"tier_2,omitempty"` + Tier2 TierLimit `json:"tier_2,omitempty" yaml:"tier_2,omitempty" toml:"tier_2,omitempty"` // Tier-3 limits - Tier3 TierLimit `json:"tier_3,omitempty" yaml:"tier_3,omitempty"` + Tier3 TierLimit `json:"tier_3,omitempty" yaml:"tier_3,omitempty" toml:"tier_3,omitempty"` // Tier-4 limits - Tier4 TierLimit `json:"tier_4,omitempty" yaml:"tier_4,omitempty"` + Tier4 TierLimit `json:"tier_4,omitempty" yaml:"tier_4,omitempty" toml:"tier_4,omitempty"` // Request Limits - Request RequestLimit `json:"per_request,omitempty" yaml:"per_request,omitempty"` + Request RequestLimit `json:"per_request,omitempty" yaml:"per_request,omitempty" toml:"per_request,omitempty"` } // TierLimit represents a Slack API Tier limits. type TierLimit struct { // Tier limiter boost - Boost uint `json:"boost,omitempty" yaml:"boost,omitempty"` + Boost uint `json:"boost,omitempty" yaml:"boost,omitempty" toml:"boost,omitempty"` // Tier limiter burst - Burst uint `json:"burst,omitempty" yaml:"burst,omitempty" validate:"gte=1"` + Burst uint `json:"burst,omitempty" yaml:"burst,omitempty" validate:"gte=1" toml:"burst,omitempty"` // Tier retries when getting transient errors, i.e. 429 or 500-599. - Retries int `json:"retries,omitempty" yaml:"retries,omitempty"` + Retries int `json:"retries,omitempty" yaml:"retries,omitempty" toml:"retries,omitempty" validate:"gte=1"` } // RequestLimit defines the limits on the requests that are sent to the API. type RequestLimit struct { // number of messages we get per 1 API request. bigger the number, fewer // requests, but they become more beefy. - Conversations int `json:"conversations,omitempty" yaml:"conversations,omitempty" validate:"gt=0,lte=100"` + Conversations int `json:"conversations,omitempty" yaml:"conversations,omitempty" validate:"gt=0,lte=100" toml:"conversations,omitempty"` // number of channels to fetch per 1 API request. - Channels int `json:"channels,omitempty" yaml:"channels,omitempty" validate:"gt=0,lte=1000"` + Channels int `json:"channels,omitempty" yaml:"channels,omitempty" validate:"gt=0,lte=1000" toml:"channels,omitempty"` // number of thread replies per request (slack default: 1000) - Replies int `json:"replies,omitempty" yaml:"replies,omitempty" validate:"gt=0,lte=1000"` + Replies int `json:"replies,omitempty" yaml:"replies,omitempty" validate:"gt=0,lte=1000" toml:"replies,omitempty"` } var DefLimits = Limits{ @@ -143,6 +141,6 @@ func apply[T comparable](this *T, other T) { } } -func isZero(a any) bool { - return a == reflect.Zero(reflect.TypeOf(a)).Interface() -} +// func isZero(a any) bool { +// return a == reflect.Zero(reflect.TypeOf(a)).Interface() +// }