diff --git a/web/src/app/home/add-extension/page.tsx b/web/src/app/home/add-extension/page.tsx index 9804018c..cf20bc6f 100644 --- a/web/src/app/home/add-extension/page.tsx +++ b/web/src/app/home/add-extension/page.tsx @@ -23,6 +23,7 @@ import { FileArchive, Loader2, CircleHelp, + Package, } from 'lucide-react'; import { Input } from '@/components/ui/input'; import { @@ -33,6 +34,8 @@ import { import React, { useState, useCallback, useEffect, useRef } from 'react'; import { useNavigate, useSearchParams } from 'react-router-dom'; import { httpClient, systemInfo } from '@/app/infra/http/HttpClient'; +import { getCloudServiceClientSync } from '@/app/infra/http'; +import { extractI18nObject } from '@/i18n/I18nProvider'; import { toast } from 'sonner'; import { useTranslation } from 'react-i18next'; import { PluginV4 } from '@/app/infra/entities/plugin'; @@ -159,6 +162,19 @@ function AddExtensionContent() { : type === 'skill' ? t('market.typeSkill') : t('market.typePlugin'); + + // Marketplace icon URL for the extension being installed, by type. + const buildInstallIconURL = () => { + const cloud = getCloudServiceClientSync(); + const a = installInfo.plugin_author || ''; + const n = installInfo.plugin_name || ''; + if (installExtensionType === 'mcp') + return cloud.getMCPMarketplaceIconURL(a, n); + if (installExtensionType === 'skill') + return cloud.getSkillMarketplaceIconURL(a, n); + return cloud.getPluginIconURL(a, n); + }; + const installIconURL = buildInstallIconURL(); const { addTask, setSelectedTaskId, @@ -174,6 +190,7 @@ function AddExtensionContent() { const [pluginInstallStatus, setPluginInstallStatus] = useState(PluginInstallStatus.ASK_CONFIRM); const [installError, setInstallError] = useState(null); + const [installIconFailed, setInstallIconFailed] = useState(false); const [popoverOpen, setPopoverOpen] = useState(false); const [popoverView, setPopoverView] = useState('menu'); const [isDragOver, setIsDragOver] = useState(false); @@ -253,10 +270,12 @@ function AddExtensionContent() { plugin_author: author, plugin_name: name, plugin_version: version, + plugin_label: name, }); setInstallExtensionType(extType); setPluginInstallStatus(PluginInstallStatus.ASK_CONFIRM); setInstallError(null); + setInstallIconFailed(false); setModalOpen(true); setSearchParams( @@ -305,10 +324,13 @@ function AddExtensionContent() { plugin_author: plugin.author, plugin_name: plugin.name, plugin_version: plugin.latest_version, + plugin_label: extractI18nObject(plugin.label) || plugin.name, + plugin_description: extractI18nObject(plugin.description) || '', }); setInstallExtensionType(plugin.type || 'plugin'); setPluginInstallStatus(PluginInstallStatus.ASK_CONFIRM); setInstallError(null); + setInstallIconFailed(false); setModalOpen(true); }, []); @@ -1221,36 +1243,38 @@ function AddExtensionContent() {

{t('addExtension.installConfirm', { type: extensionTypeLabel(installExtensionType), - name: installInfo.plugin_name, + name: installInfo.plugin_label || installInfo.plugin_name, })}

-
-
- - {t('addExtension.installInfoType')} - - - {extensionTypeLabel(installExtensionType)} - -
-
- - {t('addExtension.installInfoId')} - - - {installInfo.plugin_author}/{installInfo.plugin_name} - -
- {installInfo.plugin_version && ( -
- - {t('addExtension.installInfoVersion')} - - - v{installInfo.plugin_version} - +
+ {installIconFailed ? ( +
+
+ ) : ( + {installInfo.plugin_name} setInstallIconFailed(true)} + /> )} +
+
+ {installInfo.plugin_label || installInfo.plugin_name} +
+
+ {installInfo.plugin_author}/{installInfo.plugin_name} + {installInfo.plugin_version + ? ` ยท v${installInfo.plugin_version}` + : ''} +
+ {installInfo.plugin_description && ( +
+ {installInfo.plugin_description} +
+ )} +
)}