@@ -68,40 +68,43 @@ type startFailedMsg struct {
6868
6969type startModel struct {
7070 spinner spinner.Model
71+ startup output.StartupAnimation
7172 rows []startServiceRow
7273 indexByName map [string ]int
7374 footer string
7475 stopping bool
76+ done bool
77+ result error
7578 cancel context.CancelFunc
7679}
7780
7881var startCmd = & cobra.Command {
7982 Use : "start" ,
8083 Short : "Start project services" ,
8184 RunE : func (cmd * cobra.Command , args []string ) error {
82- fmt .Print (output .ASCIIBanner ())
83-
8485 rootPath , err := os .Getwd ()
8586 if err != nil {
8687 return err
8788 }
8889
89- projectConfig , err := config .LoadProjectConfig (rootPath )
90- if err != nil {
91- return err
92- }
93-
9490 ctx , cancel := context .WithCancel (context .Background ())
9591 defer cancel ()
9692
97- model := newStartModel (projectConfig . Services , cancel )
93+ model := newStartModel (cancel )
9894 program := tea .NewProgram (model , tea .WithoutSignalHandler ())
9995
100- go runStartWorkflow (ctx , rootPath , projectConfig , program .Send )
96+ go runStartWorkflow (ctx , rootPath , program .Send )
10197
102- if _ , err := program .Run (); err != nil {
98+ finalModel , err := program .Run ()
99+ if err != nil {
103100 return err
104101 }
102+
103+ final := finalModel .(startModel )
104+ if final .result != nil {
105+ return final .result
106+ }
107+
105108 return nil
106109 },
107110}
@@ -110,36 +113,29 @@ func init() {
110113 rootCmd .AddCommand (startCmd )
111114}
112115
113- func newStartModel (services []config.ServiceConfig , cancel context.CancelFunc ) startModel {
114- rows := make ([]startServiceRow , 0 , len (services ))
115- indexByName := make (map [string ]int , len (services ))
116-
117- for i , svc := range services {
118- rows = append (rows , startServiceRow {
119- Name : svc .Name ,
120- Status : statusPending ,
121- Detail : "waiting" ,
122- })
123- indexByName [svc .Name ] = i
124- }
125-
116+ func newStartModel (cancel context.CancelFunc ) startModel {
126117 spin := spinner .New (spinner .WithSpinner (spinner .Dot ))
127118
128119 return startModel {
129120 spinner : spin ,
130- rows : rows ,
131- indexByName : indexByName ,
121+ startup : output .NewStartupAnimation (),
122+ rows : []startServiceRow {},
123+ indexByName : make (map [string ]int ),
132124 footer : "Starting services..." ,
133125 cancel : cancel ,
134126 }
135127}
136128
137129func (m startModel ) Init () tea.Cmd {
138- return m .spinner .Tick
130+ return tea . Batch ( m .spinner .Tick , m . startup . Init ())
139131}
140132
141133func (m startModel ) Update (msg tea.Msg ) (tea.Model , tea.Cmd ) {
142134 switch msg := msg .(type ) {
135+ case output.StartupAnimationTickMsg :
136+ var cmd tea.Cmd
137+ m .startup , cmd = m .startup .Update (msg )
138+ return m , cmd
143139 case spinner.TickMsg :
144140 var cmd tea.Cmd
145141 m .spinner , cmd = m .spinner .Update (msg )
@@ -149,20 +145,29 @@ func (m startModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
149145 if ok {
150146 m .rows [idx ].Status = msg .Status
151147 m .rows [idx ].Detail = msg .Detail
148+ } else {
149+ m .indexByName [msg .Name ] = len (m .rows )
150+ m .rows = append (m .rows , startServiceRow {
151+ Name : msg .Name ,
152+ Status : msg .Status ,
153+ Detail : msg .Detail ,
154+ })
152155 }
153156 return m , nil
154157 case startFooterMsg :
155158 m .footer = msg .Text
156159 return m , nil
157160 case startStoppedMsg :
158161 m .footer = "Services stopped"
162+ m .done = true
159163 return m , tea .Quit
160164 case startFailedMsg :
161165 if msg .Message == "" {
162- m .footer = "Start failed"
166+ m .result = errors . New ( "start failed")
163167 } else {
164- m .footer = "Start failed: " + msg .Message
168+ m .result = errors . New ( msg .Message )
165169 }
170+ m .done = true
166171 return m , tea .Quit
167172 case tea.KeyMsg :
168173 if msg .String () == "ctrl+c" || msg .String () == "q" {
@@ -183,6 +188,16 @@ func (m startModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
183188func (m startModel ) View () string {
184189 var builder strings.Builder
185190
191+ if m .startup .Visible () {
192+ builder .WriteString ("\n " )
193+ if m .done {
194+ builder .WriteString (m .startup .ResolvedView ())
195+ } else {
196+ builder .WriteString (m .startup .View ())
197+ }
198+ builder .WriteString ("\n \n " )
199+ }
200+
186201 for _ , row := range m .rows {
187202 line := m .rowIcon (row .Status ) + " " + displayServiceName (row .Name )
188203 if row .Detail != "" {
@@ -197,7 +212,16 @@ func (m startModel) View() string {
197212 builder .WriteString ("\n " )
198213 }
199214
200- builder .WriteString ("\n " )
215+ if m .result != nil {
216+ if len (m .rows ) > 0 {
217+ builder .WriteString ("\n " )
218+ }
219+ return builder .String ()
220+ }
221+
222+ if len (m .rows ) > 0 {
223+ builder .WriteString ("\n " )
224+ }
201225 builder .WriteString (output .Footer (m .footer ))
202226 builder .WriteString ("\n " )
203227
@@ -230,7 +254,13 @@ func (m startModel) rowIcon(status startServiceStatus) string {
230254 }
231255}
232256
233- func runStartWorkflow (ctx context.Context , rootPath string , projectConfig config.ProjectConfig , send func (msg tea.Msg )) {
257+ func runStartWorkflow (ctx context.Context , rootPath string , send func (msg tea.Msg )) {
258+ projectConfig , err := config .LoadProjectConfig (rootPath )
259+ if err != nil {
260+ send (startFailedMsg {Message : err .Error ()})
261+ return
262+ }
263+
234264 if err := ensureDependencies (depNode , depNPM ); err != nil {
235265 send (startFailedMsg {Message : err .Error ()})
236266 return
0 commit comments