From 6a56d4972d09c4d866e146df1f6504cce95ae1b8 Mon Sep 17 00:00:00 2001 From: Dorian Date: Wed, 18 Mar 2026 11:46:38 +0000 Subject: [PATCH] fix: prevent install buttons showing before first container scan Added containers_scanned flag to StatusInfo in the data model. Starts false, set to true after the first Podman scan completes (~15s after boot). Marketplace now shows a shimmer "Checking..." indicator on app buttons until the scan finishes, preventing users from accidentally re-installing apps that are already present but not yet enumerated. Co-Authored-By: Claude Opus 4.6 (1M context) --- core/archipelago/src/data_model.rs | 5 +++++ core/archipelago/src/server.rs | 6 ++++-- neode-ui/src/types/api.ts | 1 + neode-ui/src/views/Marketplace.vue | 32 ++++++++++++++++++++++++++++++ 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/core/archipelago/src/data_model.rs b/core/archipelago/src/data_model.rs index 00ba40ed..e7e8534a 100644 --- a/core/archipelago/src/data_model.rs +++ b/core/archipelago/src/data_model.rs @@ -66,6 +66,10 @@ pub struct StatusInfo { pub backup_progress: Option, #[serde(rename = "update-progress")] pub update_progress: Option, + /// True after the first container scan completes. Frontend should + /// not show install buttons until this is true. + #[serde(rename = "containers-scanned", default)] + pub containers_scanned: bool, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] @@ -253,6 +257,7 @@ impl DataModel { updated: false, backup_progress: None, update_progress: None, + containers_scanned: false, }, lan_address: Some("http://localhost:8100".to_string()), tor_address: None, diff --git a/core/archipelago/src/server.rs b/core/archipelago/src/server.rs index cf49f3b5..51a0f015 100644 --- a/core/archipelago/src/server.rs +++ b/core/archipelago/src/server.rs @@ -417,16 +417,18 @@ async fn scan_and_update_packages( let packages_changed = !packages.is_empty() && current_data.package_data != packages; let tor_addr = docker_packages::read_tor_address("archipelago"); let tor_changed = tor_addr != current_data.server_info.tor_address; + let first_scan = !current_data.server_info.status_info.containers_scanned; - if packages_changed || tor_changed { + if packages_changed || tor_changed || first_scan { let mut data = current_data; if !packages.is_empty() { data.package_data = packages; } data.server_info.tor_address = tor_addr.clone(); data.server_info.node_address = tor_addr.as_ref().map(|t| identity.node_address(t)); + data.server_info.status_info.containers_scanned = true; state.update_data(data).await; - debug!("📦 State changed (packages={}, tor={}), broadcasting update", packages_changed, tor_changed); + debug!("📦 State changed (packages={}, tor={}, first_scan={}), broadcasting update", packages_changed, tor_changed, first_scan); } Ok(()) diff --git a/neode-ui/src/types/api.ts b/neode-ui/src/types/api.ts index 8e86250c..9161d44f 100644 --- a/neode-ui/src/types/api.ts +++ b/neode-ui/src/types/api.ts @@ -37,6 +37,7 @@ export interface StatusInfo { 'updated': boolean 'backup-progress': number | null 'update-progress': number | null + 'containers-scanned'?: boolean } export type UIMode = 'gamer' | 'easy' | 'chat' diff --git a/neode-ui/src/views/Marketplace.vue b/neode-ui/src/views/Marketplace.vue index 92b016b1..d849884b 100644 --- a/neode-ui/src/views/Marketplace.vue +++ b/neode-ui/src/views/Marketplace.vue @@ -202,6 +202,20 @@ > {{ t('common.launch') }} + + + + + + + + + Checking... + +