-
Notifications
You must be signed in to change notification settings - Fork 424
Sync Vue Nodes Right Click menu with full ContextMenu #6455
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
🎨 Storybook Build Status✅ Build completed successfully! ⏰ Completed at: 12/02/2025, 02:02:10 AM UTC 🔗 Links🎉 Your Storybook is ready for review! |
🎭 Playwright Test Results❌ Some tests failed ⏰ Completed at: 12/02/2025, 02:12:06 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) • 🔴 +191 BMain entry bundles and manifests
Status: 3 added / 3 removed Graph Workspace — 960 kB (baseline 956 kB) • 🔴 +3.79 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 — 139 kB (baseline 139 kB) • ⚪ 0 BReusable component library chunks
Status: 5 added / 5 removed Data & Services — 12.5 kB (baseline 12.5 kB) • ⚪ 0 BStores, services, APIs, and repositories
Status: 2 added / 2 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) • ⚪ 0 BExternal libraries and shared vendor chunks
Other — 3.84 MB (baseline 3.84 MB) • ⚪ 0 BBundles that do not match a named category
Status: 17 added / 17 removed |
3d05c49 to
8e7026d
Compare
8e7026d to
52b7b5c
Compare
- Add disabled property to MenuOption and SubMenuOption interfaces - Apply semantic token styling for disabled items (text-node-icon-disabled) - Prevent interactions on disabled menu and submenu items - Use cursor-not-allowed and pointer-events-none for disabled state - Pass through disabled flag from LiteGraph menu items to Vue components
Add translation key for the Extensions section label in the context menu. This allows the Extensions category header to be properly localized.
Add support for non-clickable category labels in the context menu. Category items are displayed as uppercase labels with secondary text color and proper translation support via contextMenu namespace. This enables grouping menu items under section headers like "Extensions".
Add comprehensive menu ordering system to ensure consistent context menu layout: - Define MENU_ORDER constant with 5 logical sections - Implement automatic section-based divider insertion - Separate core items from extension items - Add blacklist for unwanted duplicate items (Colors, Shapes, Title, Mode, etc.) - Preserve Vue hardcoded options over LiteGraph items during deduplication - Add source tracking (litegraph vs vue) for precedence handling Menu structure: 1. Basic operations (Rename, Copy, Duplicate) 2. Node actions (Run Branch, Pin, Bypass, Mute) 3. Structure operations (Convert to Subgraph, Frame selection, Minimize Node) 4. Node properties (Node Info, Color) 5. Node-specific operations (Image operations) 6. Extensions section (non-core items) 7. Delete (always at bottom) The system ensures proper ordering regardless of whether items come from LiteGraph or Vue hardcoded menus, with Extensions clearly separated.
Reorder menu sections to follow the specification: 1. Basic operations: Rename, Copy, Duplicate 2. Node actions: Run Branch, Pin, Bypass, Mute (for groups) 3. Structure operations: Convert to Subgraph, Frame selection, Minimize Node 4. Node properties: Node Info, Color (Shape removed) 5. Node-specific operations: Image operations only Changes: - Add explicit dividers after each section - Remove Shape, Alignment, and Adjust Size options - Merge LiteGraph and Vue options for single node selection - Add source tracking (vue) for precedence during deduplication - Add comprehensive logging for debugging menu construction For single node selection, both LiteGraph and Vue options are merged with Vue options taking precedence, then structured via buildStructuredMenu.
Add real-time search filtering to the node context menu: - Search input with icon at the top of the menu - Case-insensitive filtering by menu item label - Auto-focus on menu open - Clear search on Escape key or menu close - Smart divider handling (removes unnecessary dividers during search) - Hides Extensions category label when searching The search provides instant feedback as users type, making it easier to find specific menu items in long context menus.
Move Resize and Clone menu items from fallback section to Section 3 (Structure operations) so they appear alongside Convert to Subgraph, Frame selection, and Minimize Node. Updated section boundaries: - Section 3 now spans indices 9-15 (was 9-13) - Section 4 now spans indices 16-17 (was 14-15) This ensures Resize and Clone appear under the same divider group as other structure-related operations.
When right-clicking near the bottom of the viewport, the context menu now docks to the bottom edge instead of floating off-screen, ensuring it remains accessible and scrollable.
Replaces simple substring matching with Fuse.js fuzzy search for better user experience. Adds 300ms debouncing to reduce processing overhead. Includes debug logging for troubleshooting.
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.
How much of this is necessary because we're not using a good existing component?
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.
The menu isn't keyboard navigable?
That's a pretty big accessibility concern.
📝 WalkthroughWalkthroughReplaces the Popover-based node options UI with a PrimeVue ContextMenu, adds a LiteGraph→Vue context-menu converter and legacy compatibility wrappers, widens LiteGraph menu typings to allow null entries, moves color‑picker positioning to inline DOM, privatizes selection‑toolbox signals, and removes submenu positioning composable. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Canvas as LGraphCanvas
participant Converter as contextMenuConverter
participant Store as MenuOptionsStore
participant CMC as NodeContextMenu
participant ColorPicker as ColorPickerMenu
User->>Canvas: Right-click node
Canvas->>Canvas: getNodeMenuOptions()
Canvas->>Converter: convertContextMenuToOptions(litegraphItems)
Converter->>Converter: normalize, dedupe, capture dynamic submenus
Converter->>Store: buildStructuredMenu(merged options)
Store-->>CMC: MenuOption[]
Canvas->>CMC: toggle(event)
CMC->>CMC: convert MenuOption[] → PrimeVue menuItems
CMC->>User: show context menu
User->>CMC: Click color option (isColorPicker)
CMC->>ColorPicker: toggle(target)
ColorPicker->>ColorPicker: compute position, show
User->>ColorPicker: select color
ColorPicker->>CMC: handleColorSelect()
CMC->>CMC: execute action, hide menus
Possibly related PRs
✨ Finishing touches🧪 Generate unit tests (beta)
Comment |
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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/components/graph/selectionToolbox/MenuOptionItem.vue (1)
1-47: Category row & disabled styling look good; badge i18n keying may need tightening
- The new
option.type === 'category'branch withpointer-events-noneandt(\contextMenu.${option.label}`)` is consistent with how other context-menu labels are translated and correctly non-interactive.- The dynamic class array for the main row cleanly distinguishes disabled vs enabled states and matches the new disabled behavior elsewhere.
One small i18n concern: badge values are translated via
t(option.badge), whereoption.badgeis typically'new'or'deprecated', but the corresponding strings live under thecontextMenunamespace (contextMenu.new/contextMenu.deprecated) inmain.json. Unless you also define root-levelnew/deprecatedkeys in the messages, this will likely show the raw key instead of a localized string.You can tighten this by scoping badges to the same namespace:
- :value="t(option.badge)" + :value="t(`contextMenu.${option.badge}`)"This keeps badge translations aligned with the rest of the context-menu labels.
♻️ Duplicate comments (2)
src/components/graph/selectionToolbox/NodeOptions.vue (2)
130-189: Filtering & divider reconstruction logic looks sound, including divider/category adjacencyThe fuzzy‑search pipeline (
searchableMenuOptions→useFuse→filteredMenuOptions) correctly:
- Excludes
divider/categoryitems from search targets,- Matches by label, then rebuilds the menu in original order,
- Avoids leading/trailing dividers and collapses sequences so you never introduce multiple dividers between hits.
Since categories are skipped entirely when
queryis non‑empty, “divider + category + item” sequences in the original structured menu end up as at most a single divider before the first matching item, which answers the earlier question about adjacent dividers/categories.
226-253: DirectcssTextappend plus individual property sets
repositionPopoverupdatesoverlayEl.style.cssTextand then setstop/bottomindividually. This works but can be brittle (order/precedence) and makes it harder to reason about final styles; also, multiple style writes may cause additional layout/repaint work in some browsers. Consider computing a single style object and applying viaObject.assign(overlayEl.style, style)instead.
🧹 Nitpick comments (7)
src/components/graph/selectionToolbox/SubmenuPopover.vue (1)
89-125: Consider centralizing viewport-aware positioning with the shared utility
repositionSubmenumanually measures the overlay and docks it to the bottom of the viewport when it would overflow:const rect = overlayEl.getBoundingClientRect() const menuHeight = overlayEl.offsetHeight || overlayEl.scrollHeight const viewportHeight = window.innerHeight const menuBottom = rect.top + menuHeight const wouldOverflow = menuBottom > viewportHeight // ... overlayEl.style.position = 'fixed' overlayEl.style.bottom = '0px' overlayEl.style.top = ''This is very similar in intent to the new
calculateMenuPositionhelper you added for the main menu. To avoid drift between primary and submenu behavior (and duplicate reflow/measurement logic), it’s worth considering:
- Reusing
calculateMenuPositionhere by feeding it the submenu’s trigger rect and overlay element, or- Extracting the “dock to bottom” portion into a shared internal helper used by both.
Not urgent, but it would simplify future tweaks to overflow behavior.
src/components/graph/selectionToolbox/NodeOptions.vue (2)
76-81: Consider avoiding unused imports from@vueuse/core
breakpointsTailwind,useBreakpoints, anduseRafFnare used, but ifdebouncedRefis the only part needed for search, keep an eye that all imported symbols remain used after future refactors to avoid dead code bloat.
404-437: Search reset on show/hide is consistent, consider preserving query across brief hidesCurrently
searchQueryis cleared on bothonPopoverShowandonPopoverHide, so any transient hide (e.g. drag‑related auto‑close/restore) will always lose the query. If users often reopen the menu immediately, you might consider only clearing on true manual close, similar to howwasOpenBeforeHideis tracked.src/composables/graph/contextMenuConverter.ts (4)
23-72: Label‑driven classification is brittle under renames/localizationBoth
CORE_MENU_ITEMSandMENU_ORDERdepend on the human‑readablelabelstring (e.g.'Run Branch','Open Image') to classify and order items. This works now but is fragile if:
- Labels are localized, or
- LiteGraph/Vue options are renamed.
A more robust approach is to carry a stable identifier (e.g.
id: 'run-branch') onMenuOptionand baseCORE_MENU_ITEMS/MENU_ORDERon those ids rather than translated labels.
136-202:removeDuplicateMenuOptionspreserves ordering and Vue precedenceGrouping by
labeland choosing asource === 'vue'candidate when duplicates exist achieves the “Vue overrides LiteGraph” goal while:
- Keeping dividers/categories and unlabeled items in original order, and
- Avoiding label collisions from extension items without labels.
The two‑pass approach with
itemsWithoutLabelis a bit dense; a brief comment explaining the ordering intent would help future maintainers.
453-522: Dynamic submenu capture viaLiteGraph.ContextMenuoverride is reasonable but invasiveTemporarily replacing
LiteGraph.ContextMenuto intercept dynamic submenu construction, then restoring it in afinallyblock, is a pragmatic way to introspect items without rendering DOM. The mockContextMenureturns a minimal{ close, root }object, which should satisfy most callbacks.Given this is a global mutation, it’s important that:
- No other concurrent code depends on
LiteGraph.ContextMenuwhile a dynamic submenu is being captured, and- The target LiteGraph version doesn’t rely on special prototype behavior of
ContextMenuthat your function replacement would miss.If LiteGraph ever gains an official hook for submenu generation, migrating to that would reduce risk.
605-610: Static analysis XSS warning oninnerHTMLis a false positive in this context
stripHtmlTagsassigns totemp.innerHTMLon a detached element and only readstextContent/innerText, never inserting the element into the live DOM. That means scripts or event handlers inhtmlwill not execute, so this usage is safe against XSS.To avoid future confusion and linter noise, consider:
- Adding a comment explaining that the element is never attached to the DOM, or
- Swapping to
DOMParserfor HTML → text extraction if you want to eliminateinnerHTMLentirely.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
src/components/graph/selectionToolbox/MenuOptionItem.vue(3 hunks)src/components/graph/selectionToolbox/NodeOptions.vue(9 hunks)src/components/graph/selectionToolbox/SubmenuPopover.vue(4 hunks)src/composables/graph/contextMenuConverter.ts(1 hunks)src/composables/graph/useMoreOptionsMenu.ts(5 hunks)src/composables/graph/useNodeMenuOptions.ts(1 hunks)src/composables/graph/useViewportAwareMenuPositioning.ts(1 hunks)src/composables/useContextMenuTranslation.ts(2 hunks)src/locales/en/main.json(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
src/composables/graph/useMoreOptionsMenu.ts (5)
src/renderer/core/canvas/canvasStore.ts (1)
useCanvasStore(24-149)src/composables/graph/useImageMenuOptions.ts (1)
useImageMenuOptions(11-108)src/composables/graph/useNodeMenuOptions.ts (1)
useNodeMenuOptions(12-128)src/composables/graph/useGroupMenuOptions.ts (1)
useGroupMenuOptions(16-196)src/composables/graph/contextMenuConverter.ts (2)
convertContextMenuToOptions(358-447)buildStructuredMenu(253-349)
src/composables/graph/contextMenuConverter.ts (2)
src/composables/graph/useMoreOptionsMenu.ts (2)
MenuOption(18-29)SubMenuOption(31-37)src/lib/litegraph/src/litegraph.ts (1)
LiteGraph(17-17)
src/composables/useContextMenuTranslation.ts (2)
src/lib/litegraph/src/contextMenuCompat.ts (1)
legacyMenuCompat(148-148)src/lib/litegraph/src/interfaces.ts (1)
IContextMenuValue(405-426)
🪛 ast-grep (0.40.0)
src/composables/graph/contextMenuConverter.ts
[warning] 607-607: Direct HTML content assignment detected. Modifying innerHTML, outerHTML, or using document.write with unsanitized content can lead to XSS vulnerabilities. Use secure alternatives like textContent or sanitize HTML with libraries like DOMPurify.
Context: temp.innerHTML = html
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://www.dhairyashah.dev/posts/why-innerhtml-is-a-bad-idea-and-how-to-avoid-it/
- https://cwe.mitre.org/data/definitions/79.html
(unsafe-html-content-assignment)
[warning] 607-607: Direct modification of innerHTML or outerHTML properties detected. Modifying these properties with unsanitized user input can lead to XSS vulnerabilities. Use safe alternatives or sanitize content first.
Context: temp.innerHTML = html
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://owasp.org/www-community/xss-filter-evasion-cheatsheet
- https://cwe.mitre.org/data/definitions/79.html
(dom-content-modification)
⏰ 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: collect
- GitHub Check: setup
- GitHub Check: lint-and-format
🔇 Additional comments (17)
src/locales/en/main.json (1)
127-128: New translation keys look consistent and safe
g.noResultsandcontextMenu.Extensions/contextMenu.deprecatedfit existing naming and usage patterns; JSON structure is valid and compatible with current i18n usage.Also applies to: 431-433
src/composables/graph/useNodeMenuOptions.ts (1)
92-105: Bypass option icon change is isolated and correctOnly the icon for the bypass option changes; labels, shortcut (
Ctrl+B), and action logic remain intact. Safe UI-level adjustment.src/components/graph/selectionToolbox/MenuOptionItem.vue (1)
70-75: Defensive disabled guard inhandleClickis appropriateShort-circuiting
handleClickwhenprops.option.disabledis true matches the new disabled styling and protects against any future changes that might removepointer-events-nonefrom the row.src/components/graph/selectionToolbox/SubmenuPopover.vue (1)
31-46: Submenu disabled styling and click-guard are consistent and correctThe updated class composition for
subOptionrows plus thesubOption.disabledbranch gives you:
- Visual disabled state (
cursor-not-allowed, muted text).- Non-interactive behavior (pointer-events-none).
- A defensive guard in
handleSubmenuClickto prevent accidental emissions.This keeps submenu behavior aligned with the top‑level menu items.
Also applies to: 132-137
src/composables/useContextMenuTranslation.ts (1)
61-63: Node menu legacy/extension wiring matches the canvas patternInstalling
legacyMenuCompatforgetNodeMenuOptions, then wrapping it to:
- Append items from the new
app.collectNodeMenuItems(node)API, and- Append legacy monkey‑patched items from
legacyMenuCompat.extractLegacyItems('getNodeMenuOptions', ...),and finally registering the wrapper/original pair with
legacyMenuCompat.registerWrappermirrors the existing canvas‑menu integration and keeps all sources flowing through a single, composable hook point.The sequencing (install → capture original → wrap → register) looks correct and should preserve legacy behavior while enabling extensions.
Also applies to: 79-88, 94-101
src/components/graph/selectionToolbox/NodeOptions.vue (3)
111-117: Good separation of mobile vs desktop search focusUsing
useBreakpoints(breakpointsTailwind)andisMobileViewportto skip auto‑focus on small viewports nicely avoids pulling up the keyboard on mobile when the menu opens.
266-284: Guard against detached trigger element is a good additionThe
if (!el || !el.isConnected) return falsecheck inopenPopoverprevents trying to open against a stale DOM target during drag/move or unmount scenarios, which should avoid subtle positioning errors and exceptions.
321-349: Target‑switch behavior while open is well‑handledThe
togglelogic that switches the popover to a newtargetElwithout closing, bumps the options version, clears search, repositions, and re‑focuses the input (desktop only) gives a smooth experience when quickly right‑clicking different nodes.src/composables/graph/contextMenuConverter.ts (3)
78-122: Duplicate detection is conservative but acceptable
normalizeLabelplusequivalents(color/colors, pin/unpin, delete/remove, clone/duplicate) gives a reasonable duplicate filter while avoiding over‑eager merging. The logic short‑circuits on direct normalized match and only then checks equivalence groups, which is easy to reason about and should keep unrelated items (e.g. “Delete Selection”) distinct.
253-349: Structured core/extensions menu looks correct
buildStructuredMenu:
- Dedups first, then splits into core vs extension vs Delete,
- Orders core items using
MENU_ORDERand inserts a single divider between sections,- Adds an “Extensions” category label with a divider before it,
- Forces Delete/Remove (no submenu) to the bottom with a preceding divider.
This matches the described UX and should be stable as long as core labels remain consistent with those produced by Vue/LiteGraph.
527-599: Submenu conversion correctly propagates disabled state and strips HTML
convertSubmenuToOptions:
- Skips null separators,
- Handles both string items (calling
options.callbackwhen provided) and object items via theircallback,- Uses
stripHtmlTagsso labels from HTML‑styled content don’t leak markup into the Vue menu,- Propagates
disabledtoSubMenuOption.This is a solid bridge from LiteGraph submenu definitions to Vue submenus.
src/composables/graph/useMoreOptionsMenu.ts (6)
18-37: Type extensions align with converter/renderer changesAdding
type?: 'divider' | 'category',disabled?: boolean, andsource?: 'litegraph' | 'vue'toMenuOption, plusdisabled?: booleanonSubMenuOption, matches whatcontextMenuConverterand the menu components expect and should keep the types coherent across the pipeline.
85-96:markAsVueOptionscorrectly tags only actionable itemsThe helper skips
dividerandcategoryentries and clones other options withsource: 'vue'. This pairs cleanly withremoveDuplicateMenuOptions, which prefers Vue items over LiteGraph when de‑duplicating by label.
102-117: UsinguseCanvasStorefor LiteGraph integration is appropriatePulling
canvasStore.canvashere to accessgetNodeMenuOptionskeeps the LiteGraph dependency localized to this composable, instead of leaking it into UI components. That keeps NodeOptions.vue focused on rendering rather than data sourcing.
161-178: Single‑node LiteGraph menu merge path is sensibleThe block that, for a single node and no group context, calls
canvasStore.canvas.getNodeMenuOptions(node)and runsconvertContextMenuToOptions(rawItems, node, false)gives you raw LiteGraph options without structuring, which you then merge and structure once. The try/catch with logging prevents a bad extension from breaking the whole menu.
251-262: Merge + structuring flow achieves Vue‑over‑LiteGraph precedenceMerging with
const merged = [...litegraphOptions, ...markedVueOptions]and then callingbuildStructuredMenu(merged)ensures:
- LiteGraph contributes all its items,
- Vue items override LiteGraph ones with the same label (via
source: 'vue'),- The final menu is always ordered/sectioned consistently, regardless of which side supplied a given option.
The fallback path (no LiteGraph options) that structures only Vue options keeps behavior consistent across selection types.
265-276: FilteringmenuOptionsWithSubmenubyhasSubmenu && submenuis straightforwardThe computed
menuOptionsWithSubmenuremains aligned with the updatedMenuOptionshape and will naturally pick up submenus coming from either Vue or LiteGraph sources.
| // Section 1: Basic selection operations (Rename, Copy, Duplicate) | ||
| options.push(...getBasicSelectionOptions()) | ||
| const basicOps = getBasicSelectionOptions() | ||
| options.push(...basicOps) | ||
| options.push({ type: 'divider' }) | ||
|
|
||
| // Section 2: Node Info & Size Adjustment | ||
| if (nodeDef.value) { | ||
| options.push(getNodeInfoOption(showNodeHelp)) | ||
| // Section 2: Node actions (Run Branch, Pin, Bypass, Mute) | ||
| if (hasOutputNodesSelected.value) { | ||
| const runBranch = getRunBranchOption() | ||
| options.push(runBranch) | ||
| } | ||
|
|
||
| if (groupContext) { | ||
| options.push(getFitGroupToNodesOption(groupContext)) | ||
| } else { | ||
| options.push(getAdjustSizeOption()) | ||
| if (!groupContext) { | ||
| const pin = getPinOption(states, bump) | ||
| const bypass = getBypassOption(states, bump) | ||
| options.push(pin) | ||
| options.push(bypass) | ||
| } | ||
|
|
||
| // Section 3: Collapse/Shape/Color | ||
| if (groupContext) { | ||
| // Group context: Shape, Color, Divider | ||
| options.push(getGroupShapeOptions(groupContext, bump)) | ||
| options.push(getGroupColorOptions(groupContext, bump)) | ||
| options.push({ type: 'divider' }) | ||
| } else { | ||
| // Node context: Expand/Minimize, Shape, Color, Divider | ||
| options.push(...getNodeVisualOptions(states, bump)) | ||
| options.push({ type: 'divider' }) | ||
| const groupModes = getGroupModeOptions(groupContext, bump) | ||
| options.push(...groupModes) | ||
| } | ||
|
|
||
| // Section 4: Image operations (if image node) | ||
| if (hasImageNode.value && selectedNodes.value.length > 0) { | ||
| options.push(...getImageMenuOptions(selectedNodes.value[0])) | ||
| } | ||
|
|
||
| // Section 5: Subgraph operations | ||
| options.push(...getSubgraphOptions(hasSubgraphsSelected)) | ||
|
|
||
| // Section 6: Multiple nodes operations | ||
| if (hasMultipleNodes.value) { | ||
| options.push(...getMultipleNodesOptions()) | ||
| } | ||
|
|
||
| // Section 7: Divider | ||
| options.push({ type: 'divider' }) | ||
|
|
||
| // Section 8: Pin/Unpin (non-group only) | ||
| if (!groupContext) { | ||
| options.push(getPinOption(states, bump)) | ||
| } | ||
|
|
||
| // Section 9: Alignment (if multiple nodes) | ||
| // Section 3: Structure operations (Convert to Subgraph, Frame selection, Minimize Node) | ||
| const subgraphOps = getSubgraphOptions(hasSubgraphsSelected) | ||
| options.push(...subgraphOps) | ||
| if (hasMultipleNodes.value) { | ||
| options.push(...getAlignmentOptions()) | ||
| const multiOps = getMultipleNodesOptions() | ||
| options.push(...multiOps) | ||
| } | ||
|
|
||
| // Section 10: Mode operations | ||
| if (groupContext) { | ||
| // Group mode operations | ||
| options.push(...getGroupModeOptions(groupContext, bump)) | ||
| const fitGroup = getFitGroupToNodesOption(groupContext) | ||
| options.push(fitGroup) | ||
| } else { | ||
| // Bypass option for nodes | ||
| options.push(getBypassOption(states, bump)) | ||
| // Add minimize/expand option only | ||
| const visualOptions = getNodeVisualOptions(states, bump) | ||
| if (visualOptions.length > 0) { | ||
| options.push(visualOptions[0]) // Minimize/Expand | ||
| } | ||
| } | ||
| options.push({ type: 'divider' }) | ||
|
|
||
| // Section 11: Run Branch (if output nodes) | ||
| if (hasOutputNodesSelected.value) { | ||
| options.push(getRunBranchOption()) | ||
| // Section 4: Node properties (Node Info, Color) | ||
| if (nodeDef.value) { | ||
| const nodeInfo = getNodeInfoOption(showNodeHelp) | ||
| options.push(nodeInfo) | ||
| } | ||
| if (groupContext) { | ||
| const groupColor = getGroupColorOptions(groupContext, bump) | ||
| options.push(groupColor) | ||
| } else { | ||
| // Add shape and color options | ||
| const visualOptions = getNodeVisualOptions(states, bump) | ||
| if (visualOptions.length > 1) { | ||
| options.push(visualOptions[1]) // Shape (index 1) | ||
| } | ||
| if (visualOptions.length > 2) { | ||
| options.push(visualOptions[2]) // Color (index 2) | ||
| } | ||
| } | ||
|
|
||
| // Section 12: Final divider and Delete | ||
| options.push({ type: 'divider' }) | ||
| options.push(getDeleteOption()) | ||
|
|
||
| return options | ||
| // Section 5: Node-specific options (image operations) | ||
| if (hasImageNode.value && selectedNodes.value.length > 0) { | ||
| const imageOps = getImageMenuOptions(selectedNodes.value[0]) | ||
| options.push(...imageOps) | ||
| options.push({ type: 'divider' }) | ||
| } |
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.
🧩 Analysis chain
Vue sectioning is clear; watch for label mismatches with structuring rules
The manual sectioning (basic selection, node actions, structure, properties, image options) is neatly organized with explicit dividers. However, since buildStructuredMenu later reorders items based on label, a few things are worth double‑checking:
- The labels produced here (via
t('contextMenu.*')) must match the raw labels inCORE_MENU_ITEMS/MENU_ORDER(e.g.'Open Image','Copy Image'). - In particular,
useImageMenuOptionsusest('contextMenu.Open in Mask Editor')whileCORE_MENU_ITEMScontains'Open in MaskEditor'(no space). If the rendered label includes the space, it won’t be treated as a core item and will fall under Extensions instead of the intended section.
Consider standardizing labels (or, better, switching to stable ids as noted in the converter comment) to ensure structuring behaves as designed.
I'll verify the label mismatch concerns by examining the relevant code files.Now let me search for the specific files and functions mentioned in the review:
🏁 Script executed:
#!/bin/bash
# Find the files and functions mentioned in the review
echo "=== Searching for useImageMenuOptions ==="
rg -n "useImageMenuOptions|getImageMenuOptions" --type ts
echo -e "\n=== Searching for CORE_MENU_ITEMS and MENU_ORDER ==="
rg -n "CORE_MENU_ITEMS|MENU_ORDER" --type ts
echo -e "\n=== Searching for buildStructuredMenu ==="
rg -n "buildStructuredMenu" --type ts
echo -e "\n=== Searching for 'Open in Mask' or 'Open in MaskEditor' ==="
rg -n "Open in M" --type tsLength of output: 2508
Now let me examine the actual content of these key files:
🏁 Script executed:
#!/bin/bash
# Examine the relevant sections of contextMenuConverter.ts
echo "=== CORE_MENU_ITEMS definition (contextMenuConverter.ts around line 23) ==="
sed -n '23,80p' git/src/composables/graph/contextMenuConverter.ts
echo -e "\n=== MENU_ORDER definition (contextMenuConverter.ts around line 207) ==="
sed -n '207,250p' git/src/composables/graph/contextMenuConverter.ts
echo -e "\n=== buildStructuredMenu function (contextMenuConverter.ts around line 253) ==="
sed -n '253,300p' git/src/composables/graph/contextMenuConverter.ts
echo -e "\n=== useImageMenuOptions.ts around line 84 ==="
sed -n '75,95p' git/src/composables/graph/useImageMenuOptions.tsLength of output: 646
Let me re-run with the repository cloned:
🏁 Script executed:
#!/bin/bash
# Examine the relevant sections of contextMenuConverter.ts
echo "=== CORE_MENU_ITEMS definition (contextMenuConverter.ts around line 23) ==="
sed -n '23,80p' src/composables/graph/contextMenuConverter.ts
echo -e "\n=== MENU_ORDER definition (contextMenuConverter.ts around line 207) ==="
sed -n '207,250p' src/composables/graph/contextMenuConverter.ts
echo -e "\n=== buildStructuredMenu function (contextMenuConverter.ts around line 253) ==="
sed -n '253,310p' src/composables/graph/contextMenuConverter.ts
echo -e "\n=== useImageMenuOptions.ts around line 84 ==="
sed -n '75,95p' src/composables/graph/useImageMenuOptions.ts
echo -e "\n=== Check how translation keys are used in useImageMenuOptions ==="
sed -n '70,110p' src/composables/graph/useImageMenuOptions.tsLength of output: 5978
Fix label mismatch in "Open in Mask Editor" option
The translation key t('contextMenu.Open in Mask Editor') at useImageMenuOptions.ts:84 produces a label with a space, but CORE_MENU_ITEMS and MENU_ORDER in contextMenuConverter.ts define it as 'Open in MaskEditor' without a space. Since buildStructuredMenu matches labels against these constants using exact string comparison, this option will be incorrectly categorized as an Extension instead of a Core item and placed in the wrong menu section.
Align the label by either:
- Changing the translation key to
'contextMenu.Open in MaskEditor'(no space), or - Updating
CORE_MENU_ITEMSandMENU_ORDERto'Open in Mask Editor'(with space)
| export function calculateMenuPosition( | ||
| options: MenuPositionOptions | ||
| ): MenuPositionStyle { | ||
| const { | ||
| triggerRect, | ||
| menuElement, | ||
| isTriggeredByToolbox, | ||
| marginY = 8 | ||
| } = options | ||
|
|
||
| // Calculate horizontal position (same as before) | ||
| const left = isTriggeredByToolbox | ||
| ? triggerRect.left + triggerRect.width / 2 | ||
| : triggerRect.right - triggerRect.width / 4 | ||
|
|
||
| // Calculate initial top position | ||
| const initialTop = isTriggeredByToolbox | ||
| ? triggerRect.bottom + marginY | ||
| : triggerRect.top - marginY - 6 | ||
|
|
||
| // Get menu dimensions | ||
| const menuHeight = menuElement.offsetHeight || menuElement.scrollHeight | ||
| const viewportHeight = window.innerHeight | ||
|
|
||
| // Calculate available space below the trigger point | ||
| const spaceBelow = viewportHeight - initialTop | ||
|
|
||
| // Check if menu would overflow viewport bottom | ||
| const wouldOverflow = menuHeight > spaceBelow | ||
|
|
||
| const baseStyle: MenuPositionStyle = { | ||
| position: 'fixed', | ||
| left: `${left}px`, | ||
| transform: 'translate(-50%, 0)' | ||
| } | ||
|
|
||
| if (triggerRect.top < 0) { | ||
| // Dock to top of viewport if node is above | ||
| return { | ||
| ...baseStyle, | ||
| top: '0px' | ||
| } | ||
| } else if (wouldOverflow) { | ||
| // Dock to bottom of viewport | ||
| return { | ||
| ...baseStyle, | ||
| bottom: '0px' | ||
| } | ||
| } else { | ||
| // Position below trigger as normal | ||
| return { | ||
| ...baseStyle, | ||
| top: `${initialTop}px` | ||
| } | ||
| } |
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.
Clamp menus that would render partially above the viewport
The vertical logic handles “node above viewport” via triggerRect.top < 0 and bottom overflow via wouldOverflow, but there’s an edge case when the trigger is near the top for non-toolbox menus:
const initialTop = isTriggeredByToolbox
? triggerRect.bottom + marginY
: triggerRect.top - marginY - 6For small positive triggerRect.top, initialTop can become negative even though triggerRect.top >= 0, so the menu can be positioned partly off-screen at the top.
You can clamp based on initialTop instead to keep the menu fully visible:
- if (triggerRect.top < 0) {
+ if (initialTop < 0) {
// Dock to top of viewport if node is above
return {
...baseStyle,
top: '0px'
}
} else if (wouldOverflow) {This still covers the “node is above the viewport” case while also fixing near‑top triggers.
🤖 Prompt for AI Agents
In src/composables/graph/useViewportAwareMenuPositioning.ts around lines 26-80,
the menu can still be positioned partly off-screen near the top because
initialTop can be negative even when triggerRect.top >= 0; replace the current
triggerRect.top check with logic that clamps initialTop: compute initialTop as
before, set clampedTop = Math.max(0, initialTop), use clampedTop for
spaceBelow/wouldOverflow calculations and return top: `${clampedTop}px` when not
docking to bottom, and treat initialTop < 0 (or clampedTop === 0) as the “dock
to top” case so menus never render above the viewport.
…pe definitions and method signatures.
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 (1)
src/components/graph/selectionToolbox/NodeOptions.vue (1)
27-55: Search/filter behavior looks solid; reconsider Escape handling with PopoverThe search pipeline (
searchQuery→ debounced Fuse oversearchableMenuOptions→filteredMenuOptions) correctly:
- hides dividers and categories while filtering,
- preserves divider structure only where matched items remain, and
- exposes an empty state only when no actionable items match.
One thing to double‑check: with
@keydown.escape="clearSearch"onSearchBoxand:close-on-escape="true"on<Popover>, pressing Escape will clear the query and still close the menu, so the clear is effectively redundant and you can’t get “Escape clears first, closes on second press”. If the intended UX is “Escape clears while there’s text, otherwise closes the menu”, you’ll need to either:
- accept the
KeyboardEventinclearSearchand callevent.stopPropagation()whensearchQueryis non‑empty, or- use
.stopin the template and conditionally re‑emit only when the query is already empty.Also applies to: 81-184, 399-402, 403-416
🧹 Nitpick comments (2)
src/lib/litegraph/src/LGraphCanvas.ts (1)
711-715: Null‑aware menu typings look correct; ensure implementers handlenullentriesUpdating
getExtraMenuOptionsandgetCanvasMenuOptionsto use(IContextMenuValue | null)[]matches the actual usage ofnullas dividers in menu arrays and lines up with the compat layer. Just make sure any customgetExtraMenuOptionsimplementations and downstream consumers treat entries as nullable (skip or filter them) rather than assuming every item is a real option.Also applies to: 8012-8048
src/components/graph/selectionToolbox/NodeOptions.vue (1)
190-257: Avoid appending tostyle.cssTextevery frame inrepositionPopover
repositionPopovercurrently updates the overlay via:overlayEl.style.cssText += `; left: ${style.left}; position: ${style.position}; transform: ${style.transform};`and runs on every RAF tick while open. This continually grows the inline style string and does unnecessary work; it’s safer and cheaper to assign properties directly, e.g.:
overlayEl.style.position = style.position overlayEl.style.left = style.left overlayEl.style.transform = style.transformkeeping the existing explicit
top/bottomassignments as‑is. That avoids unboundedcssTextgrowth and makes future overrides easier to reason about.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/components/graph/selectionToolbox/MenuOptionItem.vue(3 hunks)src/components/graph/selectionToolbox/NodeOptions.vue(9 hunks)src/components/input/SearchBox.vue(1 hunks)src/composables/useContextMenuTranslation.ts(3 hunks)src/lib/litegraph/src/LGraphCanvas.ts(2 hunks)src/lib/litegraph/src/contextMenuCompat.ts(5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/components/graph/selectionToolbox/MenuOptionItem.vue
🧰 Additional context used
🧬 Code graph analysis (3)
src/lib/litegraph/src/LGraphCanvas.ts (1)
src/lib/litegraph/src/interfaces.ts (1)
IContextMenuValue(405-426)
src/lib/litegraph/src/contextMenuCompat.ts (2)
src/lib/litegraph/src/interfaces.ts (1)
IContextMenuValue(405-426)src/lib/litegraph/src/LGraphCanvas.ts (1)
LGraphCanvas(251-8596)
src/composables/useContextMenuTranslation.ts (3)
src/lib/litegraph/src/interfaces.ts (1)
IContextMenuValue(405-426)src/lib/litegraph/src/LGraphCanvas.ts (3)
getCanvasMenuOptions(8012-8048)LGraphCanvas(251-8596)item(3492-3508)src/lib/litegraph/src/contextMenuCompat.ts (1)
legacyMenuCompat(164-164)
⏰ 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: lint-and-format
- GitHub Check: test
- GitHub Check: collect
🔇 Additional comments (6)
src/components/input/SearchBox.vue (1)
65-70: ExposingfocusInputfor parent control is appropriate here
focusInputsafely guards the InputText ref and exposing it viadefineExposegives callers (e.g.NodeOptions.vue) a clean way to focus the field without leaking internals.Also applies to: 94-96
src/composables/useContextMenuTranslation.ts (1)
25-28: Node/canvas menu wrappers correctly merge extension and legacy itemsThe updated wrappers for
getCanvasMenuOptions/getNodeMenuOptionscleanly:
- call the original implementation,
- append new extension items (
collectCanvasMenuItems/collectNodeMenuItems),- then append legacy monkey‑patched items via
legacyMenuCompat.extractLegacyItems(...),
all under a unified(IContextMenuValue | null)[]return type. This preserves legacy behavior while enabling the new extension API and keepstranslateMenus’ expectations intact.Also applies to: 64-66, 73-91, 97-102
src/lib/litegraph/src/contextMenuCompat.ts (4)
10-12: Type signature correctly updated to support nullable menu items.The change from
IContextMenuValue[]to(IContextMenuValue | null)[]aligns with the broader API updates in LGraphCanvas that now support nullable menu items.
65-99: Installation logic correctly tracks monkey-patching with deprecation warnings.The method properly:
- Stores the original method
- Uses a property setter to detect monkey-patching
- Issues deprecation warnings with extension identification
- Maintains a set to avoid duplicate warnings
Note: The same type safety concerns from lines 48-55 apply to the casting at lines 72-75.
48-55: Type safety is lost through double casting; no signature validation exists.The pattern
as unknown as ContextMenuValueProvider(lines 50, 54) completely bypasses TypeScript's type checking. While this may be necessary for the compatibility layer to work with Map storage, there is no runtime signature validation. When methods are retrieved and invoked at line 143 (methodToCall.apply(context, args)), there are only identity checks (e.g.,currentMethod === registeredWrapper) but no verification that the method actually matches theContextMenuValueProvidersignature. If a caller registers a method with an incompatible signature, the code will fail at runtime without error handling.Add signature validation in
registerWrapperto verify that the provided method returns the expected type, or add a try-catch around the.apply()invocation at line 143 to gracefully handle signature mismatches.
112-161: No issues found—null entries are safely handled downstream.The
extractLegacyItemscall sites inuseContextMenuTranslation.tspush returned items (including nulls) into theresarray. Later iteration safely accesses properties using optional chaining:if (item?.content) { item.content = ... }. This pattern correctly handles null values without errors.
| if (patchedItems.length > originalItems.length) { | ||
| return patchedItems.slice(originalItems.length) as IContextMenuValue[] | ||
| return patchedItems.slice( | ||
| originalItems.length | ||
| ) as (IContextMenuValue | null)[] | ||
| } |
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.
Length-based comparison for detecting added items is fragile.
The logic at line 148 assumes monkey patches only append items to the end of the array. If a legacy patch:
- Removes items:
originalItems.lengthcould be >=patchedItems.length, returning empty array - Reorders items: The slice would return the wrong items
- Replaces items: The diff count would be wrong
This could cause legacy menu items to be missed or incorrectly extracted.
Consider one of these approaches:
- Set-based diffing: Compare items by identity/reference to find genuinely added items
- Documentation: Clearly document that this compatibility layer only supports patches that append items
- Validation: Add a warning when
patchedItems.length < originalItems.lengthto detect removals
Example of set-based diffing:
- if (patchedItems.length > originalItems.length) {
- return patchedItems.slice(
- originalItems.length
- ) as (IContextMenuValue | null)[]
- }
+ // Find items in patchedItems that aren't in originalItems by reference
+ const originalSet = new Set(originalItems)
+ const addedItems = patchedItems.filter(item => !originalSet.has(item))
+ return addedItems🤖 Prompt for AI Agents
In src/lib/litegraph/src/contextMenuCompat.ts around lines 148-152 the current
length-based check to detect added menu items is fragile (it assumes patches
only append items); replace this with a set-based diff: build a Set of
originalItems (by reference or a stable identifier) and return items from
patchedItems that are not in that Set to reliably detect additions regardless of
reorders or replacements; also add validation/logging to warn (or handle) when
patchedItems.length < originalItems.length to detect removals and avoid silent
failures, and document the behavior in a short comment above the function.
- Create NodeContextMenu.vue using pure PrimeVue ContextMenu - Remove custom positioning logic, let PrimeVue handle it - Delete NodeOptions.vue and MenuOptionItem.vue - Mount NodeContextMenu in SelectionToolbox - Update test stubs
- Rename SubmenuPopover.vue to ColorPickerMenu.vue - Add isColorPicker prop to MenuOption interface - Use isColorPicker flag instead of checking submenu colors - Fix onClickOutside immediate close with ignore option
- Delete useSubmenuPositioning.ts (no longer used) - Delete useViewportAwareMenuPositioning.ts (no longer used) - Remove unused exports from useSelectionToolboxPosition.ts
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
🧹 Nitpick comments (5)
src/composables/canvas/useSelectionToolboxPosition.ts (1)
23-23: Consider updating comment to reflect internal scope.The comment describes these as "Shared signals" but they're now module-private. Consider rewording to "Internal signals" or "Module-scoped signals" for clarity.
-// Shared signals for auxiliary UI (e.g., MoreOptions) to coordinate hide/restore +// Internal signals for auxiliary UI (e.g., MoreOptions) to coordinate hide/restoresrc/components/graph/NodeContextMenu.vue (2)
4-18: Add keyboard accessibility to the custom menu item anchor.The custom anchor element lacks keyboard accessibility attributes. Users navigating via keyboard won't be able to interact with color submenu items properly.
Consider adding
role="menuitem"and keyboard event handling:<a v-bind="props.action" class="flex items-center gap-2 px-3 py-1.5" + role="menuitem" @click="item.isColorSubmenu ? showColorPopover($event) : undefined" + @keydown.enter="item.isColorSubmenu ? showColorPopover($event) : undefined" >
126-136: Type assertionas MouseEventmay be unsafe.The
togglefunction accepts a genericEventbut casts it toMouseEventwhen callingshow(). Iftoggleis called with a keyboard event (e.g., Enter key), the cast would be incorrect and could cause issues withcontextMenu.value?.show(event)if it relies on mouse-specific properties.Consider handling both event types:
function toggle( event: Event, _element?: HTMLElement, _clickedFromToolbox?: boolean ) { if (isOpen.value) { hide() } else { - show(event as MouseEvent) + if (event instanceof MouseEvent) { + show(event) + } else { + // For keyboard events, show at a default position or use the target element + const target = event.target as HTMLElement + const rect = target.getBoundingClientRect() + const syntheticEvent = new MouseEvent('contextmenu', { + clientX: rect.left, + clientY: rect.bottom + }) + show(syntheticEvent) + } } }src/components/graph/selectionToolbox/ColorPickerMenu.vue (1)
84-95: Consider viewport boundary checking for the positioned menu.The
showToRightfunction positions the menu to the right of the target element but doesn't check if the menu would overflow the viewport. Per the PR objectives, viewport-aware positioning was introduced to prevent overflow.Consider adding viewport boundary checks:
const showToRight = (target: HTMLElement) => { const rect = target.getBoundingClientRect() + const menuWidth = 200 // Approximate menu width, or measure after render + const viewportWidth = window.innerWidth + + let left = rect.right + 4 + // If menu would overflow right edge, position to the left of target + if (left + menuWidth > viewportWidth) { + left = rect.left - menuWidth - 4 + } + position.value = { top: rect.top, - left: rect.right + 4 + left } isVisible.value = true justOpened = true setTimeout(() => { justOpened = false }, 0) }src/composables/graph/useMoreOptionsMenu.ts (1)
183-250: Section assembly is coherent; consider avoiding duplicate getNodeVisualOptions callsThe restructuring into explicit sections (basic selection, node/group actions, structure, properties, image) reads clearly and composes well with
buildStructuredMenu. Guards forgroupContext,hasMultipleNodes,hasImageNode, andhasOutputNodesSelectedkeep the menu context‑sensitive.One small cleanup:
getNodeVisualOptions(states, bump)is called twice when!groupContext(once for the Minimize/Expand entry and once for Shape/Color). You can compute it once and reuse to avoid duplicated work and keep the mapping between indices and semantics in one place:- if (groupContext) { - const fitGroup = getFitGroupToNodesOption(groupContext) - options.push(fitGroup) - } else { - // Add minimize/expand option only - const visualOptions = getNodeVisualOptions(states, bump) - if (visualOptions.length > 0) { - options.push(visualOptions[0]) // Minimize/Expand - } - } + let visualOptions: MenuOption[] = [] + if (groupContext) { + const fitGroup = getFitGroupToNodesOption(groupContext) + options.push(fitGroup) + } else { + // Add minimize/expand option only + visualOptions = getNodeVisualOptions(states, bump) + if (visualOptions.length > 0) { + options.push(visualOptions[0]) // Minimize/Expand + } + } @@ - if (groupContext) { + if (groupContext) { const groupColor = getGroupColorOptions(groupContext, bump) options.push(groupColor) } else { // Add shape and color options - const visualOptions = getNodeVisualOptions(states, bump) if (visualOptions.length > 1) { options.push(visualOptions[1]) // Shape (index 1) } if (visualOptions.length > 2) { options.push(visualOptions[2]) // Color (index 2) } }Purely an ergonomics/readability improvement; behavior stays the same.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
src/components/graph/GraphCanvas.vue(0 hunks)src/components/graph/NodeContextMenu.vue(1 hunks)src/components/graph/SelectionToolbox.test.ts(1 hunks)src/components/graph/SelectionToolbox.vue(2 hunks)src/components/graph/selectionToolbox/ColorPickerMenu.vue(4 hunks)src/components/graph/selectionToolbox/MenuOptionItem.vue(0 hunks)src/components/graph/selectionToolbox/NodeOptions.vue(0 hunks)src/composables/canvas/useSelectionToolboxPosition.ts(1 hunks)src/composables/graph/useMoreOptionsMenu.ts(5 hunks)src/composables/graph/useNodeMenuOptions.ts(2 hunks)src/composables/graph/useSubmenuPositioning.ts(0 hunks)
💤 Files with no reviewable changes (4)
- src/components/graph/GraphCanvas.vue
- src/composables/graph/useSubmenuPositioning.ts
- src/components/graph/selectionToolbox/NodeOptions.vue
- src/components/graph/selectionToolbox/MenuOptionItem.vue
🧰 Additional context used
📓 Path-based instructions (21)
**/*.{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.json
Files:
src/components/graph/SelectionToolbox.test.tssrc/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/composables/canvas/useSelectionToolboxPosition.tssrc/components/graph/SelectionToolbox.vuesrc/composables/graph/useMoreOptionsMenu.tssrc/components/graph/NodeContextMenu.vuesrc/composables/graph/useNodeMenuOptions.ts
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursorrules)
Use es-toolkit for utility functions
Files:
src/components/graph/SelectionToolbox.test.tssrc/composables/canvas/useSelectionToolboxPosition.tssrc/composables/graph/useMoreOptionsMenu.tssrc/composables/graph/useNodeMenuOptions.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 issue
Files:
src/components/graph/SelectionToolbox.test.tssrc/composables/canvas/useSelectionToolboxPosition.tssrc/composables/graph/useMoreOptionsMenu.tssrc/composables/graph/useNodeMenuOptions.ts
**/*.{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 committing
Files:
src/components/graph/SelectionToolbox.test.tssrc/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/composables/canvas/useSelectionToolboxPosition.tssrc/components/graph/SelectionToolbox.vuesrc/composables/graph/useMoreOptionsMenu.tssrc/components/graph/NodeContextMenu.vuesrc/composables/graph/useNodeMenuOptions.ts
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/components/graph/SelectionToolbox.test.tssrc/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/composables/canvas/useSelectionToolboxPosition.tssrc/components/graph/SelectionToolbox.vuesrc/composables/graph/useMoreOptionsMenu.tssrc/components/graph/NodeContextMenu.vuesrc/composables/graph/useNodeMenuOptions.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/components/graph/SelectionToolbox.test.tssrc/composables/canvas/useSelectionToolboxPosition.tssrc/composables/graph/useMoreOptionsMenu.tssrc/composables/graph/useNodeMenuOptions.ts
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use camelCase for variable and setting names in TypeScript/Vue files
Files:
src/components/graph/SelectionToolbox.test.tssrc/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/composables/canvas/useSelectionToolboxPosition.tssrc/components/graph/SelectionToolbox.vuesrc/composables/graph/useMoreOptionsMenu.tssrc/components/graph/NodeContextMenu.vuesrc/composables/graph/useNodeMenuOptions.ts
**/*.{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/components/graph/SelectionToolbox.test.tssrc/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/composables/canvas/useSelectionToolboxPosition.tssrc/components/graph/SelectionToolbox.vuesrc/composables/graph/useMoreOptionsMenu.tssrc/components/graph/NodeContextMenu.vuesrc/composables/graph/useNodeMenuOptions.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 configuration
Files:
src/components/graph/SelectionToolbox.test.tssrc/composables/canvas/useSelectionToolboxPosition.tssrc/composables/graph/useMoreOptionsMenu.tssrc/composables/graph/useNodeMenuOptions.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/components/graph/SelectionToolbox.test.tssrc/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/composables/canvas/useSelectionToolboxPosition.tssrc/components/graph/SelectionToolbox.vuesrc/composables/graph/useMoreOptionsMenu.tssrc/components/graph/NodeContextMenu.vuesrc/composables/graph/useNodeMenuOptions.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/components/graph/SelectionToolbox.test.tssrc/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/composables/canvas/useSelectionToolboxPosition.tssrc/components/graph/SelectionToolbox.vuesrc/composables/graph/useMoreOptionsMenu.tssrc/components/graph/NodeContextMenu.vuesrc/composables/graph/useNodeMenuOptions.ts
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/components/graph/SelectionToolbox.test.tssrc/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/composables/canvas/useSelectionToolboxPosition.tssrc/components/graph/SelectionToolbox.vuesrc/composables/graph/useMoreOptionsMenu.tssrc/components/graph/NodeContextMenu.vuesrc/composables/graph/useNodeMenuOptions.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/components/graph/SelectionToolbox.test.tssrc/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/composables/canvas/useSelectionToolboxPosition.tssrc/components/graph/SelectionToolbox.vuesrc/composables/graph/useMoreOptionsMenu.tssrc/components/graph/NodeContextMenu.vuesrc/composables/graph/useNodeMenuOptions.ts
src/components/**/*.{vue,ts,js}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings
Files:
src/components/graph/SelectionToolbox.test.tssrc/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/components/graph/SelectionToolbox.vuesrc/components/graph/NodeContextMenu.vue
**/*.{test,spec}.{ts,tsx,js}
📄 CodeRabbit inference engine (AGENTS.md)
Unit and component tests should be located in
tests-ui/or co-located with components assrc/components/**/*.{test,spec}.ts; E2E tests should be inbrowser_tests/
Files:
src/components/graph/SelectionToolbox.test.ts
**/*.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/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/components/graph/SelectionToolbox.vuesrc/components/graph/NodeContextMenu.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/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/components/graph/SelectionToolbox.vuesrc/components/graph/NodeContextMenu.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/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/components/graph/SelectionToolbox.vuesrc/components/graph/NodeContextMenu.vuesrc/components/**/*.vue
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue componentsFiles:
src/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/components/graph/SelectionToolbox.vuesrc/components/graph/NodeContextMenu.vuesrc/components/**/*.{vue,css}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system packageFiles:
src/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/components/graph/SelectionToolbox.vuesrc/components/graph/NodeContextMenu.vuesrc/**/{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/composables/canvas/useSelectionToolboxPosition.tssrc/composables/graph/useMoreOptionsMenu.tssrc/composables/graph/useNodeMenuOptions.ts🧠 Learnings (25)
📓 Common learnings
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 PopoverLearnt 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 TabMenu component with Tabs without panelsLearnt 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 SelectLearnt 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 Sidebar component with DrawerLearnt 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 respectivelyLearnt 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)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 InlineMessage component with MessageLearnt 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: src/components/CLAUDE.md:0-0 Timestamp: 2025-11-24T19:47:45.616Z Learning: Applies to src/components/**/*.vue : Replace PrimeVue Calendar component with DatePickerLearnt 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📚 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 setupApplied to files:
src/components/graph/SelectionToolbox.test.tssrc/composables/graph/useMoreOptionsMenu.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 testsApplied to files:
src/components/graph/SelectionToolbox.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 featuresApplied to files:
src/components/graph/SelectionToolbox.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}.{js,ts,jsx,tsx} : When adding features, always write vitest unit tests using cursor rules in @.cursorApplied to files:
src/components/graph/SelectionToolbox.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} : When writing tests for subgraph-related code, always import from the barrel export at `@/lib/litegraph/src/litegraph` to avoid circular dependency issuesApplied to files:
src/components/graph/SelectionToolbox.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 utilitiesApplied to files:
src/components/graph/SelectionToolbox.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 OverlayPanel component with PopoverApplied to files:
src/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/components/graph/NodeContextMenu.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/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/composables/graph/useMoreOptionsMenu.tssrc/components/graph/NodeContextMenu.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/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/components/graph/NodeContextMenu.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 TabMenu component with Tabs without panelsApplied to files:
src/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/composables/graph/useMoreOptionsMenu.tssrc/components/graph/NodeContextMenu.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/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/components/graph/NodeContextMenu.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 InputSwitch component with ToggleSwitchApplied to files:
src/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/components/graph/NodeContextMenu.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 Sidebar component with DrawerApplied to files:
src/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/components/graph/NodeContextMenu.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/components/graph/selectionToolbox/ColorPickerMenu.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 InlineMessage component with MessageApplied to files:
src/components/graph/selectionToolbox/ColorPickerMenu.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 Chips component with AutoComplete with multiple enabledApplied to files:
src/components/graph/selectionToolbox/ColorPickerMenu.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 existing VueUse composables (such as useElementHover) instead of manually managing event listenersApplied to files:
src/components/graph/selectionToolbox/ColorPickerMenu.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 **/*.{ts,tsx,vue} : Use `const settingStore = useSettingStore()` and `settingStore.get('Comfy.SomeSetting')` to retrieve settings in TypeScript/Vue filesApplied to files:
src/components/graph/SelectionToolbox.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/**/*.{vue,ts,tsx} : Follow Vue 3 composition API style guideApplied to files:
src/composables/graph/useMoreOptionsMenu.tssrc/components/graph/NodeContextMenu.vue📚 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} : Take advantage of `TypedArray` `subarray` when appropriateApplied to files:
src/composables/graph/useMoreOptionsMenu.ts📚 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/composables/graph/useMoreOptionsMenu.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 stylesApplied to files:
src/composables/graph/useMoreOptionsMenu.ts📚 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/composables/graph/useMoreOptionsMenu.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 : Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)Applied to files:
src/components/graph/NodeContextMenu.vue🧬 Code graph analysis (1)
src/composables/graph/useMoreOptionsMenu.ts (5)
src/renderer/core/canvas/canvasStore.ts (1)
useCanvasStore(24-152)src/composables/graph/useImageMenuOptions.ts (1)
useImageMenuOptions(11-108)src/composables/graph/useNodeMenuOptions.ts (1)
useNodeMenuOptions(12-129)src/composables/graph/useGroupMenuOptions.ts (1)
useGroupMenuOptions(16-196)src/composables/graph/contextMenuConverter.ts (2)
convertContextMenuToOptions(358-447)buildStructuredMenu(253-349)🪛 ESLint
src/components/graph/selectionToolbox/ColorPickerMenu.vue
[error] 51-51: Unable to resolve path to module '@comfyorg/tailwind-utils'.
(import-x/no-unresolved)
[error] 52-52: Unable to resolve path to module '@vueuse/core'.
(import-x/no-unresolved)
src/components/graph/SelectionToolbox.vue
[error] 72-72: Unable to resolve path to module './NodeContextMenu.vue'.
(import-x/no-unresolved)
src/composables/graph/useMoreOptionsMenu.ts
[error] 5-5: Unable to resolve path to module '@/renderer/core/canvas/canvasStore'.
(import-x/no-unresolved)
[error] 6-6: Unable to resolve path to module '@/utils/litegraphUtil'.
(import-x/no-unresolved)
[error] 11-11: Unable to resolve path to module './contextMenuConverter'.
(import-x/no-unresolved)
src/components/graph/NodeContextMenu.vue
[error] 1-1: Resolve error: EACCES: permission denied, open '/saEQzionsM'
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 '/bOzMFyGRnd'
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 '/socnuAABhC'
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 checkDefault (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/default.js:22:39)
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/default)
[error] 1-1: Resolve error: EACCES: permission denied, open '/IUYggMyLaY'
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] 1-1: Resolve error: EACCES: permission denied, open '/ZppeldVgLu'
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 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-useless-path-segments.js:58: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-useless-path-segments)
[error] 32-32: Unable to resolve path to module 'primevue/contextmenu'.
(import-x/no-unresolved)
[error] 34-34: Unable to resolve path to module 'vue'.
(import-x/no-unresolved)
[error] 39-39: Unable to resolve path to module '@/composables/graph/useMoreOptionsMenu'.
(import-x/no-unresolved)
[error] 45-45: Unable to resolve path to module './selectionToolbox/ColorPickerMenu.vue'.
(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
…e in ColorPickerMenu
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 (1)
src/components/graph/selectionToolbox/ColorPickerMenu.vue (1)
24-27: Remove duplicate hover class.Line 26 contains
hover:bg-secondary-background-hoverwhich is already applied on line 20, making it redundant.Apply this diff:
subOption.disabled ? 'cursor-not-allowed pointer-events-none text-node-icon-disabled' - : 'hover:bg-secondary-background-hover' + : ''Note: The
dark-theme:variant usage on line 26 was already flagged in a previous review.
🧹 Nitpick comments (1)
src/components/graph/selectionToolbox/ColorPickerMenu.vue (1)
109-120: Consider more maintainable ignore selectors.The ignore selectors rely on hardcoded PrimeVue internal class names (
.p-contextmenu,.p-contextmenu-item-link). If PrimeVue changes these class names in a future version, the click-outside behavior will break.Consider using data attributes or template refs for more maintainable ignore logic:
// Option 1: Pass parent context menu ref as prop onClickOutside( popoverRef, () => { if (justOpened) { justOpened = false return } hide() }, { ignore: [props.parentMenuRef] } ) // Option 2: Use data attribute selectors { ignore: ['[data-context-menu]', '[data-context-menu-item]'] }Then add the corresponding data attributes to the parent ContextMenu component's template.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/components/graph/selectionToolbox/ColorPickerMenu.vue(4 hunks)
🧰 Additional context used
📓 Path-based instructions (15)
**/*.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/components/graph/selectionToolbox/ColorPickerMenu.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/components/graph/selectionToolbox/ColorPickerMenu.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/components/graph/selectionToolbox/ColorPickerMenu.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/components/graph/selectionToolbox/ColorPickerMenu.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/components/graph/selectionToolbox/ColorPickerMenu.vue**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use camelCase for variable and setting names in TypeScript/Vue files
Files:
src/components/graph/selectionToolbox/ColorPickerMenu.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/components/graph/selectionToolbox/ColorPickerMenu.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/components/graph/selectionToolbox/ColorPickerMenu.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/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/**/{composables,components}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Clean up subscriptions in state management to prevent memory leaks
Files:
src/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/components/graph/selectionToolbox/ColorPickerMenu.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/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/components/**/*.vue
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue componentsFiles:
src/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/components/**/*.{vue,css}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system packageFiles:
src/components/graph/selectionToolbox/ColorPickerMenu.vuesrc/components/**/*.{vue,ts,js}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI stringsFiles:
src/components/graph/selectionToolbox/ColorPickerMenu.vue🧠 Learnings (17)
📓 Common learnings
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 PopoverLearnt 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 respectivelyLearnt 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 SelectLearnt 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 TabMenu component with Tabs without panelsLearnt 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)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 Sidebar component with DrawerLearnt 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: src/components/CLAUDE.md:0-0 Timestamp: 2025-11-24T19:47:45.616Z Learning: Applies to src/components/**/*.vue : Replace PrimeVue Calendar component with DatePickerLearnt 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 InlineMessage component with MessageLearnt 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 Chips component with AutoComplete with multiple enabled📚 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/components/graph/selectionToolbox/ColorPickerMenu.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/components/graph/selectionToolbox/ColorPickerMenu.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/components/graph/selectionToolbox/ColorPickerMenu.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 TabMenu component with Tabs without panelsApplied to files:
src/components/graph/selectionToolbox/ColorPickerMenu.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/components/graph/selectionToolbox/ColorPickerMenu.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 InputSwitch component with ToggleSwitchApplied to files:
src/components/graph/selectionToolbox/ColorPickerMenu.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 Sidebar component with DrawerApplied to files:
src/components/graph/selectionToolbox/ColorPickerMenu.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/components/graph/selectionToolbox/ColorPickerMenu.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 InlineMessage component with MessageApplied to files:
src/components/graph/selectionToolbox/ColorPickerMenu.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 Chips component with AutoComplete with multiple enabledApplied to files:
src/components/graph/selectionToolbox/ColorPickerMenu.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,html} : Never use `dark:` or `dark-theme:` Tailwind variants - instead use semantic values from `style.css` theme, e.g. `bg-node-component-surface`Applied to files:
src/components/graph/selectionToolbox/ColorPickerMenu.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/components/graph/selectionToolbox/ColorPickerMenu.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,css} : Use the correct tokens from style.css in the design system packageApplied to files:
src/components/graph/selectionToolbox/ColorPickerMenu.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 Tailwind CSS for stylingApplied to files:
src/components/graph/selectionToolbox/ColorPickerMenu.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 responsive design with Tailwind CSSApplied to files:
src/components/graph/selectionToolbox/ColorPickerMenu.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 existing VueUse composables (such as useElementHover) instead of manually managing event listenersApplied to files:
src/components/graph/selectionToolbox/ColorPickerMenu.vue🪛 ESLint
src/components/graph/selectionToolbox/ColorPickerMenu.vue
[error] 51-51: Unable to resolve path to module '@comfyorg/tailwind-utils'.
(import-x/no-unresolved)
[error] 52-52: Unable to resolve path to module '@vueuse/core'.
(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: lint-and-format
- GitHub Check: test
- GitHub Check: collect
🔇 Additional comments (1)
src/components/graph/selectionToolbox/ColorPickerMenu.vue (1)
129-131: LGTM!The early return for disabled submenu options correctly prevents actions from being triggered on disabled items.
| const showToRight = (target: HTMLElement) => { | ||
| const rect = target.getBoundingClientRect() | ||
| position.value = { | ||
| top: rect.top, | ||
| left: rect.right + 4 | ||
| } | ||
| isVisible.value = true | ||
| justOpened = true | ||
| setTimeout(() => { | ||
| justOpened = false | ||
| }, 0) | ||
| } |
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.
Add viewport boundary checks to prevent overflow.
The positioning logic places the menu to the right of the target without checking viewport boundaries. The menu could overflow off the right edge or bottom of the viewport, degrading user experience.
Consider adding boundary detection:
const showToRight = (target: HTMLElement) => {
const rect = target.getBoundingClientRect()
+ const menuWidth = 200 // approximate or measure actual width
+ const menuHeight = popoverRef.value?.offsetHeight || 0
+
+ let left = rect.right + 4
+ let top = rect.top
+
+ // Check right boundary
+ if (left + menuWidth > window.innerWidth) {
+ left = rect.left - menuWidth - 4
+ }
+
+ // Check bottom boundary
+ if (top + menuHeight > window.innerHeight) {
+ top = window.innerHeight - menuHeight - 8
+ }
+
position.value = {
- top: rect.top,
- left: rect.right + 4
+ top: Math.max(8, top),
+ left: Math.max(8, left)
}
isVisible.value = true
justOpened = true
setTimeout(() => {
justOpened = false
}, 0)
}Alternatively, consider using a positioning utility library or VueUse's useFloating composable.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/components/graph/selectionToolbox/ColorPickerMenu.vue around lines 84–95,
the showToRight function positions the menu to the right of the target without
checking viewport boundaries; update it to compute the menu element size
(offsetWidth/offsetHeight or getBoundingClientRect on the menu ref) and then
clamp or flip the calculated left/top so the menu stays within window.innerWidth
and window.innerHeight with a small margin (e.g., 8px); if there isn't enough
space to the right, position to the left of the target (rect.left - menuWidth -
margin), and if the bottom would overflow, adjust top to rect.bottom -
menuHeight or clamp to maximum allowed top; ensure measurement happens on a
visible element (temporarily set isVisible if needed) or compute off-DOM, then
set position.value and isVisible.value as before.
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
🧹 Nitpick comments (1)
src/components/graph/NodeContextMenu.vue (1)
117-120: Clarify the purpose ofbump()call.Line 118 calls
bump()before showing the context menu. While this likely refreshes the menu options, consider adding a comment to explain its purpose for future maintainers.function show(event: MouseEvent) { + // Refresh menu options before displaying bump() contextMenu.value?.show(event) }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/components/graph/NodeContextMenu.vue(1 hunks)
🧰 Additional context used
📓 Path-based instructions (15)
**/*.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/components/graph/NodeContextMenu.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/components/graph/NodeContextMenu.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/components/graph/NodeContextMenu.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/components/graph/NodeContextMenu.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/components/graph/NodeContextMenu.vue**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use camelCase for variable and setting names in TypeScript/Vue files
Files:
src/components/graph/NodeContextMenu.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/components/graph/NodeContextMenu.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/components/graph/NodeContextMenu.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/components/graph/NodeContextMenu.vuesrc/**/{composables,components}/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Clean up subscriptions in state management to prevent memory leaks
Files:
src/components/graph/NodeContextMenu.vuesrc/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/components/graph/NodeContextMenu.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/components/graph/NodeContextMenu.vuesrc/components/**/*.vue
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue componentsFiles:
src/components/graph/NodeContextMenu.vuesrc/components/**/*.{vue,css}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system packageFiles:
src/components/graph/NodeContextMenu.vuesrc/components/**/*.{vue,ts,js}
📄 CodeRabbit inference engine (src/components/CLAUDE.md)
src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI stringsFiles:
src/components/graph/NodeContextMenu.vue🧠 Learnings (11)
📓 Common learnings
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 PopoverLearnt 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 respectivelyLearnt 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 SelectLearnt 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 TabMenu component with Tabs without panelsLearnt 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)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 Sidebar component with DrawerLearnt 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: src/components/CLAUDE.md:0-0 Timestamp: 2025-11-24T19:47:45.616Z Learning: Applies to src/components/**/*.vue : Replace PrimeVue Calendar component with DatePickerLearnt 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 InlineMessage component with MessageLearnt 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📚 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 TabMenu component with Tabs without panelsApplied to files:
src/components/graph/NodeContextMenu.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 Sidebar component with DrawerApplied to files:
src/components/graph/NodeContextMenu.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 OverlayPanel component with PopoverApplied to files:
src/components/graph/NodeContextMenu.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/components/graph/NodeContextMenu.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/components/graph/NodeContextMenu.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/components/graph/NodeContextMenu.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 InputSwitch component with ToggleSwitchApplied to files:
src/components/graph/NodeContextMenu.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 the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)Applied to files:
src/components/graph/NodeContextMenu.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 **/*.vue : Name Vue components in PascalCase (e.g., `MenuHamburger.vue`)Applied to files:
src/components/graph/NodeContextMenu.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 InlineMessage component with MessageApplied to files:
src/components/graph/NodeContextMenu.vue🪛 ESLint
src/components/graph/NodeContextMenu.vue
[error] 1-1: Resolve error: EACCES: permission denied, open '/SBDDjiZKMN'
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 '/cFsKQTujGL'
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 '/eRcSMJPorO'
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 checkDefault (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/default.js:22:39)
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/default)
[error] 1-1: Resolve error: EACCES: permission denied, open '/huRjmINgMY'
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] 1-1: Resolve error: EACCES: permission denied, open '/qsAqdrUujK'
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 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-useless-path-segments.js:58: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-useless-path-segments)
[error] 35-35: Unable to resolve path to module 'primevue/contextmenu'.
(import-x/no-unresolved)
[error] 37-37: Unable to resolve path to module 'vue'.
(import-x/no-unresolved)
[error] 42-42: Unable to resolve path to module '@/composables/graph/useMoreOptionsMenu'.
(import-x/no-unresolved)
[error] 48-48: Unable to resolve path to module './selectionToolbox/ColorPickerMenu.vue'.
(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). (5)
- GitHub Check: deploy-and-comment
- GitHub Check: test
- GitHub Check: setup
- GitHub Check: lint-and-format
- GitHub Check: collect
🔇 Additional comments (5)
src/components/graph/NodeContextMenu.vue (5)
50-54: LGTM!The ExtendedMenuItem interface properly extends PrimeVue's MenuItem with custom properties needed for color submenu handling and shortcuts.
73-109: LGTM!The conversion logic correctly transforms MenuOption structures into PrimeVue-compatible MenuItem objects, handling dividers, color submenus, native submenus, and action items appropriately.
123-139: LGTM!The hide and toggle functions correctly manage both the context menu and color picker states. The unused parameters in
toggleare appropriately prefixed with underscores to indicate they're present for API compatibility.
143-148: Event handling prevents default behavior for color picker.Lines 144-145 stop event propagation and prevent default behavior to enable the custom ColorPickerMenu. This is necessary for the functionality but may affect accessibility features.
Ensure this custom handling doesn't break keyboard navigation or screen reader announcements. Consider adding keyboard event handling (Enter/Space keys) to activate the color picker.
4-21: Custom click handler may interfere with keyboard navigation.Line 7 intercepts clicks on color submenu items with a custom handler. While this enables the custom ColorPickerMenu, it may bypass PrimeVue's native keyboard navigation and ARIA attributes for submenus.
Verify that keyboard users can navigate to and activate the color submenu using standard arrow keys and Enter/Space. Test with a screen reader to ensure the submenu is properly announced.
| onMounted(() => { | ||
| isOpen.value = false | ||
| registerNodeOptionsInstance({ toggle, hide, isOpen }) | ||
| }) |
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.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# First, locate the NodeContextMenu.vue file
fd -t f "NodeContextMenu.vue" | head -20Repository: Comfy-Org/ComfyUI_frontend
Length of output: 110
🏁 Script executed:
#!/bin/bash
# Search for NodeContextMenu instantiation patterns
rg -n "NodeContextMenu" --type=vue --type=ts -C 2 | head -100Repository: Comfy-Org/ComfyUI_frontend
Length of output: 97
🏁 Script executed:
#!/bin/bash
# Find and examine registerNodeOptionsInstance to understand the pattern
rg -n "registerNodeOptionsInstance" --type=ts --type=vue --type=js -B 3 -A 5Repository: Comfy-Org/ComfyUI_frontend
Length of output: 97
🏁 Script executed:
#!/bin/bash
# Read the NodeContextMenu.vue file directly to inspect the relevant lines
cat -n src/components/graph/NodeContextMenu.vue | head -180 | tail -130Repository: Comfy-Org/ComfyUI_frontend
Length of output: 3853
🏁 Script executed:
#!/bin/bash
# Search for registerNodeOptionsInstance without file type restrictions
rg -n "registerNodeOptionsInstance" -B 3 -A 5Repository: Comfy-Org/ComfyUI_frontend
Length of output: 2345
🏁 Script executed:
#!/bin/bash
# Search for NodeContextMenu usage patterns
rg -n "NodeContextMenu" -B 2 -A 2Repository: Comfy-Org/ComfyUI_frontend
Length of output: 2984
🏁 Script executed:
#!/bin/bash
# Examine the useMoreOptionsMenu.ts to understand the singleton pattern
cat -n src/composables/graph/useMoreOptionsMenu.ts | head -100Repository: Comfy-Org/ComfyUI_frontend
Length of output: 3267
🏁 Script executed:
#!/bin/bash
# Check for nodeOptionsInstance variable declaration and usage
rg -n "nodeOptionsInstance" -B 2 -A 2Repository: Comfy-Org/ComfyUI_frontend
Length of output: 1179
Remove redundant initialization in onMounted.
Line 162 sets isOpen.value = false, but the ref is already initialized to false on line 58, making this line redundant and unnecessary.
The registration pattern in line 163 is intentional—nodeOptionsInstance is a module-level singleton designed to maintain a single registered instance for the toggleNodeOptions() function. This is by design and working as intended, with proper cleanup on unmount (line 167).
onMounted(() => {
- isOpen.value = false
registerNodeOptionsInstance({ toggle, hide, isOpen })
})📝 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.
| onMounted(() => { | |
| isOpen.value = false | |
| registerNodeOptionsInstance({ toggle, hide, isOpen }) | |
| }) | |
| onMounted(() => { | |
| registerNodeOptionsInstance({ toggle, hide, isOpen }) | |
| }) |
🤖 Prompt for AI Agents
In src/components/graph/NodeContextMenu.vue around lines 161 to 164, remove the
redundant initialization isOpen.value = false inside onMounted since the ref is
already initialized to false at line 58; leave the registerNodeOptionsInstance({
toggle, hide, isOpen }) call intact to preserve the module-level singleton
registration and its existing unmount cleanup.
This pull request introduces several improvements to the node context menu in the graph selection toolbox, focusing on enhanced usability, accessibility, and maintainability. The most significant changes are the addition of a search/filter feature for menu options, improved handling and display of disabled and categorized menu items, and better viewport-aware positioning for popovers and submenus.
Menu Usability & Filtering:
NodeOptions.vue,useMoreOptionsMenu.ts) [1] [2] [3] [4] [5]Menu Item Display & Accessibility:
MenuOptionItem.vue,SubmenuPopover.vue,useMoreOptionsMenu.ts) [1] [2] [3] [4] [5]categoryanddisabledflags, and added asourcefield for distinguishing between hardcoded and dynamic options. (useMoreOptionsMenu.ts) [1] [2]Popover & Submenu Positioning:
NodeOptions.vue,SubmenuPopover.vue) [1] [2]Codebase Maintenance:
NodeOptions.vue,useMoreOptionsMenu.ts) [1] [2] [3] [4]These changes collectively enhance the user experience for interacting with node options, making the menu more navigable, accessible, and robust.
Recording.2025-11-11.235411.mp4