feat: add interactive selection dialog to batch installer
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# Batch Install Plugins from GitHub
|
# Batch Install Plugins from GitHub
|
||||||
|
|
||||||
**Author:** [Fu-Jie](https://github.com/Fu-Jie) | **Version:** 1.0.0 | **Project:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions)
|
**Author:** [Fu-Jie](https://github.com/Fu-Jie) | **Version:** 1.1.0 | **Project:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions)
|
||||||
|
|
||||||
One-click batch install plugins from GitHub repositories to your OpenWebUI instance.
|
One-click batch install plugins from GitHub repositories to your OpenWebUI instance.
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ One-click batch install plugins from GitHub repositories to your OpenWebUI insta
|
|||||||
- **Auto-Update**: Automatically updates previously installed plugins
|
- **Auto-Update**: Automatically updates previously installed plugins
|
||||||
- **Public GitHub Support**: Install plugins from any public GitHub repository
|
- **Public GitHub Support**: Install plugins from any public GitHub repository
|
||||||
- **Multi-Type Support**: Supports Pipe, Action, Filter, and Tool plugins
|
- **Multi-Type Support**: Supports Pipe, Action, Filter, and Tool plugins
|
||||||
- **Confirmation**: Shows plugin list before installing, allows selective installation
|
- **Interactive Selection Dialog**: Review the filtered list, check the plugins you want, then install only that subset
|
||||||
- **i18n**: Supports 11 languages
|
- **i18n**: Supports 11 languages
|
||||||
|
|
||||||
## Flow
|
## Flow
|
||||||
@@ -32,8 +32,8 @@ User Input
|
|||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
┌─────────────────────────────────────┐
|
┌─────────────────────────────────────┐
|
||||||
│ Show Confirmation Dialog │
|
│ Show Selection Dialog │
|
||||||
│ (list plugins + exclude hint) │
|
│ (checkbox list + exclude hint) │
|
||||||
└─────────────────────────────────────┘
|
└─────────────────────────────────────┘
|
||||||
│
|
│
|
||||||
├── [Cancel] → End
|
├── [Cancel] → End
|
||||||
@@ -59,6 +59,8 @@ User Input
|
|||||||
|
|
||||||
Each request handles one repository. To mix repositories, send another request after the previous installation completes.
|
Each request handles one repository. To mix repositories, send another request after the previous installation completes.
|
||||||
|
|
||||||
|
After plugin discovery and filtering, OpenWebUI opens a browser dialog built with the `execute` event so you can check exactly which plugins to install before the API calls start.
|
||||||
|
|
||||||
## Quick Start: Install Popular Collections
|
## Quick Start: Install Popular Collections
|
||||||
|
|
||||||
Copy any of these prompts and paste them into your chat:
|
Copy any of these prompts and paste them into your chat:
|
||||||
@@ -127,11 +129,11 @@ For other repositories:
|
|||||||
| `SKIP_KEYWORDS` | `test,verify,example,template,mock` | Comma-separated keywords to skip |
|
| `SKIP_KEYWORDS` | `test,verify,example,template,mock` | Comma-separated keywords to skip |
|
||||||
| `TIMEOUT` | `20` | Request timeout in seconds |
|
| `TIMEOUT` | `20` | Request timeout in seconds |
|
||||||
|
|
||||||
## Confirmation Timeout
|
## Selection Dialog Timeout
|
||||||
|
|
||||||
User confirmation dialogs have a default timeout of **2 minutes (120 seconds)**, allowing sufficient time for users to:
|
The plugin selection dialog has a default timeout of **2 minutes (120 seconds)**, allowing sufficient time for users to:
|
||||||
- Read and review the plugin list
|
- Read and review the plugin list
|
||||||
- Make installation decisions
|
- Check or uncheck the plugins they want
|
||||||
- Handle network delays
|
- Handle network delays
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Batch Install Plugins from GitHub
|
# Batch Install Plugins from GitHub
|
||||||
|
|
||||||
**作者:** [Fu-Jie](https://github.com/Fu-Jie) | **版本:** 1.0.0 | **项目:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions)
|
**作者:** [Fu-Jie](https://github.com/Fu-Jie) | **版本:** 1.1.0 | **项目:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions)
|
||||||
|
|
||||||
一键将 GitHub 仓库中的插件批量安装到你的 OpenWebUI 实例。
|
一键将 GitHub 仓库中的插件批量安装到你的 OpenWebUI 实例。
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
- 自动更新:自动更新之前安装过的插件
|
- 自动更新:自动更新之前安装过的插件
|
||||||
- 公开 GitHub 支持:支持从任何公开 GitHub 仓库安装插件
|
- 公开 GitHub 支持:支持从任何公开 GitHub 仓库安装插件
|
||||||
- 多类型支持:支持 Pipe、Action、Filter 和 Tool 插件
|
- 多类型支持:支持 Pipe、Action、Filter 和 Tool 插件
|
||||||
- 安装确认:安装前显示插件列表,支持选择性安装
|
- 交互式选择对话框:先查看过滤后的列表,再勾选要安装的插件,只安装所选子集
|
||||||
- 国际化:支持 11 种语言
|
- 国际化:支持 11 种语言
|
||||||
|
|
||||||
## 流程
|
## 流程
|
||||||
@@ -32,8 +32,8 @@
|
|||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
┌─────────────────────────────────────┐
|
┌─────────────────────────────────────┐
|
||||||
│ 显示确认对话框 │
|
│ 显示选择对话框 │
|
||||||
│ (插件列表 + 排除提示) │
|
│ (复选列表 + 排除提示) │
|
||||||
└─────────────────────────────────────┘
|
└─────────────────────────────────────┘
|
||||||
│
|
│
|
||||||
├── [取消] → 结束
|
├── [取消] → 结束
|
||||||
@@ -59,6 +59,8 @@
|
|||||||
|
|
||||||
每次请求处理一个仓库。如需混合多个来源,请在上一次安装完成后再发起下一次请求。
|
每次请求处理一个仓库。如需混合多个来源,请在上一次安装完成后再发起下一次请求。
|
||||||
|
|
||||||
|
在插件发现和过滤完成后,OpenWebUI 会通过 `execute` 事件打开浏览器选择对话框,你可以先勾选真正想安装的插件,再开始调用安装 API。
|
||||||
|
|
||||||
## 快速开始:安装热门插件集
|
## 快速开始:安装热门插件集
|
||||||
|
|
||||||
复制以下任一提示词,粘贴到你的对话框中:
|
复制以下任一提示词,粘贴到你的对话框中:
|
||||||
@@ -127,11 +129,11 @@
|
|||||||
| `SKIP_KEYWORDS` | `test,verify,example,template,mock` | 逗号分隔的跳过关键词 |
|
| `SKIP_KEYWORDS` | `test,verify,example,template,mock` | 逗号分隔的跳过关键词 |
|
||||||
| `TIMEOUT` | `20` | 请求超时时间(秒)|
|
| `TIMEOUT` | `20` | 请求超时时间(秒)|
|
||||||
|
|
||||||
## 确认超时时间
|
## 选择对话框超时时间
|
||||||
|
|
||||||
用户确认对话框的默认超时时间为 **2 分钟(120 秒)**,为用户提供充足的时间来:
|
插件选择对话框的默认超时时间为 **2 分钟(120 秒)**,为用户提供充足的时间来:
|
||||||
- 阅读和查看插件列表
|
- 阅读和查看插件列表
|
||||||
- 做出安装决定
|
- 勾选或取消勾选想安装的插件
|
||||||
- 处理网络延迟
|
- 处理网络延迟
|
||||||
|
|
||||||
## 支持
|
## 支持
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Batch Install Plugins from GitHub
|
# Batch Install Plugins from GitHub
|
||||||
|
|
||||||
| By [Fu-Jie](https://github.com/Fu-Jie) · v1.0.0 | [⭐ Star this repo](https://github.com/Fu-Jie/openwebui-extensions) |
|
| By [Fu-Jie](https://github.com/Fu-Jie) · v1.1.0 | [⭐ Star this repo](https://github.com/Fu-Jie/openwebui-extensions) |
|
||||||
| :--- | ---: |
|
| :--- | ---: |
|
||||||
|
|
||||||
|  |  |  |  |  |  |  |
|
|  |  |  |  |  |  |  |
|
||||||
@@ -14,7 +14,7 @@ One-click batch install plugins from GitHub repositories to your OpenWebUI insta
|
|||||||
- **Auto-Update**: Automatically updates previously installed plugins
|
- **Auto-Update**: Automatically updates previously installed plugins
|
||||||
- **Public GitHub Support**: Install plugins from any public GitHub repository
|
- **Public GitHub Support**: Install plugins from any public GitHub repository
|
||||||
- **Multi-Type Support**: Supports Pipe, Action, Filter, and Tool plugins
|
- **Multi-Type Support**: Supports Pipe, Action, Filter, and Tool plugins
|
||||||
- **Confirmation**: Shows plugin list before installing, allows selective installation
|
- **Interactive Selection Dialog**: Review the filtered list, check the plugins you want, then install only that subset
|
||||||
- **i18n**: Supports 11 languages
|
- **i18n**: Supports 11 languages
|
||||||
|
|
||||||
## Flow
|
## Flow
|
||||||
@@ -36,8 +36,8 @@ User Input
|
|||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
┌─────────────────────────────────────┐
|
┌─────────────────────────────────────┐
|
||||||
│ Show Confirmation Dialog │
|
│ Show Selection Dialog │
|
||||||
│ (list plugins + exclude hint) │
|
│ (checkbox list + exclude hint) │
|
||||||
└─────────────────────────────────────┘
|
└─────────────────────────────────────┘
|
||||||
│
|
│
|
||||||
├── [Cancel] → End
|
├── [Cancel] → End
|
||||||
@@ -63,6 +63,8 @@ User Input
|
|||||||
|
|
||||||
Each request handles one repository. To mix repositories, send another request after the previous installation completes.
|
Each request handles one repository. To mix repositories, send another request after the previous installation completes.
|
||||||
|
|
||||||
|
After plugin discovery and filtering, OpenWebUI opens a browser dialog built with the `execute` event so you can check exactly which plugins to install before the API calls start.
|
||||||
|
|
||||||
## Quick Start: Install Popular Collections
|
## Quick Start: Install Popular Collections
|
||||||
|
|
||||||
Copy any of these prompts and paste them into your chat:
|
Copy any of these prompts and paste them into your chat:
|
||||||
@@ -131,11 +133,11 @@ For other repositories:
|
|||||||
| `SKIP_KEYWORDS` | `test,verify,example,template,mock` | Comma-separated keywords to skip |
|
| `SKIP_KEYWORDS` | `test,verify,example,template,mock` | Comma-separated keywords to skip |
|
||||||
| `TIMEOUT` | `20` | Request timeout in seconds |
|
| `TIMEOUT` | `20` | Request timeout in seconds |
|
||||||
|
|
||||||
## Confirmation Timeout
|
## Selection Dialog Timeout
|
||||||
|
|
||||||
User confirmation dialogs have a default timeout of **2 minutes (120 seconds)**, allowing sufficient time for users to:
|
The plugin selection dialog has a default timeout of **2 minutes (120 seconds)**, allowing sufficient time for users to:
|
||||||
- Read and review the plugin list
|
- Read and review the plugin list
|
||||||
- Make installation decisions
|
- Check or uncheck the plugins they want
|
||||||
- Handle network delays
|
- Handle network delays
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Batch Install Plugins from GitHub
|
# Batch Install Plugins from GitHub
|
||||||
|
|
||||||
| 作者:[Fu-Jie](https://github.com/Fu-Jie) · v1.0.0 | [⭐ 点个 Star 支持项目](https://github.com/Fu-Jie/openwebui-extensions) |
|
| 作者:[Fu-Jie](https://github.com/Fu-Jie) · v1.1.0 | [⭐ 点个 Star 支持项目](https://github.com/Fu-Jie/openwebui-extensions) |
|
||||||
| :--- | ---: |
|
| :--- | ---: |
|
||||||
|
|
||||||
|  |  |  |  |  |  |  |
|
|  |  |  |  |  |  |  |
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
- 自动更新:自动更新之前安装过的插件
|
- 自动更新:自动更新之前安装过的插件
|
||||||
- 公开 GitHub 支持:支持从任何公开 GitHub 仓库安装插件
|
- 公开 GitHub 支持:支持从任何公开 GitHub 仓库安装插件
|
||||||
- 多类型支持:支持 Pipe、Action、Filter 和 Tool 插件
|
- 多类型支持:支持 Pipe、Action、Filter 和 Tool 插件
|
||||||
- 安装确认:安装前显示插件列表,支持选择性安装
|
- 交互式选择对话框:先查看过滤后的列表,再勾选要安装的插件,只安装所选子集
|
||||||
- 国际化:支持 11 种语言
|
- 国际化:支持 11 种语言
|
||||||
|
|
||||||
## 流程
|
## 流程
|
||||||
@@ -36,8 +36,8 @@
|
|||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
┌─────────────────────────────────────┐
|
┌─────────────────────────────────────┐
|
||||||
│ 显示确认对话框 │
|
│ 显示选择对话框 │
|
||||||
│ (插件列表 + 排除提示) │
|
│ (复选列表 + 排除提示) │
|
||||||
└─────────────────────────────────────┘
|
└─────────────────────────────────────┘
|
||||||
│
|
│
|
||||||
├── [取消] → 结束
|
├── [取消] → 结束
|
||||||
@@ -63,6 +63,8 @@
|
|||||||
|
|
||||||
每次请求处理一个仓库。如需混合多个来源,请在上一次安装完成后再发起下一次请求。
|
每次请求处理一个仓库。如需混合多个来源,请在上一次安装完成后再发起下一次请求。
|
||||||
|
|
||||||
|
在插件发现和过滤完成后,OpenWebUI 会通过 `execute` 事件打开浏览器选择对话框,你可以先勾选真正想安装的插件,再开始调用安装 API。
|
||||||
|
|
||||||
## 快速开始:安装热门插件集
|
## 快速开始:安装热门插件集
|
||||||
|
|
||||||
复制以下任一提示词,粘贴到你的对话框中:
|
复制以下任一提示词,粘贴到你的对话框中:
|
||||||
@@ -131,11 +133,11 @@
|
|||||||
| `SKIP_KEYWORDS` | `test,verify,example,template,mock` | 逗号分隔的跳过关键词 |
|
| `SKIP_KEYWORDS` | `test,verify,example,template,mock` | 逗号分隔的跳过关键词 |
|
||||||
| `TIMEOUT` | `20` | 请求超时时间(秒)|
|
| `TIMEOUT` | `20` | 请求超时时间(秒)|
|
||||||
|
|
||||||
## 确认超时时间
|
## 选择对话框超时时间
|
||||||
|
|
||||||
用户确认对话框的默认超时时间为 **2 分钟(120 秒)**,为用户提供充足的时间来:
|
插件选择对话框的默认超时时间为 **2 分钟(120 秒)**,为用户提供充足的时间来:
|
||||||
- 阅读和查看插件列表
|
- 阅读和查看插件列表
|
||||||
- 做出安装决定
|
- 勾选或取消勾选想安装的插件
|
||||||
- 处理网络延迟
|
- 处理网络延迟
|
||||||
|
|
||||||
## 支持
|
## 支持
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ OpenWebUI native Tool plugins that can be used across models.
|
|||||||
|
|
||||||
## Available Tool Plugins
|
## Available Tool Plugins
|
||||||
|
|
||||||
- [Batch Install Plugins from GitHub](batch-install-plugins-tool.md) (v1.0.0) - One-click batch install plugins from GitHub repositories with confirmation and multi-language support.
|
- [Batch Install Plugins from GitHub](batch-install-plugins-tool.md) (v1.1.0) - One-click batch install plugins from GitHub repositories with an interactive selection dialog and multi-language support.
|
||||||
- [OpenWebUI Skills Manager Tool](openwebui-skills-manager-tool.md) (v0.3.0) - Simple native skill management (`list/show/install/create/update/delete`).
|
- [OpenWebUI Skills Manager Tool](openwebui-skills-manager-tool.md) (v0.3.0) - Simple native skill management (`list/show/install/create/update/delete`).
|
||||||
- [Smart Mind Map Tool](smart-mind-map-tool.md) (v1.0.0) - Intelligently analyzes text content and proactively generates interactive mind maps to help users structure and visualize knowledge.
|
- [Smart Mind Map Tool](smart-mind-map-tool.md) (v1.0.0) - Intelligently analyzes text content and proactively generates interactive mind maps to help users structure and visualize knowledge.
|
||||||
|
|||||||
@@ -4,6 +4,6 @@
|
|||||||
|
|
||||||
## 可用 Tool 插件
|
## 可用 Tool 插件
|
||||||
|
|
||||||
- [Batch Install Plugins from GitHub](batch-install-plugins-tool.zh.md) (v1.0.0) - 一键从 GitHub 仓库批量安装插件,支持确认和多语言。
|
- [Batch Install Plugins from GitHub](batch-install-plugins-tool.zh.md) (v1.1.0) - 一键从 GitHub 仓库批量安装插件,支持交互式选择对话框和多语言。
|
||||||
- [OpenWebUI Skills 管理工具](openwebui-skills-manager-tool.zh.md) (v0.3.0) - 简化技能管理(`list/show/install/create/update/delete`)。
|
- [OpenWebUI Skills 管理工具](openwebui-skills-manager-tool.zh.md) (v0.3.0) - 简化技能管理(`list/show/install/create/update/delete`)。
|
||||||
- [智能思维导图工具 (Smart Mind Map Tool)](smart-mind-map-tool.zh.md) (v1.0.0) - 智能分析文本内容并主动生成交互式思维导图,帮助用户结构化与可视化知识。
|
- [智能思维导图工具 (Smart Mind Map Tool)](smart-mind-map-tool.zh.md) (v1.0.0) - 智能分析文本内容并主动生成交互式思维导图,帮助用户结构化与可视化知识。
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
# 🎉 Introducing Batch Install Plugins v1.0.0
|
# 🎉 Batch Install Plugins v1.1.0
|
||||||
|
|
||||||
## Headline
|
## Headline
|
||||||
**One-Click Batch Installation of OpenWebUI Plugins - Solving the Plugin Setup Headache**
|
**Interactive Plugin Picker for OpenWebUI Batch Installation**
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
Installing plugins in OpenWebUI used to be tedious: searching for plugins, downloading them one by one, and hoping everything works in your environment. Today, we're excited to announce **Batch Install Plugins from GitHub** v1.0.0 — a powerful new tool that transforms plugin installation from a chore into a single command.
|
Installing plugins in OpenWebUI should not feel like an all-or-nothing jump. With **Batch Install Plugins from GitHub** v1.1.0, the workflow now opens an interactive browser dialog so users can review the filtered list and choose exactly which plugins to install before the API requests begin.
|
||||||
|
|
||||||
## Key Highlights
|
## Key Highlights
|
||||||
|
|
||||||
### 🚀 One-Click Bulk Installation
|
### 🚀 Interactive Plugin Selection
|
||||||
- Install multiple plugins from any public GitHub repository with a single command
|
- Uses the OpenWebUI `execute` event to open a custom browser dialog
|
||||||
- Automatically discovers plugins and validates them
|
- Displays the filtered plugin list with checkboxes, repository context, and exclude hints
|
||||||
- Updates previously installed plugins seamlessly
|
- Installs only the plugins the user keeps selected
|
||||||
|
|
||||||
### ✅ Smart Safety Features
|
### ✅ Smart Safety Features
|
||||||
- Shows a confirmation dialog with the plugin list before installation
|
- Replaces the basic confirmation event with a richer selective install flow
|
||||||
- Users can review and approve before proceeding
|
- Users can uncheck plugins they do not want without rewriting the request
|
||||||
- Automatically excludes the tool itself from installation
|
- Automatically excludes the tool itself from installation
|
||||||
|
|
||||||
### 🌍 Multi-Repository Support
|
### 🌍 Multi-Repository Support
|
||||||
@@ -43,7 +43,7 @@ Each request handles one repository. To combine multiple repositories, send anot
|
|||||||
```
|
```
|
||||||
"Install all plugins from Fu-Jie/openwebui-extensions"
|
"Install all plugins from Fu-Jie/openwebui-extensions"
|
||||||
```
|
```
|
||||||
Review the confirmation dialog, approve, and the plugins are installed.
|
Review the selection dialog, keep the plugins you want checked, and then install them.
|
||||||
|
|
||||||
2. **Add a Community Collection**
|
2. **Add a Community Collection**
|
||||||
```
|
```
|
||||||
@@ -110,8 +110,8 @@ Each line below is a separate request:
|
|||||||
|
|
||||||
- **Async Architecture**: Non-blocking I/O for better performance
|
- **Async Architecture**: Non-blocking I/O for better performance
|
||||||
- **httpx Integration**: Modern async HTTP client with timeout protection
|
- **httpx Integration**: Modern async HTTP client with timeout protection
|
||||||
- **Comprehensive Tests**: 8 regression tests with 100% pass rate
|
- **Selective Install Flow**: The install loop now runs only for the checked plugin subset
|
||||||
- **Full Event Support**: Proper OpenWebUI event injection with fallback handling
|
- **Full Event Support**: Proper OpenWebUI `execute` event handling with fallback behavior
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ Each line below is a separate request:
|
|||||||
## Links
|
## Links
|
||||||
|
|
||||||
- **GitHub Repository**: https://github.com/Fu-Jie/openwebui-extensions/tree/main/plugins/tools/batch-install-plugins
|
- **GitHub Repository**: https://github.com/Fu-Jie/openwebui-extensions/tree/main/plugins/tools/batch-install-plugins
|
||||||
- **Release Notes**: https://github.com/Fu-Jie/openwebui-extensions/blob/main/plugins/tools/batch-install-plugins/v1.0.0.md
|
- **Release Notes**: https://github.com/Fu-Jie/openwebui-extensions/blob/main/plugins/tools/batch-install-plugins/v1.1.0.md
|
||||||
|
|
||||||
## Community Love
|
## Community Love
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
# 🎉 Batch Install Plugins 首发 v1.0.0
|
# 🎉 Batch Install Plugins v1.1.0
|
||||||
|
|
||||||
## 标题
|
## 标题
|
||||||
**一键批量安装 OpenWebUI 插件 - 解决装机烦恼**
|
**为 OpenWebUI 批量安装带来可勾选的交互式插件选择器**
|
||||||
|
|
||||||
## 前言
|
## 前言
|
||||||
在 OpenWebUI 中安装插件曾经很麻烦:逐个搜索、逐个下载、祈祷一切顺利。今天,我们欣然宣布 **Batch Install Plugins from GitHub** v1.0.0 的问世 — 一款强大的新工具,让插件安装从苦差事变成一条简单命令。
|
批量安装不应该是“全装或不装”的二选一。现在,**Batch Install Plugins from GitHub** v1.1.0 新增了基于浏览器的交互式选择对话框,用户可以先查看过滤后的插件列表,再勾选真正要安装的插件,然后才开始调用安装 API。
|
||||||
|
|
||||||
## 核心特性
|
## 核心特性
|
||||||
|
|
||||||
### 🚀 一键批量安装
|
### 🚀 交互式插件选择
|
||||||
- 从任意公开 GitHub 仓库用一条命令安装多个插件
|
- 基于 OpenWebUI 的 `execute` 事件打开自定义浏览器选择对话框
|
||||||
- 自动发现插件并进行验证
|
- 显示过滤后的插件列表、仓库信息与排除提示
|
||||||
- 无缝更新已安装的插件
|
- 只安装用户保留勾选的插件
|
||||||
|
|
||||||
### ✅ 智能安全保障
|
### ✅ 智能安全保障
|
||||||
- 安装前显示插件列表确认对话框
|
- 用更丰富的选择流程替代基础 confirmation 事件
|
||||||
- 用户可在安装前查看和审批
|
- 用户无需改写请求,也能取消勾选不想安装的插件
|
||||||
- 自动排除工具自身,避免重复安装
|
- 自动排除工具自身,避免重复安装
|
||||||
|
|
||||||
### 🌍 多仓库支持
|
### 🌍 多仓库支持
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
```
|
```
|
||||||
"安装 Fu-Jie/openwebui-extensions 中的所有插件"
|
"安装 Fu-Jie/openwebui-extensions 中的所有插件"
|
||||||
```
|
```
|
||||||
查看确认对话框,批准后开始安装。
|
查看选择对话框,保留想安装的勾选项后开始安装。
|
||||||
|
|
||||||
2. **再添加社区合集**
|
2. **再添加社区合集**
|
||||||
```
|
```
|
||||||
@@ -110,8 +110,8 @@ OpenRouter API pipe 集成,提供高级模型访问。
|
|||||||
|
|
||||||
- **异步架构**:非阻塞 I/O,性能更优
|
- **异步架构**:非阻塞 I/O,性能更优
|
||||||
- **httpx 集成**:现代化异步 HTTP 客户端,包含超时保护
|
- **httpx 集成**:现代化异步 HTTP 客户端,包含超时保护
|
||||||
- **完整测试**:8 个回归测试,100% 通过率
|
- **选择性安装流程**:安装循环只会处理用户最终勾选的插件子集
|
||||||
- **完整事件支持**:正确处理 OpenWebUI 事件注入,提供回退机制
|
- **完整事件支持**:正确处理 OpenWebUI `execute` 事件,并保留回退行为
|
||||||
|
|
||||||
## 安装方法
|
## 安装方法
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ OpenRouter API pipe 集成,提供高级模型访问。
|
|||||||
## 相关链接
|
## 相关链接
|
||||||
|
|
||||||
- **GitHub 仓库**:https://github.com/Fu-Jie/openwebui-extensions/tree/main/plugins/tools/batch-install-plugins
|
- **GitHub 仓库**:https://github.com/Fu-Jie/openwebui-extensions/tree/main/plugins/tools/batch-install-plugins
|
||||||
- **发布说明**:https://github.com/Fu-Jie/openwebui-extensions/blob/main/plugins/tools/batch-install-plugins/v1.0.0_CN.md
|
- **发布说明**:https://github.com/Fu-Jie/openwebui-extensions/blob/main/plugins/tools/batch-install-plugins/v1.1.0_CN.md
|
||||||
|
|
||||||
## 社区支持
|
## 社区支持
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Batch Install Plugins from GitHub
|
# Batch Install Plugins from GitHub
|
||||||
|
|
||||||
| By [Fu-Jie](https://github.com/Fu-Jie) · v1.0.0 | [⭐ Star this repo](https://github.com/Fu-Jie/openwebui-extensions) |
|
| By [Fu-Jie](https://github.com/Fu-Jie) · v1.1.0 | [⭐ Star this repo](https://github.com/Fu-Jie/openwebui-extensions) |
|
||||||
| :--- | ---: |
|
| :--- | ---: |
|
||||||
|
|
||||||
|  |  |  |  |  |  |  |
|
|  |  |  |  |  |  |  |
|
||||||
@@ -14,7 +14,7 @@ One-click batch install plugins from GitHub repositories to your OpenWebUI insta
|
|||||||
- **Auto-Update**: Automatically updates previously installed plugins
|
- **Auto-Update**: Automatically updates previously installed plugins
|
||||||
- **Public GitHub Support**: Install plugins from any public GitHub repository
|
- **Public GitHub Support**: Install plugins from any public GitHub repository
|
||||||
- **Multi-Type Support**: Supports Pipe, Action, Filter, and Tool plugins
|
- **Multi-Type Support**: Supports Pipe, Action, Filter, and Tool plugins
|
||||||
- **Confirmation**: Shows plugin list before installing, allows selective installation
|
- **Interactive Selection Dialog**: Review the filtered list, check the plugins you want, then install only that subset
|
||||||
- **i18n**: Supports 11 languages
|
- **i18n**: Supports 11 languages
|
||||||
|
|
||||||
## Flow
|
## Flow
|
||||||
@@ -36,8 +36,8 @@ User Input
|
|||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
┌─────────────────────────────────────┐
|
┌─────────────────────────────────────┐
|
||||||
│ Show Confirmation Dialog │
|
│ Show Selection Dialog │
|
||||||
│ (list plugins + exclude hint) │
|
│ (checkbox list + exclude hint) │
|
||||||
└─────────────────────────────────────┘
|
└─────────────────────────────────────┘
|
||||||
│
|
│
|
||||||
├── [Cancel] → End
|
├── [Cancel] → End
|
||||||
@@ -63,6 +63,8 @@ User Input
|
|||||||
|
|
||||||
Each request handles one repository. To mix repositories, send another request after the previous installation completes.
|
Each request handles one repository. To mix repositories, send another request after the previous installation completes.
|
||||||
|
|
||||||
|
After plugin discovery and filtering, OpenWebUI opens a browser dialog built with the `execute` event so you can check exactly which plugins to install before the API calls start.
|
||||||
|
|
||||||
## Quick Start: Install Popular Collections
|
## Quick Start: Install Popular Collections
|
||||||
|
|
||||||
Copy any of these prompts and paste them into your chat:
|
Copy any of these prompts and paste them into your chat:
|
||||||
@@ -131,11 +133,11 @@ For other repositories:
|
|||||||
| `SKIP_KEYWORDS` | `test,verify,example,template,mock` | Comma-separated keywords to skip |
|
| `SKIP_KEYWORDS` | `test,verify,example,template,mock` | Comma-separated keywords to skip |
|
||||||
| `TIMEOUT` | `20` | Request timeout in seconds |
|
| `TIMEOUT` | `20` | Request timeout in seconds |
|
||||||
|
|
||||||
## Confirmation Timeout
|
## Selection Dialog Timeout
|
||||||
|
|
||||||
User confirmation dialogs have a default timeout of **2 minutes (120 seconds)**, allowing sufficient time for users to:
|
The plugin selection dialog has a default timeout of **2 minutes (120 seconds)**, allowing sufficient time for users to:
|
||||||
- Read and review the plugin list
|
- Read and review the plugin list
|
||||||
- Make installation decisions
|
- Check or uncheck the plugins they want
|
||||||
- Handle network delays
|
- Handle network delays
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Batch Install Plugins from GitHub
|
# Batch Install Plugins from GitHub
|
||||||
|
|
||||||
| 作者:[Fu-Jie](https://github.com/Fu-Jie) · v1.0.0 | [⭐ 点个 Star 支持项目](https://github.com/Fu-Jie/openwebui-extensions) |
|
| 作者:[Fu-Jie](https://github.com/Fu-Jie) · v1.1.0 | [⭐ 点个 Star 支持项目](https://github.com/Fu-Jie/openwebui-extensions) |
|
||||||
| :--- | ---: |
|
| :--- | ---: |
|
||||||
|
|
||||||
|  |  |  |  |  |  |  |
|
|  |  |  |  |  |  |  |
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
- 自动更新:自动更新之前安装过的插件
|
- 自动更新:自动更新之前安装过的插件
|
||||||
- 公开 GitHub 支持:支持从任何公开 GitHub 仓库安装插件
|
- 公开 GitHub 支持:支持从任何公开 GitHub 仓库安装插件
|
||||||
- 多类型支持:支持 Pipe、Action、Filter 和 Tool 插件
|
- 多类型支持:支持 Pipe、Action、Filter 和 Tool 插件
|
||||||
- 安装确认:安装前显示插件列表,支持选择性安装
|
- 交互式选择对话框:先查看过滤后的列表,再勾选要安装的插件,只安装所选子集
|
||||||
- 国际化:支持 11 种语言
|
- 国际化:支持 11 种语言
|
||||||
|
|
||||||
## 流程
|
## 流程
|
||||||
@@ -36,8 +36,8 @@
|
|||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
┌─────────────────────────────────────┐
|
┌─────────────────────────────────────┐
|
||||||
│ 显示确认对话框 │
|
│ 显示选择对话框 │
|
||||||
│ (插件列表 + 排除提示) │
|
│ (复选列表 + 排除提示) │
|
||||||
└─────────────────────────────────────┘
|
└─────────────────────────────────────┘
|
||||||
│
|
│
|
||||||
├── [取消] → 结束
|
├── [取消] → 结束
|
||||||
@@ -63,6 +63,8 @@
|
|||||||
|
|
||||||
每次请求处理一个仓库。如需混合多个来源,请在上一次安装完成后再发起下一次请求。
|
每次请求处理一个仓库。如需混合多个来源,请在上一次安装完成后再发起下一次请求。
|
||||||
|
|
||||||
|
在插件发现和过滤完成后,OpenWebUI 会通过 `execute` 事件打开浏览器选择对话框,你可以先勾选真正想安装的插件,再开始调用安装 API。
|
||||||
|
|
||||||
## 快速开始:安装热门插件集
|
## 快速开始:安装热门插件集
|
||||||
|
|
||||||
复制以下任一提示词,粘贴到你的对话框中:
|
复制以下任一提示词,粘贴到你的对话框中:
|
||||||
@@ -131,11 +133,11 @@
|
|||||||
| `SKIP_KEYWORDS` | `test,verify,example,template,mock` | 逗号分隔的跳过关键词 |
|
| `SKIP_KEYWORDS` | `test,verify,example,template,mock` | 逗号分隔的跳过关键词 |
|
||||||
| `TIMEOUT` | `20` | 请求超时时间(秒)|
|
| `TIMEOUT` | `20` | 请求超时时间(秒)|
|
||||||
|
|
||||||
## 确认超时时间
|
## 选择对话框超时时间
|
||||||
|
|
||||||
用户确认对话框的默认超时时间为 **2 分钟(120 秒)**,为用户提供充足的时间来:
|
插件选择对话框的默认超时时间为 **2 分钟(120 秒)**,为用户提供充足的时间来:
|
||||||
- 阅读和查看插件列表
|
- 阅读和查看插件列表
|
||||||
- 做出安装决定
|
- 勾选或取消勾选想安装的插件
|
||||||
- 处理网络延迟
|
- 处理网络延迟
|
||||||
|
|
||||||
## 支持
|
## 支持
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ title: Batch Install Plugins from GitHub
|
|||||||
author: Fu-Jie
|
author: Fu-Jie
|
||||||
author_url: https://github.com/Fu-Jie/openwebui-extensions
|
author_url: https://github.com/Fu-Jie/openwebui-extensions
|
||||||
funding_url: https://github.com/open-webui
|
funding_url: https://github.com/open-webui
|
||||||
version: 1.0.0
|
version: 1.1.0
|
||||||
|
openwebui_id: c9fd6e80-d58f-4312-8fbb-214d86bbe599
|
||||||
description: One-click batch install plugins from GitHub repositories to your OpenWebUI instance.
|
description: One-click batch install plugins from GitHub repositories to your OpenWebUI instance.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -298,6 +299,119 @@ TRANSLATIONS = {
|
|||||||
|
|
||||||
FALLBACK_MAP = {"zh": "zh-CN", "zh-TW": "zh-TW", "zh-HK": "zh-HK", "en": "en-US", "ko": "ko-KR", "ja": "ja-JP", "fr": "fr-FR", "de": "de-DE", "es": "es-ES", "it": "it-IT", "vi": "vi-VN"}
|
FALLBACK_MAP = {"zh": "zh-CN", "zh-TW": "zh-TW", "zh-HK": "zh-HK", "en": "en-US", "ko": "ko-KR", "ja": "ja-JP", "fr": "fr-FR", "de": "de-DE", "es": "es-ES", "it": "it-IT", "vi": "vi-VN"}
|
||||||
|
|
||||||
|
SELECTION_DIALOG_TEXTS = {
|
||||||
|
"en-US": {
|
||||||
|
"select_all": "Select all",
|
||||||
|
"clear_all": "Clear all",
|
||||||
|
"selected_count": "{count} selected",
|
||||||
|
"install_selected": "Install Selected",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"version_label": "Version",
|
||||||
|
"file_label": "File",
|
||||||
|
"repo_label": "Repository",
|
||||||
|
},
|
||||||
|
"zh-CN": {
|
||||||
|
"select_all": "全选",
|
||||||
|
"clear_all": "清空",
|
||||||
|
"selected_count": "已选 {count} 项",
|
||||||
|
"install_selected": "安装所选插件",
|
||||||
|
"cancel": "取消",
|
||||||
|
"version_label": "版本",
|
||||||
|
"file_label": "文件",
|
||||||
|
"repo_label": "仓库",
|
||||||
|
},
|
||||||
|
"zh-HK": {
|
||||||
|
"select_all": "全選",
|
||||||
|
"clear_all": "清空",
|
||||||
|
"selected_count": "已選 {count} 項",
|
||||||
|
"install_selected": "安裝所選外掛",
|
||||||
|
"cancel": "取消",
|
||||||
|
"version_label": "版本",
|
||||||
|
"file_label": "檔案",
|
||||||
|
"repo_label": "倉庫",
|
||||||
|
},
|
||||||
|
"zh-TW": {
|
||||||
|
"select_all": "全選",
|
||||||
|
"clear_all": "清空",
|
||||||
|
"selected_count": "已選 {count} 項",
|
||||||
|
"install_selected": "安裝所選外掛",
|
||||||
|
"cancel": "取消",
|
||||||
|
"version_label": "版本",
|
||||||
|
"file_label": "檔案",
|
||||||
|
"repo_label": "倉庫",
|
||||||
|
},
|
||||||
|
"ko-KR": {
|
||||||
|
"select_all": "전체 선택",
|
||||||
|
"clear_all": "선택 해제",
|
||||||
|
"selected_count": "{count}개 선택됨",
|
||||||
|
"install_selected": "선택한 플러그인 설치",
|
||||||
|
"cancel": "취소",
|
||||||
|
"version_label": "버전",
|
||||||
|
"file_label": "파일",
|
||||||
|
"repo_label": "저장소",
|
||||||
|
},
|
||||||
|
"ja-JP": {
|
||||||
|
"select_all": "すべて選択",
|
||||||
|
"clear_all": "クリア",
|
||||||
|
"selected_count": "{count}件を選択",
|
||||||
|
"install_selected": "選択したプラグインをインストール",
|
||||||
|
"cancel": "キャンセル",
|
||||||
|
"version_label": "バージョン",
|
||||||
|
"file_label": "ファイル",
|
||||||
|
"repo_label": "リポジトリ",
|
||||||
|
},
|
||||||
|
"fr-FR": {
|
||||||
|
"select_all": "Tout sélectionner",
|
||||||
|
"clear_all": "Tout effacer",
|
||||||
|
"selected_count": "{count} sélectionnés",
|
||||||
|
"install_selected": "Installer la sélection",
|
||||||
|
"cancel": "Annuler",
|
||||||
|
"version_label": "Version",
|
||||||
|
"file_label": "Fichier",
|
||||||
|
"repo_label": "Dépôt",
|
||||||
|
},
|
||||||
|
"de-DE": {
|
||||||
|
"select_all": "Alle auswählen",
|
||||||
|
"clear_all": "Auswahl löschen",
|
||||||
|
"selected_count": "{count} ausgewählt",
|
||||||
|
"install_selected": "Auswahl installieren",
|
||||||
|
"cancel": "Abbrechen",
|
||||||
|
"version_label": "Version",
|
||||||
|
"file_label": "Datei",
|
||||||
|
"repo_label": "Repository",
|
||||||
|
},
|
||||||
|
"es-ES": {
|
||||||
|
"select_all": "Seleccionar todo",
|
||||||
|
"clear_all": "Limpiar",
|
||||||
|
"selected_count": "{count} seleccionados",
|
||||||
|
"install_selected": "Instalar seleccionados",
|
||||||
|
"cancel": "Cancelar",
|
||||||
|
"version_label": "Versión",
|
||||||
|
"file_label": "Archivo",
|
||||||
|
"repo_label": "Repositorio",
|
||||||
|
},
|
||||||
|
"it-IT": {
|
||||||
|
"select_all": "Seleziona tutto",
|
||||||
|
"clear_all": "Cancella",
|
||||||
|
"selected_count": "{count} selezionati",
|
||||||
|
"install_selected": "Installa selezionati",
|
||||||
|
"cancel": "Annulla",
|
||||||
|
"version_label": "Versione",
|
||||||
|
"file_label": "File",
|
||||||
|
"repo_label": "Repository",
|
||||||
|
},
|
||||||
|
"vi-VN": {
|
||||||
|
"select_all": "Chọn tất cả",
|
||||||
|
"clear_all": "Bỏ chọn",
|
||||||
|
"selected_count": "Đã chọn {count}",
|
||||||
|
"install_selected": "Cài đặt mục đã chọn",
|
||||||
|
"cancel": "Hủy",
|
||||||
|
"version_label": "Phiên bản",
|
||||||
|
"file_label": "Tệp",
|
||||||
|
"repo_label": "Kho",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def _resolve_language(user_language: str) -> str:
|
def _resolve_language(user_language: str) -> str:
|
||||||
value = str(user_language or "").strip()
|
value = str(user_language or "").strip()
|
||||||
@@ -322,6 +436,19 @@ def _t(lang: str, key: str, **kwargs) -> str:
|
|||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def _selection_t(lang: str, key: str, **kwargs) -> str:
|
||||||
|
lang_key = _resolve_language(lang)
|
||||||
|
text = SELECTION_DIALOG_TEXTS.get(
|
||||||
|
lang_key, SELECTION_DIALOG_TEXTS["en-US"]
|
||||||
|
).get(key, SELECTION_DIALOG_TEXTS["en-US"][key])
|
||||||
|
if kwargs:
|
||||||
|
try:
|
||||||
|
text = text.format(**kwargs)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
async def _emit_status(emitter: Optional[Any], description: str, done: bool = False) -> None:
|
async def _emit_status(emitter: Optional[Any], description: str, done: bool = False) -> None:
|
||||||
if emitter:
|
if emitter:
|
||||||
await emitter(
|
await emitter(
|
||||||
@@ -738,35 +865,242 @@ def _build_confirmation_hint(lang: str, repo: str, exclude_keywords: str) -> str
|
|||||||
return _t(lang, "confirm_copy_exclude_hint", keywords=SELF_EXCLUDE_HINT)
|
return _t(lang, "confirm_copy_exclude_hint", keywords=SELF_EXCLUDE_HINT)
|
||||||
|
|
||||||
|
|
||||||
async def _request_confirmation(
|
def _build_selection_dialog_js(
|
||||||
|
options: List[Dict[str, str]],
|
||||||
|
ui_text: Dict[str, str],
|
||||||
|
) -> str:
|
||||||
|
lines = [
|
||||||
|
"return new Promise((resolve) => {",
|
||||||
|
" try {",
|
||||||
|
f" const options = {json.dumps(options, ensure_ascii=False)};",
|
||||||
|
f" const ui = {json.dumps(ui_text, ensure_ascii=False)};",
|
||||||
|
" const dialogId = 'batch-install-plugin-selector';",
|
||||||
|
" const body = typeof document !== 'undefined' ? document.body : null;",
|
||||||
|
" const existing = body ? document.getElementById(dialogId) : null;",
|
||||||
|
" if (existing) { existing.remove(); }",
|
||||||
|
" if (!body) {",
|
||||||
|
" resolve({ confirmed: false, error: 'document.body unavailable', selected_ids: [] });",
|
||||||
|
" return;",
|
||||||
|
" }",
|
||||||
|
" const selected = new Set(options.map((item) => item.id));",
|
||||||
|
" const escapeHtml = (value) => String(value ?? '').replace(/[&<>\"']/g, (char) => ({",
|
||||||
|
" '&': '&',",
|
||||||
|
" '<': '<',",
|
||||||
|
" '>': '>',",
|
||||||
|
" '\"': '"',",
|
||||||
|
" \"'\": ''',",
|
||||||
|
" }[char]));",
|
||||||
|
" const overlay = document.createElement('div');",
|
||||||
|
" overlay.id = dialogId;",
|
||||||
|
" overlay.style.cssText = [",
|
||||||
|
" 'position:fixed',",
|
||||||
|
" 'inset:0',",
|
||||||
|
" 'padding:24px',",
|
||||||
|
" 'background:rgba(15,23,42,0.52)',",
|
||||||
|
" 'backdrop-filter:blur(3px)',",
|
||||||
|
" 'display:flex',",
|
||||||
|
" 'align-items:center',",
|
||||||
|
" 'justify-content:center',",
|
||||||
|
" 'z-index:9999',",
|
||||||
|
" 'box-sizing:border-box',",
|
||||||
|
" ].join(';');",
|
||||||
|
" overlay.innerHTML = `",
|
||||||
|
" <div style=\"width:min(920px,100%);max-height:min(88vh,900px);overflow:hidden;border-radius:18px;background:#ffffff;box-shadow:0 30px 80px rgba(15,23,42,0.28);display:flex;flex-direction:column;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif\">",
|
||||||
|
" <div style=\"padding:22px 24px 16px;border-bottom:1px solid #e5e7eb\">",
|
||||||
|
" <div style=\"display:flex;justify-content:space-between;gap:16px;align-items:flex-start;flex-wrap:wrap\">",
|
||||||
|
" <div>",
|
||||||
|
" <div style=\"font-size:22px;font-weight:700;color:#0f172a\">${escapeHtml(ui.title)}</div>",
|
||||||
|
" <div style=\"margin-top:8px;font-size:14px;color:#475569\">${escapeHtml(ui.list_title)}</div>",
|
||||||
|
" </div>",
|
||||||
|
" <div style=\"display:inline-flex;align-items:center;gap:8px;border-radius:999px;background:#eff6ff;color:#1d4ed8;padding:8px 12px;font-size:12px;font-weight:600\">",
|
||||||
|
" <span>${escapeHtml(ui.repo_label)}</span>",
|
||||||
|
" <span>${escapeHtml(ui.repo)}</span>",
|
||||||
|
" </div>",
|
||||||
|
" </div>",
|
||||||
|
" <div id=\"batch-install-plugin-selector-hint\" style=\"margin-top:14px;padding:12px 14px;border-radius:12px;background:#f8fafc;color:#334155;font-size:13px;line-height:1.5;white-space:pre-wrap\"></div>",
|
||||||
|
" </div>",
|
||||||
|
" <div style=\"padding:16px 24px 0;display:flex;justify-content:space-between;gap:12px;align-items:center;flex-wrap:wrap\">",
|
||||||
|
" <div style=\"display:flex;gap:8px;flex-wrap:wrap\">",
|
||||||
|
" <button id=\"batch-install-plugin-selector-select-all\" style=\"padding:8px 12px;border:1px solid #cbd5e1;border-radius:10px;background:#fff;color:#0f172a;font-size:13px;cursor:pointer\">${escapeHtml(ui.select_all)}</button>",
|
||||||
|
" <button id=\"batch-install-plugin-selector-clear-all\" style=\"padding:8px 12px;border:1px solid #cbd5e1;border-radius:10px;background:#fff;color:#0f172a;font-size:13px;cursor:pointer\">${escapeHtml(ui.clear_all)}</button>",
|
||||||
|
" </div>",
|
||||||
|
" <div id=\"batch-install-plugin-selector-count\" style=\"font-size:13px;font-weight:600;color:#475569\"></div>",
|
||||||
|
" </div>",
|
||||||
|
" <div id=\"batch-install-plugin-selector-list\" style=\"padding:16px 24px 0;overflow:auto;display:grid;gap:12px;flex:1;min-height:0\"></div>",
|
||||||
|
" <div style=\"padding:18px 24px 24px;border-top:1px solid #e5e7eb;margin-top:18px;display:flex;justify-content:flex-end;gap:12px;flex-wrap:wrap\">",
|
||||||
|
" <button id=\"batch-install-plugin-selector-cancel\" style=\"padding:10px 16px;border:1px solid #cbd5e1;border-radius:10px;background:#fff;color:#0f172a;font-weight:600;cursor:pointer\">${escapeHtml(ui.cancel)}</button>",
|
||||||
|
" <button id=\"batch-install-plugin-selector-submit\" style=\"padding:10px 16px;border:none;border-radius:10px;background:#0f172a;color:#fff;font-weight:600;cursor:pointer\">${escapeHtml(ui.install_selected)}</button>",
|
||||||
|
" </div>",
|
||||||
|
" </div>",
|
||||||
|
" `;",
|
||||||
|
" body.appendChild(overlay);",
|
||||||
|
" const previousOverflow = body.style.overflow;",
|
||||||
|
" body.style.overflow = 'hidden';",
|
||||||
|
" const listEl = overlay.querySelector('#batch-install-plugin-selector-list');",
|
||||||
|
" const countEl = overlay.querySelector('#batch-install-plugin-selector-count');",
|
||||||
|
" const hintEl = overlay.querySelector('#batch-install-plugin-selector-hint');",
|
||||||
|
" const submitBtn = overlay.querySelector('#batch-install-plugin-selector-submit');",
|
||||||
|
" const cancelBtn = overlay.querySelector('#batch-install-plugin-selector-cancel');",
|
||||||
|
" const selectAllBtn = overlay.querySelector('#batch-install-plugin-selector-select-all');",
|
||||||
|
" const clearAllBtn = overlay.querySelector('#batch-install-plugin-selector-clear-all');",
|
||||||
|
" hintEl.textContent = ui.hint || '';",
|
||||||
|
" hintEl.style.display = ui.hint ? 'block' : 'none';",
|
||||||
|
" const updateState = () => {",
|
||||||
|
" countEl.textContent = ui.selected_count.replace('{count}', String(selected.size));",
|
||||||
|
" submitBtn.disabled = selected.size === 0;",
|
||||||
|
" submitBtn.style.opacity = selected.size === 0 ? '0.45' : '1';",
|
||||||
|
" submitBtn.style.cursor = selected.size === 0 ? 'not-allowed' : 'pointer';",
|
||||||
|
" };",
|
||||||
|
" const renderList = () => {",
|
||||||
|
" listEl.innerHTML = options.map((item) => {",
|
||||||
|
" const checked = selected.has(item.id) ? 'checked' : '';",
|
||||||
|
" return `",
|
||||||
|
" <label style=\"display:flex;gap:14px;align-items:flex-start;padding:14px;border:1px solid #e2e8f0;border-radius:14px;background:#fff;cursor:pointer\">",
|
||||||
|
" <input type=\"checkbox\" data-plugin-id=\"${escapeHtml(item.id)}\" ${checked} style=\"margin-top:3px;width:16px;height:16px;accent-color:#0f172a;flex-shrink:0\" />",
|
||||||
|
" <div style=\"min-width:0;display:grid;gap:6px\">",
|
||||||
|
" <div style=\"display:flex;gap:10px;align-items:center;flex-wrap:wrap\">",
|
||||||
|
" <span style=\"display:inline-flex;align-items:center;padding:2px 8px;border-radius:999px;background:#f1f5f9;color:#334155;font-size:12px;font-weight:700;text-transform:uppercase\">${escapeHtml(item.type)}</span>",
|
||||||
|
" <span style=\"font-size:15px;font-weight:700;color:#0f172a;word-break:break-word\">${escapeHtml(item.title)}</span>",
|
||||||
|
" </div>",
|
||||||
|
" <div style=\"font-size:12px;color:#475569;word-break:break-word\">${escapeHtml(ui.version_label)}: ${escapeHtml(item.version)} · ${escapeHtml(ui.file_label)}: ${escapeHtml(item.file_path)}</div>",
|
||||||
|
" </div>",
|
||||||
|
" </label>",
|
||||||
|
" `;",
|
||||||
|
" }).join('');",
|
||||||
|
" listEl.querySelectorAll('input[data-plugin-id]').forEach((input) => {",
|
||||||
|
" input.addEventListener('change', () => {",
|
||||||
|
" const pluginId = input.getAttribute('data-plugin-id') || '';",
|
||||||
|
" if (input.checked) {",
|
||||||
|
" selected.add(pluginId);",
|
||||||
|
" } else {",
|
||||||
|
" selected.delete(pluginId);",
|
||||||
|
" }",
|
||||||
|
" updateState();",
|
||||||
|
" });",
|
||||||
|
" });",
|
||||||
|
" updateState();",
|
||||||
|
" };",
|
||||||
|
" const cleanup = () => {",
|
||||||
|
" body.style.overflow = previousOverflow;",
|
||||||
|
" window.removeEventListener('keydown', onKeyDown, true);",
|
||||||
|
" overlay.remove();",
|
||||||
|
" };",
|
||||||
|
" const finish = (confirmed) => {",
|
||||||
|
" const selectedIds = confirmed ? options.filter((item) => selected.has(item.id)).map((item) => item.id) : [];",
|
||||||
|
" cleanup();",
|
||||||
|
" resolve({ confirmed, selected_ids: selectedIds });",
|
||||||
|
" };",
|
||||||
|
" const onKeyDown = (event) => {",
|
||||||
|
" if (event.key === 'Escape') {",
|
||||||
|
" event.preventDefault();",
|
||||||
|
" finish(false);",
|
||||||
|
" }",
|
||||||
|
" };",
|
||||||
|
" overlay.addEventListener('click', (event) => {",
|
||||||
|
" if (event.target === overlay) {",
|
||||||
|
" finish(false);",
|
||||||
|
" }",
|
||||||
|
" });",
|
||||||
|
" selectAllBtn.addEventListener('click', () => {",
|
||||||
|
" options.forEach((item) => selected.add(item.id));",
|
||||||
|
" renderList();",
|
||||||
|
" });",
|
||||||
|
" clearAllBtn.addEventListener('click', () => {",
|
||||||
|
" selected.clear();",
|
||||||
|
" renderList();",
|
||||||
|
" });",
|
||||||
|
" cancelBtn.addEventListener('click', () => finish(false));",
|
||||||
|
" submitBtn.addEventListener('click', () => {",
|
||||||
|
" if (selected.size === 0) {",
|
||||||
|
" updateState();",
|
||||||
|
" return;",
|
||||||
|
" }",
|
||||||
|
" finish(true);",
|
||||||
|
" });",
|
||||||
|
" window.addEventListener('keydown', onKeyDown, true);",
|
||||||
|
" renderList();",
|
||||||
|
" } catch (error) {",
|
||||||
|
" console.error('[Batch Install] Plugin selection dialog failed', error);",
|
||||||
|
" resolve({",
|
||||||
|
" confirmed: false,",
|
||||||
|
" error: error instanceof Error ? error.message : String(error),",
|
||||||
|
" selected_ids: [],",
|
||||||
|
" });",
|
||||||
|
" }",
|
||||||
|
"});",
|
||||||
|
]
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
async def _request_plugin_selection(
|
||||||
event_call: Optional[Any],
|
event_call: Optional[Any],
|
||||||
lang: str,
|
lang: str,
|
||||||
message: str,
|
repo: str,
|
||||||
) -> Tuple[bool, Optional[str]]:
|
candidates: List[PluginCandidate],
|
||||||
|
hint: str,
|
||||||
|
) -> Tuple[Optional[List[PluginCandidate]], Optional[str]]:
|
||||||
if not event_call:
|
if not event_call:
|
||||||
return True, None
|
return candidates, None
|
||||||
|
|
||||||
|
options = [
|
||||||
|
{
|
||||||
|
"id": candidate.function_id,
|
||||||
|
"title": candidate.title,
|
||||||
|
"type": candidate.plugin_type,
|
||||||
|
"version": candidate.version,
|
||||||
|
"file_path": candidate.file_path,
|
||||||
|
}
|
||||||
|
for candidate in candidates
|
||||||
|
]
|
||||||
|
ui_text = {
|
||||||
|
"title": _t(lang, "confirm_title"),
|
||||||
|
"list_title": _t(lang, "status_list_title", count=len(candidates)),
|
||||||
|
"repo_label": _selection_t(lang, "repo_label"),
|
||||||
|
"repo": repo,
|
||||||
|
"hint": hint.strip(),
|
||||||
|
"select_all": _selection_t(lang, "select_all"),
|
||||||
|
"clear_all": _selection_t(lang, "clear_all"),
|
||||||
|
"selected_count": _selection_t(lang, "selected_count", count="{count}"),
|
||||||
|
"install_selected": _selection_t(lang, "install_selected"),
|
||||||
|
"cancel": _selection_t(lang, "cancel"),
|
||||||
|
"version_label": _selection_t(lang, "version_label"),
|
||||||
|
"file_label": _selection_t(lang, "file_label"),
|
||||||
|
}
|
||||||
|
js_code = _build_selection_dialog_js(options, ui_text)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
confirmed = await asyncio.wait_for(
|
result = await asyncio.wait_for(
|
||||||
event_call(
|
event_call({"type": "execute", "data": {"code": js_code}}),
|
||||||
{
|
|
||||||
"type": "confirmation",
|
|
||||||
"data": {
|
|
||||||
"title": _t(lang, "confirm_title"),
|
|
||||||
"message": message,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
),
|
|
||||||
timeout=CONFIRMATION_TIMEOUT,
|
timeout=CONFIRMATION_TIMEOUT,
|
||||||
)
|
)
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
logger.warning("Installation confirmation timed out.")
|
logger.warning("Installation selection dialog timed out.")
|
||||||
return False, _t(lang, "err_confirm_unavailable")
|
return None, _t(lang, "err_confirm_unavailable")
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning("Installation confirmation failed: %s", exc)
|
logger.warning("Installation selection dialog failed: %s", exc)
|
||||||
return False, _t(lang, "err_confirm_unavailable")
|
return None, _t(lang, "err_confirm_unavailable")
|
||||||
|
|
||||||
return bool(confirmed), None
|
if not isinstance(result, dict):
|
||||||
|
logger.warning("Unexpected selection dialog result: %r", result)
|
||||||
|
return None, _t(lang, "err_confirm_unavailable")
|
||||||
|
|
||||||
|
if result.get("error"):
|
||||||
|
logger.warning("Selection dialog returned error: %s", result.get("error"))
|
||||||
|
return None, _t(lang, "err_confirm_unavailable")
|
||||||
|
|
||||||
|
if not result.get("confirmed"):
|
||||||
|
return [], None
|
||||||
|
|
||||||
|
selected_ids = result.get("selected_ids")
|
||||||
|
if not isinstance(selected_ids, list):
|
||||||
|
logger.warning("Selection dialog returned invalid selected_ids: %r", selected_ids)
|
||||||
|
return None, _t(lang, "err_confirm_unavailable")
|
||||||
|
|
||||||
|
selected_id_set = {str(item).strip() for item in selected_ids if str(item).strip()}
|
||||||
|
selected_candidates = [
|
||||||
|
candidate for candidate in candidates if candidate.function_id in selected_id_set
|
||||||
|
]
|
||||||
|
return selected_candidates, None
|
||||||
|
|
||||||
|
|
||||||
def parse_github_url(url: str) -> Optional[Tuple[str, str, str]]:
|
def parse_github_url(url: str) -> Optional[Tuple[str, str, str]]:
|
||||||
@@ -1039,24 +1373,15 @@ class Tools:
|
|||||||
event_emitter, _t(lang, "err_no_match"), notification_type="warning"
|
event_emitter, _t(lang, "err_no_match"), notification_type="warning"
|
||||||
)
|
)
|
||||||
|
|
||||||
plugin_list = "\n".join([f"- [{c.plugin_type}] {c.title}" for c in filtered])
|
|
||||||
hint_msg = _build_confirmation_hint(lang, repo, exclude_keywords)
|
hint_msg = _build_confirmation_hint(lang, repo, exclude_keywords)
|
||||||
confirm_msg = _t(
|
selected_candidates, confirm_error = await _request_plugin_selection(
|
||||||
lang,
|
__event_call__, lang, repo, filtered, hint_msg
|
||||||
"confirm_message",
|
|
||||||
count=len(filtered),
|
|
||||||
plugin_list=plugin_list,
|
|
||||||
hint=hint_msg,
|
|
||||||
)
|
|
||||||
|
|
||||||
confirmed, confirm_error = await _request_confirmation(
|
|
||||||
__event_call__, lang, confirm_msg
|
|
||||||
)
|
)
|
||||||
if confirm_error:
|
if confirm_error:
|
||||||
return await _finalize_message(
|
return await _finalize_message(
|
||||||
event_emitter, confirm_error, notification_type="warning"
|
event_emitter, confirm_error, notification_type="warning"
|
||||||
)
|
)
|
||||||
if not confirmed:
|
if not selected_candidates:
|
||||||
return await _finalize_message(
|
return await _finalize_message(
|
||||||
event_emitter,
|
event_emitter,
|
||||||
_t(lang, "confirm_cancelled"),
|
_t(lang, "confirm_cancelled"),
|
||||||
@@ -1070,7 +1395,7 @@ class Tools:
|
|||||||
"repo": repo,
|
"repo": repo,
|
||||||
"base_url": base_url,
|
"base_url": base_url,
|
||||||
"note": "Backend uses default port 8080 (containerized environment)",
|
"note": "Backend uses default port 8080 (containerized environment)",
|
||||||
"plugin_count": len(filtered),
|
"plugin_count": len(selected_candidates),
|
||||||
"plugin_types": plugin_types,
|
"plugin_types": plugin_types,
|
||||||
"exclude_keywords": exclude_keywords,
|
"exclude_keywords": exclude_keywords,
|
||||||
"timeout": timeout,
|
"timeout": timeout,
|
||||||
@@ -1092,7 +1417,7 @@ class Tools:
|
|||||||
async with httpx.AsyncClient(
|
async with httpx.AsyncClient(
|
||||||
timeout=httpx.Timeout(timeout), follow_redirects=True
|
timeout=httpx.Timeout(timeout), follow_redirects=True
|
||||||
) as client:
|
) as client:
|
||||||
for candidate in filtered:
|
for candidate in selected_candidates:
|
||||||
await _emit_status(
|
await _emit_status(
|
||||||
event_emitter,
|
event_emitter,
|
||||||
_t(
|
_t(
|
||||||
@@ -1341,12 +1666,17 @@ class Tools:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
summary = _t(lang, "status_done", success=success_count, total=len(filtered))
|
summary = _t(
|
||||||
|
lang,
|
||||||
|
"status_done",
|
||||||
|
success=success_count,
|
||||||
|
total=len(selected_candidates),
|
||||||
|
)
|
||||||
output = "\n".join(results + [summary])
|
output = "\n".join(results + [summary])
|
||||||
notification_type = "success"
|
notification_type = "success"
|
||||||
if success_count == 0:
|
if success_count == 0:
|
||||||
notification_type = "error"
|
notification_type = "error"
|
||||||
elif success_count < len(filtered):
|
elif success_count < len(selected_candidates):
|
||||||
notification_type = "warning"
|
notification_type = "warning"
|
||||||
|
|
||||||
await _emit_status(event_emitter, summary, done=True)
|
await _emit_status(event_emitter, summary, done=True)
|
||||||
|
|||||||
33
plugins/tools/batch-install-plugins/v1.1.0.md
Normal file
33
plugins/tools/batch-install-plugins/v1.1.0.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
[](https://openwebui.com/t/fujie/batch_install_plugins)
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Batch Install Plugins from GitHub v1.1.0 upgrades the install confirmation step into an interactive plugin picker powered by the OpenWebUI `execute` event. Users can now review the filtered plugin list in a browser dialog, uncheck anything they do not want, and install only the selected subset.
|
||||||
|
|
||||||
|
**[📖 README](https://github.com/Fu-Jie/openwebui-extensions/blob/main/plugins/tools/batch-install-plugins/README.md)**
|
||||||
|
|
||||||
|
## Highlights
|
||||||
|
|
||||||
|
- **Interactive Selection Dialog**: Opens a checkbox-based browser dialog instead of using the basic confirmation event
|
||||||
|
- **Selective Installation**: The install loop now runs only for the plugins the user keeps selected
|
||||||
|
- **Repository Context**: Displays the current repository and exclusion hint inside the dialog
|
||||||
|
- **Localized UI**: Dialog controls are localized for all supported languages
|
||||||
|
- **No Workflow Regression**: Existing discovery, filtering, auto-update, and fallback connection logic remain unchanged
|
||||||
|
|
||||||
|
## Technical Notes
|
||||||
|
|
||||||
|
- Replaced the install confirmation step with `__event_call__({"type": "execute"})`
|
||||||
|
- Returns a structured payload containing `confirmed` and `selected_ids`
|
||||||
|
- Preserves the existing 120-second timeout for user interaction
|
||||||
|
- Keeps installation ordering aligned with the filtered candidate list
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
|
||||||
|
- Python syntax validated with `python -m py_compile plugins/tools/batch-install-plugins/batch_install_plugins.py`
|
||||||
|
- README and mirrored docs updated to match the new interactive selection flow
|
||||||
|
|
||||||
|
## Upgrade Notes
|
||||||
|
|
||||||
|
- No new Valves are required
|
||||||
|
- Existing prompts continue to work
|
||||||
|
- Users now get a plugin picker before installation begins
|
||||||
33
plugins/tools/batch-install-plugins/v1.1.0_CN.md
Normal file
33
plugins/tools/batch-install-plugins/v1.1.0_CN.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
[](https://openwebui.com/t/fujie/batch_install_plugins)
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
Batch Install Plugins from GitHub v1.1.0 将原本的安装确认步骤升级为基于 OpenWebUI `execute` 事件的交互式插件选择器。现在,用户可以先在浏览器对话框中查看过滤后的插件列表,取消勾选不想安装的项,然后只安装最终选中的插件子集。
|
||||||
|
|
||||||
|
**[📖 README](https://github.com/Fu-Jie/openwebui-extensions/blob/main/plugins/tools/batch-install-plugins/README_CN.md)**
|
||||||
|
|
||||||
|
## 亮点
|
||||||
|
|
||||||
|
- **交互式选择对话框**:不再只使用基础 confirmation 事件,而是打开支持复选框的浏览器对话框
|
||||||
|
- **选择性安装**:安装循环只会处理用户最终保留勾选的插件
|
||||||
|
- **仓库上下文**:对话框中会显示当前仓库与排除提示
|
||||||
|
- **本地化 UI**:对话框控件已为所有支持语言提供本地化文本
|
||||||
|
- **工作流不回退**:原有的插件发现、过滤、自动更新和连接回退逻辑保持不变
|
||||||
|
|
||||||
|
## 技术说明
|
||||||
|
|
||||||
|
- 使用 `__event_call__({"type": "execute"})` 替换安装确认步骤
|
||||||
|
- 返回包含 `confirmed` 与 `selected_ids` 的结构化结果
|
||||||
|
- 保留原有的 120 秒用户交互超时时间
|
||||||
|
- 安装顺序仍与过滤后的候选列表保持一致
|
||||||
|
|
||||||
|
## 验证
|
||||||
|
|
||||||
|
- 已通过 `python -m py_compile plugins/tools/batch-install-plugins/batch_install_plugins.py` 进行 Python 语法校验
|
||||||
|
- README 与镜像文档已同步为新的交互式选择流程
|
||||||
|
|
||||||
|
## 升级说明
|
||||||
|
|
||||||
|
- 不需要新增 Valves
|
||||||
|
- 现有提示词仍可继续使用
|
||||||
|
- 安装开始前会新增一个插件选择器步骤
|
||||||
Reference in New Issue
Block a user