-
Notifications
You must be signed in to change notification settings - Fork 420
Webcam capture Node #6795
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?
Webcam capture Node #6795
Conversation
🎨 Storybook Build Status✅ Build completed successfully! ⏰ Completed at: 11/27/2025, 03:30:07 AM UTC 🔗 Links🎉 Your Storybook is ready for review! |
🎭 Playwright Test Results⏰ Completed at: 11/27/2025, 03:38:26 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.18 MB (baseline 3.18 MB) • 🔴 +1.39 kBMain entry bundles and manifests
Status: 3 added / 3 removed Graph Workspace — 928 kB (baseline 946 kB) • 🟢 -17.6 kBGraph 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 — 143 kB (baseline 139 kB) • 🔴 +4 kBReusable component library chunks
Status: 10 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 — 22.9 kB (baseline 2.94 kB) • 🔴 +20 kBHelpers, composables, and utility bundles
Status: 2 added / 1 removed Vendor & Third-Party — 8.56 MB (baseline 8.56 MB) • ⚪ 0 BExternal libraries and shared vendor chunks
Status: 5 added / 5 removed Other — 3.86 MB (baseline 3.84 MB) • 🔴 +21.4 kBBundles that do not match a named category
Status: 24 added / 23 removed |
…ontrols Implements a proper Vue toggle widget component and enhances the webcam widget to dynamically show/hide related controls based on camera state, with automatic restoration on component unmount.
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughWalkthroughAdds GraphNodeManager APIs to immutably update and re-sync Vue widget state, registers and implements two new Vue widgets (webcam and select-toggle), extends English localization with webcam/capture strings, and makes small UI/formatting tweaks to existing widget components. Changes
Sequence Diagram(s)sequenceDiagram
participant Vue as Vue Component
participant GraphMgr as GraphNodeManager
participant VueState as Vue State Map
participant LiteGraph as LiteGraph Node
rect rgb(200,220,240)
Note over Vue,GraphMgr: updateVueWidgetOptions
Vue->>GraphMgr: updateVueWidgetOptions(nodeId, widgetName, options)
GraphMgr->>VueState: Read current widget(s)
GraphMgr->>GraphMgr: Merge options immutably, build new widget object/array
GraphMgr->>VueState: Write new widget object/array (triggers reactivity)
VueState-->>Vue: UI updates
end
rect rgb(240,220,200)
Note over Vue,LiteGraph: refreshVueWidgets
Vue->>GraphMgr: refreshVueWidgets(nodeId)
GraphMgr->>LiteGraph: Read node inputs / slot metadata
GraphMgr->>GraphMgr: Map widgets via safeWidgetMapper
GraphMgr->>VueState: Replace node's widgets array
VueState-->>Vue: Re-synchronized widgets rendered
end
sequenceDiagram
participant User
participant WidgetWebcam as WidgetWebcam
participant MediaAPI as Browser Media API
participant LiteGraph as LiteGraph Node
participant API as Backend API
rect rgb(220,240,200)
Note over User,WidgetWebcam: Live preview & manual capture flows
User->>WidgetWebcam: Enable camera / open widget
WidgetWebcam->>MediaAPI: getUserMedia()
MediaAPI-->>WidgetWebcam: MediaStream
WidgetWebcam->>WidgetWebcam: Attach stream to visible + hidden video
WidgetWebcam->>LiteGraph: Add or update Capture Photo / Retake action widgets
User->>WidgetWebcam: Click Capture Photo
WidgetWebcam->>WidgetWebcam: Draw frame to canvas, create blob/dataURL
WidgetWebcam->>API: Upload image (if configured)
API-->>WidgetWebcam: Uploaded path
WidgetWebcam->>LiteGraph: Update node image data/widget
end
rect rgb(240,200,200)
Note over User,WidgetWebcam: On-queue (auto) capture
User->>WidgetWebcam: Switch capture mode to On Run
WidgetWebcam->>LiteGraph: Toggle `capture_on_queue` widget
On run -> WidgetWebcam: Capture from hidden video, upload, update node
end
Possibly related PRs
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (5)
🧰 Additional context used📓 Path-based instructions (17)**/*.{vue,ts,tsx}📄 CodeRabbit inference engine (.cursorrules)
Files:
**/*.{ts,tsx,js}📄 CodeRabbit inference engine (.cursorrules)
Files:
**/*.{ts,tsx}📄 CodeRabbit inference engine (.cursorrules)
Files:
**/*.{ts,tsx,js,vue}📄 CodeRabbit inference engine (.cursorrules)
Files:
src/**/*.{vue,ts}📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
src/**/*.ts📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
**/*.{ts,tsx,js,jsx,vue}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
**/*.{ts,tsx,vue}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
**/*.ts📄 CodeRabbit inference engine (CLAUDE.md)
Files:
src/**/{services,composables}/**/*.{ts,tsx}📄 CodeRabbit inference engine (src/CLAUDE.md)
Files:
src/**/*.{ts,tsx,vue}📄 CodeRabbit inference engine (src/CLAUDE.md)
Files:
src/**/{composables,components}/**/*.{ts,tsx,vue}📄 CodeRabbit inference engine (src/CLAUDE.md)
Files:
src/**/*.{vue,ts,tsx}📄 CodeRabbit inference engine (src/CLAUDE.md)
Files:
src/**/{components,composables}/**/*.{ts,tsx,vue}📄 CodeRabbit inference engine (src/CLAUDE.md)
Files:
**/*.vue📄 CodeRabbit inference engine (.cursorrules)
|
…elds Use toRaw() and markRaw() when modifying widget objects to prevent Vue's reactive proxy from wrapping them. This fixes errors when LiteGraph tries to access private class members like #value in BaseWidget.
Add video preview functionality with hover overlay that allows users to: - Click button to start camera and show live preview - Hover over video to see stop overlay - Click anywhere on video to hide preview (keeps camera active) - Click button again to re-show preview without re-requesting permissions Uses VueUse's useElementHover for automatic hover detection and proper MediaStream handling with cleanup on unmount.
Added programmatic capture button that appears when camera is turned on. The button uses node.addWidget() to integrate with LiteGraph canvas. - Add captureImage() function to draw video frame to canvas and store in node.imgs - Add capture button widget in showWidgets() using node.addWidget() - Create canvas element at module level for efficient reuse - Widget restoration handled by existing restoreWidgets() cleanup
Added optional iconClass property to IWidgetOptions to support icon display in widget buttons.
Updated button widget to support icon display and improved styling to match design system. - Add icon rendering using widget.options.iconClass - Update styling to use semantic tokens - Use widget.label for display instead of widget.name - Apply consistent button styling with design system tokens
… capture/retake widgets
… queue and refine default width/height values.
…capture Mutate widget objects in place instead of creating new instances to fix a reactivity issue where serializeValue closure captured stale widget references. Also adds persistent video element for background capture when UI video is hidden. Fixes capture_on_queue toggle not being read correctly during serialization.
…dget - Add updateVueWidgetOptions to GraphNodeManager to update widget options and trigger Vue reactivity - Implement capture button visibility toggle based on capture_on_queue value - Default capture mode to 'Manually' (false) - Use Vue watch to reactively hide/show capture button when mode changes
- Add refreshVueWidgets function to GraphNodeManager for manually syncing LiteGraph widget changes with Vue reactive state - Use refreshVueWidgets after widget modifications (capture, retake, show) - Fixes retake button not appearing after capturing an image
- Clear captured image and restart camera preview when toggling to On Run - Restore capture button when switching back to Manual mode - Ensures smooth UX when changing capture modes
- Add refreshVueWidgets call in hideWidgets to sync Vue state on mount - Update stop camera button with rounded container and square icon - Use bg-destructive-background design token for stop button
src/renderer/extensions/vueNodes/widgets/components/WidgetWebcam.vue
Outdated
Show resolved
Hide resolved
src/renderer/extensions/vueNodes/widgets/components/WidgetWebcam.vue
Outdated
Show resolved
Hide resolved
src/renderer/extensions/vueNodes/widgets/components/WidgetWebcam.vue
Outdated
Show resolved
Hide resolved
src/renderer/extensions/vueNodes/widgets/components/WidgetWebcam.vue
Outdated
Show resolved
Hide resolved
src/renderer/extensions/vueNodes/widgets/components/WidgetSelectToggle.vue
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.
Comprehensive PR Review
This review is generated by Claude. It may not always be accurate, as with human reviewers. If you believe that any of the comments are invalid or incorrect, please state why for each. For others, please implement the changes in one way or another.
Review Summary
PR: Webcam capture Node (#6795)
Impact: 884 additions, 2 deletions across 7 files
Issue Distribution
- Critical: 0
- High: 1
- Medium: 5
- Low: 3
Category Breakdown
- Architecture: 0 issues
- Security: 1 issues
- Performance: 4 issues
- Code Quality: 4 issues
Key Findings
Architecture & Design
The webcam widget implementation follows established Vue component patterns and integrates well with the existing widget system. The new updateVueWidgetOptions and refreshVueWidgets methods in GraphNodeManager provide necessary reactive state management for dynamic widget visibility. The component properly separates concerns between camera management, UI state, and widget lifecycle.
Security Considerations
Critical Issue: MediaStream cleanup is incomplete in error scenarios, potentially leaving camera access active and creating privacy/resource leaks. The error handling in startCameraPreview only sets UI state but does not call stopStreamTracks() to properly release media resources.
Performance Impact
Memory Management: Canvas elements are created per widget instance rather than on-demand, and event listeners lack proper cleanup. The persistent video element approach is clever but increases memory overhead. LODFallback component may be obsolete after recent LOD system removal.
Race Conditions: Camera stream initialization lacks concurrency protection, potentially causing conflicts with multiple rapid camera access attempts.
Integration Points
The implementation integrates well with existing systems:
- Widget registry properly extends with new types
- Vue reactivity system correctly manages state updates
- LiteGraph integration maintains proper node lifecycle
- Localization strings appropriately added
Positive Observations
- Clean Component Design: Well-structured Vue component with clear separation of concerns
- Comprehensive Feature Set: Supports both manual capture and auto-capture modes
- Good Error Handling: Provides user-friendly error messages for common failure scenarios
- Accessibility: Uses proper ARIA attributes and semantic HTML structure
- Resource Management: Implements proper component cleanup in onUnmounted hook
- Code Consistency: Follows established patterns from existing widgets
Next Steps
- Address critical issues before merge
- Consider architectural feedback for long-term maintainability
- Add tests for uncovered scenarios
- Update documentation if needed
This is a comprehensive automated review. For architectural decisions requiring human judgment, please request additional manual review.
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
src/renderer/extensions/vueNodes/widgets/components/WidgetSelectToggle.vue
Show resolved
Hide resolved
src/renderer/extensions/vueNodes/widgets/components/WidgetWebcam.vue
Outdated
Show resolved
Hide resolved
src/renderer/extensions/vueNodes/widgets/components/WidgetWebcam.vue
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: 0
🧹 Nitpick comments (1)
src/renderer/extensions/vueNodes/widgets/components/WidgetWebcam.vue (1)
165-181: Localize capture mode label and option texts forcapture_on_queue
applyWidgetVisibilityhardcodes several user-facing strings ('Capture Image','On Run','Manually') directly into widget labels/options. These appear in the node UI and should go through vue-i18n like the rest of this component’s text.Consider changing to something along these lines and adding the keys to
src/locales/en/main.json:if (widget.name === 'capture_on_queue') { // Mutate in place to preserve object identity for serializeValue closure widget.type = 'selectToggle' - widget.label = 'Capture Image' + widget.label = t('g.captureImage', 'Capture Image') @@ widget.options = { ...widget.options, hidden, values: [ - { label: 'On Run', value: true }, - { label: 'Manually', value: false } + { label: t('g.captureOnRun', 'On Run'), value: true }, + { label: t('g.captureManually', 'Manually'), value: false } ] }Please ensure the chosen i18n keys (
g.captureImage,g.captureOnRun,g.captureManuallyor equivalents) match what you add tomain.jsonand your naming conventions.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/locales/en/main.json(1 hunks)src/renderer/extensions/vueNodes/widgets/components/WidgetWebcam.vue(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/locales/en/main.json
🧰 Additional context used
📓 Path-based instructions (12)
**/*.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/WidgetWebcam.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/WidgetWebcam.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/WidgetWebcam.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/WidgetWebcam.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/WidgetWebcam.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/WidgetWebcam.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/WidgetWebcam.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/WidgetWebcam.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/WidgetWebcam.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/WidgetWebcam.vuesrc/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/renderer/extensions/vueNodes/widgets/components/WidgetWebcam.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/WidgetWebcam.vue🧠 Learnings (7)
📚 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 : Utilize ref and reactive for reactive state in Vue 3Applied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetWebcam.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 Vue 3's Teleport component when neededApplied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetWebcam.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/**/{composables,components}/**/*.{ts,tsx,vue} : Clean up subscriptions in state management to prevent memory leaksApplied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetWebcam.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 cleanup for async operations in Vue componentsApplied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetWebcam.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,ts,js} : Use vue-i18n for ALL UI stringsApplied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetWebcam.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/**/{components,composables}/**/*.{ts,tsx,vue} : Use vue-i18n for ALL user-facing strings by adding them to `src/locales/en/main.json`Applied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetWebcam.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} : Use vue-i18n in Composition API for any string literals and place new translation entries in src/locales/en/main.jsonApplied to files:
src/renderer/extensions/vueNodes/widgets/components/WidgetWebcam.vue🪛 ESLint
src/renderer/extensions/vueNodes/widgets/components/WidgetWebcam.vue
[error] 1-1: Resolve error: EACCES: permission denied, open '/kRoKhGDpkO'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/eslint-import-context@0.1.9_unrs-resolver@1.11.1/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)
at ExportMap.get (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/export-map.js:88:22)
at processBodyStatement (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/namespace.js:9:31)
at Program (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/namespace.js:100:21)
at ruleErrorHandler (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1173:33)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:46
at Array.forEach ()
at SourceCodeVisitor.callSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:30)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:291:18
at Array.forEach ()
at SourceCodeTraverser.traverseSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:290:10)
at runRules (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1214:12)
at #flatVerifyWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2101:4)
at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2189:43)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1773:17
at Array.map ()
at Linter._verifyWithFlatConfigArrayAndProcessor (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1768:30)
at Linter._verifyWithFlatConfigArray (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2275:16)
at Linter.verify (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1677:10)
at Linter.verifyAndFix (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2557:20)
at verifyText (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1179:45)
at readAndVerifyFile (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1320:10)(import-x/namespace)
[error] 1-1: Resolve error: EACCES: permission denied, open '/WiPpPGoVej'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/eslint-import-context@0.1.9_unrs-resolver@1.11.1/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)
at checkSourceValue (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/no-unresolved.js:31:34)
at checkSourceValue (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:14:9)
at checkSource (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:17:9)
at ruleErrorHandler (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1173:33)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:46
at Array.forEach ()
at SourceCodeVisitor.callSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:30)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:291:18
at Array.forEach ()
at SourceCodeTraverser.traverseSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:290:10)
at runRules (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1214:12)
at #flatVerifyWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2101:4)
at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2189:43)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1773:17
at Array.map ()
at Linter._verifyWithFlatConfigArrayAndProcessor (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1768:30)
at Linter._verifyWithFlatConfigArray (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2275:16)
at Linter.verify (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1677:10)
at Linter.verifyAndFix (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2557:20)
at verifyText (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1179:45)
at readAndVerifyFile (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1320:10)(import-x/no-unresolved)
[error] 1-1: Resolve error: EACCES: permission denied, open '/TdXVgIsucE'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/eslint-import-context@0.1.9_unrs-resolver@1.11.1/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)
at importType (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/import-type.js:126:63)
at checkImportForRelativePackage (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/no-relative-packages.js:15:38)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/no-relative-packages.js:59:40
at checkSourceValue (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:14:9)
at checkSource (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:17:9)
at ruleErrorHandler (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1173:33)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:46
at Array.forEach ()
at SourceCodeVisitor.callSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:30)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:291:18
at Array.forEach ()
at SourceCodeTraverser.traverseSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:290:10)
at runRules (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1214:12)
at #flatVerifyWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2101:4)
at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2189:43)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1773:17
at Array.map ()
at Linter._verifyWithFlatConfigArrayAndProcessor (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1768:30)
at Linter._verifyWithFlatConfigArray (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2275:16)
at Linter.verify (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1677:10)
at Linter.verifyAndFix (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2557:20)
at verifyText (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1179:45)
at readAndVerifyFile (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1320:10)(import-x/no-relative-packages)
[error] 66-66: Unable to resolve path to module '@vueuse/core'.
(import-x/no-unresolved)
[error] 67-67: Unable to resolve path to module 'primevue'.
(import-x/no-unresolved)
[error] 77-77: Unable to resolve path to module 'vue'.
(import-x/no-unresolved)
[error] 79-79: Unable to resolve path to module '@/composables/graph/useVueNodeLifecycle'.
(import-x/no-unresolved)
[error] 80-80: Unable to resolve path to module '@/i18n'.
(import-x/no-unresolved)
[error] 83-83: Unable to resolve path to module '@/platform/updates/common/toastStore'.
(import-x/no-unresolved)
[error] 84-84: Unable to resolve path to module '@/scripts/api'.
(import-x/no-unresolved)
[error] 85-85: Unable to resolve path to module '@/scripts/app'.
(import-x/no-unresolved)
⏰ 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: setup
- GitHub Check: test
- GitHub Check: lint-and-format
- GitHub Check: collect
🔇 Additional comments (1)
src/renderer/extensions/vueNodes/widgets/components/WidgetWebcam.vue (1)
65-111: Overall component setup and state management look solidUse of
<script setup>with typed props/refs,computed,watch, and VueUse/PrimeVue integrations is clean and aligns with the repo’s Composition API and styling guidelines. No structural issues spotted in this section.
- Add stopStreamTracks() call in catch block to release any partially acquired media tracks when camera access fails - Prevents privacy and resource leaks from orphaned media streams
- Define DEFAULT_VIDEO_WIDTH and DEFAULT_VIDEO_HEIGHT constants - Replace hardcoded 640 and 480 values with named constants
- Add isInitializingCamera flag to prevent concurrent calls to startCameraPreview - Use finally block to ensure flag is always reset after initialization
- Store cleanup function reference for pending video event listeners - Call cleanup in onUnmounted to prevent memory leaks if component unmounts while waiting for video metadata
- Add 'yes', 'on', 'off' keys to locales/en/main.json - Replace hardcoded strings in WidgetSelectToggle with t() function
- Move canvas and persistentVideo creation to onMounted - Store as refs for proper lifecycle management - Clean up elements in onUnmounted to prevent memory leaks - Prevents potential conflicts if multiple webcam widgets exist
This pull request introduces support for new widget types in the graph node system, improves widget option reactivity, and adds several UI and localization enhancements. The most significant changes are the addition of a webcam widget and a select/toggle widget, improvements to how widget option changes trigger Vue reactivity, and updates to localization strings for webcam-related UI.
Widget System Enhancements
webcamandselectToggle, including their registration in the widget registry and dynamic imports for their components (WidgetWebcam.vueandWidgetSelectToggle.vue). [1] [2]WidgetSelectToggle.vuecomponent, supporting flexible options and improved UI for boolean and multi-value widgets.Graph Node Manager Improvements
updateVueWidgetOptionsmethod to theGraphNodeManagerinterface and implementation, ensuring widget option changes (like hidden/disabled) properly trigger Vue reactivity. [1] [2] [3]Localization Updates
UI Tweaks
WidgetButton.vuecomponent for improved layout consistency.Screen.Recording.2025-11-26.at.23.31.11.mov