Add support for runtime error status in plugins

Distinguish a loaded plugin whose
capability errored (RuntimeError,
warn-styled, stays checked) from a
load-time Error. Status now derives
via resolve_plugin_status(); enum
ordinal keeps dialog sort priority.
Unloading clears stale errors.
This commit is contained in:
Andrew
2026-07-16 16:04:26 +08:00
committed by Ian Chua
parent 6d25e1777e
commit bde94ab37f
4 changed files with 34 additions and 8 deletions

View File

@@ -1347,6 +1347,8 @@ function StatusDescription(plugin) {
return "This plugin is still loading."; return "This plugin is still loading.";
case "Error": case "Error":
return "This plugin is blocked until its error is fixed."; return "This plugin is blocked until its error is fixed.";
case "RuntimeError":
return "This plugin is loaded but a capability reported an error.";
case "Inactive": case "Inactive":
default: default:
return "This plugin is inactive. Activate it to install or load it."; return "This plugin is inactive. Activate it to install or load it.";

View File

@@ -424,6 +424,11 @@ body.pane-resizing {
font-weight: 600; font-weight: 600;
} }
.status-cell.status-runtimeerror {
color: var(--plugin-status-warn);
font-weight: 600;
}
.status-cell.status-loading { .status-cell.status-loading {
color: var(--plugin-status-warn); color: var(--plugin-status-warn);
font-weight: 600; font-weight: 600;
@@ -680,6 +685,11 @@ body.pane-resizing {
color: var(--plugin-status-danger); color: var(--plugin-status-danger);
} }
.detail-status-chip.status-runtimeerror {
background: var(--plugin-status-warn-bg);
color: var(--plugin-status-warn);
}
.detail-status-chip.status-loading { .detail-status-chip.status-loading {
background: var(--plugin-status-warn-bg); background: var(--plugin-status-warn-bg);
color: var(--plugin-status-warn); color: var(--plugin-status-warn);

View File

@@ -11,6 +11,7 @@ namespace Slic3r
// IMPORTANT: ordinal order is the Plugins dialog Status sort priority. // IMPORTANT: ordinal order is the Plugins dialog Status sort priority.
Activated, Activated,
Error, Error,
RuntimeError,
Inactive, Inactive,
Loading Loading
}; };
@@ -21,11 +22,28 @@ namespace Slic3r
{ {
case PluginStatus::Activated: return "Activated"; case PluginStatus::Activated: return "Activated";
case PluginStatus::Error: return "Error"; case PluginStatus::Error: return "Error";
case PluginStatus::RuntimeError: return "RuntimeError";
case PluginStatus::Inactive: return "Inactive"; case PluginStatus::Inactive: return "Inactive";
case PluginStatus::Loading: return "Loading"; case PluginStatus::Loading: return "Loading";
} }
return "Inactive"; return "Inactive";
} }
// why: a plugin whose module is live but whose catalog carries an error is a
// RUNTIME fault (e.g. a capability rejected at register time) - it stays
// loaded/checked and is only flagged, distinct from a load-time Error where
// the module never came up. Loading wins over both so an in-flight reload
// never flashes an error.
inline PluginStatus resolve_plugin_status(bool loading, bool has_error, bool is_loaded)
{
if (loading)
return PluginStatus::Loading;
if (has_error)
return is_loaded ? PluginStatus::RuntimeError : PluginStatus::Error;
if (is_loaded)
return PluginStatus::Activated;
return PluginStatus::Inactive;
}
} }
} // namespace Slic3r::GUI } // namespace Slic3r::GUI

View File

@@ -380,14 +380,7 @@ PluginDialogItem build_plugin_dialog_item(const PluginDescriptor& descriptor)
item.sharing_token = descriptor.sharing_token; item.sharing_token = descriptor.sharing_token;
item.thumbnail_url = descriptor.thumbnail_url; item.thumbnail_url = descriptor.thumbnail_url;
if (item.loading) item.status = resolve_plugin_status(item.loading, item.has_error, item.is_loaded);
item.status = PluginStatus::Loading;
else if (item.has_error)
item.status = PluginStatus::Error;
else if (item.is_loaded)
item.status = PluginStatus::Activated;
else
item.status = PluginStatus::Inactive;
item.available_actions = evaluate_action_policy(item); item.available_actions = evaluate_action_policy(item);
const bool has_enabled_script = std::any_of(item.capabilities.begin(), item.capabilities.end(), const bool has_enabled_script = std::any_of(item.capabilities.begin(), item.capabilities.end(),
@@ -663,6 +656,9 @@ void PluginsDialog::toggle_plugin(const std::string& plugin_key, bool enabled)
} }
BOOST_LOG_TRIVIAL(info) << "Plugin unloaded from Plugins dialog: " << plugin_key; BOOST_LOG_TRIVIAL(info) << "Plugin unloaded from Plugins dialog: " << plugin_key;
// A user-disabled plugin has no meaningful error state.
if (!manager.clear_plugin_error(plugin_key))
BOOST_LOG_TRIVIAL(warning) << "Failed to clear plugin error for " << plugin_key << " (failed to find)";
// A prior activation of this plugin is moot now; drop it so no stale "Activated" arrives later. // A prior activation of this plugin is moot now; drop it so no stale "Activated" arrives later.
if (m_activating_plugin_key == plugin_key) if (m_activating_plugin_key == plugin_key)
m_activating_plugin_key.clear(); m_activating_plugin_key.clear();