mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-09-03 08:07:14 +00:00
feat(web): type-aware install dialog + refresh sidebar after install
The marketplace install confirm dialog was hardcoded to "安装插件 / 确定要安装 插件 X 吗" for every type. Make it type-aware (plugin / MCP / skill) and show more info: type chip, author/name id, and version when present. Also refresh all sidebar extension lists (plugins, MCP servers, skills) when an install task completes, so the newly-installed extension appears immediately regardless of type (previously only refreshPlugins ran). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -151,6 +151,14 @@ function AddExtensionContent() {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
const { refreshPlugins, refreshMCPServers, refreshSkills } = useSidebarData();
|
const { refreshPlugins, refreshMCPServers, refreshSkills } = useSidebarData();
|
||||||
|
|
||||||
|
// Localized label for an extension type, used in the install dialog.
|
||||||
|
const extensionTypeLabel = (type: string) =>
|
||||||
|
type === 'mcp'
|
||||||
|
? t('market.typeMCP')
|
||||||
|
: type === 'skill'
|
||||||
|
? t('market.typeSkill')
|
||||||
|
: t('market.typePlugin');
|
||||||
const {
|
const {
|
||||||
addTask,
|
addTask,
|
||||||
setSelectedTaskId,
|
setSelectedTaskId,
|
||||||
@@ -271,15 +279,26 @@ function AddExtensionContent() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const onComplete = (_taskId: number, success: boolean) => {
|
const onComplete = (_taskId: number, success: boolean) => {
|
||||||
if (success) {
|
if (success) {
|
||||||
toast.success(t('plugins.installSuccess'));
|
toast.success(t('addExtension.installSuccess'));
|
||||||
|
// Refresh every sidebar extension list so the newly-installed
|
||||||
|
// plugin / MCP / skill shows up immediately, regardless of type.
|
||||||
refreshPlugins();
|
refreshPlugins();
|
||||||
|
refreshMCPServers();
|
||||||
|
refreshSkills();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
registerOnTaskComplete(onComplete);
|
registerOnTaskComplete(onComplete);
|
||||||
return () => {
|
return () => {
|
||||||
unregisterOnTaskComplete(onComplete);
|
unregisterOnTaskComplete(onComplete);
|
||||||
};
|
};
|
||||||
}, [registerOnTaskComplete, unregisterOnTaskComplete, refreshPlugins, t]);
|
}, [
|
||||||
|
registerOnTaskComplete,
|
||||||
|
unregisterOnTaskComplete,
|
||||||
|
refreshPlugins,
|
||||||
|
refreshMCPServers,
|
||||||
|
refreshSkills,
|
||||||
|
t,
|
||||||
|
]);
|
||||||
|
|
||||||
const handleInstallPlugin = useCallback(async (plugin: PluginV4) => {
|
const handleInstallPlugin = useCallback(async (plugin: PluginV4) => {
|
||||||
setInstallInfo({
|
setInstallInfo({
|
||||||
@@ -1189,22 +1208,50 @@ function AddExtensionContent() {
|
|||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle className="flex items-center gap-4">
|
<DialogTitle className="flex items-center gap-4">
|
||||||
<Download className="size-6" />
|
<Download className="size-6" />
|
||||||
<span>{t('plugins.installPlugin')}</span>
|
<span>
|
||||||
|
{t('addExtension.installTitle', {
|
||||||
|
type: extensionTypeLabel(installExtensionType),
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
{pluginInstallStatus === PluginInstallStatus.ASK_CONFIRM && (
|
{pluginInstallStatus === PluginInstallStatus.ASK_CONFIRM && (
|
||||||
<div className="mt-4">
|
<div className="mt-4 space-y-3">
|
||||||
<p className="mb-2">
|
<p>
|
||||||
{installInfo.plugin_version
|
{t('addExtension.installConfirm', {
|
||||||
? t('plugins.askConfirm', {
|
type: extensionTypeLabel(installExtensionType),
|
||||||
name: installInfo.plugin_name,
|
name: installInfo.plugin_name,
|
||||||
version: installInfo.plugin_version,
|
})}
|
||||||
})
|
|
||||||
: t('plugins.askConfirmNoVersion', {
|
|
||||||
name: installInfo.plugin_name,
|
|
||||||
})}
|
|
||||||
</p>
|
</p>
|
||||||
|
<div className="space-y-1.5 rounded-md bg-muted/40 p-3 text-sm">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span className="w-12 shrink-0 text-muted-foreground">
|
||||||
|
{t('addExtension.installInfoType')}
|
||||||
|
</span>
|
||||||
|
<span className="rounded bg-background px-1.5 py-0.5 text-xs font-medium">
|
||||||
|
{extensionTypeLabel(installExtensionType)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span className="w-12 shrink-0 text-muted-foreground">
|
||||||
|
{t('addExtension.installInfoId')}
|
||||||
|
</span>
|
||||||
|
<span className="break-all font-medium">
|
||||||
|
{installInfo.plugin_author}/{installInfo.plugin_name}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{installInfo.plugin_version && (
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span className="w-12 shrink-0 text-muted-foreground">
|
||||||
|
{t('addExtension.installInfoVersion')}
|
||||||
|
</span>
|
||||||
|
<span className="font-medium">
|
||||||
|
v{installInfo.plugin_version}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -1531,6 +1531,12 @@ const enUS = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
addExtension: {
|
addExtension: {
|
||||||
|
installTitle: 'Install {{type}}',
|
||||||
|
installConfirm: 'Install {{type}} "{{name}}"?',
|
||||||
|
installInfoType: 'Type',
|
||||||
|
installInfoId: 'ID',
|
||||||
|
installInfoVersion: 'Version',
|
||||||
|
installSuccess: 'Installed successfully',
|
||||||
manualAdd: 'Manual Add',
|
manualAdd: 'Manual Add',
|
||||||
uploadExtension: 'Drag & drop or click to upload',
|
uploadExtension: 'Drag & drop or click to upload',
|
||||||
uploadHint: 'Supports .zip (skills) and .lbpkg (plugins) files',
|
uploadHint: 'Supports .zip (skills) and .lbpkg (plugins) files',
|
||||||
|
|||||||
@@ -1467,6 +1467,12 @@ const zhHans = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
addExtension: {
|
addExtension: {
|
||||||
|
installTitle: '安装{{type}}',
|
||||||
|
installConfirm: '确定要安装{{type}} "{{name}}" 吗?',
|
||||||
|
installInfoType: '类型',
|
||||||
|
installInfoId: '标识',
|
||||||
|
installInfoVersion: '版本',
|
||||||
|
installSuccess: '安装成功',
|
||||||
manualAdd: '手动添加',
|
manualAdd: '手动添加',
|
||||||
uploadExtension: '拖拽或点击上传扩展包',
|
uploadExtension: '拖拽或点击上传扩展包',
|
||||||
uploadHint: '支持 .zip(技能)和 .lbpkg(插件)文件',
|
uploadHint: '支持 .zip(技能)和 .lbpkg(插件)文件',
|
||||||
|
|||||||
Reference in New Issue
Block a user