@@ -37,15 +37,25 @@ const BUTTON_TOOLTIP: &str = "Execution host";
3737
3838const MENU_HEADER_LABEL : & str = "Execution host" ;
3939
40- #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
40+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
4141pub enum Host {
4242 Warp ,
43+ SelfHosted { slug : String } ,
4344}
4445
4546impl Host {
46- fn display_name ( self ) -> & ' static str {
47+ fn display_name ( & self ) -> & str {
4748 match self {
4849 Host :: Warp => "Warp" ,
50+ Host :: SelfHosted { slug } => slug. as_str ( ) ,
51+ }
52+ }
53+
54+ /// Returns the value to send as `worker_host` in the config snapshot.
55+ pub fn worker_host_value ( & self ) -> Option < String > {
56+ match self {
57+ Host :: Warp => Some ( "warp" . to_string ( ) ) ,
58+ Host :: SelfHosted { slug } => Some ( slug. clone ( ) ) ,
4959 }
5060 }
5161}
@@ -58,6 +68,7 @@ pub enum HostSelectorAction {
5868
5969pub enum HostSelectorEvent {
6070 MenuVisibilityChanged { open : bool } ,
71+ HostSelected ,
6172}
6273
6374pub struct HostSelector {
@@ -66,6 +77,8 @@ pub struct HostSelector {
6677 is_menu_open : bool ,
6778 menu_positioning_provider : Arc < dyn MenuPositioningProvider > ,
6879 selected : Host ,
80+ /// The configured default self-hosted host, if any.
81+ default_host : Option < Host > ,
6982}
7083
7184impl HostSelector {
@@ -78,9 +91,10 @@ impl HostSelector {
7891 // `SelectHost`), so it stays out of clippy's `field is never read`
7992 // warning while still serving as the source of truth for the label.
8093 let selected = Host :: Warp ;
94+ let initial_label = selected. display_name ( ) . to_string ( ) ;
8195
8296 let button = ctx. add_typed_action_view ( |_ctx| {
83- ActionButton :: new ( selected . display_name ( ) , NakedHeaderButtonTheme )
97+ ActionButton :: new ( initial_label , NakedHeaderButtonTheme )
8498 . with_size ( ButtonSize :: AgentInputButton )
8599 . with_menu ( true )
86100 . with_tooltip ( BUTTON_TOOLTIP )
@@ -114,6 +128,7 @@ impl HostSelector {
114128 is_menu_open : false ,
115129 menu_positioning_provider,
116130 selected,
131+ default_host : None ,
117132 } ;
118133 me. refresh_menu ( ctx) ;
119134 me
@@ -123,6 +138,25 @@ impl HostSelector {
123138 self . is_menu_open
124139 }
125140
141+ pub fn has_default_host ( & self ) -> bool {
142+ self . default_host . is_some ( )
143+ }
144+
145+ pub fn selected ( & self ) -> & Host {
146+ & self . selected
147+ }
148+
149+ pub fn set_default_host ( & mut self , slug : String , ctx : & mut ViewContext < Self > ) {
150+ let host = Host :: SelfHosted { slug } ;
151+ let label = host. display_name ( ) . to_string ( ) ;
152+ self . selected = host. clone ( ) ;
153+ self . button . update ( ctx, |button, ctx| {
154+ button. set_label ( label. clone ( ) , ctx) ;
155+ } ) ;
156+ self . default_host = Some ( host) ;
157+ self . refresh_menu ( ctx) ;
158+ }
159+
126160 /// Programmatically opens the host selector popover. No-op if already open.
127161 pub fn open_menu ( & mut self , ctx : & mut ViewContext < Self > ) {
128162 self . set_menu_visibility ( true , ctx) ;
@@ -132,7 +166,7 @@ impl HostSelector {
132166 /// from closed to open so the user has a clear starting point for arrow-key navigation
133167 /// instead of an unselected list.
134168 fn highlight_selected_host ( & mut self , ctx : & mut ViewContext < Self > ) {
135- let selected_action = HostSelectorAction :: SelectHost ( self . selected ) ;
169+ let selected_action = HostSelectorAction :: SelectHost ( self . selected . clone ( ) ) ;
136170 self . menu . update ( ctx, |menu, ctx| {
137171 menu. set_selected_by_action ( & selected_action, ctx) ;
138172 } ) ;
@@ -157,7 +191,11 @@ impl HostSelector {
157191 let hover_background: Fill = internal_colors:: neutral_4 ( theme) . into ( ) ;
158192 let header_text_color = theme. disabled_text_color ( theme. surface_2 ( ) ) . into_solid ( ) ;
159193 let border = Border :: all ( 1. ) . with_border_fill ( theme. outline ( ) ) ;
160- let items = build_menu_items ( hover_background, header_text_color) ;
194+ let items = build_menu_items (
195+ hover_background,
196+ header_text_color,
197+ self . default_host . as_ref ( ) ,
198+ ) ;
161199 self . menu . update ( ctx, |menu, ctx| {
162200 menu. set_border ( Some ( border) ) ;
163201 menu. set_items ( items, ctx) ;
@@ -185,6 +223,7 @@ impl HostSelector {
185223fn build_menu_items (
186224 hover_background : Fill ,
187225 header_text_color : ColorU ,
226+ default_host : Option < & Host > ,
188227) -> Vec < MenuItem < HostSelectorAction > > {
189228 let header = MenuItem :: Header {
190229 fields : MenuItemFields :: new ( MENU_HEADER_LABEL )
@@ -197,16 +236,22 @@ fn build_menu_items(
197236 } ;
198237
199238 let item_for = |host : Host | {
239+ let label = host. display_name ( ) . to_string ( ) ;
200240 MenuItem :: Item (
201- MenuItemFields :: new ( host . display_name ( ) )
241+ MenuItemFields :: new ( label )
202242 . with_font_size_override ( ITEM_FONT_SIZE )
203243 . with_padding_override ( ITEM_VERTICAL_PADDING , MENU_HORIZONTAL_PADDING )
204244 . with_override_hover_background_color ( hover_background)
205245 . with_on_select_action ( HostSelectorAction :: SelectHost ( host) ) ,
206246 )
207247 } ;
208248
209- vec ! [ header, item_for( Host :: Warp ) ]
249+ let mut items = vec ! [ header] ;
250+ if let Some ( host) = default_host {
251+ items. push ( item_for ( host. clone ( ) ) ) ;
252+ }
253+ items. push ( item_for ( Host :: Warp ) ) ;
254+ items
210255}
211256
212257impl Entity for HostSelector {
@@ -223,11 +268,12 @@ impl TypedActionView for HostSelector {
223268 self . set_menu_visibility ( new_state, ctx) ;
224269 }
225270 HostSelectorAction :: SelectHost ( host) => {
226- self . selected = * host;
227- let label = self . selected . display_name ( ) ;
271+ self . selected = host. clone ( ) ;
272+ let label = self . selected . display_name ( ) . to_string ( ) ;
228273 self . button . update ( ctx, |button, ctx| {
229- button. set_label ( label, ctx) ;
274+ button. set_label ( label. clone ( ) , ctx) ;
230275 } ) ;
276+ ctx. emit ( HostSelectorEvent :: HostSelected ) ;
231277 self . set_menu_visibility ( false , ctx) ;
232278 }
233279 }
0 commit comments