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:
Copilot
2025-11-16 23:37:40 +08:00
committed by GitHub
parent abb2f7ae05
commit c27ccb8475
5 changed files with 104 additions and 78 deletions

View File

@@ -331,48 +331,56 @@ export default function PipelineExtension({
<DialogTitle>{t('pipelines.extensions.selectPlugins')}</DialogTitle>
</DialogHeader>
<div className="flex-1 overflow-y-auto space-y-2 pr-2">
{allPlugins.map((plugin) => {
const pluginId = getPluginId(plugin);
const metadata = plugin.manifest.manifest.metadata;
const isSelected = tempSelectedPluginIds.includes(pluginId);
return (
<div
key={pluginId}
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,
{allPlugins.length === 0 ? (
<div className="flex h-full items-center justify-center">
<p className="text-sm text-muted-foreground">
{t('pipelines.extensions.noPluginsInstalled')}
</p>
</div>
) : (
allPlugins.map((plugin) => {
const pluginId = getPluginId(plugin);
const metadata = plugin.manifest.manifest.metadata;
const isSelected = tempSelectedPluginIds.includes(pluginId);
return (
<div
key={pluginId}
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>
{!plugin.enabled && (
<Badge variant="secondary">
{t('pipelines.extensions.disabled')}
</Badge>
)}
</div>
);
})}
);
})
)}
</div>
<DialogFooter>
<Button
@@ -397,46 +405,56 @@ export default function PipelineExtension({
</DialogTitle>
</DialogHeader>
<div className="flex-1 overflow-y-auto space-y-2 pr-2">
{allMCPServers.map((server) => {
const isSelected = tempSelectedMCPIds.includes(server.uuid || '');
return (
<div
key={server.uuid}
className="flex items-center gap-3 rounded-lg border p-3 hover:bg-accent cursor-pointer"
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 className="flex-1">
<div className="font-medium">{server.name}</div>
<div className="text-sm text-muted-foreground">
{server.mode}
{allMCPServers.length === 0 ? (
<div className="flex h-full items-center justify-center">
<p className="text-sm text-muted-foreground">
{t('pipelines.extensions.noMCPServersConfigured')}
</p>
</div>
) : (
allMCPServers.map((server) => {
const isSelected = tempSelectedMCPIds.includes(
server.uuid || '',
);
return (
<div
key={server.uuid}
className="flex items-center gap-3 rounded-lg border p-3 hover:bg-accent cursor-pointer"
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>
{server.runtime_info &&
server.runtime_info.status === 'connected' && (
<Badge
variant="outline"
className="flex items-center gap-1 mt-1"
>
<Wrench className="h-3 w-3 text-black dark:text-white" />
<span className="text-xs text-black dark:text-white">
{t('pipelines.extensions.toolCount', {
count: server.runtime_info.tool_count || 0,
})}
</span>
</Badge>
)}
<div className="flex-1">
<div className="font-medium">{server.name}</div>
<div className="text-sm text-muted-foreground">
{server.mode}
</div>
{server.runtime_info &&
server.runtime_info.status === 'connected' && (
<Badge
variant="outline"
className="flex items-center gap-1 mt-1"
>
<Wrench className="h-3 w-3 text-black dark:text-white" />
<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>
{!server.enable && (
<Badge variant="secondary">
{t('pipelines.extensions.disabled')}
</Badge>
)}
</div>
);
})}
);
})
)}
</div>
<DialogFooter>
<Button variant="outline" onClick={() => setMcpDialogOpen(false)}>

View File

@@ -482,6 +482,8 @@ const enUS = {
addMCPServer: 'Add MCP Server',
selectMCPServers: 'Select MCP Servers',
toolCount: '{{count}} tools',
noPluginsInstalled: 'No installed plugins',
noMCPServersConfigured: 'No configured MCP servers',
},
debugDialog: {
title: 'Pipeline Chat',

View File

@@ -485,6 +485,8 @@ const jaJP = {
addMCPServer: 'MCPサーバーを追加',
selectMCPServers: 'MCPサーバーを選択',
toolCount: '{{count}}個のツール',
noPluginsInstalled: 'インストールされているプラグインがありません',
noMCPServersConfigured: '設定されているMCPサーバーがありません',
},
debugDialog: {
title: 'パイプラインのチャット',

View File

@@ -464,6 +464,8 @@ const zhHans = {
addMCPServer: '添加 MCP 服务器',
selectMCPServers: '选择 MCP 服务器',
toolCount: '{{count}} 个工具',
noPluginsInstalled: '无已安装的插件',
noMCPServersConfigured: '无已配置的 MCP 服务器',
},
debugDialog: {
title: '流水线对话',

View File

@@ -462,6 +462,8 @@ const zhHant = {
addMCPServer: '新增 MCP 伺服器',
selectMCPServers: '選擇 MCP 伺服器',
toolCount: '{{count}} 個工具',
noPluginsInstalled: '無已安裝的插件',
noMCPServersConfigured: '無已配置的 MCP 伺服器',
},
debugDialog: {
title: '流程線對話',