fix(recipes): distinguish unobtainable LoRAs in recipe status and skip them in syntax

The recipe card pill counted LoRAs deleted from the source (isDeleted) as
available, showing a green 'ready 2/2' for recipes that cannot be fully
reproduced. LoRAs with an unresolvable hash (hashInvalid) were counted as
missing/downloadable even though downloads always fail, and recipe syntax
generation emitted broken tokens for them.

- Four-state status on RecipeCard pill and RecipeTab badge: ready (all in
  library), missing (downloadable, red, keeps the action cue), partial
  (unobtainable entries skipped when used, amber, fa-circle-minus),
  unavailable (nothing usable, gray, fa-ban)
- Pill numerator is now the real in-library count; tooltips spell out
  missing vs unavailable (deleted from source or unresolvable hash)
- get_recipe_syntax_tokens skips hashInvalid entries like deleted ones
  instead of emitting tokens pointing at nonexistent files
- Bulk missing-download manager and recipe context menu exclude
  hashInvalid LoRAs, matching the modal's per-item download block
- New locale keys loraStatus.missingAndUnavailable/partial/noneUsable,
  translated for all 9 non-en locales
This commit is contained in:
Will Miao
2026-08-29 16:41:48 +08:00
parent ebe3df7d22
commit c972c755fc
19 changed files with 258 additions and 40 deletions
+4 -1
View File
@@ -883,7 +883,10 @@
"loraStatus": {
"none": "Keine LoRAs in diesem Rezept",
"allAvailable": "Alle LoRAs verfügbar - Einsatzbereit",
"missing": "{missing} von {total} LoRAs fehlen"
"missing": "{missing} von {total} LoRAs fehlen",
"missingAndUnavailable": "{missing} von {total} LoRAs fehlen, {unavailable} nicht verfügbar (von der Quelle gelöscht oder Hash nicht auflösbar)",
"partial": "{unavailable} von {total} LoRAs nicht verfügbar (von der Quelle gelöscht oder Hash nicht auflösbar) - werden bei Verwendung des Rezepts übersprungen",
"noneUsable": "Keine verwendbaren LoRAs - {unavailable} von {total} von der Quelle gelöscht oder Hash nicht auflösbar"
},
"resources": {
"inLibrary": "In Bibliothek",
+4 -1
View File
@@ -883,7 +883,10 @@
"loraStatus": {
"none": "No LoRAs in this recipe",
"allAvailable": "All LoRAs available - Ready to use",
"missing": "{missing} of {total} LoRAs missing"
"missing": "{missing} of {total} LoRAs missing",
"missingAndUnavailable": "{missing} of {total} LoRAs missing, {unavailable} unavailable (deleted from source or unresolvable hash)",
"partial": "{unavailable} of {total} LoRAs unavailable (deleted from source or unresolvable hash) - skipped when recipe is used",
"noneUsable": "No usable LoRAs - {unavailable} of {total} deleted from source or unresolvable hash"
},
"resources": {
"inLibrary": "In Library",
+4 -1
View File
@@ -883,7 +883,10 @@
"loraStatus": {
"none": "No hay LoRAs en esta receta",
"allAvailable": "Todos los LoRAs disponibles - Listo para usar",
"missing": "Faltan {missing} de {total} LoRAs"
"missing": "Faltan {missing} de {total} LoRAs",
"missingAndUnavailable": "Faltan {missing} de {total} LoRAs, {unavailable} no disponibles (eliminados de la fuente o hash no resoluble)",
"partial": "{unavailable} de {total} LoRAs no disponibles (eliminados de la fuente o hash no resoluble) - se omiten al usar la receta",
"noneUsable": "No hay LoRAs utilizables - {unavailable} de {total} eliminados de la fuente o hash no resoluble"
},
"resources": {
"inLibrary": "En la biblioteca",
+4 -1
View File
@@ -883,7 +883,10 @@
"loraStatus": {
"none": "Aucun LoRA dans cette Recipe",
"allAvailable": "Tous les LoRAs sont disponibles - Prêt à l'emploi",
"missing": "{missing} LoRA(s) manquant(s) sur {total}"
"missing": "{missing} LoRA(s) manquant(s) sur {total}",
"missingAndUnavailable": "{missing} LoRA(s) manquant(s) sur {total}, {unavailable} indisponible(s) (supprimé(s) de la source ou hash irrésolvable)",
"partial": "{unavailable} LoRA(s) indisponible(s) sur {total} (supprimé(s) de la source ou hash irrésolvable) - ignoré(s) lors de l'utilisation de la Recipe",
"noneUsable": "Aucun LoRA utilisable - {unavailable} sur {total} supprimé(s) de la source ou hash irrésolvable"
},
"resources": {
"inLibrary": "Dans la bibliothèque",
+4 -1
View File
@@ -883,7 +883,10 @@
"loraStatus": {
"none": "אין LoRAs במתכון הזה",
"allAvailable": "כל ה-LoRAs זמינים - מוכן לשימוש",
"missing": "{missing} מתוך {total} LoRAs חסרים"
"missing": "{missing} מתוך {total} LoRAs חסרים",
"missingAndUnavailable": "{missing} מתוך {total} LoRAs חסרים, {unavailable} לא זמינים (נמחקו מהמקור או hash שלא ניתן לפתור)",
"partial": "{unavailable} מתוך {total} LoRAs לא זמינים (נמחקו מהמקור או hash שלא ניתן לפתור) - ידולגו בעת שימוש במתכון",
"noneUsable": "אין LoRAs שמישים - {unavailable} מתוך {total} נמחקו מהמקור או hash שלא ניתן לפתור"
},
"resources": {
"inLibrary": "בספרייה",
+4 -1
View File
@@ -883,7 +883,10 @@
"loraStatus": {
"none": "このレシピにはLoRAがありません",
"allAvailable": "すべてのLoRAが利用可能 - 使用可能",
"missing": "{total} 件中 {missing} 件のLoRAが不足"
"missing": "{total} 件中 {missing} 件のLoRAが不足",
"missingAndUnavailable": "{total} 件中 {missing} 件のLoRAが不足、{unavailable} 件は利用不可(ソースから削除済みかハッシュを解決できません)",
"partial": "{total} 件中 {unavailable} 件のLoRAが利用不可(ソースから削除済みかハッシュを解決できません)- レシピ使用時はスキップされます",
"noneUsable": "使用可能なLoRAがありません - {total} 件中 {unavailable} 件がソースから削除済みかハッシュを解決できません"
},
"resources": {
"inLibrary": "ライブラリ内",
+4 -1
View File
@@ -883,7 +883,10 @@
"loraStatus": {
"none": "이 레시피에는 LoRA가 없습니다",
"allAvailable": "모든 LoRA 사용 가능 - 바로 사용 가능",
"missing": "총 {total}개 중 {missing}개 LoRA 누락"
"missing": "총 {total}개 중 {missing}개 LoRA 누락",
"missingAndUnavailable": "총 {total}개 중 {missing}개 LoRA 누락, {unavailable}개 사용 불가(소스에서 삭제되었거나 해시를 확인할 수 없음)",
"partial": "총 {total}개 중 {unavailable}개 LoRA 사용 불가(소스에서 삭제되었거나 해시를 확인할 수 없음) - 레시피 사용 시 건너뜁니다",
"noneUsable": "사용 가능한 LoRA가 없습니다 - 총 {total}개 중 {unavailable}개가 소스에서 삭제되었거나 해시를 확인할 수 없습니다"
},
"resources": {
"inLibrary": "라이브러리에 있음",
+4 -1
View File
@@ -883,7 +883,10 @@
"loraStatus": {
"none": "В этом рецепте нет LoRAs",
"allAvailable": "Все LoRAs доступны - Готово к использованию",
"missing": "Отсутствует {missing} из {total} LoRAs"
"missing": "Отсутствует {missing} из {total} LoRAs",
"missingAndUnavailable": "Отсутствует {missing} из {total} LoRAs, {unavailable} недоступны (удалены из источника или хеш не разрешается)",
"partial": "{unavailable} из {total} LoRAs недоступны (удалены из источника или хеш не разрешается) - будут пропущены при использовании рецепта",
"noneUsable": "Нет доступных LoRAs - {unavailable} из {total} удалены из источника или хеш не разрешается"
},
"resources": {
"inLibrary": "В библиотеке",
+4 -1
View File
@@ -883,7 +883,10 @@
"loraStatus": {
"none": "此配方不包含 LoRA",
"allAvailable": "所有 LoRA 均已就绪 - 可直接使用",
"missing": "{total} 个 LoRA 中缺失 {missing} 个"
"missing": "{total} 个 LoRA 中缺失 {missing} 个",
"missingAndUnavailable": "{total} 个 LoRA 中缺失 {missing} 个,{unavailable} 个不可用(已从源站删除或哈希无法解析)",
"partial": "{total} 个 LoRA 中 {unavailable} 个不可用(已从源站删除或哈希无法解析)- 使用配方时将被跳过",
"noneUsable": "没有可用的 LoRA - {total} 个中 {unavailable} 个已从源站删除或哈希无法解析"
},
"resources": {
"inLibrary": "在库中",
+4 -1
View File
@@ -883,7 +883,10 @@
"loraStatus": {
"none": "此配方不含 LoRA",
"allAvailable": "所有 LoRA 皆已就緒 - 可直接使用",
"missing": "{total} 個 LoRA 中缺少 {missing} 個"
"missing": "{total} 個 LoRA 中缺少 {missing} 個",
"missingAndUnavailable": "{total} 個 LoRA 中缺少 {missing} 個,{unavailable} 個不可用(已從來源刪除或雜湊無法解析)",
"partial": "{total} 個 LoRA 中 {unavailable} 個不可用(已從來源刪除或雜湊無法解析)- 使用配方時將被略過",
"noneUsable": "沒有可用的 LoRA - {total} 個中 {unavailable} 個已從來源刪除或雜湊無法解析"
},
"resources": {
"inLibrary": "已在庫存",