@@ -74,7 +74,7 @@ use std::sync::{
7474use std:: thread;
7575use std:: time:: Duration ;
7676use tempfile:: Builder ;
77- use tokio:: sync:: mpsc;
77+ use tokio:: { sync:: mpsc, time :: MissedTickBehavior } ;
7878
7979pub ( crate ) use self :: refresh:: build_command_context;
8080
@@ -107,38 +107,34 @@ pub(crate) async fn run_ui(
107107 let refresh_in_flight = Arc :: new ( AtomicBool :: new ( false ) ) ;
108108
109109 let mut refresh = tokio:: time:: interval ( args. refresh_interval ) ;
110+ refresh. set_missed_tick_behavior ( MissedTickBehavior :: Skip ) ;
110111 let _ = refresh. tick ( ) . await ;
112+ let mut activity_tick = tokio:: time:: interval ( Duration :: from_millis ( 120 ) ) ;
113+ activity_tick. set_missed_tick_behavior ( MissedTickBehavior :: Skip ) ;
114+ let _ = activity_tick. tick ( ) . await ;
111115
112116 let result = loop {
113117 session. draw ( & mut app) ?;
114118
115119 tokio:: select! {
116120 _ = tokio:: signal:: ctrl_c( ) => break Ok ( ( ) ) ,
121+ _ = activity_tick. tick( ) , if app. is_activity_active( ) => {
122+ app. advance_activity_frame( ) ;
123+ }
117124 _ = refresh. tick( ) => {
118- spawn_refresh_task(
119- client. clone( ) ,
120- app. clone( ) ,
121- args. clone( ) ,
122- tx. clone( ) ,
123- refresh_in_flight. clone( ) ,
124- ) ;
125+ request_refresh( client, & mut app, & args, & tx, & refresh_in_flight) ;
125126 }
126127 Some ( event) = rx. recv( ) => {
127128 match event {
128129 UiEvent :: RefreshComplete ( refreshed) => {
129130 apply_refreshed_app( & mut app, * refreshed) ;
131+ app. end_activity( ) ;
130132 }
131133 UiEvent :: Terminal ( event) => {
132134 match handle_event( event, & mut app) {
133135 EventOutcome :: Quit => break Ok ( ( ) ) ,
134136 EventOutcome :: Refresh => {
135- spawn_refresh_task(
136- client. clone( ) ,
137- app. clone( ) ,
138- args. clone( ) ,
139- tx. clone( ) ,
140- refresh_in_flight. clone( ) ,
141- ) ;
137+ request_refresh( client, & mut app, & args, & tx, & refresh_in_flight) ;
142138 }
143139 EventOutcome :: OpenPipelineEditor { group_id, pipeline_id } => {
144140 if let Err ( err) = stage_pipeline_editor_draft(
@@ -155,27 +151,15 @@ pub(crate) async fn run_ui(
155151 {
156152 app. last_error = Some ( err. to_string( ) ) ;
157153 }
158- spawn_refresh_task(
159- client. clone( ) ,
160- app. clone( ) ,
161- args. clone( ) ,
162- tx. clone( ) ,
163- refresh_in_flight. clone( ) ,
164- ) ;
154+ request_refresh( client, & mut app, & args, & tx, & refresh_in_flight) ;
165155 }
166156 EventOutcome :: Execute ( action) => {
167157 if let Err ( err) =
168158 execute_ui_action( client, & mut app, & args, action) . await
169159 {
170160 app. last_error = Some ( err. to_string( ) ) ;
171161 }
172- spawn_refresh_task(
173- client. clone( ) ,
174- app. clone( ) ,
175- args. clone( ) ,
176- tx. clone( ) ,
177- refresh_in_flight. clone( ) ,
178- ) ;
162+ request_refresh( client, & mut app, & args, & tx, & refresh_in_flight) ;
179163 }
180164 EventOutcome :: Continue => { }
181165 }
@@ -192,25 +176,44 @@ pub(crate) async fn run_ui(
192176 result
193177}
194178
179+ fn request_refresh (
180+ client : & AdminClient ,
181+ app : & mut AppState ,
182+ args : & UiArgs ,
183+ tx : & mpsc:: Sender < UiEvent > ,
184+ refresh_in_flight : & Arc < AtomicBool > ,
185+ ) {
186+ if spawn_refresh_task (
187+ client. clone ( ) ,
188+ app. clone ( ) ,
189+ args. clone ( ) ,
190+ tx. clone ( ) ,
191+ refresh_in_flight. clone ( ) ,
192+ ) {
193+ app. begin_activity ( ) ;
194+ }
195+ }
196+
195197fn spawn_refresh_task (
196198 client : AdminClient ,
197199 mut app : AppState ,
198200 args : UiArgs ,
199201 tx : mpsc:: Sender < UiEvent > ,
200202 refresh_in_flight : Arc < AtomicBool > ,
201- ) {
203+ ) -> bool {
202204 if refresh_in_flight
203205 . compare_exchange ( false , true , Ordering :: Relaxed , Ordering :: Relaxed )
204206 . is_err ( )
205207 {
206- return ;
208+ return false ;
207209 }
208210
209211 let _handle = tokio:: spawn ( async move {
210212 refresh_view ( & client, & mut app, & args) . await ;
211213 refresh_in_flight. store ( false , Ordering :: Relaxed ) ;
212214 let _ = tx. send ( UiEvent :: RefreshComplete ( Box :: new ( app) ) ) . await ;
213215 } ) ;
216+ true
214217}
215218
216219fn apply_refreshed_app ( app : & mut AppState , refreshed : AppState ) {
@@ -234,6 +237,7 @@ fn apply_refreshed_app(app: &mut AppState, refreshed: AppState) {
234237 let detail_scroll = app. detail_scroll ;
235238 let terminal_size = app. terminal_size ;
236239 let command_context = app. command_context . clone ( ) ;
240+ let activity_indicator = app. activity_indicator . clone ( ) ;
237241
238242 * app = refreshed;
239243 app. view = view;
@@ -248,6 +252,7 @@ fn apply_refreshed_app(app: &mut AppState, refreshed: AppState) {
248252 app. detail_scroll = detail_scroll;
249253 app. terminal_size = terminal_size;
250254 app. command_context = command_context;
255+ app. activity_indicator = activity_indicator;
251256}
252257
253258#[ cfg( test) ]
0 commit comments