Marketplace: edit only the marketplace fields of a project (PR review #2)
ProjectsStore gains update_marketplace_fields / update_all_marketplace_fields, which read-modify-write installs and opt-outs under the store's own lock. Install, uninstall, update, forget and set_global_item_disabled use them instead of writing back a whole Project read earlier, so a concurrent start's status/container_id change is no longer overwritten. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -761,16 +761,12 @@ pub async fn forget_marketplace_installs(
|
||||
.global_marketplace_installs
|
||||
.retain(|i| i.marketplace_id != marketplace_id);
|
||||
state.settings_store.update(settings)?;
|
||||
for mut p in state.projects_store.list() {
|
||||
let before = (p.marketplace_installs.len(), p.marketplace_disabled.len());
|
||||
p.marketplace_installs
|
||||
.retain(|i| i.marketplace_id != marketplace_id);
|
||||
p.marketplace_disabled
|
||||
.retain(|r| r.marketplace_id != marketplace_id);
|
||||
if (p.marketplace_installs.len(), p.marketplace_disabled.len()) != before {
|
||||
state.projects_store.update(p)?;
|
||||
}
|
||||
}
|
||||
state
|
||||
.projects_store
|
||||
.update_all_marketplace_fields(|installs, disabled| {
|
||||
installs.retain(|i| i.marketplace_id != marketplace_id);
|
||||
disabled.retain(|r| r.marketplace_id != marketplace_id);
|
||||
})?;
|
||||
refresh_pins(&state).await;
|
||||
Ok(())
|
||||
}
|
||||
@@ -807,9 +803,12 @@ pub async fn install_marketplace_item(
|
||||
state.settings_store.update(s)?;
|
||||
}
|
||||
InstallScope::Project { project_id } => {
|
||||
let mut p = find_project(&state, &project_id)?;
|
||||
ops::upsert_install(&mut p.marketplace_installs, inst);
|
||||
state.projects_store.update(p)?;
|
||||
state
|
||||
.projects_store
|
||||
.update_marketplace_fields(&project_id, |installs, _| {
|
||||
ops::upsert_install(installs, inst);
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
}
|
||||
refresh_pins(&state).await;
|
||||
@@ -830,19 +829,23 @@ pub async fn uninstall_marketplace_item(
|
||||
}
|
||||
state.settings_store.update(s)?;
|
||||
// An opt-out of an item that is no longer global means nothing.
|
||||
for mut p in state.projects_store.list() {
|
||||
if p.marketplace_disabled.contains(&item) {
|
||||
ops::set_disabled(&mut p.marketplace_disabled, &item, false);
|
||||
state.projects_store.update(p)?;
|
||||
}
|
||||
}
|
||||
state
|
||||
.projects_store
|
||||
.update_all_marketplace_fields(|_, disabled| {
|
||||
ops::set_disabled(disabled, &item, false)
|
||||
})?;
|
||||
}
|
||||
InstallScope::Project { project_id } => {
|
||||
let mut p = find_project(&state, &project_id)?;
|
||||
if !ops::remove_install(&mut p.marketplace_installs, &item) {
|
||||
return Err(format!("That item is not installed in \"{}\".", p.name));
|
||||
}
|
||||
state.projects_store.update(p)?;
|
||||
let name = find_project(&state, &project_id)?.name;
|
||||
state
|
||||
.projects_store
|
||||
.update_marketplace_fields(&project_id, |installs, _| {
|
||||
if ops::remove_install(installs, &item) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!("That item is not installed in \"{name}\"."))
|
||||
}
|
||||
})?;
|
||||
}
|
||||
}
|
||||
refresh_pins(&state).await;
|
||||
@@ -857,9 +860,13 @@ pub async fn set_global_item_disabled(
|
||||
state: State<'_, AppState>,
|
||||
) -> Result<Project, String> {
|
||||
validate_item(&item)?;
|
||||
let mut p = find_project(&state, &project_id)?;
|
||||
ops::set_disabled(&mut p.marketplace_disabled, &item, disabled);
|
||||
state.projects_store.update(p)
|
||||
let ((), saved) = state
|
||||
.projects_store
|
||||
.update_marketplace_fields(&project_id, |_, list| {
|
||||
ops::set_disabled(list, &item, disabled);
|
||||
Ok(())
|
||||
})?;
|
||||
Ok(saved)
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
@@ -924,11 +931,16 @@ pub async fn update_marketplace_item(
|
||||
state.settings_store.update(s)?;
|
||||
}
|
||||
InstallScope::Project { project_id } => {
|
||||
let mut p = find_project(&state, &project_id)?;
|
||||
if !ops::repin(&mut p.marketplace_installs, &item, &head) {
|
||||
return Err(format!("That item is not installed in \"{}\".", p.name));
|
||||
}
|
||||
state.projects_store.update(p)?;
|
||||
let name = find_project(&state, &project_id)?.name;
|
||||
state
|
||||
.projects_store
|
||||
.update_marketplace_fields(&project_id, |installs, _| {
|
||||
if ops::repin(installs, &item, &head) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!("That item is not installed in \"{name}\"."))
|
||||
}
|
||||
})?;
|
||||
}
|
||||
}
|
||||
refresh_pins(&state).await;
|
||||
|
||||
Reference in New Issue
Block a user