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 - **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
- **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 - **i18n**: Supports 11 languages
## Flow ## Flow
@@ -33,7 +33,7 @@ User Input
┌─────────────────────────────────────┐ ┌─────────────────────────────────────┐
│ Show Selection Dialog │ │ Show Selection Dialog │
│ (checkbox list + exclude hint) │ (checkbox list + type tags + desc)
└─────────────────────────────────────┘ └─────────────────────────────────────┘
├── [Cancel] → End ├── [Cancel] → End
@@ -59,7 +59,7 @@ 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. 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 ## Quick Start: Install Popular Collections

View File

@@ -10,7 +10,7 @@
- 自动更新:自动更新之前安装过的插件 - 自动更新:自动更新之前安装过的插件
- 公开 GitHub 支持:支持从任何公开 GitHub 仓库安装插件 - 公开 GitHub 支持:支持从任何公开 GitHub 仓库安装插件
- 多类型支持:支持 Pipe、Action、Filter 和 Tool 插件 - 多类型支持:支持 Pipe、Action、Filter 和 Tool 插件
- 交互式选择对话框:先查看过滤后的列表,再勾选要安装的插件,只安装所选子集 - 交互式选择对话框:先查看带类型标签和描述信息的过滤列表,再勾选要安装的插件,只安装所选子集
- 国际化:支持 11 种语言 - 国际化:支持 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 - **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
- **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 - **i18n**: Supports 11 languages
## Flow ## Flow
@@ -37,7 +37,7 @@ User Input
┌─────────────────────────────────────┐ ┌─────────────────────────────────────┐
│ Show Selection Dialog │ │ Show Selection Dialog │
│ (checkbox list + exclude hint) │ (checkbox list + type tags + desc)
└─────────────────────────────────────┘ └─────────────────────────────────────┘
├── [Cancel] → End ├── [Cancel] → End
@@ -63,7 +63,7 @@ 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. 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 ## Quick Start: Install Popular Collections

View File

@@ -14,7 +14,7 @@
- 自动更新:自动更新之前安装过的插件 - 自动更新:自动更新之前安装过的插件
- 公开 GitHub 支持:支持从任何公开 GitHub 仓库安装插件 - 公开 GitHub 支持:支持从任何公开 GitHub 仓库安装插件
- 多类型支持:支持 Pipe、Action、Filter 和 Tool 插件 - 多类型支持:支持 Pipe、Action、Filter 和 Tool 插件
- 交互式选择对话框:先查看过滤后的列表,再勾选要安装的插件,只安装所选子集 - 交互式选择对话框:先查看带类型标签和描述信息的过滤列表,再勾选要安装的插件,只安装所选子集
- 国际化:支持 11 种语言 - 国际化:支持 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 ### 🚀 Interactive Plugin Selection
- Uses the OpenWebUI `execute` event to open a custom browser dialog - 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 - Installs only the plugins the user keeps selected
### ✅ Smart Safety Features ### ✅ Smart Safety Features
- Replaces the basic confirmation event with a richer selective install flow - Replaces the basic confirmation event with a richer selective install flow
- Users can uncheck plugins they do not want without rewriting the request - 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 - Automatically excludes the tool itself from installation
### 🌍 Multi-Repository Support ### 🌍 Multi-Repository Support

View File

@@ -10,12 +10,13 @@
### 🚀 交互式插件选择 ### 🚀 交互式插件选择
- 基于 OpenWebUI 的 `execute` 事件打开自定义浏览器选择对话框 - 基于 OpenWebUI 的 `execute` 事件打开自定义浏览器选择对话框
- 显示过滤后的插件列表、仓库信息与排除提示 - 显示带复选框、类型标签、插件描述和仓库信息的过滤结果
- 只安装用户保留勾选的插件 - 只安装用户保留勾选的插件
### ✅ 智能安全保障 ### ✅ 智能安全保障
- 用更丰富的选择流程替代基础 confirmation 事件 - 用更丰富的选择流程替代基础 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 - **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
- **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 - **i18n**: Supports 11 languages
## Flow ## Flow
@@ -37,7 +37,7 @@ User Input
┌─────────────────────────────────────┐ ┌─────────────────────────────────────┐
│ Show Selection Dialog │ │ Show Selection Dialog │
│ (checkbox list + exclude hint) │ (checkbox list + type tags + desc)
└─────────────────────────────────────┘ └─────────────────────────────────────┘
├── [Cancel] → End ├── [Cancel] → End
@@ -63,7 +63,7 @@ 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. 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 ## Quick Start: Install Popular Collections

View File

@@ -14,7 +14,7 @@
- 自动更新:自动更新之前安装过的插件 - 自动更新:自动更新之前安装过的插件
- 公开 GitHub 支持:支持从任何公开 GitHub 仓库安装插件 - 公开 GitHub 支持:支持从任何公开 GitHub 仓库安装插件
- 多类型支持:支持 Pipe、Action、Filter 和 Tool 插件 - 多类型支持:支持 Pipe、Action、Filter 和 Tool 插件
- 交互式选择对话框:先查看过滤后的列表,再勾选要安装的插件,只安装所选子集 - 交互式选择对话框:先查看带类型标签和描述信息的过滤列表,再勾选要安装的插件,只安装所选子集
- 国际化:支持 11 种语言 - 国际化:支持 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": { "en-US": {
"select_all": "Select all", "select_all": "Select all",
"clear_all": "Clear all", "clear_all": "Clear all",
"quick_select": "Types",
"selected_count": "{count} selected", "selected_count": "{count} selected",
"install_selected": "Install Selected", "install_selected": "Install Selected",
"cancel": "Cancel", "cancel": "Cancel",
"version_label": "Version", "version_label": "Version",
"file_label": "File", "file_label": "File",
"description_label": "Description",
"repo_label": "Repository", "repo_label": "Repository",
}, },
"zh-CN": { "zh-CN": {
"select_all": "全选", "select_all": "全选",
"clear_all": "清空", "clear_all": "清空",
"quick_select": "类型标签",
"selected_count": "已选 {count}", "selected_count": "已选 {count}",
"install_selected": "安装所选插件", "install_selected": "安装所选插件",
"cancel": "取消", "cancel": "取消",
"version_label": "版本", "version_label": "版本",
"file_label": "文件", "file_label": "文件",
"description_label": "描述",
"repo_label": "仓库", "repo_label": "仓库",
}, },
"zh-HK": { "zh-HK": {
"select_all": "全選", "select_all": "全選",
"clear_all": "清空", "clear_all": "清空",
"quick_select": "類型標籤",
"selected_count": "已選 {count}", "selected_count": "已選 {count}",
"install_selected": "安裝所選外掛", "install_selected": "安裝所選外掛",
"cancel": "取消", "cancel": "取消",
"version_label": "版本", "version_label": "版本",
"file_label": "檔案", "file_label": "檔案",
"description_label": "描述",
"repo_label": "倉庫", "repo_label": "倉庫",
}, },
"zh-TW": { "zh-TW": {
"select_all": "全選", "select_all": "全選",
"clear_all": "清空", "clear_all": "清空",
"quick_select": "類型標籤",
"selected_count": "已選 {count}", "selected_count": "已選 {count}",
"install_selected": "安裝所選外掛", "install_selected": "安裝所選外掛",
"cancel": "取消", "cancel": "取消",
"version_label": "版本", "version_label": "版本",
"file_label": "檔案", "file_label": "檔案",
"description_label": "描述",
"repo_label": "倉庫", "repo_label": "倉庫",
}, },
"ko-KR": { "ko-KR": {
"select_all": "전체 선택", "select_all": "전체 선택",
"clear_all": "선택 해제", "clear_all": "선택 해제",
"quick_select": "유형",
"selected_count": "{count}개 선택됨", "selected_count": "{count}개 선택됨",
"install_selected": "선택한 플러그인 설치", "install_selected": "선택한 플러그인 설치",
"cancel": "취소", "cancel": "취소",
"version_label": "버전", "version_label": "버전",
"file_label": "파일", "file_label": "파일",
"description_label": "설명",
"repo_label": "저장소", "repo_label": "저장소",
}, },
"ja-JP": { "ja-JP": {
"select_all": "すべて選択", "select_all": "すべて選択",
"clear_all": "クリア", "clear_all": "クリア",
"quick_select": "タイプ",
"selected_count": "{count}件を選択", "selected_count": "{count}件を選択",
"install_selected": "選択したプラグインをインストール", "install_selected": "選択したプラグインをインストール",
"cancel": "キャンセル", "cancel": "キャンセル",
"version_label": "バージョン", "version_label": "バージョン",
"file_label": "ファイル", "file_label": "ファイル",
"description_label": "説明",
"repo_label": "リポジトリ", "repo_label": "リポジトリ",
}, },
"fr-FR": { "fr-FR": {
"select_all": "Tout sélectionner", "select_all": "Tout sélectionner",
"clear_all": "Tout effacer", "clear_all": "Tout effacer",
"quick_select": "Types",
"selected_count": "{count} sélectionnés", "selected_count": "{count} sélectionnés",
"install_selected": "Installer la sélection", "install_selected": "Installer la sélection",
"cancel": "Annuler", "cancel": "Annuler",
"version_label": "Version", "version_label": "Version",
"file_label": "Fichier", "file_label": "Fichier",
"description_label": "Description",
"repo_label": "Dépôt", "repo_label": "Dépôt",
}, },
"de-DE": { "de-DE": {
"select_all": "Alle auswählen", "select_all": "Alle auswählen",
"clear_all": "Auswahl löschen", "clear_all": "Auswahl löschen",
"quick_select": "Typen",
"selected_count": "{count} ausgewählt", "selected_count": "{count} ausgewählt",
"install_selected": "Auswahl installieren", "install_selected": "Auswahl installieren",
"cancel": "Abbrechen", "cancel": "Abbrechen",
"version_label": "Version", "version_label": "Version",
"file_label": "Datei", "file_label": "Datei",
"description_label": "Beschreibung",
"repo_label": "Repository", "repo_label": "Repository",
}, },
"es-ES": { "es-ES": {
"select_all": "Seleccionar todo", "select_all": "Seleccionar todo",
"clear_all": "Limpiar", "clear_all": "Limpiar",
"quick_select": "Tipos",
"selected_count": "{count} seleccionados", "selected_count": "{count} seleccionados",
"install_selected": "Instalar seleccionados", "install_selected": "Instalar seleccionados",
"cancel": "Cancelar", "cancel": "Cancelar",
"version_label": "Versión", "version_label": "Versión",
"file_label": "Archivo", "file_label": "Archivo",
"description_label": "Descripción",
"repo_label": "Repositorio", "repo_label": "Repositorio",
}, },
"it-IT": { "it-IT": {
"select_all": "Seleziona tutto", "select_all": "Seleziona tutto",
"clear_all": "Cancella", "clear_all": "Cancella",
"quick_select": "Tipi",
"selected_count": "{count} selezionati", "selected_count": "{count} selezionati",
"install_selected": "Installa selezionati", "install_selected": "Installa selezionati",
"cancel": "Annulla", "cancel": "Annulla",
"version_label": "Versione", "version_label": "Versione",
"file_label": "File", "file_label": "File",
"description_label": "Descrizione",
"repo_label": "Repository", "repo_label": "Repository",
}, },
"vi-VN": { "vi-VN": {
"select_all": "Chọn tất cả", "select_all": "Chọn tất cả",
"clear_all": "Bỏ chọn", "clear_all": "Bỏ chọn",
"quick_select": "Loại",
"selected_count": "Đã chọn {count}", "selected_count": "Đã chọn {count}",
"install_selected": "Cài đặt mục đã chọn", "install_selected": "Cài đặt mục đã chọn",
"cancel": "Hủy", "cancel": "Hủy",
"version_label": "Phiên bản", "version_label": "Phiên bản",
"file_label": "Tệp", "file_label": "Tệp",
"description_label": "Mô tả",
"repo_label": "Kho", "repo_label": "Kho",
}, },
} }
@@ -862,7 +884,7 @@ def _build_confirmation_hint(lang: str, repo: str, exclude_keywords: str) -> str
if excluded_parts: if excluded_parts:
return _t(lang, "confirm_excluded_hint", excluded=", ".join(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( def _build_selection_dialog_js(
@@ -919,12 +941,18 @@ def _build_selection_dialog_js(
" </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 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>",
" <div style=\"padding:16px 24px 0;display:flex;justify-content:space-between;gap:12px;align-items:center;flex-wrap:wrap\">", " <div style=\"padding:16px 24px 0;display:grid;gap:12px\">",
" <div style=\"display:flex;gap:8px;flex-wrap:wrap\">", " <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-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>", " <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>",
" <div id=\"batch-install-plugin-selector-count\" style=\"font-size:13px;font-weight:600;color:#475569\"></div>",
" </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 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\">", " <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 listEl = overlay.querySelector('#batch-install-plugin-selector-list');",
" const countEl = overlay.querySelector('#batch-install-plugin-selector-count');", " const countEl = overlay.querySelector('#batch-install-plugin-selector-count');",
" const hintEl = overlay.querySelector('#batch-install-plugin-selector-hint');", " 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 submitBtn = overlay.querySelector('#batch-install-plugin-selector-submit');",
" const cancelBtn = overlay.querySelector('#batch-install-plugin-selector-cancel');", " const cancelBtn = overlay.querySelector('#batch-install-plugin-selector-cancel');",
" const selectAllBtn = overlay.querySelector('#batch-install-plugin-selector-select-all');", " const selectAllBtn = overlay.querySelector('#batch-install-plugin-selector-select-all');",
" const clearAllBtn = overlay.querySelector('#batch-install-plugin-selector-clear-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.textContent = ui.hint || '';",
" hintEl.style.display = ui.hint ? 'block' : 'none';", " 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 = () => {", " const updateState = () => {",
" countEl.textContent = ui.selected_count.replace('{count}', String(selected.size));", " countEl.textContent = ui.selected_count.replace('{count}', String(selected.size));",
" submitBtn.disabled = selected.size === 0;", " submitBtn.disabled = selected.size === 0;",
" submitBtn.style.opacity = selected.size === 0 ? '0.45' : '1';", " submitBtn.style.opacity = selected.size === 0 ? '0.45' : '1';",
" submitBtn.style.cursor = selected.size === 0 ? 'not-allowed' : 'pointer';", " submitBtn.style.cursor = selected.size === 0 ? 'not-allowed' : 'pointer';",
" renderTypeButtons();",
" };", " };",
" const renderList = () => {", " const renderList = () => {",
" listEl.innerHTML = options.map((item) => {", " listEl.innerHTML = options.map((item) => {",
" const checked = selected.has(item.id) ? 'checked' : '';", " 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 `", " return `",
" <label style=\"display:flex;gap:14px;align-items:flex-start;padding:14px;border:1px solid #e2e8f0;border-radius:14px;background:#fff;cursor:pointer\">", " <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\" />", " <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>", " <span style=\"font-size:15px;font-weight:700;color:#0f172a;word-break:break-word\">${escapeHtml(item.title)}</span>",
" </div>", " </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 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>", " </div>",
" </label>", " </label>",
" `;", " `;",
@@ -1049,6 +1125,7 @@ async def _request_plugin_selection(
"type": candidate.plugin_type, "type": candidate.plugin_type,
"version": candidate.version, "version": candidate.version,
"file_path": candidate.file_path, "file_path": candidate.file_path,
"description": candidate.metadata.get("description", ""),
} }
for candidate in candidates for candidate in candidates
] ]
@@ -1060,11 +1137,13 @@ async def _request_plugin_selection(
"hint": hint.strip(), "hint": hint.strip(),
"select_all": _selection_t(lang, "select_all"), "select_all": _selection_t(lang, "select_all"),
"clear_all": _selection_t(lang, "clear_all"), "clear_all": _selection_t(lang, "clear_all"),
"quick_select": _selection_t(lang, "quick_select"),
"selected_count": _selection_t(lang, "selected_count", count="{count}"), "selected_count": _selection_t(lang, "selected_count", count="{count}"),
"install_selected": _selection_t(lang, "install_selected"), "install_selected": _selection_t(lang, "install_selected"),
"cancel": _selection_t(lang, "cancel"), "cancel": _selection_t(lang, "cancel"),
"version_label": _selection_t(lang, "version_label"), "version_label": _selection_t(lang, "version_label"),
"file_label": _selection_t(lang, "file_label"), "file_label": _selection_t(lang, "file_label"),
"description_label": _selection_t(lang, "description_label"),
} }
js_code = _build_selection_dialog_js(options, ui_text) 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 ## 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 - **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 - **Localized UI**: Dialog controls are localized for all supported languages
- **No Workflow Regression**: Existing discovery, filtering, auto-update, and fallback connection logic remain unchanged - **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**:对话框控件已为所有支持语言提供本地化文本 - **本地化 UI**:对话框控件已为所有支持语言提供本地化文本
- **工作流不回退**:原有的插件发现、过滤、自动更新和连接回退逻辑保持不变 - **工作流不回退**:原有的插件发现、过滤、自动更新和连接回退逻辑保持不变