Commit Graph

34 Commits

Author SHA1 Message Date
Will Miao
2121054cb9 feat(lora-cycler): implement batch queue synchronization with dual-index mechanism
- Add execution_index and next_index fields to CyclerConfig interface
- Introduce beforeQueued hook in widget to handle index shifting for batch executions
- Use execution_index when provided, fall back to current_index for single executions
- Track execution state with Symbol to differentiate first vs subsequent executions
- Update state management to handle dual-index logic for proper LoRA cycling in batch queues
2026-01-22 21:22:52 +08:00
Will Miao
bf0291ec0e test(nodeModeChange): fix tests after mode change refactoring
After refactoring mode change logic from lora_stacker.js to main.ts
(compiled to lora-manager-widgets.js), updateConnectedTriggerWords became
a bundled inline function, making the mock from utils.js ineffective.

Changes:
- Import Vue widgets module in test to register mode change handlers
- Call both extensions' beforeRegisterNodeDef when setting up nodes
- Fix test node structure with proper widget setup (input widget with
  options property and loras widget with test data)
- Update test assertions to verify mode setter configuration via property
  descriptor check instead of mocking bundled functions

Also fix Lora Cycler widget min height from 316 to 314 pixels.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-22 20:56:41 +08:00
Will Miao
932d85617c refactor(lora-provider): extract mode change logic to shared TypeScript module
- Extract common mode change logic from lora_randomizer.js and lora_stacker.js
  into new mode-change-handler.ts TypeScript module
- Add LORA_PROVIDER_NODE_TYPES constant to centralize LoRA provider node types
- Update getActiveLorasFromNode in utils.js to support Lora Cycler's
  cycler_config widget (single current_lora_filename)
- Update getConnectedInputStackers and updateDownstreamLoaders to use
  isLoraProviderNode helper instead of hardcoded class checks
- Register mode change handlers in main.ts for all LoRA provider nodes
  (Lora Stacker, Lora Randomizer, Lora Cycler)
- Add value change callback to Lora Cycler widget to trigger
  updateDownstreamLoaders when current_lora_filename changes
- Remove duplicate mode change logic from lora_stacker.js
- Delete lora_randomizer.js (logic now centralized)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-22 20:46:09 +08:00
Will Miao
b0f852cc6c refactor(lora-cycler): remove sort by control, always use filename
Removed the sort by selection UI from the Lora Cycler widget and
hardcoded the sorting to always use filename. This simplifies the
interface while maintaining all sorting functionality.

Changes:
- Removed sort_by prop/emit from LoraCyclerSettingsView
- Removed sort tabs UI and associated styles
- Hardcoded sort_by = "filename" in backend node
- Removed sort by handling logic from LoraCyclerWidget
- Updated widget height to accommodate removal
2026-01-22 19:58:51 +08:00
Will Miao
d1c65a6186 fix(dual-range-slider): allow equal min/max values in Lora Randomizer (#775)
Add allowEqualValues prop to DualRangeSlider component (default: false for backward compatibility).
When enabled, removes the step offset constraint that prevented min and max handles from being set to the same value.

Applied to all range sliders in LoraRandomizerSettingsView:
- LoRA Count range slider
- Model Strength Range slider
- Recommended Strength Scale slider
- Clip Strength Range slider

Backend already handles equal values correctly via rng.uniform().
2026-01-22 16:47:39 +08:00
Will Miao
6fbea77137 feat(lora-cycler): add sequential LoRA cycling through filtered pool
Add Lora Cycler node that cycles through LoRAs sequentially from a filtered pool. Supports configurable sort order, strength settings, and persists cycle progress across workflow save/load.

Backend:
- New LoraCyclerNode with cycle() method
- New /api/lm/loras/cycler-list endpoint
- LoraService.get_cycler_list() for filtered/sorted list

Frontend:
- LoraCyclerWidget with Vue.js component
- useLoraCyclerState composable
- LoraCyclerSettingsView for UI display
2026-01-22 15:36:32 +08:00
Will Miao
1b7b598f7a feat(sliders): adjust value label positioning and line height
- Move slider handle value labels 6px upward in both DualRangeSlider and SingleSlider components
- Add consistent line-height of 14px to ensure proper text alignment
- Improves visual spacing and readability of value labels during slider interaction
2026-01-21 01:05:15 +08:00
Will Miao
fd06086a05 feat(lora_randomizer): implement dual seed mechanism for batch queue synchronization, fixes #773
- Add execution_seed and next_seed parameters to support deterministic randomization across batch executions
- Separate UI display generation from execution stack generation to maintain consistency in batch queues
- Update LoraService to accept optional seed parameter for reproducible randomization
- Ensure each execution with a different seed produces unique results without affecting global random state
2026-01-21 00:52:08 +08:00
Will Miao
50c012ae33 fix(ui): unify Lora Randomizer widget styles with Loras widget
Align visual design of Lora Randomizer widget with Loras widget for
consistent UI/UX across the node interface.

Changes:
- Unified border-radius system (4px→6px for containers, 6px for inputs)
- Standardized padding (12px→6px for widget container)
- Reduced slider height (32px→24px) following desktop tool best practices
- Aligned font sizes (12px→13px for labels, 11px→12px for buttons)
- Unified spacing system (16px→6px for sections, 8px→6px for gaps)
- Adjusted widget minimum height (510px→448px) to reflect layout changes
2026-01-20 20:38:24 +08:00
Will Miao
88e7f671d2 fix(autocomplete): resolve instability in Vue DOM mode and fix WanVideo node binding
- Fix infinite reinitialization loop by only validating stale widget.inputEl when it's actually in DOM
- Improve findWidgetInputElement to specifically search for textarea for text widgets, avoiding mismatches with checkbox inputs on nodes like WanVideo Lora Select that have toggle switches
- Add data-node-id based element search as primary strategy for better reliability across rendering modes
- Fix autocomplete initialization to properly handle element DOM state transitions

Fixes autocomplete failing after Canvas ↔ Vue DOM mode switches and WanVideo node always failing to trigger autocomplete.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-01-17 14:19:20 +08:00
Will Miao
c5b597dc89 Merge branch 'main' of https://github.com/willmiao/ComfyUI-Lora-Manager 2026-01-15 16:05:41 +08:00
Will Miao
bd4958edc3 fix: improve loras widget drag functionality in Vue DOM render mode
- Use pointer events (pointerdown/pointermove/pointerup/pointercancel) with proper capture
- Fix drag not updating strength values by avoiding re-renders during drag
- Fix cursor stuck in resize state by ensuring proper cleanup
- Fix cursor showing wrong icon on hover (should be pointer)
- Ensure strength values display fixed width with 2 decimal places
- Remove unnecessary data-capture-wheel attribute (no wheel adjustment in loras widget)
- Add font-variant-numeric: tabular-nums for consistent number display

This ensures loras widget works consistently in both Canvas and Vue DOM render modes.
2026-01-15 15:57:48 +08:00
Will Miao
428a2ce420 fix: support multiple include folders in LoRA pool widget
- Add folder_include parameter support in backend API handlers
- Add folder_include to FilterCriteria and implement multi-folder filtering logic
- Update frontend to send all include folders instead of only the first
- Add tests for single/multiple include folders, include with exclude, and non-recursive filtering
2026-01-15 15:17:33 +08:00
Will Miao
0c67ff85ee build: rebuild Vue widgets with slider compatibility fixes 2026-01-15 07:03:17 +08:00
Will Miao
40756b7dd3 feat: add clear button to search inputs in modals
Add a clear button (X icon) to the search bars in BaseModelModal and TagsModal. The button appears when there is search text, and clicking it clears the search input and refocuses the search field.
2026-01-14 21:38:42 +08:00
Will Miao
2a9ceb9e85 feat: auto-focus search bar in LoRA pool modals 2026-01-14 21:22:52 +08:00
Will Miao
30077099ec fix: improve LoRA Randomizer toggle UX and semantic clarity
- Fix toggle UX consistency: both toggles now follow 'enabled → slider enabled' pattern
- Rename useSameClipStrength to useCustomClipRange for semantic clarity
- Update 'Respect Recommended Strength' label to 'Preset Strength Scale'
- Add explicit conversion logic in composable for backend compatibility
- Add visual disabled state for clip strength slider container
2026-01-14 18:43:46 +08:00
Will Miao
fc8240e99e feat: add "Respect Recommended Strength" feature to LoRA Randomizer
Add support for respecting recommended strength values from LoRA usage_tips
when randomizing LoRA selection.

Features:
- New toggle setting to enable/disable recommended strength respect (default off)
- Scale range slider (0-2, default 0.5-1.0) to adjust recommended values
- Uses recommended strength × random(scale) when feature enabled
- Fallbacks to original Model/Clip Strength range when no recommendation exists
- Clip strength recommendations only apply when using Custom Range mode

Backend changes:
- Parse usage_tips JSON string to extract strength/clipStrength
- Apply scale factor to recommended values during randomization
- Pass new parameters through API route and node

Frontend changes:
- Update RandomizerConfig type with new properties
- Add new UI section with toggle and dual-range slider
- Wire up state management and event handlers
- No layout shift (removed description text)

Tests:
- Add tests for enabled/disabled recommended strength in API routes
- Add test verifying config passed to service
- All existing tests pass

Build: Include compiled Vue widgets
2026-01-14 16:34:24 +08:00
Will Miao
73f2a34d08 fix: prevent cursor flickering when dragging slider handles
Fix issue where mouse cursor flickers between 'grabbing' and 'default'
while dragging slider handles. The cursor now remains 'grabbing'
throughout the entire drag operation regardless of mouse position.

Changes:
- Add dynamic 'is-dragging' class to SingleSlider and DualRangeSlider
- Apply cursor: grabbing to root component when dragging state is active
2026-01-14 11:47:47 +08:00
Will Miao
bc08a45214 feat: improve code formatting and readability in model handlers
- Add blank line after module docstring for better PEP 8 compliance
- Reformat long lines to adhere to 88-character limit using Black-style formatting
- Improve string consistency by using double quotes consistently
- Enhance readability of complex list comprehensions and method calls
- Maintain all existing functionality while improving code structure
2026-01-13 22:57:15 +08:00
Will Miao
859277a7eb feat(ui): enhance tag hover states and adjust toggle switch alignment
- Improve tag chip hover states in TagsModal with contextual colors for include/exclude modes
- Adjust toggle switch thumb vertical alignment in LicenseSection and LoraRandomizerSettingsView
- Remove debug console.log from loras widget value update
2026-01-13 19:54:36 +08:00
Will Miao
9e510d64ec feat(lora-randomizer): prevent early watch triggers by tracking mount state
Add isMounted ref to LoraRandomizerWidget to avoid premature updates from the loras widget watch. The watch now only responds after the component is fully mounted, and the onMounted hook captures the initial loras widget value before enabling the watcher. This prevents the watch from overwriting valid initial data with empty values during component initialization.
2026-01-13 19:22:51 +08:00
Will Miao
0ae2d084f4 feat(lora-randomizer): add segmented scale mode to strength sliders
- Add `scaleMode` and `segments` props to DualRangeSlider component
- Implement segmented scale visualization with configurable segment widths
- Define strength segments for model and clip strength sliders with expanded middle range
- Enable finer control in common value ranges via wheel step multipliers
2026-01-13 16:16:11 +08:00
Will Miao
514846cd4a feat(lora-randomizer): refactor randomization logic and add input preprocessing
- Add `_preprocess_loras_input` method to handle different widget input formats
- Move core randomization logic to `LoraService` for better separation of concerns
- Update `_select_loras` method to use new service-based approach
- Add comprehensive test fixtures for license filtering scenarios
- Include debug print statement for pool config inspection during development

This refactor improves code organization by centralizing business logic in the service layer while maintaining backward compatibility with existing widget inputs.
2026-01-13 15:47:59 +08:00
Will Miao
1ebd2c93a0 feat: add .opencode to gitignore and refactor lora routes
- Add .opencode directory to gitignore for agent-related files
- Refactor lora_routes.py with consistent string formatting and improved route registration
- Add DualRangeSlider Vue component for enhanced UI controls
2026-01-13 13:59:36 +08:00
Will Miao
688baef2f0 feat(dom-widgets): forward middle mouse events to canvas for panning
Add `forwardMiddleMouseToCanvas` utility to forward middle mouse button events from DOM widgets to the ComfyUI canvas, enabling workflow panning when the cursor is over a widget. The function is implemented in `vue-widgets/src/main.ts` and documented in the developer guide. Additionally, fix `getPoolConfigFromConnectedNode` to return null for inactive pool nodes.
2026-01-13 11:45:12 +08:00
Will Miao
177b20263d feat: add LoraDemoNode and LoraRandomizerNode with documentation
- Import and register two new nodes: LoraDemoNode and LoraRandomizerNode
- Update import exception handling for better readability with multi-line formatting
- Add comprehensive documentation file `docs/custom-node-ui-output.md` for UI output usage in custom nodes
- Ensure proper node registration in NODE_CLASS_MAPPINGS for ComfyUI integration
- Maintain backward compatibility with existing node structure and import fallbacks
2026-01-12 15:06:38 +08:00
Will Miao
65cede7335 feat(lora-pool): add folder filtering and preview tooltip enhancements
- Add include/exclude folder modals for advanced filtering
- Implement folder tree search with auto-expand functionality
- Add hover tooltip to preview header showing matching LoRA thumbnails
- Format match count with locale string for better readability
- Prevent event propagation on refresh button click
- Improve folder tree component with expand/collapse controls
2026-01-12 10:08:16 +08:00
Will Miao
9719dd4d07 docs(dom_widget_dev_guide): clarify dynamic resizing and add performance note
- Add performance note explaining that providing `getMinHeight` and `getHeight` via `options` avoids expensive DOM measurements
- Expand dynamic resizing section with detailed update sequence and common scenarios table
- Update LoraPoolSummaryView.vue with `min-height: 0` to allow flex shrinking
- Update main.ts to provide `getMinHeight` via options and adjust `computeLayoutSize` for performance
2026-01-12 09:22:18 +08:00
Will Miao
7a5f4514f3 feat(lora-pool): add external value handling and config update support
- Add `onSetValue` callback to handle external updates like workflow loading
- Implement `updateConfig` method for direct widget value updates
- Add value change detection in `restoreFromConfig` to prevent unnecessary updates
- Remove debug console log on component mount
- Extend widget value type to support legacy config format
2026-01-11 20:37:17 +08:00
Will Miao
b44ef9ceaa feat(ui): update LoRA pool widget color scheme and empty state styling
- Change primary accent color from green to blue across multiple components
- Update background colors for better visual consistency
- Improve empty state styling in TagsSection with better padding and background
- Add box-sizing to BaseModelSection for consistent layout
- Update CSS comments to reflect new color scheme
2026-01-11 19:54:44 +08:00
Will Miao
647728b2e1 feat: rename demo widget to lora-manager-widgets and remove demo node
- Update documentation to reflect new widget filename `lora-manager-widgets.js`
- Remove `LoraManagerDemoNode` import and registration from `__init__.py`
- Translate development guide from Chinese to English for broader accessibility
- Clean up obsolete demo references to align with actual widget implementation
2026-01-11 19:08:55 +08:00
Will Miao
3d348900ac feat(randomizer): add lora pool Vue widget 2026-01-11 16:26:38 +08:00
Will Miao
32249d1886 feat: add Vue widget demo node and development support
- Add LoraManagerDemoNode to node mappings for Vue widget demonstration
- Update .gitignore to exclude Vue widget development artifacts (node_modules, .vite, dist)
- Implement automatic Vue widget build check in development mode with fallback handling
- Maintain pytest compatibility with proper import error handling
2026-01-10 17:45:26 +08:00