feat: support subgraph instances in node context menu

- Detect subgraph instance scope and distinguish top-level vs nested nodes
- Aggregate inner resolved models for outer subgraph instances so menus show
  promoted and hidden models together
- Patch both class prototypes and individual node instances when they define
  getExtraMenuOptions or getMenuOptions, preserving native menu hooks
- Re-inject context menu after loadedGraphNode and queueMicrotask for
  subgraph-created nodes
- Add tests for menu injection on overridden getMenuOptions and instance
  patching, plus subgraph scope and aggregation behavior
This commit is contained in:
Dariusz L
2026-08-03 21:05:49 +02:00
parent 0f70d85f56
commit 514b7d5114
5 changed files with 392 additions and 41 deletions
+56
View File
@@ -4,6 +4,7 @@ import test from 'node:test';
import {
buildModelResolverNodeMenu,
getImmediateModelsForNode,
getModelsForSubgraphInstance,
getResolvedModelsForNode,
isExistingResolvedModel,
matchesWorkflowModelReference,
@@ -46,6 +47,61 @@ test('node context menu filters existing models by path and workflow scope', ()
assert.deepEqual(models.map(item => item.widget_index), [1, 2]);
});
test('node context menu aggregates inner models for an outer subgraph instance', () => {
const models = getModelsForSubgraphInstance({
resolved_models: [
{
node_id: 7,
widget_index: 0,
original_path: 'promoted.safetensors',
full_path: 'C:\\promoted',
is_top_level: true,
subgraph_id: 'subgraph-a',
promoted_inner_node_id: 10,
promoted_inner_widget_index: 0,
exists: true,
},
{
node_id: 10,
widget_index: 0,
original_path: 'promoted.safetensors',
full_path: 'C:\\promoted',
is_top_level: false,
subgraph_id: 'subgraph-a',
exists: true,
},
{
node_id: 11,
widget_index: 1,
original_path: 'hidden.safetensors',
full_path: 'C:\\hidden',
is_top_level: false,
subgraph_id: 'subgraph-a',
exists: true,
},
{
node_id: 12,
widget_index: 0,
original_path: 'other.safetensors',
full_path: 'C:\\other',
is_top_level: false,
subgraph_id: 'subgraph-b',
exists: true,
},
],
}, 7, {
is_top_level: true,
subgraph_id: 'subgraph-a',
subgraph_instance_id: 'subgraph-a',
is_subgraph_instance: true,
});
assert.deepEqual(
models.map(model => model.original_path),
['promoted.safetensors', 'hidden.safetensors'],
);
});
test('node context menu resolves immediate widget selections and ignores invalid references', () => {
const node = {
id: 7,