Compare commits

..

25 Commits

Author SHA1 Message Date
Junyan Qin 4011a302af chore: bump version 4.6.0b2 for testing 2025-11-16 19:28:52 +08:00
Junyan Qin deb725a2e2 fix: send adapters and requesters icons 2025-11-16 19:26:30 +08:00
Junyan Qin 33eb866660 chore: add templates/** 2025-11-16 19:20:43 +08:00
Junyan Qin 34e2fa03ce chore: bump version 4.6.0-beta.1 for testing 2025-11-16 19:11:02 +08:00
Junyan Qin 7b63bcdc39 ci: publish pypi 2025-11-16 19:09:24 +08:00
Junyan Qin d26e81620d fix: tests 2025-11-16 18:39:45 +08:00
Junyan Qin e7885539a7 fix: read default-pipeline-config.json 2025-11-16 18:13:10 +08:00
Junyan Qin f216505237 fix: read default-pipeline-config.json 2025-11-16 18:12:29 +08:00
Junyan Qin 8b11eefd0c Merge branch 'master' into copilot/create-langbot-python-package 2025-11-16 17:50:37 +08:00
Junyan Qin 418cddd657 chore: fix imports 2025-11-16 17:44:18 +08:00
Junyan Qin 75edeb7a01 chore: adjust dir structure 2025-11-16 16:28:04 +08:00
Junyan Qin c5aa5be4d8 chore: update 2025-11-07 23:19:51 +08:00
Junyan Qin 92614062cc chore: update 2025-11-07 23:10:57 +08:00
Junyan Qin 09307d8c6d chore: update 2025-11-07 23:04:49 +08:00
Junyan Qin 894db240ae chore: update 2025-11-07 23:02:50 +08:00
Junyan Qin f79cde5b0c chore: update 2025-11-07 22:55:33 +08:00
Junyan Qin d43c2c498c chore: try pack templates in langbot/ 2025-11-07 22:51:30 +08:00
Junyan Qin 5f6036c5a8 chore: update pyproject.toml 2025-11-07 22:19:15 +08:00
copilot-swe-agent[bot] dead0794b1 Simplify package configuration and document behavioral differences
- Removed redundant package-data configuration, relying on MANIFEST.in
- Added documentation about behavioral differences between package and source installation
- Clarified that include-package-data=true uses MANIFEST.in for data files

Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>
2025-11-07 14:08:57 +00:00
copilot-swe-agent[bot] f784bad08b Fix code review issues
- Use specific exception types instead of bare except
- Fix misleading comments about directory levels
- Remove redundant existence check before makedirs with exist_ok=True
- Use context manager for file opening to ensure proper cleanup

Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>
2025-11-07 14:06:49 +00:00
copilot-swe-agent[bot] 4e86e1c93d Address code review feedback
- Made package-data configuration more specific to langbot package only
- Improved path detection with caching to avoid repeated file I/O
- Removed sys.path searching which was incorrect for package data
- Removed interactive input() call for non-interactive environment compatibility
- Simplified error messages for version check

Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>
2025-11-07 14:04:47 +00:00
copilot-swe-agent[bot] c0eec966ac Add PyPI installation documentation
- Created PYPI_INSTALLATION.md with detailed installation and usage instructions
- Updated README.md to feature uvx/pip installation as recommended method
- Updated README_EN.md with same changes for English documentation

Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>
2025-11-07 14:02:49 +00:00
copilot-swe-agent[bot] 62d6dae4f5 Add PyPI publishing workflow and update license
- Created GitHub Actions workflow to build frontend and publish to PyPI
- Added license field to pyproject.toml to fix deprecation warning
- Updated .gitignore to exclude build artifacts
- Tested package building successfully

Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>
2025-11-07 14:01:07 +00:00
copilot-swe-agent[bot] cab573f3e2 Add package structure and resource path utilities
- Created langbot/ package with __init__.py and __main__.py entry point
- Added paths utility to find frontend and resource files from package installation
- Updated config loading to use resource paths
- Updated frontend serving to use resource paths
- Added MANIFEST.in for package data inclusion
- Updated pyproject.toml with build system and entry points

Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>
2025-11-07 13:58:18 +00:00
copilot-swe-agent[bot] 8fe59da302 Initial plan 2025-11-07 13:48:46 +00:00
19 changed files with 244 additions and 308 deletions
-11
View File
@@ -2,17 +2,6 @@
> 请在此部分填写你实现/解决/优化的内容: > 请在此部分填写你实现/解决/优化的内容:
> Summary of what you implemented/solved/optimized: > Summary of what you implemented/solved/optimized:
>
### 更改前后对比截图 / Screenshots
> 请在此部分粘贴更改前后对比截图(可以是界面截图、控制台输出、对话截图等):
> Please paste the screenshots of changes before and after here (can be interface screenshots, console output, conversation screenshots, etc.):
>
> 修改前 / Before:
>
> 修改后 / After:
>
## 检查清单 / Checklist ## 检查清单 / Checklist
+11 -2
View File
@@ -31,16 +31,25 @@ LangBot 是一个开源的大语言模型原生即时通信机器人开发平台
## 📦 开始使用 ## 📦 开始使用
#### 快速部署 #### 快速体验(推荐)
使用 `uvx` 一键启动(需要先安装 [uv](https://docs.astral.sh/uv/getting-started/installation/)): 使用 `uvx` 一键启动(无需安装):
```bash ```bash
uvx langbot uvx langbot
``` ```
或使用 `pip` 安装后运行:
```bash
pip install langbot
langbot
```
访问 http://localhost:5300 即可开始使用。 访问 http://localhost:5300 即可开始使用。
详细文档[PyPI 安装](docs/PYPI_INSTALLATION.md)。
#### Docker Compose 部署 #### Docker Compose 部署
```bash ```bash
+11 -2
View File
@@ -25,16 +25,25 @@ LangBot is an open-source LLM native instant messaging robot development platfor
## 📦 Getting Started ## 📦 Getting Started
#### Quick Start #### Quick Start (Recommended)
Use `uvx` to start with one command (need to install [uv](https://docs.astral.sh/uv/getting-started/installation/)): Use `uvx` to start with one command (no installation required):
```bash ```bash
uvx langbot uvx langbot
``` ```
Or install with `pip` and run:
```bash
pip install langbot
langbot
```
Visit http://localhost:5300 to start using it. Visit http://localhost:5300 to start using it.
Detailed documentation [PyPI Installation](docs/PYPI_INSTALLATION.md).
#### Docker Compose Deployment #### Docker Compose Deployment
```bash ```bash
-10
View File
@@ -25,16 +25,6 @@ LangBot は、エージェント、RAG、MCP などの LLM アプリケーショ
## 📦 始め方 ## 📦 始め方
#### クイックスタート
`uvx` を使用した迅速なデプロイ([uv](https://docs.astral.sh/uv/getting-started/installation/) が必要です):
```bash
uvx langbot
```
http://localhost:5300 にアクセスして使用を開始します。
#### Docker Compose デプロイ #### Docker Compose デプロイ
```bash ```bash
-10
View File
@@ -27,16 +27,6 @@ LangBot 是一個開源的大語言模型原生即時通訊機器人開發平台
## 📦 開始使用 ## 📦 開始使用
#### 快速部署
使用 `uvx` 一鍵啟動(需要先安裝 [uv](https://docs.astral.sh/uv/getting-started/installation/) ):
```bash
uvx langbot
```
訪問 http://localhost:5300 即可開始使用。
#### Docker Compose 部署 #### Docker Compose 部署
```bash ```bash
-2
View File
@@ -7,7 +7,6 @@ services:
langbot_plugin_runtime: langbot_plugin_runtime:
image: rockchin/langbot:latest image: rockchin/langbot:latest
container_name: langbot_plugin_runtime container_name: langbot_plugin_runtime
platform: linux/amd64 # For Apple Silicon compatibility
volumes: volumes:
- ./data/plugins:/app/data/plugins - ./data/plugins:/app/data/plugins
ports: ports:
@@ -22,7 +21,6 @@ services:
langbot: langbot:
image: rockchin/langbot:latest image: rockchin/langbot:latest
container_name: langbot container_name: langbot
platform: linux/amd64 # For Apple Silicon compatibility
volumes: volumes:
- ./data:/app/data - ./data:/app/data
- ./plugins:/app/plugins - ./plugins:/app/plugins
+2 -2
View File
@@ -1,6 +1,6 @@
[project] [project]
name = "langbot" name = "langbot"
version = "4.5.3" version = "4.6.0-beta.2"
description = "Easy-to-use global IM bot platform designed for LLM era" description = "Easy-to-use global IM bot platform designed for LLM era"
readme = "README.md" readme = "README.md"
license-files = ["LICENSE"] license-files = ["LICENSE"]
@@ -63,7 +63,7 @@ dependencies = [
"langchain-text-splitters>=0.0.1", "langchain-text-splitters>=0.0.1",
"chromadb>=0.4.24", "chromadb>=0.4.24",
"qdrant-client (>=1.15.1,<2.0.0)", "qdrant-client (>=1.15.1,<2.0.0)",
"langbot-plugin==0.1.11", "langbot-plugin==0.1.11b1",
"asyncpg>=0.30.0", "asyncpg>=0.30.0",
"line-bot-sdk>=3.19.0", "line-bot-sdk>=3.19.0",
"tboxsdk>=0.0.10", "tboxsdk>=0.0.10",
+1 -1
View File
@@ -1,3 +1,3 @@
"""LangBot - Easy-to-use global IM bot platform designed for LLM era""" """LangBot - Easy-to-use global IM bot platform designed for LLM era"""
__version__ = '4.5.3' __version__ = '4.6.0-beta.2'
+1 -3
View File
@@ -1,6 +1,4 @@
import langbot semantic_version = 'v4.6.0-beta.2'
semantic_version = f'v{langbot.__version__}'
required_database_version = 11 required_database_version = 11
"""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"""
@@ -188,6 +188,40 @@ export default function HomeSidebar({
</div> </div>
)} )}
<SidebarChild
onClick={() => {
// open docs.langbot.app
const language = localStorage.getItem('langbot_language');
if (language === 'zh-Hans') {
window.open(
'https://docs.langbot.app/zh/insight/guide.html',
'_blank',
);
} else if (language === 'zh-Hant') {
window.open(
'https://docs.langbot.app/zh/insight/guide.html',
'_blank',
);
} else {
window.open(
'https://docs.langbot.app/en/insight/guide.html',
'_blank',
);
}
}}
isSelected={false}
icon={
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
>
<path d="M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM11 15H13V17H11V15ZM13 13.3551V14H11V12.5C11 11.9477 11.4477 11.5 12 11.5C12.8284 11.5 13.5 10.8284 13.5 10C13.5 9.17157 12.8284 8.5 12 8.5C11.2723 8.5 10.6656 9.01823 10.5288 9.70577L8.56731 9.31346C8.88637 7.70919 10.302 6.5 12 6.5C13.933 6.5 15.5 8.067 15.5 10C15.5 11.5855 14.4457 12.9248 13 13.3551Z"></path>
</svg>
}
name={t('common.helpDocs')}
/>
<SidebarChild <SidebarChild
onClick={() => { onClick={() => {
setApiKeyDialogOpen(true); setApiKeyDialogOpen(true);
@@ -268,41 +302,6 @@ export default function HomeSidebar({
<div className="flex flex-col gap-2 w-full"> <div className="flex flex-col gap-2 w-full">
<span className="text-sm font-medium">{t('common.account')}</span> <span className="text-sm font-medium">{t('common.account')}</span>
<Button
variant="ghost"
className="w-full justify-start font-normal"
onClick={() => {
// open docs.langbot.app
const language = localStorage.getItem('langbot_language');
if (language === 'zh-Hans') {
window.open(
'https://docs.langbot.app/zh/insight/guide.html',
'_blank',
);
} else if (language === 'zh-Hant') {
window.open(
'https://docs.langbot.app/zh/insight/guide.html',
'_blank',
);
} else {
window.open(
'https://docs.langbot.app/en/insight/guide.html',
'_blank',
);
}
setPopoverOpen(false);
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
className="w-4 h-4 mr-2"
>
<path d="M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM11 15H13V17H11V15ZM13 13.3551V14H11V12.5C11 11.9477 11.4477 11.5 12 11.5C12.8284 11.5 13.5 10.8284 13.5 10C13.5 9.17157 12.8284 8.5 12 8.5C11.2723 8.5 10.6656 9.01823 10.5288 9.70577L8.56731 9.31346C8.88637 7.70919 10.302 6.5 12 6.5C13.933 6.5 15.5 8.067 15.5 10C15.5 11.5855 14.4457 12.9248 13 13.3551Z"></path>
</svg>
{t('common.helpDocs')}
</Button>
<Button <Button
variant="ghost" variant="ghost"
className="w-full justify-start font-normal" className="w-full justify-start font-normal"
@@ -331,14 +331,7 @@ 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.length === 0 ? ( {allPlugins.map((plugin) => {
<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 pluginId = getPluginId(plugin);
const metadata = plugin.manifest.manifest.metadata; const metadata = plugin.manifest.manifest.metadata;
const isSelected = tempSelectedPluginIds.includes(pluginId); const isSelected = tempSelectedPluginIds.includes(pluginId);
@@ -379,8 +372,7 @@ export default function PipelineExtension({
)} )}
</div> </div>
); );
}) })}
)}
</div> </div>
<DialogFooter> <DialogFooter>
<Button <Button
@@ -405,17 +397,8 @@ 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.length === 0 ? ( {allMCPServers.map((server) => {
<div className="flex h-full items-center justify-center"> const isSelected = tempSelectedMCPIds.includes(server.uuid || '');
<p className="text-sm text-muted-foreground">
{t('pipelines.extensions.noMCPServersConfigured')}
</p>
</div>
) : (
allMCPServers.map((server) => {
const isSelected = tempSelectedMCPIds.includes(
server.uuid || '',
);
return ( return (
<div <div
key={server.uuid} key={server.uuid}
@@ -453,8 +436,7 @@ export default function PipelineExtension({
)} )}
</div> </div>
); );
}) })}
)}
</div> </div>
<DialogFooter> <DialogFooter>
<Button variant="outline" onClick={() => setMcpDialogOpen(false)}> <Button variant="outline" onClick={() => setMcpDialogOpen(false)}>
@@ -274,7 +274,7 @@ const PluginInstalledComponent = forwardRef<PluginInstalledComponentRef>(
</Dialog> </Dialog>
{pluginList.length === 0 ? ( {pluginList.length === 0 ? (
<div className="flex flex-col items-center justify-center text-gray-500 min-h-[60vh] w-full gap-2"> <div className="flex flex-col items-center justify-center text-gray-500 h-[calc(100vh-16rem)] w-full gap-2">
<svg <svg
className="h-[3rem] w-[3rem]" className="h-[3rem] w-[3rem]"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@@ -57,7 +57,6 @@ function MarketPageContent({
const pageSize = 16; // 每页16个,4行x4列 const pageSize = 16; // 每页16个,4行x4列
const searchTimeoutRef = useRef<NodeJS.Timeout | null>(null); const searchTimeoutRef = useRef<NodeJS.Timeout | null>(null);
const scrollContainerRef = useRef<HTMLDivElement | null>(null);
// 排序选项 // 排序选项
const sortOptions: SortOption[] = [ const sortOptions: SortOption[] = [
@@ -263,21 +262,19 @@ function MarketPageContent({
} }
}, [currentPage, isLoadingMore, hasMore, fetchPlugins, searchQuery]); }, [currentPage, isLoadingMore, hasMore, fetchPlugins, searchQuery]);
// Listen to scroll events on the scroll container // 监听滚动事件
useEffect(() => { useEffect(() => {
const scrollContainer = scrollContainerRef.current;
if (!scrollContainer) return;
const handleScroll = () => { const handleScroll = () => {
const { scrollTop, scrollHeight, clientHeight } = scrollContainer; if (
// Load more when scrolled to within 100px of the bottom window.innerHeight + document.documentElement.scrollTop >=
if (scrollTop + clientHeight >= scrollHeight - 100) { document.documentElement.offsetHeight - 100
) {
loadMore(); loadMore();
} }
}; };
scrollContainer.addEventListener('scroll', handleScroll); window.addEventListener('scroll', handleScroll);
return () => scrollContainer.removeEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll);
}, [loadMore]); }, [loadMore]);
// 安装插件 // 安装插件
@@ -286,10 +283,8 @@ function MarketPageContent({
// }; // };
return ( return (
<div className="h-full flex flex-col"> <div className="container mx-auto px-3 sm:px-4 py-4 sm:py-6 space-y-4 sm:space-y-6">
{/* Fixed header with search and sort controls */} {/* 搜索框 */}
<div className="flex-shrink-0 space-y-4 px-3 sm:px-4 py-4 sm:py-6">
{/* Search box */}
<div className="flex items-center justify-center"> <div className="flex items-center justify-center">
<div className="relative w-full max-w-2xl"> <div className="relative w-full max-w-2xl">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-muted-foreground h-4 w-4" /> <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-muted-foreground h-4 w-4" />
@@ -299,7 +294,7 @@ function MarketPageContent({
onChange={(e) => handleSearchInputChange(e.target.value)} onChange={(e) => handleSearchInputChange(e.target.value)}
onKeyPress={(e) => { onKeyPress={(e) => {
if (e.key === 'Enter') { if (e.key === 'Enter') {
// Immediately search, clear debounce timer // 立即搜索,清除防抖定时器
if (searchTimeoutRef.current) { if (searchTimeoutRef.current) {
clearTimeout(searchTimeoutRef.current); clearTimeout(searchTimeoutRef.current);
} }
@@ -311,7 +306,7 @@ function MarketPageContent({
</div> </div>
</div> </div>
{/* Sort dropdown */} {/* 排序下拉框 */}
<div className="flex items-center justify-center"> <div className="flex items-center justify-center">
<div className="w-full max-w-2xl flex items-center gap-2 sm:gap-3"> <div className="w-full max-w-2xl flex items-center gap-2 sm:gap-3">
<span className="text-xs sm:text-sm text-muted-foreground whitespace-nowrap"> <span className="text-xs sm:text-sm text-muted-foreground whitespace-nowrap">
@@ -332,7 +327,7 @@ function MarketPageContent({
</div> </div>
</div> </div>
{/* Search results stats */} {/* 搜索结果统计 */}
{total > 0 && ( {total > 0 && (
<div className="text-center text-muted-foreground text-sm"> <div className="text-center text-muted-foreground text-sm">
{searchQuery {searchQuery
@@ -340,13 +335,8 @@ function MarketPageContent({
: t('market.totalPlugins', { count: total })} : t('market.totalPlugins', { count: total })}
</div> </div>
)} )}
</div>
{/* Scrollable content area */} {/* 插件列表 */}
<div
ref={scrollContainerRef}
className="flex-1 overflow-y-auto px-3 sm:px-4"
>
{isLoading ? ( {isLoading ? (
<div className="flex items-center justify-center py-12"> <div className="flex items-center justify-center py-12">
<Loader2 className="h-8 w-8 animate-spin" /> <Loader2 className="h-8 w-8 animate-spin" />
@@ -359,8 +349,7 @@ function MarketPageContent({
</div> </div>
</div> </div>
) : ( ) : (
<> <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4 gap-6">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4 gap-6 pb-6">
{plugins.map((plugin) => ( {plugins.map((plugin) => (
<PluginMarketCardComponent <PluginMarketCardComponent
key={plugin.pluginId} key={plugin.pluginId}
@@ -369,8 +358,9 @@ function MarketPageContent({
/> />
))} ))}
</div> </div>
)}
{/* Loading more indicator */} {/* 加载更多指示器 */}
{isLoadingMore && ( {isLoadingMore && (
<div className="flex items-center justify-center py-6"> <div className="flex items-center justify-center py-6">
<Loader2 className="h-6 w-6 animate-spin" /> <Loader2 className="h-6 w-6 animate-spin" />
@@ -378,17 +368,14 @@ function MarketPageContent({
</div> </div>
)} )}
{/* No more data hint */} {/* 没有更多数据提示 */}
{!hasMore && plugins.length > 0 && ( {!hasMore && plugins.length > 0 && (
<div className="text-center text-muted-foreground py-6"> <div className="text-center text-muted-foreground py-6">
{t('market.allLoaded')} {t('market.allLoaded')}
</div> </div>
)} )}
</>
)}
</div>
{/* Plugin detail dialog */} {/* 插件详情对话框 */}
<PluginDetailDialog <PluginDetailDialog
open={dialogOpen} open={dialogOpen}
onOpenChange={handleDialogClose} onOpenChange={handleDialogClose}
@@ -73,14 +73,14 @@ export default function MCPComponent({
return ( return (
<div className="w-full h-full"> <div className="w-full h-full">
{/* Server list */} {/* 已安装的服务器列表 */}
<div className="w-full h-full px-[0.8rem] pt-[0rem]"> <div className="w-full px-[0.8rem] pt-[0rem] gap-4">
{loading ? ( {loading ? (
<div className="flex flex-col items-center justify-center text-gray-500 min-h-[60vh] w-full gap-2"> <div className="flex flex-col items-center justify-center text-gray-500 h-[calc(100vh-16rem)] w-full gap-2">
{t('mcp.loading')} {t('mcp.loading')}
</div> </div>
) : installedServers.length === 0 ? ( ) : installedServers.length === 0 ? (
<div className="flex flex-col items-center justify-center text-gray-500 min-h-[60vh] w-full gap-2"> <div className="flex flex-col items-center justify-center text-gray-500 h-[calc(100vh-16rem)] w-full gap-2">
<svg <svg
className="h-[3rem] w-[3rem]" className="h-[3rem] w-[3rem]"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@@ -92,7 +92,7 @@ export default function MCPComponent({
<div className="text-lg mb-2">{t('mcp.noServerInstalled')}</div> <div className="text-lg mb-2">{t('mcp.noServerInstalled')}</div>
</div> </div>
) : ( ) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 pt-[2rem] pb-6"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 pt-[2rem]">
{installedServers.map((server, index) => ( {installedServers.map((server, index) => (
<div key={`${server.name}-${index}`}> <div key={`${server.name}-${index}`}>
<MCPCardComponent <MCPCardComponent
+6 -13
View File
@@ -431,7 +431,7 @@ export default function PluginConfigPage() {
return ( return (
<div <div
className={`${styles.pageContainer} h-full flex flex-col ${isDragOver ? 'bg-blue-50' : ''}`} className={`${styles.pageContainer} ${isDragOver ? 'bg-blue-50' : ''}`}
onDragOver={handleDragOver} onDragOver={handleDragOver}
onDragLeave={handleDragLeave} onDragLeave={handleDragLeave}
onDrop={handleDrop} onDrop={handleDrop}
@@ -443,12 +443,8 @@ export default function PluginConfigPage() {
onChange={handleFileChange} onChange={handleFileChange}
style={{ display: 'none' }} style={{ display: 'none' }}
/> />
<Tabs <Tabs value={activeTab} onValueChange={setActiveTab} className="w-full">
value={activeTab} <div className="flex flex-row justify-between items-center px-[0.8rem]">
onValueChange={setActiveTab}
className="w-full h-full flex flex-col"
>
<div className="flex flex-row justify-between items-center px-[0.8rem] flex-shrink-0">
<TabsList className="shadow-md py-5 bg-[#f0f0f0] dark:bg-[#2a2a2e]"> <TabsList className="shadow-md py-5 bg-[#f0f0f0] dark:bg-[#2a2a2e]">
<TabsTrigger value="installed" className="px-6 py-4 cursor-pointer"> <TabsTrigger value="installed" className="px-6 py-4 cursor-pointer">
{t('plugins.installed')} {t('plugins.installed')}
@@ -526,10 +522,10 @@ export default function PluginConfigPage() {
</DropdownMenu> </DropdownMenu>
</div> </div>
</div> </div>
<TabsContent value="installed" className="flex-1 overflow-y-auto mt-0"> <TabsContent value="installed">
<PluginInstalledComponent ref={pluginInstalledRef} /> <PluginInstalledComponent ref={pluginInstalledRef} />
</TabsContent> </TabsContent>
<TabsContent value="market" className="flex-1 overflow-y-auto mt-0"> <TabsContent value="market">
<MarketPage <MarketPage
installPlugin={(plugin: PluginV4) => { installPlugin={(plugin: PluginV4) => {
setInstallSource('marketplace'); setInstallSource('marketplace');
@@ -543,10 +539,7 @@ export default function PluginConfigPage() {
}} }}
/> />
</TabsContent> </TabsContent>
<TabsContent <TabsContent value="mcp-servers">
value="mcp-servers"
className="flex-1 overflow-y-auto mt-0"
>
<MCPServerComponent <MCPServerComponent
key={refreshKey} key={refreshKey}
onEditServer={(serverName) => { onEditServer={(serverName) => {
-2
View File
@@ -482,8 +482,6 @@ 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',
-2
View File
@@ -485,8 +485,6 @@ const jaJP = {
addMCPServer: 'MCPサーバーを追加', addMCPServer: 'MCPサーバーを追加',
selectMCPServers: 'MCPサーバーを選択', selectMCPServers: 'MCPサーバーを選択',
toolCount: '{{count}}個のツール', toolCount: '{{count}}個のツール',
noPluginsInstalled: 'インストールされているプラグインがありません',
noMCPServersConfigured: '設定されているMCPサーバーがありません',
}, },
debugDialog: { debugDialog: {
title: 'パイプラインのチャット', title: 'パイプラインのチャット',
-2
View File
@@ -464,8 +464,6 @@ const zhHans = {
addMCPServer: '添加 MCP 服务器', addMCPServer: '添加 MCP 服务器',
selectMCPServers: '选择 MCP 服务器', selectMCPServers: '选择 MCP 服务器',
toolCount: '{{count}} 个工具', toolCount: '{{count}} 个工具',
noPluginsInstalled: '无已安装的插件',
noMCPServersConfigured: '无已配置的 MCP 服务器',
}, },
debugDialog: { debugDialog: {
title: '流水线对话', title: '流水线对话',
-2
View File
@@ -462,8 +462,6 @@ const zhHant = {
addMCPServer: '新增 MCP 伺服器', addMCPServer: '新增 MCP 伺服器',
selectMCPServers: '選擇 MCP 伺服器', selectMCPServers: '選擇 MCP 伺服器',
toolCount: '{{count}} 個工具', toolCount: '{{count}} 個工具',
noPluginsInstalled: '無已安裝的插件',
noMCPServersConfigured: '無已配置的 MCP 伺服器',
}, },
debugDialog: { debugDialog: {
title: '流程線對話', title: '流程線對話',