Remove cloud deletion of owned plugins from the plugin dialog (#14946)

Owned ("Mine") cloud plugins now offer the same local-only Delete as local
plugins: it removes the installed package and leaves the plugin in the cloud,
still reinstallable. Deleting a plugin from the cloud belongs on the plugin hub
and is no longer reachable from OrcaSlicer, so the whole cloud-delete chain is
removed down to the REST binding.

The deleted row is restored locally instead of via a blocking cloud refetch, so
it survives being offline, and it comes back without the deleted package's error
state.
This commit is contained in:
SoftFever
2026-07-25 22:31:40 +08:00
committed by GitHub
parent 9a72dda79a
commit a62fb17e03
8 changed files with 20 additions and 161 deletions

View File

@@ -138,6 +138,9 @@ PluginDescriptor as_cloud_only_descriptor(PluginDescriptor descriptor)
descriptor.plugin_root.clear();
descriptor.entry_path.clear();
descriptor.installed_version.clear();
// No local package is left behind, so the package verdict and any load error it produced go with it.
descriptor.metadata_valid = false;
descriptor.clear_error();
if (descriptor.cloud.has_value()) {
descriptor.cloud->installed = false;
descriptor.cloud->update_available = false;
@@ -289,11 +292,10 @@ PluginAvailableActions evaluate_action_policy(const PluginDialogItem& item)
available_actions.context_actions.push_back(PluginContextAction{id, label, enabled, danger});
};
if (is_cloud) {
if (is_mine)
add_action("delete_mine_plugin", "Delete", true, true);
else
add_action("unsubscribe_plugin", "Unsubscribe", true, true);
// Owned cloud plugins fall through to the local delete: it removes the installed package only.
// Deleting a plugin from the cloud is a plugin hub operation and is never offered here.
if (is_cloud && !is_mine) {
add_action("unsubscribe_plugin", "Unsubscribe", true, true);
} else if (has_local) {
add_action("delete_plugin", "Delete", true, true);
}
@@ -742,8 +744,6 @@ void PluginsDialog::handle_plugin_menu_action(const std::string& plugin_key, con
delete_local_plugin(row_data);
} else if (action == "unsubscribe_plugin") {
unsubscribe_cloud_plugin(row_data);
} else if (action == "delete_mine_plugin") {
delete_mine_local_and_cloud_plugin(plugin_key);
} else if (action == "reload_plugin") {
reload_local_plugin(plugin_key, /*clear_cache=*/false);
} else if (action == "clear_cache_reload_plugin") {
@@ -1071,19 +1071,25 @@ void PluginsDialog::open_plugin_hub()
void PluginsDialog::delete_local_plugin(const PluginDescriptor& plugin)
{
const wxString plugin_name = from_u8(plugin.name);
const int rc = wxMessageBox(wxString::Format(_L("Delete plugin \"%s\"?\n\nThis permanently removes the plugin folder."), plugin_name),
kDeletePluginTitle, wxYES_NO | wxNO_DEFAULT | wxICON_WARNING, this);
const int rc = wxMessageBox(
wxString::Format(plugin.is_cloud_plugin() ?
_L("Delete plugin \"%s\"?\n\nThis removes the local plugin files. The plugin stays in the cloud "
"and can be reinstalled.") :
_L("Delete plugin \"%s\"?\n\nThis permanently removes the plugin folder."),
plugin_name),
kDeletePluginTitle, wxYES_NO | wxNO_DEFAULT | wxICON_WARNING, this);
restore_z_order();
if (rc != wxYES)
return;
auto state = std::make_shared<PluginOperationState>();
run_with_dialog(
[plugin_key = plugin.plugin_key, should_refresh = plugin.is_cloud_plugin(), state]() {
[plugin_key = plugin.plugin_key, cloud_row = as_cloud_only_descriptor(plugin), state]() {
std::string error;
const bool succeeded = PluginManager::instance().delete_plugin(plugin_key, error);
if (succeeded && should_refresh)
refresh_plugin_metadata_blocking(kFetchCloudMeta);
// Keep the cloud row listed so the plugin stays reinstallable without waiting on a cloud fetch.
if (succeeded && cloud_row.is_cloud_plugin())
PluginManager::instance().update_cloud_metadata(std::vector<PluginDescriptor>{cloud_row});
store_plugin_operation_result(state, succeeded, std::move(error));
},
[this, state, plugin_name]() {
@@ -1249,28 +1255,4 @@ void PluginsDialog::reinstall_cloud_plugin(const PluginDescriptor& plugin)
show_status(wxString::Format(_L("Reloaded \"%s\"."), plugin_display_name(plugin_key)), "success");
}
void PluginsDialog::delete_mine_local_and_cloud_plugin(const std::string& plugin_key)
{
PluginDescriptor descriptor;
const std::string display = get_descriptor(plugin_key, descriptor) ? descriptor.name : std::string{};
const wxString plugin_name = from_u8(display.empty() ? plugin_key : display);
const int rc = wxMessageBox(
wxString::Format(_L("Delete plugin \"%s\" from local and cloud?\n\nThis permanently removes the local plugin files and "
"deletes the plugin from the cloud. This action cannot be undone."),
plugin_name),
kDeletePluginTitle, wxYES_NO | wxNO_DEFAULT | wxICON_WARNING, this);
restore_z_order();
if (rc != wxYES)
return;
std::string error;
if (!PluginManager::instance().delete_mine_local_and_cloud_plugin(plugin_key, error)) {
show_status(error.empty() ? _L("Failed to delete plugin from local and cloud.") : from_u8(error), "error");
return;
}
send_plugins();
show_status(wxString::Format(_L("Deleted \"%s\"."), plugin_name), "success");
}
}} // namespace Slic3r::GUI