@@ -5,14 +5,14 @@ import (
55 "fmt"
66 "strings"
77
8- "github.com/AlecAivazis/survey/v2"
98 "github.com/apppackio/apppack/bridge"
109 "github.com/apppackio/apppack/ui"
1110 "github.com/aws/aws-sdk-go-v2/aws"
1211 "github.com/aws/aws-sdk-go-v2/service/cloudformation/types"
1312 "github.com/aws/aws-sdk-go-v2/service/elasticache"
1413 "github.com/aws/aws-sdk-go-v2/service/ssm"
1514 ssmtypes "github.com/aws/aws-sdk-go-v2/service/ssm/types"
15+ "github.com/charmbracelet/huh"
1616 "github.com/sirupsen/logrus"
1717 "github.com/spf13/pflag"
1818)
@@ -166,11 +166,8 @@ func (a *RedisStack) UpdateFromFlags(flags *pflag.FlagSet) error {
166166}
167167
168168func (a * RedisStack ) AskQuestions (cfg aws.Config ) error {
169- var questions []* ui.QuestionExtra
170-
171- var err error
172169 if a .Stack == nil {
173- err = AskForCluster (
170+ err : = AskForCluster (
174171 cfg ,
175172 "Which cluster should this Redis instance be installed in?" ,
176173 "A cluster represents an isolated network and its associated resources (Apps, Database, Redis, etc.)." ,
@@ -185,29 +182,14 @@ func (a *RedisStack) AskQuestions(cfg aws.Config) error {
185182 a .Parameters .InstanceClass = DefaultRedisStackParameters .InstanceClass
186183 }
187184
188- questions = append (questions , []* ui.QuestionExtra {
189- {
190- Verbose : "Should this Redis instance be setup in multiple availability zones?" ,
191- HelpText : "Multiple availability zones (AZs) provide more resilience in the case of an AZ outage, " +
192- "but double the cost at AWS. For more info see " +
193- "https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/AutoFailover.html." ,
194- WriteTo : & ui.BooleanOptionProxy {Value : & a .Parameters .MultiAZ },
195- Question : & survey.Question {
196- Prompt : & survey.Select {
197- Message : "Multi AZ" ,
198- Options : []string {"yes" , "no" },
199- FilterMessage : "" ,
200- Default : ui .BooleanAsYesNo (a .Parameters .MultiAZ ),
201- },
202- },
203- },
204- }... )
205- if err = ui .AskQuestions (questions , a .Parameters ); err != nil {
185+ // Multi-AZ prompt
186+ multiAZForm , multiAZPtr := RedisMultiAZForm (a .Parameters .MultiAZ )
187+ if err := multiAZForm .Run (); err != nil {
206188 return err
207189 }
208- // Clear the questions slice so we can reuse it
209- questions = questions [:0 ]
190+ a .Parameters .MultiAZ = ui .YesNoToBool (* multiAZPtr )
210191
192+ // Fetch instance classes from AWS
211193 ui .StartSpinner ()
212194 ui .Spinner .Suffix = " retrieving instance classes"
213195
@@ -219,24 +201,63 @@ func (a *RedisStack) AskQuestions(cfg aws.Config) error {
219201 ui .Spinner .Stop ()
220202 ui .Spinner .Suffix = ""
221203
222- questions = append (questions , []* ui.QuestionExtra {
223- {
224- Verbose : "What instance class should be used for this Redis instance?" ,
225- HelpText : "Enter the Redis instance class. For more info see https://aws.amazon.com/elasticache/pricing/." ,
226- Question : & survey.Question {
227- Name : "InstanceClass" ,
228- Prompt : & survey.Select {
229- Message : "Instance Class" ,
230- Options : instanceClasses ,
231- FilterMessage : "" ,
232- Default : a .Parameters .InstanceClass ,
233- },
234- Validate : survey .Required ,
235- },
236- },
237- }... )
238-
239- return ui .AskQuestions (questions , a .Parameters )
204+ // Instance class prompt
205+ instanceClassForm , instanceClassPtr := RedisInstanceClassForm (instanceClasses , a .Parameters .InstanceClass )
206+ if err := instanceClassForm .Run (); err != nil {
207+ return err
208+ }
209+ a .Parameters .InstanceClass = * instanceClassPtr
210+
211+ return nil
212+ }
213+
214+ // RedisMultiAZForm builds the interactive form for selecting multi-AZ mode.
215+ // Returns the form and a pointer to the selected "yes"/"no" value.
216+ func RedisMultiAZForm (defaultMultiAZ bool ) (* huh.Form , * string ) {
217+ selected := ui .BooleanAsYesNo (defaultMultiAZ )
218+
219+ form := huh .NewForm (
220+ huh .NewGroup (
221+ huh .NewNote ().
222+ Title ("Should this Redis instance be setup in multiple availability zones?" ).
223+ Description ("Multiple availability zones (AZs) provide more resilience in the case of an AZ outage,\n but double the cost at AWS. For more info see\n https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/AutoFailover.html." ),
224+ huh .NewSelect [string ]().
225+ Title ("Multi AZ" ).
226+ Options (ui .YesNoOptions (defaultMultiAZ )... ).
227+ Value (& selected ),
228+ ),
229+ )
230+
231+ return form , & selected
232+ }
233+
234+ // RedisInstanceClassForm builds the interactive form for selecting an instance class.
235+ // Returns the form and a pointer to the selected instance class.
236+ func RedisInstanceClassForm (instanceClasses []string , defaultClass string ) (* huh.Form , * string ) {
237+ selected := defaultClass
238+
239+ options := make ([]huh.Option [string ], len (instanceClasses ))
240+ for i , c := range instanceClasses {
241+ opt := huh .NewOption (c , c )
242+ if c == defaultClass {
243+ opt = opt .Selected (true )
244+ }
245+ options [i ] = opt
246+ }
247+
248+ form := huh .NewForm (
249+ huh .NewGroup (
250+ huh .NewNote ().
251+ Title ("What instance class should be used for this Redis instance?" ).
252+ Description ("Enter the Redis instance class. For more info see https://aws.amazon.com/elasticache/pricing/." ),
253+ huh .NewSelect [string ]().
254+ Title ("Instance Class" ).
255+ Options (options ... ).
256+ Value (& selected ),
257+ ),
258+ )
259+
260+ return form , & selected
240261}
241262
242263func (* RedisStack ) StackName (name * string ) * string {
0 commit comments