Skip to content

Commit b8a3c55

Browse files
committed
fix: 修复调试功能入口节点可能无法被正常识别的问题
1 parent 9e1d094 commit b8a3c55

8 files changed

Lines changed: 217 additions & 16 deletions

File tree

src/data/updateLogs.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,9 @@ export const updateLogs: UpdateLogItem[] = [
115115
"优化资源健康检查相关术语",
116116
],
117117
fixes: [
118-
"修复 on_error 无法连接至自身的问题",
118+
"修复调试功能入口节点可能无法被正常识别的问题",
119119
"修复 adb 不填写 extra 无法连接的问题",
120+
"修复 on_error 无法连接至自身的问题",
120121
],
121122
},
122123
},

src/features/debug/hooks/useDebugModalController.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,12 @@ export function useDebugModalController() {
202202
deviceInfo: state.deviceInfo,
203203
})),
204204
);
205-
const flowNodes = useFlowStore((state) => state.nodes);
205+
const { flowEdges, flowNodes } = useFlowStore(
206+
useShallow((state) => ({
207+
flowEdges: state.edges,
208+
flowNodes: state.nodes,
209+
})),
210+
);
206211
const selectedFlowNodeId = useFlowStore((state) =>
207212
state.selectedNodes.length === 1 ? state.selectedNodes[0]?.id : undefined,
208213
);
@@ -298,6 +303,7 @@ export function useDebugModalController() {
298303
);
299304

300305
const nodeExecutionController = useDebugNodeExecutionController({
306+
flowEdges,
301307
flowNodes,
302308
liveSummary,
303309
nodeExecutionAttributionMode,

src/features/debug/hooks/useDebugNodeExecutionController.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useCallback, useEffect, useMemo, useState } from "react";
22
import { useDebugOverlayStore } from "../../../stores/debugOverlayStore";
3-
import type { NodeType } from "../../../stores/flow";
3+
import { useFileStore } from "../../../stores/fileStore";
4+
import type { EdgeType, NodeType } from "../../../stores/flow";
45
import { useLocalFileStore } from "../../../stores/localFileStore";
56
import { useDebugRunProfileStore } from "../../../stores/debugRunProfileStore";
67
import { applyDebugNodeTarget } from "../nodeTargetActions";
@@ -24,6 +25,7 @@ import {
2425
} from "../types";
2526

2627
interface UseDebugNodeExecutionControllerInput {
28+
flowEdges: EdgeType[];
2729
flowNodes: NodeType[];
2830
liveSummary: DebugTraceSummary;
2931
nodeExecutionAttributionMode: DebugExecutionAttributionMode;
@@ -36,6 +38,7 @@ interface UseDebugNodeExecutionControllerInput {
3638
}
3739

3840
export function useDebugNodeExecutionController({
41+
flowEdges,
3942
flowNodes,
4043
liveSummary,
4144
nodeExecutionAttributionMode,
@@ -58,11 +61,51 @@ export function useDebugNodeExecutionController({
5861
const resourcePaths = useDebugRunProfileStore(
5962
(state) => state.profile.resourcePaths,
6063
);
64+
const fileSnapshotKey = useFileStore((state) =>
65+
JSON.stringify({
66+
currentFile: {
67+
fileName: state.currentFile.fileName,
68+
filePath: state.currentFile.config.filePath,
69+
prefix: state.currentFile.config.prefix,
70+
relativePath: state.currentFile.config.relativePath,
71+
},
72+
files: state.files.map((file) => ({
73+
fileName: file.fileName,
74+
filePath: file.config.filePath,
75+
prefix: file.config.prefix,
76+
relativePath: file.config.relativePath,
77+
nodeCount: file.nodes.length,
78+
edgeCount: file.edges.length,
79+
})),
80+
}),
81+
);
6182
const flowNodeIds = useMemo(
6283
() => new Set(flowNodes.map((node) => node.id)),
6384
[flowNodes],
6485
);
86+
const flowSnapshotKey = useMemo(
87+
() =>
88+
JSON.stringify({
89+
edges: flowEdges.map((edge) => ({
90+
id: edge.id,
91+
source: edge.source,
92+
sourceHandle: edge.sourceHandle,
93+
target: edge.target,
94+
targetHandle: edge.targetHandle,
95+
jumpBack: edge.attributes?.jump_back,
96+
anchor: edge.attributes?.anchor,
97+
})),
98+
nodes: flowNodes.map((node) => ({
99+
id: node.id,
100+
label: node.data.label,
101+
type: node.type,
102+
})),
103+
}),
104+
[flowEdges, flowNodes],
105+
);
65106
const debugResolver = useMemo(() => {
107+
void fileSnapshotKey;
108+
void flowSnapshotKey;
66109
const bundle = buildDebugSnapshotBundle(localFiles, resourcePaths);
67110
return {
68111
edges: bundle.resolverSnapshot.edges,
@@ -71,7 +114,7 @@ export function useDebugNodeExecutionController({
71114
),
72115
allNodes: bundle.resolverSnapshot.nodes,
73116
};
74-
}, [flowNodeIds, localFiles, resourcePaths]);
117+
}, [fileSnapshotKey, flowNodeIds, flowSnapshotKey, localFiles, resourcePaths]);
75118
const resolverEdges = debugResolver.edges;
76119
const resolverEdgeIndex = useMemo(
77120
() => createDebugResolverEdgeIndex(resolverEdges),

src/features/debug/snapshot.test.ts

Lines changed: 130 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,120 @@
1-
import { describe, expect, it } from "vitest";
1+
import { afterEach, describe, expect, it } from "vitest";
2+
import { NodeTypeEnum } from "../../components/flow/nodes";
3+
import { useFileStore } from "../../stores/fileStore";
4+
import { useFlowStore, type PipelineNodeType } from "../../stores/flow";
25
import {
6+
buildDebugSnapshotBundle,
37
selectEffectiveResolverEdges,
48
selectEffectiveResolverNodes,
59
} from "./snapshot";
610
import type { DebugNodeResolverSnapshot } from "./types";
711

812
describe("snapshot resource override resolution", () => {
13+
afterEach(() => {
14+
useFlowStore.setState({ nodes: [], edges: [] });
15+
});
16+
17+
it("uses currentFile config for the active opened file", () => {
18+
const node = makePipelineNode("p_1", "Entry");
19+
const staleFile = {
20+
fileName: "main.json",
21+
nodes: [],
22+
edges: [],
23+
config: {
24+
prefix: "Stale",
25+
},
26+
};
27+
const currentFile = {
28+
...staleFile,
29+
config: {
30+
filePath: "C:/resource/base/pipeline/main.json",
31+
prefix: "Live",
32+
relativePath: "pipeline/main.json",
33+
},
34+
};
35+
36+
useFileStore.setState({
37+
currentFile,
38+
files: [staleFile],
39+
});
40+
useFlowStore.setState({
41+
nodes: [node],
42+
edges: [],
43+
});
44+
45+
const bundle = buildDebugSnapshotBundle(
46+
[
47+
{
48+
file_path: "C:/resource/base/pipeline/main.json",
49+
file_name: "main.json",
50+
relative_path: "pipeline/main.json",
51+
prefix: "Live",
52+
nodes: [
53+
{
54+
label: "Live_Entry",
55+
prefix: "Live",
56+
anchors: [],
57+
},
58+
],
59+
},
60+
],
61+
["C:/resource/base"],
62+
);
63+
64+
expect(bundle.resolverSnapshot.nodes).toEqual([
65+
{
66+
fileId: "main.json",
67+
nodeId: "p_1",
68+
runtimeName: "Live_Entry",
69+
displayName: "Entry",
70+
prefix: "Live",
71+
sourcePath: "C:/resource/base/pipeline/main.json",
72+
},
73+
]);
74+
});
75+
76+
it("includes the active file when it is missing from files", () => {
77+
const node = makePipelineNode("p_1", "Entry");
78+
const currentFile = {
79+
fileName: "main.json",
80+
nodes: [],
81+
edges: [],
82+
config: {
83+
filePath: "C:/resource/base/pipeline/main.json",
84+
prefix: "Live",
85+
relativePath: "pipeline/main.json",
86+
},
87+
};
88+
89+
useFileStore.setState({
90+
currentFile,
91+
files: [],
92+
});
93+
useFlowStore.setState({
94+
nodes: [node],
95+
edges: [],
96+
});
97+
98+
const bundle = buildDebugSnapshotBundle([], ["C:/resource/base"]);
99+
100+
expect(bundle.graphSnapshot.files).toHaveLength(1);
101+
expect(bundle.graphSnapshot.files[0]).toMatchObject({
102+
fileId: "main.json",
103+
path: "C:/resource/base/pipeline/main.json",
104+
relativePath: "pipeline/main.json",
105+
});
106+
expect(bundle.resolverSnapshot.nodes).toEqual([
107+
{
108+
fileId: "main.json",
109+
nodeId: "p_1",
110+
runtimeName: "Live_Entry",
111+
displayName: "Entry",
112+
prefix: "Live",
113+
sourcePath: "C:/resource/base/pipeline/main.json",
114+
},
115+
]);
116+
});
117+
9118
it("prefers later resource paths for duplicate runtime names", () => {
10119
const nodes: DebugNodeResolverSnapshot["nodes"] = [
11120
{
@@ -58,3 +167,23 @@ describe("snapshot resource override resolution", () => {
58167
).toEqual([edges[1]]);
59168
});
60169
});
170+
171+
function makePipelineNode(id: string, label: string): PipelineNodeType {
172+
return {
173+
id,
174+
type: NodeTypeEnum.Pipeline,
175+
data: {
176+
label,
177+
recognition: {
178+
type: "DirectHit",
179+
param: {},
180+
},
181+
action: {
182+
type: "DoNothing",
183+
param: {},
184+
},
185+
others: {},
186+
},
187+
position: { x: 0, y: 0 },
188+
};
189+
}

src/features/debug/snapshot.ts

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,27 +70,35 @@ function buildFileSources(): DebugFileSource[] {
7070
const fileState = useFileStore.getState();
7171
const flowState = useFlowStore.getState();
7272

73-
return fileState.files.map((file) => {
73+
const openedFiles = fileState.files.some(
74+
(file) => file.fileName === fileState.currentFile.fileName,
75+
)
76+
? fileState.files
77+
: [...fileState.files, fileState.currentFile];
78+
79+
return openedFiles.map((file) => {
7480
const isCurrent = file.fileName === fileState.currentFile.fileName;
81+
const sourceFile = isCurrent ? fileState.currentFile : file;
82+
const config = sourceFile.config;
7583
const nodes = isCurrent ? flowState.nodes : file.nodes;
7684
const edges = isCurrent ? flowState.edges : file.edges;
7785
const pipeline = flowToPipeline({
7886
nodes,
7987
edges,
80-
fileName: file.fileName,
81-
config: file.config,
88+
fileName: sourceFile.fileName,
89+
config,
8290
});
8391

8492
return {
85-
fileId: file.fileName,
86-
path: file.config.filePath,
87-
relativePath: file.config.relativePath,
88-
prefix: file.config.prefix,
93+
fileId: sourceFile.fileName,
94+
path: config.filePath,
95+
relativePath: config.relativePath,
96+
prefix: config.prefix,
8997
nodes,
9098
edges,
9199
pipeline,
92-
config: toRecord(file.config),
93-
dirty: !file.config.filePath || file.config.isModifiedExternally,
100+
config: toRecord(config),
101+
dirty: !config.filePath || config.isModifiedExternally,
94102
};
95103
});
96104
}

src/stores/configStore.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { encryptApiKey } from "../utils/ai/crypto";
77
export const globalConfig = {
88
dev: true,
99
version: `1.6.1`,
10-
betaIteration: 1,
10+
betaIteration: 2,
1111
mfwVersion: "5.10.5",
1212
protocolVersion: "1.0.5",
1313
};

src/stores/debugRunProfileStore.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,9 @@ export const useDebugRunProfileStore = create<DebugRunProfileState>(
358358
targetNodeId !== undefined
359359
? resolveDebugNodeTarget(targetNodeId, bundle.resolverSnapshot)
360360
: undefined;
361+
if (targetNodeId !== undefined && !target) {
362+
throw new Error("所选入口节点不在当前调试快照中,请重新打开入口节点所在文件后再试。");
363+
}
361364
const snapshotEntry =
362365
bundle.resolverSnapshot.nodes.find(
363366
(node) => node.fileId === bundle.resolverSnapshot.rootFileId,

src/stores/fileStore.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,18 @@ export const useFileStore = create<FileState>()((set) => ({
411411
setFileConfig(key, value) {
412412
set((state) => {
413413
const config = { ...state.currentFile.config, [key]: value };
414-
state.currentFile.config = config;
414+
const currentFile = { ...state.currentFile, config };
415+
const currentFileIndex = state.files.findIndex(
416+
(file) => file.fileName === currentFile.fileName,
417+
);
418+
const files =
419+
currentFileIndex >= 0
420+
? state.files.map((file, index) =>
421+
index === currentFileIndex ? currentFile : file,
422+
)
423+
: state.files;
424+
state.currentFile = currentFile;
425+
state.files = files;
415426
return {};
416427
});
417428
},

0 commit comments

Comments
 (0)