Redefine the empty download filename template from a no-op to a bulk revert: FilenameTemplateUseCase resolves the target from each model's recorded original_file_name sidecar entry (skipping models without one), which resolves follow-ups 1 and 2 with a single coherent semantic shared by the download and bulk-apply paths. Also replace the browser-native confirm() with a self-managed confirmation modal (filenameTemplateConfirmModal) that stacks above the settings modal, since ModalManager would close the settings modal when opening a registered one.
5.7 KiB
Plan: Filename Template Follow-ups
Issue: #1071 — Lora Renaming
Status: Core feature implemented (2026-09-19, commit 2bc9860b,
preceded by the settings-tab split in 327da046). Follow-ups 1 and 2 were
resolved together on 2026-09-19 by redefining the empty template as
"revert to recorded original filename" (see below). Follow-up 3 remains open.
What shipped in 2bc9860b
- Per-model-type
download_filename_templatessetting (empty = keep current filename; opt-in). Placeholders:{model_name},{version_name},{base_model},{author},{first_tag},{hash_short},{original_name}. calculate_filename_for_model()inpy/utils/utils.pyrenders the template; templates containing path separators are rejected.- Downloads apply the template post-download
(
DownloadManager._apply_download_filename_template); rename conflicts keep the original name and never fail the download. ModelLifecycleService.rename_modelrecordsoriginal_file_namein the.metadata.jsonsidecar (first rename wins viasetdefault).- Bulk apply:
GET|POST /api/lm/{prefix}/apply-filename-template(FilenameTemplateUseCase, shares the auto-organize lock, WS progress typefilename_template_progress). - Settings UI: "Filename Templates" subsection in the new Organization
settings tab (
templates/components/modals/settings/organization.html), with validation, live preview, and per-type "Apply to Library Now".
Sandbox E2E verified: rename incl. companion files (previews, sidecars),
metadata pointer updates, original_file_name recording, idempotency,
conflict handling (failure counted, batch continues), empty-template no-op,
GET variant.
Follow-ups 1 & 2 — RESOLVED: empty template = revert to recorded original
Follow-up 1 asked to reword the ambiguous "Valid (keep original filename)"
empty-template message; Follow-up 2 asked for a bulk revert to the recorded
original_file_name. Both were resolved by a single semantic change: an
empty template now means "restore the recorded original filename" instead of
"leave the current filename untouched".
Rationale: for never-renamed models a revert is a no-op (no recorded
original), for renamed models it restores the pre-rename name, and new
downloads with an empty template keep the download name as before — so the
two contexts (download path and bulk apply) share one coherent meaning, and
no separate revert feature or {recorded_original} placeholder is needed.
Implemented changes:
FilenameTemplateUseCase._process_model: an empty template now resolves the target name from the sidecar'soriginal_file_namevia the injectedmetadata_loader(defaultload_local_metadata); models without a recorded original or whose original matches the current name are skipped. Cache entries do not projectoriginal_file_name, so the sidecar is read per model.SettingsManager.js: removed the empty-template early return and the apply-button disable (updateFilenameTemplateApplyButtondeleted — the button is now always enabled). The browser-nativeconfirm()was replaced withfilenameTemplateConfirmModal(templates/components/modals/confirm_modals.html), a self-managed modal (likeDirectoryPickerModal, NOT registered with ModalManager): ModalManager's "close current modal on open" behavior would kill the settings modal underneath. It stacks viaz-index: 10010(delete-modal.css), handles ESC in capture phase withstopPropagation, and shows apply vs revert wording (modals.filenameTemplateConfirm.titleApply/titleRevert/revertButton; messages reusesettings.filenameTemplates.confirmApply/confirmRevert).locales/en.json: rewordedhelp/applyHelp, replacedvalidation.keepOriginalwithvalidation.restoreOriginal("Valid (empty template restores original filenames)"), addedconfirmRevert, removed the now-unusedemptyTemplateInfo. Other locales re-synced with[TODO: Translate]placeholders — retranslation waits for the feature owner's request perdocs/i18n-translation-guidelines.md§7.- Tests: revert / no-record-skip / same-name-skip cases in
tests/services/test_use_cases.py; modal confirm-and-revert and cancel paths intests/frontend/managers/settingsManager.filenameTemplates.test.js.
Sandbox E2E verified (standalone server, sandboxed settings + library under
/tmp, 2026-09-19): template apply renames and records
original_file_name; empty-template apply reverts to the recorded name;
revert target occupied by a newer file counts as failure and keeps the
current name; models without a recorded original are skipped;
apply → revert → re-apply cycles repeat cleanly.
Standing caveats (unchanged):
- The revert target may collide with an existing file — the existing conflict handling (count as failure, keep current name) covers this.
original_file_nameonly exists for models renamed after2bc9860b; older renames have no recorded original and are skipped.original_file_nameis kept (not cleared) after a revert, so apply → revert → re-apply stays repeatable.
Follow-up 3 — Cross-page refresh after bulk apply
Problem: the settings-modal "Apply to Library Now" button calls
resetAndReload(true), which refreshes only the page type currently open.
Applying the checkpoint template while on the loras page leaves the loras
view refreshed but does not touch the checkpoints page state (same
limitation as the existing bulk auto-organize flow in
static/js/managers/SettingsManager.js#applyFilenameTemplate).
Fix options: broadcast a generic "library changed" event that every page's state listens to, or accept the limitation (the other page reloads its cache on next visit). Low priority.