@arronqzy/react-blueprint 1.0.0 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -0
- package/package.json +6 -6
- package/src/BlueprintNodeConfigSidebar.tsx +3 -0
- package/src/blueprint.css +21 -15
- package/src/components/BlueprintExecutionLogPanel.tsx +2 -2
- package/src/components/FetchNodeConfigPanel.tsx +4 -1
- package/src/graph/blueprint-graph.ts +5 -1
- package/src/graph/document.ts +46 -8
- package/src/graph/sync-nodes.ts +3 -1
- package/src/hooks/useBlueprintDebugSession.ts +24 -22
- package/src/hooks/useBlueprintFlowColorMode.ts +30 -6
- package/src/runtime/document-to-runnable-graph.ts +9 -6
- package/.pnpm-cache/metadata/registry.npmjs.org/@esbuild/aix-ppc64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@esbuild/android-arm.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@esbuild/android-arm64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@esbuild/android-x64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@esbuild/darwin-arm64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@esbuild/darwin-x64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@esbuild/freebsd-arm64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@esbuild/freebsd-x64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@esbuild/linux-arm.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@esbuild/linux-arm64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@esbuild/linux-ia32.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@esbuild/linux-loong64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@esbuild/linux-mips64el.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@esbuild/linux-ppc64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@esbuild/linux-riscv64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@esbuild/linux-s390x.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@esbuild/linux-x64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@esbuild/netbsd-x64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@esbuild/openbsd-x64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@esbuild/sunos-x64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@esbuild/win32-arm64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@esbuild/win32-ia32.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@esbuild/win32-x64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@rollup/rollup-android-arm-eabi.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@rollup/rollup-android-arm64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@rollup/rollup-darwin-arm64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@rollup/rollup-darwin-x64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@rollup/rollup-freebsd-arm64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@rollup/rollup-freebsd-x64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@rollup/rollup-linux-arm64-gnu.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@rollup/rollup-linux-arm64-musl.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@rollup/rollup-linux-riscv64-musl.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@rollup/rollup-linux-s390x-gnu.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@rollup/rollup-linux-x64-gnu.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@rollup/rollup-linux-x64-musl.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@rollup/rollup-win32-arm64-msvc.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@rollup/rollup-win32-ia32-msvc.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/@rollup/rollup-win32-x64-msvc.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/eslint.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/fsevents.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/react-dom.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/react-is.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/turbo-darwin-64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/turbo-darwin-arm64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/turbo-linux-64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/turbo-linux-arm64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/turbo-windows-64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/turbo-windows-arm64.json +0 -1
- package/.pnpm-cache/metadata/registry.npmjs.org/typescript.json +0 -1
- package/.turbo/turbo-lint.log +0 -4
- package/dist/assets/index-CneNgzWb.css +0 -1
- package/dist/assets/index-DsVhHV0-.js +0 -226
- package/dist/index.html +0 -14
package/README.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# @arronqzy/react-blueprint
|
|
2
|
+
|
|
3
|
+
Abuilder 的**蓝图编辑器** React 包,基于 [React Flow](https://reactflow.dev/) 提供节点连线编辑、调试执行与蓝图库管理。
|
|
4
|
+
|
|
5
|
+
## 功能概览
|
|
6
|
+
|
|
7
|
+
- **可视化蓝图**:拖拽节点、连线、对齐、视口平移缩放
|
|
8
|
+
- **节点类型**:逻辑、请求、时钟、JSON、子蓝图引用等(由 `blueprint-dsl` 定义行为)
|
|
9
|
+
- **调试执行**:单步/连续调试、执行轨迹、连线信号高亮、时钟节点进度
|
|
10
|
+
- **蓝图库**:IndexedDB 存储、导入导出、元数据编辑
|
|
11
|
+
- **执行日志**:运行记录持久化、导出与清理策略
|
|
12
|
+
- **视图联动**:生命周期钩子向视图节点写入 Scope
|
|
13
|
+
|
|
14
|
+
## 安装
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm add @arronqzy/react-blueprint @xyflow/react
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import "@arronqzy/react-blueprint/blueprint.css";
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 使用
|
|
25
|
+
|
|
26
|
+
### 蓝图画布
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
import { useState } from "react";
|
|
30
|
+
import { BluePrintReactRoot, BlueprintGraph } from "@arronqzy/react-blueprint";
|
|
31
|
+
import "@arronqzy/react-blueprint/blueprint.css";
|
|
32
|
+
|
|
33
|
+
function BlueprintEditor() {
|
|
34
|
+
const [graph, setGraph] = useState(() => BlueprintGraph.empty());
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<BluePrintReactRoot
|
|
38
|
+
graph={graph}
|
|
39
|
+
onGraphChange={setGraph}
|
|
40
|
+
selectedNodeId={null}
|
|
41
|
+
onSelectNode={() => {}}
|
|
42
|
+
/>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 文档转可执行图
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { documentToRunnableGraph } from "@arronqzy/react-blueprint";
|
|
51
|
+
|
|
52
|
+
const runnable = documentToRunnableGraph(document, { libraryNameById });
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 调试会话
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
import { useBlueprintDebugSession } from "@arronqzy/react-blueprint";
|
|
59
|
+
|
|
60
|
+
const debug = useBlueprintDebugSession({
|
|
61
|
+
graph,
|
|
62
|
+
blueprintId,
|
|
63
|
+
blueprintName: "我的蓝图",
|
|
64
|
+
resolveLibraryBlueprint,
|
|
65
|
+
onViewScopeUpdate: (ids, scope) => { /* 回写视图 Scope */ },
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 页面生命周期(与视图集成)
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
import { useBlueprintPageLifecycle } from "@arronqzy/react-blueprint";
|
|
73
|
+
|
|
74
|
+
useBlueprintPageLifecycle({
|
|
75
|
+
graph,
|
|
76
|
+
active: blueprintOpen,
|
|
77
|
+
onViewScopeUpdate,
|
|
78
|
+
resolveLibraryBlueprint,
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## 主要导出
|
|
83
|
+
|
|
84
|
+
| 模块 | 说明 |
|
|
85
|
+
|------|------|
|
|
86
|
+
| `BluePrintReactRoot` | 蓝图主画布 |
|
|
87
|
+
| `BlueprintGraph` | 图数据结构(`src/graph`) |
|
|
88
|
+
| `documentToRunnableGraph` | 文档 → 运行时图 |
|
|
89
|
+
| `useBlueprintDebugSession` | 调试工具栏与会话 |
|
|
90
|
+
| `useBlueprintPageLifecycle` | 挂载/卸载时启停蓝图 |
|
|
91
|
+
| `BlueprintNodeConfigSidebar` | 节点配置侧栏 |
|
|
92
|
+
| `BlueprintPanelToolbar` | 蓝图工具栏 |
|
|
93
|
+
| `blueprint-library-db` | 蓝图库 IndexedDB API |
|
|
94
|
+
|
|
95
|
+
## 依赖关系
|
|
96
|
+
|
|
97
|
+
- `@arronqzy/blueprint-dsl` — 节点定义与执行引擎
|
|
98
|
+
- `@arronqzy/react-rx-store` — 与画布状态订阅
|
|
99
|
+
- `@arronqzy/ui` — UI 组件
|
|
100
|
+
|
|
101
|
+
## 许可证
|
|
102
|
+
|
|
103
|
+
ISC
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arronqzy/react-blueprint",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"exports": {
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
"dayjs": "^1.11.13",
|
|
13
13
|
"react-dom": "^19",
|
|
14
14
|
"@xyflow/react": "^12.9.3",
|
|
15
|
-
"@arronqzy/blueprint-dsl": "
|
|
16
|
-
"@arronqzy/react-rx-store": "1.
|
|
17
|
-
"@arronqzy/ui": "
|
|
15
|
+
"@arronqzy/blueprint-dsl": "1.0.3",
|
|
16
|
+
"@arronqzy/react-rx-store": "1.1.2",
|
|
17
|
+
"@arronqzy/ui": "1.0.2"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@types/react": "^19.0.1",
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
"eslint": "^8.57.0",
|
|
28
28
|
"typescript": "^5.5.4",
|
|
29
29
|
"vite": "^5.1.4",
|
|
30
|
-
"@arronqzy/tailwind": "
|
|
30
|
+
"@arronqzy/tailwind": "1.0.2",
|
|
31
31
|
"@arronqzy/eslint-config": "0.0.0",
|
|
32
|
-
"@arronqzy/typescript-config": "
|
|
32
|
+
"@arronqzy/typescript-config": "1.0.0"
|
|
33
33
|
},
|
|
34
34
|
"keywords": [],
|
|
35
35
|
"author": "",
|
|
@@ -87,6 +87,8 @@ export function BlueprintNodeConfigSidebar({
|
|
|
87
87
|
|
|
88
88
|
useEffect(() => {
|
|
89
89
|
if (configSource !== "view") return;
|
|
90
|
+
// 视图画布尚未就绪时不清理,避免误删有效绑定导致绑定节点「执行了但不写 scope」
|
|
91
|
+
if (viewElementOptions.length === 0) return;
|
|
90
92
|
const linked = resolveViewElementIds(node);
|
|
91
93
|
if (linked.length === 0) return;
|
|
92
94
|
const pruned = pruneViewElementIds(linked, existingViewElementIdSet);
|
|
@@ -103,6 +105,7 @@ export function BlueprintNodeConfigSidebar({
|
|
|
103
105
|
node.viewElementId,
|
|
104
106
|
node.viewElementIds,
|
|
105
107
|
onUpdateNode,
|
|
108
|
+
viewElementOptions.length,
|
|
106
109
|
]);
|
|
107
110
|
|
|
108
111
|
return (
|
package/src/blueprint.css
CHANGED
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
--xy-edge-stroke-selected: #1d4ed8;
|
|
20
20
|
--xy-connectionline-stroke: #2563eb;
|
|
21
21
|
--xy-connectionline-stroke-width: 2.5;
|
|
22
|
+
--xy-handle-background-color: hsl(var(--primary));
|
|
23
|
+
--xy-handle-border-color: hsl(var(--background));
|
|
22
24
|
background-color: transparent;
|
|
23
25
|
}
|
|
24
26
|
|
|
@@ -174,11 +176,11 @@
|
|
|
174
176
|
height: 10px;
|
|
175
177
|
min-width: 10px;
|
|
176
178
|
min-height: 10px;
|
|
177
|
-
border: 2px solid hsl(var(--background));
|
|
179
|
+
border: 2px solid hsl(var(--background)) !important;
|
|
178
180
|
border-radius: 9999px;
|
|
179
|
-
background: hsl(var(--
|
|
181
|
+
background-color: hsl(var(--foreground) / 0.42) !important;
|
|
180
182
|
transition:
|
|
181
|
-
background 0.15s ease,
|
|
183
|
+
background-color 0.15s ease,
|
|
182
184
|
border-color 0.15s ease,
|
|
183
185
|
box-shadow 0.15s ease;
|
|
184
186
|
}
|
|
@@ -186,30 +188,34 @@
|
|
|
186
188
|
.bp-canvas .react-flow__handle.bp-flow-handle:hover,
|
|
187
189
|
.bp-flow .react-flow__handle.bp-flow-handle:hover,
|
|
188
190
|
[data-workspace-region="blueprint"] .react-flow__handle.bp-flow-handle:hover {
|
|
189
|
-
background: hsl(var(--primary));
|
|
190
|
-
border-color: hsl(var(--background));
|
|
191
|
+
background-color: hsl(var(--primary)) !important;
|
|
192
|
+
border-color: hsl(var(--background)) !important;
|
|
191
193
|
box-shadow: 0 0 0 3px hsl(var(--primary) / 0.28);
|
|
192
194
|
}
|
|
193
195
|
|
|
194
196
|
.bp-canvas .react-flow__handle.bp-flow-handle--target,
|
|
195
197
|
.bp-flow .react-flow__handle.bp-flow-handle--target,
|
|
196
198
|
[data-workspace-region="blueprint"] .react-flow__handle.bp-flow-handle--target {
|
|
197
|
-
background: hsl(var(--
|
|
199
|
+
background-color: hsl(var(--foreground) / 0.48) !important;
|
|
198
200
|
}
|
|
199
201
|
|
|
200
202
|
.bp-canvas .react-flow__handle.bp-flow-handle--source,
|
|
201
203
|
.bp-flow .react-flow__handle.bp-flow-handle--source,
|
|
202
204
|
[data-workspace-region="blueprint"] .react-flow__handle.bp-flow-handle--source {
|
|
203
|
-
background: hsl(var(--primary) / 0.
|
|
205
|
+
background-color: hsl(var(--primary) / 0.72) !important;
|
|
204
206
|
}
|
|
205
207
|
|
|
206
208
|
.bp-node--selected .bp-flow-handle {
|
|
207
|
-
border-color: hsl(var(--card));
|
|
209
|
+
border-color: hsl(var(--card)) !important;
|
|
208
210
|
box-shadow: 0 0 0 2px hsl(var(--primary) / 0.35);
|
|
209
211
|
}
|
|
210
212
|
|
|
213
|
+
.bp-node--selected .bp-flow-handle--target {
|
|
214
|
+
background-color: hsl(var(--foreground) / 0.55) !important;
|
|
215
|
+
}
|
|
216
|
+
|
|
211
217
|
.bp-node--selected .bp-flow-handle--source {
|
|
212
|
-
background: hsl(var(--primary));
|
|
218
|
+
background-color: hsl(var(--primary)) !important;
|
|
213
219
|
}
|
|
214
220
|
|
|
215
221
|
.bp-node--execution-true .bp-node-card {
|
|
@@ -225,11 +231,11 @@
|
|
|
225
231
|
}
|
|
226
232
|
|
|
227
233
|
.bp-node--execution-true .bp-flow-handle--source {
|
|
228
|
-
background: #16a34a;
|
|
234
|
+
background-color: #16a34a !important;
|
|
229
235
|
}
|
|
230
236
|
|
|
231
237
|
.bp-node--execution-true .bp-flow-handle--target {
|
|
232
|
-
background: rgb(22 163 74 / 0.55);
|
|
238
|
+
background-color: rgb(22 163 74 / 0.55) !important;
|
|
233
239
|
}
|
|
234
240
|
|
|
235
241
|
.bp-node--execution-false .bp-node-card {
|
|
@@ -245,11 +251,11 @@
|
|
|
245
251
|
}
|
|
246
252
|
|
|
247
253
|
.bp-node--execution-false .bp-flow-handle--source {
|
|
248
|
-
background: hsl(var(--destructive));
|
|
254
|
+
background-color: hsl(var(--destructive)) !important;
|
|
249
255
|
}
|
|
250
256
|
|
|
251
257
|
.bp-node--execution-false .bp-flow-handle--target {
|
|
252
|
-
background: hsl(var(--destructive) / 0.55);
|
|
258
|
+
background-color: hsl(var(--destructive) / 0.55) !important;
|
|
253
259
|
}
|
|
254
260
|
|
|
255
261
|
/* 生命周期节点无输入口:隐藏任何左侧/目标连接点(含旧数据产生的幽灵 handle) */
|
|
@@ -267,13 +273,13 @@
|
|
|
267
273
|
.bp-canvas .react-flow__handle.bp-flow-handle--signal,
|
|
268
274
|
.bp-flow .react-flow__handle.bp-flow-handle--signal,
|
|
269
275
|
[data-workspace-region="blueprint"] .react-flow__handle.bp-flow-handle--signal {
|
|
270
|
-
background: hsl(38 92% 50% / 0.75);
|
|
276
|
+
background-color: hsl(38 92% 50% / 0.75) !important;
|
|
271
277
|
width: 8px;
|
|
272
278
|
height: 8px;
|
|
273
279
|
}
|
|
274
280
|
|
|
275
281
|
.bp-node--selected .bp-flow-handle--signal {
|
|
276
|
-
background: hsl(38 92% 50%);
|
|
282
|
+
background-color: hsl(38 92% 50%) !important;
|
|
277
283
|
}
|
|
278
284
|
|
|
279
285
|
/* 右键菜单 */
|
|
@@ -53,8 +53,8 @@ function IconClearDb({ className }: { className?: string }) {
|
|
|
53
53
|
aria-hidden="true"
|
|
54
54
|
>
|
|
55
55
|
<ellipse cx="12" cy="6" rx="7" ry="2.5" />
|
|
56
|
-
<path d="M5 6v12c0 1.5 3.
|
|
57
|
-
<path d="M5 12c0 1.5 3.
|
|
56
|
+
<path d="M5 6v12c0 1.5 3.134 2.5 7 2.5s7-1.343 7-2.5V6" />
|
|
57
|
+
<path d="M5 12c0 1.5 3.134 2.5 7 2.5s7-1.343 7-2.5" />
|
|
58
58
|
<path d="m16 16 4 4M20 16l-4 4" />
|
|
59
59
|
</svg>
|
|
60
60
|
);
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
FETCH_CREDENTIALS,
|
|
20
20
|
FETCH_HTTP_METHODS,
|
|
21
21
|
FETCH_MODES,
|
|
22
|
+
FETCH_NODE_TYPE,
|
|
22
23
|
FETCH_REDIRECTS,
|
|
23
24
|
FETCH_RESPONSE_TYPES,
|
|
24
25
|
} from "@arronqzy/blueprint-dsl";
|
|
@@ -238,8 +239,10 @@ function patchFetchConfig(
|
|
|
238
239
|
patch: Partial<FetchRequestConfig>
|
|
239
240
|
) {
|
|
240
241
|
return {
|
|
241
|
-
|
|
242
|
+
role: "fetch" as const,
|
|
243
|
+
nodeType: FETCH_NODE_TYPE,
|
|
242
244
|
configSource: "fetch" as const,
|
|
245
|
+
fetchConfig: { ...resolveNodeFetchConfig(node), ...patch },
|
|
243
246
|
};
|
|
244
247
|
}
|
|
245
248
|
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
resolveNodeFetchConfig,
|
|
9
9
|
resolveNodeJsonConfig,
|
|
10
10
|
resolveNodeLogicConfig,
|
|
11
|
+
resolveRunnableNodeType,
|
|
11
12
|
sanitizeBlueprintDocument,
|
|
12
13
|
type BlueprintDocument,
|
|
13
14
|
type BlueprintGraphEdge,
|
|
@@ -250,7 +251,10 @@ export class BlueprintGraph {
|
|
|
250
251
|
...patch.clockConfig,
|
|
251
252
|
};
|
|
252
253
|
}
|
|
253
|
-
return
|
|
254
|
+
return {
|
|
255
|
+
...nextNode,
|
|
256
|
+
nodeType: resolveRunnableNodeType(nextNode),
|
|
257
|
+
};
|
|
254
258
|
}),
|
|
255
259
|
});
|
|
256
260
|
}
|
package/src/graph/document.ts
CHANGED
|
@@ -89,19 +89,50 @@ export function pruneViewElementIds(
|
|
|
89
89
|
export function resolveBlueprintConfigSource(
|
|
90
90
|
node: Pick<
|
|
91
91
|
BlueprintGraphNode,
|
|
92
|
-
"role" | "configSource" | "viewElementId" | "viewElementIds"
|
|
92
|
+
"role" | "nodeType" | "configSource" | "viewElementId" | "viewElementIds"
|
|
93
93
|
>
|
|
94
94
|
): BlueprintConfigSource {
|
|
95
95
|
if (node.configSource) return node.configSource;
|
|
96
|
-
if (resolveViewElementIds(node).length > 0) return "view";
|
|
97
96
|
if (node.role === "lifecycle") return "lifecycle";
|
|
98
97
|
if (node.role === "clock") return "clock";
|
|
99
98
|
if (node.role === "and") return "and";
|
|
100
99
|
if (node.role === "fetch") return "fetch";
|
|
101
100
|
if (node.role === "json") return "json";
|
|
101
|
+
if (node.nodeType === FETCH_NODE_TYPE) return "fetch";
|
|
102
|
+
if (node.nodeType === JSON_NODE_TYPE) return "json";
|
|
103
|
+
if (node.nodeType === CLOCK_NODE_TYPE) return "clock";
|
|
104
|
+
if (node.nodeType === VIEW_NODE_TYPE) return "view";
|
|
105
|
+
if (resolveViewElementIds(node).length > 0) return "view";
|
|
102
106
|
return node.role === "logic" ? "logic" : "blueprint";
|
|
103
107
|
}
|
|
104
108
|
|
|
109
|
+
/** 可执行图节点类型:与配置类型对齐,避免文档里残留旧 nodeType */
|
|
110
|
+
export function resolveRunnableNodeType(
|
|
111
|
+
node: Pick<
|
|
112
|
+
BlueprintGraphNode,
|
|
113
|
+
"role" | "nodeType" | "configSource" | "viewElementId" | "viewElementIds"
|
|
114
|
+
>
|
|
115
|
+
): string {
|
|
116
|
+
switch (resolveBlueprintConfigSource(node)) {
|
|
117
|
+
case "view":
|
|
118
|
+
return VIEW_NODE_TYPE;
|
|
119
|
+
case "lifecycle":
|
|
120
|
+
return LIFECYCLE_NODE_TYPE;
|
|
121
|
+
case "clock":
|
|
122
|
+
return CLOCK_NODE_TYPE;
|
|
123
|
+
case "and":
|
|
124
|
+
return AND_NODE_TYPE;
|
|
125
|
+
case "fetch":
|
|
126
|
+
return FETCH_NODE_TYPE;
|
|
127
|
+
case "json":
|
|
128
|
+
return JSON_NODE_TYPE;
|
|
129
|
+
case "logic":
|
|
130
|
+
return DEFAULT_LOGIC_NODE_TYPE;
|
|
131
|
+
default:
|
|
132
|
+
return BLUEPRINT_NODE_TYPE;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
105
136
|
/** 画布节点顶部(拖拽区)展示的配置类型文案 */
|
|
106
137
|
export const BLUEPRINT_CONFIG_TYPE_LABELS: Record<
|
|
107
138
|
BlueprintConfigSource,
|
|
@@ -120,7 +151,7 @@ export const BLUEPRINT_CONFIG_TYPE_LABELS: Record<
|
|
|
120
151
|
export function resolveBlueprintNodeTypeLabel(
|
|
121
152
|
node: Pick<
|
|
122
153
|
BlueprintGraphNode,
|
|
123
|
-
"role" | "configSource" | "viewElementId" | "viewElementIds"
|
|
154
|
+
"role" | "nodeType" | "configSource" | "viewElementId" | "viewElementIds"
|
|
124
155
|
>
|
|
125
156
|
): string {
|
|
126
157
|
return BLUEPRINT_CONFIG_TYPE_LABELS[resolveBlueprintConfigSource(node)];
|
|
@@ -221,11 +252,9 @@ export function sanitizeBlueprintDocument(
|
|
|
221
252
|
viewElementId: undefined,
|
|
222
253
|
};
|
|
223
254
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
next
|
|
227
|
-
) {
|
|
228
|
-
next = { ...next, nodeType: VIEW_NODE_TYPE };
|
|
255
|
+
const runnableNodeType = resolveRunnableNodeType(next);
|
|
256
|
+
if (next.nodeType !== runnableNodeType) {
|
|
257
|
+
next = { ...next, nodeType: runnableNodeType };
|
|
229
258
|
}
|
|
230
259
|
if (next.role === "lifecycle") {
|
|
231
260
|
return { ...next, configSource: "lifecycle" as const };
|
|
@@ -233,6 +262,15 @@ export function sanitizeBlueprintDocument(
|
|
|
233
262
|
if (next.role === "clock") {
|
|
234
263
|
return { ...next, configSource: "clock" as const };
|
|
235
264
|
}
|
|
265
|
+
if (next.role === "fetch") {
|
|
266
|
+
return { ...next, configSource: "fetch" as const };
|
|
267
|
+
}
|
|
268
|
+
if (next.role === "json") {
|
|
269
|
+
return { ...next, configSource: "json" as const };
|
|
270
|
+
}
|
|
271
|
+
if (next.role === "and") {
|
|
272
|
+
return { ...next, configSource: "and" as const };
|
|
273
|
+
}
|
|
236
274
|
if (next.configSource === "lifecycle" || next.configSource === "clock") {
|
|
237
275
|
return { ...next, configSource: undefined };
|
|
238
276
|
}
|
package/src/graph/sync-nodes.ts
CHANGED
|
@@ -42,6 +42,8 @@ export function nodeStructureSignature(
|
|
|
42
42
|
lifecyclePhase?: string;
|
|
43
43
|
libraryBlueprintId?: string;
|
|
44
44
|
nodeType?: string;
|
|
45
|
+
viewElementId?: string;
|
|
46
|
+
viewElementIds?: string[];
|
|
45
47
|
fetchConfig?: { url?: string; method?: string; apiBaseUrl?: string; swaggerDocsUrl?: string };
|
|
46
48
|
jsonConfig?: { jsonString?: string };
|
|
47
49
|
logicConfig?: { sourceCode?: string };
|
|
@@ -51,7 +53,7 @@ export function nodeStructureSignature(
|
|
|
51
53
|
return nodes
|
|
52
54
|
.map(
|
|
53
55
|
(n) =>
|
|
54
|
-
`${n.id}:${n.role}:${n.label}:${n.configSource ?? ""}:${n.lifecyclePhase ?? ""}:${n.libraryBlueprintId ?? ""}:${n.nodeType ?? ""}:${n.fetchConfig?.url ?? ""}:${n.fetchConfig?.method ?? ""}:${n.fetchConfig?.apiBaseUrl ?? ""}:${n.fetchConfig?.swaggerDocsUrl ?? ""}:${n.jsonConfig?.jsonString ?? ""}:${n.logicConfig?.sourceCode ?? ""}:${n.clockConfig?.intervalSeconds ?? ""}:${n.clockConfig?.timeFormat ?? ""}:${n.clockConfig?.outputCount ?? ""}:${n.clockConfig?.emitImmediately ?? ""}`
|
|
56
|
+
`${n.id}:${n.role}:${n.label}:${n.configSource ?? ""}:${n.lifecyclePhase ?? ""}:${n.libraryBlueprintId ?? ""}:${n.nodeType ?? ""}:${(n.viewElementIds ?? (n.viewElementId ? [n.viewElementId] : [])).join(",")}:${n.fetchConfig?.url ?? ""}:${n.fetchConfig?.method ?? ""}:${n.fetchConfig?.apiBaseUrl ?? ""}:${n.fetchConfig?.swaggerDocsUrl ?? ""}:${n.jsonConfig?.jsonString ?? ""}:${n.logicConfig?.sourceCode ?? ""}:${n.clockConfig?.intervalSeconds ?? ""}:${n.clockConfig?.timeFormat ?? ""}:${n.clockConfig?.outputCount ?? ""}:${n.clockConfig?.emitImmediately ?? ""}`
|
|
55
57
|
)
|
|
56
58
|
.sort()
|
|
57
59
|
.join("|");
|
|
@@ -112,16 +112,22 @@ export function useBlueprintDebugSession({
|
|
|
112
112
|
[graph.document, libraryNameById]
|
|
113
113
|
);
|
|
114
114
|
|
|
115
|
-
const
|
|
115
|
+
const syncRunnerGraphConfig = useCallback(() => {
|
|
116
116
|
const runner = runnerRef.current;
|
|
117
117
|
if (!runner?.isDebugSessionActive()) return;
|
|
118
118
|
runner.updateGraph(buildRunnableGraph());
|
|
119
119
|
if (selectedLifecycleNodeId) {
|
|
120
120
|
runner.refreshDebugLifecycleScope(selectedLifecycleNodeId);
|
|
121
121
|
}
|
|
122
|
-
runner.refreshPendingQueueFromLatestGraph();
|
|
123
122
|
}, [buildRunnableGraph, selectedLifecycleNodeId]);
|
|
124
123
|
|
|
124
|
+
const syncRunnerWithLatestGraph = useCallback(() => {
|
|
125
|
+
syncRunnerGraphConfig();
|
|
126
|
+
const runner = runnerRef.current;
|
|
127
|
+
if (!runner?.isDebugSessionActive()) return;
|
|
128
|
+
runner.refreshPendingQueueFromLatestGraph();
|
|
129
|
+
}, [syncRunnerGraphConfig]);
|
|
130
|
+
|
|
125
131
|
const resolveBlueprintName = useCallback(
|
|
126
132
|
(id: string) => libraryNameById?.get(id) ?? id,
|
|
127
133
|
[libraryNameById]
|
|
@@ -242,12 +248,9 @@ export function useBlueprintDebugSession({
|
|
|
242
248
|
useEffect(() => {
|
|
243
249
|
const runner = runnerRef.current;
|
|
244
250
|
if (!runner?.isDebugSessionActive()) return;
|
|
245
|
-
|
|
246
|
-
if (selectedLifecycleNodeId) {
|
|
247
|
-
runner.refreshDebugLifecycleScope(selectedLifecycleNodeId);
|
|
248
|
-
}
|
|
251
|
+
syncRunnerGraphConfig();
|
|
249
252
|
runner.refreshPendingQueueFromLatestGraph();
|
|
250
|
-
}, [
|
|
253
|
+
}, [graphDebugSig, syncRunnerGraphConfig]);
|
|
251
254
|
|
|
252
255
|
useEffect(() => {
|
|
253
256
|
if (running) return;
|
|
@@ -277,24 +280,14 @@ export function useBlueprintDebugSession({
|
|
|
277
280
|
try {
|
|
278
281
|
const runner = beginRun();
|
|
279
282
|
if (!runner) return;
|
|
283
|
+
runner.updateGraph(buildRunnableGraph());
|
|
284
|
+
runner.refreshDebugLifecycleScope(selectedLifecycleNodeId);
|
|
280
285
|
const labels = buildNodeLabelMap(graph);
|
|
281
286
|
const onProgress = (trace: ExecutionTraceEntry[]) => {
|
|
282
287
|
setEntries([...trace]);
|
|
283
288
|
};
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
await runner.debugStep(labels, onProgress);
|
|
287
|
-
const trace = runner.getTraceEntries();
|
|
288
|
-
setEntries(trace);
|
|
289
|
-
if (shouldHaltDebugOnFalseSignal(trace, allowFalseSignalPropagation)) {
|
|
290
|
-
setChainComplete(true);
|
|
291
|
-
break;
|
|
292
|
-
}
|
|
293
|
-
await new Promise<void>((resolve) => {
|
|
294
|
-
requestAnimationFrame(() => resolve());
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
const result = runner.getTraceEntries();
|
|
289
|
+
const result = await runner.debugRunAll(labels, onProgress);
|
|
290
|
+
setEntries(result);
|
|
298
291
|
setChainComplete(
|
|
299
292
|
shouldHaltDebugOnFalseSignal(result, allowFalseSignalPropagation) ||
|
|
300
293
|
(runner.isDebugQueueEmpty() && result.length > 0)
|
|
@@ -304,7 +297,16 @@ export function useBlueprintDebugSession({
|
|
|
304
297
|
} finally {
|
|
305
298
|
setRunning(false);
|
|
306
299
|
}
|
|
307
|
-
}, [
|
|
300
|
+
}, [
|
|
301
|
+
allowFalseSignalPropagation,
|
|
302
|
+
beginRun,
|
|
303
|
+
buildRunRecord,
|
|
304
|
+
buildRunnableGraph,
|
|
305
|
+
graph,
|
|
306
|
+
persistRunIfNeeded,
|
|
307
|
+
selectedLifecycleNodeId,
|
|
308
|
+
validateBlueprintGraph,
|
|
309
|
+
]);
|
|
308
310
|
|
|
309
311
|
const stepNext = useCallback(async () => {
|
|
310
312
|
if (
|
|
@@ -1,8 +1,32 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useSyncExternalStore } from "react";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
export type BlueprintColorMode = "light" | "dark";
|
|
4
|
+
|
|
5
|
+
function readDocumentColorMode(): BlueprintColorMode {
|
|
6
|
+
if (typeof document === "undefined") return "light";
|
|
7
|
+
const root = document.documentElement;
|
|
8
|
+
if (root.classList.contains("dark")) return "dark";
|
|
9
|
+
if (root.classList.contains("light")) return "light";
|
|
10
|
+
const dataTheme = root.dataset.theme;
|
|
11
|
+
if (dataTheme === "dark" || dataTheme === "light") return dataTheme;
|
|
12
|
+
return "light";
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function subscribeDocumentColorMode(onChange: () => void) {
|
|
16
|
+
const root = document.documentElement;
|
|
17
|
+
const observer = new MutationObserver(onChange);
|
|
18
|
+
observer.observe(root, {
|
|
19
|
+
attributes: true,
|
|
20
|
+
attributeFilter: ["class", "data-theme"],
|
|
21
|
+
});
|
|
22
|
+
return () => observer.disconnect();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** 与 document 上的全局主题(class / data-theme)对齐,避免与 panel 手动切换脱节 */
|
|
26
|
+
export function useBlueprintFlowColorMode(): BlueprintColorMode {
|
|
27
|
+
return useSyncExternalStore(
|
|
28
|
+
subscribeDocumentColorMode,
|
|
29
|
+
readDocumentColorMode,
|
|
30
|
+
() => "light"
|
|
31
|
+
);
|
|
8
32
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
FETCH_NODE_TYPE,
|
|
3
3
|
type RunnableGraph,
|
|
4
4
|
} from "@arronqzy/blueprint-dsl";
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
|
-
|
|
7
|
+
resolveNodeFetchConfig,
|
|
8
|
+
resolveRunnableNodeType,
|
|
8
9
|
resolveViewElementIds,
|
|
9
10
|
type BlueprintDocument,
|
|
10
11
|
} from "../graph/document";
|
|
@@ -17,17 +18,19 @@ export function documentToRunnableGraph(
|
|
|
17
18
|
): RunnableGraph {
|
|
18
19
|
return {
|
|
19
20
|
nodes: document.nodes.map((node) => {
|
|
20
|
-
const configSource = resolveBlueprintConfigSource(node);
|
|
21
21
|
const viewElementIds = resolveViewElementIds(node);
|
|
22
|
+
const nodeType = resolveRunnableNodeType(node);
|
|
22
23
|
return {
|
|
23
24
|
id: node.id,
|
|
24
|
-
nodeType
|
|
25
|
-
configSource === "view" ? VIEW_NODE_TYPE : node.nodeType,
|
|
25
|
+
nodeType,
|
|
26
26
|
lifecyclePhase: node.lifecyclePhase,
|
|
27
27
|
libraryBlueprintId: node.libraryBlueprintId,
|
|
28
28
|
viewElementIds:
|
|
29
29
|
viewElementIds.length > 0 ? viewElementIds : undefined,
|
|
30
|
-
fetchConfig:
|
|
30
|
+
fetchConfig:
|
|
31
|
+
nodeType === FETCH_NODE_TYPE
|
|
32
|
+
? resolveNodeFetchConfig(node)
|
|
33
|
+
: node.fetchConfig,
|
|
31
34
|
jsonConfig: node.jsonConfig,
|
|
32
35
|
logicConfig: node.logicConfig,
|
|
33
36
|
clockConfig: node.clockConfig,
|