feat: improve batch installer selection dialog

This commit is contained in:
fujie
2026-03-16 14:24:48 +08:00
parent 00afae4a6d
commit 7a2ecee010
11 changed files with 109 additions and 28 deletions

View File

@@ -10,7 +10,7 @@ One-click batch install plugins from GitHub repositories to your OpenWebUI insta
- **Auto-Update**: Automatically updates previously installed plugins
- **Public GitHub Support**: Install plugins from any public GitHub repository
- **Multi-Type Support**: Supports Pipe, Action, Filter, and Tool plugins
- **Interactive Selection Dialog**: Review the filtered list, check the plugins you want, then install only that subset
- **Interactive Selection Dialog**: Review the filtered list with type tags and plugin descriptions, then install only the checked subset
- **i18n**: Supports 11 languages
## Flow
@@ -33,7 +33,7 @@ User Input
┌─────────────────────────────────────┐
│ Show Selection Dialog │
│ (checkbox list + exclude hint)
│ (checkbox list + type tags + desc)
└─────────────────────────────────────┘
├── [Cancel] → End
@@ -59,7 +59,7 @@ User Input
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.
After plugin discovery and filtering, OpenWebUI opens a browser dialog built with the `execute` event so you can review plugin descriptions, use type tags for quick batch selection, and check exactly which plugins to install before the API calls start.
## Quick Start: Install Popular Collections

View File

@@ -10,7 +10,7 @@
- 自动更新:自动更新之前安装过的插件
- 公开 GitHub 支持:支持从任何公开 GitHub 仓库安装插件
- 多类型支持:支持 Pipe、Action、Filter 和 Tool 插件
- 交互式选择对话框:先查看过滤后的列表,再勾选要安装的插件,只安装所选子集
- 交互式选择对话框:先查看带类型标签和描述信息的过滤列表,再勾选要安装的插件,只安装所选子集
- 国际化:支持 11 种语言
## 流程
@@ -33,7 +33,7 @@
┌─────────────────────────────────────┐
│ 显示选择对话框 │
│ (复选列表 + 排除提示)
│ (复选列表 + 类型标签 + 描述)
└─────────────────────────────────────┘
├── [取消] → 结束
@@ -59,7 +59,7 @@
每次请求处理一个仓库。如需混合多个来源,请在上一次安装完成后再发起下一次请求。
在插件发现和过滤完成后OpenWebUI 会通过 `execute` 事件打开浏览器选择对话框你可以先勾选真正想安装的插件,再开始调用安装 API。
在插件发现和过滤完成后OpenWebUI 会通过 `execute` 事件打开浏览器选择对话框你可以先查看插件描述,使用类型标签进行批量勾选,再开始调用安装 API。
## 快速开始:安装热门插件集

View File

@@ -14,7 +14,7 @@ One-click batch install plugins from GitHub repositories to your OpenWebUI insta
- **Auto-Update**: Automatically updates previously installed plugins
- **Public GitHub Support**: Install plugins from any public GitHub repository
- **Multi-Type Support**: Supports Pipe, Action, Filter, and Tool plugins
- **Interactive Selection Dialog**: Review the filtered list, check the plugins you want, then install only that subset
- **Interactive Selection Dialog**: Review the filtered list with type tags and plugin descriptions, then install only the checked subset
- **i18n**: Supports 11 languages
## Flow
@@ -37,7 +37,7 @@ User Input
┌─────────────────────────────────────┐
│ Show Selection Dialog │
│ (checkbox list + exclude hint)
│ (checkbox list + type tags + desc)
└─────────────────────────────────────┘
├── [Cancel] → End
@@ -63,7 +63,7 @@ User Input
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.
After plugin discovery and filtering, OpenWebUI opens a browser dialog built with the `execute` event so you can review plugin descriptions, use type tags for quick batch selection, and check exactly which plugins to install before the API calls start.
## Quick Start: Install Popular Collections

View File

@@ -14,7 +14,7 @@
- 自动更新:自动更新之前安装过的插件
- 公开 GitHub 支持:支持从任何公开 GitHub 仓库安装插件
- 多类型支持:支持 Pipe、Action、Filter 和 Tool 插件
- 交互式选择对话框:先查看过滤后的列表,再勾选要安装的插件,只安装所选子集
- 交互式选择对话框:先查看带类型标签和描述信息的过滤列表,再勾选要安装的插件,只安装所选子集
- 国际化:支持 11 种语言
## 流程
@@ -37,7 +37,7 @@
┌─────────────────────────────────────┐
│ 显示选择对话框 │
│ (复选列表 + 排除提示)
│ (复选列表 + 类型标签 + 描述)
└─────────────────────────────────────┘
├── [取消] → 结束
@@ -63,7 +63,7 @@
每次请求处理一个仓库。如需混合多个来源,请在上一次安装完成后再发起下一次请求。
在插件发现和过滤完成后OpenWebUI 会通过 `execute` 事件打开浏览器选择对话框你可以先勾选真正想安装的插件,再开始调用安装 API。
在插件发现和过滤完成后OpenWebUI 会通过 `execute` 事件打开浏览器选择对话框你可以先查看插件描述,使用类型标签进行批量勾选,再开始调用安装 API。
## 快速开始:安装热门插件集

View File

@@ -10,12 +10,13 @@ Installing plugins in OpenWebUI should not feel like an all-or-nothing jump. Wit
### 🚀 Interactive Plugin Selection
- Uses the OpenWebUI `execute` event to open a custom browser dialog
- Displays the filtered plugin list with checkboxes, repository context, and exclude hints
- Displays the filtered plugin list with checkboxes, type tags, plugin descriptions, and repository context
- Installs only the plugins the user keeps selected
### ✅ Smart Safety Features
- Replaces the basic confirmation event with a richer selective install flow
- Users can uncheck plugins they do not want without rewriting the request
- Removes the noisy copy-to-exclude helper when it is not needed
- Automatically excludes the tool itself from installation
### 🌍 Multi-Repository Support

View File

@@ -10,12 +10,13 @@
### 🚀 交互式插件选择
- 基于 OpenWebUI 的 `execute` 事件打开自定义浏览器选择对话框
- 显示过滤后的插件列表、仓库信息与排除提示
- 显示带复选框、类型标签、插件描述和仓库信息的过滤结果
- 只安装用户保留勾选的插件
### ✅ 智能安全保障
- 用更丰富的选择流程替代基础 confirmation 事件
- 用户无需改写请求,也能取消勾选不想安装的插件
- 不再显示多余的“复制 exclude_keywords”提示
- 自动排除工具自身,避免重复安装
### 🌍 多仓库支持

View File

@@ -14,7 +14,7 @@ One-click batch install plugins from GitHub repositories to your OpenWebUI insta
- **Auto-Update**: Automatically updates previously installed plugins
- **Public GitHub Support**: Install plugins from any public GitHub repository
- **Multi-Type Support**: Supports Pipe, Action, Filter, and Tool plugins
- **Interactive Selection Dialog**: Review the filtered list, check the plugins you want, then install only that subset
- **Interactive Selection Dialog**: Review the filtered list with type tags and plugin descriptions, then install only the checked subset
- **i18n**: Supports 11 languages
## Flow
@@ -37,7 +37,7 @@ User Input
┌─────────────────────────────────────┐
│ Show Selection Dialog │
│ (checkbox list + exclude hint)
│ (checkbox list + type tags + desc)
└─────────────────────────────────────┘
├── [Cancel] → End
@@ -63,7 +63,7 @@ User Input
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.
After plugin discovery and filtering, OpenWebUI opens a browser dialog built with the `execute` event so you can review plugin descriptions, use type tags for quick batch selection, and check exactly which plugins to install before the API calls start.
## Quick Start: Install Popular Collections

View File

@@ -14,7 +14,7 @@
- 自动更新:自动更新之前安装过的插件
- 公开 GitHub 支持:支持从任何公开 GitHub 仓库安装插件
- 多类型支持:支持 Pipe、Action、Filter 和 Tool 插件
- 交互式选择对话框:先查看过滤后的列表,再勾选要安装的插件,只安装所选子集
- 交互式选择对话框:先查看带类型标签和描述信息的过滤列表,再勾选要安装的插件,只安装所选子集
- 国际化:支持 11 种语言
## 流程
@@ -37,7 +37,7 @@
┌─────────────────────────────────────┐
│ 显示选择对话框 │
│ (复选列表 + 排除提示)
│ (复选列表 + 类型标签 + 描述)
└─────────────────────────────────────┘
├── [取消] → 结束
@@ -63,7 +63,7 @@
每次请求处理一个仓库。如需混合多个来源,请在上一次安装完成后再发起下一次请求。
在插件发现和过滤完成后OpenWebUI 会通过 `execute` 事件打开浏览器选择对话框你可以先勾选真正想安装的插件,再开始调用安装 API。
在插件发现和过滤完成后OpenWebUI 会通过 `execute` 事件打开浏览器选择对话框你可以先查看插件描述,使用类型标签进行批量勾选,再开始调用安装 API。
## 快速开始:安装热门插件集

View File

@@ -303,111 +303,133 @@ SELECTION_DIALOG_TEXTS = {
"en-US": {
"select_all": "Select all",
"clear_all": "Clear all",
"quick_select": "Types",
"selected_count": "{count} selected",
"install_selected": "Install Selected",
"cancel": "Cancel",
"version_label": "Version",
"file_label": "File",
"description_label": "Description",
"repo_label": "Repository",
},
"zh-CN": {
"select_all": "全选",
"clear_all": "清空",
"quick_select": "类型标签",
"selected_count": "已选 {count}",
"install_selected": "安装所选插件",
"cancel": "取消",
"version_label": "版本",
"file_label": "文件",
"description_label": "描述",
"repo_label": "仓库",
},
"zh-HK": {
"select_all": "全選",
"clear_all": "清空",
"quick_select": "類型標籤",
"selected_count": "已選 {count}",
"install_selected": "安裝所選外掛",
"cancel": "取消",
"version_label": "版本",
"file_label": "檔案",
"description_label": "描述",
"repo_label": "倉庫",
},
"zh-TW": {
"select_all": "全選",
"clear_all": "清空",
"quick_select": "類型標籤",
"selected_count": "已選 {count}",
"install_selected": "安裝所選外掛",
"cancel": "取消",
"version_label": "版本",
"file_label": "檔案",
"description_label": "描述",
"repo_label": "倉庫",
},
"ko-KR": {
"select_all": "전체 선택",
"clear_all": "선택 해제",
"quick_select": "유형",
"selected_count": "{count}개 선택됨",
"install_selected": "선택한 플러그인 설치",
"cancel": "취소",
"version_label": "버전",
"file_label": "파일",
"description_label": "설명",
"repo_label": "저장소",
},
"ja-JP": {
"select_all": "すべて選択",
"clear_all": "クリア",
"quick_select": "タイプ",
"selected_count": "{count}件を選択",
"install_selected": "選択したプラグインをインストール",
"cancel": "キャンセル",
"version_label": "バージョン",
"file_label": "ファイル",
"description_label": "説明",
"repo_label": "リポジトリ",
},
"fr-FR": {
"select_all": "Tout sélectionner",
"clear_all": "Tout effacer",
"quick_select": "Types",
"selected_count": "{count} sélectionnés",
"install_selected": "Installer la sélection",
"cancel": "Annuler",
"version_label": "Version",
"file_label": "Fichier",
"description_label": "Description",
"repo_label": "Dépôt",
},
"de-DE": {
"select_all": "Alle auswählen",
"clear_all": "Auswahl löschen",
"quick_select": "Typen",
"selected_count": "{count} ausgewählt",
"install_selected": "Auswahl installieren",
"cancel": "Abbrechen",
"version_label": "Version",
"file_label": "Datei",
"description_label": "Beschreibung",
"repo_label": "Repository",
},
"es-ES": {
"select_all": "Seleccionar todo",
"clear_all": "Limpiar",
"quick_select": "Tipos",
"selected_count": "{count} seleccionados",
"install_selected": "Instalar seleccionados",
"cancel": "Cancelar",
"version_label": "Versión",
"file_label": "Archivo",
"description_label": "Descripción",
"repo_label": "Repositorio",
},
"it-IT": {
"select_all": "Seleziona tutto",
"clear_all": "Cancella",
"quick_select": "Tipi",
"selected_count": "{count} selezionati",
"install_selected": "Installa selezionati",
"cancel": "Annulla",
"version_label": "Versione",
"file_label": "File",
"description_label": "Descrizione",
"repo_label": "Repository",
},
"vi-VN": {
"select_all": "Chọn tất cả",
"clear_all": "Bỏ chọn",
"quick_select": "Loại",
"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",
"description_label": "Mô tả",
"repo_label": "Kho",
},
}
@@ -862,7 +884,7 @@ def _build_confirmation_hint(lang: str, repo: str, exclude_keywords: str) -> str
if excluded_parts:
return _t(lang, "confirm_excluded_hint", excluded=", ".join(excluded_parts))
return _t(lang, "confirm_copy_exclude_hint", keywords=SELF_EXCLUDE_HINT)
return ""
def _build_selection_dialog_js(
@@ -919,12 +941,18 @@ def _build_selection_dialog_js(
" </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\">",
" <div style=\"padding:16px 24px 0;display:grid;gap:12px\">",
" <div style=\"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 style=\"display:flex;gap:10px;align-items:center;flex-wrap:wrap\">",
" <div style=\"font-size:12px;font-weight:700;color:#475569;text-transform:uppercase;letter-spacing:0.04em\">${escapeHtml(ui.quick_select)}</div>",
" <div id=\"batch-install-plugin-selector-types\" style=\"display:flex;gap:8px;flex-wrap:wrap\"></div>",
" </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\">",
@@ -939,21 +967,68 @@ def _build_selection_dialog_js(
" 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 typesEl = overlay.querySelector('#batch-install-plugin-selector-types');",
" 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');",
" const typeMap = options.reduce((groups, item) => {",
" if (!groups[item.type]) {",
" groups[item.type] = [];",
" }",
" groups[item.type].push(item);",
" return groups;",
" }, {});",
" const typeEntries = Object.entries(typeMap);",
" const formatMultilineText = (value) => escapeHtml(value).replace(/\\n+/g, '<br />');",
" hintEl.textContent = ui.hint || '';",
" hintEl.style.display = ui.hint ? 'block' : 'none';",
" const renderTypeButtons = () => {",
" typesEl.innerHTML = typeEntries.map(([type, items]) => {",
" const allSelected = items.every((item) => selected.has(item.id));",
" const anySelected = items.some((item) => selected.has(item.id));",
" const background = allSelected ? '#0f172a' : '#ffffff';",
" const color = allSelected ? '#ffffff' : '#0f172a';",
" const border = anySelected ? '#94a3b8' : '#cbd5e1';",
" return `",
" <button type=\"button\" data-plugin-type=\"${escapeHtml(type)}\" style=\"padding:7px 12px;border:1px solid ${border};border-radius:999px;background:${background};color:${color};font-size:12px;font-weight:700;cursor:pointer;display:inline-flex;gap:8px;align-items:center\">",
" <span>${escapeHtml(type)}</span>",
" <span style=\"display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;padding:0 6px;border-radius:999px;background:${allSelected ? 'rgba(255,255,255,0.16)' : '#e2e8f0'};color:${allSelected ? '#ffffff' : '#334155'}\">${items.length}</span>",
" </button>",
" `;",
" }).join('');",
" typesEl.querySelectorAll('button[data-plugin-type]').forEach((button) => {",
" button.addEventListener('click', () => {",
" const pluginType = button.getAttribute('data-plugin-type') || '';",
" const items = typeMap[pluginType] || [];",
" const allSelected = items.length > 0 && items.every((item) => selected.has(item.id));",
" items.forEach((item) => {",
" if (allSelected) {",
" selected.delete(item.id);",
" } else {",
" selected.add(item.id);",
" }",
" });",
" renderList();",
" });",
" });",
" };",
" 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';",
" renderTypeButtons();",
" };",
" const renderList = () => {",
" listEl.innerHTML = options.map((item) => {",
" const checked = selected.has(item.id) ? 'checked' : '';",
" const description = item.description ? `",
" <div style=\"display:grid;gap:4px\">",
" <div style=\"font-size:11px;font-weight:700;color:#64748b;text-transform:uppercase;letter-spacing:0.04em\">${escapeHtml(ui.description_label)}</div>",
" <div style=\"font-size:13px;color:#334155;line-height:1.55;word-break:break-word\">${formatMultilineText(item.description)}</div>",
" </div>",
" ` : '';",
" 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\" />",
@@ -963,6 +1038,7 @@ def _build_selection_dialog_js(
" <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>",
" ${description}",
" </div>",
" </label>",
" `;",
@@ -1049,6 +1125,7 @@ async def _request_plugin_selection(
"type": candidate.plugin_type,
"version": candidate.version,
"file_path": candidate.file_path,
"description": candidate.metadata.get("description", ""),
}
for candidate in candidates
]
@@ -1060,11 +1137,13 @@ async def _request_plugin_selection(
"hint": hint.strip(),
"select_all": _selection_t(lang, "select_all"),
"clear_all": _selection_t(lang, "clear_all"),
"quick_select": _selection_t(lang, "quick_select"),
"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"),
"description_label": _selection_t(lang, "description_label"),
}
js_code = _build_selection_dialog_js(options, ui_text)

View File

@@ -8,9 +8,9 @@ Batch Install Plugins from GitHub v1.1.0 upgrades the install confirmation step
## Highlights
- **Interactive Selection Dialog**: Opens a checkbox-based browser dialog instead of using the basic confirmation event
- **Interactive Selection Dialog**: Opens a checkbox-based browser dialog with type tags and visible plugin descriptions
- **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
- **Repository Context**: Displays the current repository and only shows useful exclusion information 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

View File

@@ -8,9 +8,9 @@ Batch Install Plugins from GitHub v1.1.0 将原本的安装确认步骤升级为
## 亮点
- **交互式选择对话框**:不再只使用基础 confirmation 事件,而是打开支持复选框的浏览器对话框
- **交互式选择对话框**:不再只使用基础 confirmation 事件,而是打开带类型标签、描述信息和复选框的浏览器对话框
- **选择性安装**:安装循环只会处理用户最终保留勾选的插件
- **仓库上下文**:对话框中会显示当前仓库与排除提示
- **仓库上下文**:对话框中会显示当前仓库,并且只展示真正有用的排除信息
- **本地化 UI**:对话框控件已为所有支持语言提供本地化文本
- **工作流不回退**:原有的插件发现、过滤、自动更新和连接回退逻辑保持不变