From d261474f3abc5c4f359585b9351bb3cabd1317d0 Mon Sep 17 00:00:00 2001 From: pixelpaws Date: Wed, 19 Nov 2025 00:01:50 +0800 Subject: [PATCH] feat(context-menu): add single model update checks --- locales/de.json | 1 + locales/en.json | 1 + locales/es.json | 1 + locales/fr.json | 1 + locales/he.json | 1 + locales/ja.json | 1 + locales/ko.json | 1 + locales/ru.json | 1 + locales/zh-CN.json | 1 + locales/zh-TW.json | 1 + .../ContextMenu/ModelContextMenuMixin.js | 104 +++++++++++++++++- templates/components/context_menu.html | 3 + 12 files changed, 115 insertions(+), 2 deletions(-) diff --git a/locales/de.json b/locales/de.json index 69035fe4..c357f2fd 100644 --- a/locales/de.json +++ b/locales/de.json @@ -496,6 +496,7 @@ }, "contextMenu": { "refreshMetadata": "Civitai-Daten aktualisieren", + "checkUpdates": "Updates prüfen", "relinkCivitai": "Mit Civitai neu verknüpfen", "copySyntax": "LoRA-Syntax kopieren", "copyFilename": "Modell-Dateiname kopieren", diff --git a/locales/en.json b/locales/en.json index c8a98ed2..bd7e57c4 100644 --- a/locales/en.json +++ b/locales/en.json @@ -496,6 +496,7 @@ }, "contextMenu": { "refreshMetadata": "Refresh Civitai Data", + "checkUpdates": "Check Updates", "relinkCivitai": "Re-link to Civitai", "copySyntax": "Copy LoRA Syntax", "copyFilename": "Copy Model Filename", diff --git a/locales/es.json b/locales/es.json index 93848935..96065094 100644 --- a/locales/es.json +++ b/locales/es.json @@ -496,6 +496,7 @@ }, "contextMenu": { "refreshMetadata": "Actualizar datos de Civitai", + "checkUpdates": "Comprobar actualizaciones", "relinkCivitai": "Re-vincular a Civitai", "copySyntax": "Copiar sintaxis de LoRA", "copyFilename": "Copiar nombre de archivo del modelo", diff --git a/locales/fr.json b/locales/fr.json index 9c6d3a34..755abf50 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -496,6 +496,7 @@ }, "contextMenu": { "refreshMetadata": "Actualiser les données Civitai", + "checkUpdates": "Vérifier les mises à jour", "relinkCivitai": "Relier à nouveau à Civitai", "copySyntax": "Copier la syntaxe LoRA", "copyFilename": "Copier le nom de fichier du modèle", diff --git a/locales/he.json b/locales/he.json index 0ed1cd10..be758c28 100644 --- a/locales/he.json +++ b/locales/he.json @@ -496,6 +496,7 @@ }, "contextMenu": { "refreshMetadata": "רענן נתוני Civitai", + "checkUpdates": "בדוק עדכונים", "relinkCivitai": "קשר מחדש ל-Civitai", "copySyntax": "העתק תחביר LoRA", "copyFilename": "העתק שם קובץ מודל", diff --git a/locales/ja.json b/locales/ja.json index 227923fe..b5c75cec 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -496,6 +496,7 @@ }, "contextMenu": { "refreshMetadata": "Civitaiデータを更新", + "checkUpdates": "更新確認", "relinkCivitai": "Civitaiに再リンク", "copySyntax": "LoRA構文をコピー", "copyFilename": "モデルファイル名をコピー", diff --git a/locales/ko.json b/locales/ko.json index 5942b619..06eb575a 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -496,6 +496,7 @@ }, "contextMenu": { "refreshMetadata": "Civitai 데이터 새로고침", + "checkUpdates": "업데이트 확인", "relinkCivitai": "Civitai에 다시 연결", "copySyntax": "LoRA 문법 복사", "copyFilename": "모델 파일명 복사", diff --git a/locales/ru.json b/locales/ru.json index 10e26e58..4469e996 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -496,6 +496,7 @@ }, "contextMenu": { "refreshMetadata": "Обновить данные Civitai", + "checkUpdates": "Проверить обновления", "relinkCivitai": "Пересвязать с Civitai", "copySyntax": "Копировать синтаксис LoRA", "copyFilename": "Копировать имя файла модели", diff --git a/locales/zh-CN.json b/locales/zh-CN.json index c8275ee0..c358c95b 100644 --- a/locales/zh-CN.json +++ b/locales/zh-CN.json @@ -496,6 +496,7 @@ }, "contextMenu": { "refreshMetadata": "刷新 Civitai 数据", + "checkUpdates": "检查更新", "relinkCivitai": "重新关联到 Civitai", "copySyntax": "复制 LoRA 语法", "copyFilename": "复制模型文件名", diff --git a/locales/zh-TW.json b/locales/zh-TW.json index 6eddf4ed..ca188c59 100644 --- a/locales/zh-TW.json +++ b/locales/zh-TW.json @@ -496,6 +496,7 @@ }, "contextMenu": { "refreshMetadata": "刷新 Civitai 資料", + "checkUpdates": "檢查更新", "relinkCivitai": "重新連結 Civitai", "copySyntax": "複製 LoRA 語法", "copyFilename": "複製模型檔名", diff --git a/static/js/components/ContextMenu/ModelContextMenuMixin.js b/static/js/components/ContextMenu/ModelContextMenuMixin.js index 17c9339b..3616c2b6 100644 --- a/static/js/components/ContextMenu/ModelContextMenuMixin.js +++ b/static/js/components/ContextMenu/ModelContextMenuMixin.js @@ -1,8 +1,10 @@ import { showToast, getNSFWLevelName, openExampleImagesFolder } from '../../utils/uiHelpers.js'; import { modalManager } from '../../managers/ModalManager.js'; import { state } from '../../state/index.js'; -import { getModelApiClient } from '../../api/modelApiFactory.js'; +import { getModelApiClient, resetAndReload } from '../../api/modelApiFactory.js'; import { bulkManager } from '../../managers/BulkManager.js'; +import { MODEL_CONFIG } from '../../api/apiConfig.js'; +import { translate } from '../../utils/i18nHelpers.js'; // Mixin with shared functionality for LoraContextMenu and CheckpointContextMenu export const ModelContextMenuMixin = { @@ -245,7 +247,102 @@ export const ModelContextMenuMixin = { return { modelId: null, modelVersionId: null }; } }, - + + parseModelId(value) { + if (value === undefined || value === null || value === '') { + return null; + } + + const parsed = Number.parseInt(value, 10); + return Number.isNaN(parsed) ? null : parsed; + }, + + getModelIdFromCard(card) { + if (!card) { + return null; + } + + const directValue = this.parseModelId(card.dataset?.modelId); + if (directValue !== null) { + return directValue; + } + + if (card.dataset?.meta) { + try { + const meta = JSON.parse(card.dataset.meta); + const metaValue = this.parseModelId(meta?.modelId ?? meta?.model_id); + if (metaValue !== null) { + return metaValue; + } + } catch (error) { + console.warn('Unable to parse card metadata for model ID', error); + } + } + + return null; + }, + + async checkUpdatesForCurrentModel() { + const card = this.currentCard; + if (!card) { + return; + } + + const modelId = this.getModelIdFromCard(card); + const typeConfig = MODEL_CONFIG[this.modelType] || {}; + const typeLabel = (typeConfig.displayName || 'Model').toLowerCase(); + + if (modelId === null) { + showToast('toast.models.bulkUpdatesMissing', { type: typeLabel }, 'warning'); + return; + } + + const apiClient = getModelApiClient(); + if (!apiClient || typeof apiClient.refreshUpdatesForModels !== 'function') { + console.warn('Model API client does not support refreshUpdatesForModels'); + showToast('toast.models.bulkUpdatesFailed', { type: typeLabel, message: 'Operation not supported' }, 'error'); + return; + } + + const loadingMessage = translate( + 'toast.models.bulkUpdatesChecking', + { count: 1, type: typeLabel }, + `Checking selected ${typeLabel}(s) for updates...` + ); + state.loadingManager?.showSimpleLoading?.(loadingMessage); + + try { + const response = await apiClient.refreshUpdatesForModels([modelId]); + const records = Array.isArray(response?.records) ? response.records : []; + const updatesCount = records.length; + + if (updatesCount > 0) { + showToast('toast.models.bulkUpdatesSuccess', { count: updatesCount, type: typeLabel }, 'success'); + } else { + showToast('toast.models.bulkUpdatesNone', { type: typeLabel }, 'info'); + } + + const resetFn = this.resetAndReload || resetAndReload; + if (typeof resetFn === 'function') { + await resetFn(false); + } + } catch (error) { + console.error('Error checking updates for model:', error); + showToast( + 'toast.models.bulkUpdatesFailed', + { type: typeLabel, message: error?.message ?? 'Unknown error' }, + 'error' + ); + } finally { + if (state.loadingManager?.hide) { + state.loadingManager.hide(); + } + if (typeof state.loadingManager?.restoreProgressBar === 'function') { + state.loadingManager.restoreProgressBar(); + } + } + }, + // Common action handlers handleCommonMenuActions(action) { switch(action) { @@ -272,6 +369,9 @@ export const ModelContextMenuMixin = { case 'set-nsfw': this.showNSFWLevelSelector(null, null, this.currentCard); return true; + case 'check-updates': + this.checkUpdatesForCurrentModel(); + return true; default: return false; } diff --git a/templates/components/context_menu.html b/templates/components/context_menu.html index fd5103fc..525f0008 100644 --- a/templates/components/context_menu.html +++ b/templates/components/context_menu.html @@ -8,6 +8,9 @@
{{ t('loras.contextMenu.refreshMetadata') }}
+
+ {{ t('loras.contextMenu.checkUpdates') }} +
{{ t('loras.contextMenu.relinkCivitai') }}