mirror of
https://github.com/langbot-app/LangBot.git
synced 2025-11-25 19:37:36 +08:00
feat(web): Add centered empty state messages to pipeline extension dialogs (#1784)
* Initial plan * feat: add empty state messages in pipeline extension dialogs Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com> * fix: center empty state messages in dialog content area Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>
This commit is contained in:
@@ -331,48 +331,56 @@ export default function PipelineExtension({
|
|||||||
<DialogTitle>{t('pipelines.extensions.selectPlugins')}</DialogTitle>
|
<DialogTitle>{t('pipelines.extensions.selectPlugins')}</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className="flex-1 overflow-y-auto space-y-2 pr-2">
|
<div className="flex-1 overflow-y-auto space-y-2 pr-2">
|
||||||
{allPlugins.map((plugin) => {
|
{allPlugins.length === 0 ? (
|
||||||
const pluginId = getPluginId(plugin);
|
<div className="flex h-full items-center justify-center">
|
||||||
const metadata = plugin.manifest.manifest.metadata;
|
<p className="text-sm text-muted-foreground">
|
||||||
const isSelected = tempSelectedPluginIds.includes(pluginId);
|
{t('pipelines.extensions.noPluginsInstalled')}
|
||||||
return (
|
</p>
|
||||||
<div
|
</div>
|
||||||
key={pluginId}
|
) : (
|
||||||
className="flex items-center gap-3 rounded-lg border p-3 hover:bg-accent cursor-pointer"
|
allPlugins.map((plugin) => {
|
||||||
onClick={() => handleTogglePlugin(pluginId)}
|
const pluginId = getPluginId(plugin);
|
||||||
>
|
const metadata = plugin.manifest.manifest.metadata;
|
||||||
<Checkbox checked={isSelected} />
|
const isSelected = tempSelectedPluginIds.includes(pluginId);
|
||||||
<img
|
return (
|
||||||
src={backendClient.getPluginIconURL(
|
<div
|
||||||
metadata.author || '',
|
key={pluginId}
|
||||||
metadata.name,
|
className="flex items-center gap-3 rounded-lg border p-3 hover:bg-accent cursor-pointer"
|
||||||
|
onClick={() => handleTogglePlugin(pluginId)}
|
||||||
|
>
|
||||||
|
<Checkbox checked={isSelected} />
|
||||||
|
<img
|
||||||
|
src={backendClient.getPluginIconURL(
|
||||||
|
metadata.author || '',
|
||||||
|
metadata.name,
|
||||||
|
)}
|
||||||
|
alt={metadata.name}
|
||||||
|
className="w-10 h-10 rounded-lg border bg-muted object-cover flex-shrink-0"
|
||||||
|
/>
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="font-medium">{metadata.name}</div>
|
||||||
|
<div className="text-sm text-muted-foreground">
|
||||||
|
{metadata.author} • v{metadata.version}
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-1 mt-1">
|
||||||
|
<PluginComponentList
|
||||||
|
components={plugin.components}
|
||||||
|
showComponentName={true}
|
||||||
|
showTitle={false}
|
||||||
|
useBadge={true}
|
||||||
|
t={t}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{!plugin.enabled && (
|
||||||
|
<Badge variant="secondary">
|
||||||
|
{t('pipelines.extensions.disabled')}
|
||||||
|
</Badge>
|
||||||
)}
|
)}
|
||||||
alt={metadata.name}
|
|
||||||
className="w-10 h-10 rounded-lg border bg-muted object-cover flex-shrink-0"
|
|
||||||
/>
|
|
||||||
<div className="flex-1">
|
|
||||||
<div className="font-medium">{metadata.name}</div>
|
|
||||||
<div className="text-sm text-muted-foreground">
|
|
||||||
{metadata.author} • v{metadata.version}
|
|
||||||
</div>
|
|
||||||
<div className="flex gap-1 mt-1">
|
|
||||||
<PluginComponentList
|
|
||||||
components={plugin.components}
|
|
||||||
showComponentName={true}
|
|
||||||
showTitle={false}
|
|
||||||
useBadge={true}
|
|
||||||
t={t}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{!plugin.enabled && (
|
);
|
||||||
<Badge variant="secondary">
|
})
|
||||||
{t('pipelines.extensions.disabled')}
|
)}
|
||||||
</Badge>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button
|
<Button
|
||||||
@@ -397,46 +405,56 @@ export default function PipelineExtension({
|
|||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className="flex-1 overflow-y-auto space-y-2 pr-2">
|
<div className="flex-1 overflow-y-auto space-y-2 pr-2">
|
||||||
{allMCPServers.map((server) => {
|
{allMCPServers.length === 0 ? (
|
||||||
const isSelected = tempSelectedMCPIds.includes(server.uuid || '');
|
<div className="flex h-full items-center justify-center">
|
||||||
return (
|
<p className="text-sm text-muted-foreground">
|
||||||
<div
|
{t('pipelines.extensions.noMCPServersConfigured')}
|
||||||
key={server.uuid}
|
</p>
|
||||||
className="flex items-center gap-3 rounded-lg border p-3 hover:bg-accent cursor-pointer"
|
</div>
|
||||||
onClick={() => handleToggleMCPServer(server.uuid || '')}
|
) : (
|
||||||
>
|
allMCPServers.map((server) => {
|
||||||
<Checkbox checked={isSelected} />
|
const isSelected = tempSelectedMCPIds.includes(
|
||||||
<div className="w-10 h-10 rounded-lg border bg-muted flex items-center justify-center flex-shrink-0">
|
server.uuid || '',
|
||||||
<Server className="h-5 w-5 text-muted-foreground" />
|
);
|
||||||
</div>
|
return (
|
||||||
<div className="flex-1">
|
<div
|
||||||
<div className="font-medium">{server.name}</div>
|
key={server.uuid}
|
||||||
<div className="text-sm text-muted-foreground">
|
className="flex items-center gap-3 rounded-lg border p-3 hover:bg-accent cursor-pointer"
|
||||||
{server.mode}
|
onClick={() => handleToggleMCPServer(server.uuid || '')}
|
||||||
|
>
|
||||||
|
<Checkbox checked={isSelected} />
|
||||||
|
<div className="w-10 h-10 rounded-lg border bg-muted flex items-center justify-center flex-shrink-0">
|
||||||
|
<Server className="h-5 w-5 text-muted-foreground" />
|
||||||
</div>
|
</div>
|
||||||
{server.runtime_info &&
|
<div className="flex-1">
|
||||||
server.runtime_info.status === 'connected' && (
|
<div className="font-medium">{server.name}</div>
|
||||||
<Badge
|
<div className="text-sm text-muted-foreground">
|
||||||
variant="outline"
|
{server.mode}
|
||||||
className="flex items-center gap-1 mt-1"
|
</div>
|
||||||
>
|
{server.runtime_info &&
|
||||||
<Wrench className="h-3 w-3 text-black dark:text-white" />
|
server.runtime_info.status === 'connected' && (
|
||||||
<span className="text-xs text-black dark:text-white">
|
<Badge
|
||||||
{t('pipelines.extensions.toolCount', {
|
variant="outline"
|
||||||
count: server.runtime_info.tool_count || 0,
|
className="flex items-center gap-1 mt-1"
|
||||||
})}
|
>
|
||||||
</span>
|
<Wrench className="h-3 w-3 text-black dark:text-white" />
|
||||||
</Badge>
|
<span className="text-xs text-black dark:text-white">
|
||||||
)}
|
{t('pipelines.extensions.toolCount', {
|
||||||
|
count: server.runtime_info.tool_count || 0,
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{!server.enable && (
|
||||||
|
<Badge variant="secondary">
|
||||||
|
{t('pipelines.extensions.disabled')}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{!server.enable && (
|
);
|
||||||
<Badge variant="secondary">
|
})
|
||||||
{t('pipelines.extensions.disabled')}
|
)}
|
||||||
</Badge>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button variant="outline" onClick={() => setMcpDialogOpen(false)}>
|
<Button variant="outline" onClick={() => setMcpDialogOpen(false)}>
|
||||||
|
|||||||
@@ -482,6 +482,8 @@ const enUS = {
|
|||||||
addMCPServer: 'Add MCP Server',
|
addMCPServer: 'Add MCP Server',
|
||||||
selectMCPServers: 'Select MCP Servers',
|
selectMCPServers: 'Select MCP Servers',
|
||||||
toolCount: '{{count}} tools',
|
toolCount: '{{count}} tools',
|
||||||
|
noPluginsInstalled: 'No installed plugins',
|
||||||
|
noMCPServersConfigured: 'No configured MCP servers',
|
||||||
},
|
},
|
||||||
debugDialog: {
|
debugDialog: {
|
||||||
title: 'Pipeline Chat',
|
title: 'Pipeline Chat',
|
||||||
|
|||||||
@@ -485,6 +485,8 @@ const jaJP = {
|
|||||||
addMCPServer: 'MCPサーバーを追加',
|
addMCPServer: 'MCPサーバーを追加',
|
||||||
selectMCPServers: 'MCPサーバーを選択',
|
selectMCPServers: 'MCPサーバーを選択',
|
||||||
toolCount: '{{count}}個のツール',
|
toolCount: '{{count}}個のツール',
|
||||||
|
noPluginsInstalled: 'インストールされているプラグインがありません',
|
||||||
|
noMCPServersConfigured: '設定されているMCPサーバーがありません',
|
||||||
},
|
},
|
||||||
debugDialog: {
|
debugDialog: {
|
||||||
title: 'パイプラインのチャット',
|
title: 'パイプラインのチャット',
|
||||||
|
|||||||
@@ -464,6 +464,8 @@ const zhHans = {
|
|||||||
addMCPServer: '添加 MCP 服务器',
|
addMCPServer: '添加 MCP 服务器',
|
||||||
selectMCPServers: '选择 MCP 服务器',
|
selectMCPServers: '选择 MCP 服务器',
|
||||||
toolCount: '{{count}} 个工具',
|
toolCount: '{{count}} 个工具',
|
||||||
|
noPluginsInstalled: '无已安装的插件',
|
||||||
|
noMCPServersConfigured: '无已配置的 MCP 服务器',
|
||||||
},
|
},
|
||||||
debugDialog: {
|
debugDialog: {
|
||||||
title: '流水线对话',
|
title: '流水线对话',
|
||||||
|
|||||||
@@ -462,6 +462,8 @@ const zhHant = {
|
|||||||
addMCPServer: '新增 MCP 伺服器',
|
addMCPServer: '新增 MCP 伺服器',
|
||||||
selectMCPServers: '選擇 MCP 伺服器',
|
selectMCPServers: '選擇 MCP 伺服器',
|
||||||
toolCount: '{{count}} 個工具',
|
toolCount: '{{count}} 個工具',
|
||||||
|
noPluginsInstalled: '無已安裝的插件',
|
||||||
|
noMCPServersConfigured: '無已配置的 MCP 伺服器',
|
||||||
},
|
},
|
||||||
debugDialog: {
|
debugDialog: {
|
||||||
title: '流程線對話',
|
title: '流程線對話',
|
||||||
|
|||||||
Reference in New Issue
Block a user