feat(contextMenu): add extension API for context menu items

Introduces a new extension API that allows extensions to provide context menu items directly, without monkey-patching. This provides a clean, type-safe way for extensions to add menu items.

**New API methods:**
- `getCanvasMenuItems(canvas)`: Add items to canvas right-click menus
- `getNodeMenuItems(node)`: Add items to node right-click menus

**Implementation:**
- Added TypeScript interfaces in `src/types/comfy.ts`
- Added collection methods in `ComfyApp` class
- Comprehensive test coverage for the new API
This commit is contained in:
Johnpaul
2025-10-09 01:33:29 +01:00
parent 338cbd4eed
commit 5b37fc59e7
4 changed files with 438 additions and 2 deletions

View File

@@ -0,0 +1,65 @@
import { describe, expect, it, vi } from 'vitest'
import { legacyMenuCompat } from '@/lib/litegraph/src/contextMenuCompat'
import { LGraphCanvas } from '@/lib/litegraph/src/litegraph'
/**
* Test that demonstrates the extension name appearing in deprecation warnings
*/
describe('Context Menu Extension Name in Warnings', () => {
it('should include extension name in deprecation warning', () => {
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
// Install compatibility layer
legacyMenuCompat.install(LGraphCanvas.prototype, 'getCanvasMenuOptions')
// Simulate what happens during extension setup
legacyMenuCompat.setCurrentExtension('MyCustomExtension')
// Extension monkey-patches the method
const original = LGraphCanvas.prototype.getCanvasMenuOptions
LGraphCanvas.prototype.getCanvasMenuOptions = function (...args: any[]) {
const items = (original as any).apply(this, args)
items.push({ content: 'My Custom Menu Item', callback: () => {} })
return items
}
// Clear extension (happens after setup completes)
legacyMenuCompat.setCurrentExtension(null)
// Verify the warning includes the extension name
expect(warnSpy).toHaveBeenCalled()
const warningMessage = warnSpy.mock.calls[0][0]
expect(warningMessage).toContain('[DEPRECATED]')
expect(warningMessage).toContain('getCanvasMenuOptions')
expect(warningMessage).toContain('"MyCustomExtension"')
vi.restoreAllMocks()
})
it('should not include extension name if not set', () => {
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
// Install compatibility layer
legacyMenuCompat.install(LGraphCanvas.prototype, 'getNodeMenuOptions')
// Extension monkey-patches without setting current extension
const original = LGraphCanvas.prototype.getNodeMenuOptions
LGraphCanvas.prototype.getNodeMenuOptions = function (...args: any[]) {
const items = (original as any).apply(this, args)
items.push({ content: 'My Node Menu Item', callback: () => {} })
return items
}
// Verify the warning does NOT include extension info
expect(warnSpy).toHaveBeenCalled()
const warningMessage = warnSpy.mock.calls[0][0]
expect(warningMessage).toContain('[DEPRECATED]')
expect(warningMessage).toContain('getNodeMenuOptions')
expect(warningMessage).not.toContain('Extension:')
vi.restoreAllMocks()
})
})