()
| 859 | // Load installed plugins grouped by marketplace |
| 860 | useEffect(() => { |
| 861 | async function loadInstalledPlugins() { |
| 862 | setLoading(true); |
| 863 | try { |
| 864 | const { |
| 865 | enabled, |
| 866 | disabled |
| 867 | } = await loadAllPlugins(); |
| 868 | const mergedSettings = getSettings_DEPRECATED(); // Use merged settings to respect all layers |
| 869 | |
| 870 | const allPlugins = filterManagedDisabledPlugins([...enabled, ...disabled]); |
| 871 | |
| 872 | // Group plugins by marketplace |
| 873 | const pluginsByMarketplace: Record<string, LoadedPlugin[]> = {}; |
| 874 | for (const plugin of allPlugins) { |
| 875 | const marketplace = plugin.source.split('@')[1] || 'local'; |
| 876 | if (!pluginsByMarketplace[marketplace]) { |
| 877 | pluginsByMarketplace[marketplace] = []; |
| 878 | } |
| 879 | pluginsByMarketplace[marketplace]!.push(plugin); |
| 880 | } |
| 881 | |
| 882 | // Create marketplace info array with enabled/disabled counts |
| 883 | const marketplaceInfos: MarketplaceInfo[] = []; |
| 884 | for (const [name, plugins] of Object.entries(pluginsByMarketplace)) { |
| 885 | const enabledCount = count(plugins, p => { |
| 886 | const pluginId = `${p.name}@${name}`; |
| 887 | return mergedSettings?.enabledPlugins?.[pluginId] !== false; |
| 888 | }); |
| 889 | const disabledCount = plugins.length - enabledCount; |
| 890 | marketplaceInfos.push({ |
| 891 | name, |
| 892 | installedPlugins: plugins, |
| 893 | enabledCount, |
| 894 | disabledCount |
| 895 | }); |
| 896 | } |
| 897 | |
| 898 | // Sort marketplaces: claude-plugin-directory first, then alphabetically |
| 899 | marketplaceInfos.sort((a, b) => { |
| 900 | if (a.name === 'claude-plugin-directory') return -1; |
| 901 | if (b.name === 'claude-plugin-directory') return 1; |
| 902 | return a.name.localeCompare(b.name); |
| 903 | }); |
| 904 | setMarketplaces(marketplaceInfos); |
| 905 | |
| 906 | // Build flat list of all plugin states |
| 907 | const allStates: PluginState[] = []; |
| 908 | for (const marketplace of marketplaceInfos) { |
| 909 | for (const plugin of marketplace.installedPlugins) { |
| 910 | const pluginId = `${plugin.name}@${marketplace.name}`; |
| 911 | // Built-in plugins don't have V2 install entries — skip the lookup. |
| 912 | const scope = plugin.isBuiltin ? 'builtin' : getPluginInstallationFromV2(pluginId).scope; |
| 913 | allStates.push({ |
| 914 | plugin, |
| 915 | marketplace: marketplace.name, |
| 916 | scope, |
| 917 | pendingEnable: undefined, |
| 918 | pendingUpdate: false |
no test coverage detected