diff --git a/crates/nyaterm-desktop/src/features/ai/ai_agent_runtime.rs b/crates/nyaterm-desktop/src/features/ai/ai_agent_runtime.rs index 3d0bee628..1f633b424 100644 --- a/crates/nyaterm-desktop/src/features/ai/ai_agent_runtime.rs +++ b/crates/nyaterm-desktop/src/features/ai/ai_agent_runtime.rs @@ -180,8 +180,9 @@ impl NyaTermApp { cx.spawn(async move |this, cx| { if let Err(error) = task.await { let _ = this.update(cx, |this, cx| { - this.settings.store_status.message = format!("AI audit save failed: {error}"); - this.settings.store_status.ready = false; + this.settings + .set_store_message(format!("AI audit save failed: {error}")); + this.settings.set_store_ready(false); cx.notify(); }); } else { diff --git a/crates/nyaterm-desktop/src/features/ai/ai_runtime/chat/discovery.rs b/crates/nyaterm-desktop/src/features/ai/ai_runtime/chat/discovery.rs index 1996c3d7e..4ed4219e4 100644 --- a/crates/nyaterm-desktop/src/features/ai/ai_runtime/chat/discovery.rs +++ b/crates/nyaterm-desktop/src/features/ai/ai_runtime/chat/discovery.rs @@ -85,14 +85,16 @@ impl NyaTermApp { Ok(discoveries) => { let count = self.apply_ai_model_discoveries(&event.profile_id, discoveries); self.ai.panel.status = format!("Discovered {count} AI model(s)"); - self.settings.store_status.message = self.ai.panel.status.clone(); - self.settings.store_status.ready = true; + self.settings + .set_store_message(self.ai.panel.status.clone()); + self.settings.set_store_ready(true); self.persist_ai_settings_now(cx); } Err(error) => { self.ai.panel.status = format!("AI model discovery failed: {error}"); - self.settings.store_status.message = self.ai.panel.status.clone(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.ai.panel.status.clone()); + self.settings.set_store_ready(false); } } } diff --git a/crates/nyaterm-desktop/src/features/ai/ai_runtime/chat/jobs.rs b/crates/nyaterm-desktop/src/features/ai/ai_runtime/chat/jobs.rs index 51bcc982b..10446e931 100644 --- a/crates/nyaterm-desktop/src/features/ai/ai_runtime/chat/jobs.rs +++ b/crates/nyaterm-desktop/src/features/ai/ai_runtime/chat/jobs.rs @@ -75,7 +75,8 @@ impl NyaTermApp { "AI Agent request was cancelled", ); } - self.settings.store_status.message = self.ai.panel.status.clone(); + self.settings + .set_store_message(self.ai.panel.status.clone()); cx.notify(); } @@ -790,9 +791,9 @@ impl NyaTermApp { } else { "AI stream receiving".to_string() }; - self.settings.store_status.message = - format!("AI session {session_id} streaming"); - self.settings.store_status.ready = true; + self.settings + .set_store_message(format!("AI session {session_id} streaming")); + self.settings.set_store_ready(true); } AiChatWorkerEvent::AgentToolCallDelta { job_id, @@ -832,9 +833,10 @@ impl NyaTermApp { format!("Streaming arguments (+{arguments_delta_len} chars)") }, ); - self.settings.store_status.message = - format!("AI session {session_id} streaming Agent tool call"); - self.settings.store_status.ready = true; + self.settings.set_store_message(format!( + "AI session {session_id} streaming Agent tool call" + )); + self.settings.set_store_ready(true); } AiChatWorkerEvent::AgentBackgroundFinished { job_id, @@ -879,8 +881,9 @@ impl NyaTermApp { "Failed", truncate_preview(&error, 140), ); - self.settings.store_status.message = self.ai.panel.status.clone(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.ai.panel.status.clone()); + self.settings.set_store_ready(false); } } } @@ -958,9 +961,11 @@ impl NyaTermApp { message.command_cards = output.command_cards.clone(); } } - self.settings.store_status.message = - format!("AI session {} updated", event.session_id); - self.settings.store_status.ready = true; + self.settings.set_store_message(format!( + "AI session {} updated", + event.session_id + )); + self.settings.set_store_ready(true); self.reset_text_input("ai.chat.prompt", "", cx); self.ai.chat.prompt_draft.clear(); self.refresh_ai_usage_counts(cx); @@ -1007,8 +1012,9 @@ impl NyaTermApp { truncate_preview(&error, 140), ); } - self.settings.store_status.message = self.ai.panel.status.clone(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.ai.panel.status.clone()); + self.settings.set_store_ready(false); } } } diff --git a/crates/nyaterm-desktop/src/features/ai/ai_runtime/chat/settings_actions.rs b/crates/nyaterm-desktop/src/features/ai/ai_runtime/chat/settings_actions.rs index 444eb8d5d..92a91785e 100644 --- a/crates/nyaterm-desktop/src/features/ai/ai_runtime/chat/settings_actions.rs +++ b/crates/nyaterm-desktop/src/features/ai/ai_runtime/chat/settings_actions.rs @@ -125,13 +125,15 @@ impl NyaTermApp { if self.ai.panel.status.trim().is_empty() { self.ai.panel.status = "AI settings saved".to_string(); } - self.settings.store_status.message = self.ai.panel.status.clone(); - self.settings.store_status.ready = true; + self.settings + .set_store_message(self.ai.panel.status.clone()); + self.settings.set_store_ready(true); } Err(error) => { self.ai.panel.status = format!("AI settings save failed: {error}"); - self.settings.store_status.message = self.ai.panel.status.clone(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.ai.panel.status.clone()); + self.settings.set_store_ready(false); } } cx.notify(); diff --git a/crates/nyaterm-desktop/src/features/app_state/construct.rs b/crates/nyaterm-desktop/src/features/app_state/construct.rs index f33e08338..d1eeeecb7 100644 --- a/crates/nyaterm-desktop/src/features/app_state/construct.rs +++ b/crates/nyaterm-desktop/src/features/app_state/construct.rs @@ -14,7 +14,7 @@ use nyaterm_transport::{SessionManager, SftpDuplicatePolicy}; use std::collections::HashMap; use std::sync::Arc; -use super::super::settings::{SettingsFeatureFocus, SettingsFeatureState, StoreStatus}; +use super::super::settings::{SettingsFeatureFocus, SettingsFeatureState}; use super::super::{ AiFeatureFocus, AiFeatureState, CloudSyncFeatureState, CommandFeatureInit, CommandFeatureState, ConnectionCatalogState, ConnectionFeatureFocus, ConnectionFeatureState, @@ -111,11 +111,7 @@ impl NyaTermApp { command_history, keyword_highlights, settings, - StoreStatus { - path, - message: "redb connection store online".to_string(), - ready: true, - }, + (path, "redb connection store online".to_string(), true), cloud_sync_settings, cloud_sync_state, translation_settings, @@ -141,11 +137,7 @@ impl NyaTermApp { Vec::new(), KeywordHighlightConfig::default(), AppSettingsSummary::default(), - StoreStatus { - path, - message: format!("failed to load sessions: {error}"), - ready: false, - }, + (path, format!("failed to load sessions: {error}"), false), CloudSyncSettings::default(), CloudSyncState::default(), TranslationSettings::default(), @@ -172,15 +164,15 @@ impl NyaTermApp { Vec::new(), KeywordHighlightConfig::default(), AppSettingsSummary::default(), - StoreStatus { - path: runtime + ( + runtime .config_dir() .join("nyaterm.redb") .display() .to_string(), - message: format!("failed to open store: {error}"), - ready: false, - }, + format!("failed to open store: {error}"), + false, + ), CloudSyncSettings::default(), CloudSyncState::default(), TranslationSettings::default(), @@ -431,7 +423,9 @@ impl NyaTermApp { settings: SettingsFeatureState::new( settings, keyword_highlights, - store_status, + store_status.0, + store_status.1, + store_status.2, appearance_ui_font_options, appearance_terminal_font_options, SettingsFeatureFocus { diff --git a/crates/nyaterm-desktop/src/features/commands/command_runtime/history.rs b/crates/nyaterm-desktop/src/features/commands/command_runtime/history.rs index c2672dc7d..b2c51183c 100644 --- a/crates/nyaterm-desktop/src/features/commands/command_runtime/history.rs +++ b/crates/nyaterm-desktop/src/features/commands/command_runtime/history.rs @@ -267,17 +267,17 @@ impl NyaTermApp { } } if !self.commands.queue_command_history(submitted) { - self.settings.store_status.message = - "command history worker is unavailable".to_string(); - self.settings.store_status.ready = false; + self.settings + .set_store_message("command history worker is unavailable".to_string()); + self.settings.set_store_ready(false); } } pub(in crate::features) fn queue_quick_command_use_count(&mut self, command_id: String) { if !self.commands.queue_quick_command_use_count(command_id) { - self.settings.store_status.message = - "command persistence worker is unavailable".to_string(); - self.settings.store_status.ready = false; + self.settings + .set_store_message("command persistence worker is unavailable".to_string()); + self.settings.set_store_ready(false); } } @@ -289,9 +289,10 @@ impl NyaTermApp { CommandPersistencePoll::Empty => break, CommandPersistencePoll::Disconnected { had_pending } => { if had_pending { - self.settings.store_status.message = - "command persistence worker disconnected".to_string(); - self.settings.store_status.ready = false; + self.settings.set_store_message( + "command persistence worker disconnected".to_string(), + ); + self.settings.set_store_ready(false); dirty = true; } break; @@ -299,8 +300,8 @@ impl NyaTermApp { }; dirty = true; if let Err(message) = self.commands.apply_persistence_result(event) { - self.settings.store_status.message = message; - self.settings.store_status.ready = false; + self.settings.set_store_message(message); + self.settings.set_store_ready(false); } } dirty diff --git a/crates/nyaterm-desktop/src/features/commands/quick_command_runtime/catalog.rs b/crates/nyaterm-desktop/src/features/commands/quick_command_runtime/catalog.rs index 9b1edf461..0057864cb 100644 --- a/crates/nyaterm-desktop/src/features/commands/quick_command_runtime/catalog.rs +++ b/crates/nyaterm-desktop/src/features/commands/quick_command_runtime/catalog.rs @@ -23,9 +23,9 @@ impl NyaTermApp { .replace_quick_command_catalog(config.commands, config.categories); } Err(error) => { - self.settings.store_status.message = - format!("quick command refresh failed: {error}"); - self.settings.store_status.ready = false; + self.settings + .set_store_message(format!("quick command refresh failed: {error}")); + self.settings.set_store_ready(false); } } } @@ -61,15 +61,16 @@ impl NyaTermApp { { Ok(settings) => { self.apply_gpui_settings(settings); - self.settings.store_status.message = "quick command UI settings saved".to_string(); - self.settings.store_status.ready = true; + self.settings + .set_store_message("quick command UI settings saved".to_string()); + self.settings.set_store_ready(true); self.terminal.view.status = "quick command UI settings saved".to_string(); } Err(error) => { - self.settings.store_status.message = - format!("quick command UI settings save failed: {error}"); - self.settings.store_status.ready = false; - self.terminal.view.status = self.settings.store_status.message.clone(); + self.settings + .set_store_message(format!("quick command UI settings save failed: {error}")); + self.settings.set_store_ready(false); + self.terminal.view.status = self.settings.store_status().message.to_string(); } } cx.notify(); diff --git a/crates/nyaterm-desktop/src/features/commands/quick_command_runtime/dialogs.rs b/crates/nyaterm-desktop/src/features/commands/quick_command_runtime/dialogs.rs index db31bc4cc..f60998a0a 100644 --- a/crates/nyaterm-desktop/src/features/commands/quick_command_runtime/dialogs.rs +++ b/crates/nyaterm-desktop/src/features/commands/quick_command_runtime/dialogs.rs @@ -153,19 +153,19 @@ impl NyaTermApp { self.commands .replace_quick_command_catalog(config.commands, config.categories); self.commands.clear_quick_delete(); - self.settings.store_status.message = if deleted { + self.settings.set_store_message(if deleted { format!("quick command '{}' deleted", delete.label) } else { format!("quick command '{}' was already deleted", delete.label) - }; - self.settings.store_status.ready = deleted; - self.terminal.view.status = self.settings.store_status.message.clone(); + }); + self.settings.set_store_ready(deleted); + self.terminal.view.status = self.settings.store_status().message.to_string(); } Err(error) => { - self.settings.store_status.message = - format!("quick command delete failed: {error}"); - self.settings.store_status.ready = false; - self.terminal.view.status = self.settings.store_status.message.clone(); + self.settings + .set_store_message(format!("quick command delete failed: {error}")); + self.settings.set_store_ready(false); + self.terminal.view.status = self.settings.store_status().message.to_string(); } } cx.notify(); @@ -242,7 +242,7 @@ impl NyaTermApp { self.commands .replace_quick_command_catalog(config.commands, config.categories); self.commands.finish_quick_category_delete(&delete.id); - self.settings.store_status.message = if deleted_category { + self.settings.set_store_message(if deleted_category { format!( "quick command category '{}' deleted with {} command(s)", delete.name, deleted_commands @@ -252,15 +252,15 @@ impl NyaTermApp { "quick command category '{}' was already deleted", delete.name ) - }; - self.settings.store_status.ready = deleted_category; - self.terminal.view.status = self.settings.store_status.message.clone(); + }); + self.settings.set_store_ready(deleted_category); + self.terminal.view.status = self.settings.store_status().message.to_string(); } Err(error) => { - self.settings.store_status.message = - format!("quick command category delete failed: {error}"); - self.settings.store_status.ready = false; - self.terminal.view.status = self.settings.store_status.message.clone(); + self.settings + .set_store_message(format!("quick command category delete failed: {error}")); + self.settings.set_store_ready(false); + self.terminal.view.status = self.settings.store_status().message.to_string(); } } cx.notify(); @@ -362,28 +362,29 @@ impl NyaTermApp { .replace_quick_command_catalog(config.commands, config.categories); if renamed { self.commands.clear_quick_category_rename(); - self.settings.store_status.message = format!( + self.settings.set_store_message(format!( "quick command category '{}' renamed to '{}'", rename.original_name, name - ); - self.settings.store_status.ready = true; + )); + self.settings.set_store_ready(true); } else { self.commands.set_quick_category_rename_error( "Category is no longer available".to_string(), ); - self.settings.store_status.message = - "quick command category rename failed: category missing".to_string(); - self.settings.store_status.ready = false; + self.settings.set_store_message( + "quick command category rename failed: category missing".to_string(), + ); + self.settings.set_store_ready(false); } - self.terminal.view.status = self.settings.store_status.message.clone(); + self.terminal.view.status = self.settings.store_status().message.to_string(); } Err(error) => { self.commands .set_quick_category_rename_error(error.to_string()); - self.settings.store_status.message = - format!("quick command category rename failed: {error}"); - self.settings.store_status.ready = false; - self.terminal.view.status = self.settings.store_status.message.clone(); + self.settings + .set_store_message(format!("quick command category rename failed: {error}")); + self.settings.set_store_ready(false); + self.terminal.view.status = self.settings.store_status().message.to_string(); } } cx.notify(); diff --git a/crates/nyaterm-desktop/src/features/commands/quick_command_runtime/editor.rs b/crates/nyaterm-desktop/src/features/commands/quick_command_runtime/editor.rs index 52c164dde..31ad3c8f2 100644 --- a/crates/nyaterm-desktop/src/features/commands/quick_command_runtime/editor.rs +++ b/crates/nyaterm-desktop/src/features/commands/quick_command_runtime/editor.rs @@ -180,17 +180,18 @@ impl NyaTermApp { self.commands .replace_quick_command_catalog(config.commands, config.categories); self.commands.close_quick_editor(); - self.settings.store_status.message = - format!("quick command '{}' saved", command.label); - self.settings.store_status.ready = true; - self.terminal.view.status = self.settings.store_status.message.clone(); + self.settings + .set_store_message(format!("quick command '{}' saved", command.label)); + self.settings.set_store_ready(true); + self.terminal.view.status = self.settings.store_status().message.to_string(); } Err(error) => { self.commands .set_quick_editor_error(error.to_string(), None); - self.settings.store_status.message = format!("quick command save failed: {error}"); - self.settings.store_status.ready = false; - self.terminal.view.status = self.settings.store_status.message.clone(); + self.settings + .set_store_message(format!("quick command save failed: {error}")); + self.settings.set_store_ready(false); + self.terminal.view.status = self.settings.store_status().message.to_string(); } } cx.notify(); diff --git a/crates/nyaterm-desktop/src/features/commands/quick_command_runtime/import/dialog.rs b/crates/nyaterm-desktop/src/features/commands/quick_command_runtime/import/dialog.rs index 95efccca5..f3556d7ad 100644 --- a/crates/nyaterm-desktop/src/features/commands/quick_command_runtime/import/dialog.rs +++ b/crates/nyaterm-desktop/src/features/commands/quick_command_runtime/import/dialog.rs @@ -112,16 +112,18 @@ impl NyaTermApp { self.terminal.view.status = format!( "imported {imported_commands} quick command(s), updated {updated_commands}, categories +{imported_categories}, total {total_commands}/{total_categories}" ); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = true; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(true); } QuickCommandImportPathPromptResult::Cancelled => { self.terminal.view.status = "quick command import cancelled".to_string(); } QuickCommandImportPathPromptResult::Failed(error) => { self.terminal.view.status = format!("quick command import failed: {error}"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(false); } QuickCommandImportPathPromptResult::Closed => { self.terminal.view.status = diff --git a/crates/nyaterm-desktop/src/features/commands/quick_command_runtime/run.rs b/crates/nyaterm-desktop/src/features/commands/quick_command_runtime/run.rs index 583de32f8..e61c2b70a 100644 --- a/crates/nyaterm-desktop/src/features/commands/quick_command_runtime/run.rs +++ b/crates/nyaterm-desktop/src/features/commands/quick_command_runtime/run.rs @@ -126,14 +126,16 @@ impl NyaTermApp { "Saved AI command card '{}' to Quick Commands", label )); - self.settings.store_status.message = self.ai.panel_status().to_string(); - self.settings.store_status.ready = true; + self.settings + .set_store_message(self.ai.panel_status().to_string()); + self.settings.set_store_ready(true); } Err(error) => { self.ai .set_panel_status(format!("Quick command save failed: {error}")); - self.settings.store_status.message = self.ai.panel_status().to_string(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.ai.panel_status().to_string()); + self.settings.set_store_ready(false); } } cx.notify(); 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 0d901eb86..636238c97 100644 --- a/crates/nyaterm-desktop/src/features/connections/connection_import_runtime.rs +++ b/crates/nyaterm-desktop/src/features/connections/connection_import_runtime.rs @@ -147,8 +147,8 @@ impl NyaTermApp { .tr("savedConnections.importSuccess") .replace("{{count}}", &count.to_string()); self.terminal.view.status = message.clone(); - self.settings.store_status.message = message; - self.settings.store_status.ready = true; + self.settings.set_store_message(message); + self.settings.set_store_ready(true); } ConnectionImportResult::Cancelled => { self.terminal.view.status = "connection import cancelled".to_string(); @@ -158,8 +158,8 @@ impl NyaTermApp { .tr("savedConnections.importFailed") .replace("{{error}}", &error); self.terminal.view.status = message.clone(); - self.settings.store_status.message = message; - self.settings.store_status.ready = false; + self.settings.set_store_message(message); + self.settings.set_store_ready(false); } ConnectionImportResult::Closed => { self.terminal.view.status = "connection import picker closed".to_string(); 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 590775fab..94259b529 100644 --- a/crates/nyaterm-desktop/src/features/connections/connection_runtime/actions.rs +++ b/crates/nyaterm-desktop/src/features/connections/connection_runtime/actions.rs @@ -38,8 +38,9 @@ impl NyaTermApp { Err(error) => { self.connection_state.close_clear_all(); self.terminal.view.status = format!("clear saved connections failed: {error}"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(false); } } cx.notify(); diff --git a/crates/nyaterm-desktop/src/features/connections/connections/dnd.rs b/crates/nyaterm-desktop/src/features/connections/connections/dnd.rs index f1dd408f4..64bfe2fa7 100644 --- a/crates/nyaterm-desktop/src/features/connections/connections/dnd.rs +++ b/crates/nyaterm-desktop/src/features/connections/connections/dnd.rs @@ -67,8 +67,9 @@ impl NyaTermApp { } Err(error) => { self.terminal.view.status = format!("reorder connection failed: {error}"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(false); } } self.connection_state.clear_list_drop_target(); @@ -139,8 +140,9 @@ impl NyaTermApp { } Err(error) => { self.terminal.view.status = format!("reorder connection failed: {error}"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(false); } } self.connection_state.clear_list_drop_target(); @@ -190,8 +192,9 @@ impl NyaTermApp { } Err(error) => { self.terminal.view.status = format!("move connection failed: {error}"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(false); } } cx.notify(); @@ -238,8 +241,9 @@ impl NyaTermApp { } Err(error) => { self.terminal.view.status = format!("move connections failed: {error}"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(false); } } 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 31c753a63..63d908f1a 100644 --- a/crates/nyaterm-desktop/src/features/connections/connections/menus.rs +++ b/crates/nyaterm-desktop/src/features/connections/connections/menus.rs @@ -70,8 +70,9 @@ impl NyaTermApp { } Err(error) => { self.terminal.view.status = format!("copy connection failed: {error}"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(false); } } cx.notify(); diff --git a/crates/nyaterm-desktop/src/features/connections/connections/selection.rs b/crates/nyaterm-desktop/src/features/connections/connections/selection.rs index 00f6b2cad..a25a8583c 100644 --- a/crates/nyaterm-desktop/src/features/connections/connections/selection.rs +++ b/crates/nyaterm-desktop/src/features/connections/connections/selection.rs @@ -54,8 +54,9 @@ impl NyaTermApp { } Err(error) => { self.terminal.view.status = format!("copy selected connections failed: {error}"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(false); } } cx.notify(); @@ -94,8 +95,9 @@ impl NyaTermApp { .map_err(|error| error.to_string())? .connections, ); - self.settings.store_status.message = "saved connections copied".to_string(); - self.settings.store_status.ready = true; + self.settings + .set_store_message("saved connections copied".to_string()); + self.settings.set_store_ready(true); Ok(connections.len()) } } diff --git a/crates/nyaterm-desktop/src/features/layout/sidebar/sessions.rs b/crates/nyaterm-desktop/src/features/layout/sidebar/sessions.rs index bf6ffd25c..ef597e846 100644 --- a/crates/nyaterm-desktop/src/features/layout/sidebar/sessions.rs +++ b/crates/nyaterm-desktop/src/features/layout/sidebar/sessions.rs @@ -358,7 +358,7 @@ impl NyaTermApp { div() .rounded_md() .border_1() - .border_color(if self.settings.store_status.ready { + .border_color(if self.settings.store_status().ready { rgb(palette.hover) } else { rgb(palette.hover) @@ -375,19 +375,19 @@ impl NyaTermApp { div() .mt_1() .text_sm() - .text_color(if self.settings.store_status.ready { + .text_color(if self.settings.store_status().ready { rgb(palette.success) } else { rgb(palette.danger) }) - .child(self.settings.store_status.message.clone()), + .child(self.settings.store_status().message.to_string()), ) .child( div() .mt_2() .text_xs() .text_color(rgb(palette.text_muted)) - .child(self.settings.store_status.path.clone()), + .child(self.settings.store_status().path.to_string()), ), ) } diff --git a/crates/nyaterm-desktop/src/features/pages/transfers/browser_navigation.rs b/crates/nyaterm-desktop/src/features/pages/transfers/browser_navigation.rs index 5c533ed5c..923a6d5a1 100644 --- a/crates/nyaterm-desktop/src/features/pages/transfers/browser_navigation.rs +++ b/crates/nyaterm-desktop/src/features/pages/transfers/browser_navigation.rs @@ -331,15 +331,16 @@ impl NyaTermApp { { Ok(settings) => { self.apply_gpui_settings(settings); - self.settings.store_status.message = "file explorer favorites saved".to_string(); - self.settings.store_status.ready = true; + self.settings + .set_store_message("file explorer favorites saved".to_string()); + self.settings.set_store_ready(true); } Err(error) => { - self.settings.store_status.message = - format!("file explorer favorites save failed: {error}"); - self.settings.store_status.ready = false; + self.settings + .set_store_message(format!("file explorer favorites save failed: {error}")); + self.settings.set_store_ready(false); self.transfer - .set_browser_status(self.settings.store_status.message.clone()); + .set_browser_status(self.settings.store_status().message.to_string()); } } } diff --git a/crates/nyaterm-desktop/src/features/settings/catalog.rs b/crates/nyaterm-desktop/src/features/settings/catalog.rs index 9846f2383..296061759 100644 --- a/crates/nyaterm-desktop/src/features/settings/catalog.rs +++ b/crates/nyaterm-desktop/src/features/settings/catalog.rs @@ -37,10 +37,10 @@ impl SettingsMasterPasswordState { } #[derive(Debug, Clone)] -pub(in crate::features) struct StoreStatus { - pub path: String, - pub message: String, - pub ready: bool, +pub(super) struct StoreStatus { + pub(super) path: String, + pub(super) message: String, + pub(super) ready: bool, } #[cfg(test)] diff --git a/crates/nyaterm-desktop/src/features/settings/config_runtime.rs b/crates/nyaterm-desktop/src/features/settings/config_runtime.rs index 6b829c95d..9b22365e7 100644 --- a/crates/nyaterm-desktop/src/features/settings/config_runtime.rs +++ b/crates/nyaterm-desktop/src/features/settings/config_runtime.rs @@ -10,8 +10,6 @@ use crate::models::{ TranslationSecretDraft, }; -use super::StoreStatus; - impl NyaTermApp { pub(in crate::features) fn prompt_config_export(&mut self, cx: &mut Context) { if !self @@ -592,11 +590,11 @@ impl NyaTermApp { .set_duplicate_policy(SftpDuplicatePolicy::from_legacy_value( &self.settings.summary.transfer_duplicate_strategy, )); - self.settings.store_status = StoreStatus { + self.settings.replace_store_status( path, - message: "redb connection store online".to_string(), - ready: true, - }; + "redb connection store online".to_string(), + true, + ); } Err(error) => { self.connection_catalog.clear_loaded(); @@ -609,11 +607,11 @@ impl NyaTermApp { TranslationSettings::default(), TranslationSecretDraft::default(), ); - self.settings.store_status = StoreStatus { + self.settings.replace_store_status( path, - message: format!("failed to load sessions: {error}"), - ready: false, - }; + format!("failed to load sessions: {error}"), + false, + ); } } } @@ -626,16 +624,15 @@ impl NyaTermApp { TranslationSettings::default(), TranslationSecretDraft::default(), ); - self.settings.store_status = StoreStatus { - path: self - .runtime + self.settings.replace_store_status( + self.runtime .config_dir() .join("nyaterm.redb") .display() .to_string(), - message: format!("failed to open store: {error}"), - ready: false, - }; + format!("failed to open store: {error}"), + false, + ); } } } diff --git a/crates/nyaterm-desktop/src/features/settings/mod.rs b/crates/nyaterm-desktop/src/features/settings/mod.rs index 9aa5a8c8d..0999a2011 100644 --- a/crates/nyaterm-desktop/src/features/settings/mod.rs +++ b/crates/nyaterm-desktop/src/features/settings/mod.rs @@ -8,7 +8,6 @@ mod security_state; mod settings_runtime; mod state; -pub(in crate::features) use catalog::StoreStatus; pub(in crate::features) use security_state::{ SecurityCatalogState, SecurityFeatureFocus, SecurityFeatureState, }; diff --git a/crates/nyaterm-desktop/src/features/settings/state.rs b/crates/nyaterm-desktop/src/features/settings/state.rs index 70acbd129..9d6f483e7 100644 --- a/crates/nyaterm-desktop/src/features/settings/state.rs +++ b/crates/nyaterm-desktop/src/features/settings/state.rs @@ -17,7 +17,7 @@ pub(in crate::features) struct SettingsFeatureState { pub summary: AppSettingsSummary, pub keyword_config: KeywordHighlightConfig, pub master_password: SettingsMasterPasswordState, - pub store_status: StoreStatus, + pub(super) store_status: StoreStatus, search_engines: SearchEngineSettingsState, keyword_highlights: KeywordHighlightSettingsState, appearance: AppearanceSettingsState, @@ -39,6 +39,12 @@ pub(in crate::features) struct SettingsFeatureFocus { pub keybindings: FocusHandle, } +pub(in crate::features) struct StoreStatusView<'a> { + pub path: &'a str, + pub message: &'a str, + pub ready: bool, +} + struct SearchEngineSettingsState { expanded_index: Option, icon_picker_index: Option, @@ -97,7 +103,9 @@ impl SettingsFeatureState { pub(in crate::features) fn new( summary: AppSettingsSummary, keyword_config: KeywordHighlightConfig, - store_status: StoreStatus, + store_path: String, + store_message: String, + store_ready: bool, ui_font_options: Vec, terminal_font_options: Vec, focus: SettingsFeatureFocus, @@ -107,7 +115,11 @@ impl SettingsFeatureState { summary, keyword_config, master_password, - store_status, + store_status: StoreStatus { + path: store_path, + message: store_message, + ready: store_ready, + }, search_engines: SearchEngineSettingsState { expanded_index: None, icon_picker_index: None, @@ -139,6 +151,35 @@ impl SettingsFeatureState { self.master_password.reset(self.summary.has_master_password); } + pub(in crate::features) fn store_status(&self) -> StoreStatusView<'_> { + StoreStatusView { + path: &self.store_status.path, + message: &self.store_status.message, + ready: self.store_status.ready, + } + } + + pub(in crate::features) fn set_store_message(&mut self, message: impl Into) { + self.store_status.message = message.into(); + } + + pub(in crate::features) fn set_store_ready(&mut self, ready: bool) { + self.store_status.ready = ready; + } + + pub(in crate::features) fn replace_store_status( + &mut self, + path: String, + message: String, + ready: bool, + ) { + self.store_status = StoreStatus { + path, + message, + ready, + }; + } + pub(in crate::features) fn search_engine_presentation(&self) -> SearchEnginePresentationState { SearchEnginePresentationState { expanded_index: self.search_engines.expanded_index, @@ -535,7 +576,6 @@ mod tests { }; use super::{SearchEngineMenu, SettingsFeatureFocus, SettingsFeatureState}; - use crate::features::settings::StoreStatus; use crate::models::{ ConfigPathPromptKind, KeywordHighlightEditorField, SnapshotPasswordPromptKind, }; @@ -546,11 +586,9 @@ mod tests { SettingsFeatureState::new( AppSettingsSummary::default(), KeywordHighlightConfig::default(), - StoreStatus { - path: String::new(), - message: String::new(), - ready: true, - }, + String::new(), + String::new(), + true, vec!["Inter".to_string()], vec!["JetBrains Mono".to_string()], SettingsFeatureFocus { @@ -657,4 +695,26 @@ mod tests { assert_eq!(interaction.pending_keys, None); assert!(interaction.search_draft.is_empty()); } + + #[test] + fn settings_owner_controls_store_status_updates_and_replacement() { + let mut state = settings_state(); + + state.set_store_message("saving settings"); + state.set_store_ready(false); + let status = state.store_status(); + assert_eq!(status.path, ""); + assert_eq!(status.message, "saving settings"); + assert!(!status.ready); + + state.replace_store_status( + "/tmp/nyaterm.redb".to_string(), + "store reopened".to_string(), + true, + ); + let status = state.store_status(); + assert_eq!(status.path, "/tmp/nyaterm.redb"); + assert_eq!(status.message, "store reopened"); + assert!(status.ready); + } } diff --git a/crates/nyaterm-desktop/src/features/shell/appearance.rs b/crates/nyaterm-desktop/src/features/shell/appearance.rs index e4cef1150..f989e765a 100644 --- a/crates/nyaterm-desktop/src/features/shell/appearance.rs +++ b/crates/nyaterm-desktop/src/features/shell/appearance.rs @@ -594,15 +594,16 @@ impl NyaTermApp { Ok(settings) => { self.apply_gpui_settings(settings); self.refresh_visible_terminal_surfaces(cx); - self.settings.store_status.message = "appearance settings saved".to_string(); - self.settings.store_status.ready = true; + self.settings + .set_store_message("appearance settings saved".to_string()); + self.settings.set_store_ready(true); self.terminal.view.status = "appearance settings saved".to_string(); } Err(error) => { - self.settings.store_status.message = - format!("appearance settings save failed: {error}"); - self.settings.store_status.ready = false; - self.terminal.view.status = self.settings.store_status.message.clone(); + self.settings + .set_store_message(format!("appearance settings save failed: {error}")); + self.settings.set_store_ready(false); + self.terminal.view.status = self.settings.store_status().message.to_string(); } } cx.notify(); diff --git a/crates/nyaterm-desktop/src/features/shell/keybinding_runtime/keybindings.rs b/crates/nyaterm-desktop/src/features/shell/keybinding_runtime/keybindings.rs index eac02c718..26f84464a 100644 --- a/crates/nyaterm-desktop/src/features/shell/keybinding_runtime/keybindings.rs +++ b/crates/nyaterm-desktop/src/features/shell/keybinding_runtime/keybindings.rs @@ -107,14 +107,15 @@ impl NyaTermApp { Ok(settings) => { self.apply_gpui_settings(settings); self.settings.finish_keybinding_recording(); - self.settings.store_status.message = success_message.clone(); - self.settings.store_status.ready = true; + self.settings.set_store_message(success_message.clone()); + self.settings.set_store_ready(true); self.terminal.view.status = success_message; } Err(error) => { - self.settings.store_status.message = format!("shortcut save failed: {error}"); - self.settings.store_status.ready = false; - self.terminal.view.status = self.settings.store_status.message.clone(); + self.settings + .set_store_message(format!("shortcut save failed: {error}")); + self.settings.set_store_ready(false); + self.terminal.view.status = self.settings.store_status().message.to_string(); } } cx.notify(); diff --git a/crates/nyaterm-desktop/src/features/shell/keybinding_runtime/keyword_highlights.rs b/crates/nyaterm-desktop/src/features/shell/keybinding_runtime/keyword_highlights.rs index 584f3b063..1ef4639a4 100644 --- a/crates/nyaterm-desktop/src/features/shell/keybinding_runtime/keyword_highlights.rs +++ b/crates/nyaterm-desktop/src/features/shell/keybinding_runtime/keyword_highlights.rs @@ -38,15 +38,16 @@ impl NyaTermApp { { Ok(config) => { self.settings.keyword_config = config; - self.settings.store_status.message = "keyword highlight settings saved".to_string(); - self.settings.store_status.ready = true; + self.settings + .set_store_message("keyword highlight settings saved".to_string()); + self.settings.set_store_ready(true); self.terminal.view.status = "keyword highlight settings saved".to_string(); } Err(error) => { - self.settings.store_status.message = - format!("keyword highlight settings save failed: {error}"); - self.settings.store_status.ready = false; - self.terminal.view.status = self.settings.store_status.message.clone(); + self.settings + .set_store_message(format!("keyword highlight settings save failed: {error}")); + self.settings.set_store_ready(false); + self.terminal.view.status = self.settings.store_status().message.to_string(); } } cx.notify(); @@ -130,16 +131,18 @@ impl NyaTermApp { self.terminal.view.status = format!( "imported {imported_rules} keyword highlight rule(s), updated {updated_rules}, total {total_rules}" ); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = true; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(true); } KeywordHighlightPathPromptResult::Cancelled => { self.terminal.view.status = "keyword highlight import cancelled".to_string(); } KeywordHighlightPathPromptResult::Failed(error) => { self.terminal.view.status = format!("keyword highlight import failed: {error}"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(false); } KeywordHighlightPathPromptResult::Closed => { self.terminal.view.status = diff --git a/crates/nyaterm-desktop/src/features/shell/panel_resize_runtime.rs b/crates/nyaterm-desktop/src/features/shell/panel_resize_runtime.rs index 197f35b95..f651a3e54 100644 --- a/crates/nyaterm-desktop/src/features/shell/panel_resize_runtime.rs +++ b/crates/nyaterm-desktop/src/features/shell/panel_resize_runtime.rs @@ -162,13 +162,14 @@ impl NyaTermApp { match store.save_ui_layout_settings(&self.settings.summary) { Ok(summary) => { self.apply_gpui_settings(summary); - self.settings.store_status.ready = true; - self.settings.store_status.message = "panel layout saved".to_string(); + self.settings.set_store_ready(true); + self.settings + .set_store_message("panel layout saved".to_string()); } Err(error) => { - self.settings.store_status.ready = false; - self.settings.store_status.message = - format!("failed to save panel layout: {error}"); + self.settings.set_store_ready(false); + self.settings + .set_store_message(format!("failed to save panel layout: {error}")); } } } diff --git a/crates/nyaterm-desktop/src/features/translation/translation_runtime.rs b/crates/nyaterm-desktop/src/features/translation/translation_runtime.rs index dd3e5308c..ee19f3c34 100644 --- a/crates/nyaterm-desktop/src/features/translation/translation_runtime.rs +++ b/crates/nyaterm-desktop/src/features/translation/translation_runtime.rs @@ -44,13 +44,15 @@ impl NyaTermApp { { Ok(saved) => { self.translation.settings_saved(saved); - self.settings.store_status.message = "translation settings saved".to_string(); - self.settings.store_status.ready = true; + self.settings + .set_store_message("translation settings saved".to_string()); + self.settings.set_store_ready(true); } Err(error) => { self.translation.settings_save_failed(error); - self.settings.store_status.message = self.translation.status().to_string(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.translation.status().to_string()); + self.settings.set_store_ready(false); } } cx.notify(); 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 921cf2752..729af6ef5 100644 --- a/crates/nyaterm-desktop/src/features/tunnels/tunnel_runtime/actions.rs +++ b/crates/nyaterm-desktop/src/features/tunnels/tunnel_runtime/actions.rs @@ -69,13 +69,15 @@ impl NyaTermApp { self.tunnel_state.commit_tunnels(next_tunnels); self.connection_state.close_network_move_picker(); self.terminal.view.status = format!("tunnel moved to {label}"); - self.settings.store_status.message = "tunnel group saved".to_string(); - self.settings.store_status.ready = true; + self.settings + .set_store_message("tunnel group saved".to_string()); + self.settings.set_store_ready(true); } Err(error) => { self.terminal.view.status = format!("failed to move tunnel: {error}"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(false); } } cx.notify(); @@ -117,13 +119,15 @@ impl NyaTermApp { self.tunnel_state.commit_proxies(next_proxies); self.connection_state.close_network_move_picker(); self.terminal.view.status = format!("proxy moved to {label}"); - self.settings.store_status.message = "proxy group saved".to_string(); - self.settings.store_status.ready = true; + self.settings + .set_store_message("proxy group saved".to_string()); + self.settings.set_store_ready(true); } Err(error) => { self.terminal.view.status = format!("failed to move proxy: {error}"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(false); } } cx.notify(); @@ -192,13 +196,15 @@ impl NyaTermApp { } else { format!("tunnel '{label}' was already deleted") }; - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = deleted; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(deleted); } Err(error) => { self.terminal.view.status = format!("failed to delete tunnel: {error}"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(false); } } cx.notify(); @@ -226,13 +232,15 @@ impl NyaTermApp { } else { format!("proxy '{label}' was already deleted") }; - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = deleted; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(deleted); } Err(error) => { self.terminal.view.status = format!("failed to delete proxy: {error}"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(false); } } cx.notify(); 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 1e9e2e618..4b03df228 100644 --- a/crates/nyaterm-desktop/src/features/tunnels/tunnel_runtime/groups.rs +++ b/crates/nyaterm-desktop/src/features/tunnels/tunnel_runtime/groups.rs @@ -109,13 +109,15 @@ impl NyaTermApp { self.tunnel_state.commit_tunnel_groups(groups); self.connection_state.close_network_group_editor(); self.terminal.view.status = format!("tunnel group '{name}' saved"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = true; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(true); } Err(error) => { self.terminal.view.status = format!("failed to save tunnel group: {error}"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(false); } } cx.notify(); @@ -146,13 +148,15 @@ impl NyaTermApp { self.tunnel_state.commit_proxy_groups(groups); self.connection_state.close_network_group_editor(); self.terminal.view.status = format!("proxy group '{name}' saved"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = true; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(true); } Err(error) => { self.terminal.view.status = format!("failed to save proxy group: {error}"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(false); } } cx.notify(); @@ -220,13 +224,15 @@ impl NyaTermApp { &deleted_tunnel_ids, ); self.terminal.view.status = format!("tunnel group '{label}' deleted"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = true; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(true); } Err(error) => { self.terminal.view.status = format!("failed to delete tunnel group: {error}"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(false); } } cx.notify(); @@ -256,13 +262,15 @@ impl NyaTermApp { &deleted_proxy_ids, ); self.terminal.view.status = format!("proxy group '{label}' deleted"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = true; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(true); } Err(error) => { self.terminal.view.status = format!("failed to delete proxy group: {error}"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(false); } } cx.notify(); 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 ecbf88f43..aa4d04fed 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 @@ -199,13 +199,15 @@ impl NyaTermApp { self.tunnel_state.commit_proxies(next_proxies); self.connection_state.close_network_proxy_editor(); self.terminal.view.status = format!("proxy '{name}' saved"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = true; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(true); } Err(error) => { self.terminal.view.status = format!("failed to save proxy: {error}"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(false); self.connection_state .set_network_proxy_editor_error(self.terminal.view.status.clone()); } 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 f14f9db6d..afd8ef9ab 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 @@ -254,13 +254,15 @@ impl NyaTermApp { self.tunnel_state.commit_tunnels(next_tunnels); self.connection_state.close_network_tunnel_editor(); self.terminal.view.status = format!("tunnel '{name}' saved"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = true; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(true); } Err(error) => { self.terminal.view.status = format!("failed to save tunnel: {error}"); - self.settings.store_status.message = self.terminal.view.status.clone(); - self.settings.store_status.ready = false; + self.settings + .set_store_message(self.terminal.view.status.clone()); + self.settings.set_store_ready(false); self.connection_state .set_network_tunnel_editor_error(self.terminal.view.status.clone()); } diff --git a/docs/architecture/gpui-migration-status.md b/docs/architecture/gpui-migration-status.md index 2eebfcf65..6a2b40d16 100644 --- a/docs/architecture/gpui-migration-status.md +++ b/docs/architecture/gpui-migration-status.md @@ -232,7 +232,11 @@ these as staged extraction candidates, not as formatting-only refactor targets. reconciliation, keyword expansion/edit lifecycle, appearance-menu exclusion, keybinding recording/search transitions and kind-matched prompt completion execute on `SettingsFeatureState`; views receive immutable presentation data - and focus handles. Filesystem prompts, persistence and GPUI notification stay + and focus handles. A storage-status follow-up made the implementation type + and backing child settings-module-private. Cross-domain persistence adapters + now update its message/readiness through owner methods, rendering receives a + borrowed immutable view, and store reopen replaces path/message/readiness as + one transition. Filesystem prompts, persistence and GPUI notification stay in their existing adapters. - Translation and native-update background state now have authoritative `TranslationFeatureState` and `UpdateFeatureState` owners. Eighteen app fields @@ -1487,6 +1491,7 @@ Current ownership map: | Command history and persistence worker | Private state in `NyaTermApp.commands` | Persisted catalog plus background runtime | History snapshots, queue admission, event polling and idle checks enter through `CommandFeatureState`; failed optimistic use-count updates roll back on the owner. | | Send-command composer/options/progress | Private children in `NyaTermApp.send_command` | Transient editor and send lifecycle | Views receive immutable presentation data; control edits, mutually-exclusive menus, data/mode defaults, progress counters and cancellation enter through `SendCommandFeatureState`. Session selection, terminal writes, GPUI/text-input routing and status remain in adapters. | | Settings interaction and prompts | Private children in `NyaTermApp.settings` | Transient settings UI and prompt lifecycle | Search-engine rows, keyword-highlight editing, appearance menus, keybinding recording/search and config/diagnostics/import/password prompt admission enter through `SettingsFeatureState`; views use immutable presentation values and read-only focus/font access. Persistence, native filesystem prompts, text inputs and GPUI notification remain in adapters. | +| Global storage status | Settings-module-private child in `NyaTermApp.settings` | Runtime persistence health/presentation state | Cross-domain persistence adapters update message/readiness through `SettingsFeatureState`; rendering receives a borrowed immutable view, while store reopen replaces path/message/readiness together. Database work and compatibility handling remain in existing adapters and `nyaterm-core`. | | AI settings/chat/history/discovery/agent/panel | AI-module-private children in `NyaTermApp.ai` | Persisted settings plus transient UI and background lifecycle | Desktop consumers use read-only slices/queries and semantic transitions; settings draft groups, menu exclusion, confirmations, request/focus preparation, detected-error throttling, picker clamping and Agent capture/reset enter through `AiFeatureState`. Persistence, terminal-context collection, GPUI focus/rendering and notification remain in adapters. | | Shell viewport/navigation/panels/chrome/workspace | Shell-module-private children in `NyaTermApp.shell` | Transient GPUI composition and interaction state | Other desktop modules use read-only geometry/navigation/pane queries and semantic transitions; menu exclusion, settings-window lifecycle, mobile panels, failure chrome, submenu paths and pane ownership update through `ShellFeatureState`. Persistence, rendering, GPUI windows/notification and terminal coordination remain in adapters. | | Remote Docker/process/stats panes | Private children in `NyaTermApp.remote_ops` | Transient UI state plus typed background-event lifecycle | Views use immutable presentation values; menu exclusion, list-offset clamping, Docker details/Compose/confirmation cleanup, process PID-scoped cleanup, Stats expansion/data and job identity/failure timing enter through `RemoteOpsFeatureState`. SSH service launch, active-session policy, terminal status mirroring and GPUI notification remain in adapters. | @@ -1746,6 +1751,10 @@ honest remaining list. cross-domain consumers receive a borrowed immutable view, and navigation, session cache, history/favorites, search/sort, path editing, selection/rename, menu and resize transitions moved onto `TransferFeatureState`. + The settings storage-status batch then made the backing child and + implementation type settings-module-private, moved cross-domain status + writes behind owner transitions, and gave rendering a borrowed immutable + view without changing storage execution or compatibility formats. What remains at the composition root is stores, runtime and focused feature owners. Group by cohesion where a cluster exists; do not force the count down for diff --git a/scripts/check-architecture-boundaries.sh b/scripts/check-architecture-boundaries.sh index a0cd9a881..a5a06d185 100755 --- a/scripts/check-architecture-boundaries.sh +++ b/scripts/check-architecture-boundaries.sh @@ -251,6 +251,23 @@ check_no_multiline_matches \ "settings interaction child access must use SettingsFeatureState methods" \ '(self|this|app)\.settings[[:space:]]*\.(search_engines|keyword_highlights|appearance|keybindings|prompts)(\.|[[:space:]]*=)' \ crates/nyaterm-desktop/src/features +check_no_multiline_matches \ + "SettingsFeatureState store status must stay inside the settings module" \ + 'struct[[:space:]]+SettingsFeatureState[[:space:]]*\{[^}]*pub([[:space:]]|\(crate\)|\(in crate\)|\(in crate::features\))[[:space:]]+store_status[[:space:]]*:' \ + crates/nyaterm-desktop/src/features/settings/state.rs +check_no_matches \ + "StoreStatus implementation must stay inside the settings module" \ + 'pub([[:space:]]|\(crate\)|\(in crate\)|\(in crate::features\))[[:space:]]+struct[[:space:]]+StoreStatus' \ + crates/nyaterm-desktop/src/features/settings/catalog.rs +check_no_matches \ + "StoreStatus implementation must not be re-exported from settings" \ + 'pub([^;]*)use([^;]*)StoreStatus' \ + crates/nyaterm-desktop/src/features/settings/mod.rs +check_no_multiline_matches_excluding \ + "settings store status access must use SettingsFeatureState methods outside settings" \ + '(self|this|app)\.settings[[:space:]]*\.[[:space:]]*store_status[[:space:]]*(\.|=)' \ + crates/nyaterm-desktop/src/features \ + 'crates/nyaterm-desktop/src/features/settings/**' check_no_matches \ "translation state must stay grouped under TranslationFeatureState" \