- Add an icon-only copy button next to Send to ComfyUI in the header
actions row, styled as a textless variant of the neighboring pill
buttons
- Restore fetchAndCopyRecipeSyntax() wiring against the existing
/api/lm/recipe/{id}/syntax endpoint (context menu action unaffected)
- Add recipes.actions.copyRecipeSyntax i18n key, reusing the existing
per-locale translations of the identical context menu string
- Sync modal test fixtures and add copySyntax tests
The Reconnect action button was rendered for both deleted and hash-invalid
(Unresolvable Hash) LoRA entries, but the .lora-reconnect-container input
form was only rendered for deleted ones. Clicking Reconnect on a
hash-invalid item silently did nothing because showReconnectInput() could
not find the container. Align the container render condition with the
button condition, and extend the resource-items test to assert the form
opens on click.
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
- import: prefer A1111 Lora hashes (12-char AutoV3) over conflicting Hashes
JSON values; recover the quote-wrapped AutoV3 from CivitAI image API meta;
merge EXIF-parsed LoRAs when the API-only parse yields none (meta=null)
- rematch: treat entries whose hash failed CivitAI resolution (hashInvalid)
as unresolved candidates; clear the flag on rematch/reconnect write-back
- download: persist hashInvalid and show a distinct toast when hash lookup
returns "Model not found", so unresolvable entries become recoverable
- ui: add Unresolvable Hash badge styling and reconnect affordance
- i18n: translate the new keys across all 10 locales
- Badges are pure status indicators with tooltips; remediation moves to a
per-item action row (Download / Reconnect), matching the versions-tab
badge/button pattern
- Civitai link inlines with the model title; the action row renders only
when real actions exist, removing empty-row whitespace
- Single-LoRA download resolves identifiers from hash on demand (same
fallback as the bulk missing-download flow) and shows immediate
'Preparing download' feedback while resolving
- Successful downloads (LoRA and checkpoint) refresh the resources
section and the recipe card in place, mirroring the bulk flow
- Row navigation is limited to in-library items with keyboard support;
checkpoint type renders as muted text instead of a chip; badges use
tonal styling; the local-path hover tooltip is removed
- Add resourceItems frontend tests and translate the new keys for all
10 locales
- Recipe card: compact status pill with state icon + available/total
fraction (e.g. "2/3"), pinned to the footer bottom-right like model
card actions; status is encoded by icon + color, never color alone
- Recipe modal: "N missing" is now a real <button> with a persistent
border, leading download icon, focus-visible ring and aria-label;
clicking opens the download-missing flow
- Fix context menu missing-LoRA detection selector after badge refactor
- i18n: add recipes.status/loraStatus keys with translations for all
10 locales, and fill pending rate-limit translations
Stop resetting the whole listing after a successful download. The legacy
flow reloaded page 1, scrolled to the top and hijacked the sidebar's
active folder whenever a custom target folder was used, which made the
Updates view lose its place (and sometimes render as an empty page).
Downloads only flip the update flag for one model, so the listing is now
reconciled in place through the virtual scroller:
- Updates view: the model's cards are removed once its newest eligible
version is installed (the flag is model-level).
- Normal listing: the card stays; only update_available is cleared.
- Model not in the current view (different folder/filter/window):
no-op; the sidebar folder tree alone is refreshed.
- Falling back to the legacy reload only when no virtual scroller is
available (e.g. recipes page, duplicates mode, HF downloads).
- Extract a shared BaseModelPicker (search, keyboard navigation,
filename-based suggestions, dynamic API models such as MiniMax H3
under 'Other (API)') used by both the single-model metadata modal
and the bulk base model modal
- Rework the bulk base model modal into a dedicated inline-list
layout: fixed modal size, sticky-free footer with app-standard
modal-actions/primary-btn/cancel-btn buttons, and an inline option
list that scrolls itself instead of an overlay dropdown covering
the footer
- Selecting an option in change mode now filters the list to the
selection instead of resetting and scroll-jumping to it
- Restore opaque sticky section headers in the bulk modal so scrolled
items no longer bleed through
After a drag move empties the selected folder, refresh() resets the
stale activeFolder to root but the grid kept showing the old filtered
(empty) view until a manual reload. Trigger resetAndReload when the
fallback happens post-initialization; the initial page load is untouched
because it picks up the cleared filter on its own.
restoreSelectedFolder trusted localStorage blindly: a stale activeFolder
(moved/deleted, or saved while the tree was still empty) left the grid
filtered to a nonexistent folder with a phantom breadcrumb and no way to
recover short of clicking the root breadcrumb. Validate the persisted
path against the freshly loaded tree and reset to root when it is gone;
skip validation when the tree load failed so transient errors don't wipe
the saved location.
The recipes page always rendered with is_initializing=False, so a cold
start displayed an empty grid that never updated until a manual refresh.
Mirror the model pages: gate render_page on the scanner state, broadcast
init progress from RecipeScanner (including a completion message, and a
failure fallback so the page never stalls), and teach initialization.js
to detect the /loras/recipes page before the generic /loras match.
Tag move-to-folder drags with a custom dataTransfer MIME type so card
preview-drop handlers skip them entirely (no highlight, no upload), and
mark the preview image non-draggable so the browser no longer synthesizes
a File payload when a drag starts on the image. Fixes card-on-card drops
and click-jitter self-drops replacing the preview with itself.
- Three-column layout (preview | generation parameters | resources) with
independent per-pane scrolling and a content-sized modal shell that
shrinks to fit short recipes and caps at viewport height for long ones
- Blurred, darker backdrop to focus attention on the modal
- Preview frame hugs the image instead of a fixed-size box
- Move recipe-level 'Send to ComfyUI' into the header actions row to match
the model detail modal convention; remove the modal 'Copy Recipe Syntax'
button (context menu action is unaffected)
- Add recipes.actions.sendRecipe i18n keys with translations
- Sync modal test fixtures to the new structure
CivitAI's PaidAccess cutover deprecated the availability=EarlyAccess and
earlyAccessEndsAt signals; gated versions now report availability=Public
with a paidAccess DTO that LoRA Manager previously ignored, so "Hide
Early Access Updates" missed paid/early-access models and downloads
failed with 401.
Parse and persist paidAccess from model-level, bulk, and by-hash
responses; treat timed paid gates as early access and permanent paid
versions as a distinct is_paid state; add a hide_paid_updates setting
with a "Paid" badge in the versions tab; warn before downloading gated
versions. Includes SQLite migration, i18n for all locales, and
backend/frontend tests.
Track recipe modal opens in a separate stats file (never touching recipe
JSON/EXIF), expose a fire-and-forget POST endpoint, and add an 'opened'
sort that hides never-opened recipes as a true recently-opened view.
Includes i18n for all locales and backend/frontend tests.
Downloads failed with "No suitable file found in metadata" for models whose
only file uses newer CivitAI file types (e.g. 'Enhancement LoRA' for
Anima/AIR image-editing LoRAs) because the primary-file allowlist only
covered legacy types.
- unify the weights-type allowlist as MODEL_WEIGHT_FILE_TYPES
(py/utils/constants.py) and apply it across download, recipe and
metadata-refresh lookups
- mirror CivitAI's getPrimaryFile() semantics: prefer weights-type primary,
fall back to weights files, then trust CivitAI's primary flag (excluding
non-downloadable artifacts like Config/Archive/Workflow)
- mirror the allowlist in the frontend via shared isModelWeightFile() helper
- add regression tests for the Enhancement LoRA primary-file download,
primary-flag fallback and weights-over-non-weights-primary preference
Version-tab updates reused the current version's folder, so updating a LoRA
to a version with a different base model (e.g. Illustrious -> Anima) ignored
the download path template and landed in the old version's directory.
When the target version's base model differs from the current local version
and a path template is configured, re-resolve the template under the same
model root. The backend keeps an explicitly provided root when
use_save_dir_as_root is set, so regular downloads still use the default root.
Move the recipe delete modal's undo warning into modals.deleteRecipe.
recoverableWarning instead of hardcoded English; sync placeholders into
all 9 non-English locales
- Remove delete_undo_enabled setting (backend default, frontend state,
settings modal UI, 10 locales); staged deletes with 30s undo are now
the only delete path and stale settings keys are silently ignored
- Remove the 1500ms delete-button arm delay (armDeleteButton) from all
delete modals; misclicks are recoverable via the undo toast
- Delete modal always shows the recoverable warning
- Log the first staged file path in staging log lines for easier support
Move the 'Download Missing' / 'Re-process All' example image actions
under a single 'Download Example Images' submenu item in the single-model
and bulk context menus, matching the existing send-to-workflow submenu
pattern. Shorten the submenu labels and update all locale translations.
Split the single-model and bulk context menu actions into 'Download
Missing Example Images' (regular endpoint, skips already-processed
models) and 'Re-process Example Images' (force endpoint, retries
failed models).
- start_download accepts model_hashes so a selected subset can be
processed with the progress-aware skip logic; explicitly targeted
models bypass the failed/processed model-level guards so per-image
gaps are filled
- pre-download existence check in the processor skips network requests
for image files already on disk across all download paths
- force download retries previously failed models and clears their
failed status on success
- add i18n keys for the new menu items across all locales
When using full path lora syntax, the context menu (single/bulk)
and bulk copy actions were passing only the file basename to
buildLoraSyntax(), ignoring the folder prefix. This caused the
output to look like legacy A1111 format even when full path mode
was enabled.
Aligns all entry points with ModelCard.handleSendToWorkflow(),
which correctly includes the folder prefix.
Also fixes selectAllVisibleModels() to cache the folder field,
preventing missing prefix on select-all-then-send flows.