-
Notifications
You must be signed in to change notification settings - Fork 435
Support "control after generate" in vue #6985
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
The @PointerUp.stop was breaking reka ui NumberFields. IIRC, this was added to allow selecting text without dragging nodes. Current testing suggests this isn't required for pointerup This reduces the margins some on number inputs. It's trivial to add a px-2.5, but helps with information density
📝 WalkthroughWalkthroughAdds a number-control system: new control types and SafeControlWidget, mapping into graph payloads, composables for stepping and control application, a NumberControlRegistry with before/after hooks invoked during queue processing, UI components for selecting modes, widget linking for post-generation controls, locales, and tests. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant WidgetComponent as Widget
participant Popover as NumberControlPopover
participant Registry as NumberControlRegistry
participant App as App (queuePrompt)
participant Settings as SettingsStore
User->>Widget: open control popover
Widget->>Popover: show
User->>Popover: select mode
Popover->>Widget: emit update:controlMode
Widget->>Widget: call widget.controlWidget.update(mode)
User->>App: queue prompt
App->>Registry: executeNumberControls("before")
Registry->>Settings: read WidgetControlMode
Settings-->>Registry: current phase matches?
Registry-->>App: execute registered callbacks (apply controls)
App->>App: run generation
App->>Registry: executeNumberControls("after")
Registry->>Settings: read WidgetControlMode
Settings-->>Registry: current phase matches?
Registry-->>App: execute registered callbacks (post-generation)
✨ Finishing touches🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: ASSERTIVE Plan: Pro 📒 Files selected for processing (1)
🧰 Additional context used📓 Path-based instructions (1)src/locales/**/*.json📄 CodeRabbit inference engine (AGENTS.md)
Files:
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🎨 Storybook Build Status✅ Build completed successfully! ⏰ Completed at: 12/09/2025, 12:36:07 AM UTC 🔗 Links🎉 Your Storybook is ready for review! |
🎭 Playwright Test Results❌ Some tests failed ⏰ Completed at: 12/09/2025, 12:47:40 AM UTC 📈 Summary
📊 Test Reports by Browser
🎉 Click on the links above to view detailed test results for each browser configuration. |
Bundle Size ReportSummary
Category Glance Per-category breakdownApp Entry Points — 3.21 MB (baseline 3.21 MB) • 🔴 +2.26 kBMain entry bundles and manifests
Status: 3 added / 3 removed Graph Workspace — 979 kB (baseline 978 kB) • 🔴 +794 BGraph editor runtime, canvas, workflow orchestration
Status: 1 added / 1 removed Views & Navigation — 6.54 kB (baseline 6.54 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces
Status: 1 added / 1 removed Panels & Settings — 298 kB (baseline 298 kB) • ⚪ 0 BConfiguration panels, inspectors, and settings screens
Status: 6 added / 6 removed UI Components — 183 kB (baseline 177 kB) • 🔴 +6.19 kBReusable component library chunks
Status: 9 added / 9 removed Data & Services — 12.5 kB (baseline 12.5 kB) • ⚪ 0 BStores, services, APIs, and repositories
Status: 3 added / 3 removed Utilities & Hooks — 2.94 kB (baseline 2.94 kB) • ⚪ 0 BHelpers, composables, and utility bundles
Status: 1 added / 1 removed Vendor & Third-Party — 8.56 MB (baseline 8.56 MB) • 🟢 -16 BExternal libraries and shared vendor chunks
Status: 5 added / 5 removed Other — 3.82 MB (baseline 3.81 MB) • 🔴 +7.49 kBBundles that do not match a named category
Status: 24 added / 23 removed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (8)
src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue (2)
148-165: UnifieddropdownItemslogic looks correctThe refactor to have asset mode always use
allItemsand non-asset “all” explicitly concatenateinputItemsandoutputItemsis consistent with the surrounding data flow; no functional issues stand out. If you want to reduce duplication, the'all'branch could just returnallItems.value, but that’s purely optional.
70-81: Localize user-facing strings and tighten upload error messagingSeveral strings are user-visible but not run through vue-i18n, which conflicts with the repo guidelines:
- Filter option labels:
'All','Inputs','Outputs'(Lines 76–79).- Toast messages:
File upload failed,Upload failed: ${error}(Lines 296, 320).Consider:
- Replacing these literals with
t(...)calls and adding appropriate entries insrc/locales/en/main.json.- For the upload error toast, deriving a readable message (e.g.
error instanceof Error ? error.message : String(error)) rather than stringifying the raw error object.This keeps UX consistent and ready for localization without changing behavior.
Also applies to: 263-264, 295-321
tests-ui/tests/stores/globalSeedStore.test.ts (1)
21-28: Consider replacing the probabilistic assertion.This test relies on random seed generation to be different across store instances, which introduces non-determinism. While the 1-in-1,000,000 chance is low, flaky tests can cause false failures in CI/CD pipelines.
Consider one of these alternatives:
- Mock
Math.random()to return predictable values- Test that the seed is within the valid range instead of comparing uniqueness
- Accept the low flakiness risk and document it clearly
Example with mocking:
it('should create different seeds for different store instances', () => { + const mockRandom = vi.spyOn(Math, 'random') + mockRandom.mockReturnValueOnce(0.5) const store1 = useGlobalSeedStore() setActivePinia(createPinia()) // Reset pinia + mockRandom.mockReturnValueOnce(0.7) const store2 = useGlobalSeedStore() - // Very unlikely to be the same (1 in 1,000,000 chance) - expect(store1.globalSeed).not.toBe(store2.globalSeed) + expect(store1.globalSeed).toBe(500000) + expect(store2.globalSeed).toBe(700000) + mockRandom.mockRestore() })src/types/simplifiedWidget.ts (1)
18-26: Consider adding 'link-to-global' to ControlWidgetOptions type.The
NumberControlPopover.vuecomponent references aLINK_TO_GLOBALmode (currently disabled via feature flag), but this option is missing from theControlWidgetOptionstype union. While the feature is disabled now, including it in the type definition would ensure type safety when the feature is enabled.export type ControlWidgetOptions = | 'fixed' | 'increment' | 'decrement' | 'randomize' + | 'link-to-global'src/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue (1)
29-29: Document the LINK_TO_GLOBAL feature flag.The
ENABLE_LINK_TO_GLOBALconstant is hardcoded tofalse, but there's no comment explaining why this feature is disabled or what would be required to enable it. Consider adding a comment to guide future development.+// TODO: Enable LINK_TO_GLOBAL once global seed synchronization is fully implemented const ENABLE_LINK_TO_GLOBAL = falsesrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberWithControl.vue (1)
57-64: Consider usingcn()utility for class merging.Per coding guidelines, prefer using the
cn()utility from@/utils/tailwindUtilfor class merging instead of template string interpolation.- <i :class="`${controlButtonIcon} text-blue-100 text-xs`" /> + <i :class="cn(controlButtonIcon, 'text-blue-100 text-xs')" />You'll need to import
cnfrom@/utils/tailwindUtil.src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue (1)
123-128: Remove potentially dead PrimeVue CSS.This scoped CSS targets
.p-inputnumber-input, a PrimeVue class. Since the component now uses Reka UI'sNumberFieldRoot/NumberFieldInput, this CSS may no longer apply and could be removed.src/renderer/extensions/vueNodes/widgets/services/NumberControlRegistry.ts (1)
27-34: Consider wrapping callback execution in try-catch for resilience.If one registered
applyFnthrows an error, it will prevent subsequent controls from being applied. Consider wrapping each callback in a try-catch to ensure all controls are executed.executeControls(phase: 'before' | 'after'): void { const settingStore = useSettingStore() if (settingStore.get('Comfy.WidgetControlMode') === phase) { for (const applyFn of this.controls.values()) { - applyFn() + try { + applyFn() + } catch (error) { + console.error('Error executing number control:', error) + } } } }
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue
Outdated
Show resolved
Hide resolved
src/scripts/utils.ts
Outdated
| if (typeof window !== 'undefined') { | ||
| import('@/base/common/downloadUtil') | ||
| .then((module) => { | ||
| const fn = ( | ||
| module as { | ||
| downloadBlob?: typeof import('@/base/common/downloadUtil').downloadBlob | ||
| } | ||
| ).downloadBlob | ||
| if (typeof fn === 'function') { | ||
| ;(window as any).downloadBlob = fn | ||
| } | ||
| }) | ||
| .catch(() => {}) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix TypeScript violations: avoid as any and improve error handling.
This code violates two explicit coding guidelines:
- Line 63 uses
as anytype assertion - Line 66 silently swallows errors
As per coding guidelines, never use as any type assertions and implement proper error handling.
Apply this diff to fix both issues:
+declare global {
+ interface Window {
+ downloadBlob?: typeof import('@/base/common/downloadUtil').downloadBlob
+ }
+}
+
if (typeof window !== 'undefined') {
import('@/base/common/downloadUtil')
.then((module) => {
const fn = (
module as {
downloadBlob?: typeof import('@/base/common/downloadUtil').downloadBlob
}
).downloadBlob
if (typeof fn === 'function') {
- ;(window as any).downloadBlob = fn
+ window.downloadBlob = fn
}
})
- .catch(() => {})
+ .catch((error) => {
+ console.error('Failed to load downloadBlob utility:', error)
+ })
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (typeof window !== 'undefined') { | |
| import('@/base/common/downloadUtil') | |
| .then((module) => { | |
| const fn = ( | |
| module as { | |
| downloadBlob?: typeof import('@/base/common/downloadUtil').downloadBlob | |
| } | |
| ).downloadBlob | |
| if (typeof fn === 'function') { | |
| ;(window as any).downloadBlob = fn | |
| } | |
| }) | |
| .catch(() => {}) | |
| } | |
| declare global { | |
| interface Window { | |
| downloadBlob?: typeof import('@/base/common/downloadUtil').downloadBlob | |
| } | |
| } | |
| if (typeof window !== 'undefined') { | |
| import('@/base/common/downloadUtil') | |
| .then((module) => { | |
| const fn = ( | |
| module as { | |
| downloadBlob?: typeof import('@/base/common/downloadUtil').downloadBlob | |
| } | |
| ).downloadBlob | |
| if (typeof fn === 'function') { | |
| window.downloadBlob = fn | |
| } | |
| }) | |
| .catch((error) => { | |
| console.error('Failed to load downloadBlob utility:', error) | |
| }) | |
| } |
|
Updating Playwright Expectations |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (4)
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue (1)
115-117: Add conditional rendering to prevent invisible hitbox.The absolutely positioned wrapper renders unconditionally, creating an invisible overlay that can block input interaction when no slot is provided. This should only render when a default slot exists, matching the conditional padding logic.
Apply this diff:
- <div class="absolute top-5 right-8 h-4 w-7 -translate-y-4/5"> + <div + v-if="slots.default" + class="absolute top-5 right-8 h-4 w-7 -translate-y-4/5" + > <slot /> </div>src/renderer/extensions/vueNodes/widgets/composables/useStepperControl.ts (1)
65-99: Fix inconsistent boundary constraint in LINK_TO_GLOBAL mode.Line 88 uses
minfor the lower bound while all other modes consistently usesafeMin. This inconsistency could allow values outside the safe integer range ifmin < -1125899906842624.Apply this diff for consistency:
case NumberControlMode.LINK_TO_GLOBAL: // Use global seed value, constrained by min/max - newValue = Math.max(min, Math.min(safeMax, globalSeedStore.globalSeed)) + newValue = Math.max(safeMin, Math.min(safeMax, globalSeedStore.globalSeed)) breaksrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberWithControl.vue (1)
26-37: Add runtime guard or tighten prop type to prevent unsafe non-null assertions.Lines 32 and 37 use non-null assertions (
widget.controlWidget!) without defensive checks. IfcontrolWidgetis undefined, this will cause a runtime error. While the parent component may conditionally render this component only whencontrolWidgetexists, TypeScript cannot verify this guarantee.Consider one of these solutions:
Option 1: Add a runtime guard at component entry:
const props = defineProps<{ widget: SimplifiedWidget<number> }>() if (!props.widget.controlWidget) { throw new Error('WidgetInputNumberWithControl requires a widget with controlWidget') } // Then remove the `!` assertions belowOption 2: Tighten the prop type to require controlWidget:
const props = defineProps<{ widget: SimplifiedWidget<number> & { controlWidget: SafeControlWidget } }>() // Then remove the `!` assertions belowOption 2 is preferred as it provides compile-time safety.
src/composables/graph/useGraphNodeManager.ts (1)
87-96: Use strict equality operator.Line 89 uses loose equality (
==) instead of strict equality (===). While this works for string comparison, TypeScript best practices recommend using===for type safety and consistency.Apply this diff:
const cagWidget = widget.linkedWidgets?.find( - (w) => w.name == 'control_after_generate' + (w) => w.name === 'control_after_generate' )Based on coding guidelines, TypeScript should use strict equality for type safety.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (7)
src/composables/graph/useGraphNodeManager.ts(4 hunks)src/locales/en/main.json(1 hunks)src/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue(1 hunks)src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue(4 hunks)src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberWithControl.vue(1 hunks)src/renderer/extensions/vueNodes/widgets/composables/useStepperControl.ts(1 hunks)src/types/simplifiedWidget.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (18)
**/*.vue
📄 CodeRabbit inference engine (.cursorrules)
**/*.vue: Use setup() function for component logic in Vue 3 Composition API
Utilize ref and reactive for reactive state in Vue 3
Implement computed properties with computed() function
Use watch and watchEffect for side effects in Vue 3
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection in Vue 3
Use Vue 3.5 style of default prop declaration with defineProps()
Organize Vue components in <script> <style> order
Use Tailwind CSS for styling Vue components
Implement responsive design with Tailwind CSS
Do not use deprecated PrimeVue components (Dropdown, OverlayPanel, Calendar, InputSwitch, Sidebar, Chips, TabMenu, Steps, InlineMessage). Use replacements: Select, Popover, DatePicker, ToggleSwitch, Drawer, AutoComplete, Tabs, Stepper, Message respectively
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components in Vue 3
Follow Vue 3 style guide and naming conventions
Never use deprecated PrimeVue components (Dropdown, OverlayPanel, Calendar, InputSwitch, Sidebar, Chips, TabMenu, Steps, InlineMessage)Never use
:class="[]"to merge class names - always useimport { cn } from '@/utils/tailwindUtil'for class merging in Vue templates
**/*.vue: Use TypeScript with Vue 3 Single File Components (.vuefiles)
Name Vue components in PascalCase (e.g.,MenuHamburger.vue)Files:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberWithControl.vuesrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{vue,ts,tsx}: Leverage VueUse functions for performance-enhancing utilities
Use vue-i18n in Composition API for any string literals and place new translation entries in src/locales/en/main.jsonFiles:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/composables/graph/useGraphNodeManager.tssrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberWithControl.vuesrc/types/simplifiedWidget.tssrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue**/*.{ts,tsx,js,vue}
📄 CodeRabbit inference engine (.cursorrules)
Implement proper error handling in components and services
**/*.{ts,tsx,js,vue}: Use 2-space indentation, single quotes, no semicolons, and maintain 80-character line width as configured in.prettierrc
Organize imports by sorting and grouping by plugin, and runpnpm formatbefore committingFiles:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/composables/graph/useGraphNodeManager.tssrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberWithControl.vuesrc/types/simplifiedWidget.tssrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vuesrc/**/*.vue
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventionsFiles:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberWithControl.vuesrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vuesrc/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.jsonFiles:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/composables/graph/useGraphNodeManager.tssrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberWithControl.vuesrc/types/simplifiedWidget.tssrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use camelCase for variable and setting names in TypeScript/Vue files
Files:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/composables/graph/useGraphNodeManager.tssrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberWithControl.vuesrc/types/simplifiedWidget.tssrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue**/*.{vue,html}
📄 CodeRabbit inference engine (CLAUDE.md)
Never use
dark:ordark-theme:Tailwind variants - instead use semantic values fromstyle.csstheme, e.g.bg-node-component-surfaceFiles:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberWithControl.vuesrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,vue}: Useconst settingStore = useSettingStore()andsettingStore.get('Comfy.SomeSetting')to retrieve settings in TypeScript/Vue files
Useawait settingStore.set('Comfy.SomeSetting', newValue)to update settings in TypeScript/Vue files
Check server capabilities usingapi.serverSupportsFeature('feature_name')before using enhanced features
Useapi.getServerFeature('config_name', defaultValue)to retrieve server feature configurationEnforce ESLint rules for Vue + TypeScript including: no floating promises, no unused imports, and i18n raw text restrictions in templates
Files:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/composables/graph/useGraphNodeManager.tssrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberWithControl.vuesrc/types/simplifiedWidget.tssrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vuesrc/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebaseFiles:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/composables/graph/useGraphNodeManager.tssrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberWithControl.vuesrc/types/simplifiedWidget.tssrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vuesrc/**/{composables,components}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Clean up subscriptions in state management to prevent memory leaks
Files:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/composables/graph/useGraphNodeManager.tssrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberWithControl.vuesrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vuesrc/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/composables/graph/useGraphNodeManager.tssrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberWithControl.vuesrc/types/simplifiedWidget.tssrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vuesrc/**/{components,composables}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Use vue-i18n for ALL user-facing strings by adding them to
src/locales/en/main.jsonFiles:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/composables/graph/useGraphNodeManager.tssrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberWithControl.vuesrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursorrules)
Use es-toolkit for utility functions
Files:
src/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/composables/graph/useGraphNodeManager.tssrc/types/simplifiedWidget.ts**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
Use TypeScript for type safety
**/*.{ts,tsx}: Never useanytype - use proper TypeScript types
Never useas anytype assertions - fix the underlying type issueFiles:
src/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/composables/graph/useGraphNodeManager.tssrc/types/simplifiedWidget.tssrc/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safetyFiles:
src/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/composables/graph/useGraphNodeManager.tssrc/types/simplifiedWidget.ts**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.ts: Define dynamic setting defaults using runtime context with functions in settings configuration
UsedefaultsByInstallVersionproperty for gradual feature rollout based on version in settings configurationFiles:
src/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/composables/graph/useGraphNodeManager.tssrc/types/simplifiedWidget.tssrc/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directlyFiles:
src/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/composables/graph/useGraphNodeManager.ts**/composables/use*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Name composables in the format
useXyz.tsFiles:
src/renderer/extensions/vueNodes/widgets/composables/useStepperControl.ts🧠 Learnings (17)
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: src/components/CLAUDE.md:0-0 Timestamp: 2025-11-24T19:47:45.616Z Learning: Applies to src/components/**/*.vue : Replace PrimeVue InputSwitch component with ToggleSwitchApplied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberWithControl.vuesrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue📚 Learning: 2025-11-24T19:46:52.279Z
Learnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: .cursorrules:0-0 Timestamp: 2025-11-24T19:46:52.279Z Learning: Applies to **/*.vue : Do not use deprecated PrimeVue components (Dropdown, OverlayPanel, Calendar, InputSwitch, Sidebar, Chips, TabMenu, Steps, InlineMessage). Use replacements: Select, Popover, DatePicker, ToggleSwitch, Drawer, AutoComplete, Tabs, Stepper, Message respectivelyApplied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue📚 Learning: 2025-11-24T19:46:52.279Z
Learnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: .cursorrules:0-0 Timestamp: 2025-11-24T19:46:52.279Z Learning: Applies to **/*.vue : Never use deprecated PrimeVue components (Dropdown, OverlayPanel, Calendar, InputSwitch, Sidebar, Chips, TabMenu, Steps, InlineMessage)Applied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: src/components/CLAUDE.md:0-0 Timestamp: 2025-11-24T19:47:45.616Z Learning: Applies to src/components/**/*.vue : Replace PrimeVue Steps component with Stepper without panelsApplied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberWithControl.vue📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: src/components/CLAUDE.md:0-0 Timestamp: 2025-11-24T19:47:45.616Z Learning: Applies to src/components/**/*.vue : Use setup() function in Vue 3 Composition APIApplied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: src/components/CLAUDE.md:0-0 Timestamp: 2025-11-24T19:47:45.616Z Learning: Applies to src/components/**/*.vue : Implement computed() for derived state in Vue 3 Composition APIApplied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue📚 Learning: 2025-11-24T19:46:52.279Z
Learnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: .cursorrules:0-0 Timestamp: 2025-11-24T19:46:52.279Z Learning: Applies to **/*.vue : Implement computed properties with computed() functionApplied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: .github/copilot-instructions.md:0-0 Timestamp: 2025-11-24T19:47:02.860Z Learning: Applies to src/**/*.vue : Implement computed properties with computed()Applied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: .github/copilot-instructions.md:0-0 Timestamp: 2025-11-24T19:47:02.860Z Learning: Applies to src/**/*.{vue,ts} : Leverage VueUse functions for performance-enhancing stylesApplied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue📚 Learning: 2025-11-24T19:46:52.279Z
Learnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: .cursorrules:0-0 Timestamp: 2025-11-24T19:46:52.279Z Learning: Applies to **/*.{vue,ts,tsx} : Leverage VueUse functions for performance-enhancing utilitiesApplied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue📚 Learning: 2025-11-24T19:46:52.279Z
Learnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: .cursorrules:0-0 Timestamp: 2025-11-24T19:46:52.279Z Learning: Applies to **/*.vue : Use setup() function for component logic in Vue 3 Composition APIApplied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue📚 Learning: 2025-11-24T19:47:14.779Z
Learnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: CLAUDE.md:0-0 Timestamp: 2025-11-24T19:47:14.779Z Learning: Applies to **/*.vue : Never use `:class="[]"` to merge class names - always use `import { cn } from '@/utils/tailwindUtil'` for class merging in Vue templatesApplied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue📚 Learning: 2025-11-24T19:48:23.088Z
Learnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: AGENTS.md:0-0 Timestamp: 2025-11-24T19:48:23.088Z Learning: Applies to **/composables/use*.ts : Name composables in the format `useXyz.ts`Applied to files:
src/renderer/extensions/vueNodes/widgets/composables/useStepperControl.ts📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: src/lib/litegraph/CLAUDE.md:0-0 Timestamp: 2025-11-24T19:47:56.371Z Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Do not replace `&&=` or `||=` with `=` when there is no reason to do so. If you do find a reason to remove either `&&=` or `||=`, leave a comment explaining why the removal occurredApplied to files:
src/composables/graph/useGraphNodeManager.ts📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: src/components/CLAUDE.md:0-0 Timestamp: 2025-11-24T19:47:45.616Z Learning: Applies to src/components/**/*.vue : Replace PrimeVue OverlayPanel component with PopoverApplied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberWithControl.vuesrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: src/components/CLAUDE.md:0-0 Timestamp: 2025-11-24T19:47:45.616Z Learning: Applies to src/components/**/*.vue : Replace PrimeVue Dropdown component with SelectApplied to files:
src/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: src/components/CLAUDE.md:0-0 Timestamp: 2025-11-24T19:47:45.616Z Learning: Applies to src/components/**/*.vue : Replace PrimeVue Calendar component with DatePickerApplied to files:
src/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue🧬 Code graph analysis (1)
src/renderer/extensions/vueNodes/widgets/composables/useStepperControl.ts (3)
src/types/simplifiedWidget.ts (1)
ControlOptions(24-24)src/stores/globalSeedStore.ts (1)
useGlobalSeedStore(4-16)src/renderer/extensions/vueNodes/widgets/services/NumberControlRegistry.ts (1)
numberControlRegistry(52-52)⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: deploy-and-comment
- GitHub Check: collect
- GitHub Check: lint-and-format
- GitHub Check: test
- GitHub Check: setup
🔇 Additional comments (12)
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue (2)
3-3: LGTM!The
useSlotsimport is correctly added and used to detect the presence of a default slot for conditional styling.
72-72: LGTM!The slot detection and conditional padding logic is well-implemented. The right padding is correctly applied only when a default slot is present.
Also applies to: 94-98
src/types/simplifiedWidget.ts (2)
18-30: LGTM!The control options validation is well-implemented. The exclusion of 'linkToGlobal' is intentional since the feature is currently disabled (ENABLE_LINK_TO_GLOBAL = false in NumberControlPopover.vue). The default fallback to 'randomize' provides safe behavior for unknown values.
32-35: LGTM!The
SafeControlWidgettype provides a clean API for control interaction with a value getter and update callback. The optionalcontrolWidgetfield inSimplifiedWidgetcorrectly enables the control feature without breaking existing widgets.Also applies to: 68-68
src/composables/graph/useGraphNodeManager.ts (2)
23-24: LGTM!The imports are correctly added for the new control widget functionality.
130-131: LGTM!The
controlWidgetis correctly populated in the widget mapper using the helper function. The integration is clean and follows the existing pattern.src/renderer/extensions/vueNodes/widgets/composables/useStepperControl.ts (3)
9-23: LGTM!The
NumberControlModeenum andStepperControlOptionsinterface are well-defined. IncludingLINK_TO_GLOBALin the enum despite the feature being currently disabled is good forward-planning for future enablement.
25-37: LGTM!The
convertToEnumfunction correctly handles all enabled control options. The absence of 'linkToGlobal' is intentional since the feature is currently disabled (ENABLE_LINK_TO_GLOBAL = false).
39-54: LGTM!The icon mapping is comprehensive and uses appropriate icons for each control mode.
src/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue (2)
1-87: LGTM!The component is well-structured using Vue 3 Composition API. The feature flag for
LINK_TO_GLOBALis appropriately placed, and the component API (props, emits, expose) is clean and well-defined.As per coding guidelines, the component correctly uses PrimeVue Popover (not the deprecated OverlayPanel) and ToggleSwitch (not the deprecated InputSwitch).
89-171: LGTM!The template is well-structured with proper use of semantic CSS classes, i18n for all user-facing text, and clean conditional rendering. The layout is responsive and accessible.
As per coding guidelines, all user-facing strings are correctly internationalized using vue-i18n.
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberWithControl.vue (1)
45-67: LGTM!The template is well-structured with proper component composition and grid layout. The button and popover integration is clean.
| "numberControl": { | ||
| "header" : { | ||
| "prefix": "Automatically update the value", | ||
| "after": "AFTER", | ||
| "before": "BEFORE", | ||
| "postfix": "running the workflow:" | ||
| }, | ||
| "linkToGlobal": "Link to", | ||
| "linkToGlobalSeed": "Global Value", | ||
| "linkToGlobalDesc": "Unique value linked to the Global Value's control setting", | ||
| "randomize": "Randomize Value", | ||
| "randomizeDesc": "Shuffles the value randomly after each generation", | ||
| "increment": "Increment Value", | ||
| "incrementDesc": "Adds 1 to the value number", | ||
| "decrement": "Decrement Value", | ||
| "decrementDesc": "Subtracts 1 from the value number", | ||
| "editSettings": "Edit control settings" | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Verify intentional ALL CAPS usage for mode labels.
Lines 1917-1918 use ALL CAPS for "AFTER" and "BEFORE" while surrounding text uses mixed case. This creates visual emphasis but is inconsistent with typical UI text conventions.
Please confirm this capitalization is intentional for design/UX reasons. If the goal is to emphasize the control mode, consider alternative approaches like bold styling or a separate UI treatment rather than ALL CAPS in the localization string.
Example alternative structure:
"header": {
"prefix": "Automatically update the value",
"afterMode": "after",
"beforeMode": "before",
"postfix": "running the workflow:"
}Then apply emphasis via CSS in the component rather than hardcoding capitalization.
🤖 Prompt for AI Agents
In src/locales/en/main.json around lines 1914 to 1931, the header labels "AFTER"
and "BEFORE" are in ALL CAPS while surrounding text is mixed case; confirm
whether ALL CAPS is intentional for UX, and if not replace those values with
normal-cased alternatives (e.g., "after"/"before" or "After"/"Before") and
optionally rename the keys to semantic names like afterMode/beforeMode so
emphasis is applied in the component via styling/CSS instead of hardcoded
capitalization.
| // precision 1 → 0.1, precision 2 → 0.01, etc. | ||
| return 1 / Math.pow(10, precision.value) | ||
| }) | ||
| const stepValue = useNumberStepCalculation(widget.options, precision, true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this could be a utility function instead of a composable for now.
src/renderer/extensions/vueNodes/widgets/composables/useNumberStepCalculation.ts
Outdated
Show resolved
Hide resolved
| export enum NumberControlMode { | ||
| FIXED = 'fixed', | ||
| INCREMENT = 'increment', | ||
| DECREMENT = 'decrement', | ||
| RANDOMIZE = 'randomize', | ||
| LINK_TO_GLOBAL = 'linkToGlobal' | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| export enum NumberControlMode { | |
| FIXED = 'fixed', | |
| INCREMENT = 'increment', | |
| DECREMENT = 'decrement', | |
| RANDOMIZE = 'randomize', | |
| LINK_TO_GLOBAL = 'linkToGlobal' | |
| } | |
| export const NumberControlMode = { | |
| FIXED: 'fixed', | |
| INCREMENT: 'increment', | |
| DECREMENT: 'decrement', | |
| RANDOMIZE: 'randomize', | |
| LINK_TO_GLOBAL: 'linkToGlobal' | |
| } as const |
That thing we talked about
src/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue
Show resolved
Hide resolved
|
|
||
| const applyControl = () => { | ||
| const { min = 0, max = 1000000, step2, step = 1, onChange } = options | ||
| const safeMax = Math.min(1125899906842624, max) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
|
||
| // Register with singleton registry | ||
| onMounted(() => { | ||
| numberControlRegistry.register(controlId, applyControl) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Double check to see if you need to be DOM dependent here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Followup: sorta. It's being used as a convenient way to ensure it gets unregistered at some point. Since I'm proposing removal in a future PR, it's probably not worth rewriting the implementation here.
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
♻️ Duplicate comments (5)
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue (1)
113-115: Conditionally render the slot wrapper to avoid invisible hitbox.This issue was previously flagged: the absolutely positioned wrapper div renders unconditionally, creating an invisible hitbox over the input's top-right area when no default slot is provided. This can intercept clicks/focus without showing any control.
Apply this diff to align the wrapper rendering with the
hasSlotcomputed property:</InputNumber> - <div class="absolute top-5 right-8 h-4 w-7 -translate-y-4/5"> + <div + v-if="hasSlot" + class="absolute top-5 right-8 h-4 w-7 -translate-y-4/5" + > <slot /> </div> </WidgetLayoutField>This keeps the overlay and extra padding in sync and avoids an invisible hitbox when no control is slotted in.
Based on learnings, as per coding guidelines: Always use
cn()from@/utils/tailwindUtilto merge class names.src/renderer/extensions/vueNodes/widgets/composables/useComboWidget.ts (1)
72-80: Guard MultiSelect control wiring withisComboWidgetto avoid numeric-control path
addMultiSelectWidgetwiresaddValueControlWidgetswheneverinputSpec.control_after_generateis set, but it doesn’t assert that theComponentWidgetImplis actually treated as a combo widget. IfisComboWidget(widget)ever returnsfalse,addValueControlWidgetswill take the numeric path (usingmin/max/step2) against a multi-select widget, which can lead to incorrect behavior or type mismatches at runtime.Mirroring the defensive pattern used in
createInputMappingWidget/addComboWidgethere keeps behavior predictable:// TODO: Add remote support to multi-select widget // https://github.com/Comfy-Org/ComfyUI_frontend/issues/3003 if (inputSpec.control_after_generate) { + if (!isComboWidget(widget)) { + throw new Error(`Expected combo widget but received ${widget.type}`) + } widget.linkedWidgets = addValueControlWidgets( node, widget, 'fixed', undefined, transformInputSpecV2ToV1(inputSpec) ) }src/locales/en/main.json (1)
1914-1931: Align increment/decrement descriptions (and optionally casing) with actual behaviorThe control descriptions currently say:
"incrementDesc": "Adds 1 to the value number""decrementDesc": "Subtracts 1 from the value number"but the underlying logic uses the widget’s step (
step/step2), not a literal1. That can confuse users for non‑unit steps (e.g. 0.5, 5, 10).Consider wording them in terms of the step amount instead:
- "incrementDesc": "Adds 1 to the value number", - "decrementDesc": "Subtracts 1 from the value number", + "incrementDesc": "Adds the step amount to the value", + "decrementDesc": "Subtracts the step amount from the value",Also, the ALL‑CAPS
"AFTER"/"BEFORE"in the header are visually inconsistent with surrounding copy; if this emphasis isn’t intentional, you may want to normalize their casing as noted in the earlier review.src/renderer/extensions/vueNodes/widgets/composables/useStepperControl.ts (1)
24-36: Missing 'linkToGlobal' case in convertToEnum.The
convertToEnumfunction does not handle'linkToGlobal'. WhenENABLE_LINK_TO_GLOBALis enabled inNumberControlPopover.vueand a user selects that mode, the value will incorrectly fall through to the default case and returnRANDOMIZE.Apply this diff to add the missing case:
function convertToEnum(str?: ControlOptions): NumberControlMode { switch (str) { case 'fixed': return NumberControlMode.FIXED case 'increment': return NumberControlMode.INCREMENT case 'decrement': return NumberControlMode.DECREMENT case 'randomize': return NumberControlMode.RANDOMIZE + case 'linkToGlobal': + return NumberControlMode.LINK_TO_GLOBAL } return NumberControlMode.RANDOMIZE }src/types/simplifiedWidget.ts (1)
18-24: Missing 'linkToGlobal' in CONTROL_OPTIONS array.The
CONTROL_OPTIONSarray does not include'linkToGlobal', butNumberControlMode.LINK_TO_GLOBALexists inuseStepperControl.tsandNumberControlPopover.vueconditionally uses it whenENABLE_LINK_TO_GLOBALis true. This creates a type inconsistency where valid enum values cannot be normalized correctly.Apply this diff:
const CONTROL_OPTIONS = [ 'fixed', 'increment', 'decrement', - 'randomize' + 'randomize', + 'linkToGlobal' ] as const
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (15)
src/composables/graph/useGraphNodeManager.ts(4 hunks)src/locales/en/main.json(1 hunks)src/renderer/extensions/vueNodes/components/NodeWidgets.vue(1 hunks)src/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue(1 hunks)src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue(2 hunks)src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberSlider.vue(3 hunks)src/renderer/extensions/vueNodes/widgets/components/layout/WidgetLayoutField.vue(1 hunks)src/renderer/extensions/vueNodes/widgets/composables/useComboWidget.ts(2 hunks)src/renderer/extensions/vueNodes/widgets/composables/useFloatWidget.ts(3 hunks)src/renderer/extensions/vueNodes/widgets/composables/useNumberStepCalculation.ts(1 hunks)src/renderer/extensions/vueNodes/widgets/composables/useStepperControl.ts(1 hunks)src/scripts/utils.ts(0 hunks)src/types/simplifiedWidget.ts(2 hunks)tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts(1 hunks)tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer.test.ts(2 hunks)
💤 Files with no reviewable changes (1)
- src/scripts/utils.ts
🧰 Additional context used
📓 Path-based instructions (16)
src/**/*.vue
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions
Files:
src/renderer/extensions/vueNodes/components/NodeWidgets.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/components/layout/WidgetLayoutField.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberSlider.vuesrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
Files:
src/renderer/extensions/vueNodes/components/NodeWidgets.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/components/layout/WidgetLayoutField.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberSlider.vuesrc/renderer/extensions/vueNodes/widgets/composables/useFloatWidget.tssrc/renderer/extensions/vueNodes/widgets/composables/useNumberStepCalculation.tssrc/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/renderer/extensions/vueNodes/widgets/composables/useComboWidget.tssrc/composables/graph/useGraphNodeManager.tssrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vuesrc/types/simplifiedWidget.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
Files:
src/renderer/extensions/vueNodes/components/NodeWidgets.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/components/layout/WidgetLayoutField.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberSlider.vuesrc/renderer/extensions/vueNodes/widgets/composables/useFloatWidget.tssrc/renderer/extensions/vueNodes/widgets/composables/useNumberStepCalculation.tssrc/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/renderer/extensions/vueNodes/widgets/composables/useComboWidget.tssrc/composables/graph/useGraphNodeManager.tssrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vuesrc/types/simplifiedWidget.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Clean up subscriptions in state management to prevent memory leaks
Files:
src/renderer/extensions/vueNodes/components/NodeWidgets.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/components/layout/WidgetLayoutField.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberSlider.vuesrc/renderer/extensions/vueNodes/widgets/composables/useFloatWidget.tssrc/renderer/extensions/vueNodes/widgets/composables/useNumberStepCalculation.tssrc/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/renderer/extensions/vueNodes/widgets/composables/useComboWidget.tssrc/composables/graph/useGraphNodeManager.tssrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/renderer/extensions/vueNodes/components/NodeWidgets.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/components/layout/WidgetLayoutField.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberSlider.vuesrc/renderer/extensions/vueNodes/widgets/composables/useFloatWidget.tssrc/renderer/extensions/vueNodes/widgets/composables/useNumberStepCalculation.tssrc/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/renderer/extensions/vueNodes/widgets/composables/useComboWidget.tssrc/composables/graph/useGraphNodeManager.tssrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vuesrc/types/simplifiedWidget.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Use vue-i18n for ALL user-facing strings by adding them to
src/locales/en/main.json
Files:
src/renderer/extensions/vueNodes/components/NodeWidgets.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/components/layout/WidgetLayoutField.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberSlider.vuesrc/renderer/extensions/vueNodes/widgets/composables/useFloatWidget.tssrc/renderer/extensions/vueNodes/widgets/composables/useNumberStepCalculation.tssrc/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/renderer/extensions/vueNodes/widgets/composables/useComboWidget.tssrc/composables/graph/useGraphNodeManager.tssrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue
**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
**/*.vue: Use Vue 3 SFCs with Composition API only (use<script setup lang="ts">, not Options API)
Avoid using<style>blocks; use Tailwind 4 for all styling
UsedefinePropswith TypeScript style default declaration; do not usewithDefaultsor runtime props declaration
PreferuseModelover separately defining a prop and emit
Usecomputedinstead of arefandwatchif possible
Avoid usingrefif a prop would accomplish the design goals; avoid usingcomputedif arefor prop directly would work
Do not import Vue macros unnecessarily
Never use thedark:Tailwind variant; use semantic values from thestyle.csstheme instead (e.g.,bg-node-component-surface)
Never use:class="[]"to merge class names; always usecn()from@/utils/tailwindUtil(e.g.,<div :class="cn('text-node-component-header-icon', hasError && 'text-danger')" />)
Leverage VueUse functions for performance-enhancing styles
Avoid new usage of PrimeVue components
Use Vue 3 Teleport component when needed
Use Vue 3 Suspense for async components
Files:
src/renderer/extensions/vueNodes/components/NodeWidgets.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/components/layout/WidgetLayoutField.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberSlider.vuesrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue
**/*.{ts,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,vue}: Use camelCase for variable and function names
Indent with 2 spaces (see.prettierrc)
Use single quotes for strings (see.prettierrc)
No trailing semicolons (see.prettierrc)
Maximum line width of 80 characters (see.prettierrc)
Sort and group imports by plugin (runpnpm formatbefore committing)
Never useanytype; use proper TypeScript types instead
Never useas anytype assertions; fix the underlying type issue instead
Avoid code comments unless absolutely necessary; write expressive, self-documenting code instead
When writing new code, ask if there is a simpler way to introduce the same functionality; if yes, choose the simpler approach
Use refactoring to make complex code simpler
Use es-toolkit for utility functions
Use Vite for fast development and building
Implement proper error handling
Write tests for all changes, especially bug fixes to catch future regressions
Files:
src/renderer/extensions/vueNodes/components/NodeWidgets.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/components/layout/WidgetLayoutField.vuetests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer.test.tssrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberSlider.vuesrc/renderer/extensions/vueNodes/widgets/composables/useFloatWidget.tstests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.tssrc/renderer/extensions/vueNodes/widgets/composables/useNumberStepCalculation.tssrc/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/renderer/extensions/vueNodes/widgets/composables/useComboWidget.tssrc/composables/graph/useGraphNodeManager.tssrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vuesrc/types/simplifiedWidget.ts
**/components/**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
Name Vue components in PascalCase (e.g.,
MenuHamburger.vue)
Files:
src/renderer/extensions/vueNodes/components/NodeWidgets.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/components/layout/WidgetLayoutField.vuesrc/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberSlider.vuesrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue
src/locales/**/*.json
📄 CodeRabbit inference engine (AGENTS.md)
Place new i18n translation entries in
src/locales/en/main.jsonand usevue-i18nin Composition API for string literals
Files:
src/locales/en/main.json
tests-ui/**/*.test.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (tests-ui/CLAUDE.md)
tests-ui/**/*.test.{js,ts,jsx,tsx}: Write tests for new features
Follow existing test patterns in the codebase
Use existing test utilities rather than writing custom utilities
Mock external dependencies in tests
Always prefer vitest mock functions over writing verbose manual mocks
Files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer.test.tstests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript exclusively; no new JavaScript code
Files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer.test.tssrc/renderer/extensions/vueNodes/widgets/composables/useFloatWidget.tstests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.tssrc/renderer/extensions/vueNodes/widgets/composables/useNumberStepCalculation.tssrc/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/renderer/extensions/vueNodes/widgets/composables/useComboWidget.tssrc/composables/graph/useGraphNodeManager.tssrc/types/simplifiedWidget.ts
**/composables/**/use*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Name composables with
useXyz.tspattern
Files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer.test.tssrc/renderer/extensions/vueNodes/widgets/composables/useFloatWidget.tstests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.tssrc/renderer/extensions/vueNodes/widgets/composables/useNumberStepCalculation.tssrc/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/renderer/extensions/vueNodes/widgets/composables/useComboWidget.tssrc/composables/graph/useGraphNodeManager.ts
**/*.test.ts
📄 CodeRabbit inference engine (AGENTS.md)
**/*.test.ts: Avoid writing change detector tests that just assert default values
Avoid writing tests dependent on non-behavioral features like utility classes or styles
Avoid writing redundant tests
Files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer.test.tstests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
Files:
src/renderer/extensions/vueNodes/widgets/composables/useFloatWidget.tssrc/renderer/extensions/vueNodes/widgets/composables/useNumberStepCalculation.tssrc/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/renderer/extensions/vueNodes/widgets/composables/useComboWidget.tssrc/composables/graph/useGraphNodeManager.tssrc/types/simplifiedWidget.ts
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
src/renderer/extensions/vueNodes/widgets/composables/useFloatWidget.tssrc/renderer/extensions/vueNodes/widgets/composables/useNumberStepCalculation.tssrc/renderer/extensions/vueNodes/widgets/composables/useStepperControl.tssrc/renderer/extensions/vueNodes/widgets/composables/useComboWidget.tssrc/composables/graph/useGraphNodeManager.ts
🧠 Learnings (36)
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue InputSwitch component with ToggleSwitch
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vuesrc/renderer/extensions/vueNodes/widgets/composables/useComboWidget.tssrc/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue
📚 Learning: 2025-12-06T00:52:35.750Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T00:52:35.750Z
Learning: Applies to **/*.vue : Never use `:class="[]"` to merge class names; always use `cn()` from `@/utils/tailwindUtil` (e.g., `<div :class="cn('text-node-component-header-icon', hasError && 'text-danger')" />`)
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue
📚 Learning: 2025-12-06T00:52:35.750Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T00:52:35.750Z
Learning: Applies to **/*.{ts,vue} : Use es-toolkit for utility functions
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/layout/WidgetLayoutField.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Use setup() function in Vue 3 Composition API
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/layout/WidgetLayoutField.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize provide/inject for dependency injection
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/layout/WidgetLayoutField.vue
📚 Learning: 2025-12-06T00:52:35.750Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T00:52:35.750Z
Learning: Applies to **/*.vue : Use Vue 3 SFCs with Composition API only (use `<script setup lang="ts">`, not Options API)
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/layout/WidgetLayoutField.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Use setup() function for component logic
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/layout/WidgetLayoutField.vue
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Use es-toolkit for utility functions instead of other utility libraries
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/layout/WidgetLayoutField.vue
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Mock external dependencies in tests
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer.test.tstests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer.test.tstests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Always prefer vitest mock functions over writing verbose manual mocks
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer.test.tstests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Use existing test utilities rather than writing custom utilities
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer.test.tstests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer.test.ts
📚 Learning: 2025-12-06T00:52:35.750Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T00:52:35.750Z
Learning: Applies to **/*.{ts,vue} : Write tests for all changes, especially bug fixes to catch future regressions
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer.test.tstests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Follow existing test patterns in the codebase
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer.test.tstests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer.test.tstests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
📚 Learning: 2025-12-06T00:52:35.750Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T00:52:35.750Z
Learning: Applies to src/**/*.test.ts : Write unit and component tests with Vitest using happy-dom
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer.test.ts
📚 Learning: 2025-11-24T19:47:22.909Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:22.909Z
Learning: Applies to browser_tests/**/*.{e2e,spec}.{ts,tsx,js,jsx} : Use Playwright fixtures for browser tests
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `vitest` for unit testing in this project
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `test` instead of `it` for defining test cases in vitest
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer.test.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue Steps component with Stepper without panels
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberSlider.vuetests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.tssrc/renderer/extensions/vueNodes/widgets/composables/useNumberStepCalculation.tssrc/renderer/extensions/vueNodes/widgets/composables/useStepperControl.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Check tests-ui/README.md for test guidelines
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
📚 Learning: 2025-12-06T00:52:35.750Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T00:52:35.750Z
Learning: Applies to **/*.test.ts : Avoid writing change detector tests that just assert default values
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
📚 Learning: 2025-12-06T00:52:35.750Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T00:52:35.750Z
Learning: Applies to **/*.test.ts : Avoid writing tests dependent on non-behavioral features like utility classes or styles
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize ref and reactive for reactive state
Applied to files:
src/renderer/extensions/vueNodes/widgets/composables/useNumberStepCalculation.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Use ref/reactive for state management in Vue 3 Composition API
Applied to files:
src/renderer/extensions/vueNodes/widgets/composables/useNumberStepCalculation.ts
📚 Learning: 2025-12-06T00:52:35.750Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T00:52:35.750Z
Learning: Applies to **/*.vue : Use `computed` instead of a `ref` and `watch` if possible
Applied to files:
src/renderer/extensions/vueNodes/widgets/composables/useNumberStepCalculation.ts
📚 Learning: 2025-12-06T00:52:35.750Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T00:52:35.750Z
Learning: Applies to **/*.vue : Avoid using `ref` if a prop would accomplish the design goals; avoid using `computed` if a `ref` or prop directly would work
Applied to files:
src/renderer/extensions/vueNodes/widgets/composables/useNumberStepCalculation.ts
📚 Learning: 2025-12-04T21:43:49.363Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7137
File: src/components/rightSidePanel/parameters/TabParameters.vue:10-0
Timestamp: 2025-12-04T21:43:49.363Z
Learning: Vue 3.5+ supports reactive props destructure in <script setup>. Destructuring props directly (e.g., `const { nodes } = defineProps<{ nodes: LGraphNode[] }>()`) maintains reactivity through compiler transformation. This is the recommended modern approach and does not require using `props.x` or `toRef`/`toRefs`.
Applied to files:
src/renderer/extensions/vueNodes/widgets/composables/useNumberStepCalculation.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Implement computed() for derived state in Vue 3 Composition API
Applied to files:
src/renderer/extensions/vueNodes/widgets/composables/useNumberStepCalculation.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/*.{vue,ts,tsx} : Follow Vue 3 composition API style guide
Applied to files:
src/renderer/extensions/vueNodes/widgets/composables/useStepperControl.ts
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.{vue,ts} : Leverage VueUse functions for performance-enhancing styles
Applied to files:
src/renderer/extensions/vueNodes/widgets/composables/useStepperControl.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Do not replace `&&=` or `||=` with `=` when there is no reason to do so. If you do find a reason to remove either `&&=` or `||=`, leave a comment explaining why the removal occurred
Applied to files:
src/composables/graph/useGraphNodeManager.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue OverlayPanel component with Popover
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue Dropdown component with Select
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue Calendar component with DatePicker
Applied to files:
src/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue
🧬 Code graph analysis (5)
src/renderer/extensions/vueNodes/widgets/composables/useFloatWidget.ts (2)
src/scripts/widgets.ts (1)
addValueControlWidget(79-102)src/schemas/nodeDef/migration.ts (1)
transformInputSpecV2ToV1(139-143)
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts (2)
src/renderer/extensions/vueNodes/widgets/composables/useStepperControl.ts (1)
useStepperControl(55-111)src/renderer/core/layout/store/layoutStore.ts (1)
onChange(926-929)
src/renderer/extensions/vueNodes/widgets/composables/useStepperControl.ts (3)
src/types/simplifiedWidget.ts (1)
ControlOptions(24-24)src/renderer/core/layout/store/layoutStore.ts (1)
onChange(926-929)src/renderer/extensions/vueNodes/widgets/services/NumberControlRegistry.ts (1)
numberControlRegistry(52-52)
src/renderer/extensions/vueNodes/widgets/composables/useComboWidget.ts (2)
src/scripts/widgets.ts (1)
addValueControlWidgets(104-286)src/schemas/nodeDef/migration.ts (1)
transformInputSpecV2ToV1(139-143)
src/composables/graph/useGraphNodeManager.ts (1)
src/types/simplifiedWidget.ts (2)
SafeControlWidget(35-38)normalizeControlOption(30-33)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: setup
- GitHub Check: lint-and-format
- GitHub Check: setup
- GitHub Check: test
- GitHub Check: collect
🔇 Additional comments (13)
src/renderer/extensions/vueNodes/widgets/components/layout/WidgetLayoutField.vue (1)
32-34: Event propagation simplification looks goodReplacing
noophandlers with bare.stopmodifiers keeps the intended behavior (blocking pointer event bubbling beyond this container) while removing unnecessary code. Slot children still receive pointer events, and no regressions are apparent for layout or interaction.src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue (1)
92-96: UseuseSlots()for reactive slot detection in the:ptbinding.The
$slots.defaultreference inside the:ptobject binding may not be reactive when slot presence changes dynamically. In Vue 3 Composition API, slot access should use theuseSlots()composable for guaranteed reactivity.Apply this diff to ensure reactive slot detection:
<script setup lang="ts"> import InputNumber from 'primevue/inputnumber' -import { computed } from 'vue' +import { computed, useSlots } from 'vue' import type { SimplifiedWidget } from '@/types/simplifiedWidget' import { cn } from '@/utils/tailwindUtil' @@ -18,6 +18,9 @@ const modelValue = defineModel<number>({ default: 0 }) +const slots = useSlots() +const hasSlot = computed(() => !!slots.default) + const filteredProps = computed(() => filterWidgetProps(props.widget.options, INPUT_EXCLUDED_PROPS) )Then update the
:ptbinding::pt="{ root: { class: cn( '[&>input]:bg-transparent [&>input]:border-0', '[&>input]:truncate [&>input]:min-w-[4ch]', - $slots.default && '[&>input]:pr-7' + hasSlot.value && '[&>input]:pr-7' ) },⛔ Skipped due to learnings
Learnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: AGENTS.md:0-0 Timestamp: 2025-12-06T00:52:35.750Z Learning: Applies to **/*.vue : Never use `:class="[]"` to merge class names; always use `cn()` from `@/utils/tailwindUtil` (e.g., `<div :class="cn('text-node-component-header-icon', hasError && 'text-danger')" />`)Learnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: AGENTS.md:0-0 Timestamp: 2025-12-06T00:52:35.750Z Learning: Applies to **/*.vue : Avoid new usage of PrimeVue componentsLearnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: .github/copilot-instructions.md:0-0 Timestamp: 2025-11-24T19:47:02.860Z Learning: Applies to src/**/*.vue : Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)Learnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: src/CLAUDE.md:0-0 Timestamp: 2025-11-24T19:47:34.324Z Learning: Applies to src/**/*.{vue,ts,tsx} : Follow Vue 3 composition API style guideLearnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: src/components/CLAUDE.md:0-0 Timestamp: 2025-11-24T19:47:45.616Z Learning: Applies to src/components/**/*.vue : Replace PrimeVue InputSwitch component with ToggleSwitchLearnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: AGENTS.md:0-0 Timestamp: 2025-12-06T00:52:35.750Z Learning: Applies to **/*.vue : Avoid using `ref` if a prop would accomplish the design goals; avoid using `computed` if a `ref` or prop directly would workLearnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: AGENTS.md:0-0 Timestamp: 2025-12-06T00:52:35.750Z Learning: Applies to **/*.vue : Use `computed` instead of a `ref` and `watch` if possibleLearnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: AGENTS.md:0-0 Timestamp: 2025-12-06T00:52:35.750Z Learning: Applies to **/*.vue : Use Vue 3 SFCs with Composition API only (use `<script setup lang="ts">`, not Options API)Learnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: .github/copilot-instructions.md:0-0 Timestamp: 2025-11-24T19:47:02.860Z Learning: Applies to src/**/*.vue : Utilize ref and reactive for reactive stateLearnt from: CR Repo: Comfy-Org/ComfyUI_frontend PR: 0 File: src/components/CLAUDE.md:0-0 Timestamp: 2025-11-24T19:47:45.616Z Learning: Applies to src/components/**/*.vue : Use ref/reactive for state management in Vue 3 Composition APIsrc/renderer/extensions/vueNodes/widgets/composables/useComboWidget.ts (1)
20-25: Imports for combo control wiring look correctUsing
isComboInputSpec,transformInputSpecV2ToV1, andaddValueControlWidgetshere aligns this composable with the rest of the control-after-generate infrastructure; no issues from a typing or dependency perspective.tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer.test.ts (1)
1-3: Improved test isolation with Pinia and settings mockUsing
createTestingPiniainbeforeEachplus a focuseduseSettingStoremock gives these widget registry tests a clean, deterministic environment without leaking Pinia state across cases. This looks solid.Also applies to: 31-42
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts (1)
33-190: Comprehensive coverage of stepper control behaviorThese tests exercise all the control modes, min/max clamping, default options, and
onChangesemantics, with appropriate mocking for the global seed store and the registry. This gives good confidence thatuseStepperControlwill behave correctly across typical and edge scenarios.Also applies to: 192-272
src/renderer/extensions/vueNodes/components/NodeWidgets.vue (1)
157-166: Correctly propagating control widget metadata into SimplifiedWidgetForwarding both
specand the newcontrolWidgetfield intosimplifiedkeeps the Vue components in sync with the LiteGraph widget state and the graph manager’s SafeWidgetData. This is the right place to expose the control metadata; looks good.src/renderer/extensions/vueNodes/widgets/composables/useFloatWidget.ts (1)
60-61: Float widget control-after-generate wiring is consistent and type-safeCapturing the float widget in a local
widgetvariable and, wheninputSpec.control_after_generateis set, creating a control widget viaaddValueControlWidget(with the V2→V1-transformed spec) and assigningwidget.linkedWidgets = [controlWidget]matches the established pattern for numeric controls. The parameter ordering and default'fixed'mode are correct.Also applies to: 79-89, 91-92
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberSlider.vue (1)
59-60: The original concern aboutnullhandling inhandleNumberInputUpdateis based on incorrect assumptions about PrimeVue InputNumber behaviorPrimeVue InputNumber does NOT emit
update:modelValuewhen the user clears the field. According to PrimeVue's behavior,update:modelValueonly fires on validated changes (blur, Enter, or spinner clicks). Clearing with the clear icon does not trigger this event at all—it only fires theinputevent if anything.The current code at lines 59–60 handles
undefinedcorrectly for its actual purpose: the:key="timesEmptied"binding (line 13) forces InputNumber to re-render and reset its internal state whentimesEmptiedincrements. Sinceupdate:modelValuedoesn't emit anything on clear, thenewValue !== undefinedcheck works as intended for the limited cases where InputNumber does emit (blur, Enter, spinner).The concern about
nullpropagating into anumber-typed model is not applicable here because InputNumber'supdate:modelValuedoesn't emitnullon clear. If clearing behavior needs to be handled differently, consider using the@inputevent instead, but no change is required for the currentundefinedhandling.Likely an incorrect or invalid review comment.
src/renderer/extensions/vueNodes/widgets/composables/useNumberStepCalculation.ts (1)
13-35: LGTM! Well-structured step calculation logic.The composable correctly:
- Prioritizes explicit
step2values over precision-derived steps- Uses
toValuewithMaybeRefOrGetterfor flexible reactivity (as previously suggested)- Handles the
returnUndefinedForDefaultflag appropriately- Returns a
computedref for efficient reactivitysrc/types/simplifiedWidget.ts (2)
26-38: SafeControlWidget type and helper functions look good.The type guard
isControlOptionand normalization functionnormalizeControlOptionprovide safe runtime validation with appropriate fallback behavior. TheSafeControlWidgettype cleanly encapsulates control state and updates.
71-71: Good addition of controlWidget to SimplifiedWidget.Adding the optional
controlWidgetfield enables the control-after-generate feature while maintaining backward compatibility.src/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue (2)
89-170: Excellent use of vue-i18n and semantic styling.The template correctly:
- Uses
$t()for all user-facing strings with entries insrc/locales/en/main.json- Applies semantic Tailwind classes (
bg-interface-panel-surface,text-muted-foreground, etc.) instead ofdark:variants- Provides clear visual hierarchy and accessibility structure
As per coding guidelines.
29-60: Feature flag pattern is clean, but verify LINK_TO_GLOBAL implementation.The
ENABLE_LINK_TO_GLOBALflag cleanly controls the experimental feature. However, enabling this feature will expose the issues flagged inuseStepperControl.ts(missingconvertToEnumcase and missingapplyControlswitch case) andsimplifiedWidget.ts(missing'linkToGlobal'inCONTROL_OPTIONS).Ensure that the flagged issues in the related files are resolved before enabling this feature.
| function getControlWidget(widget: IBaseWidget): SafeControlWidget | undefined { | ||
| const cagWidget = widget.linkedWidgets?.find( | ||
| (w) => w.name == 'control_after_generate' | ||
| ) | ||
| if (!cagWidget) return | ||
| return { | ||
| value: normalizeControlOption(cagWidget.value), | ||
| update: (value) => (cagWidget.value = normalizeControlOption(value)) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use strict equality when locating the control widget
getControlWidget currently uses loose equality:
const cagWidget = widget.linkedWidgets?.find(
(w) => w.name == 'control_after_generate'
)Since w.name is a string, there’s no benefit to == over ===, and sticking to strict equality avoids surprises and matches the rest of the codebase’s style.
- const cagWidget = widget.linkedWidgets?.find(
- (w) => w.name == 'control_after_generate'
- )
+ const cagWidget = widget.linkedWidgets?.find(
+ (w) => w.name === 'control_after_generate'
+ )The rest of the helper (normalizing the value on read/write and exposing controlWidget via safeWidgetMapper) looks good.
Also applies to: 130-132
🤖 Prompt for AI Agents
In src/composables/graph/useGraphNodeManager.ts around lines 87 to 96 (and
similarly at lines 130 to 132), the find predicate uses loose equality when
comparing widget names; change the comparison from == to strict === to match
codebase style and avoid surprises, i.e. update the predicate to use w.name ===
'control_after_generate' in both locations so the control widget is located with
strict equality.
| import Button from 'primevue/button' | ||
| import Popover from 'primevue/popover' | ||
| import ToggleSwitch from 'primevue/toggleswitch' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider future migration away from PrimeVue components.
This component uses PrimeVue's Button, Popover, and ToggleSwitch. The coding guidelines state "Avoid new usage of PrimeVue components," and retrieved learnings mention replacing these with native alternatives. While this may be acceptable within the current architecture, plan to migrate away from PrimeVue in future refactoring.
Based on coding guidelines.
🤖 Prompt for AI Agents
In src/renderer/extensions/vueNodes/widgets/components/NumberControlPopover.vue
around lines 2 to 4, this file imports PrimeVue Button, Popover, and
ToggleSwitch which violates the "avoid new usage of PrimeVue components"
guideline; replace direct PrimeVue usage by creating/using local native or
framework-agnostic equivalents (e.g., a simple native <button> wrapper, a
lightweight popover component implemented with Portal/teleport and CSS, and a
toggle built from input[type="checkbox"] or an existing internal Toggle
component), or introduce small adapter wrappers (e.g., LocalButton,
LocalPopover, LocalToggle) and update the template and props to use those
wrappers so the component no longer depends on PrimeVue and is easier to migrate
later.
| const applyControl = () => { | ||
| const { min = 0, max = 1000000, step2, step = 1, onChange } = options | ||
| const safeMax = Math.min(2 ** 50, max) | ||
| const safeMin = Math.max(-(2 ** 50), min) | ||
| // Use step2 if available (widget context), otherwise use step as-is (direct API usage) | ||
| const actualStep = step2 !== undefined ? step2 : step | ||
|
|
||
| let newValue: number | ||
| switch (controlMode.value) { | ||
| case NumberControlMode.FIXED: | ||
| // Do nothing - keep current value | ||
| return | ||
| case NumberControlMode.INCREMENT: | ||
| newValue = Math.min(safeMax, modelValue.value + actualStep) | ||
| break | ||
| case NumberControlMode.DECREMENT: | ||
| newValue = Math.max(safeMin, modelValue.value - actualStep) | ||
| break | ||
| case NumberControlMode.RANDOMIZE: | ||
| newValue = Math.floor(Math.random() * (safeMax - safeMin + 1)) + safeMin | ||
| break | ||
| default: | ||
| return | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing LINK_TO_GLOBAL case in applyControl logic.
The applyControl function's switch statement (lines 71-86) does not include a case for NumberControlMode.LINK_TO_GLOBAL, even though the enum defines it and useControlButtonIcon handles it. When this mode is active, the function will fall through to the default case and return early without applying any control.
Apply this diff to add the missing case:
case NumberControlMode.RANDOMIZE:
newValue = Math.floor(Math.random() * (safeMax - safeMin + 1)) + safeMin
break
+ case NumberControlMode.LINK_TO_GLOBAL:
+ // Use global seed value, constrained by min/max
+ // Note: Requires globalSeedStore import and implementation
+ // Placeholder for when feature is enabled
+ return
default:
return
}Note: The actual implementation will require importing and using a global seed store, as referenced in the past review comments.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/renderer/extensions/vueNodes/widgets/composables/useStepperControl.ts
around lines 63 to 86 the applyControl switch is missing a case for
NumberControlMode.LINK_TO_GLOBAL; add a case that reads the global seed from the
shared/global seed store (import the store at top), set newValue to that global
seed while clamping it between safeMin and safeMax, and then break so the value
is applied like other modes; ensure the store import and access follow existing
project patterns (reactive getter or accessor) and handle undefined/missing
global seed by falling back to modelValue or a sensible default before clamping.
| const safeMax = Math.min(2 ** 50, max) | ||
| const safeMin = Math.max(-(2 ** 50), min) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider using Number.MAX_SAFE_INTEGER for clarity.
The safe bounds use 2 ** 50, which is within JavaScript's safe integer range but less explicit than the standard constant.
Apply this diff:
- const safeMax = Math.min(2 ** 50, max)
- const safeMin = Math.max(-(2 ** 50), min)
+ const safeMax = Math.min(Number.MAX_SAFE_INTEGER, max)
+ const safeMin = Math.max(-Number.MAX_SAFE_INTEGER, min)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const safeMax = Math.min(2 ** 50, max) | |
| const safeMin = Math.max(-(2 ** 50), min) | |
| const safeMax = Math.min(Number.MAX_SAFE_INTEGER, max) | |
| const safeMin = Math.max(-Number.MAX_SAFE_INTEGER, min) |
🤖 Prompt for AI Agents
In src/renderer/extensions/vueNodes/widgets/composables/useStepperControl.ts
around lines 65-66, replace the hardcoded 2 ** 50 bounds with the standard
constants: set safeMax using Math.min(Number.MAX_SAFE_INTEGER, max) and set
safeMin using Math.max(Number.MIN_SAFE_INTEGER, min) so the intent is explicit
and uses built-in safe-integer constants.
| it('should randomize value in RANDOMIZE mode', () => { | ||
| const modelValue = ref(100) | ||
| const options = { min: 0, max: 10, step: 1 } | ||
|
|
||
| const { controlMode, applyControl } = useStepperControl( | ||
| modelValue, | ||
| options | ||
| ) | ||
| controlMode.value = NumberControlMode.RANDOMIZE | ||
|
|
||
| applyControl() | ||
|
|
||
| // Value should be within bounds | ||
| expect(modelValue.value).toBeGreaterThanOrEqual(0) | ||
| expect(modelValue.value).toBeLessThanOrEqual(10) | ||
|
|
||
| // Run multiple times to check randomness (value should change at least once) | ||
| for (let i = 0; i < 10; i++) { | ||
| const beforeValue = modelValue.value | ||
| applyControl() | ||
| if (modelValue.value !== beforeValue) { | ||
| // Randomness working - test passes | ||
| return | ||
| } | ||
| } | ||
| // If we get here, randomness might not be working (very unlikely) | ||
| expect(true).toBe(true) // Still pass the test | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Simplify RANDOMIZE test to assert behavior deterministically
The RANDOMIZE test already verifies that the resulting value stays within [min, max], which is the key behavior. The follow-up loop that tries to detect that the value “changes at least once” but ultimately falls back to expect(true).toBe(true) doesn’t add real signal and can be dropped to keep the test focused and deterministic.
You could safely remove the change-detection loop and keep only the bounds assertions.
🤖 Prompt for AI Agents
In
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
around lines 134 to 161, the RANDOMIZE test contains a non-deterministic loop
that tries to detect value changes and ends with a no-op fallback
(expect(true).toBe(true)); remove the entire for-loop and the fallback
assertion, leaving only the deterministic assertions that the modelValue.value
is within the min and max bounds after applyControl() to keep the test focused
and reliable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
♻️ Duplicate comments (1)
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts (1)
127-154: Simplify RANDOMIZE test to focus on deterministic behavior.The non-deterministic loop (lines 143-153) that tries to detect value changes and falls back to
expect(true).toBe(true)doesn't add meaningful signal. The bounds assertions (lines 140-141) already validate the key behavior.Remove the loop and keep only the bounds assertions:
it('should randomize value in RANDOMIZE mode', () => { const modelValue = ref(100) const options = { min: 0, max: 10, step: 1 } const { controlMode, applyControl } = useStepperControl( modelValue, options ) controlMode.value = NumberControlMode.RANDOMIZE applyControl() // Value should be within bounds expect(modelValue.value).toBeGreaterThanOrEqual(0) expect(modelValue.value).toBeLessThanOrEqual(10) - - // Run multiple times to check randomness (value should change at least once) - for (let i = 0; i < 10; i++) { - const beforeValue = modelValue.value - applyControl() - if (modelValue.value !== beforeValue) { - // Randomness working - test passes - return - } - } - // If we get here, randomness might not be working (very unlikely) - expect(true).toBe(true) // Still pass the test })
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (16)
browser_tests/tests/vueNodes/groups/groups.spec.ts-snapshots/vue-groups-create-group-chromium-linux.pngis excluded by!**/*.pngbrowser_tests/tests/vueNodes/groups/groups.spec.ts-snapshots/vue-groups-fit-to-contents-chromium-linux.pngis excluded by!**/*.pngbrowser_tests/tests/vueNodes/interactions/canvas/zoom.spec.ts-snapshots/zoomed-in-ctrl-shift-chromium-linux.pngis excluded by!**/*.pngbrowser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-dragging-link-chromium-linux.pngis excluded by!**/*.pngbrowser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-input-drag-ctrl-alt-chromium-linux.pngis excluded by!**/*.pngbrowser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-input-drag-reuses-origin-chromium-linux.pngis excluded by!**/*.pngbrowser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-reroute-input-drag-chromium-linux.pngis excluded by!**/*.pngbrowser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-reroute-output-shift-drag-chromium-linux.pngis excluded by!**/*.pngbrowser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-shift-output-multi-link-chromium-linux.pngis excluded by!**/*.pngbrowser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-snap-to-node-chromium-linux.pngis excluded by!**/*.pngbrowser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-snap-to-slot-chromium-linux.pngis excluded by!**/*.pngbrowser_tests/tests/vueNodes/interactions/node/move.spec.ts-snapshots/vue-node-moved-node-chromium-linux.pngis excluded by!**/*.pngbrowser_tests/tests/vueNodes/nodeStates/bypass.spec.ts-snapshots/vue-node-bypassed-state-chromium-linux.pngis excluded by!**/*.pngbrowser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-color-blue-chromium-linux.pngis excluded by!**/*.pngbrowser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-colors-dark-all-colors-chromium-linux.pngis excluded by!**/*.pngbrowser_tests/tests/vueNodes/nodeStates/mute.spec.ts-snapshots/vue-node-muted-state-chromium-linux.pngis excluded by!**/*.png
📒 Files selected for processing (1)
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
tests-ui/**/*.test.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (tests-ui/CLAUDE.md)
tests-ui/**/*.test.{js,ts,jsx,tsx}: Write tests for new features
Follow existing test patterns in the codebase
Use existing test utilities rather than writing custom utilities
Mock external dependencies in tests
Always prefer vitest mock functions over writing verbose manual mocks
Files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript exclusively; no new JavaScript code
Files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
**/*.{ts,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,vue}: Use camelCase for variable and function names
Indent with 2 spaces (see.prettierrc)
Use single quotes for strings (see.prettierrc)
No trailing semicolons (see.prettierrc)
Maximum line width of 80 characters (see.prettierrc)
Sort and group imports by plugin (runpnpm formatbefore committing)
Never useanytype; use proper TypeScript types instead
Never useas anytype assertions; fix the underlying type issue instead
Avoid code comments unless absolutely necessary; write expressive, self-documenting code instead
When writing new code, ask if there is a simpler way to introduce the same functionality; if yes, choose the simpler approach
Use refactoring to make complex code simpler
Use es-toolkit for utility functions
Use Vite for fast development and building
Implement proper error handling
Write tests for all changes, especially bug fixes to catch future regressions
Files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
**/composables/**/use*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Name composables with
useXyz.tspattern
Files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
**/*.test.ts
📄 CodeRabbit inference engine (AGENTS.md)
**/*.test.ts: Avoid writing change detector tests that just assert default values
Avoid writing tests dependent on non-behavioral features like utility classes or styles
Avoid writing redundant tests
Files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
🧠 Learnings (12)
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
📚 Learning: 2025-12-06T00:52:35.750Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T00:52:35.750Z
Learning: Applies to **/*.{ts,vue} : Write tests for all changes, especially bug fixes to catch future regressions
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Use existing test utilities rather than writing custom utilities
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue Steps component with Stepper without panels
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Follow existing test patterns in the codebase
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Mock external dependencies in tests
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Check tests-ui/README.md for test guidelines
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
📚 Learning: 2025-12-06T00:52:35.750Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T00:52:35.750Z
Learning: Applies to **/*.test.ts : Avoid writing change detector tests that just assert default values
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
📚 Learning: 2025-12-06T00:52:35.750Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T00:52:35.750Z
Learning: Applies to **/*.test.ts : Avoid writing tests dependent on non-behavioral features like utility classes or styles
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
📚 Learning: 2025-12-06T00:52:35.750Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T00:52:35.750Z
Learning: Applies to **/*.test.ts : Avoid writing redundant tests
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Always prefer vitest mock functions over writing verbose manual mocks
Applied to files:
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
🧬 Code graph analysis (1)
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts (1)
src/renderer/extensions/vueNodes/widgets/composables/useStepperControl.ts (1)
useStepperControl(55-111)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: test
- GitHub Check: lint-and-format
- GitHub Check: setup
- GitHub Check: collect
| // Mock the registry to spy on calls | ||
| vi.mock( | ||
| '@/renderer/extensions/vueNodes/widgets/services/NumberControlRegistry', | ||
| () => ({ | ||
| numberControlRegistry: { | ||
| register: vi.fn(), | ||
| unregister: vi.fn(), | ||
| executeControls: vi.fn(), | ||
| getControlCount: vi.fn(() => 0), | ||
| clear: vi.fn() | ||
| }, | ||
| executeNumberControls: vi.fn() | ||
| }) | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider verifying registry registration behavior.
The mock is correctly set up, but none of the tests verify that register and unregister are called during the composable's lifecycle (onMounted/onUnmounted). Since the implementation registers the control with the singleton registry, this is testable behavior that should be verified.
Add a test to verify the lifecycle hooks:
+ describe('registry integration', () => {
+ it('should register control on mount and unregister on unmount', async () => {
+ const { numberControlRegistry } = await import(
+ '@/renderer/extensions/vueNodes/widgets/services/NumberControlRegistry'
+ )
+ const modelValue = ref(100)
+ const options = { min: 0, max: 1000, step: 1 }
+
+ const wrapper = mount({
+ setup() {
+ return useStepperControl(modelValue, options)
+ },
+ template: '<div />'
+ })
+
+ expect(numberControlRegistry.register).toHaveBeenCalledTimes(1)
+ expect(numberControlRegistry.register).toHaveBeenCalledWith(
+ expect.any(Symbol),
+ expect.any(Function)
+ )
+
+ wrapper.unmount()
+
+ expect(numberControlRegistry.unregister).toHaveBeenCalledTimes(1)
+ })
+ })Committable suggestion skipped: line range outside the PR's diff.
| it('should return control mode and apply function', () => { | ||
| const modelValue = ref(100) | ||
| const options = { min: 0, max: 1000, step: 1 } | ||
|
|
||
| const { controlMode, applyControl } = useStepperControl( | ||
| modelValue, | ||
| options | ||
| ) | ||
|
|
||
| expect(controlMode.value).toBe(NumberControlMode.RANDOMIZE) | ||
| expect(typeof applyControl).toBe('function') | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider consolidating initialization tests.
This test overlaps significantly with the previous test (line 33), both checking the default mode is RANDOMIZE. The additional type check for applyControl is useful but could be merged into a single, more comprehensive initialization test to reduce redundancy.
As per coding guidelines: Avoid writing redundant tests.
🤖 Prompt for AI Agents
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
lines 42-53: duplicate initialization test — merge this block with the earlier
test around line 33 so there is a single comprehensive initialization test that
asserts the default controlMode is NumberControlMode.RANDOMIZE and also checks
that applyControl is a function; remove the redundant test case and update the
combined test to include both expectations (default mode and applyControl type)
to avoid repetition.
| describe('control modes', () => { | ||
| it('should not change value in FIXED mode', () => { | ||
| const modelValue = ref(100) | ||
| const options = { min: 0, max: 1000, step: 1 } | ||
|
|
||
| const { controlMode, applyControl } = useStepperControl( | ||
| modelValue, | ||
| options | ||
| ) | ||
| controlMode.value = NumberControlMode.FIXED | ||
|
|
||
| applyControl() | ||
| expect(modelValue.value).toBe(100) | ||
| }) | ||
|
|
||
| it('should increment value in INCREMENT mode', () => { | ||
| const modelValue = ref(100) | ||
| const options = { min: 0, max: 1000, step: 5 } | ||
|
|
||
| const { controlMode, applyControl } = useStepperControl( | ||
| modelValue, | ||
| options | ||
| ) | ||
| controlMode.value = NumberControlMode.INCREMENT | ||
|
|
||
| applyControl() | ||
| expect(modelValue.value).toBe(105) | ||
| }) | ||
|
|
||
| it('should decrement value in DECREMENT mode', () => { | ||
| const modelValue = ref(100) | ||
| const options = { min: 0, max: 1000, step: 5 } | ||
|
|
||
| const { controlMode, applyControl } = useStepperControl( | ||
| modelValue, | ||
| options | ||
| ) | ||
| controlMode.value = NumberControlMode.DECREMENT | ||
|
|
||
| applyControl() | ||
| expect(modelValue.value).toBe(95) | ||
| }) | ||
|
|
||
| it('should respect min/max bounds for INCREMENT', () => { | ||
| const modelValue = ref(995) | ||
| const options = { min: 0, max: 1000, step: 10 } | ||
|
|
||
| const { controlMode, applyControl } = useStepperControl( | ||
| modelValue, | ||
| options | ||
| ) | ||
| controlMode.value = NumberControlMode.INCREMENT | ||
|
|
||
| applyControl() | ||
| expect(modelValue.value).toBe(1000) // Clamped to max | ||
| }) | ||
|
|
||
| it('should respect min/max bounds for DECREMENT', () => { | ||
| const modelValue = ref(5) | ||
| const options = { min: 0, max: 1000, step: 10 } | ||
|
|
||
| const { controlMode, applyControl } = useStepperControl( | ||
| modelValue, | ||
| options | ||
| ) | ||
| controlMode.value = NumberControlMode.DECREMENT | ||
|
|
||
| applyControl() | ||
| expect(modelValue.value).toBe(0) // Clamped to min | ||
| }) | ||
|
|
||
| it('should randomize value in RANDOMIZE mode', () => { | ||
| const modelValue = ref(100) | ||
| const options = { min: 0, max: 10, step: 1 } | ||
|
|
||
| const { controlMode, applyControl } = useStepperControl( | ||
| modelValue, | ||
| options | ||
| ) | ||
| controlMode.value = NumberControlMode.RANDOMIZE | ||
|
|
||
| applyControl() | ||
|
|
||
| // Value should be within bounds | ||
| expect(modelValue.value).toBeGreaterThanOrEqual(0) | ||
| expect(modelValue.value).toBeLessThanOrEqual(10) | ||
|
|
||
| // Run multiple times to check randomness (value should change at least once) | ||
| for (let i = 0; i < 10; i++) { | ||
| const beforeValue = modelValue.value | ||
| applyControl() | ||
| if (modelValue.value !== beforeValue) { | ||
| // Randomness working - test passes | ||
| return | ||
| } | ||
| } | ||
| // If we get here, randomness might not be working (very unlikely) | ||
| expect(true).toBe(true) // Still pass the test | ||
| }) | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Add test coverage for step2 vs step behavior.
The implementation uses step2 when available and falls back to step (see useStepperControl.ts lines 67-68), but no tests verify this code path. Since step2 is used in widget contexts, this is important behavior to test.
Add tests for step2 behavior:
+ it('should prefer step2 over step for INCREMENT when both provided', () => {
+ const modelValue = ref(100)
+ const options = { min: 0, max: 1000, step: 1, step2: 10 }
+
+ const { controlMode, applyControl } = useStepperControl(
+ modelValue,
+ options
+ )
+ controlMode.value = NumberControlMode.INCREMENT
+
+ applyControl()
+ expect(modelValue.value).toBe(110) // step2 should be used
+ })
+
+ it('should prefer step2 over step for DECREMENT when both provided', () => {
+ const modelValue = ref(100)
+ const options = { min: 0, max: 1000, step: 1, step2: 10 }
+
+ const { controlMode, applyControl } = useStepperControl(
+ modelValue,
+ options
+ )
+ controlMode.value = NumberControlMode.DECREMENT
+
+ applyControl()
+ expect(modelValue.value).toBe(90) // step2 should be used
+ })🤖 Prompt for AI Agents
In
tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useStepperControl.test.ts
around lines 56-155, add unit tests that explicitly cover the step2 vs step
behavior: create test cases where options include both step (e.g. 1) and step2
(e.g. 7) and assert that INCREMENT/DECREMENT change modelValue by step2 (±7) and
respect min/max when using step2; also add a test where step2 is undefined to
confirm fallback to step (e.g. step=5 causes ±5). Keep tests consistent with the
existing pattern (use ref for modelValue, set controlMode, call applyControl,
assert expected values and clamping).
Continuation of #6034 with
Several issues from original PR have not (yet) been addressed, but are likely better moved to future PR
┆Issue is synchronized with this Notion page by Unito