@@ -11,9 +11,13 @@ use crate::{
1111} ;
1212use anyhow:: Result ;
1313use asyncgit:: {
14+ asyncjob:: AsyncSingleJob ,
15+ remotes:: AsyncRemoteTagsJob ,
16+ sync:: cred:: { extract_username_password, need_username_password} ,
1417 sync:: { get_tags_with_metadata, TagWithMetadata } ,
15- CWD ,
18+ AsyncGitNotification , CWD ,
1619} ;
20+ use crossbeam_channel:: Sender ;
1721use crossterm:: event:: Event ;
1822use std:: convert:: TryInto ;
1923use tui:: {
@@ -36,6 +40,9 @@ pub struct TagListComponent {
3640 visible : bool ,
3741 table_state : std:: cell:: Cell < TableState > ,
3842 current_height : std:: cell:: Cell < usize > ,
43+ missing_remote_tags : Option < Vec < String > > ,
44+ async_remote_tags :
45+ AsyncSingleJob < AsyncRemoteTagsJob , AsyncGitNotification > ,
3946 key_config : SharedKeyConfig ,
4047}
4148
@@ -65,6 +72,8 @@ impl DrawableComponent for TagListComponent {
6572 } ) ;
6673
6774 let constraints = [
75+ // symbol if tag is not yet on remote and can be pushed
76+ Constraint :: Length ( 1 ) ,
6877 // tag name
6978 Constraint :: Length ( tag_name_width. try_into ( ) ?) ,
7079 // commit date
@@ -230,6 +239,7 @@ impl Component for TagListComponent {
230239impl TagListComponent {
231240 pub fn new (
232241 queue : & Queue ,
242+ sender : & Sender < AsyncGitNotification > ,
233243 theme : SharedTheme ,
234244 key_config : SharedKeyConfig ,
235245 ) -> Self {
@@ -240,6 +250,11 @@ impl TagListComponent {
240250 visible : false ,
241251 table_state : std:: cell:: Cell :: new ( TableState :: default ( ) ) ,
242252 current_height : std:: cell:: Cell :: new ( 0 ) ,
253+ missing_remote_tags : None ,
254+ async_remote_tags : AsyncSingleJob :: new (
255+ sender. clone ( ) ,
256+ AsyncGitNotification :: RemoteTags ,
257+ ) ,
243258 key_config,
244259 }
245260 }
@@ -251,9 +266,41 @@ impl TagListComponent {
251266
252267 self . update_tags ( ) ?;
253268
269+ let basic_credential = if need_username_password ( ) ? {
270+ let credential = extract_username_password ( ) ?;
271+
272+ if credential. is_complete ( ) {
273+ Some ( credential)
274+ } else {
275+ None
276+ }
277+ } else {
278+ None
279+ } ;
280+
281+ self . async_remote_tags
282+ . spawn ( AsyncRemoteTagsJob :: new ( basic_credential) ) ;
283+
254284 Ok ( ( ) )
255285 }
256286
287+ ///
288+ pub fn update ( & mut self , event : AsyncGitNotification ) {
289+ if event == AsyncGitNotification :: RemoteTags {
290+ if let Some ( job) = self . async_remote_tags . take_last ( ) {
291+ if let Some ( Ok ( missing_remote_tags) ) = job. result ( ) {
292+ self . missing_remote_tags =
293+ Some ( missing_remote_tags) ;
294+ }
295+ }
296+ }
297+ }
298+
299+ ///
300+ pub fn any_work_pending ( & self ) -> bool {
301+ self . async_remote_tags . is_pending ( )
302+ }
303+
257304 /// fetch list of tags
258305 pub fn update_tags ( & mut self ) -> Result < ( ) > {
259306 let tags = get_tags_with_metadata ( CWD ) ?;
@@ -307,7 +354,27 @@ impl TagListComponent {
307354
308355 ///
309356 fn get_row ( & self , tag : & TagWithMetadata ) -> Row {
357+ const UPSTREAM_SYMBOL : & str = "\u{2191} " ;
358+ const EMPTY_SYMBOL : & str = " " ;
359+
360+ let is_tag_missing_on_remote = self
361+ . missing_remote_tags
362+ . as_ref ( )
363+ . map_or ( false , |missing_remote_tags| {
364+ let remote_tag = format ! ( "refs/tags/{}" , tag. name) ;
365+
366+ missing_remote_tags. contains ( & remote_tag)
367+ } ) ;
368+
369+ let has_remote_str = if is_tag_missing_on_remote {
370+ UPSTREAM_SYMBOL
371+ } else {
372+ EMPTY_SYMBOL
373+ } ;
374+
310375 let cells: Vec < Cell > = vec ! [
376+ Cell :: from( has_remote_str)
377+ . style( self . theme. commit_author( false ) ) ,
311378 Cell :: from( tag. name. clone( ) )
312379 . style( self . theme. text( true , false ) ) ,
313380 Cell :: from( utils:: time_to_string( tag. time, true ) )
0 commit comments