mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-12 16:56:02 +00:00
Feat/pipeline enable all extensions (#1807)
* feat: 添加流水线扩展集成"启用所有"选项
为流水线的扩展集成配置添加独立的"启用所有插件"和"启用所有MCP服务器"选项。
主要变更:
- 数据模型:在 extensions_preferences 中添加 enable_all_plugins 和 enable_all_mcp_servers 字段
- 后端逻辑:修改 RuntimePipeline 以支持独立的启用所有选项,当启用时设置为 None 表示使用所有可用资源
- API 接口:更新 GET/PUT /api/v1/pipelines/{uuid}/extensions 以支持新字段
- 前端 UI:为插件和 MCP 服务器分别添加独立的开关控件
- 国际化:添加对应的中文翻译文本
- 默认行为:新创建的流水线默认启用所有插件和 MCP 服务器
🤖 Generated with [Claude Code](https://claude.com/claude-code)
via [Happy](https://happy.engineering)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
* fix(i18n): add missing translations for pipeline extensions
Added translations for enable all plugins/MCP servers feature:
- en-US: English translations
- ja-JP: Japanese translations
- zh-Hant: Traditional Chinese translations
Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
* chore: add migration for enable all extensions config
* fix: bad renaming
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Happy <yesreply@happy.engineering>
This commit is contained in:
committed by
GitHub
parent
7d51293594
commit
87131cf03b
@@ -62,22 +62,27 @@ class PipelinesRouterGroup(group.RouterGroup):
|
|||||||
plugins = await self.ap.plugin_connector.list_plugins()
|
plugins = await self.ap.plugin_connector.list_plugins()
|
||||||
mcp_servers = await self.ap.mcp_service.get_mcp_servers(contain_runtime_info=True)
|
mcp_servers = await self.ap.mcp_service.get_mcp_servers(contain_runtime_info=True)
|
||||||
|
|
||||||
|
extensions_prefs = pipeline.get('extensions_preferences', {})
|
||||||
return self.success(
|
return self.success(
|
||||||
data={
|
data={
|
||||||
'bound_plugins': pipeline.get('extensions_preferences', {}).get('plugins', []),
|
'enable_all_plugins': extensions_prefs.get('enable_all_plugins', True),
|
||||||
|
'enable_all_mcp_servers': extensions_prefs.get('enable_all_mcp_servers', True),
|
||||||
|
'bound_plugins': extensions_prefs.get('plugins', []),
|
||||||
'available_plugins': plugins,
|
'available_plugins': plugins,
|
||||||
'bound_mcp_servers': pipeline.get('extensions_preferences', {}).get('mcp_servers', []),
|
'bound_mcp_servers': extensions_prefs.get('mcp_servers', []),
|
||||||
'available_mcp_servers': mcp_servers,
|
'available_mcp_servers': mcp_servers,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
elif quart.request.method == 'PUT':
|
elif quart.request.method == 'PUT':
|
||||||
# Update bound plugins and MCP servers for this pipeline
|
# Update bound plugins and MCP servers for this pipeline
|
||||||
json_data = await quart.request.json
|
json_data = await quart.request.json
|
||||||
|
enable_all_plugins = json_data.get('enable_all_plugins', True)
|
||||||
|
enable_all_mcp_servers = json_data.get('enable_all_mcp_servers', True)
|
||||||
bound_plugins = json_data.get('bound_plugins', [])
|
bound_plugins = json_data.get('bound_plugins', [])
|
||||||
bound_mcp_servers = json_data.get('bound_mcp_servers', [])
|
bound_mcp_servers = json_data.get('bound_mcp_servers', [])
|
||||||
|
|
||||||
await self.ap.pipeline_service.update_pipeline_extensions(
|
await self.ap.pipeline_service.update_pipeline_extensions(
|
||||||
pipeline_uuid, bound_plugins, bound_mcp_servers
|
pipeline_uuid, bound_plugins, bound_mcp_servers, enable_all_plugins, enable_all_mcp_servers
|
||||||
)
|
)
|
||||||
|
|
||||||
return self.success()
|
return self.success()
|
||||||
|
|||||||
@@ -85,6 +85,15 @@ class PipelineService:
|
|||||||
with open(template_path, 'r', encoding='utf-8') as f:
|
with open(template_path, 'r', encoding='utf-8') as f:
|
||||||
pipeline_data['config'] = json.load(f)
|
pipeline_data['config'] = json.load(f)
|
||||||
|
|
||||||
|
# Ensure extensions_preferences is set with enable_all_plugins and enable_all_mcp_servers=True by default
|
||||||
|
if 'extensions_preferences' not in pipeline_data:
|
||||||
|
pipeline_data['extensions_preferences'] = {
|
||||||
|
'enable_all_plugins': True,
|
||||||
|
'enable_all_mcp_servers': True,
|
||||||
|
'plugins': [],
|
||||||
|
'mcp_servers': [],
|
||||||
|
}
|
||||||
|
|
||||||
await self.ap.persistence_mgr.execute_async(
|
await self.ap.persistence_mgr.execute_async(
|
||||||
sqlalchemy.insert(persistence_pipeline.LegacyPipeline).values(**pipeline_data)
|
sqlalchemy.insert(persistence_pipeline.LegacyPipeline).values(**pipeline_data)
|
||||||
)
|
)
|
||||||
@@ -143,7 +152,12 @@ class PipelineService:
|
|||||||
await self.ap.pipeline_mgr.remove_pipeline(pipeline_uuid)
|
await self.ap.pipeline_mgr.remove_pipeline(pipeline_uuid)
|
||||||
|
|
||||||
async def update_pipeline_extensions(
|
async def update_pipeline_extensions(
|
||||||
self, pipeline_uuid: str, bound_plugins: list[dict], bound_mcp_servers: list[str] = None
|
self,
|
||||||
|
pipeline_uuid: str,
|
||||||
|
bound_plugins: list[dict],
|
||||||
|
bound_mcp_servers: list[str] = None,
|
||||||
|
enable_all_plugins: bool = True,
|
||||||
|
enable_all_mcp_servers: bool = True,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Update the bound plugins and MCP servers for a pipeline"""
|
"""Update the bound plugins and MCP servers for a pipeline"""
|
||||||
# Get current pipeline
|
# Get current pipeline
|
||||||
@@ -159,6 +173,8 @@ class PipelineService:
|
|||||||
|
|
||||||
# Update extensions_preferences
|
# Update extensions_preferences
|
||||||
extensions_preferences = pipeline.extensions_preferences or {}
|
extensions_preferences = pipeline.extensions_preferences or {}
|
||||||
|
extensions_preferences['enable_all_plugins'] = enable_all_plugins
|
||||||
|
extensions_preferences['enable_all_mcp_servers'] = enable_all_mcp_servers
|
||||||
extensions_preferences['plugins'] = bound_plugins
|
extensions_preferences['plugins'] = bound_plugins
|
||||||
if bound_mcp_servers is not None:
|
if bound_mcp_servers is not None:
|
||||||
extensions_preferences['mcp_servers'] = bound_mcp_servers
|
extensions_preferences['mcp_servers'] = bound_mcp_servers
|
||||||
|
|||||||
@@ -22,7 +22,11 @@ class LegacyPipeline(Base):
|
|||||||
is_default = sqlalchemy.Column(sqlalchemy.Boolean, nullable=False, default=False)
|
is_default = sqlalchemy.Column(sqlalchemy.Boolean, nullable=False, default=False)
|
||||||
stages = sqlalchemy.Column(sqlalchemy.JSON, nullable=False)
|
stages = sqlalchemy.Column(sqlalchemy.JSON, nullable=False)
|
||||||
config = sqlalchemy.Column(sqlalchemy.JSON, nullable=False)
|
config = sqlalchemy.Column(sqlalchemy.JSON, nullable=False)
|
||||||
extensions_preferences = sqlalchemy.Column(sqlalchemy.JSON, nullable=False, default={})
|
extensions_preferences = sqlalchemy.Column(
|
||||||
|
sqlalchemy.JSON,
|
||||||
|
nullable=False,
|
||||||
|
default={'enable_all_plugins': True, 'enable_all_mcp_servers': True, 'plugins': [], 'mcp_servers': []},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class PipelineRunRecord(Base):
|
class PipelineRunRecord(Base):
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from ...entity.persistence import pipeline as persistence_pipeline
|
|||||||
|
|
||||||
@migration.migration_class(11)
|
@migration.migration_class(11)
|
||||||
class DBMigrateDifyApiConfig(migration.DBMigration):
|
class DBMigrateDifyApiConfig(migration.DBMigration):
|
||||||
"""Langflow API config"""
|
"""Dify base prompt config"""
|
||||||
|
|
||||||
async def upgrade(self):
|
async def upgrade(self):
|
||||||
"""Upgrade"""
|
"""Upgrade"""
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
from .. import migration
|
||||||
|
|
||||||
|
import sqlalchemy
|
||||||
|
|
||||||
|
from ...entity.persistence import pipeline as persistence_pipeline
|
||||||
|
|
||||||
|
|
||||||
|
@migration.migration_class(12)
|
||||||
|
class DBMigratePipelineExtensionsEnableAll(migration.DBMigration):
|
||||||
|
"""Pipeline extensions enable all"""
|
||||||
|
|
||||||
|
async def upgrade(self):
|
||||||
|
"""Upgrade"""
|
||||||
|
# read all pipelines
|
||||||
|
pipelines = await self.ap.persistence_mgr.execute_async(sqlalchemy.select(persistence_pipeline.LegacyPipeline))
|
||||||
|
|
||||||
|
for pipeline in pipelines:
|
||||||
|
serialized_pipeline = self.ap.persistence_mgr.serialize_model(persistence_pipeline.LegacyPipeline, pipeline)
|
||||||
|
|
||||||
|
extensions_preferences = serialized_pipeline['extensions_preferences']
|
||||||
|
|
||||||
|
if 'enable_all_plugins' not in extensions_preferences:
|
||||||
|
if 'plugins' in extensions_preferences:
|
||||||
|
extensions_preferences['enable_all_plugins'] = False
|
||||||
|
else:
|
||||||
|
extensions_preferences['enable_all_plugins'] = True
|
||||||
|
extensions_preferences['plugins'] = []
|
||||||
|
|
||||||
|
if 'enable_all_mcp_servers' not in extensions_preferences:
|
||||||
|
if 'mcp_servers' in extensions_preferences:
|
||||||
|
extensions_preferences['enable_all_mcp_servers'] = False
|
||||||
|
else:
|
||||||
|
extensions_preferences['enable_all_mcp_servers'] = True
|
||||||
|
extensions_preferences['mcp_servers'] = []
|
||||||
|
|
||||||
|
await self.ap.persistence_mgr.execute_async(
|
||||||
|
sqlalchemy.update(persistence_pipeline.LegacyPipeline)
|
||||||
|
.where(persistence_pipeline.LegacyPipeline.uuid == serialized_pipeline['uuid'])
|
||||||
|
.values(
|
||||||
|
extensions_preferences=extensions_preferences,
|
||||||
|
for_version=self.ap.ver_mgr.get_current_version(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
async def downgrade(self):
|
||||||
|
"""Downgrade"""
|
||||||
|
pass
|
||||||
@@ -69,11 +69,17 @@ class RuntimePipeline:
|
|||||||
stage_containers: list[StageInstContainer]
|
stage_containers: list[StageInstContainer]
|
||||||
"""阶段实例容器"""
|
"""阶段实例容器"""
|
||||||
|
|
||||||
bound_plugins: list[str]
|
bound_plugins: list[str] | None
|
||||||
"""绑定到此流水线的插件列表(格式:author/plugin_name)"""
|
"""绑定到此流水线的插件列表(格式:author/plugin_name),None表示启用所有"""
|
||||||
|
|
||||||
bound_mcp_servers: list[str]
|
bound_mcp_servers: list[str] | None
|
||||||
"""绑定到此流水线的MCP服务器列表(格式:uuid)"""
|
"""绑定到此流水线的MCP服务器列表(格式:uuid),None表示启用所有"""
|
||||||
|
|
||||||
|
enable_all_plugins: bool
|
||||||
|
"""是否启用所有插件"""
|
||||||
|
|
||||||
|
enable_all_mcp_servers: bool
|
||||||
|
"""是否启用所有MCP服务器"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -87,11 +93,22 @@ class RuntimePipeline:
|
|||||||
|
|
||||||
# Extract bound plugins and MCP servers from extensions_preferences
|
# Extract bound plugins and MCP servers from extensions_preferences
|
||||||
extensions_prefs = pipeline_entity.extensions_preferences or {}
|
extensions_prefs = pipeline_entity.extensions_preferences or {}
|
||||||
plugin_list = extensions_prefs.get('plugins', [])
|
self.enable_all_plugins = extensions_prefs.get('enable_all_plugins', True)
|
||||||
self.bound_plugins = [f'{p["author"]}/{p["name"]}' for p in plugin_list] if plugin_list else []
|
self.enable_all_mcp_servers = extensions_prefs.get('enable_all_mcp_servers', True)
|
||||||
|
|
||||||
mcp_server_list = extensions_prefs.get('mcp_servers', [])
|
if self.enable_all_plugins:
|
||||||
self.bound_mcp_servers = mcp_server_list if mcp_server_list else []
|
# None indicates to use all available plugins
|
||||||
|
self.bound_plugins = None
|
||||||
|
else:
|
||||||
|
plugin_list = extensions_prefs.get('plugins', [])
|
||||||
|
self.bound_plugins = [f'{p["author"]}/{p["name"]}' for p in plugin_list] if plugin_list else []
|
||||||
|
|
||||||
|
if self.enable_all_mcp_servers:
|
||||||
|
# None indicates to use all available MCP servers
|
||||||
|
self.bound_mcp_servers = None
|
||||||
|
else:
|
||||||
|
mcp_server_list = extensions_prefs.get('mcp_servers', [])
|
||||||
|
self.bound_mcp_servers = mcp_server_list if mcp_server_list else []
|
||||||
|
|
||||||
async def run(self, query: pipeline_query.Query):
|
async def run(self, query: pipeline_query.Query):
|
||||||
query.pipeline_config = self.pipeline_entity.config
|
query.pipeline_config = self.pipeline_entity.config
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import langbot
|
|||||||
|
|
||||||
semantic_version = f'v{langbot.__version__}'
|
semantic_version = f'v{langbot.__version__}'
|
||||||
|
|
||||||
required_database_version = 11
|
required_database_version = 12
|
||||||
"""Tag the version of the database schema, used to check if the database needs to be migrated"""
|
"""Tag the version of the database schema, used to check if the database needs to be migrated"""
|
||||||
|
|
||||||
debug_mode = False
|
debug_mode = False
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ import {
|
|||||||
import { Checkbox } from '@/components/ui/checkbox';
|
import { Checkbox } from '@/components/ui/checkbox';
|
||||||
import { Plus, X, Server, Wrench } from 'lucide-react';
|
import { Plus, X, Server, Wrench } from 'lucide-react';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { Switch } from '@/components/ui/switch';
|
||||||
|
import { Label } from '@/components/ui/label';
|
||||||
import { Plugin } from '@/app/infra/entities/plugin';
|
import { Plugin } from '@/app/infra/entities/plugin';
|
||||||
import { MCPServer } from '@/app/infra/entities/api';
|
import { MCPServer } from '@/app/infra/entities/api';
|
||||||
import PluginComponentList from '@/app/home/plugins/components/plugin-installed/PluginComponentList';
|
import PluginComponentList from '@/app/home/plugins/components/plugin-installed/PluginComponentList';
|
||||||
@@ -27,6 +29,8 @@ export default function PipelineExtension({
|
|||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [enableAllPlugins, setEnableAllPlugins] = useState(true);
|
||||||
|
const [enableAllMCPServers, setEnableAllMCPServers] = useState(true);
|
||||||
const [selectedPlugins, setSelectedPlugins] = useState<Plugin[]>([]);
|
const [selectedPlugins, setSelectedPlugins] = useState<Plugin[]>([]);
|
||||||
const [allPlugins, setAllPlugins] = useState<Plugin[]>([]);
|
const [allPlugins, setAllPlugins] = useState<Plugin[]>([]);
|
||||||
const [selectedMCPServers, setSelectedMCPServers] = useState<MCPServer[]>([]);
|
const [selectedMCPServers, setSelectedMCPServers] = useState<MCPServer[]>([]);
|
||||||
@@ -53,6 +57,9 @@ export default function PipelineExtension({
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
const data = await backendClient.getPipelineExtensions(pipelineId);
|
const data = await backendClient.getPipelineExtensions(pipelineId);
|
||||||
|
|
||||||
|
setEnableAllPlugins(data.enable_all_plugins ?? true);
|
||||||
|
setEnableAllMCPServers(data.enable_all_mcp_servers ?? true);
|
||||||
|
|
||||||
const boundPluginIds = new Set(
|
const boundPluginIds = new Set(
|
||||||
data.bound_plugins.map((p) => `${p.author}/${p.name}`),
|
data.bound_plugins.map((p) => `${p.author}/${p.name}`),
|
||||||
);
|
);
|
||||||
@@ -80,7 +87,12 @@ export default function PipelineExtension({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveToBackend = async (plugins: Plugin[], mcpServers: MCPServer[]) => {
|
const saveToBackend = async (
|
||||||
|
plugins: Plugin[],
|
||||||
|
mcpServers: MCPServer[],
|
||||||
|
newEnableAllPlugins?: boolean,
|
||||||
|
newEnableAllMCPServers?: boolean,
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
const boundPluginsArray = plugins.map((plugin) => {
|
const boundPluginsArray = plugins.map((plugin) => {
|
||||||
const metadata = plugin.manifest.manifest.metadata;
|
const metadata = plugin.manifest.manifest.metadata;
|
||||||
@@ -96,6 +108,8 @@ export default function PipelineExtension({
|
|||||||
pipelineId,
|
pipelineId,
|
||||||
boundPluginsArray,
|
boundPluginsArray,
|
||||||
boundMCPServerIds,
|
boundMCPServerIds,
|
||||||
|
newEnableAllPlugins ?? enableAllPlugins,
|
||||||
|
newEnableAllMCPServers ?? enableAllMCPServers,
|
||||||
);
|
);
|
||||||
toast.success(t('pipelines.extensions.saveSuccess'));
|
toast.success(t('pipelines.extensions.saveSuccess'));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -184,6 +198,26 @@ export default function PipelineExtension({
|
|||||||
await saveToBackend(selectedPlugins, newSelected);
|
await saveToBackend(selectedPlugins, newSelected);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleToggleEnableAllPlugins = async (checked: boolean) => {
|
||||||
|
setEnableAllPlugins(checked);
|
||||||
|
await saveToBackend(
|
||||||
|
selectedPlugins,
|
||||||
|
selectedMCPServers,
|
||||||
|
checked,
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleToggleEnableAllMCPServers = async (checked: boolean) => {
|
||||||
|
setEnableAllMCPServers(checked);
|
||||||
|
await saveToBackend(
|
||||||
|
selectedPlugins,
|
||||||
|
selectedMCPServers,
|
||||||
|
undefined,
|
||||||
|
checked,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
@@ -198,11 +232,32 @@ export default function PipelineExtension({
|
|||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{/* Plugins Section */}
|
{/* Plugins Section */}
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<h3 className="text-sm font-semibold text-foreground">
|
<div className="flex items-center justify-between">
|
||||||
{t('pipelines.extensions.pluginsTitle')}
|
<h3 className="text-sm font-semibold text-foreground">
|
||||||
</h3>
|
{t('pipelines.extensions.pluginsTitle')}
|
||||||
|
</h3>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Label
|
||||||
|
htmlFor="enable-all-plugins"
|
||||||
|
className="text-sm font-normal cursor-pointer"
|
||||||
|
>
|
||||||
|
{t('pipelines.extensions.enableAllPlugins')}
|
||||||
|
</Label>
|
||||||
|
<Switch
|
||||||
|
id="enable-all-plugins"
|
||||||
|
checked={enableAllPlugins}
|
||||||
|
onCheckedChange={handleToggleEnableAllPlugins}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{selectedPlugins.length === 0 ? (
|
{enableAllPlugins ? (
|
||||||
|
<div className="flex h-32 items-center justify-center rounded-lg border-2 border-dashed border-border bg-muted/30">
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
{t('pipelines.extensions.allPluginsEnabled')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
) : selectedPlugins.length === 0 ? (
|
||||||
<div className="flex h-32 items-center justify-center rounded-lg border-2 border-dashed border-border">
|
<div className="flex h-32 items-center justify-center rounded-lg border-2 border-dashed border-border">
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
{t('pipelines.extensions.noPluginsSelected')}
|
{t('pipelines.extensions.noPluginsSelected')}
|
||||||
@@ -278,6 +333,7 @@ export default function PipelineExtension({
|
|||||||
onClick={handleOpenPluginDialog}
|
onClick={handleOpenPluginDialog}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="w-full"
|
className="w-full"
|
||||||
|
disabled={enableAllPlugins}
|
||||||
>
|
>
|
||||||
<Plus className="mr-2 h-4 w-4" />
|
<Plus className="mr-2 h-4 w-4" />
|
||||||
{t('pipelines.extensions.addPlugin')}
|
{t('pipelines.extensions.addPlugin')}
|
||||||
@@ -286,11 +342,32 @@ export default function PipelineExtension({
|
|||||||
|
|
||||||
{/* MCP Servers Section */}
|
{/* MCP Servers Section */}
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<h3 className="text-sm font-semibold text-foreground">
|
<div className="flex items-center justify-between">
|
||||||
{t('pipelines.extensions.mcpServersTitle')}
|
<h3 className="text-sm font-semibold text-foreground">
|
||||||
</h3>
|
{t('pipelines.extensions.mcpServersTitle')}
|
||||||
|
</h3>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Label
|
||||||
|
htmlFor="enable-all-mcp-servers"
|
||||||
|
className="text-sm font-normal cursor-pointer"
|
||||||
|
>
|
||||||
|
{t('pipelines.extensions.enableAllMCPServers')}
|
||||||
|
</Label>
|
||||||
|
<Switch
|
||||||
|
id="enable-all-mcp-servers"
|
||||||
|
checked={enableAllMCPServers}
|
||||||
|
onCheckedChange={handleToggleEnableAllMCPServers}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{selectedMCPServers.length === 0 ? (
|
{enableAllMCPServers ? (
|
||||||
|
<div className="flex h-32 items-center justify-center rounded-lg border-2 border-dashed border-border bg-muted/30">
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
{t('pipelines.extensions.allMCPServersEnabled')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
) : selectedMCPServers.length === 0 ? (
|
||||||
<div className="flex h-32 items-center justify-center rounded-lg border-2 border-dashed border-border">
|
<div className="flex h-32 items-center justify-center rounded-lg border-2 border-dashed border-border">
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
{t('pipelines.extensions.noMCPServersSelected')}
|
{t('pipelines.extensions.noMCPServersSelected')}
|
||||||
@@ -350,6 +427,7 @@ export default function PipelineExtension({
|
|||||||
onClick={handleOpenMCPDialog}
|
onClick={handleOpenMCPDialog}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="w-full"
|
className="w-full"
|
||||||
|
disabled={enableAllMCPServers}
|
||||||
>
|
>
|
||||||
<Plus className="mr-2 h-4 w-4" />
|
<Plus className="mr-2 h-4 w-4" />
|
||||||
{t('pipelines.extensions.addMCPServer')}
|
{t('pipelines.extensions.addMCPServer')}
|
||||||
|
|||||||
@@ -171,6 +171,8 @@ export class BackendClient extends BaseHttpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getPipelineExtensions(uuid: string): Promise<{
|
public getPipelineExtensions(uuid: string): Promise<{
|
||||||
|
enable_all_plugins: boolean;
|
||||||
|
enable_all_mcp_servers: boolean;
|
||||||
bound_plugins: Array<{ author: string; name: string }>;
|
bound_plugins: Array<{ author: string; name: string }>;
|
||||||
available_plugins: Plugin[];
|
available_plugins: Plugin[];
|
||||||
bound_mcp_servers: string[];
|
bound_mcp_servers: string[];
|
||||||
@@ -183,10 +185,14 @@ export class BackendClient extends BaseHttpClient {
|
|||||||
uuid: string,
|
uuid: string,
|
||||||
bound_plugins: Array<{ author: string; name: string }>,
|
bound_plugins: Array<{ author: string; name: string }>,
|
||||||
bound_mcp_servers: string[],
|
bound_mcp_servers: string[],
|
||||||
|
enable_all_plugins: boolean = true,
|
||||||
|
enable_all_mcp_servers: boolean = true,
|
||||||
): Promise<object> {
|
): Promise<object> {
|
||||||
return this.put(`/api/v1/pipelines/${uuid}/extensions`, {
|
return this.put(`/api/v1/pipelines/${uuid}/extensions`, {
|
||||||
bound_plugins,
|
bound_plugins,
|
||||||
bound_mcp_servers,
|
bound_mcp_servers,
|
||||||
|
enable_all_plugins,
|
||||||
|
enable_all_mcp_servers,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -494,6 +494,10 @@ const enUS = {
|
|||||||
noPluginsInstalled: 'No installed plugins',
|
noPluginsInstalled: 'No installed plugins',
|
||||||
noMCPServersConfigured: 'No configured MCP servers',
|
noMCPServersConfigured: 'No configured MCP servers',
|
||||||
selectAll: 'Select All',
|
selectAll: 'Select All',
|
||||||
|
enableAllPlugins: 'Enable All Plugins',
|
||||||
|
enableAllMCPServers: 'Enable All MCP Servers',
|
||||||
|
allPluginsEnabled: 'All plugins enabled',
|
||||||
|
allMCPServersEnabled: 'All MCP servers enabled',
|
||||||
},
|
},
|
||||||
debugDialog: {
|
debugDialog: {
|
||||||
title: 'Pipeline Chat',
|
title: 'Pipeline Chat',
|
||||||
|
|||||||
@@ -497,6 +497,10 @@ const jaJP = {
|
|||||||
noPluginsInstalled: 'インストールされているプラグインがありません',
|
noPluginsInstalled: 'インストールされているプラグインがありません',
|
||||||
noMCPServersConfigured: '設定されているMCPサーバーがありません',
|
noMCPServersConfigured: '設定されているMCPサーバーがありません',
|
||||||
selectAll: 'すべて選択',
|
selectAll: 'すべて選択',
|
||||||
|
enableAllPlugins: 'すべてのプラグインを有効にする',
|
||||||
|
enableAllMCPServers: 'すべてのMCPサーバーを有効にする',
|
||||||
|
allPluginsEnabled: 'すべてのプラグインが有効になっています',
|
||||||
|
allMCPServersEnabled: 'すべてのMCPサーバーが有効になっています',
|
||||||
},
|
},
|
||||||
debugDialog: {
|
debugDialog: {
|
||||||
title: 'パイプラインのチャット',
|
title: 'パイプラインのチャット',
|
||||||
|
|||||||
@@ -476,6 +476,10 @@ const zhHans = {
|
|||||||
noPluginsInstalled: '无已安装的插件',
|
noPluginsInstalled: '无已安装的插件',
|
||||||
noMCPServersConfigured: '无已配置的 MCP 服务器',
|
noMCPServersConfigured: '无已配置的 MCP 服务器',
|
||||||
selectAll: '全选',
|
selectAll: '全选',
|
||||||
|
enableAllPlugins: '启用所有插件',
|
||||||
|
enableAllMCPServers: '启用所有 MCP 服务器',
|
||||||
|
allPluginsEnabled: '已启用所有插件',
|
||||||
|
allMCPServersEnabled: '已启用所有 MCP 服务器',
|
||||||
},
|
},
|
||||||
debugDialog: {
|
debugDialog: {
|
||||||
title: '流水线对话',
|
title: '流水线对话',
|
||||||
|
|||||||
@@ -474,6 +474,10 @@ const zhHant = {
|
|||||||
noPluginsInstalled: '無已安裝的插件',
|
noPluginsInstalled: '無已安裝的插件',
|
||||||
noMCPServersConfigured: '無已配置的 MCP 伺服器',
|
noMCPServersConfigured: '無已配置的 MCP 伺服器',
|
||||||
selectAll: '全選',
|
selectAll: '全選',
|
||||||
|
enableAllPlugins: '啟用所有插件',
|
||||||
|
enableAllMCPServers: '啟用所有 MCP 伺服器',
|
||||||
|
allPluginsEnabled: '已啟用所有插件',
|
||||||
|
allMCPServersEnabled: '已啟用所有 MCP 伺服器',
|
||||||
},
|
},
|
||||||
debugDialog: {
|
debugDialog: {
|
||||||
title: '流程線對話',
|
title: '流程線對話',
|
||||||
|
|||||||
Reference in New Issue
Block a user