( host: SlashCommandHost, options?: ShowPluginsPickerOptions, )
| 152 | } |
| 153 | |
| 154 | async function showPluginsPicker( |
| 155 | host: SlashCommandHost, |
| 156 | options?: ShowPluginsPickerOptions, |
| 157 | ): Promise<void> { |
| 158 | let plugins: readonly PluginSummary[]; |
| 159 | try { |
| 160 | plugins = await host.requireSession().listPlugins(); |
| 161 | } catch (error) { |
| 162 | host.showError(`Failed to load plugins: ${formatErrorMessage(error)}`); |
| 163 | return; |
| 164 | } |
| 165 | |
| 166 | const panel = new PluginsPanelComponent({ |
| 167 | installed: plugins, |
| 168 | installedIds: new Set(plugins.map((plugin) => plugin.id)), |
| 169 | initialTab: options?.initialTab, |
| 170 | selectedId: options?.selectedId, |
| 171 | pluginHint: options?.pluginHint, |
| 172 | onSelect: (selection) => { |
| 173 | // Each branch of the handler either mounts the next view or restores the |
| 174 | // editor itself, so do not pre-restore here — that would flash the editor |
| 175 | // for in-place actions like toggling a plugin. |
| 176 | void handlePluginsPanelSelection(host, panel, selection).catch((error: unknown) => { |
| 177 | host.showError(`/plugins failed: ${formatErrorMessage(error)}`); |
| 178 | }); |
| 179 | }, |
| 180 | onCancel: () => { |
| 181 | host.restoreEditor(); |
| 182 | }, |
| 183 | // Every tab except Custom needs the catalog: Official/Third-party list it, |
| 184 | // and Installed uses it to show update badges. The Installed/Custom tabs |
| 185 | // keep working even when the marketplace is unreachable (badges simply stay |
| 186 | // hidden until data arrives). |
| 187 | onRequestMarketplace: () => { |
| 188 | void loadMarketplaceCatalog(host, panel, options?.marketplaceSource); |
| 189 | }, |
| 190 | }); |
| 191 | host.mountEditorReplacement(panel); |
| 192 | // Kick off the catalog fetch for any tab that needs it: Installed uses it for |
| 193 | // update badges, Official/Third-party list it. Custom never reads the catalog, |
| 194 | // so skip the fetch there. Done here (after `panel` is initialized) rather |
| 195 | // than inside the component constructor, because the callback above closes |
| 196 | // over `panel`. |
| 197 | if (options?.initialTab !== 'custom') { |
| 198 | panel.setMarketplaceLoading(); |
| 199 | void loadMarketplaceCatalog(host, panel, options?.marketplaceSource); |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | async function loadMarketplaceCatalog( |
| 204 | host: SlashCommandHost, |
no test coverage detected