diff --git a/cmd/members/invite.go b/cmd/members/invite.go index 62127560..1cdd4246 100644 --- a/cmd/members/invite.go +++ b/cmd/members/invite.go @@ -12,8 +12,6 @@ import ( "ldcli/internal/members" ) -const defaultRole = "reader" - func NewInviteCmd(client members.Client) (*cobra.Command, error) { cmd := &cobra.Command{ Args: validators.Validate(), diff --git a/internal/quickstart/container.go b/internal/quickstart/container.go index 79afa761..29282705 100644 --- a/internal/quickstart/container.go +++ b/internal/quickstart/container.go @@ -25,6 +25,7 @@ type ContainerModel struct { err error flagKey string flagsClient flags.Client + quitMsg string quitting bool sdk sdkDetail steps []tea.Model @@ -52,12 +53,20 @@ func (m ContainerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case key.Matches(msg, keys.Enter): switch m.currentStep { case createFlagStep: - updated, _ := m.steps[createFlagStep].Update(msg) + updated, cmd := m.steps[createFlagStep].Update(msg) if model, ok := updated.(createFlagModel); ok { if model.err != nil { m.err = model.err + if model.quitting { + m.quitMsg = model.quitMsg + m.quitting = true + + return m, cmd + } + return m, nil } + m.flagKey = model.flagKey m.currentStep += 1 } @@ -86,24 +95,33 @@ func (m ContainerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } func (m ContainerModel) View() string { - if m.quitting { - return "" + // TODO: remove after creating more steps + if m.currentStep > chooseSDKStep { + return fmt.Sprintf("created flag %s\nselected the %s SDK", m.flagKey, m.sdk.DisplayName) } + out := fmt.Sprintf("\nStep %d of %d\n"+m.steps[m.currentStep].View(), m.currentStep+1, len(m.steps)) if m.err != nil { - return lipgloss. + if m.quitting { + out := m.quitMsg + "\n\n" + out += m.err.Error() + + return lipgloss. + NewStyle(). + SetString(out). + Render() + "\n" + } + + // show error and stay on the same step + out += "\n" + lipgloss. NewStyle(). - Foreground(lipgloss.Color("#eb4034")). SetString(m.err.Error()). - Render() - } + Render() + "\n" - // TODO: remove after creating more steps - if m.currentStep > chooseSDKStep { - return fmt.Sprintf("created flag %s\nselected the %s SDK", m.flagKey, m.sdk.DisplayName) + return out } - return fmt.Sprintf("\nStep %d of %d\n"+m.steps[m.currentStep].View(), m.currentStep+1, len(m.steps)) + return out } type keyMap struct { diff --git a/internal/quickstart/create_flag.go b/internal/quickstart/create_flag.go index 1b0ece0d..e6444cf5 100644 --- a/internal/quickstart/create_flag.go +++ b/internal/quickstart/create_flag.go @@ -2,6 +2,7 @@ package quickstart import ( "context" + "encoding/json" "fmt" "github.com/charmbracelet/bubbles/key" @@ -17,10 +18,12 @@ import ( const defaultFlagName = "my new flag" type createFlagModel struct { + client flags.Client err error flagKey string flagName string - client flags.Client + quitMsg string + quitting bool textInput textinput.Model } @@ -69,6 +72,24 @@ func (m createFlagModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { ) if err != nil { m.err = err + // TODO: we may want a more robust error type so we don't need to do this + var e struct { + Code string `json:"code"` + Message string `json:"message"` + } + _ = json.Unmarshal([]byte(m.err.Error()), &e) + switch { + case e.Code == "unauthorized": + m.quitting = true + m.quitMsg = "Your API key is unauthorized. Try another API key or speak to a LaunchDarkly account administrator." + + return m, tea.Quit + case e.Code == "forbidden": + m.quitting = true + m.quitMsg = "You lack access to complete this action. Try authenticating with elevated access or speak to a LaunchDarkly account administrator." + + return m, tea.Quit + } return m, nil }