Skip to content

Commit 2ff65d0

Browse files
committed
refactor!: migrate entity state to dedicated stores
Scope link and reroute topology by owning graph, centralize layout ownership and command submission, preserve subgraph topology during unpack, and transfer node ownership during replacement. Amp-Thread-ID: https://ampcode.com/threads/T-01a00362-7d94-7648-8717-b4e1e72495f4
1 parent 9a54e1f commit 2ff65d0

373 files changed

Lines changed: 23520 additions & 12814 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

browser_tests/README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,8 +391,10 @@ await expect(node).toHaveClass(BYPASS_CLASS)
391391
before `page.keyboard.press(...)`, or keys go nowhere.
392392
- Mark the canvas dirty after programmatic state changes:
393393
`window['app'].graph.setDirtyCanvas(true, true)`.
394-
- `dblclick()` on canvas needs a small `{ delay: 5 }`; drags need
395-
`{ steps: 10 }` not `{ steps: 1 }`.
394+
- `dblclick()` on canvas needs a small `{ delay: 5 }`. Use the shared drag
395+
helpers, which emit enough intermediate events for canvas behavior without
396+
making coverage runs process excessive pointer events. For a local drag,
397+
use the fewest steps the behavior needs (usually 5–20), never 100.
396398

397399
### Custom assertions
398400

browser_tests/assets/missing/missing_model_nested_promoted_widget.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"nodes": [
77
{
88
"id": 3,
9-
"type": "outer-subgraph-with-promoted-missing-model",
9+
"type": "4e7c1a2b-3d5f-4a6b-8c9d-0e1f2a3b4c5d",
1010
"pos": [10, 250],
1111
"size": [400, 200],
1212
"flags": {},
@@ -20,7 +20,7 @@
2020
},
2121
{
2222
"id": 4,
23-
"type": "outer-subgraph-with-promoted-missing-model",
23+
"type": "4e7c1a2b-3d5f-4a6b-8c9d-0e1f2a3b4c5d",
2424
"pos": [450, 250],
2525
"size": [400, 200],
2626
"flags": {},
@@ -38,7 +38,7 @@
3838
"definitions": {
3939
"subgraphs": [
4040
{
41-
"id": "outer-subgraph-with-promoted-missing-model",
41+
"id": "4e7c1a2b-3d5f-4a6b-8c9d-0e1f2a3b4c5d",
4242
"version": 1,
4343
"state": {
4444
"lastGroupId": 0,
@@ -71,7 +71,7 @@
7171
"nodes": [
7272
{
7373
"id": 2,
74-
"type": "inner-subgraph-with-promoted-missing-model",
74+
"type": "5f8d2b3c-4e6a-4b7c-9d0e-1f2a3b4c5d6e",
7575
"pos": [250, 180],
7676
"size": [400, 200],
7777
"flags": {},
@@ -105,7 +105,7 @@
105105
]
106106
},
107107
{
108-
"id": "inner-subgraph-with-promoted-missing-model",
108+
"id": "5f8d2b3c-4e6a-4b7c-9d0e-1f2a3b4c5d6e",
109109
"version": 1,
110110
"state": {
111111
"lastGroupId": 0,

browser_tests/assets/missing/missing_models_in_subgraph.json

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
"version": 1,
4848
"state": {
4949
"lastGroupId": 0,
50-
"lastNodeId": 1,
50+
"lastNodeId": 5,
5151
"lastLinkId": 2,
5252
"lastRerouteId": 0
5353
},
@@ -100,6 +100,25 @@
100100
"Node name for S&R": "CheckpointLoaderSimple"
101101
},
102102
"widgets_values": ["fake_model.safetensors"]
103+
},
104+
{
105+
"id": 5,
106+
"type": "CheckpointLoaderSimple",
107+
"pos": [250, 320],
108+
"size": [315, 98],
109+
"flags": {},
110+
"order": 1,
111+
"mode": 0,
112+
"inputs": [],
113+
"outputs": [
114+
{ "name": "MODEL", "type": "MODEL", "links": null },
115+
{ "name": "CLIP", "type": "CLIP", "links": null },
116+
{ "name": "VAE", "type": "VAE", "links": null }
117+
],
118+
"properties": {
119+
"Node name for S&R": "CheckpointLoaderSimple"
120+
},
121+
"widgets_values": ["fake_model.safetensors"]
103122
}
104123
],
105124
"links": [
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{
2+
"last_node_id": 9,
3+
"last_link_id": 13,
4+
"nodes": [
5+
{
6+
"id": 3,
7+
"type": "KSampler",
8+
"pos": [120, 320],
9+
"size": {
10+
"0": 315,
11+
"1": 262
12+
},
13+
"flags": {},
14+
"order": 0,
15+
"mode": 0,
16+
"inputs": [],
17+
"outputs": [],
18+
"properties": {
19+
"Node name for S&R": "KSampler"
20+
}
21+
},
22+
{
23+
"id": 3,
24+
"type": "KSampler",
25+
"pos": [560, 320],
26+
"size": {
27+
"0": 315,
28+
"1": 262
29+
},
30+
"flags": {},
31+
"order": 1,
32+
"mode": 0,
33+
"inputs": [],
34+
"outputs": [],
35+
"properties": {
36+
"Node name for S&R": "KSampler"
37+
}
38+
}
39+
],
40+
"links": [],
41+
"groups": [],
42+
"config": {},
43+
"extra": {
44+
"ds": {
45+
"scale": 1,
46+
"offset": [0, 0]
47+
}
48+
},
49+
"version": 0.4
50+
}
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
{
2+
"id": "987de650-fd73-4f2d-a7d6-ef58909d56cb",
3+
"revision": 0,
4+
"last_node_id": 2,
5+
"last_link_id": 0,
6+
"nodes": [
7+
{
8+
"id": 1,
9+
"type": "11111111-1111-4111-8111-111111111111",
10+
"pos": [300, 300],
11+
"size": [220, 80],
12+
"flags": {},
13+
"order": 0,
14+
"mode": 0,
15+
"inputs": [{ "name": "input", "type": "*", "link": null }],
16+
"outputs": [{ "name": "output", "type": "*", "links": null }],
17+
"properties": {},
18+
"widgets_values": []
19+
},
20+
{
21+
"id": 2,
22+
"type": "22222222-2222-4222-8222-222222222222",
23+
"pos": [650, 300],
24+
"size": [220, 80],
25+
"flags": {},
26+
"order": 1,
27+
"mode": 0,
28+
"inputs": [{ "name": "input", "type": "*", "link": null }],
29+
"outputs": [{ "name": "output", "type": "*", "links": null }],
30+
"properties": {},
31+
"widgets_values": []
32+
}
33+
],
34+
"links": [],
35+
"groups": [],
36+
"definitions": {
37+
"subgraphs": [
38+
{
39+
"id": "11111111-1111-4111-8111-111111111111",
40+
"version": 1,
41+
"state": {
42+
"lastGroupId": 0,
43+
"lastNodeId": 0,
44+
"lastLinkId": 1,
45+
"lastRerouteId": 101
46+
},
47+
"revision": 0,
48+
"config": {},
49+
"name": "Identity collision A",
50+
"inputNode": {
51+
"id": -10,
52+
"bounding": [100, 200, 120, 60]
53+
},
54+
"outputNode": {
55+
"id": -20,
56+
"bounding": [500, 200, 120, 60]
57+
},
58+
"inputs": [
59+
{
60+
"id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
61+
"name": "input",
62+
"type": "*",
63+
"linkIds": [1],
64+
"pos": { "0": 200, "1": 220 }
65+
}
66+
],
67+
"outputs": [
68+
{
69+
"id": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
70+
"name": "output",
71+
"type": "*",
72+
"linkIds": [1],
73+
"pos": { "0": 520, "1": 220 }
74+
}
75+
],
76+
"widgets": [],
77+
"nodes": [],
78+
"groups": [],
79+
"links": [
80+
{
81+
"id": 1,
82+
"origin_id": -10,
83+
"origin_slot": 0,
84+
"target_id": -20,
85+
"target_slot": 0,
86+
"type": "*",
87+
"parentId": 101
88+
}
89+
],
90+
"reroutes": [{ "id": 101, "pos": [300, 220], "linkIds": [1] }],
91+
"extra": {}
92+
},
93+
{
94+
"id": "22222222-2222-4222-8222-222222222222",
95+
"version": 1,
96+
"state": {
97+
"lastGroupId": 0,
98+
"lastNodeId": 0,
99+
"lastLinkId": 1,
100+
"lastRerouteId": 201
101+
},
102+
"revision": 0,
103+
"config": {},
104+
"name": "Identity collision B",
105+
"inputNode": {
106+
"id": -10,
107+
"bounding": [100, 400, 120, 60]
108+
},
109+
"outputNode": {
110+
"id": -20,
111+
"bounding": [500, 400, 120, 60]
112+
},
113+
"inputs": [
114+
{
115+
"id": "cccccccc-cccc-4ccc-8ccc-cccccccccccc",
116+
"name": "input",
117+
"type": "*",
118+
"linkIds": [1],
119+
"pos": { "0": 200, "1": 420 }
120+
}
121+
],
122+
"outputs": [
123+
{
124+
"id": "dddddddd-dddd-4ddd-8ddd-dddddddddddd",
125+
"name": "output",
126+
"type": "*",
127+
"linkIds": [1],
128+
"pos": { "0": 520, "1": 420 }
129+
}
130+
],
131+
"widgets": [],
132+
"nodes": [],
133+
"groups": [],
134+
"links": [
135+
{
136+
"id": 1,
137+
"origin_id": -10,
138+
"origin_slot": 0,
139+
"target_id": -20,
140+
"target_slot": 0,
141+
"type": "*",
142+
"parentId": 201
143+
}
144+
],
145+
"reroutes": [{ "id": 201, "pos": [400, 420], "linkIds": [1] }],
146+
"extra": {}
147+
}
148+
]
149+
},
150+
"config": {},
151+
"extra": {
152+
"ds": { "scale": 1, "offset": [0, 0] },
153+
"frontendVersion": "1.24.1"
154+
},
155+
"version": 0.4
156+
}

browser_tests/fixtures/helpers/CanvasHelper.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
import { expect } from '@playwright/test'
12
import type { Locator, Page } from '@playwright/test'
23

34
import { DefaultGraphPositions } from '@e2e/fixtures/constants/defaultGraphPositions'
45
import type { Position } from '@e2e/fixtures/types'
56
import { nextFrame } from '@e2e/fixtures/utils/timing'
7+
import type { RerouteId } from '@/types/rerouteId'
68

79
export class CanvasHelper {
810
constructor(
@@ -122,7 +124,7 @@ export class CanvasHelper {
122124
async dragAndDrop(source: Position, target: Position): Promise<void> {
123125
await this.page.mouse.move(source.x, source.y)
124126
await this.page.mouse.down()
125-
await this.page.mouse.move(target.x, target.y, { steps: 100 })
127+
await this.page.mouse.move(target.x, target.y, { steps: 20 })
126128
await this.page.mouse.up()
127129
await nextFrame(this.page)
128130
}
@@ -195,6 +197,30 @@ export class CanvasHelper {
195197
}, title)
196198
}
197199

200+
async expectRootReroutePositions(
201+
expectedReroutes: Record<RerouteId, Position>
202+
): Promise<void> {
203+
await expect(async () => {
204+
const reroutes = await this.page.evaluate(() => {
205+
const graph = window.app!.canvas.graph?.rootGraph
206+
if (!graph) throw new Error('Graph not available')
207+
return [...graph.reroutes.values()].map((reroute) => ({
208+
id: reroute.id,
209+
x: reroute.pos[0],
210+
y: reroute.pos[1]
211+
}))
212+
})
213+
214+
expect(reroutes).toHaveLength(Object.keys(expectedReroutes).length)
215+
for (const reroute of reroutes) {
216+
const expected = expectedReroutes[reroute.id]
217+
if (!expected) throw new Error(`Unexpected reroute ${reroute.id}`)
218+
expect(reroute.x).toBeCloseTo(expected.x, 1)
219+
expect(reroute.y).toBeCloseTo(expected.y, 1)
220+
}
221+
}).toPass({ timeout: 5000 })
222+
}
223+
198224
async getGroupPosition(title: string): Promise<Position> {
199225
const pos = await this.page.evaluate((title) => {
200226
const groups = window.app!.graph.groups

browser_tests/fixtures/helpers/NodeOperationsHelper.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,6 @@ export class NodeOperationsHelper {
9595
return await this.page.evaluate(() => window.app!.graph.nodes.length)
9696
}
9797

98-
async getNodes(): Promise<LGraphNode[]> {
99-
return await this.page.evaluate(() => {
100-
return window.app!.graph.nodes
101-
})
102-
}
103-
10498
async waitForGraphNodes(count: number): Promise<void> {
10599
await this.page.waitForFunction((count) => {
106100
return window.app?.canvas.graph?.nodes?.length === count

0 commit comments

Comments
 (0)