mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-10-08 02:22:12 -03:00
feat(sidebar): manage folders that live under several model roots
The sidebar's folder tree merges every model root into one relative-path
namespace, but folder operations turned a node into a path by prefixing
default_*_root. A folder living under another root failed to delete with
"Folder no longer exists" (recipes under the primary lora root while
default_lora_root is the extra one), and where the same relative folder
exists in both roots the operation silently hit the other copy — 14 of the
16 top-level folders in the reporting library are shared, so guessing a root
was never safe.
Backend:
* ModelMoveService.resolve_folder() and GET /api/lm/{prefix}/resolve-folder
answer which directories a library-relative folder maps to
(folder_path/root/is_symlink), in scanner root order, skipping directories
no root holds and refusing absolute or climbing paths.
* delete_folder/rename_folder tag a vanished directory with code "missing"
so the sidebar can tell "this node is stale, refresh" from a failed
operation.
Frontend:
* _resolveFolderCandidates() is the single place that turns a node into
absolute paths: default root first, the old root-prefix fallback only
while a single root is configured, and an explicit unresolved error for a
multi-root library — nothing is guessed silently any more.
* One copy keeps the single-target modal, which now names the resolved
absolute path. Several copies render one checkbox row per copy, each
dry-run against the delete guard ("no models" / "contains N model
file(s)..." / a deletion is still pending / no longer exists / symbolic
link): a blocked copy is unticked, disabled and explained, the button
reads "Delete N folders", every ticked copy is deleted and guarded on its
own, and a partial failure is reported without discarding the successes.
* Rows are built once per open and only their status text is updated, so
ticking a box no longer rebuilds the list, steals focus or resizes the
modal mid-click; the action row keeps a fixed button width.
* Rename offers a root picker in its inline row, create inherits the
parent's root when the parent resolves to exactly one directory, and the
undo restores every copy a delete removed.
i18n: 26 new keys (sidebar.deleteFolderModal.*, .deleteFolderResult.*,
.renameFolderResult.*, .folderRoot.*, .folderResult.*) translated in all 9
locales, with the en wording normalized to the established "model root" noun
(it had said "library root") and the new terminology recorded in
docs/i18n-translation-guidelines.md.
Verified: pytest 3686 passed, vitest 1473 passed (86 in the folder-management
suite), pytest tests/i18n 20 passed, sync_translation_keys.py --dry-run
clean. A sandboxed standalone instance with two roots confirmed that deleting
one copy leaves the node in place, that the twin's model card survives the
purge, and that deleting both copies and undoing restores both directories.
This commit is contained in:
+31
-3
@@ -1409,9 +1409,16 @@
|
||||
"notEmptyMessage": "Dieser Ordner enthält noch Modelle. Löschen oder verschieben Sie diese zuerst — beim Löschen eines Ordners werden Modelldateien niemals mitgelöscht.",
|
||||
"notEmptyMessageCount": "Dieser Ordner enthält noch {count} Modelldatei(en). Löschen oder verschieben Sie diese zuerst — beim Löschen eines Ordners werden Modelldateien niemals mitgelöscht.",
|
||||
"notEmptyMessageExcluded": "Dieser Ordner enthält noch {count} Modelldatei(en), davon {excluded} von der Bibliothek ausgeschlossen. Heben Sie den Ausschluss unter „Ausgeschlossene Modelle verwalten“ auf und löschen Sie sie zuerst — beim Löschen eines Ordners werden Modelldateien niemals mitgelöscht.",
|
||||
"missingTitle": "Ordner nicht gefunden",
|
||||
"missingMessage": "Dieser Ordner existiert nicht mehr auf dem Datenträger. Aktualisieren Sie die Seitenleiste und versuchen Sie es erneut.",
|
||||
"symlinkTitle": "Ordner ist ein symbolischer Link",
|
||||
"symlinkMessage": "Alle Kopien dieses Ordners sind symbolische Links; entfernen Sie den Link oder sein Ziel außerhalb von LoRA Manager.",
|
||||
"busyTitle": "Eine Löschung steht noch aus",
|
||||
"checking": "Ordnerinhalt wird geprüft...",
|
||||
"confirm": "Ordner löschen"
|
||||
"confirm": "Ordner löschen",
|
||||
"confirmMulti": "{count} Ordner löschen",
|
||||
"deleting": "Wird gelöscht...",
|
||||
"keptNote": "Nicht angehakte Kopien lassen diesen Ordner in der Seitenleiste bestehen."
|
||||
},
|
||||
"deleteFolderResult": {
|
||||
"success": "Ordner \"{name}\" gelöscht",
|
||||
@@ -1422,7 +1429,10 @@
|
||||
"notEmptyWithCount": "Dieser Ordner enthält noch {count} Modelldatei(en). Aktualisieren Sie die Seitenleiste und versuchen Sie es erneut.",
|
||||
"busy": "In diesem Ordner steht noch eine Löschung aus. Warten Sie, bis das Zeitfenster für das Rückgängigmachen abgelaufen ist.",
|
||||
"unsupported": "Das Löschen von Ordnern wird auf dieser Seite nicht unterstützt",
|
||||
"noRoot": "Es ist kein Modell-Stammverzeichnis konfiguriert"
|
||||
"missing": "Dieser Ordner existiert nicht mehr auf dem Datenträger. Aktualisieren Sie die Seitenleiste und versuchen Sie es erneut.",
|
||||
"symlink": "Dieser Ordner ist ein symbolischer Link; er kann nicht über die Seitenleiste gelöscht werden.",
|
||||
"successMulti": "Ordner \"{name}\" aus {count} Modell-Stammverzeichnissen gelöscht",
|
||||
"partial": "{count} von {total} Kopien gelöscht — {failed} konnten nicht gelöscht werden. Aktualisieren Sie die Seitenleiste und versuchen Sie es erneut."
|
||||
},
|
||||
"renameFolder": "Ordner umbenennen",
|
||||
"renameFolderResult": {
|
||||
@@ -1431,7 +1441,25 @@
|
||||
"targetExists": "Ein Ordner mit diesem Namen ist hier bereits vorhanden",
|
||||
"busy": "In diesem Ordner steht noch eine Löschung aus. Warten Sie, bis das Zeitfenster für das Rückgängigmachen abgelaufen ist.",
|
||||
"unsupported": "Das Umbenennen von Ordnern wird auf dieser Seite nicht unterstützt",
|
||||
"noRoot": "Es ist kein Modell-Stammverzeichnis konfiguriert"
|
||||
"missing": "Dieser Ordner existiert nicht mehr auf dem Datenträger. Aktualisieren Sie die Seitenleiste und versuchen Sie es erneut.",
|
||||
"symlink": "Dieser Ordner ist ein symbolischer Link; er kann nicht über die Seitenleiste umbenannt werden."
|
||||
},
|
||||
"folderRoot": {
|
||||
"chooseTitle": "Dieser Ordner existiert in mehreren Modell-Stammverzeichnissen",
|
||||
"symlinkOption": "symbolischer Link",
|
||||
"rootsHint": "Wählen Sie die Modell-Stammverzeichnisse, aus denen dieser Ordner gelöscht werden soll:",
|
||||
"checkingStatus": "wird geprüft...",
|
||||
"okStatus": "keine Modelle",
|
||||
"notEmptyStatus": "enthält {count} Modelldatei(en) — löschen oder verschieben Sie diese zuerst",
|
||||
"notEmptyExcludedStatus": "enthält {count} Modelldatei(en), davon {excluded} von der Bibliothek ausgeschlossen",
|
||||
"busyStatus": "eine Löschung steht noch aus",
|
||||
"missingStatus": "existiert nicht mehr auf dem Datenträger",
|
||||
"symlinkStatus": "symbolischer Link — hier nicht löschbar",
|
||||
"unknownStatus": "konnte nicht geprüft werden",
|
||||
"deletedStatus": "gelöscht"
|
||||
},
|
||||
"folderResult": {
|
||||
"unresolved": "Es konnte nicht ermittelt werden, welches Modell-Stammverzeichnis diesen Ordner enthält. Aktualisieren Sie die Seitenleiste und versuchen Sie es erneut."
|
||||
},
|
||||
"dragDrop": {
|
||||
"unableToResolveRoot": "Zielpfad für das Verschieben konnte nicht ermittelt werden.",
|
||||
|
||||
Reference in New Issue
Block a user