fix(web): widget cache-busting, dead frontend code, and dependency pins (#656)

- Plugin-supplied widgets load as /static/plugin-widgets/...js?v=<plugin
  version>, so an update isn't hidden behind the year-long immutable cache.
- Fire-and-forget loadInstalledPlugins() calls catch the rejection it has
  already reported, so the global handler no longer adds a second toast.
- Timezone picker renders again when the General partial is re-injected.
- Remove dead code: executePluginAction's six plugin-id fallbacks and
  [DEBUG] logging, window.currentPluginConfig and every read of it, the
  file-upload JSON delete branch, unused PluginAPI / PluginInstallManager /
  PluginStateManager helpers, loadPluginWidgetsFromManifest, the stale
  install_manager.js and LEDVisibility fallbacks, error_handler.js's global
  escapeHtml, 13 unused CSS rules, and stale comments/no-op returns.
- pytz < 2027, psutil < 7 in requirements-test.txt, pytest-cov < 8.
- Pin anthropics/claude-code-action to the commit v1 resolves to.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Chuck
2026-09-28 10:40:52 -04:00
committed by GitHub
co-authored by Claude Opus 5.5
parent 65d82580bc
commit 0e9e2cabba
24 changed files with 109 additions and 579 deletions
@@ -9,12 +9,7 @@ const PluginStateManager = {
* Installed plugins state.
*/
installedPlugins: [],
/**
* Current plugin configuration state.
*/
currentConfig: null,
/**
* Load installed plugins.
*
@@ -32,83 +27,6 @@ const PluginStateManager = {
}
throw error;
}
},
/**
* Get plugin by ID.
*
* @param {string} pluginId - Plugin identifier
* @returns {Object|null} Plugin object or null
*/
getPlugin(pluginId) {
return this.installedPlugins.find(p => p.id === pluginId) || null;
},
/**
* Update plugin state.
*
* @param {string} pluginId - Plugin identifier
* @param {Object} updates - State updates
*/
updatePlugin(pluginId, updates) {
const plugin = this.getPlugin(pluginId);
if (plugin) {
Object.assign(plugin, updates);
}
},
/**
* Set plugin enabled state.
*
* @param {string} pluginId - Plugin identifier
* @param {boolean} enabled - Whether plugin is enabled
*/
setPluginEnabled(pluginId, enabled) {
this.updatePlugin(pluginId, { enabled });
},
/**
* Get current plugin configuration.
*
* @param {string} pluginId - Plugin identifier
* @returns {Promise<Object>} Plugin configuration
*/
async getPluginConfig(pluginId) {
try {
const config = await window.PluginAPI.getPluginConfig(pluginId);
this.currentConfig = { pluginId, config };
return config;
} catch (error) {
if (window.errorHandler) {
window.errorHandler.displayError(error, `Failed to load config for ${pluginId}`);
}
throw error;
}
},
/**
* Save plugin configuration.
*
* @param {string} pluginId - Plugin identifier
* @param {Object} config - Configuration data
* @returns {Promise<Object>} Save result
*/
async savePluginConfig(pluginId, config) {
try {
const result = await window.PluginAPI.savePluginConfig(pluginId, config);
// Update local state
if (this.currentConfig && this.currentConfig.pluginId === pluginId) {
this.currentConfig.config = config;
}
return result;
} catch (error) {
if (window.errorHandler) {
window.errorHandler.displayError(error, `Failed to save config for ${pluginId}`);
}
throw error;
}
}
};