Instead of always using default paths, downloads from the model versions
tab now target the same directory as the current in-library version.
Falls back silently to default paths if the current version path cannot
be resolved.
Store textarea reference on container element to allow cloned widgets to access inputEl when promoted to subgraph nodes. This ensures both original and cloned widgets can properly get and set values through the shared DOM element.
Update the help text for 'Metadata Refresh Skip Paths' setting to explicitly
state that paths should be relative to the 'model root directory' instead of
just saying 'relative folder paths', which was ambiguous.
Updated translations:
- English (en)
- Chinese Simplified (zh-CN)
- Chinese Traditional (zh-TW)
- Japanese (ja)
- Korean (ko)
- Russian (ru)
- German (de)
- French (fr)
- Spanish (es)
- Hebrew (he)
Replace _SYNC_KEYS (37 keys) with _NO_SYNC_KEYS (5 keys) in SettingsHandler.
New settings automatically sync to frontend unless explicitly excluded.
Changes:
- SettingsHandler now syncs all settings except those in _NO_SYNC_KEYS
- Added keys() method to SettingsManager for iteration
- Updated tests to use new behavior
Benefits:
- No more missing keys when adding new settings
- Reduced maintenance burden
- Explicit exclusions for sensitive/internal settings only
Fixes: #86
Complete TODO translations from previous commit:
- Add translations for hideEarlyAccessUpdates setting
- Add translations for EA time formatting (endingSoon, hours, days)
- Add translations for EA badges and tooltips
- Translate to: de, es, fr, he, ja, ko, ru, zh-CN, zh-TW
Closes#815 translations
Add Early Access version support with filtering and improved UI:
Backend:
- Add is_early_access and early_access_ends_at fields to ModelVersionRecord
- Implement two-phase EA detection (bulk API + single API enrichment)
- Add hide_early_access_updates setting to filter EA updates
- Update has_update() and has_updates_bulk() to respect EA filter setting
- Add _enrich_early_access_details() for precise EA time fetching
- Fix setting propagation through base_model_service and model_update_service
Frontend:
- Add smart relative time display for EA (in Xh, in Xd, or date)
- Replace EA label with clock icon in metadata (fa-clock)
- Show Download button with bolt icon for EA versions (fa-bolt)
- Change EA badge color to #F59F00 (CivitAI Buzz theme)
- Fix toggle UI for hide_early_access_updates setting
- Add translation keys for EA time formatting
Tests:
- Update all tests to pass with new EA functionality
- Add test coverage for EA filtering logic
Closes#815
- Backend: Support limit=0 to return all tags in top-tags API
- Frontend: Remove tags limit setting and fetch all tags by default
- UI: Implement virtual scrolling in TagsModal for performance
- Initial display 200 tags, load more on scroll
- Show all results when searching
- Remove lora_pool_tags_limit setting to simplify UX
Fixes#819
Fix KeyError when 'hashes', 'name', or 'model' fields are missing from
Civitai API responses. Use .get() with defaults instead of direct dict
access in:
- LoraMetadata.from_civitai_info()
- CheckpointMetadata.from_civitai_info()
- EmbeddingMetadata.from_civitai_info()
- RecipeScanner._get_hash_from_civitai()
- DownloadManager._process_download()
Fixes#820
Previously, long LoRA filenames were truncated from the right with ellipsis,
which hid important checkpoint step numbers (e.g., -00800, -01000) that users
need to distinguish between different training checkpoints.
Changes:
- Replace single-line truncation with multi-line display (max 3 lines)
- Add line-height and word-break properties for better readability
- Use -webkit-line-clamp to gracefully handle extremely long names
This ensures the step number suffix is always visible in the tooltip.
- Remove max height setting, let ComfyUI handle widget sizing
- Widget now uses getMinHeight() to declare 150px minimum
- Container fills available space with overflow: auto for scrollbars
- Users can freely resize the node; content overflows show scrollbar
- Simplified renderTags by removing height calculation logic
Fixes#706
- Add new setting 'loramanager.trigger_word_max_height' (150-600px, default 300px)
- Add getTriggerWordMaxHeight() getter to retrieve setting value
- Update tags_widget to respect max height limit with scrollbar
- Add getMaxHeight callback for ComfyUI layout system
- Add tooltip note about requiring page reload
Fixes#706
- Extract progress file loading to async methods to run in executor
- Refactor start_download to reduce lock time by pre-loading data before entering lock
- Improve check_pending_models efficiency with single-pass model collection and async loading
- Add type hints to get_status method
- Add tests for download task callback execution and error handling
Translate all skip metadata refresh UI strings to all supported languages:
- zh-CN, zh-TW, ja, ko, de, fr, es, ru, he
Completes the translation TODOs from the previous commit.
- Reframe supporter access section to emphasize sustainability and gratitude
- Add CivArchive support announcement and image
- Document new dedicated download button and hide models feature in v0.4.8
- Improve readability and flow of the overview and supporter sections
- Add clear button inside autocomplete text widget that shows when text exists
- Support both Canvas mode and Vue DOM mode with appropriate styling
- Fix clear button visibility when value is changed externally (e.g., via 'send lora to workflow')
- Implement dual notification mechanism: CustomEvent + onSetValue callback
- Update widget interface to include onSetValue property
When no duplicate groups are detected, the duplicate manager now checks if it is currently in duplicate mode and calls `exitDuplicateMode()` to clear the display. This prevents the UI from showing stale duplicate information when no duplicates exist.
Add a segmented toggle in the Filter Panel to switch between 'Any' (OR)
and 'All' (AND) logic when filtering by multiple include tags.
Changes:
- Backend: Add tag_logic field to FilterCriteria and ModelFilterSet
- Backend: Parse tag_logic parameter in model handlers
- Frontend: Add segmented toggle UI in filter panel header
- Frontend: Add interaction logic and state management for tag logic
- Add translations for all supported languages
- Add comprehensive tests for the new feature
Closes#802
Add automatic cleanup of default values from settings.json to keep configuration files minimal and focused on user customizations. Introduces a threshold-based cleanup that only removes default values when the file contains a significant number of them (10+), preserving small template-based configurations while cleaning up legacy bloated files.
Key changes:
- Add DEFAULT_KEYS_CLEANUP_THRESHOLD constant to control cleanup aggressiveness
- Implement _cleanup_default_values_from_disk() method that removes default values from disk while keeping them available in memory
- Modify _ensure_default_settings() to only save when existing values are updated, not when defaults are inserted
- Update _serialize_settings_for_disk() to only persist settings that differ from defaults
- Add cleanup call during initialization for existing settings files
This reduces file size and noise in settings.json while maintaining full functionality at runtime.
- Added filter presets feature allowing users to save and quickly switch between filter combinations
- Fixed various bugs to improve overall stability
- Updated project version from 0.9.14 to 0.9.15 in pyproject.toml
- Use modelVersionId as fallback for all loras in fingerprint calculation (not just deleted)
- Add URL-based duplicate detection using source_path field
- Combine both fingerprint and URL-based duplicate detection in API response
- Fix _download_remote_media return type and unbound variable issue
- Hide delete button by default and show on hover for inactive presets
- Show delete button on active presets only when hovering over the preset
- Add ellipsis truncation for long preset names to prevent layout breakage
- Remove checkmark icon from active preset names for cleaner visual design
When checkpoints and unet folders point to the same physical location
(via symlinks), prioritize checkpoints for backward compatibility.
This prevents the 'Failed to load Checkpoint root' error that users
experience when they have incorrectly configured their ComfyUI paths.
Changes:
- Detect overlapping real paths between checkpoints and unet
- Log warning to inform users of the configuration issue
- Remove overlapping paths from unet_map, keeping checkpoints
Fixes #<issue-number>
Introduce a new private method `_normalize_trigger_words` to handle consistent splitting and cleaning of trigger word strings. This method splits input by both single and double commas, strips whitespace, and filters out empty strings, returning a set of normalized words. It is now used in `process_trigger_words` to compare trigger word overrides, ensuring accurate detection of changes by comparing normalized sets instead of raw strings.
The width of the repeat input field in the LoRA cycler settings view has been increased from 40px to 50px. This change improves usability by providing more space for user input, making the control easier to interact with and reducing visual crowding.
When a deleted model is checked against the SQLite archive and not found, the `db_checked` flag was set in memory but never saved to disk. This occurred because the save operation was only triggered when `civitai_api_not_found` was True, which is not the case for deleted models (since the CivitAI API is not attempted). As a result, deleted models would be rechecked on every refresh instead of being skipped.
Changes:
- Introduce a `needs_save` flag to track when metadata state is updated
- Save metadata whenever `db_checked` is set to True, regardless of API status
- Ensure `last_checked_at` is set for SQLite-only attempts
- Add regression test to verify the fix
- Add LoRA Cycler node with iteration support
- Enhance Prompt node with tag autocomplete (Danbooru + e621)
- Add command system (/char, /artist, /ac, /noac) for tag operations
- Reference Lora Cycler and Lora Manager Basic template workflows
- Bug fixes and stability improvements
Refactor recipe lookup logic to improve efficiency from O(n²) to O(n + m):
- Build recipe_by_id dictionary for O(1) recipe ID lookups
- Simplify persisted_by_path construction using recipe_id extraction
- Add fallback lookup by recipe_id when path lookup fails
- Maintain same functionality while reducing computational complexity
When enable_metadata_archive_db=True, the previous filter logic would
repeatedly try to fetch metadata for models that were already confirmed
to not exist on CivitAI (from_civitai=False, civitai_deleted=True).
The fix adds a skip condition to exclude models that:
1. Are confirmed not from CivitAI (from_civitai=False)
2. Are marked as deleted/not found on CivitAI (civitai_deleted=True)
3. Either have no archive DB enabled, or have already been checked (db_checked=True)
This prevents unnecessary API calls to CivArchive for user-trained models
or models from non-CivitAI sources.
Fixes repeated "Error fetching version of CivArchive model by hash" logs
for models that will never be found on CivitAI/CivArchive.