Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/interactive input #133

Merged
merged 4 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
*__debug_bin1675735721
.DS_Store
.env
components/mdz/bin/mdz
.idea
*.iml
components/ledger/_docker-compose.yml
Binary file modified components/mdz/bin/mdz
Binary file not shown.
2 changes: 1 addition & 1 deletion components/mdz/internal/rest/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func (r *Auth) AuthenticateWithCredentials(username, password string) (*model.To
}

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("error: status %d - %w", resp.StatusCode, err)
return nil, fmt.Errorf("status %d", resp.StatusCode)
}

var tokenResponse model.TokenResponse
Expand Down
26 changes: 23 additions & 3 deletions components/mdz/pkg/cmd/login/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,24 @@ type factoryLogin struct {
auth repository.Auth
}

func validateCredentials(username, password string) error {
if len(username) == 0 {
return errors.New("username must not be empty")
}

if len(password) == 0 {
return errors.New("password must not be empty")
}

return nil
}

func (l *factoryLogin) runE(cmd *cobra.Command, _ []string) error {
if cmd.Flags().Changed("username") &&
cmd.Flags().Changed("password") &&
len(l.username) > 0 && len(l.password) > 0 {
if cmd.Flags().Changed("username") && cmd.Flags().Changed("password") {
if err := validateCredentials(l.username, l.password); err != nil {
return err
}

r := rest.Auth{Factory: l.factory}
_, err := r.AuthenticateWithCredentials(l.username, l.password)

Expand All @@ -37,6 +51,8 @@ func (l *factoryLogin) runE(cmd *cobra.Command, _ []string) error {
}

output.Printf(l.factory.IOStreams.Out, color.New(color.Bold).Sprint("Successfully logged in"))

return nil
}

option, err := tui.Select(
Expand Down Expand Up @@ -84,6 +100,10 @@ func (l *factoryLogin) execMethodLogin(answer string) error {
case strings.Contains(answer, "terminal"):
err := l.terminalLogin()

if err := validateCredentials(l.username, l.password); err != nil {
return err
}

if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion components/mdz/pkg/cmd/login/term.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func (l *factoryLogin) terminalLogin() error {
}

if len(l.password) == 0 {
l.password, err = tui.Password()
l.password, err = tui.Password("Enter your password")
if err != nil {
return err
}
Expand Down
9 changes: 0 additions & 9 deletions components/mdz/pkg/tui/constant.go

This file was deleted.

77 changes: 28 additions & 49 deletions components/mdz/pkg/tui/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package tui
import (
"fmt"

"github.com/charmbracelet/bubbles/textinput"
tea "github.com/charmbracelet/bubbletea"
)

Expand All @@ -12,80 +13,58 @@ func Input(message string) (string, error) {

func runInput(m tea.Model) (string, error) {
p := tea.NewProgram(m)
finalModel, err := p.Run()

finalModel, err := p.Run()
if err != nil {
return "", fmt.Errorf("erro ao iniciar o programa: %w", err)
return "", fmt.Errorf("error starting program: %w", err)
}

if pm, ok := finalModel.(inputModel); ok && pm.entered {
return pm.input, nil
if im, ok := finalModel.(inputModel); ok && im.inputDone {
return im.textInput.Value(), nil
}

return "", nil
}

func initialInputModel(message string) inputModel {
return inputModel{message: message}
type inputModel struct {
textInput textinput.Model
message string
inputDone bool
}

type inputModel struct {
message string
input string
cursor int
entered bool
func initialInputModel(message string) inputModel {
ti := textinput.New()
ti.Placeholder = "..."
ti.Focus()
ti.CharLimit = 156
ti.Width = 20

return inputModel{textInput: ti, message: message}
}

func (m inputModel) Init() tea.Cmd {
return nil
return textinput.Blink
}

func (m inputModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd

switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case ctrlC:
switch msg.Type {
case tea.KeyCtrlC, tea.KeyEsc:
return m, tea.Quit
case enter:
m.entered = true
case tea.KeyEnter:
m.inputDone = true
return m, tea.Quit
case backspace:
if m.cursor > 0 {
m.input = m.input[:m.cursor-1] + m.input[m.cursor:]
m.cursor--
}
case left:
if m.cursor > 0 {
m.cursor--
}
case right:
if m.cursor < len(m.input) {
m.cursor++
}
default:
// Adiciona o caractere digitado à entrada
m.input = m.input[:m.cursor] + msg.String() + m.input[m.cursor:]
m.cursor++
}
}

return m, nil
m.textInput, cmd = m.textInput.Update(msg)

return m, cmd
}

func (m inputModel) View() string {
if m.entered {
return "Entry received!\n"
}

return fmt.Sprintf("%s: %s\n", m.message, m.input)
return fmt.Sprintf("%s %s\n", m.message, m.textInput.View())
}

// Example of using
// func main() {
// input, err := Input("Enter your name")
// if err != nil {
// fmt.Fprintf(os.Stderr, "Error: %v\n", err)
// os.Exit(1)
// }

// fmt.Printf("Name entered: %s\n", input)
89 changes: 32 additions & 57 deletions components/mdz/pkg/tui/password.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,96 +2,71 @@ package tui

import (
"fmt"
"strings"

"github.com/charmbracelet/bubbles/textinput"
tea "github.com/charmbracelet/bubbletea"
)

func Password() (string, error) {
return runPassword(initialPasswordModel())
func Password(message string) (string, error) {
return runPasswordInput(initialPasswordInputModel(message))
}

func runPassword(m tea.Model) (string, error) {
func runPasswordInput(m tea.Model) (string, error) {
p := tea.NewProgram(m)

finalModel, err := p.Run()
if err != nil {
return "", fmt.Errorf("error starting the program: %w", err)
return "", fmt.Errorf("error starting program: %w", err)
}

if pm, ok := finalModel.(passwordModel); ok && pm.entered {
return pm.password, nil
if im, ok := finalModel.(passwordModel); ok && im.inputDone {
return im.textInput.Value(), nil
}

return "", nil
}

func initialPasswordModel() passwordModel {
return passwordModel{}
type passwordModel struct {
textInput textinput.Model
message string
inputDone bool
}

type passwordModel struct {
password string
cursor int
entered bool
func initialPasswordInputModel(message string) passwordModel {
ti := textinput.New()
ti.Placeholder = "..."
ti.Focus()
ti.EchoMode = textinput.EchoPassword
ti.EchoCharacter = '*'
ti.CharLimit = 50
ti.Width = 20

return passwordModel{textInput: ti, message: message}
}

func (m passwordModel) Init() tea.Cmd {
return nil
return textinput.Blink
}

func (m passwordModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd

switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case ctrlC:
switch msg.Type {
case tea.KeyCtrlC, tea.KeyEsc:
return m, tea.Quit
case enter:
m.entered = true
case tea.KeyEnter:
m.inputDone = true
return m, tea.Quit
case backspace:
if m.cursor > 0 {
m.password = m.password[:m.cursor-1] + m.password[m.cursor:]
m.cursor--
}
case left:
if m.cursor > 0 {
m.cursor--
}
case right:
if m.cursor < len(m.password) {
m.cursor++
}
default:
// Adds the character entered to the password
m.password = m.password[:m.cursor] + msg.String() + m.password[m.cursor:]
m.cursor++
}
}

return m, nil
}

func (m passwordModel) View() string {
if m.entered {
return "Password received!\n"
}
m.textInput, cmd = m.textInput.Update(msg)

return fmt.Sprintf("Enter your password: %s\n", repeatAsterisks(len(m.password)))
return m, cmd
}

// Função para repetir asteriscos
func repeatAsterisks(n int) string {
return strings.Repeat("*", n)
func (m passwordModel) View() string {
return fmt.Sprintf("%s %s\n", m.message, m.textInput.View())
}

// Example of using
// func main() {
// password, err := Password(InitialPasswordModel())
// if err != nil {
// fmt.Fprintf(os.Stderr, "Erro: %v\n", err)
// os.Exit(1)
// }
//
// fmt.Printf("%s\n", password)
// }
21 changes: 5 additions & 16 deletions components/mdz/pkg/tui/select.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,18 @@ func (m selectModel) Init() tea.Cmd {
func (m selectModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "q":
switch msg.Type {
case tea.KeyCtrlC, tea.KeyEsc:
return m, tea.Quit
case "up", "ctrl+p":
case tea.KeyUp, tea.KeyCtrlP:
if m.cursor > 0 {
m.cursor--
}
case "down", "ctrl+n":
case tea.KeyDown, tea.KeyCtrlN:
if m.cursor < len(m.choices)-1 {
m.cursor++
}
case "enter":
case tea.KeyEnter:
m.selected = true
return m, tea.Quit
}
Expand All @@ -80,14 +80,3 @@ func (m selectModel) View() string {

return s
}

// Example of using
// func main() {
// answer, err := Select([]string{"Log in via browser", "Log in via terminal"})
// if err != nil {
// fmt.Fprintf(os.Stderr, "Error: %v\n", err)
// os.Exit(1)
// }
//
// fmt.Printf("You chose: %s\n", answer)
// }
Loading
Loading