diff --git a/crates/nyaterm-desktop/src/features/connections/connection_import_runtime.rs b/crates/nyaterm-desktop/src/features/connections/connection_import_runtime.rs index 332f0371a..85352fc28 100644 --- a/crates/nyaterm-desktop/src/features/connections/connection_import_runtime.rs +++ b/crates/nyaterm-desktop/src/features/connections/connection_import_runtime.rs @@ -39,24 +39,24 @@ impl NyaTermApp { window: &mut Window, cx: &mut Context, ) { - if self.connection_state.import.path_prompt_active() || self.config_path_prompt.is_some() { + if self.connection_state.import_path_prompt_active() || self.config_path_prompt.is_some() { self.terminal.view.status = "connection import picker is already open".to_string(); cx.notify(); return; } - self.connection_state.import.open_dialog(); + self.connection_state.open_import_dialog(); self.connection_state.list.close_more_menu(); self.title_menu_open = None; self.title_menu_submenu = None; self.terminal.view.status = "select a connection import source".to_string(); - let import_focus = self.connection_state.import.focus_handle(); + let import_focus = self.connection_state.import_focus_handle(); window.focus(&import_focus); cx.notify(); } pub(in crate::features) fn close_connection_import_dialog(&mut self, cx: &mut Context) { - self.connection_state.import.close_dialog(); + self.connection_state.close_import_dialog(); cx.notify(); } @@ -65,7 +65,7 @@ impl NyaTermApp { source: ConnectionImportSource, cx: &mut Context, ) { - self.connection_state.import.close_dialog(); + self.connection_state.close_import_dialog(); if source == ConnectionImportSource::NyatermBackup { self.prompt_portable_snapshot_import(cx); return; @@ -78,7 +78,7 @@ impl NyaTermApp { source: ConnectionImportSource, cx: &mut Context, ) { - if self.connection_state.import.path_prompt_active() { + if self.connection_state.import_path_prompt_active() { self.terminal.view.status = "connection import picker is already open".to_string(); cx.notify(); return; @@ -92,7 +92,7 @@ impl NyaTermApp { }); let config_dir = self.runtime.config_dir().to_path_buf(); let portable_key_path = self.runtime.portable_key_path().map(ToOwned::to_owned); - self.connection_state.import.begin_path_prompt(source); + self.connection_state.begin_import_path_prompt(source); self.terminal.view.status = source.selecting_status().to_string(); cx.spawn(async move |this, cx| { @@ -132,7 +132,7 @@ impl NyaTermApp { result: ConnectionImportResult, cx: &mut Context, ) { - self.connection_state.import.finish_path_prompt(); + self.connection_state.finish_import_path_prompt(); match result { ConnectionImportResult::Imported(count) => { self.refresh_store_from_runtime(); diff --git a/crates/nyaterm-desktop/src/features/connections/connection_runtime/actions.rs b/crates/nyaterm-desktop/src/features/connections/connection_runtime/actions.rs index 62d03b230..ed8663751 100644 --- a/crates/nyaterm-desktop/src/features/connections/connection_runtime/actions.rs +++ b/crates/nyaterm-desktop/src/features/connections/connection_runtime/actions.rs @@ -10,7 +10,7 @@ impl NyaTermApp { cx: &mut Context, ) { self.connection_state.list.close_more_menu(); - self.connection_state.confirmations.open_clear_all(); + self.connection_state.open_clear_all(); self.terminal.view.status = "confirm clearing all saved connections".to_string(); cx.notify(); } @@ -19,24 +19,24 @@ impl NyaTermApp { &mut self, cx: &mut Context, ) { - self.connection_state.confirmations.close_clear_all(); + self.connection_state.close_clear_all(); cx.notify(); } pub(in crate::features) fn confirm_connections_clear_all(&mut self, cx: &mut Context) { - if !self.connection_state.confirmations.clear_all_is_open() { + if !self.connection_state.clear_all_is_open() { return; } match self.with_connection_store(|store| store.replace_sessions(&SessionsConfig::default())) { Ok(()) => { - self.connection_state.confirmations.close_clear_all(); + self.connection_state.close_clear_all(); self.connection_state.list.clear_runtime_state(); self.refresh_store_from_runtime(); self.terminal.view.status = self.tr("savedConnections.clearAllSuccess").to_string(); } Err(error) => { - self.connection_state.confirmations.close_clear_all(); + self.connection_state.close_clear_all(); self.terminal.view.status = format!("clear saved connections failed: {error}"); self.store_status.message = self.terminal.view.status.clone(); self.store_status.ready = false; @@ -60,8 +60,7 @@ impl NyaTermApp { return; }; self.connection_state - .confirmations - .open_delete(ConnectionDeleteConfirmState { + .open_delete_confirm(ConnectionDeleteConfirmState { connection_id, label: connection.name.clone(), }); @@ -70,12 +69,12 @@ impl NyaTermApp { } pub(in crate::features) fn close_connection_delete_confirm(&mut self, cx: &mut Context) { - self.connection_state.confirmations.close_delete(); + self.connection_state.close_delete_confirm(); cx.notify(); } pub(in crate::features) fn confirm_connection_delete(&mut self, cx: &mut Context) { - let Some(confirm) = self.connection_state.confirmations.take_delete() else { + let Some(confirm) = self.connection_state.take_delete_confirm() else { return; }; match self.with_connection_store(|store| store.delete_connection(&confirm.connection_id)) { @@ -118,8 +117,7 @@ impl NyaTermApp { .filter(|child| child.parent_id.as_deref() == Some(group_id.as_str())) .count(); self.connection_state - .confirmations - .open_group_delete(ConnectionGroupDeleteConfirmState { + .open_group_delete_confirm(ConnectionGroupDeleteConfirmState { group_id, label: group.name.clone(), connection_count, @@ -133,12 +131,12 @@ impl NyaTermApp { &mut self, cx: &mut Context, ) { - self.connection_state.confirmations.close_group_delete(); + self.connection_state.close_group_delete_confirm(); cx.notify(); } pub(in crate::features) fn confirm_connection_group_delete(&mut self, cx: &mut Context) { - let Some(confirm) = self.connection_state.confirmations.take_group_delete() else { + let Some(confirm) = self.connection_state.take_group_delete_confirm() else { return; }; match self.with_connection_store(|store| store.delete_group(&confirm.group_id)) { diff --git a/crates/nyaterm-desktop/src/features/connections/connection_runtime/groups.rs b/crates/nyaterm-desktop/src/features/connections/connection_runtime/groups.rs index 59af98297..7eb514c24 100644 --- a/crates/nyaterm-desktop/src/features/connections/connection_runtime/groups.rs +++ b/crates/nyaterm-desktop/src/features/connections/connection_runtime/groups.rs @@ -36,8 +36,7 @@ impl NyaTermApp { .or(parent_id); self.connection_state - .group_editor - .begin_edit(ConnectionGroupEditorState { + .begin_group_editor(ConnectionGroupEditorState { id: group_id, name, parent_id, @@ -52,7 +51,7 @@ impl NyaTermApp { } pub(in crate::features) fn close_connection_group_editor(&mut self, cx: &mut Context) { - self.connection_state.group_editor.close(); + self.connection_state.close_group_editor(); self.connection_state.clear_group_editor_field(); self.terminal.view.status = "connection group editor closed".to_string(); cx.notify(); @@ -74,8 +73,7 @@ impl NyaTermApp { "backspace" if !keystroke.modifiers.platform && !keystroke.modifiers.control => { if self .connection_state - .group_editor - .apply_name_key("backspace", None) + .apply_group_editor_name_key("backspace", None) { cx.notify(); } @@ -88,8 +86,7 @@ impl NyaTermApp { { if self .connection_state - .group_editor - .apply_name_key(keystroke.key.as_str(), Some(input)) + .apply_group_editor_name_key(keystroke.key.as_str(), Some(input)) { cx.notify(); } @@ -100,13 +97,13 @@ impl NyaTermApp { } pub(in crate::features) fn save_connection_group_editor(&mut self, cx: &mut Context) { - let Some(editor) = self.connection_state.group_editor.active_draft() else { + let Some(editor) = self.connection_state.active_group_editor_draft() else { return; }; let name = editor.name.trim().to_string(); if name.is_empty() { let message = self.tr("savedConnections.folderNameRequired").to_string(); - self.connection_state.group_editor.set_error(message); + self.connection_state.set_group_editor_error(message); cx.notify(); return; } @@ -132,12 +129,12 @@ impl NyaTermApp { match self.with_connection_store(|store| store.save_group(&group)) { Ok(()) => { self.connection_state.list.expand_group(group.id.clone()); - self.connection_state.group_editor.close(); + self.connection_state.close_group_editor(); self.refresh_store_from_runtime(); self.terminal.view.status = format!("saved connection group {}", group.name); } Err(error) => { - self.connection_state.group_editor.set_error(error); + self.connection_state.set_group_editor_error(error); } } cx.notify(); diff --git a/crates/nyaterm-desktop/src/features/connections/connections/menus.rs b/crates/nyaterm-desktop/src/features/connections/connections/menus.rs index e06533400..0dfb7a1d7 100644 --- a/crates/nyaterm-desktop/src/features/connections/connections/menus.rs +++ b/crates/nyaterm-desktop/src/features/connections/connections/menus.rs @@ -128,16 +128,12 @@ impl NyaTermApp { return; } self.connection_state - .confirmations - .open_group_open(ConnectionGroupOpenConfirmState { + .open_group_open_confirm(ConnectionGroupOpenConfirmState { group_id, label: group.name.clone(), connection_count, }); - let group_open_focus = self - .connection_state - .confirmations - .group_open_focus_handle(); + let group_open_focus = self.connection_state.group_open_focus_handle(); window.focus(&group_open_focus); cx.notify(); } @@ -146,7 +142,7 @@ impl NyaTermApp { &mut self, cx: &mut Context, ) { - self.connection_state.confirmations.close_group_open(); + self.connection_state.close_group_open_confirm(); cx.notify(); } @@ -155,7 +151,7 @@ impl NyaTermApp { window: &mut Window, cx: &mut Context, ) { - let Some(confirm) = self.connection_state.confirmations.take_group_open() else { + let Some(confirm) = self.connection_state.take_group_open_confirm() else { return; }; self.start_group_connections(confirm.group_id, window, cx); diff --git a/crates/nyaterm-desktop/src/features/connections/state.rs b/crates/nyaterm-desktop/src/features/connections/state.rs index 75c51247d..b377d0d79 100644 --- a/crates/nyaterm-desktop/src/features/connections/state.rs +++ b/crates/nyaterm-desktop/src/features/connections/state.rs @@ -61,11 +61,11 @@ use self::network_logic::{ pub(in crate::features) struct ConnectionFeatureState { pub list: ConnectionListState, - pub import: ConnectionImportState, + import: ConnectionImportState, pub editor: ConnectionEditorFeatureState, - pub group_editor: ConnectionGroupEditorFeatureState, - pub confirmations: ConnectionConfirmationState, - pub network: NetworkFeatureState, + group_editor: ConnectionGroupEditorFeatureState, + confirmations: ConnectionConfirmationState, + network: NetworkFeatureState, } pub(in crate::features) struct ConnectionFeatureFocus { @@ -109,7 +109,7 @@ pub(in crate::features) struct ConnectionListState { last_selected_id: Option, } -pub(in crate::features) struct ConnectionImportState { +struct ConnectionImportState { import_dialog_open: bool, import_path_prompt: Option, import_focus: FocusHandle, @@ -139,7 +139,7 @@ pub(in crate::features) struct ConnectionEditorFeatureState { menu_scroll: ScrollHandle, } -pub(in crate::features) struct ConnectionGroupEditorFeatureState { +struct ConnectionGroupEditorFeatureState { draft: Option, /// The folder-name input, built with the draft it mirrors. field: Option>, @@ -147,7 +147,7 @@ pub(in crate::features) struct ConnectionGroupEditorFeatureState { focus: FocusHandle, } -pub(in crate::features) struct ConnectionConfirmationState { +struct ConnectionConfirmationState { clear_all_open: bool, delete: Option, group_delete: Option, @@ -155,7 +155,7 @@ pub(in crate::features) struct ConnectionConfirmationState { group_open_focus: FocusHandle, } -pub(in crate::features) struct NetworkFeatureState { +struct NetworkFeatureState { tab: NetworkTab, delete_confirm: Option, group_editor: Option, @@ -357,6 +357,285 @@ impl ConnectionFeatureState { } } + pub fn active_group_editor_draft(&self) -> Option { + self.group_editor.active_draft() + } + + pub fn group_editor_focus_handle(&self) -> FocusHandle { + self.group_editor.focus_handle() + } + + pub fn begin_group_editor(&mut self, draft: ConnectionGroupEditorState) { + self.group_editor.begin_edit(draft); + } + + pub fn apply_group_editor_name_key(&mut self, key: &str, input: Option<&str>) -> bool { + self.group_editor.apply_name_key(key, input) + } + + pub fn set_group_editor_error(&mut self, error: String) -> bool { + self.group_editor.set_error(error) + } + + pub fn close_group_editor(&mut self) { + self.group_editor.close(); + } + + pub fn open_clear_all(&mut self) { + self.confirmations.open_clear_all(); + } + + pub fn close_clear_all(&mut self) { + self.confirmations.close_clear_all(); + } + + pub fn clear_all_is_open(&self) -> bool { + self.confirmations.clear_all_is_open() + } + + pub fn active_delete_confirm(&self) -> Option { + self.confirmations.active_delete() + } + + pub fn open_delete_confirm(&mut self, confirm: ConnectionDeleteConfirmState) { + self.confirmations.open_delete(confirm); + } + + pub fn close_delete_confirm(&mut self) { + self.confirmations.close_delete(); + } + + pub fn take_delete_confirm(&mut self) -> Option { + self.confirmations.take_delete() + } + + pub fn active_group_delete_confirm(&self) -> Option { + self.confirmations.active_group_delete() + } + + pub fn open_group_delete_confirm(&mut self, confirm: ConnectionGroupDeleteConfirmState) { + self.confirmations.open_group_delete(confirm); + } + + pub fn close_group_delete_confirm(&mut self) { + self.confirmations.close_group_delete(); + } + + pub fn take_group_delete_confirm(&mut self) -> Option { + self.confirmations.take_group_delete() + } + + pub fn active_group_open_confirm(&self) -> Option { + self.confirmations.active_group_open() + } + + pub fn open_group_open_confirm(&mut self, confirm: ConnectionGroupOpenConfirmState) { + self.confirmations.open_group_open(confirm); + } + + pub fn close_group_open_confirm(&mut self) { + self.confirmations.close_group_open(); + } + + pub fn take_group_open_confirm(&mut self) -> Option { + self.confirmations.take_group_open() + } + + pub fn group_open_focus_handle(&self) -> FocusHandle { + self.confirmations.group_open_focus_handle() + } + + pub fn network_active_tab(&self) -> NetworkTab { + self.network.active_tab() + } + + pub fn network_tab_is(&self, tab: NetworkTab) -> bool { + self.network.tab_is(tab) + } + + pub fn network_section_is_expanded(&self, section_key: &str) -> bool { + self.network.section_is_expanded(section_key) + } + + pub fn network_item_menu_is_open(&self, tab: NetworkTab, id: &str) -> bool { + self.network.item_menu_is_open(tab, id) + } + + pub fn network_move_picker_is_open(&self, tab: NetworkTab, id: &str) -> bool { + self.network.move_picker_is_open(tab, id) + } + + pub fn active_network_delete_confirm(&self) -> Option { + self.network.active_delete_confirm() + } + + pub fn active_network_group_editor(&self) -> Option { + self.network.active_group_editor() + } + + pub fn active_network_group_delete_confirm(&self) -> Option { + self.network.active_group_delete_confirm() + } + + pub fn active_network_tunnel_editor(&self) -> Option { + self.network.active_tunnel_editor() + } + + pub fn active_network_proxy_editor(&self) -> Option { + self.network.active_proxy_editor() + } + + pub fn network_tunnel_editor_focus_handle(&self) -> FocusHandle { + self.network.tunnel_editor_focus_handle() + } + + pub fn network_proxy_editor_focus_handle(&self) -> FocusHandle { + self.network.proxy_editor_focus_handle() + } + + pub fn set_network_tab(&mut self, tab: NetworkTab) { + self.network.set_tab(tab); + } + + pub fn toggle_network_section(&mut self, section_key: String) -> bool { + self.network.toggle_section(section_key) + } + + pub fn toggle_network_item_menu(&mut self, tab: NetworkTab, id: String) -> bool { + self.network.toggle_item_menu(tab, id) + } + + pub fn toggle_network_move_picker(&mut self, tab: NetworkTab, id: String) -> bool { + self.network.toggle_move_picker(tab, id) + } + + pub fn close_network_move_picker(&mut self) { + self.network.close_move_picker(); + } + + pub fn open_network_delete_confirm(&mut self, confirm: NetworkDeleteConfirmState) { + self.network.open_delete_confirm(confirm); + } + + pub fn close_network_delete_confirm(&mut self) { + self.network.close_delete_confirm(); + } + + pub fn begin_network_group_edit(&mut self, draft: NetworkGroupEditorState) { + self.network.begin_group_edit(draft); + } + + pub fn set_network_group_editor_name(&mut self, text: String) -> bool { + self.network.set_group_editor_name(text) + } + + pub fn set_network_group_editor_error(&mut self, error: String) -> bool { + self.network.set_group_editor_error(error) + } + + pub fn close_network_group_editor(&mut self) { + self.network.close_group_editor(); + } + + pub fn open_network_group_delete_confirm(&mut self, confirm: NetworkGroupDeleteConfirmState) { + self.network.open_group_delete_confirm(confirm); + } + + pub fn close_network_group_delete_confirm(&mut self) { + self.network.close_group_delete_confirm(); + } + + pub fn begin_network_tunnel_edit(&mut self, draft: NetworkTunnelEditorState) { + self.network.begin_tunnel_edit(draft); + } + + pub fn close_network_tunnel_editor(&mut self) { + self.network.close_tunnel_editor(); + } + + pub fn set_network_tunnel_editor_field( + &mut self, + field: NetworkTunnelEditorField, + text: String, + ) -> bool { + self.network.set_tunnel_editor_field(field, text) + } + + pub fn cycle_network_tunnel_type(&mut self) -> Option { + self.network.cycle_tunnel_type() + } + + pub fn cycle_network_tunnel_connection<'a>( + &mut self, + connection_ids: impl IntoIterator, + ) -> bool { + self.network.cycle_tunnel_connection(connection_ids) + } + + pub fn cycle_network_tunnel_group<'a>( + &mut self, + group_ids: impl IntoIterator, + ) -> bool { + self.network.cycle_tunnel_group(group_ids) + } + + pub fn set_network_tunnel_bind_localhost(&mut self, bind_localhost: bool) -> bool { + self.network.set_tunnel_bind_localhost(bind_localhost) + } + + pub fn toggle_network_tunnel_auto_open(&mut self) -> Option { + self.network.toggle_tunnel_auto_open() + } + + pub fn set_network_tunnel_editor_error(&mut self, error: String) -> bool { + self.network.set_tunnel_editor_error(error) + } + + pub fn begin_network_proxy_edit(&mut self, draft: NetworkProxyEditorState) { + self.network.begin_proxy_edit(draft); + } + + pub fn close_network_proxy_editor(&mut self) { + self.network.close_proxy_editor(); + } + + pub fn set_network_proxy_editor_field( + &mut self, + field: NetworkProxyEditorField, + text: String, + ) -> bool { + self.network.set_proxy_editor_field(field, text) + } + + pub fn cycle_network_proxy_protocol(&mut self) -> Option { + self.network.cycle_proxy_protocol() + } + + pub fn cycle_network_proxy_group<'a>( + &mut self, + group_ids: impl IntoIterator, + ) -> bool { + self.network.cycle_proxy_group(group_ids) + } + + pub fn set_network_proxy_editor_error(&mut self, error: String) -> bool { + self.network.set_proxy_editor_error(error) + } + + pub fn remove_network_item_references(&mut self, tab: NetworkTab, id: &str) { + self.network.remove_item_references(tab, id); + } + + pub fn remove_network_group_references( + &mut self, + tab: NetworkTab, + group_id: &str, + deleted_item_ids: &[String], + ) { + self.network + .remove_group_references(tab, group_id, deleted_item_ids); + } + pub fn clear_editor_fields(&mut self) { self.editor.fields.clear(); self.editor.field_subscriptions.clear(); @@ -376,6 +655,34 @@ impl ConnectionFeatureState { group_id, ); } + + pub fn import_dialog_is_open(&self) -> bool { + self.import.is_dialog_open() + } + + pub fn import_path_prompt_active(&self) -> bool { + self.import.path_prompt_active() + } + + pub fn import_focus_handle(&self) -> FocusHandle { + self.import.focus_handle() + } + + pub fn open_import_dialog(&mut self) { + self.import.open_dialog(); + } + + pub fn close_import_dialog(&mut self) { + self.import.close_dialog(); + } + + pub fn begin_import_path_prompt(&mut self, source: ConnectionImportSource) { + self.import.begin_path_prompt(source); + } + + pub fn finish_import_path_prompt(&mut self) { + self.import.finish_path_prompt(); + } } impl ConnectionListState { @@ -1309,18 +1616,18 @@ mod tests { clear_network_tunnel_editor, clear_selected_connection_ids, close_connection_more_menu, commit_connection_editor_new_group, connection_drop_position_for_target, connection_editor_inline_panel_draft, connection_editor_window_open_or_pending, - cycle_connection_sort_mode, cycle_network_proxy_group, cycle_network_proxy_protocol, - cycle_network_tunnel_connection, cycle_network_tunnel_group, cycle_network_tunnel_type, - finish_connection_editor_save_state, insert_connection_editor_description_newline, - remove_connection_list_references, remove_group_list_references, - remove_network_group_and_item_references, remove_network_group_references, - remove_network_item_references, retain_loaded_connection_list_references, - select_connection_ids, set_connection_drop_target_if_changed, - set_connection_editor_advanced_tab, set_connection_editor_error, - set_connection_editor_field_text, set_connection_editor_icon, set_connection_editor_kind, - set_connection_editor_menu_value, set_connection_editor_password_source, - set_connection_editor_telnet_tab, set_connection_group_editor_error, - set_connection_group_hover, set_network_group_editor_error, set_network_group_editor_name, + cycle_connection_sort_mode, cycle_network_proxy_protocol, cycle_network_tunnel_connection, + cycle_network_tunnel_group, cycle_network_tunnel_type, finish_connection_editor_save_state, + insert_connection_editor_description_newline, remove_connection_list_references, + remove_group_list_references, remove_network_group_and_item_references, + remove_network_group_references, remove_network_item_references, + retain_loaded_connection_list_references, select_connection_ids, + set_connection_drop_target_if_changed, set_connection_editor_advanced_tab, + set_connection_editor_error, set_connection_editor_field_text, set_connection_editor_icon, + set_connection_editor_kind, set_connection_editor_menu_value, + set_connection_editor_password_source, set_connection_editor_telnet_tab, + set_connection_group_editor_error, set_connection_group_hover, + set_network_group_editor_error, set_network_group_editor_name, set_network_proxy_editor_error, set_network_proxy_editor_field, set_network_tunnel_bind_localhost, set_network_tunnel_editor_error, set_network_tunnel_editor_field, stepped_menu_highlight, sync_connection_search_expansion, diff --git a/crates/nyaterm-desktop/src/features/pages/connections/editor/group_delete.rs b/crates/nyaterm-desktop/src/features/pages/connections/editor/group_delete.rs index 4b4c3a3ab..26cf43d62 100644 --- a/crates/nyaterm-desktop/src/features/pages/connections/editor/group_delete.rs +++ b/crates/nyaterm-desktop/src/features/pages/connections/editor/group_delete.rs @@ -33,9 +33,9 @@ impl NyaTermApp { .flex() .flex_col() .gap_3() - .track_focus(&self.connection_state.group_editor.focus_handle()) + .track_focus(&self.connection_state.group_editor_focus_handle()) .on_click(cx.listener(|this, _, window, cx| { - let group_editor_focus = this.connection_state.group_editor.focus_handle(); + let group_editor_focus = this.connection_state.group_editor_focus_handle(); window.focus(&group_editor_focus); cx.notify(); })) @@ -259,17 +259,9 @@ impl NyaTermApp { .flex() .flex_col() .gap_3() - .track_focus( - &self - .connection_state - .confirmations - .group_open_focus_handle(), - ) + .track_focus(&self.connection_state.group_open_focus_handle()) .on_click(cx.listener(|this, _, window, cx| { - let group_open_focus = this - .connection_state - .confirmations - .group_open_focus_handle(); + let group_open_focus = this.connection_state.group_open_focus_handle(); window.focus(&group_open_focus); cx.notify(); })) diff --git a/crates/nyaterm-desktop/src/features/pages/connections/view/page.rs b/crates/nyaterm-desktop/src/features/pages/connections/view/page.rs index 15abaf674..768578d28 100644 --- a/crates/nyaterm-desktop/src/features/pages/connections/view/page.rs +++ b/crates/nyaterm-desktop/src/features/pages/connections/view/page.rs @@ -221,25 +221,24 @@ impl NyaTermApp { .child(self.connections_search_bar(window, cx)) .child(list) .when_some( - self.connection_state.group_editor.active_draft(), + self.connection_state.active_group_editor_draft(), |this, editor| this.child(self.connection_group_editor_panel(editor, cx)), ) .when_some( - self.connection_state.confirmations.active_delete(), + self.connection_state.active_delete_confirm(), |this, confirm| this.child(self.connection_delete_confirm_panel(confirm, cx)), ) .when_some( - self.connection_state.confirmations.active_group_delete(), + self.connection_state.active_group_delete_confirm(), |this, confirm| this.child(self.connection_group_delete_confirm_panel(confirm, cx)), ) .when_some( - self.connection_state.confirmations.active_group_open(), + self.connection_state.active_group_open_confirm(), |this, confirm| this.child(self.connection_group_open_confirm_panel(confirm, cx)), ) - .when( - self.connection_state.confirmations.clear_all_is_open(), - |this| this.child(self.connections_clear_all_confirm_panel(cx)), - ) + .when(self.connection_state.clear_all_is_open(), |this| { + this.child(self.connections_clear_all_confirm_panel(cx)) + }) .when(self.connection_state.list.context_menu_is_open(), |this| { this.child(self.connection_context_menu_overlay(cx)) }) diff --git a/crates/nyaterm-desktop/src/features/pages/tunnels/mod.rs b/crates/nyaterm-desktop/src/features/pages/tunnels/mod.rs index d21bf554b..78e86de6a 100644 --- a/crates/nyaterm-desktop/src/features/pages/tunnels/mod.rs +++ b/crates/nyaterm-desktop/src/features/pages/tunnels/mod.rs @@ -79,7 +79,7 @@ impl NyaTermApp { proxy_list = proxy_list.child(proxy_section(palette, section, self, cx)); } } - let active_tab = self.connection_state.network.active_tab(); + let active_tab = self.connection_state.network_active_tab(); // Tauri NetworkPanel body (PanelHeader is shared): // scroll(p-3) > Tabs(grid-cols-2) > config row (label + New Group/New item) > grouped list. // Network create/edit/delete use modal dialogs (Tauri Dialog) over the panel. @@ -119,7 +119,7 @@ impl NyaTermApp { .child(network_tab_button( "network-tab-tunnels", self.tr("network.tunnels").to_string(), - self.connection_state.network.tab_is(NetworkTab::Tunnels), + self.connection_state.network_tab_is(NetworkTab::Tunnels), self.theme_palette(), cx.listener(|this, _, _, cx| { this.set_network_tab(NetworkTab::Tunnels, cx); @@ -128,7 +128,7 @@ impl NyaTermApp { .child(network_tab_button( "network-tab-proxies", self.tr("network.proxy").to_string(), - self.connection_state.network.tab_is(NetworkTab::Proxies), + self.connection_state.network_tab_is(NetworkTab::Proxies), self.theme_palette(), cx.listener(|this, _, _, cx| { this.set_network_tab(NetworkTab::Proxies, cx); @@ -161,7 +161,7 @@ impl NyaTermApp { "icons/fe/new-folder.svg", cx.listener(|this, _, _, cx| { this.open_network_group_editor( - this.connection_state.network.active_tab(), + this.connection_state.network_active_tab(), None, cx, ); @@ -169,8 +169,7 @@ impl NyaTermApp { )) .when( self.connection_state - .network - .tab_is(NetworkTab::Tunnels), + .network_tab_is(NetworkTab::Tunnels), |this| { this.child(network_create_button( palette, @@ -187,8 +186,7 @@ impl NyaTermApp { ) .when( self.connection_state - .network - .tab_is(NetworkTab::Proxies), + .network_tab_is(NetworkTab::Proxies), |this| { this.child(network_create_button( palette, @@ -223,19 +221,19 @@ impl NyaTermApp { cx: &mut Context, ) -> Option { let palette = self.theme_palette(); - if let Some(confirm) = self.connection_state.network.active_delete_confirm() { + if let Some(confirm) = self.connection_state.active_network_delete_confirm() { return Some(network_delete_confirm_panel(self, confirm, cx).into_any_element()); } - if let Some(editor) = self.connection_state.network.active_group_editor() { + if let Some(editor) = self.connection_state.active_network_group_editor() { return Some(network_group_editor_panel(self, editor, cx).into_any_element()); } - if let Some(confirm) = self.connection_state.network.active_group_delete_confirm() { + if let Some(confirm) = self.connection_state.active_network_group_delete_confirm() { return Some(network_group_delete_confirm_panel(self, confirm, cx).into_any_element()); } - if let Some(editor) = self.connection_state.network.active_tunnel_editor() { + if let Some(editor) = self.connection_state.active_network_tunnel_editor() { return Some(network_tunnel_editor_panel(palette, editor, self, cx).into_any_element()); } - if let Some(editor) = self.connection_state.network.active_proxy_editor() { + if let Some(editor) = self.connection_state.active_network_proxy_editor() { return Some(network_proxy_editor_panel(palette, editor, self, cx).into_any_element()); } None diff --git a/crates/nyaterm-desktop/src/features/pages/tunnels/proxy/rows.rs b/crates/nyaterm-desktop/src/features/pages/tunnels/proxy/rows.rs index 686740022..d0250ab6f 100644 --- a/crates/nyaterm-desktop/src/features/pages/tunnels/proxy/rows.rs +++ b/crates/nyaterm-desktop/src/features/pages/tunnels/proxy/rows.rs @@ -33,8 +33,7 @@ pub(in crate::features::pages::tunnels) fn proxy_network_row( let proxy_label_for_delete = proxy.name.clone(); let menu_open = app .connection_state - .network - .item_menu_is_open(NetworkTab::Proxies, &proxy.id); + .network_item_menu_is_open(NetworkTab::Proxies, &proxy.id); // Tauri ProxyRow: name, protocol, address; overflow actions on the right. div() diff --git a/crates/nyaterm-desktop/src/features/pages/tunnels/proxy/sections.rs b/crates/nyaterm-desktop/src/features/pages/tunnels/proxy/sections.rs index ca3c8b65a..cf47aa88a 100644 --- a/crates/nyaterm-desktop/src/features/pages/tunnels/proxy/sections.rs +++ b/crates/nyaterm-desktop/src/features/pages/tunnels/proxy/sections.rs @@ -74,8 +74,7 @@ pub(in crate::features::pages::tunnels) fn proxy_section( let section_key = format!("proxy:{}", section.id); let collapsed = !app .connection_state - .network - .section_is_expanded(§ion_key); + .network_section_is_expanded(§ion_key); let section_id_for_toggle = section.id.clone(); let mut rows = div().flex().flex_col(); if section.proxies.is_empty() { @@ -93,8 +92,7 @@ pub(in crate::features::pages::tunnels) fn proxy_section( for (index, proxy) in section.proxies.into_iter().enumerate() { let move_picker_open = app .connection_state - .network - .move_picker_is_open(NetworkTab::Proxies, &proxy.id); + .network_move_picker_is_open(NetworkTab::Proxies, &proxy.id); rows = rows.child( div() .flex() @@ -191,8 +189,7 @@ pub(in crate::features::pages::tunnels) fn proxy_section( let menu_id = format!("group:{}", group.id); let menu_open = app .connection_state - .network - .item_menu_is_open(NetworkTab::Proxies, &menu_id); + .network_item_menu_is_open(NetworkTab::Proxies, &menu_id); this.child(network_item_overflow_menu( palette, app.shell_surface_color(palette.surface), diff --git a/crates/nyaterm-desktop/src/features/pages/tunnels/tunnel/sections.rs b/crates/nyaterm-desktop/src/features/pages/tunnels/tunnel/sections.rs index d0172ed1f..1b2b8357b 100644 --- a/crates/nyaterm-desktop/src/features/pages/tunnels/tunnel/sections.rs +++ b/crates/nyaterm-desktop/src/features/pages/tunnels/tunnel/sections.rs @@ -77,8 +77,7 @@ pub(in crate::features::pages::tunnels) fn tunnel_section( let section_key = format!("tunnel:{}", section.id); let collapsed = !app .connection_state - .network - .section_is_expanded(§ion_key); + .network_section_is_expanded(§ion_key); let section_id_for_toggle = section.id.clone(); let mut rows = div().flex().flex_col(); if section.tunnels.is_empty() { @@ -119,12 +118,10 @@ pub(in crate::features::pages::tunnels) fn tunnel_section( let tunnel_label_for_delete = tunnel_name(&tunnel); let move_picker_open = app .connection_state - .network - .move_picker_is_open(NetworkTab::Tunnels, &tunnel.id); + .network_move_picker_is_open(NetworkTab::Tunnels, &tunnel.id); let menu_open = app .connection_state - .network - .item_menu_is_open(NetworkTab::Tunnels, &tunnel.id); + .network_item_menu_is_open(NetworkTab::Tunnels, &tunnel.id); let current_group_id = tunnel.group_id.clone(); rows = rows.child( div() @@ -272,8 +269,7 @@ pub(in crate::features::pages::tunnels) fn tunnel_section( let menu_id = format!("group:{}", group.id); let menu_open = app .connection_state - .network - .item_menu_is_open(NetworkTab::Tunnels, &menu_id); + .network_item_menu_is_open(NetworkTab::Tunnels, &menu_id); this.child(network_item_overflow_menu( palette, app.shell_surface_color(palette.surface), diff --git a/crates/nyaterm-desktop/src/features/panels/connection_import_overlay.rs b/crates/nyaterm-desktop/src/features/panels/connection_import_overlay.rs index 304749cbf..66a58f7f5 100644 --- a/crates/nyaterm-desktop/src/features/panels/connection_import_overlay.rs +++ b/crates/nyaterm-desktop/src/features/panels/connection_import_overlay.rs @@ -35,7 +35,7 @@ impl NyaTermApp { .items_center() .justify_center() .p_3() - .track_focus(&self.connection_state.import.focus_handle()) + .track_focus(&self.connection_state.import_focus_handle()) .on_click(cx.listener(|this, _, _, cx| { this.close_connection_import_dialog(cx); })) diff --git a/crates/nyaterm-desktop/src/features/root.rs b/crates/nyaterm-desktop/src/features/root.rs index 020bc2957..eb37bce4d 100644 --- a/crates/nyaterm-desktop/src/features/root.rs +++ b/crates/nyaterm-desktop/src/features/root.rs @@ -619,7 +619,7 @@ impl NyaTermApp { .when(self.quick_command_state.import.dialog_open, |this| { this.child(self.quick_command_import_overlay(cx)) }) - .when(self.connection_state.import.is_dialog_open(), |this| { + .when(self.connection_state.import_dialog_is_open(), |this| { this.child(self.connection_import_overlay(cx)) }) .when(quick_switch_open, |this| { diff --git a/crates/nyaterm-desktop/src/features/shell/panel_stack_runtime.rs b/crates/nyaterm-desktop/src/features/shell/panel_stack_runtime.rs index 27ad6bf5a..235781415 100644 --- a/crates/nyaterm-desktop/src/features/shell/panel_stack_runtime.rs +++ b/crates/nyaterm-desktop/src/features/shell/panel_stack_runtime.rs @@ -554,7 +554,7 @@ impl NyaTermApp { NavItem::ActiveSessions => SharedString::from(self.active_sessions_header_count()), // Tauri NetworkPanel header shows active tab profile count. NavItem::Tunnels => { - let count = match self.connection_state.network.active_tab() { + let count = match self.connection_state.network_active_tab() { NetworkTab::Tunnels => self.tunnels.len(), NetworkTab::Proxies => self.proxies.len(), }; diff --git a/crates/nyaterm-desktop/src/features/tunnels/tunnel_runtime/actions.rs b/crates/nyaterm-desktop/src/features/tunnels/tunnel_runtime/actions.rs index 68ff91df5..78e8346f4 100644 --- a/crates/nyaterm-desktop/src/features/tunnels/tunnel_runtime/actions.rs +++ b/crates/nyaterm-desktop/src/features/tunnels/tunnel_runtime/actions.rs @@ -15,7 +15,7 @@ impl NyaTermApp { id: String, cx: &mut Context, ) { - self.connection_state.network.toggle_item_menu(tab, id); + self.connection_state.toggle_network_item_menu(tab, id); cx.notify(); } @@ -25,7 +25,7 @@ impl NyaTermApp { id: String, cx: &mut Context, ) { - if self.connection_state.network.toggle_move_picker(tab, id) { + if self.connection_state.toggle_network_move_picker(tab, id) { self.terminal.view.status = format!("choose {} group", tab.label()); } else { self.terminal.view.status = "network move menu closed".to_string(); @@ -74,7 +74,7 @@ impl NyaTermApp { { Ok(()) => { self.tunnels = next_tunnels; - self.connection_state.network.close_move_picker(); + self.connection_state.close_network_move_picker(); self.terminal.view.status = format!("tunnel moved to {label}"); self.store_status.message = "tunnel group saved".to_string(); self.store_status.ready = true; @@ -126,7 +126,7 @@ impl NyaTermApp { { Ok(()) => { self.proxies = next_proxies; - self.connection_state.network.close_move_picker(); + self.connection_state.close_network_move_picker(); self.terminal.view.status = format!("proxy moved to {label}"); self.store_status.message = "proxy group saved".to_string(); self.store_status.ready = true; @@ -148,20 +148,19 @@ impl NyaTermApp { cx: &mut Context, ) { self.connection_state - .network - .open_delete_confirm(NetworkDeleteConfirmState { tab, id, label }); + .open_network_delete_confirm(NetworkDeleteConfirmState { tab, id, label }); self.terminal.view.status = "network delete confirmation opened".to_string(); cx.notify(); } pub(in crate::features) fn cancel_network_delete(&mut self, cx: &mut Context) { - self.connection_state.network.close_delete_confirm(); + self.connection_state.close_network_delete_confirm(); self.terminal.view.status = "network delete cancelled".to_string(); cx.notify(); } pub(in crate::features) fn confirm_network_delete(&mut self, cx: &mut Context) { - let Some(delete) = self.connection_state.network.active_delete_confirm() else { + let Some(delete) = self.connection_state.active_network_delete_confirm() else { self.terminal.view.status = "no network delete is pending".to_string(); cx.notify(); return; @@ -202,8 +201,7 @@ impl NyaTermApp { self.tunnels = next_tunnels; self.pending_tunnels.retain(|id| id != &tunnel_id); self.connection_state - .network - .remove_item_references(NetworkTab::Tunnels, &tunnel_id); + .remove_network_item_references(NetworkTab::Tunnels, &tunnel_id); self.terminal.view.status = if deleted { format!("tunnel '{label}' deleted") } else { @@ -240,8 +238,7 @@ impl NyaTermApp { let deleted = next_proxies.len() != before; self.proxies = next_proxies; self.connection_state - .network - .remove_item_references(NetworkTab::Proxies, &proxy_id); + .remove_network_item_references(NetworkTab::Proxies, &proxy_id); self.terminal.view.status = if deleted { format!("proxy '{label}' deleted") } else { diff --git a/crates/nyaterm-desktop/src/features/tunnels/tunnel_runtime/groups.rs b/crates/nyaterm-desktop/src/features/tunnels/tunnel_runtime/groups.rs index 6e9a6af49..31b5332b6 100644 --- a/crates/nyaterm-desktop/src/features/tunnels/tunnel_runtime/groups.rs +++ b/crates/nyaterm-desktop/src/features/tunnels/tunnel_runtime/groups.rs @@ -31,8 +31,7 @@ impl NyaTermApp { }; self.connection_state - .network - .begin_group_edit(NetworkGroupEditorState { + .begin_network_group_edit(NetworkGroupEditorState { tab, id: group_id, name, @@ -46,7 +45,7 @@ impl NyaTermApp { } pub(in crate::features) fn close_network_group_editor(&mut self, cx: &mut Context) { - self.connection_state.network.close_group_editor(); + self.connection_state.close_network_group_editor(); self.forget_text_inputs("network.group-editor."); self.terminal.view.status = "network group editor closed".to_string(); cx.notify(); @@ -58,13 +57,13 @@ impl NyaTermApp { text: String, cx: &mut Context, ) { - if self.connection_state.network.set_group_editor_name(text) { + if self.connection_state.set_network_group_editor_name(text) { cx.notify(); } } pub(in crate::features) fn save_network_group_editor(&mut self, cx: &mut Context) { - let Some(editor) = self.connection_state.network.active_group_editor() else { + let Some(editor) = self.connection_state.active_network_group_editor() else { self.terminal.view.status = "no network group editor is active".to_string(); cx.notify(); return; @@ -72,8 +71,7 @@ impl NyaTermApp { let name = editor.name.trim().to_string(); if name.is_empty() { self.connection_state - .network - .set_group_editor_error("Group name is required".to_string()); + .set_network_group_editor_error("Group name is required".to_string()); cx.notify(); return; } @@ -114,7 +112,7 @@ impl NyaTermApp { { Ok(()) => { self.tunnel_groups = groups; - self.connection_state.network.close_group_editor(); + self.connection_state.close_network_group_editor(); self.terminal.view.status = format!("tunnel group '{name}' saved"); self.store_status.message = self.terminal.view.status.clone(); self.store_status.ready = true; @@ -158,7 +156,7 @@ impl NyaTermApp { { Ok(()) => { self.proxy_groups = groups; - self.connection_state.network.close_group_editor(); + self.connection_state.close_network_group_editor(); self.terminal.view.status = format!("proxy group '{name}' saved"); self.store_status.message = self.terminal.view.status.clone(); self.store_status.ready = true; @@ -181,8 +179,7 @@ impl NyaTermApp { cx: &mut Context, ) { self.connection_state - .network - .open_group_delete_confirm(NetworkGroupDeleteConfirmState { + .open_network_group_delete_confirm(NetworkGroupDeleteConfirmState { tab, id, label, @@ -193,13 +190,13 @@ impl NyaTermApp { } pub(in crate::features) fn cancel_network_group_delete(&mut self, cx: &mut Context) { - self.connection_state.network.close_group_delete_confirm(); + self.connection_state.close_network_group_delete_confirm(); self.terminal.view.status = "network group delete cancelled".to_string(); cx.notify(); } pub(in crate::features) fn confirm_network_group_delete(&mut self, cx: &mut Context) { - let Some(delete) = self.connection_state.network.active_group_delete_confirm() else { + let Some(delete) = self.connection_state.active_network_group_delete_confirm() else { self.terminal.view.status = "no network group delete is pending".to_string(); cx.notify(); return; @@ -247,7 +244,7 @@ impl NyaTermApp { Ok(()) => { self.tunnel_groups = groups; self.tunnels = tunnels; - self.connection_state.network.remove_group_references( + self.connection_state.remove_network_group_references( NetworkTab::Tunnels, &group_id, &deleted_tunnel_ids, @@ -301,7 +298,7 @@ impl NyaTermApp { Ok(()) => { self.proxy_groups = groups; self.proxies = proxies; - self.connection_state.network.remove_group_references( + self.connection_state.remove_network_group_references( NetworkTab::Proxies, &group_id, &deleted_proxy_ids, diff --git a/crates/nyaterm-desktop/src/features/tunnels/tunnel_runtime/proxy_editor.rs b/crates/nyaterm-desktop/src/features/tunnels/tunnel_runtime/proxy_editor.rs index c01119eed..d6ca90fcc 100644 --- a/crates/nyaterm-desktop/src/features/tunnels/tunnel_runtime/proxy_editor.rs +++ b/crates/nyaterm-desktop/src/features/tunnels/tunnel_runtime/proxy_editor.rs @@ -23,8 +23,7 @@ impl NyaTermApp { }; self.connection_state - .network - .begin_proxy_edit(NetworkProxyEditorState { + .begin_network_proxy_edit(NetworkProxyEditorState { id: proxy_id, name: proxy.name, protocol: match proxy.protocol.as_str() { @@ -54,13 +53,13 @@ impl NyaTermApp { // the next proxy to seed from its own values. self.forget_text_inputs("network.proxy-editor."); self.terminal.view.status = "proxy editor opened".to_string(); - let proxy_editor_focus = self.connection_state.network.proxy_editor_focus_handle(); + let proxy_editor_focus = self.connection_state.network_proxy_editor_focus_handle(); window.focus(&proxy_editor_focus); cx.notify(); } pub(in crate::features) fn close_network_proxy_editor(&mut self, cx: &mut Context) { - self.connection_state.network.close_proxy_editor(); + self.connection_state.close_network_proxy_editor(); self.forget_text_inputs("network.proxy-editor."); self.terminal.view.status = "proxy editor closed".to_string(); cx.notify(); @@ -84,15 +83,14 @@ impl NyaTermApp { }; if self .connection_state - .network - .set_proxy_editor_field(field, text) + .set_network_proxy_editor_field(field, text) { cx.notify(); } } pub(in crate::features) fn cycle_network_proxy_protocol(&mut self, cx: &mut Context) { - if let Some(protocol) = self.connection_state.network.cycle_proxy_protocol() { + if let Some(protocol) = self.connection_state.cycle_network_proxy_protocol() { self.terminal.view.status = format!("proxy protocol set to {protocol}"); } cx.notify(); @@ -101,8 +99,7 @@ impl NyaTermApp { pub(in crate::features) fn cycle_network_proxy_group(&mut self, cx: &mut Context) { if self .connection_state - .network - .cycle_proxy_group(self.proxy_groups.iter().map(|group| group.id.as_str())) + .cycle_network_proxy_group(self.proxy_groups.iter().map(|group| group.id.as_str())) { self.terminal.view.status = "proxy group changed".to_string(); } @@ -110,7 +107,7 @@ impl NyaTermApp { } pub(in crate::features) fn save_network_proxy_editor(&mut self, cx: &mut Context) { - let Some(editor) = self.connection_state.network.active_proxy_editor() else { + let Some(editor) = self.connection_state.active_network_proxy_editor() else { self.terminal.view.status = "no proxy editor is active".to_string(); cx.notify(); return; @@ -200,7 +197,7 @@ impl NyaTermApp { { Ok(()) => { self.proxies = next_proxies; - self.connection_state.network.close_proxy_editor(); + self.connection_state.close_network_proxy_editor(); self.terminal.view.status = format!("proxy '{name}' saved"); self.store_status.message = self.terminal.view.status.clone(); self.store_status.ready = true; @@ -210,8 +207,7 @@ impl NyaTermApp { self.store_status.message = self.terminal.view.status.clone(); self.store_status.ready = false; self.connection_state - .network - .set_proxy_editor_error(self.terminal.view.status.clone()); + .set_network_proxy_editor_error(self.terminal.view.status.clone()); } } cx.notify(); @@ -224,8 +220,7 @@ impl NyaTermApp { ) { let error = error.into(); self.connection_state - .network - .set_proxy_editor_error(error.clone()); + .set_network_proxy_editor_error(error.clone()); self.terminal.view.status = error; cx.notify(); } diff --git a/crates/nyaterm-desktop/src/features/tunnels/tunnel_runtime/tunnel_editor.rs b/crates/nyaterm-desktop/src/features/tunnels/tunnel_runtime/tunnel_editor.rs index 32f4b5c13..872659cff 100644 --- a/crates/nyaterm-desktop/src/features/tunnels/tunnel_runtime/tunnel_editor.rs +++ b/crates/nyaterm-desktop/src/features/tunnels/tunnel_runtime/tunnel_editor.rs @@ -7,7 +7,7 @@ use crate::models::{NetworkTab, NetworkTunnelEditorField, NetworkTunnelEditorSta impl NyaTermApp { pub(in crate::features) fn set_network_tab(&mut self, tab: NetworkTab, cx: &mut Context) { - self.connection_state.network.set_tab(tab); + self.connection_state.set_network_tab(tab); self.terminal.view.status = format!("network tab set to {}", tab.label()); cx.notify(); } @@ -19,7 +19,7 @@ impl NyaTermApp { cx: &mut Context, ) { let key = network_section_key(tab, §ion_id); - if self.connection_state.network.toggle_section(key) { + if self.connection_state.toggle_network_section(key) { self.terminal.view.status = format!("expanded {} group", tab.label()); } else { self.terminal.view.status = format!("collapsed {} group", tab.label()); @@ -44,8 +44,7 @@ impl NyaTermApp { }; self.connection_state - .network - .begin_tunnel_edit(NetworkTunnelEditorState { + .begin_network_tunnel_edit(NetworkTunnelEditorState { id: tunnel_id, is_open: tunnel.is_open, name: tunnel.name, @@ -79,13 +78,13 @@ impl NyaTermApp { // next tunnel to seed from its own values. self.forget_text_inputs("network.tunnel-editor."); self.terminal.view.status = "tunnel editor opened".to_string(); - let tunnel_editor_focus = self.connection_state.network.tunnel_editor_focus_handle(); + let tunnel_editor_focus = self.connection_state.network_tunnel_editor_focus_handle(); window.focus(&tunnel_editor_focus); cx.notify(); } pub(in crate::features) fn close_network_tunnel_editor(&mut self, cx: &mut Context) { - self.connection_state.network.close_tunnel_editor(); + self.connection_state.close_network_tunnel_editor(); self.forget_text_inputs("network.tunnel-editor."); self.terminal.view.status = "tunnel editor closed".to_string(); cx.notify(); @@ -107,15 +106,14 @@ impl NyaTermApp { }; if self .connection_state - .network - .set_tunnel_editor_field(field, text) + .set_network_tunnel_editor_field(field, text) { cx.notify(); } } pub(in crate::features) fn cycle_network_tunnel_type(&mut self, cx: &mut Context) { - if let Some(tunnel_type) = self.connection_state.network.cycle_tunnel_type() { + if let Some(tunnel_type) = self.connection_state.cycle_network_tunnel_type() { self.terminal.view.status = format!("tunnel type set to {tunnel_type}"); } cx.notify(); @@ -130,8 +128,7 @@ impl NyaTermApp { .collect::>(); if self .connection_state - .network - .cycle_tunnel_connection(connection_ids) + .cycle_network_tunnel_connection(connection_ids) { self.terminal.view.status = "tunnel SSH connection changed".to_string(); cx.notify(); @@ -141,8 +138,7 @@ impl NyaTermApp { pub(in crate::features) fn cycle_network_tunnel_group(&mut self, cx: &mut Context) { if self .connection_state - .network - .cycle_tunnel_group(self.tunnel_groups.iter().map(|group| group.id.as_str())) + .cycle_network_tunnel_group(self.tunnel_groups.iter().map(|group| group.id.as_str())) { self.terminal.view.status = "tunnel group changed".to_string(); } @@ -155,13 +151,12 @@ impl NyaTermApp { cx: &mut Context, ) { self.connection_state - .network - .set_tunnel_bind_localhost(bind_localhost); + .set_network_tunnel_bind_localhost(bind_localhost); cx.notify(); } pub(in crate::features) fn toggle_network_tunnel_auto_open(&mut self, cx: &mut Context) { - if let Some(auto_open) = self.connection_state.network.toggle_tunnel_auto_open() { + if let Some(auto_open) = self.connection_state.toggle_network_tunnel_auto_open() { self.terminal.view.status = if auto_open { "tunnel auto-open enabled" } else { @@ -173,7 +168,7 @@ impl NyaTermApp { } pub(in crate::features) fn save_network_tunnel_editor(&mut self, cx: &mut Context) { - let Some(editor) = self.connection_state.network.active_tunnel_editor() else { + let Some(editor) = self.connection_state.active_network_tunnel_editor() else { self.terminal.view.status = "no tunnel editor is active".to_string(); cx.notify(); return; @@ -255,7 +250,7 @@ impl NyaTermApp { { Ok(()) => { self.tunnels = next_tunnels; - self.connection_state.network.close_tunnel_editor(); + self.connection_state.close_network_tunnel_editor(); self.terminal.view.status = format!("tunnel '{name}' saved"); self.store_status.message = self.terminal.view.status.clone(); self.store_status.ready = true; @@ -265,8 +260,7 @@ impl NyaTermApp { self.store_status.message = self.terminal.view.status.clone(); self.store_status.ready = false; self.connection_state - .network - .set_tunnel_editor_error(self.terminal.view.status.clone()); + .set_network_tunnel_editor_error(self.terminal.view.status.clone()); } } cx.notify(); @@ -279,8 +273,7 @@ impl NyaTermApp { ) { let error = error.into(); self.connection_state - .network - .set_tunnel_editor_error(error.clone()); + .set_network_tunnel_editor_error(error.clone()); self.terminal.view.status = error; cx.notify(); } diff --git a/docs/architecture/gpui-migration-status.md b/docs/architecture/gpui-migration-status.md index ddfe8cd21..543487598 100644 --- a/docs/architecture/gpui-migration-status.md +++ b/docs/architecture/gpui-migration-status.md @@ -3,13 +3,13 @@ This document records the current GPUI migration boundaries and debt in `nyaterm-desktop`. Keep dynamic counts here instead of in `AGENTS.md`. -Last updated from the working tree on 2026-07-27. +Last updated from the working tree on 2026-07-28. ## Current Metrics | Metric | Current value | Notes | | --- | ---: | --- | -| `NyaTermApp` fields | 262 | Counted from `features/app_state/mod.rs`; down from 585, still transitional. | +| `NyaTermApp` fields | 261 | Counted from `features/app_state/mod.rs`; down from 585, still transitional. | | `impl NyaTermApp` blocks | 240 | Spread across 235 files under `crates/nyaterm-desktop/src`. | | `#[path = "..."]` declarations in desktop | 0 | Cleared. Every directory is a real module; the boundary script fails on any new occurrence. | | `use super::*` imports in desktop | 372 | Includes indented test-module imports; historical migration debt, do not add new occurrences. | @@ -318,17 +318,21 @@ these as staged extraction candidates, not as formatting-only refactor targets. guards governed editor runtime/view/projection paths against direct `focus` field reads. - Connection import runtime, overlay, and root rendering now use - `ConnectionImportState` façade methods for dialog visibility, active path - prompts, and focus handle access. The architecture script guards those files - against reintroducing direct `import_dialog_open`/`import_path_prompt`/ - `import_focus` field reads. + `ConnectionFeatureState` façade methods for dialog visibility, active path + prompts, and focus handle access. The `import` child state is private, and + the architecture script guards governed features against reintroducing direct + `connection_state.import.*` access. - Connection group editor name input and validation errors now route through - `ConnectionGroupEditorFeatureState` methods instead of direct runtime draft - mutation. + `ConnectionFeatureState` methods instead of direct runtime draft mutation. - Connection group editor runtime, modal view, page rendering, and snapshot - publication now use `ConnectionGroupEditorFeatureState` façade methods for - active draft, open state, and focus handle access. The architecture script - guards those files against reintroducing direct `draft`/`focus` field reads. + publication now use `ConnectionFeatureState` façade methods for active draft, + open state, and focus handle access. The `group_editor` child state is + private, and the architecture script guards governed features against + reintroducing direct `connection_state.group_editor.*` access. +- Connection delete, group-delete, group-open and clear-all confirmations now + route through `ConnectionFeatureState` façade methods. The `confirmations` + child state is private, so rendering and runtime actions no longer reach into + `connection_state.confirmations.*` directly. - Connection list refresh cleanup now runs after successful `refresh_store_from_runtime()` session reloads. Selection, range anchor, hover, pending hover, context menus, expanded groups, and drop target state @@ -340,12 +344,13 @@ these as staged extraction candidates, not as formatting-only refactor targets. - Saved-group expansion now routes through `ConnectionListState::expand_group`; the architecture script guards against reintroducing direct expanded-group insertion in governed connections code. -- Network page UI state now exposes semantic methods for tab/menu/move-picker - state, expanded-section reads, delete and group confirmations, tunnel/proxy - editor lifetime, group/tunnel/proxy editor input, focus/error/cycle/toggle - transitions, and deleted item reference cleanup. Tunnel runtime actions and - Network page rendering now use these methods instead of directly accessing - `connection_state.network` fields for those transitions and projections. +- Network page UI state now sits behind `ConnectionFeatureState` façade methods + for tab/menu/move-picker state, expanded-section reads, delete and group + confirmations, tunnel/proxy editor lifetime, group/tunnel/proxy editor input, + focus/error/cycle/toggle transitions, and deleted item reference cleanup. The + `network` child state and `NetworkFeatureState` type are private to the state + module; tunnel runtime actions, Network page rendering, and panel-count + projection no longer access `connection_state.network.*` directly. - `NetworkFeatureState` pure helper logic now lives in `features/connections/state/network_logic.rs`. The public semantic methods remain in `state.rs`, while 485 lines of menu, move-picker, group editor, @@ -814,6 +819,10 @@ these as staged extraction candidates, not as formatting-only refactor targets. import JSON parsing, rule normalization, and merge accounting. `storage.rs` still owns settings load/save persistence, so redb table names, settings field paths, encryption, backup, and legacy fallback behavior are unchanged. +- The architecture script's local legacy-source-path allowlist now includes + only the static icon vendoring script and manifest in addition to the existing + migration inventory paths. These references are provenance for committed + assets; default builds still must not depend on `./temp/nyaterm-tauri`. ## Migrating @@ -831,11 +840,11 @@ Current ownership map: | Serial ports | `NyaTermApp.connection_serial_ports` | Runtime/discovered state | Not persisted by this state grouping. | | Tunnel/proxy configs | `NyaTermApp.tunnels`, `tunnel_groups`, `proxies`, `proxy_groups` | Persisted network config | UI overlay state moved under `connection_state.network`; config collections remain persisted domain state. | | List search/sort/hover/selection/DnD | `NyaTermApp.connection_state.list` | Temporary UI state | State is not persisted except sort setting remains synced to settings as before. | -| Connection import dialog | `NyaTermApp.connection_state.import` | Temporary UI/runtime prompt state | File import still runs through existing runtime paths. | +| Connection import dialog | `NyaTermApp.connection_state` private import child | Temporary UI/runtime prompt state | File import still runs through existing runtime paths; runtime and rendering enter through `ConnectionFeatureState` methods. | | Connection editor | `NyaTermApp.connection_state.editor` | Editing draft/window UI state | Runtime key handling, window lifecycle, rendering popovers, and sideband projection use state methods; draft remains separate from saved connection data. | -| Group editor | `NyaTermApp.connection_state.group_editor` | Editing draft UI state | Draft remains separate from saved groups. | -| Delete/open confirmations | `NyaTermApp.connection_state.confirmations` | Temporary UI state | Rendering and sideband projection now use state methods; persisted data changes only after existing confirm actions run. | -| Network page UI | `NyaTermApp.connection_state.network` | Temporary UI/editor state | Page rendering, editor focus, confirm/editor draft reads, and panel-count projection use state methods. Tunnel/proxy configs remain in top-level persisted collections. | +| Group editor | `NyaTermApp.connection_state` private group-editor child | Editing draft UI state | Draft remains separate from saved groups; runtime and rendering enter through `ConnectionFeatureState` methods. | +| Delete/open confirmations | `NyaTermApp.connection_state` private confirmations child | Temporary UI state | Rendering and runtime actions enter through `ConnectionFeatureState` methods; persisted data changes only after existing confirm actions run. | +| Network page UI | `NyaTermApp.connection_state` private network child | Temporary UI/editor state | Page rendering, editor focus, confirm/editor draft reads, and panel-count projection use `ConnectionFeatureState` methods. Tunnel/proxy configs remain in top-level persisted collections. | This round changed desktop-side state ownership, UI state plumbing, and module boundaries. Final reports should avoid broad statements that sound like no @@ -858,7 +867,7 @@ desktop state ownership/UI adapter change, not a terminal parser, terminal protocol, SSH/SFTP protocol, transfer protocol, or persistence-format change. The tunnel/proxy runtime action files were touched only to route Network page menu, editor, confirmation, and stale-reference UI state through -`NetworkFeatureState` after the existing persistence operations succeed. +`ConnectionFeatureState` after the existing persistence operations succeed. Tunnel/proxy config storage formats and transport execution paths continue to use the existing behavior. diff --git a/scripts/check-architecture-boundaries.sh b/scripts/check-architecture-boundaries.sh index 8eb6357d2..2413774d4 100755 --- a/scripts/check-architecture-boundaries.sh +++ b/scripts/check-architecture-boundaries.sh @@ -453,6 +453,8 @@ while IFS=: read -r file _line text; do case "$file" in crates/nyaterm-desktop/src/features/mod.rs) ;; crates/nyaterm-desktop/src/features/app_state/construct.rs) ;; + scripts/sync-icons.sh) ;; + scripts/icons.manifest) ;; docs/architecture/gpui-migration-status.md) ;; scripts/check-architecture-boundaries.sh) ;; *) @@ -577,27 +579,31 @@ check_no_matches \ '^[[:space:]]*pub(\([^)]*\))?[[:space:]]+(search_draft|search_focus|sort_mode|more_menu_open|context_menu|group_context_menu|hovered_connection_id|hover_pending|drop_target|hovered_group_id|expanded_group_ids|selected_ids|last_selected_id|import_dialog_open|import_path_prompt|import_focus|draft|window|window_open_pending|focus|icon_picker_open|menu|clear_all_open|delete|group_delete|group_open|group_open_focus|tab|delete_confirm|group_delete_confirm|item_menu|move_picker|expanded_sections|tunnel_editor|proxy_editor|group_editor_focus|tunnel_editor_focus|proxy_editor_focus)[[:space:]]*:' \ crates/nyaterm-desktop/src/features/connections/state.rs check_no_matches \ - "connection confirmations must be mutated through ConnectionConfirmationState methods" \ + "connection confirmation child state must stay behind ConnectionFeatureState methods" \ + 'connection_state\.confirmations\.' \ + crates/nyaterm-desktop/src/features +check_no_matches \ + "connection confirmations must be mutated through ConnectionFeatureState methods" \ 'connection_state\.confirmations\.(clear_all_open|delete|group_delete|group_open)\s*=' \ crates/nyaterm-desktop/src/features/connections check_no_matches \ - "connection page confirmations must be mutated through ConnectionConfirmationState methods" \ + "connection page confirmations must be mutated through ConnectionFeatureState methods" \ 'connection_state\.confirmations\.(clear_all_open|delete|group_delete|group_open)\s*=' \ crates/nyaterm-desktop/src/features/pages/connections check_no_matches \ - "connection menu confirmation reads must use ConnectionConfirmationState methods" \ + "connection menu confirmation reads must use ConnectionFeatureState methods" \ 'connection_state\.confirmations\.(clear_all_open|delete|group_delete|group_open|group_open_focus)(\.|[[:space:]]|$)' \ crates/nyaterm-desktop/src/features/connections/connections/menus.rs check_no_matches \ - "connection confirmation panel reads must use ConnectionConfirmationState methods" \ + "connection confirmation panel reads must use ConnectionFeatureState methods" \ 'connection_state\.confirmations\.(clear_all_open|delete|group_delete|group_open|group_open_focus)(\.|[[:space:]]|$)' \ crates/nyaterm-desktop/src/features/pages/connections/editor/group_delete.rs check_no_matches \ - "connections page confirmation reads must use ConnectionConfirmationState methods" \ + "connections page confirmation reads must use ConnectionFeatureState methods" \ 'connection_state\.confirmations\.(clear_all_open|delete|group_delete|group_open|group_open_focus)(\.|[[:space:]]|$)' \ crates/nyaterm-desktop/src/features/pages/connections/view/page.rs check_no_matches \ - "event pump confirmation projection must use ConnectionConfirmationState methods" \ + "event pump confirmation projection must use ConnectionFeatureState methods" \ 'connection_state\.confirmations\.(clear_all_open|delete|group_delete|group_open|group_open_focus)(\.|[[:space:]]|$)' \ crates/nyaterm-desktop/src/features/shell/event_pump/publish.rs @@ -634,15 +640,19 @@ check_no_matches \ crates/nyaterm-desktop/src/features/root.rs check_no_matches \ - "connection import runtime must use ConnectionImportState methods" \ + "connection import child state must stay behind ConnectionFeatureState methods" \ + 'connection_state\.import\.' \ + crates/nyaterm-desktop/src/features +check_no_matches \ + "connection import runtime must use ConnectionFeatureState methods" \ 'connection_state\.import\.(import_dialog_open|import_path_prompt|import_focus)' \ crates/nyaterm-desktop/src/features/connections/connection_import_runtime.rs check_no_matches \ - "connection import overlay must use ConnectionImportState methods" \ + "connection import overlay must use ConnectionFeatureState methods" \ 'connection_state\.import\.(import_dialog_open|import_path_prompt|import_focus)' \ crates/nyaterm-desktop/src/features/panels/connection_import_overlay.rs check_no_matches \ - "root connection import overlay state must use ConnectionImportState methods" \ + "root connection import overlay state must use ConnectionFeatureState methods" \ 'connection_state\.import\.(import_dialog_open|import_path_prompt|import_focus)' \ crates/nyaterm-desktop/src/features/root.rs @@ -650,21 +660,25 @@ check_no_matches \ "connection group editor draft mutations must go through ConnectionGroupEditorFeatureState methods" \ 'connection_state\.group_editor\.draft\.as_mut\(' \ crates/nyaterm-desktop/src/features/connections +check_no_matches \ + "connection group editor child state must stay behind ConnectionFeatureState methods" \ + 'connection_state\.group_editor\.' \ + crates/nyaterm-desktop/src/features check_no_matches \ - "connection group runtime must use ConnectionGroupEditorFeatureState methods" \ + "connection group runtime must use ConnectionFeatureState methods" \ 'connection_state\.group_editor\.(draft|focus)(\.|[[:space:]]|$)' \ crates/nyaterm-desktop/src/features/connections/connection_runtime/groups.rs check_no_matches \ - "connection group editor panel must use ConnectionGroupEditorFeatureState methods" \ + "connection group editor panel must use ConnectionFeatureState methods" \ 'connection_state\.group_editor\.(draft|focus)(\.|[[:space:]]|$)' \ crates/nyaterm-desktop/src/features/pages/connections/editor/group_delete.rs check_no_matches \ - "connections page group editor state must use ConnectionGroupEditorFeatureState methods" \ + "connections page group editor state must use ConnectionFeatureState methods" \ 'connection_state\.group_editor\.(draft|focus)(\.|[[:space:]]|$)' \ crates/nyaterm-desktop/src/features/pages/connections/view/page.rs check_no_matches \ - "event pump group editor state must use ConnectionGroupEditorFeatureState methods" \ + "event pump group editor state must use ConnectionFeatureState methods" \ 'connection_state\.group_editor\.(draft|focus)(\.|[[:space:]]|$)' \ crates/nyaterm-desktop/src/features/shell/event_pump/publish.rs @@ -708,19 +722,23 @@ check_no_matches \ crates/nyaterm-desktop/src/features/shell/panel_resize_runtime.rs check_no_matches \ - "network editor drafts must be mutated through NetworkFeatureState methods" \ + "network child state must stay behind ConnectionFeatureState methods" \ + 'connection_state\.network\.' \ + crates/nyaterm-desktop/src/features +check_no_matches \ + "network editor drafts must be mutated through ConnectionFeatureState methods" \ 'connection_state\.network\.(group_editor|tunnel_editor|proxy_editor)\.as_mut\(' \ crates/nyaterm-desktop/src/features/tunnels check_no_matches \ - "network page state reads must use NetworkFeatureState methods" \ + "network page state reads must use ConnectionFeatureState methods" \ 'connection_state\.network\.(tab|delete_confirm|group_editor|group_delete_confirm|item_menu|move_picker|expanded_sections|tunnel_editor|proxy_editor|group_editor_focus|tunnel_editor_focus|proxy_editor_focus)(\.|[[:space:]]|==|,|\)|$)' \ crates/nyaterm-desktop/src/features/pages/tunnels check_no_matches \ - "network runtime state reads must use NetworkFeatureState methods" \ + "network runtime state reads must use ConnectionFeatureState methods" \ 'connection_state\.network\.(tab|delete_confirm|group_editor|group_delete_confirm|item_menu|move_picker|expanded_sections|tunnel_editor|proxy_editor|group_editor_focus|tunnel_editor_focus|proxy_editor_focus)(\.|[[:space:]]|==|,|\)|$)' \ crates/nyaterm-desktop/src/features/tunnels check_no_matches \ - "panel stack network projection must use NetworkFeatureState methods" \ + "panel stack network projection must use ConnectionFeatureState methods" \ 'connection_state\.network\.(tab|delete_confirm|group_editor|group_delete_confirm|item_menu|move_picker|expanded_sections|tunnel_editor|proxy_editor|group_editor_focus|tunnel_editor_focus|proxy_editor_focus)(\.|[[:space:]]|==|,|\)|$)' \ crates/nyaterm-desktop/src/features/shell/panel_stack_runtime.rs