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": "이 폴더에는 아직 모델이 있습니다. 먼저 해당 모델을 삭제하거나 이동하세요 —— 폴더를 삭제해도 모델 파일이 함께 삭제되지는 않습니다.",
|
||||
"notEmptyMessageCount": "이 폴더에는 아직 모델 파일이 {count}개 있습니다. 먼저 해당 모델을 삭제하거나 이동하세요 —— 폴더를 삭제해도 모델 파일이 함께 삭제되지는 않습니다.",
|
||||
"notEmptyMessageExcluded": "이 폴더에는 아직 모델 파일이 {count}개 있으며, 그중 {excluded}개는 라이브러리에서 제외되어 있습니다. '제외된 모델 관리'에서 제외를 해제한 뒤 먼저 삭제하세요 —— 폴더를 삭제해도 모델 파일이 함께 삭제되지는 않습니다.",
|
||||
"missingTitle": "폴더를 찾을 수 없습니다",
|
||||
"missingMessage": "이 폴더는 디스크에 더 이상 존재하지 않습니다. 사이드바를 새로 고친 후 다시 시도하세요.",
|
||||
"symlinkTitle": "폴더가 심볼릭 링크입니다",
|
||||
"symlinkMessage": "이 폴더의 모든 복사본이 심볼릭 링크입니다. LoRA Manager 외부에서 링크 또는 그 대상을 삭제하세요.",
|
||||
"busyTitle": "대기 중인 삭제 작업이 있습니다",
|
||||
"checking": "폴더 내용을 확인하는 중...",
|
||||
"confirm": "폴더 삭제"
|
||||
"confirm": "폴더 삭제",
|
||||
"confirmMulti": "폴더 {count}개 삭제",
|
||||
"deleting": "삭제하는 중...",
|
||||
"keptNote": "선택하지 않은 복사본이 있으면 이 폴더가 사이드바에 계속 표시됩니다."
|
||||
},
|
||||
"deleteFolderResult": {
|
||||
"success": "\"{name}\" 폴더를 삭제했습니다",
|
||||
@@ -1422,7 +1429,10 @@
|
||||
"notEmptyWithCount": "이 폴더에는 아직 모델 파일이 {count}개 있습니다. 사이드바를 새로 고친 후 다시 시도하세요.",
|
||||
"busy": "이 폴더에 아직 대기 중인 삭제 작업이 있습니다. 되돌리기 시간이 끝날 때까지 기다리세요.",
|
||||
"unsupported": "이 페이지에서는 폴더를 삭제할 수 없습니다",
|
||||
"noRoot": "모델 루트가 설정되지 않았습니다"
|
||||
"missing": "이 폴더는 디스크에 더 이상 존재하지 않습니다. 사이드바를 새로 고친 후 다시 시도하세요.",
|
||||
"symlink": "이 폴더는 심볼릭 링크이므로 사이드바에서 삭제할 수 없습니다.",
|
||||
"successMulti": "모델 루트 {count}개에서 \"{name}\" 폴더를 삭제했습니다",
|
||||
"partial": "복사본 {total}개 중 {count}개를 삭제했습니다 —— {failed}개는 삭제하지 못했습니다. 사이드바를 새로 고친 후 다시 시도하세요."
|
||||
},
|
||||
"renameFolder": "폴더 이름 바꾸기",
|
||||
"renameFolderResult": {
|
||||
@@ -1431,7 +1441,25 @@
|
||||
"targetExists": "같은 이름의 폴더가 이미 있습니다",
|
||||
"busy": "이 폴더에 아직 대기 중인 삭제 작업이 있습니다. 되돌리기 시간이 끝날 때까지 기다리세요.",
|
||||
"unsupported": "이 페이지에서는 폴더 이름을 바꿀 수 없습니다",
|
||||
"noRoot": "모델 루트가 설정되지 않았습니다"
|
||||
"missing": "이 폴더는 디스크에 더 이상 존재하지 않습니다. 사이드바를 새로 고친 후 다시 시도하세요.",
|
||||
"symlink": "이 폴더는 심볼릭 링크이므로 사이드바에서 이름을 바꿀 수 없습니다."
|
||||
},
|
||||
"folderRoot": {
|
||||
"chooseTitle": "이 폴더는 여러 모델 루트에 존재합니다",
|
||||
"symlinkOption": "심볼릭 링크",
|
||||
"rootsHint": "이 폴더를 삭제할 모델 루트를 선택하세요:",
|
||||
"checkingStatus": "확인하는 중...",
|
||||
"okStatus": "모델 없음",
|
||||
"notEmptyStatus": "모델 파일이 {count}개 있습니다 —— 먼저 삭제하거나 이동하세요",
|
||||
"notEmptyExcludedStatus": "모델 파일이 {count}개 있으며, 그중 {excluded}개는 라이브러리에서 제외되어 있습니다",
|
||||
"busyStatus": "대기 중인 삭제 작업이 있습니다",
|
||||
"missingStatus": "디스크에 존재하지 않습니다",
|
||||
"symlinkStatus": "심볼릭 링크 —— 여기에서는 삭제할 수 없습니다",
|
||||
"unknownStatus": "확인할 수 없습니다",
|
||||
"deletedStatus": "삭제됨"
|
||||
},
|
||||
"folderResult": {
|
||||
"unresolved": "이 폴더가 어느 모델 루트에 있는지 확인할 수 없습니다. 사이드바를 새로 고친 후 다시 시도하세요."
|
||||
},
|
||||
"dragDrop": {
|
||||
"unableToResolveRoot": "이동할 대상 경로를 확인할 수 없습니다.",
|
||||
|
||||
Reference in New Issue
Block a user