From 9465fcda6e852264c8922f98bd1ad25508ea50d6 Mon Sep 17 00:00:00 2001 From: Chuck <33324927+ChuckBuilds@users.noreply.github.com> Date: Tue, 24 Feb 2026 17:35:08 -0500 Subject: [PATCH] fix(store): fix installed status detection for plugins with path-derived IDs (#270) The plugin registry uses short IDs (e.g. "weather", "stocks") but plugin_path points to the actual installed directory name (e.g. "plugins/ledmatrix-weather"). isStorePluginInstalled() was only comparing registry IDs, causing all monorepo plugins with mismatched IDs to show as not installed in the store UI. - Updated isStorePluginInstalled() to also check the last segment of plugin_path against installed plugin IDs - Updated all 3 call sites to pass the full plugin object instead of just plugin.id - Fixed the same bug in renderCustomRegistryPlugins() which used the same direct ID comparison Co-authored-by: Chuck Co-authored-by: Claude Sonnet 4.6 --- web_interface/static/v3/plugins_manager.js | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/web_interface/static/v3/plugins_manager.js b/web_interface/static/v3/plugins_manager.js index 01bc1df9..b6111066 100644 --- a/web_interface/static/v3/plugins_manager.js +++ b/web_interface/static/v3/plugins_manager.js @@ -5251,8 +5251,17 @@ function showStoreLoading(show) { // ── Plugin Store: Client-Side Filter/Sort/Pagination ──────────────────────── -function isStorePluginInstalled(pluginId) { - return (window.installedPlugins || installedPlugins || []).some(p => p.id === pluginId); +function isStorePluginInstalled(pluginIdOrPlugin) { + const installed = window.installedPlugins || installedPlugins || []; + // Accept either a plain ID string or a store plugin object (which may have plugin_path) + if (typeof pluginIdOrPlugin === 'string') { + return installed.some(p => p.id === pluginIdOrPlugin); + } + const storeId = pluginIdOrPlugin.id; + // Derive the actual installed directory name from plugin_path (e.g. "plugins/ledmatrix-weather" → "ledmatrix-weather") + const pluginPath = pluginIdOrPlugin.plugin_path || ''; + const pathDerivedId = pluginPath ? pluginPath.split('/').pop() : null; + return installed.some(p => p.id === storeId || (pathDerivedId && p.id === pathDerivedId)); } function applyStoreFiltersAndSort(skipPageReset) { @@ -5282,9 +5291,9 @@ function applyStoreFiltersAndSort(skipPageReset) { // Installed filter if (st.filterInstalled === true) { - list = list.filter(plugin => isStorePluginInstalled(plugin.id)); + list = list.filter(plugin => isStorePluginInstalled(plugin)); } else if (st.filterInstalled === false) { - list = list.filter(plugin => !isStorePluginInstalled(plugin.id)); + list = list.filter(plugin => !isStorePluginInstalled(plugin)); } // Sort @@ -5531,7 +5540,7 @@ function renderPluginStore(plugins) { }; container.innerHTML = plugins.map(plugin => { - const installed = isStorePluginInstalled(plugin.id); + const installed = isStorePluginInstalled(plugin); return `
@@ -6093,7 +6102,7 @@ function renderCustomRegistryPlugins(plugins, registryUrl) { }; container.innerHTML = plugins.map(plugin => { - const isInstalled = installedPlugins.some(p => p.id === plugin.id); + const isInstalled = isStorePluginInstalled(plugin); const pluginIdJs = escapeJs(plugin.id); const escapedUrlJs = escapeJs(registryUrl); const pluginPathJs = escapeJs(plugin.plugin_path || '');