@arronqzy/vue-blueprint 0.1.0
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 +50 -0
- package/package.json +44 -0
- package/src/BlueprintCanvasContext.ts +71 -0
- package/src/BlueprintNodeConfigSidebar.vue +338 -0
- package/src/blueprint.css +327 -0
- package/src/blueprintNodeTypes.ts +20 -0
- package/src/components/BluePrintVueRoot.vue +73 -0
- package/src/components/BlueprintCanvas.vue +220 -0
- package/src/components/BlueprintContextMenu.vue +114 -0
- package/src/components/BlueprintExecutionLogPanel.vue +294 -0
- package/src/components/BlueprintMetaDialog.vue +80 -0
- package/src/components/BlueprintNodeSwitchTaskDialog.vue +41 -0
- package/src/components/ClockNodeConfigPanel.vue +124 -0
- package/src/components/FetchNodeConfigPanel.vue +559 -0
- package/src/components/FetchUrlAutocomplete.vue +174 -0
- package/src/components/JsonNodeConfigPanel.vue +73 -0
- package/src/components/LogicNodeConfigPanel.vue +73 -0
- package/src/components/ViewElementMultiSelect.vue +50 -0
- package/src/composables/useBlueprintDebugSession.ts +441 -0
- package/src/composables/useBlueprintFlowState.ts +486 -0
- package/src/composables/useBlueprintFlowViewport.ts +65 -0
- package/src/composables/useBlueprintNodeSelectionGuard.ts +41 -0
- package/src/composables/useBlueprintPageLifecycle.ts +244 -0
- package/src/createBlueprintEdgeTypes.ts +10 -0
- package/src/edges/BlueprintSmoothEdge.vue +31 -0
- package/src/env.d.ts +7 -0
- package/src/fetch-config-task-store.ts +206 -0
- package/src/flowCoordinates.ts +19 -0
- package/src/flowDefaults.ts +9 -0
- package/src/graph/blueprint-graph.ts +265 -0
- package/src/graph/document.ts +422 -0
- package/src/graph/index.ts +7 -0
- package/src/graph/node-summary.ts +88 -0
- package/src/graph/node-types.ts +9 -0
- package/src/graph/sync-edges.ts +69 -0
- package/src/graph/sync-nodes.ts +110 -0
- package/src/graph/vue-flow-adapter.ts +127 -0
- package/src/index.ts +37 -0
- package/src/library/blueprint-io.ts +108 -0
- package/src/library/blueprint-library-db.ts +112 -0
- package/src/library/execution-log-db.ts +171 -0
- package/src/library/execution-log-settings.ts +50 -0
- package/src/library/swagger-docs.ts +56 -0
- package/src/library/types.ts +35 -0
- package/src/nodes/AndFlowNode.vue +60 -0
- package/src/nodes/BlueprintFlowNode.vue +26 -0
- package/src/nodes/BlueprintNodeCard.vue +155 -0
- package/src/nodes/BlueprintNodeShell.vue +70 -0
- package/src/nodes/ClockFlowNode.vue +60 -0
- package/src/nodes/FetchFlowNode.vue +26 -0
- package/src/nodes/JsonFlowNode.vue +26 -0
- package/src/nodes/LifecycleFlowNode.vue +45 -0
- package/src/nodes/LogicFlowNode.vue +26 -0
- package/src/runtime/document-to-runnable-graph.ts +51 -0
- package/src/runtime/execution-overlay.ts +169 -0
- package/src/types.ts +1 -0
- package/src/utils/cn.ts +3 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { NodeProps } from "@vue-flow/core";
|
|
3
|
+
import { resolveBlueprintNodeTypeLabel } from "../graph/document";
|
|
4
|
+
import { resolveBlueprintNodeSummary } from "../graph/node-summary";
|
|
5
|
+
import { useBlueprintNodeSelect } from "../BlueprintCanvasContext";
|
|
6
|
+
import { resolveBlueprintNodeExecutionTone } from "../runtime/execution-overlay";
|
|
7
|
+
import type { BlueprintFlowNodeData } from "../types";
|
|
8
|
+
import BlueprintNodeShell from "./BlueprintNodeShell.vue";
|
|
9
|
+
|
|
10
|
+
const props = defineProps<NodeProps<BlueprintFlowNodeData>>();
|
|
11
|
+
const onSelect = useBlueprintNodeSelect();
|
|
12
|
+
const nodeData = props.data;
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<BlueprintNodeShell
|
|
17
|
+
:node-id="props.id"
|
|
18
|
+
:label="nodeData.label"
|
|
19
|
+
:meta="resolveBlueprintNodeTypeLabel(nodeData)"
|
|
20
|
+
:subtitle="resolveBlueprintNodeSummary(nodeData)"
|
|
21
|
+
variant="fetch"
|
|
22
|
+
:selected="Boolean(nodeData.isSelected)"
|
|
23
|
+
:execution-tone="resolveBlueprintNodeExecutionTone(nodeData)"
|
|
24
|
+
@select="onSelect"
|
|
25
|
+
/>
|
|
26
|
+
</template>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { NodeProps } from "@vue-flow/core";
|
|
3
|
+
import { resolveBlueprintNodeTypeLabel } from "../graph/document";
|
|
4
|
+
import { resolveBlueprintNodeSummary } from "../graph/node-summary";
|
|
5
|
+
import { useBlueprintNodeSelect } from "../BlueprintCanvasContext";
|
|
6
|
+
import { resolveBlueprintNodeExecutionTone } from "../runtime/execution-overlay";
|
|
7
|
+
import type { BlueprintFlowNodeData } from "../types";
|
|
8
|
+
import BlueprintNodeShell from "./BlueprintNodeShell.vue";
|
|
9
|
+
|
|
10
|
+
const props = defineProps<NodeProps<BlueprintFlowNodeData>>();
|
|
11
|
+
const onSelect = useBlueprintNodeSelect();
|
|
12
|
+
const nodeData = props.data;
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<BlueprintNodeShell
|
|
17
|
+
:node-id="props.id"
|
|
18
|
+
:label="nodeData.label"
|
|
19
|
+
:meta="resolveBlueprintNodeTypeLabel(nodeData)"
|
|
20
|
+
:subtitle="resolveBlueprintNodeSummary(nodeData)"
|
|
21
|
+
variant="json"
|
|
22
|
+
:selected="Boolean(nodeData.isSelected)"
|
|
23
|
+
:execution-tone="resolveBlueprintNodeExecutionTone(nodeData)"
|
|
24
|
+
@select="onSelect"
|
|
25
|
+
/>
|
|
26
|
+
</template>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { Handle, Position, type NodeProps } from "@vue-flow/core";
|
|
3
|
+
import { resolveBlueprintNodeTypeLabel } from "../graph/document";
|
|
4
|
+
import { resolveBlueprintNodeSummary } from "../graph/node-summary";
|
|
5
|
+
import { useBlueprintNodeSelect } from "../BlueprintCanvasContext";
|
|
6
|
+
import { resolveBlueprintNodeExecutionTone } from "../runtime/execution-overlay";
|
|
7
|
+
import type { BlueprintFlowNodeData } from "../types";
|
|
8
|
+
import BlueprintNodeCard from "./BlueprintNodeCard.vue";
|
|
9
|
+
import { cn } from "../utils/cn";
|
|
10
|
+
|
|
11
|
+
const props = defineProps<NodeProps<BlueprintFlowNodeData>>();
|
|
12
|
+
const onSelect = useBlueprintNodeSelect();
|
|
13
|
+
const nodeData = props.data;
|
|
14
|
+
const executionTone = resolveBlueprintNodeExecutionTone(nodeData);
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<div
|
|
19
|
+
:class="
|
|
20
|
+
cn(
|
|
21
|
+
'bp-node bp-node--lifecycle',
|
|
22
|
+
executionTone === 'success' && 'bp-node--execution-true',
|
|
23
|
+
executionTone === 'error' && 'bp-node--execution-false'
|
|
24
|
+
)
|
|
25
|
+
"
|
|
26
|
+
>
|
|
27
|
+
<BlueprintNodeCard
|
|
28
|
+
:node-id="props.id"
|
|
29
|
+
:label="nodeData.label"
|
|
30
|
+
:meta="resolveBlueprintNodeTypeLabel(nodeData)"
|
|
31
|
+
:subtitle="resolveBlueprintNodeSummary(nodeData)"
|
|
32
|
+
variant="lifecycle"
|
|
33
|
+
:selected="Boolean(nodeData.isSelected)"
|
|
34
|
+
hide-leading-dot
|
|
35
|
+
@select="onSelect"
|
|
36
|
+
/>
|
|
37
|
+
<Handle
|
|
38
|
+
type="source"
|
|
39
|
+
:position="Position.Right"
|
|
40
|
+
id="out"
|
|
41
|
+
class="bp-flow-handle bp-flow-handle--source"
|
|
42
|
+
title="生命周期满足时输出真/假信号"
|
|
43
|
+
/>
|
|
44
|
+
</div>
|
|
45
|
+
</template>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { NodeProps } from "@vue-flow/core";
|
|
3
|
+
import { resolveBlueprintNodeTypeLabel } from "../graph/document";
|
|
4
|
+
import { resolveBlueprintNodeSummary } from "../graph/node-summary";
|
|
5
|
+
import { useBlueprintNodeSelect } from "../BlueprintCanvasContext";
|
|
6
|
+
import { resolveBlueprintNodeExecutionTone } from "../runtime/execution-overlay";
|
|
7
|
+
import type { BlueprintFlowNodeData } from "../types";
|
|
8
|
+
import BlueprintNodeShell from "./BlueprintNodeShell.vue";
|
|
9
|
+
|
|
10
|
+
const props = defineProps<NodeProps<BlueprintFlowNodeData>>();
|
|
11
|
+
const onSelect = useBlueprintNodeSelect();
|
|
12
|
+
const nodeData = props.data;
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<BlueprintNodeShell
|
|
17
|
+
:node-id="props.id"
|
|
18
|
+
:label="nodeData.label"
|
|
19
|
+
:meta="resolveBlueprintNodeTypeLabel(nodeData)"
|
|
20
|
+
:subtitle="resolveBlueprintNodeSummary(nodeData)"
|
|
21
|
+
variant="logic"
|
|
22
|
+
:selected="Boolean(nodeData.isSelected)"
|
|
23
|
+
:execution-tone="resolveBlueprintNodeExecutionTone(nodeData)"
|
|
24
|
+
@select="onSelect"
|
|
25
|
+
/>
|
|
26
|
+
</template>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FETCH_NODE_TYPE,
|
|
3
|
+
type RunnableGraph,
|
|
4
|
+
} from "@arronqzy/blueprint-dsl";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
resolveNodeFetchConfig,
|
|
8
|
+
resolveRunnableNodeType,
|
|
9
|
+
resolveViewElementIds,
|
|
10
|
+
type BlueprintDocument,
|
|
11
|
+
} from "../graph/document";
|
|
12
|
+
|
|
13
|
+
export function documentToRunnableGraph(
|
|
14
|
+
document: BlueprintDocument,
|
|
15
|
+
options?: {
|
|
16
|
+
libraryNameById?: ReadonlyMap<string, string>;
|
|
17
|
+
}
|
|
18
|
+
): RunnableGraph {
|
|
19
|
+
return {
|
|
20
|
+
nodes: document.nodes.map((node) => {
|
|
21
|
+
const viewElementIds = resolveViewElementIds(node);
|
|
22
|
+
const nodeType = resolveRunnableNodeType(node);
|
|
23
|
+
return {
|
|
24
|
+
id: node.id,
|
|
25
|
+
nodeType,
|
|
26
|
+
lifecyclePhase: node.lifecyclePhase,
|
|
27
|
+
libraryBlueprintId: node.libraryBlueprintId,
|
|
28
|
+
viewElementIds:
|
|
29
|
+
viewElementIds.length > 0 ? viewElementIds : undefined,
|
|
30
|
+
fetchConfig:
|
|
31
|
+
nodeType === FETCH_NODE_TYPE
|
|
32
|
+
? resolveNodeFetchConfig(node)
|
|
33
|
+
: node.fetchConfig,
|
|
34
|
+
jsonConfig: node.jsonConfig,
|
|
35
|
+
logicConfig: node.logicConfig,
|
|
36
|
+
clockConfig: node.clockConfig,
|
|
37
|
+
blueprintName: node.libraryBlueprintId
|
|
38
|
+
? (options?.libraryNameById?.get(node.libraryBlueprintId) ??
|
|
39
|
+
node.label)
|
|
40
|
+
: undefined,
|
|
41
|
+
};
|
|
42
|
+
}),
|
|
43
|
+
edges: document.edges.map((edge) => ({
|
|
44
|
+
source: edge.source,
|
|
45
|
+
target: edge.target,
|
|
46
|
+
sourceHandle: edge.sourceHandle,
|
|
47
|
+
targetHandle: edge.targetHandle,
|
|
48
|
+
})),
|
|
49
|
+
allowFalseSignalPropagation: document.allowFalseSignalPropagation,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CLOCK_NODE_TYPE,
|
|
3
|
+
type ExecutionTraceEntry,
|
|
4
|
+
} from "@arronqzy/blueprint-dsl";
|
|
5
|
+
|
|
6
|
+
import type { BlueprintGraph } from "../graph/blueprint-graph";
|
|
7
|
+
|
|
8
|
+
export type BlueprintNodeSignalKind = "true" | "false";
|
|
9
|
+
|
|
10
|
+
export type BlueprintEdgeSignalKind = BlueprintNodeSignalKind | "clock-green" | "clock-blue";
|
|
11
|
+
|
|
12
|
+
export type BlueprintExecutionOverlay = {
|
|
13
|
+
/** 当前执行到的节点(最后一条 trace 对应节点) */
|
|
14
|
+
activeNodeId: string | null;
|
|
15
|
+
/** 当前执行节点的主输出信号类型 */
|
|
16
|
+
activeNodeSignalKind: BlueprintNodeSignalKind | null;
|
|
17
|
+
/** 边 id -> 该边最近一次流出的信号类型 */
|
|
18
|
+
edgeSignals: Record<string, BlueprintEdgeSignalKind>;
|
|
19
|
+
/** 时钟节点输出口连线对应当前 tick(用于同色系再次输出时触发重置动画) */
|
|
20
|
+
clockEdgeTicks?: Record<string, number>;
|
|
21
|
+
/** 时钟节点已发送信号进度(调试用) */
|
|
22
|
+
clockNodeProgress?: Record<string, { current: number; total: number }>;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
function readOutputSignalKind(value: unknown): BlueprintNodeSignalKind | null {
|
|
26
|
+
if (!value || typeof value !== "object" || !("kind" in value)) return null;
|
|
27
|
+
const kind = (value as { kind: unknown }).kind;
|
|
28
|
+
if (kind === "true" || kind === "false") return kind;
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function resolveOutputEdgeSignalKind(
|
|
33
|
+
entry: ExecutionTraceEntry,
|
|
34
|
+
value: unknown
|
|
35
|
+
): BlueprintEdgeSignalKind | null {
|
|
36
|
+
const kind = readOutputSignalKind(value);
|
|
37
|
+
if (!kind) return null;
|
|
38
|
+
// 时钟每次输出真信号时连线均显示为绿色(与其它真信号一致)
|
|
39
|
+
if (entry.nodeType === CLOCK_NODE_TYPE && kind === "true") {
|
|
40
|
+
return "true";
|
|
41
|
+
}
|
|
42
|
+
return kind;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function applyClockEdgeTicks(
|
|
46
|
+
graph: BlueprintGraph,
|
|
47
|
+
entry: ExecutionTraceEntry,
|
|
48
|
+
clockEdgeTicks: Record<string, number>
|
|
49
|
+
) {
|
|
50
|
+
const tickIndex = entry.clockTickIndex ?? 1;
|
|
51
|
+
for (const edge of graph.document.edges) {
|
|
52
|
+
if (
|
|
53
|
+
edge.source === entry.nodeId &&
|
|
54
|
+
(edge.sourceHandle ?? "out") === "out"
|
|
55
|
+
) {
|
|
56
|
+
clockEdgeTicks[edge.id] = tickIndex;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function findLastClockTraceEntry(
|
|
62
|
+
entries: ExecutionTraceEntry[]
|
|
63
|
+
): ExecutionTraceEntry | undefined {
|
|
64
|
+
return [...entries]
|
|
65
|
+
.reverse()
|
|
66
|
+
.find(
|
|
67
|
+
(entry) =>
|
|
68
|
+
entry.nodeType === CLOCK_NODE_TYPE &&
|
|
69
|
+
getTraceEntryOutputKind(entry) === "true"
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function applyEntryOutputEdgeSignals(
|
|
74
|
+
graph: BlueprintGraph,
|
|
75
|
+
entry: ExecutionTraceEntry,
|
|
76
|
+
edgeSignals: Record<string, BlueprintEdgeSignalKind>
|
|
77
|
+
) {
|
|
78
|
+
for (const [port, value] of Object.entries(entry.outputs)) {
|
|
79
|
+
const kind = resolveOutputEdgeSignalKind(entry, value);
|
|
80
|
+
if (!kind) continue;
|
|
81
|
+
|
|
82
|
+
for (const edge of graph.document.edges) {
|
|
83
|
+
if (
|
|
84
|
+
edge.source === entry.nodeId &&
|
|
85
|
+
(edge.sourceHandle ?? "out") === port
|
|
86
|
+
) {
|
|
87
|
+
edgeSignals[edge.id] = kind;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function getTraceEntryOutputKind(
|
|
94
|
+
entry: ExecutionTraceEntry,
|
|
95
|
+
port = "out"
|
|
96
|
+
): BlueprintNodeSignalKind | null {
|
|
97
|
+
if (entry.error) return "false";
|
|
98
|
+
return readOutputSignalKind(entry.outputs[port]);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function isTraceHaltedByFalseSignal(
|
|
102
|
+
entries: ExecutionTraceEntry[]
|
|
103
|
+
): boolean {
|
|
104
|
+
if (entries.length === 0) return false;
|
|
105
|
+
return getTraceEntryOutputKind(entries[entries.length - 1]!) === "false";
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function shouldHaltDebugOnFalseSignal(
|
|
109
|
+
entries: ExecutionTraceEntry[],
|
|
110
|
+
allowFalseSignalPropagation = false
|
|
111
|
+
): boolean {
|
|
112
|
+
if (allowFalseSignalPropagation) return false;
|
|
113
|
+
return isTraceHaltedByFalseSignal(entries);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function buildExecutionOverlay(
|
|
117
|
+
graph: BlueprintGraph,
|
|
118
|
+
entries: ExecutionTraceEntry[]
|
|
119
|
+
): BlueprintExecutionOverlay | null {
|
|
120
|
+
if (entries.length === 0) return null;
|
|
121
|
+
|
|
122
|
+
const lastEntry = entries[entries.length - 1]!;
|
|
123
|
+
const edgeSignals: Record<string, BlueprintEdgeSignalKind> = {};
|
|
124
|
+
const clockEdgeTicks: Record<string, number> = {};
|
|
125
|
+
|
|
126
|
+
// 按执行顺序累积各输出口最近一次信号;未再次输出的连线保持变色
|
|
127
|
+
for (const entry of entries) {
|
|
128
|
+
applyEntryOutputEdgeSignals(graph, entry, edgeSignals);
|
|
129
|
+
if (
|
|
130
|
+
entry.nodeType === CLOCK_NODE_TYPE &&
|
|
131
|
+
getTraceEntryOutputKind(entry) === "true"
|
|
132
|
+
) {
|
|
133
|
+
applyClockEdgeTicks(graph, entry, clockEdgeTicks);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const lastClockEntry = findLastClockTraceEntry(entries);
|
|
138
|
+
|
|
139
|
+
const clockNodeProgress: Record<string, { current: number; total: number }> =
|
|
140
|
+
{};
|
|
141
|
+
if (lastClockEntry) {
|
|
142
|
+
clockNodeProgress[lastClockEntry.nodeId] = {
|
|
143
|
+
current: lastClockEntry.clockTickIndex ?? 1,
|
|
144
|
+
total: lastClockEntry.clockTickTotal ?? 1,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
activeNodeId: lastEntry.nodeId,
|
|
150
|
+
activeNodeSignalKind: getTraceEntryOutputKind(lastEntry),
|
|
151
|
+
edgeSignals,
|
|
152
|
+
clockEdgeTicks:
|
|
153
|
+
Object.keys(clockEdgeTicks).length > 0 ? clockEdgeTicks : undefined,
|
|
154
|
+
clockNodeProgress:
|
|
155
|
+
Object.keys(clockNodeProgress).length > 0 ? clockNodeProgress : undefined,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export type BlueprintNodeExecutionTone = "success" | "error";
|
|
160
|
+
|
|
161
|
+
export function resolveBlueprintNodeExecutionTone(data: {
|
|
162
|
+
isExecutionActive?: boolean;
|
|
163
|
+
executionSignalKind?: BlueprintNodeSignalKind | null;
|
|
164
|
+
}): BlueprintNodeExecutionTone | undefined {
|
|
165
|
+
if (!data.isExecutionActive) return undefined;
|
|
166
|
+
if (data.executionSignalKind === "false") return "error";
|
|
167
|
+
if (data.executionSignalKind === "true") return "success";
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type { BlueprintFlowNodeData } from "./graph/vue-flow-adapter";
|
package/src/utils/cn.ts
ADDED