Skip to content

Commit c642ed5

Browse files
authored
Complete context menu migration for Load3D, Preview3D, and SaveGLB (#6454)
This pull request refactors how export menu options are added to 3D-related nodes, updating the API to use a new `getNodeMenuItems` hook and simplifying the menu item creation logic. The changes improve consistency and maintainability across extensions handling 3D nodes, and clarify the expected return types for menu item hooks. **Refactoring and API updates for node menu items:** * Replaced usage of the legacy `createExportMenuOptions` function with the new `createExportMenuItems` function in `load3d.ts`, `saveMesh.ts`, and related imports, aligning all 3D node extensions to the new API. [[1]](diffhunk://#diff-a5c612d9322ca4cbbeda097d13e2fa1ef017d4c3076d23fc228afee5a79a56e3L6-R12) [[2]](diffhunk://#diff-7dede72060130d77ce5191fc86d115bd9b93311cb0438400730d8e20b2aa8e43L4-R7) * Introduced and implemented the `getNodeMenuItems` hook in the extension registration for `Load3D`, `Preview3D`, and `SaveGLB` nodes, ensuring export menu items are only shown for the appropriate node types. [[1]](diffhunk://#diff-a5c612d9322ca4cbbeda097d13e2fa1ef017d4c3076d23fc228afee5a79a56e3R293-R302) [[2]](diffhunk://#diff-a5c612d9322ca4cbbeda097d13e2fa1ef017d4c3076d23fc228afee5a79a56e3R521-R530) [[3]](diffhunk://#diff-7dede72060130d77ce5191fc86d115bd9b93311cb0438400730d8e20b2aa8e43R48-R57) * Removed assignment of `getExtraMenuOptions` to nodes, fully migrating to the new menu item hook approach for context menus. [[1]](diffhunk://#diff-a5c612d9322ca4cbbeda097d13e2fa1ef017d4c3076d23fc228afee5a79a56e3L301-L302) [[2]](diffhunk://#diff-a5c612d9322ca4cbbeda097d13e2fa1ef017d4c3076d23fc228afee5a79a56e3L548-L549) [[3]](diffhunk://#diff-7dede72060130d77ce5191fc86d115bd9b93311cb0438400730d8e20b2aa8e43L64-L67) **Menu item creation logic simplification:** * Refactored `createExportMenuOptions` to `createExportMenuItems` in `exportMenuHelper.ts`, changing it to directly return an array of menu items (with separators) instead of a function, simplifying its usage and reducing boilerplate. [[1]](diffhunk://#diff-42404da1a87a52d304371a13d5f021bdad837765b94d86d186abb2d99a8cb707L14-R22) [[2]](diffhunk://#diff-42404da1a87a52d304371a13d5f021bdad837765b94d86d186abb2d99a8cb707L59-R58) **Type and documentation improvements:** * Updated the `ComfyExtension` interface in `comfy.ts` to clarify that menu item hooks (`getCanvasMenuItems`, `getNodeMenuItems`) now return arrays that may include `null` values as separators, improving type safety and documentation. See before and after below <img width="1459" height="897" alt="Screenshot 2025-10-30 at 07 08 04" src="https://github.com/user-attachments/assets/ec4464c9-f733-4b4c-87c4-bb5060ccaa68" /> ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6454-Complete-context-menu-migration-for-Load3D-Preview3D-and-SaveGLB-29c6d73d3650819995b4c4dc1582cd86) by [Unito](https://www.unito.io)
1 parent 9e30930 commit c642ed5

File tree

4 files changed

+51
-28
lines changed

4 files changed

+51
-28
lines changed

src/extensions/core/load3d.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import { nextTick } from 'vue'
33
import Load3D from '@/components/load3d/Load3D.vue'
44
import Load3DAnimation from '@/components/load3d/Load3DAnimation.vue'
55
import Load3DViewerContent from '@/components/load3d/Load3dViewerContent.vue'
6-
import { createExportMenuOptions } from '@/extensions/core/load3d/exportMenuHelper'
6+
import { createExportMenuItems } from '@/extensions/core/load3d/exportMenuHelper'
77
import Load3DConfiguration from '@/extensions/core/load3d/Load3DConfiguration'
88
import Load3dAnimation from '@/extensions/core/load3d/Load3dAnimation'
99
import Load3dUtils from '@/extensions/core/load3d/Load3dUtils'
1010
import { t } from '@/i18n'
11+
import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
12+
import type { IContextMenuValue } from '@/lib/litegraph/src/interfaces'
1113
import type { IStringWidget } from '@/lib/litegraph/src/types/widgets'
1214
import { useToastStore } from '@/platform/updates/common/toastStore'
1315
import { type CustomInputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
@@ -288,6 +290,16 @@ useExtensionService().registerExtension({
288290
}
289291
},
290292

293+
getNodeMenuItems(node: LGraphNode): (IContextMenuValue | null)[] {
294+
// Only show menu items for Load3D nodes
295+
if (node.constructor.comfyClass !== 'Load3D') return []
296+
297+
const load3d = useLoad3dService().getLoad3d(node)
298+
if (!load3d) return []
299+
300+
return createExportMenuItems(load3d)
301+
},
302+
291303
async nodeCreated(node) {
292304
if (node.constructor.comfyClass !== 'Load3D') return
293305

@@ -298,8 +310,6 @@ useExtensionService().registerExtension({
298310
await nextTick()
299311

300312
useLoad3dService().waitForLoad3d(node, (load3d) => {
301-
node.getExtraMenuOptions = createExportMenuOptions(load3d)
302-
303313
let cameraState = node.properties['Camera Info']
304314

305315
const config = new Load3DConfiguration(load3d)
@@ -508,6 +518,16 @@ useExtensionService().registerExtension({
508518
}
509519
},
510520

521+
getNodeMenuItems(node: LGraphNode): (IContextMenuValue | null)[] {
522+
// Only show menu items for Preview3D nodes
523+
if (node.constructor.comfyClass !== 'Preview3D') return []
524+
525+
const load3d = useLoad3dService().getLoad3d(node)
526+
if (!load3d) return []
527+
528+
return createExportMenuItems(load3d)
529+
},
530+
511531
getCustomWidgets() {
512532
return {
513533
PREVIEW_3D(node) {
@@ -545,8 +565,6 @@ useExtensionService().registerExtension({
545565
const onExecuted = node.onExecuted
546566

547567
useLoad3dService().waitForLoad3d(node, (load3d) => {
548-
node.getExtraMenuOptions = createExportMenuOptions(load3d)
549-
550568
const config = new Load3DConfiguration(load3d)
551569

552570
const modelWidget = node.widgets?.find((w) => w.name === 'model_file')

src/extensions/core/load3d/exportMenuHelper.ts

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { t } from '@/i18n'
2-
import type { LGraphCanvas } from '@/lib/litegraph/src/LGraphCanvas'
32
import type { IContextMenuValue } from '@/lib/litegraph/src/interfaces'
43
import { useToastStore } from '@/platform/updates/common/toastStore'
54
import Load3d from '@/extensions/core/load3d/Load3d'
@@ -11,17 +10,16 @@ const EXPORT_FORMATS = [
1110
{ label: 'STL', value: 'stl' }
1211
] as const
1312

14-
export function createExportMenuOptions(
13+
/**
14+
* Creates export menu items for a 3D node using the new extension API.
15+
* Returns an array of context menu items including a separator and export submenu.
16+
*/
17+
export function createExportMenuItems(
1518
load3d: Load3d
16-
): (
17-
canvas: LGraphCanvas,
18-
options: (IContextMenuValue | null)[]
19-
) => (IContextMenuValue | null)[] {
20-
return function (
21-
_canvas: LGraphCanvas,
22-
options: (IContextMenuValue | null)[]
23-
): (IContextMenuValue | null)[] {
24-
options.push(null, {
19+
): (IContextMenuValue | null)[] {
20+
return [
21+
null, // Separator
22+
{
2523
content: 'Save',
2624
has_submenu: true,
2725
callback: (_value, _options, event, prev_menu) => {
@@ -56,7 +54,6 @@ export function createExportMenuOptions(
5654
parentMenu: prev_menu
5755
})
5856
}
59-
})
60-
return options
61-
}
57+
}
58+
]
6259
}

src/extensions/core/saveMesh.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { nextTick } from 'vue'
22

33
import Load3D from '@/components/load3d/Load3D.vue'
4-
import { createExportMenuOptions } from '@/extensions/core/load3d/exportMenuHelper'
4+
import { createExportMenuItems } from '@/extensions/core/load3d/exportMenuHelper'
55
import Load3DConfiguration from '@/extensions/core/load3d/Load3DConfiguration'
6+
import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
7+
import type { IContextMenuValue } from '@/lib/litegraph/src/interfaces'
68
import { type CustomInputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
79
import { ComponentWidgetImpl, addWidget } from '@/scripts/domWidget'
810
import { useExtensionService } from '@/services/extensionService'
@@ -43,6 +45,16 @@ useExtensionService().registerExtension({
4345
}
4446
},
4547

48+
getNodeMenuItems(node: LGraphNode): (IContextMenuValue | null)[] {
49+
// Only show menu items for SaveGLB nodes
50+
if (node.constructor.comfyClass !== 'SaveGLB') return []
51+
52+
const load3d = useLoad3dService().getLoad3d(node)
53+
if (!load3d) return []
54+
55+
return createExportMenuItems(load3d)
56+
},
57+
4658
async nodeCreated(node) {
4759
if (node.constructor.comfyClass !== 'SaveGLB') return
4860

@@ -61,10 +73,6 @@ useExtensionService().registerExtension({
6173

6274
const load3d = useLoad3dService().getLoad3d(node)
6375

64-
if (load3d) {
65-
node.getExtraMenuOptions = createExportMenuOptions(load3d)
66-
}
67-
6876
const modelWidget = node.widgets?.find((w) => w.name === 'image')
6977

7078
if (load3d && modelWidget) {

src/types/comfy.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,16 +140,16 @@ export interface ComfyExtension {
140140
/**
141141
* Allows the extension to add context menu items to canvas right-click menus
142142
* @param canvas The canvas instance
143-
* @returns An array of context menu items to add
143+
* @returns An array of context menu items to add (null values represent separators)
144144
*/
145-
getCanvasMenuItems?(canvas: LGraphCanvas): IContextMenuValue[]
145+
getCanvasMenuItems?(canvas: LGraphCanvas): (IContextMenuValue | null)[]
146146

147147
/**
148148
* Allows the extension to add context menu items to node right-click menus
149149
* @param node The node being right-clicked
150-
* @returns An array of context menu items to add
150+
* @returns An array of context menu items to add (null values represent separators)
151151
*/
152-
getNodeMenuItems?(node: LGraphNode): IContextMenuValue[]
152+
getNodeMenuItems?(node: LGraphNode): (IContextMenuValue | null)[]
153153

154154
/**
155155
* Allows the extension to add additional handling to the node before it is registered with **LGraph**

0 commit comments

Comments
 (0)