From 186ef4da786a039ee2a429508c93f5bffaedf1e3 Mon Sep 17 00:00:00 2001 From: Will Miao Date: Mon, 3 Aug 2026 21:17:42 +0800 Subject: [PATCH] refactor(ui): group example image download actions into a submenu Move the 'Download Missing' / 'Re-process All' example image actions under a single 'Download Example Images' submenu item in the single-model and bulk context menus, matching the existing send-to-workflow submenu pattern. Shorten the submenu labels and update all locale translations. --- locales/de.json | 10 +++--- locales/en.json | 10 +++--- locales/es.json | 10 +++--- locales/fr.json | 10 +++--- locales/he.json | 10 +++--- locales/ja.json | 10 +++--- locales/ko.json | 10 +++--- locales/ru.json | 10 +++--- locales/zh-CN.json | 10 +++--- locales/zh-TW.json | 10 +++--- .../components/ContextMenu/BulkContextMenu.js | 13 ++----- templates/checkpoints.html | 8 +++-- templates/components/context_menu.html | 34 +++++++++++++------ templates/embeddings.html | 8 +++-- .../contextMenu.interactions.test.js | 8 +++-- 15 files changed, 105 insertions(+), 66 deletions(-) diff --git a/locales/de.json b/locales/de.json index b4c9a6c1..59dd60a1 100644 --- a/locales/de.json +++ b/locales/de.json @@ -772,8 +772,9 @@ "unfavorite": "Aus Favoriten entfernen", "deleteAll": "Ausgewählte löschen", "downloadMissingLoras": "Fehlende LoRAs herunterladen", - "downloadMissingExamples": "Fehlende Beispielbilder herunterladen", - "reprocessExamples": "Beispielbilder erneut verarbeiten", + "downloadExamples": "Beispielbilder herunterladen", + "downloadMissingExamples": "Fehlende herunterladen", + "reprocessExamples": "Alle erneut verarbeiten", "clear": "Auswahl löschen", "skipMetadataRefreshCount": "Überspringen({count} Modelle)", "resumeMetadataRefreshCount": "Fortsetzen({count} Modelle)", @@ -808,8 +809,9 @@ "sendToWorkflowAppend": "An Workflow senden (Anhängen)", "sendToWorkflowReplace": "An Workflow senden (Ersetzen)", "openExamples": "Beispiele-Ordner öffnen", - "downloadExamples": "Fehlende Beispielbilder herunterladen", - "reprocessExamples": "Beispielbilder erneut verarbeiten", + "downloadExamples": "Beispielbilder herunterladen", + "downloadMissingExamples": "Fehlende herunterladen", + "reprocessExamples": "Alle erneut verarbeiten", "replacePreview": "Vorschau ersetzen", "setContentRating": "Inhaltsbewertung festlegen", "moveToFolder": "In Ordner verschieben", diff --git a/locales/en.json b/locales/en.json index 3b98b013..123cd8b0 100644 --- a/locales/en.json +++ b/locales/en.json @@ -772,8 +772,9 @@ "unfavorite": "Remove from Favorites", "deleteAll": "Delete Selected", "downloadMissingLoras": "Download Missing LoRAs", - "downloadMissingExamples": "Download Missing Example Images", - "reprocessExamples": "Re-process Example Images", + "downloadExamples": "Download Example Images", + "downloadMissingExamples": "Download Missing", + "reprocessExamples": "Re-process All", "clear": "Clear Selection", "skipMetadataRefreshCount": "Skip ({count} models)", "resumeMetadataRefreshCount": "Resume ({count} models)", @@ -808,8 +809,9 @@ "sendToWorkflowAppend": "Send to Workflow (Append)", "sendToWorkflowReplace": "Send to Workflow (Replace)", "openExamples": "Open Examples Folder", - "downloadExamples": "Download Missing Example Images", - "reprocessExamples": "Re-process Example Images", + "downloadExamples": "Download Example Images", + "downloadMissingExamples": "Download Missing", + "reprocessExamples": "Re-process All", "replacePreview": "Replace Preview", "setContentRating": "Set Content Rating", "moveToFolder": "Move to Folder", diff --git a/locales/es.json b/locales/es.json index 2ecc2164..2130e1ea 100644 --- a/locales/es.json +++ b/locales/es.json @@ -772,8 +772,9 @@ "unfavorite": "Quitar de favoritos", "deleteAll": "Eliminar seleccionados", "downloadMissingLoras": "Descargar LoRAs faltantes", - "downloadMissingExamples": "Descargar imágenes de ejemplo faltantes", - "reprocessExamples": "Reprocesar imágenes de ejemplo", + "downloadExamples": "Descargar imágenes de ejemplo", + "downloadMissingExamples": "Descargar faltantes", + "reprocessExamples": "Reprocesar todo", "clear": "Limpiar selección", "skipMetadataRefreshCount": "Omitir({count} modelos)", "resumeMetadataRefreshCount": "Reanudar({count} modelos)", @@ -808,8 +809,9 @@ "sendToWorkflowAppend": "Enviar al flujo de trabajo (Añadir)", "sendToWorkflowReplace": "Enviar al flujo de trabajo (Reemplazar)", "openExamples": "Abrir carpeta de ejemplos", - "downloadExamples": "Descargar imágenes de ejemplo faltantes", - "reprocessExamples": "Reprocesar imágenes de ejemplo", + "downloadExamples": "Descargar imágenes de ejemplo", + "downloadMissingExamples": "Descargar faltantes", + "reprocessExamples": "Reprocesar todo", "replacePreview": "Reemplazar vista previa", "setContentRating": "Establecer clasificación de contenido", "moveToFolder": "Mover a carpeta", diff --git a/locales/fr.json b/locales/fr.json index 10bf4aa1..cae78f7b 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -772,8 +772,9 @@ "unfavorite": "Retirer des favoris", "deleteAll": "Supprimer la sélection", "downloadMissingLoras": "Télécharger les LoRAs manquants", - "downloadMissingExamples": "Télécharger les images d'exemple manquantes", - "reprocessExamples": "Retraiter les images d'exemple", + "downloadExamples": "Télécharger les images d'exemple", + "downloadMissingExamples": "Télécharger les manquantes", + "reprocessExamples": "Tout retraiter", "clear": "Effacer la sélection", "skipMetadataRefreshCount": "Ignorer({count} modèles)", "resumeMetadataRefreshCount": "Reprendre({count} modèles)", @@ -808,8 +809,9 @@ "sendToWorkflowAppend": "Envoyer vers le workflow (Ajouter)", "sendToWorkflowReplace": "Envoyer vers le workflow (Remplacer)", "openExamples": "Ouvrir le dossier d'exemples", - "downloadExamples": "Télécharger les images d'exemple manquantes", - "reprocessExamples": "Retraiter les images d'exemple", + "downloadExamples": "Télécharger les images d'exemple", + "downloadMissingExamples": "Télécharger les manquantes", + "reprocessExamples": "Tout retraiter", "replacePreview": "Remplacer l'aperçu", "setContentRating": "Définir la classification du contenu", "moveToFolder": "Déplacer vers un dossier", diff --git a/locales/he.json b/locales/he.json index 4a2a2580..dc8f978d 100644 --- a/locales/he.json +++ b/locales/he.json @@ -772,8 +772,9 @@ "unfavorite": "הסר ממועדפים", "deleteAll": "מחק נבחרים", "downloadMissingLoras": "הורדת LoRAs חסרים", - "downloadMissingExamples": "הורדת תמונות דוגמה חסרות", - "reprocessExamples": "עיבוד מחדש של תמונות דוגמה", + "downloadExamples": "הורד תמונות דוגמה", + "downloadMissingExamples": "הורדת חסרים", + "reprocessExamples": "עיבוד מחדש של הכול", "clear": "נקה בחירה", "skipMetadataRefreshCount": "דילוג({count} מודלים)", "resumeMetadataRefreshCount": "המשך({count} מודלים)", @@ -808,8 +809,9 @@ "sendToWorkflowAppend": "שלח ל-Workflow (הוסף)", "sendToWorkflowReplace": "שלח ל-Workflow (החלף)", "openExamples": "פתח תיקיית דוגמאות", - "downloadExamples": "הורדת תמונות דוגמה חסרות", - "reprocessExamples": "עיבוד מחדש של תמונות דוגמה", + "downloadExamples": "הורד תמונות דוגמה", + "downloadMissingExamples": "הורדת חסרים", + "reprocessExamples": "עיבוד מחדש של הכול", "replacePreview": "החלף תצוגה מקדימה", "setContentRating": "הגדר דירוג תוכן", "moveToFolder": "העבר לתיקייה", diff --git a/locales/ja.json b/locales/ja.json index 5564f417..5dc90cad 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -772,8 +772,9 @@ "unfavorite": "お気に入りから削除", "deleteAll": "選択したものを削除", "downloadMissingLoras": "不足している LoRA をダウンロード", - "downloadMissingExamples": "不足しているサンプル画像をダウンロード", - "reprocessExamples": "サンプル画像を再処理", + "downloadExamples": "例画像をダウンロード", + "downloadMissingExamples": "不足分をダウンロード", + "reprocessExamples": "すべて再処理", "clear": "選択をクリア", "skipMetadataRefreshCount": "スキップ({count}モデル)", "resumeMetadataRefreshCount": "再開({count}モデル)", @@ -808,8 +809,9 @@ "sendToWorkflowAppend": "ワークフローに送信(追加)", "sendToWorkflowReplace": "ワークフローに送信(置換)", "openExamples": "例画像フォルダを開く", - "downloadExamples": "不足しているサンプル画像をダウンロード", - "reprocessExamples": "サンプル画像を再処理", + "downloadExamples": "例画像をダウンロード", + "downloadMissingExamples": "不足分をダウンロード", + "reprocessExamples": "すべて再処理", "replacePreview": "プレビューを置換", "setContentRating": "コンテンツレーティングを設定", "moveToFolder": "フォルダに移動", diff --git a/locales/ko.json b/locales/ko.json index 576e2d49..1a931b85 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -772,8 +772,9 @@ "unfavorite": "즐겨찾기 해제", "deleteAll": "선택된 항목 삭제", "downloadMissingLoras": "누락된 LoRA 다운로드", - "downloadMissingExamples": "누락된 예시 이미지 다운로드", - "reprocessExamples": "예시 이미지 다시 처리", + "downloadExamples": "예시 이미지 다운로드", + "downloadMissingExamples": "누락된 것만 다운로드", + "reprocessExamples": "모두 다시 처리", "clear": "선택 지우기", "skipMetadataRefreshCount": "건너뛰기({count}개 모델)", "resumeMetadataRefreshCount": "재개({count}개 모델)", @@ -808,8 +809,9 @@ "sendToWorkflowAppend": "워크플로로 전송 (추가)", "sendToWorkflowReplace": "워크플로로 전송 (교체)", "openExamples": "예시 폴더 열기", - "downloadExamples": "누락된 예시 이미지 다운로드", - "reprocessExamples": "예시 이미지 다시 처리", + "downloadExamples": "예시 이미지 다운로드", + "downloadMissingExamples": "누락된 것만 다운로드", + "reprocessExamples": "모두 다시 처리", "replacePreview": "미리보기 교체", "setContentRating": "콘텐츠 등급 설정", "moveToFolder": "폴더로 이동", diff --git a/locales/ru.json b/locales/ru.json index f7cc8e69..7f8df383 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -772,8 +772,9 @@ "unfavorite": "Удалить из избранного", "deleteAll": "Удалить выбранные", "downloadMissingLoras": "Скачать отсутствующие LoRAs", - "downloadMissingExamples": "Загрузить недостающие примеры изображений", - "reprocessExamples": "Повторно обработать примеры изображений", + "downloadExamples": "Загрузить примеры изображений", + "downloadMissingExamples": "Скачать недостающие", + "reprocessExamples": "Обработать всё заново", "clear": "Очистить выбор", "skipMetadataRefreshCount": "Пропустить({count} моделей)", "resumeMetadataRefreshCount": "Возобновить({count} моделей)", @@ -808,8 +809,9 @@ "sendToWorkflowAppend": "Отправить в Workflow (Добавить)", "sendToWorkflowReplace": "Отправить в Workflow (Заменить)", "openExamples": "Открыть папку примеров", - "downloadExamples": "Загрузить недостающие примеры изображений", - "reprocessExamples": "Повторно обработать примеры изображений", + "downloadExamples": "Загрузить примеры изображений", + "downloadMissingExamples": "Скачать недостающие", + "reprocessExamples": "Обработать всё заново", "replacePreview": "Заменить превью", "setContentRating": "Установить рейтинг контента", "moveToFolder": "Переместить в папку", diff --git a/locales/zh-CN.json b/locales/zh-CN.json index 185c2712..3bda05cb 100644 --- a/locales/zh-CN.json +++ b/locales/zh-CN.json @@ -772,8 +772,9 @@ "unfavorite": "取消收藏", "deleteAll": "删除已选", "downloadMissingLoras": "下载缺失的 LoRAs", - "downloadMissingExamples": "下载缺失的示例图片", - "reprocessExamples": "重新处理示例图片", + "downloadExamples": "下载示例图片", + "downloadMissingExamples": "下载缺失的", + "reprocessExamples": "重新处理全部", "clear": "清除选择", "skipMetadataRefreshCount": "跳过({count} 个模型)", "resumeMetadataRefreshCount": "恢复({count} 个模型)", @@ -808,8 +809,9 @@ "sendToWorkflowAppend": "发送到工作流(追加)", "sendToWorkflowReplace": "发送到工作流(替换)", "openExamples": "打开示例文件夹", - "downloadExamples": "下载缺失的示例图片", - "reprocessExamples": "重新处理示例图片", + "downloadExamples": "下载示例图片", + "downloadMissingExamples": "下载缺失的", + "reprocessExamples": "重新处理全部", "replacePreview": "替换预览", "setContentRating": "设置内容评级", "moveToFolder": "移动到文件夹", diff --git a/locales/zh-TW.json b/locales/zh-TW.json index 4185280d..3ff4652b 100644 --- a/locales/zh-TW.json +++ b/locales/zh-TW.json @@ -772,8 +772,9 @@ "unfavorite": "取消收藏", "deleteAll": "刪除所選", "downloadMissingLoras": "下載缺失的 LoRAs", - "downloadMissingExamples": "下載缺少的範例圖片", - "reprocessExamples": "重新處理範例圖片", + "downloadExamples": "下載範例圖片", + "downloadMissingExamples": "下載缺少的", + "reprocessExamples": "重新處理全部", "clear": "清除選取", "skipMetadataRefreshCount": "跳過({count} 個模型)", "resumeMetadataRefreshCount": "恢復({count} 個模型)", @@ -808,8 +809,9 @@ "sendToWorkflowAppend": "傳送到工作流(附加)", "sendToWorkflowReplace": "傳送到工作流(取代)", "openExamples": "開啟範例資料夾", - "downloadExamples": "下載缺少的範例圖片", - "reprocessExamples": "重新處理範例圖片", + "downloadExamples": "下載範例圖片", + "downloadMissingExamples": "下載缺少的", + "reprocessExamples": "重新處理全部", "replacePreview": "更換預覽圖", "setContentRating": "設定內容分級", "moveToFolder": "移動到資料夾", diff --git a/static/js/components/ContextMenu/BulkContextMenu.js b/static/js/components/ContextMenu/BulkContextMenu.js index 7c40384d..1750389a 100644 --- a/static/js/components/ContextMenu/BulkContextMenu.js +++ b/static/js/components/ContextMenu/BulkContextMenu.js @@ -137,17 +137,10 @@ export class BulkContextMenu extends BaseContextMenu { downloadMissingLorasItem.style.display = currentModelType === 'recipes' ? 'flex' : 'none'; } - const downloadExampleImagesItem = this.menu.querySelector('[data-action="download-example-images"]'); - if (downloadExampleImagesItem) { + const downloadExampleImagesSubmenu = this.menu.querySelector('[data-has-submenu="download-example-images"]'); + if (downloadExampleImagesSubmenu) { // Show on model pages (loras, checkpoints, embeddings), hide on recipes - const modelPages = ['loras', 'checkpoints', 'embeddings']; - downloadExampleImagesItem.style.display = modelPages.includes(currentModelType) ? 'flex' : 'none'; - } - - const downloadMissingExampleImagesItem = this.menu.querySelector('[data-action="download-missing-example-images"]'); - if (downloadMissingExampleImagesItem) { - // Show on model pages (loras, checkpoints, embeddings), hide on recipes - downloadMissingExampleImagesItem.style.display = ['loras', 'checkpoints', 'embeddings'].includes(currentModelType) ? 'flex' : 'none'; + downloadExampleImagesSubmenu.style.display = ['loras', 'checkpoints', 'embeddings'].includes(currentModelType) ? 'flex' : 'none'; } const skipMetadataRefreshItem = this.menu.querySelector('[data-action="skip-metadata-refresh"]'); diff --git a/templates/checkpoints.html b/templates/checkpoints.html index 06fcccb5..db87e1ed 100644 --- a/templates/checkpoints.html +++ b/templates/checkpoints.html @@ -32,8 +32,12 @@
{{ t('loras.contextMenu.openExamples') }}
-
{{ t('loras.contextMenu.downloadExamples') }}
-
{{ t('loras.contextMenu.reprocessExamples') }}
+
{{ t('loras.contextMenu.downloadExamples') }} +
+
{{ t('loras.contextMenu.downloadMissingExamples') }}
+
{{ t('loras.contextMenu.reprocessExamples') }}
+
+
{{ t('loras.contextMenu.replacePreview') }}
diff --git a/templates/components/context_menu.html b/templates/components/context_menu.html index af04e835..a6c0c8d5 100644 --- a/templates/components/context_menu.html +++ b/templates/components/context_menu.html @@ -44,11 +44,18 @@
{{ t('loras.contextMenu.openExamples') }}
-
- {{ t('loras.contextMenu.downloadExamples') }} -
-
- {{ t('loras.contextMenu.reprocessExamples') }} +
+ + {{ t('loras.contextMenu.downloadExamples') }} + +
+
+ {{ t('loras.contextMenu.downloadMissingExamples') }} +
+
+ {{ t('loras.contextMenu.reprocessExamples') }} +
+
{{ t('loras.contextMenu.replacePreview') }} @@ -139,11 +146,18 @@
{{ t('loras.bulkOperations.sections.download') }}
-
- {{ t('loras.bulkOperations.downloadMissingExamples') }} -
-
- {{ t('loras.bulkOperations.reprocessExamples') }} +
+ + {{ t('loras.bulkOperations.downloadExamples') }} + +
+
+ {{ t('loras.bulkOperations.downloadMissingExamples') }} +
+
+ {{ t('loras.bulkOperations.reprocessExamples') }} +
+
{{ t('loras.bulkOperations.downloadMissingLoras') }} diff --git a/templates/embeddings.html b/templates/embeddings.html index 8056f7ff..3416b2e8 100644 --- a/templates/embeddings.html +++ b/templates/embeddings.html @@ -32,8 +32,12 @@
{{ t('loras.contextMenu.openExamples') }}
-
{{ t('loras.contextMenu.downloadExamples') }}
-
{{ t('loras.contextMenu.reprocessExamples') }}
+
{{ t('loras.contextMenu.downloadExamples') }} +
+
{{ t('loras.contextMenu.downloadMissingExamples') }}
+
{{ t('loras.contextMenu.reprocessExamples') }}
+
+
{{ t('loras.contextMenu.replacePreview') }}
diff --git a/tests/frontend/components/contextMenu.interactions.test.js b/tests/frontend/components/contextMenu.interactions.test.js index d43e36c7..fd172496 100644 --- a/tests/frontend/components/contextMenu.interactions.test.js +++ b/tests/frontend/components/contextMenu.interactions.test.js @@ -2159,8 +2159,12 @@ describe('Interaction-level regression coverage', () => { it('routes single-model example downloads to missing-only and force paths', async () => { document.body.innerHTML = `
-
-
+
+
+
+
+
+
`;