diff --git a/internal/setup/flags.go b/internal/setup/flags.go index c5d2f175..7d2fe380 100644 --- a/internal/setup/flags.go +++ b/internal/setup/flags.go @@ -2,11 +2,9 @@ package setup import ( "fmt" - "io" - "strings" - "github.com/charmbracelet/bubbles/key" "github.com/charmbracelet/bubbles/list" + "github.com/charmbracelet/bubbles/textinput" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" ) @@ -18,6 +16,8 @@ var ( _ list.Item = flag{} ) +const defaultFlagKey = "setup-test-flag" + type flag struct { Key string `json:"key"` Name string `json:"name"` @@ -26,83 +26,20 @@ type flag struct { func (p flag) FilterValue() string { return "" } type flagModel struct { - choice string + input string err error - list list.Model - parentKey string -} - -var flags = map[string][]flag{ - "env1": { - { - Key: "flag1", - Name: "flag 1", - }, - { - Key: "flag2", - Name: "flag 2", - }, - }, - "env2": { - { - Key: "flag3", - Name: "flag 3", - }, - { - Key: "flag4", - Name: "flag 4", - }, - }, - "env3": { - { - Key: "flag5", - Name: "flag 5", - }, - { - Key: "flag6", - Name: "flag 6", - }, - }, - "env4": { - { - Key: "flag7", - Name: "flag 7", - }, - { - Key: "flag8", - Name: "flag 8", - }, - }, - "env5": { - { - Key: "flag9", - Name: "flag 9", - }, - { - Key: "flag10", - Name: "flag 10", - }, - }, - "env6": { - { - Key: "flag11", - Name: "flag 11", - }, - { - Key: "flag12", - Name: "flag 12", - }, - }, + textInput textinput.Model } func NewFlag() tea.Model { - l := list.New(nil, flagDelegate{}, 30, 14) - l.Title = "Select a flag" - l.SetShowStatusBar(false) - l.SetFilteringEnabled(false) + ti := textinput.New() + ti.Focus() + ti.CharLimit = 156 + ti.Width = 20 + ti.Placeholder = defaultFlagKey return flagModel{ - list: l, + textInput: ti, } } @@ -110,28 +47,21 @@ func (p flagModel) Init() tea.Cmd { return nil } -// This method has drifted from the ProjectModel's version, but it should do something similar. func (m flagModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmd tea.Cmd switch msg := msg.(type) { - case fetchResources: - fs, err := getFlags(m.parentKey) - if err != nil { - m.err = err - return m, nil - } - m.list.SetItems(flagsToItems(fs)) case tea.KeyMsg: switch { case key.Matches(msg, keys.Enter): - i, ok := m.list.SelectedItem().(flag) - if ok { - m.choice = i.Key + input := m.textInput.Value() + if input == "" { + input = defaultFlagKey } + m.input = input case key.Matches(msg, keys.Quit): return m, tea.Quit default: - m.list, cmd = m.list.Update(msg) + m.textInput, cmd = m.textInput.Update(msg) } } @@ -139,44 +69,9 @@ func (m flagModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } func (m flagModel) View() string { - return "\n" + m.list.View() -} - -func getFlags(envKey string) ([]flag, error) { - flagList := flags[envKey] - createNewOption := flag{Key: CreateNewResourceKey, Name: "Create a new flag"} - flagList = append(flagList, createNewOption) - return flagList, nil -} - -type flagDelegate struct{} - -func (d flagDelegate) Height() int { return 1 } -func (d flagDelegate) Spacing() int { return 0 } -func (d flagDelegate) Update(_ tea.Msg, _ *list.Model) tea.Cmd { return nil } -func (d flagDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) { - i, ok := listItem.(flag) - if !ok { - return - } - - str := fmt.Sprintf("%d. %s", index+1, i.Name) - - fn := flagStyle.Render - if index == m.Index() { - fn = func(s ...string) string { - return selectedFlagItemStyle.Render("> " + strings.Join(s, " ")) - } - } - - fmt.Fprint(w, fn(str)) -} - -func flagsToItems(flags []flag) []list.Item { - items := make([]list.Item, len(flags)) - for i, proj := range flags { - items[i] = list.Item(proj) - } - - return items + return fmt.Sprintf( + "Name your first feature flag (enter for default value):\n\n%s\n\n%s", + m.textInput.View(), + "(esc to quit)", + ) + "\n" } diff --git a/internal/setup/sdk_build_instructions/go.md b/internal/setup/sdk_build_instructions/go.md index 01efeb5a..b7f71ca3 100644 --- a/internal/setup/sdk_build_instructions/go.md +++ b/internal/setup/sdk_build_instructions/go.md @@ -20,4 +20,4 @@ const featureFlagKey = "my-flag-key" 3. Run `./hello-go` -You should see the message `"Feature flag '' is for this context"`. +You should see the message `"Feature flag 'my-flag-key' is for this context"`. diff --git a/internal/setup/sdk_build_instructions/js.md b/internal/setup/sdk_build_instructions/js.md index 5b7eb4a5..7d71d08b 100644 --- a/internal/setup/sdk_build_instructions/js.md +++ b/internal/setup/sdk_build_instructions/js.md @@ -8,4 +8,4 @@ const flagKey = 'my-flag-key'; 2. Open `index.html` in your browser. -You should receive the message "Feature flag key '' is for this user". \ No newline at end of file +You should receive the message "Feature flag key 'my-flag-key' is for this user". \ No newline at end of file diff --git a/internal/setup/wizard.go b/internal/setup/wizard.go index c66410f3..5eee6bb5 100644 --- a/internal/setup/wizard.go +++ b/internal/setup/wizard.go @@ -19,10 +19,7 @@ type fetchResources struct{} // list of steps in the wizard const ( - autoCreateStep sessionState = iota - projectsStep - environmentsStep - flagsStep + flagsStep sessionState = iota sdksStep ) @@ -46,15 +43,12 @@ func NewWizardModel() tea.Model { // Since there isn't a model for the initial step, the currStep value will always be one ahead of the step in // this slice. It may be convenient to add a model for the initial step to contain its own view logic and to // prevent this off-by-one issue. - NewAutoCreate(), - NewProject(), - NewEnvironment(), NewFlag(), NewSdk(), } return WizardModel{ - currStep: autoCreateStep, + currStep: 0, steps: steps, } } @@ -73,64 +67,11 @@ func (m WizardModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch { case key.Matches(msg, keys.Enter): switch m.currStep { - case autoCreateStep: - model, _ := m.steps[autoCreateStep].Update(msg) - p, ok := model.(autoCreateModel) - if ok { - m.useRecommendedResources = p.choice == "Yes" - if m.useRecommendedResources { - // create project, environment, and flag - // go to step after flagsStep - m.currProjectKey = "setup-wizard-project" - m.currEnvironmentKey = "test" - m.currFlagKey = "setup-wizard-flag" - m.currStep = flagsStep + 1 - } else { - // pre-load projects - m.steps[projectsStep], _ = m.steps[projectsStep].Update(fetchResources{}) - m.currStep += 1 - } - } - case projectsStep: - projModel, _ := m.steps[projectsStep].Update(msg) - // we need to cast this to get the data out of it, but maybe we can create our own interface with - // common values such as Choice() and Err() so we don't have to cast - p, ok := projModel.(projectModel) - if ok { - m.currProjectKey = p.choice - // update projModel with new input model - m.steps[projectsStep] = p - // only progress if we don't want to show input - if !p.showInput { - // pre-load environments based on project selected - envModel := m.steps[environmentsStep] - e, ok := envModel.(environmentModel) - if ok { - e.parentKey = m.currProjectKey - m.steps[environmentsStep], _ = e.Update(fetchResources{}) - m.currStep += 1 - } - } - } - case environmentsStep: - envModel, _ := m.steps[environmentsStep].Update(msg) - p, ok := envModel.(environmentModel) - if ok { - m.currEnvironmentKey = p.choice - // pre-load flags based on environment selected - fModel := m.steps[flagsStep] - f, ok := fModel.(flagModel) - if ok { - f.parentKey = m.currEnvironmentKey - m.steps[flagsStep], _ = f.Update(fetchResources{}) - m.currStep += 1 - } - } case flagsStep: model, _ := m.steps[flagsStep].Update(msg) f, ok := model.(flagModel) - if ok { - m.currFlagKey = f.choice + if ok && f.input != "" { + m.currFlagKey = f.input m.currStep += 1 } case sdksStep: @@ -144,15 +85,8 @@ func (m WizardModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { default: } case key.Matches(msg, keys.Back): - // if we've opted to use recommended resources but want to go back from the SDK step, - // make sure we go back to the right step - if m.useRecommendedResources && m.currStep == sdksStep { - m.currStep = autoCreateStep - } // only go back if not on the first step - if m.currStep > autoCreateStep { - // fetch resources for the previous step again in case we created new ones - m.steps[m.currStep-1], _ = m.steps[m.currStep-1].Update(fetchResources{}) + if m.currStep > 0 { m.currStep -= 1 } case key.Matches(msg, keys.Quit): @@ -179,9 +113,7 @@ func (m WizardModel) View() string { if m.currStep > sdksStep { return wordwrap.String( fmt.Sprintf( - "Selected project: %s\nSelected environment: %s\n\nSet up your application. Here are the steps to incorporate the LaunchDarkly %s SDK into your code. \n\n%s", - m.currProjectKey, - m.currEnvironmentKey, + "Set up your application. Here are the steps to incorporate the LaunchDarkly %s SDK into your code. \n\n%s", m.currSdk.Name, m.renderMarkdown(), ),