@arronqzy/react-blueprint 1.0.3 → 1.0.4
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/index.ts +2 -1
- package/package.json +4 -3
- package/src/BlueprintContextMenu.tsx +5 -3
- package/src/BlueprintNodeConfigSidebar.tsx +56 -57
- package/src/components/BlueprintExecutionLogPanel.tsx +30 -28
- package/src/components/BlueprintLibrarySelect.tsx +11 -4
- package/src/components/BlueprintMetaDialog.tsx +20 -10
- package/src/components/BlueprintNodeSwitchTaskDialog.tsx +14 -8
- package/src/components/BlueprintPanelToolbar.tsx +50 -42
- package/src/components/ClockNodeConfigPanel.tsx +19 -12
- package/src/components/FetchNodeConfigPanel.tsx +36 -33
- package/src/components/FetchUrlAutocomplete.tsx +3 -1
- package/src/components/JsonNodeConfigPanel.tsx +15 -7
- package/src/components/LogicNodeConfigPanel.tsx +13 -7
- package/src/components/ViewElementMultiSelect.tsx +25 -18
- package/src/dev-seed.ts +2 -2
- package/src/fetch-config-task-store.ts +8 -2
- package/src/graph/document.ts +51 -14
- package/src/graph/node-summary.ts +32 -18
- package/src/hooks/useBlueprintPageLifecycle.ts +29 -1
- package/src/library/blueprint-io.ts +12 -3
- package/src/library/swagger-docs.ts +15 -5
- package/src/main.tsx +12 -5
- package/src/nodes/AndFlowNode.tsx +7 -5
- package/src/nodes/BlueprintFlowNode.tsx +4 -2
- package/src/nodes/BlueprintNodeCard.tsx +4 -2
- package/src/nodes/BlueprintNodeShell.tsx +4 -2
- package/src/nodes/ClockFlowNode.tsx +5 -3
- package/src/nodes/FetchFlowNode.tsx +4 -2
- package/src/nodes/JsonFlowNode.tsx +4 -2
- package/src/nodes/LifecycleFlowNode.tsx +5 -3
- package/src/nodes/LogicFlowNode.tsx +4 -2
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
} from "@arronqzy/blueprint-dsl";
|
|
1
|
+
import { resolveFetchRequestUrl } from "@arronqzy/blueprint-dsl";
|
|
2
|
+
import type { TranslateFn } from "@arronqzy/i18n";
|
|
3
|
+
import { resolveLocale, tForLocale } from "@arronqzy/i18n";
|
|
5
4
|
|
|
6
5
|
import {
|
|
6
|
+
getLifecyclePhaseLabel,
|
|
7
7
|
resolveBlueprintConfigSource,
|
|
8
8
|
resolveNodeClockConfig,
|
|
9
9
|
resolveNodeFetchConfig,
|
|
@@ -19,21 +19,26 @@ function truncate(text: string, max: number): string {
|
|
|
19
19
|
return `${trimmed.slice(0, Math.max(0, max - 1))}…`;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
function defaultTranslate(): TranslateFn {
|
|
23
|
+
return tForLocale(resolveLocale());
|
|
24
|
+
}
|
|
25
|
+
|
|
22
26
|
/** 画布节点正文区展示的配置摘要 */
|
|
23
27
|
export function resolveBlueprintNodeSummary(
|
|
24
|
-
data: BlueprintFlowNodeData
|
|
28
|
+
data: BlueprintFlowNodeData,
|
|
29
|
+
t: TranslateFn = defaultTranslate()
|
|
25
30
|
): string | undefined {
|
|
26
31
|
const configSource = resolveBlueprintConfigSource(data);
|
|
27
32
|
|
|
28
33
|
switch (configSource) {
|
|
29
34
|
case "fetch": {
|
|
30
35
|
const config = resolveNodeFetchConfig(data);
|
|
31
|
-
if (!config.url?.trim()) return "
|
|
36
|
+
if (!config.url?.trim()) return t("blueprint.node.summaryNoUrl");
|
|
32
37
|
let url = config.url.trim();
|
|
33
38
|
try {
|
|
34
39
|
url = resolveFetchRequestUrl(config);
|
|
35
40
|
} catch {
|
|
36
|
-
/*
|
|
41
|
+
/* keep raw input */
|
|
37
42
|
}
|
|
38
43
|
const method = config.method ?? "GET";
|
|
39
44
|
return truncate(`${method} ${url}`, 44);
|
|
@@ -41,20 +46,26 @@ export function resolveBlueprintNodeSummary(
|
|
|
41
46
|
case "clock": {
|
|
42
47
|
const clock = resolveNodeClockConfig(data);
|
|
43
48
|
const parts = [
|
|
44
|
-
|
|
45
|
-
clock.intervalSeconds > 0
|
|
46
|
-
|
|
49
|
+
t("blueprint.node.summaryOutputCount", { count: clock.outputCount }),
|
|
50
|
+
clock.intervalSeconds > 0
|
|
51
|
+
? t("blueprint.node.summaryInterval", {
|
|
52
|
+
seconds: clock.intervalSeconds,
|
|
53
|
+
})
|
|
54
|
+
: null,
|
|
55
|
+
clock.emitImmediately
|
|
56
|
+
? t("blueprint.node.summaryEmitImmediate")
|
|
57
|
+
: t("blueprint.node.summaryEmitDelayed"),
|
|
47
58
|
].filter(Boolean);
|
|
48
59
|
return parts.join(" · ");
|
|
49
60
|
}
|
|
50
61
|
case "json": {
|
|
51
62
|
const json = resolveNodeJsonConfig(data).jsonString?.trim();
|
|
52
|
-
if (!json) return "
|
|
63
|
+
if (!json) return t("blueprint.node.summaryEmptyJson");
|
|
53
64
|
return truncate(json.replace(/\s+/g, " "), 44);
|
|
54
65
|
}
|
|
55
66
|
case "logic": {
|
|
56
67
|
const code = resolveNodeLogicConfig(data).sourceCode?.trim();
|
|
57
|
-
if (!code) return "
|
|
68
|
+
if (!code) return t("blueprint.node.summaryNoScript");
|
|
58
69
|
const firstLine =
|
|
59
70
|
code.split("\n").find((line) => line.trim())?.trim() ?? code;
|
|
60
71
|
return truncate(firstLine, 44);
|
|
@@ -66,22 +77,25 @@ export function resolveBlueprintNodeSummary(
|
|
|
66
77
|
if (data.libraryBlueprintId) {
|
|
67
78
|
return truncate(data.libraryBlueprintId, 44);
|
|
68
79
|
}
|
|
69
|
-
return "
|
|
80
|
+
return t("blueprint.node.summaryNoBlueprint");
|
|
70
81
|
}
|
|
71
82
|
case "lifecycle": {
|
|
72
83
|
const phase = data.lifecyclePhase ?? "mounted";
|
|
73
|
-
return
|
|
84
|
+
return getLifecyclePhaseLabel(t, phase);
|
|
74
85
|
}
|
|
75
86
|
case "view": {
|
|
76
87
|
const ids = resolveViewElementIds(data);
|
|
77
|
-
if (ids.length === 0) return "
|
|
88
|
+
if (ids.length === 0) return t("blueprint.node.summaryNoView");
|
|
78
89
|
if (ids.length === 1) {
|
|
79
|
-
return truncate(
|
|
90
|
+
return truncate(
|
|
91
|
+
t("blueprint.node.summaryViewOne", { id: ids[0] }),
|
|
92
|
+
44
|
|
93
|
+
);
|
|
80
94
|
}
|
|
81
|
-
return
|
|
95
|
+
return t("blueprint.node.summaryViewMany", { count: ids.length });
|
|
82
96
|
}
|
|
83
97
|
case "and":
|
|
84
|
-
return "
|
|
98
|
+
return t("blueprint.node.summaryAnd");
|
|
85
99
|
default:
|
|
86
100
|
return undefined;
|
|
87
101
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect, useRef, useState } from "react";
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
2
|
import {
|
|
3
3
|
BlueprintGraphRunner,
|
|
4
4
|
detectBlueprintReferenceCycle,
|
|
@@ -242,4 +242,32 @@ export function useBlueprintPageLifecycle({
|
|
|
242
242
|
if (!enabled || !bootCompleted) return;
|
|
243
243
|
void emitPhases(graphRef.current, ["updated"], runnerOptionsRef.current);
|
|
244
244
|
}, [bootCompleted, enabled, onUpdated]);
|
|
245
|
+
|
|
246
|
+
const triggerBlueprintNode = useCallback(
|
|
247
|
+
async (nodeId: string, inputValue?: unknown) => {
|
|
248
|
+
const id = nodeId.trim();
|
|
249
|
+
if (!id) return;
|
|
250
|
+
const opts = runnerOptionsRef.current;
|
|
251
|
+
if (opts.resolveLibraryBlueprint) {
|
|
252
|
+
const result = await detectBlueprintReferenceCycle({
|
|
253
|
+
rootGraph: documentToRunnableGraph(graphRef.current.document, {
|
|
254
|
+
libraryNameById: opts.libraryNameById,
|
|
255
|
+
}),
|
|
256
|
+
rootLibraryBlueprintId: opts.rootLibraryBlueprintId,
|
|
257
|
+
resolveLibraryBlueprint: opts.resolveLibraryBlueprint,
|
|
258
|
+
resolveBlueprintName: (libId) =>
|
|
259
|
+
resolveBlueprintName(opts.libraryNameById, libId),
|
|
260
|
+
});
|
|
261
|
+
if (!result.ok) {
|
|
262
|
+
opts.onExecutionBlocked?.(result.message);
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
const runner = createRunner(graphRef.current, opts);
|
|
267
|
+
await runner.triggerNode(id, inputValue);
|
|
268
|
+
},
|
|
269
|
+
[]
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
return { triggerBlueprintNode };
|
|
245
273
|
}
|
|
@@ -8,6 +8,15 @@ import {
|
|
|
8
8
|
type BlueprintLibrarySource,
|
|
9
9
|
type BlueprintMetaDraft,
|
|
10
10
|
} from "./types";
|
|
11
|
+
import { resolveLocale, tForLocale } from "@arronqzy/i18n";
|
|
12
|
+
|
|
13
|
+
function unnamedBlueprintName() {
|
|
14
|
+
return tForLocale(resolveLocale())("blueprint.dialog.unnamedBlueprint");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function importedBlueprintName() {
|
|
18
|
+
return tForLocale(resolveLocale())("blueprint.dialog.importedBlueprint");
|
|
19
|
+
}
|
|
11
20
|
|
|
12
21
|
export function createLibraryBlueprintId() {
|
|
13
22
|
return createNodeId("lib_bp");
|
|
@@ -27,7 +36,7 @@ export function buildBlueprintExportPayload(
|
|
|
27
36
|
return {
|
|
28
37
|
kind: BLUEPRINT_EXPORT_KIND,
|
|
29
38
|
version: BLUEPRINT_EXPORT_VERSION,
|
|
30
|
-
name: meta.name.trim() ||
|
|
39
|
+
name: meta.name.trim() || unnamedBlueprintName(),
|
|
31
40
|
remark: meta.remark.trim() || undefined,
|
|
32
41
|
exportedAt: Date.now(),
|
|
33
42
|
document: {
|
|
@@ -51,7 +60,7 @@ export function parseBlueprintImportFile(raw: unknown): BlueprintExportPayload {
|
|
|
51
60
|
return {
|
|
52
61
|
kind: BLUEPRINT_EXPORT_KIND,
|
|
53
62
|
version: BLUEPRINT_EXPORT_VERSION,
|
|
54
|
-
name: typeof data.name === "string" ? data.name :
|
|
63
|
+
name: typeof data.name === "string" ? data.name : importedBlueprintName(),
|
|
55
64
|
remark: typeof data.remark === "string" ? data.remark : undefined,
|
|
56
65
|
exportedAt: typeof data.exportedAt === "number" ? data.exportedAt : Date.now(),
|
|
57
66
|
document: data.document,
|
|
@@ -81,7 +90,7 @@ export function buildLibraryRecord(args: {
|
|
|
81
90
|
createdAt?: number;
|
|
82
91
|
}): BlueprintLibraryRecord {
|
|
83
92
|
const now = Date.now();
|
|
84
|
-
const name = args.meta.name.trim() ||
|
|
93
|
+
const name = args.meta.name.trim() || unnamedBlueprintName();
|
|
85
94
|
return {
|
|
86
95
|
id: args.id ?? createLibraryBlueprintId(),
|
|
87
96
|
name,
|
|
@@ -2,14 +2,20 @@ import {
|
|
|
2
2
|
parseSwaggerDocument,
|
|
3
3
|
type ParsedSwaggerDocument,
|
|
4
4
|
} from "@arronqzy/blueprint-dsl";
|
|
5
|
+
import { resolveLocale, tForLocale } from "@arronqzy/i18n";
|
|
6
|
+
|
|
7
|
+
function t() {
|
|
8
|
+
return tForLocale(resolveLocale());
|
|
9
|
+
}
|
|
5
10
|
|
|
6
11
|
export async function loadSwaggerDocument(
|
|
7
12
|
docsUrl: string,
|
|
8
13
|
signal?: AbortSignal
|
|
9
14
|
): Promise<ParsedSwaggerDocument> {
|
|
15
|
+
const translate = t();
|
|
10
16
|
const trimmed = docsUrl.trim();
|
|
11
17
|
if (!trimmed) {
|
|
12
|
-
throw new Error("
|
|
18
|
+
throw new Error(translate("blueprint.config.enterSwaggerUrl"));
|
|
13
19
|
}
|
|
14
20
|
|
|
15
21
|
if (signal?.aborted) {
|
|
@@ -28,7 +34,9 @@ export async function loadSwaggerDocument(
|
|
|
28
34
|
throw new DOMException("Aborted", "AbortError");
|
|
29
35
|
}
|
|
30
36
|
throw new Error(
|
|
31
|
-
error instanceof Error
|
|
37
|
+
error instanceof Error
|
|
38
|
+
? error.message
|
|
39
|
+
: translate("blueprint.config.cannotFetchSwagger")
|
|
32
40
|
);
|
|
33
41
|
}
|
|
34
42
|
|
|
@@ -37,19 +45,21 @@ export async function loadSwaggerDocument(
|
|
|
37
45
|
}
|
|
38
46
|
|
|
39
47
|
if (!response.ok) {
|
|
40
|
-
throw new Error(
|
|
48
|
+
throw new Error(
|
|
49
|
+
translate("blueprint.config.swaggerHttpFailed", { status: response.status })
|
|
50
|
+
);
|
|
41
51
|
}
|
|
42
52
|
|
|
43
53
|
const contentType = response.headers.get("content-type") ?? "";
|
|
44
54
|
if (contentType.includes("text/html")) {
|
|
45
|
-
throw new Error("
|
|
55
|
+
throw new Error(translate("blueprint.config.swaggerHtmlReturned"));
|
|
46
56
|
}
|
|
47
57
|
|
|
48
58
|
let spec: unknown;
|
|
49
59
|
try {
|
|
50
60
|
spec = await response.json();
|
|
51
61
|
} catch {
|
|
52
|
-
throw new Error("
|
|
62
|
+
throw new Error(translate("blueprint.config.swaggerInvalidJson"));
|
|
53
63
|
}
|
|
54
64
|
|
|
55
65
|
return parseSwaggerDocument(spec, trimmed);
|
package/src/main.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
2
|
import { createRoot } from "react-dom/client";
|
|
3
3
|
import { ThemeProvider } from "@arronqzy/ui";
|
|
4
|
+
import { I18nProvider, useI18n } from "@arronqzy/i18n/react";
|
|
4
5
|
import "@arronqzy/ui/styles.css";
|
|
5
6
|
import "@xyflow/react/dist/style.css";
|
|
6
7
|
import "./dev.css";
|
|
@@ -10,6 +11,7 @@ import { BluePrintReactRoot } from ".";
|
|
|
10
11
|
import { createDevBlueprintGraph } from "./dev-seed";
|
|
11
12
|
|
|
12
13
|
function DevApp() {
|
|
14
|
+
const { t } = useI18n();
|
|
13
15
|
const [graph, setGraph] = useState(() => createDevBlueprintGraph());
|
|
14
16
|
const [selectedNodeId, setSelectedNodeId] = useState<string | null>(null);
|
|
15
17
|
|
|
@@ -18,10 +20,13 @@ function DevApp() {
|
|
|
18
20
|
<header className="bp-dev-toolbar">
|
|
19
21
|
<strong>Blueprint Dev</strong>
|
|
20
22
|
<span className="text-muted-foreground">
|
|
21
|
-
|
|
23
|
+
{t("blueprint.dev.hint")}
|
|
22
24
|
</span>
|
|
23
25
|
<span className="text-muted-foreground">
|
|
24
|
-
|
|
26
|
+
{t("blueprint.dev.stats", {
|
|
27
|
+
nodes: graph.document.nodes.length,
|
|
28
|
+
edges: graph.document.edges.length,
|
|
29
|
+
})}
|
|
25
30
|
</span>
|
|
26
31
|
</header>
|
|
27
32
|
<div className="bp-dev-canvas">
|
|
@@ -37,7 +42,9 @@ function DevApp() {
|
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
createRoot(document.getElementById("app")!).render(
|
|
40
|
-
<
|
|
41
|
-
<
|
|
42
|
-
|
|
45
|
+
<I18nProvider>
|
|
46
|
+
<ThemeProvider defaultTheme="light" enableSystem={false}>
|
|
47
|
+
<DevApp />
|
|
48
|
+
</ThemeProvider>
|
|
49
|
+
</I18nProvider>
|
|
43
50
|
);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useI18n } from "@arronqzy/i18n/react";
|
|
1
2
|
import { Handle, Position, type NodeProps } from "@xyflow/react";
|
|
2
3
|
import { cn } from "@arronqzy/ui";
|
|
3
4
|
|
|
@@ -10,6 +11,7 @@ import { BlueprintNodeCard } from "./BlueprintNodeCard";
|
|
|
10
11
|
|
|
11
12
|
/** 并运算节点:两路输入均为真时输出真信号;单端口多连线按「或」合并 */
|
|
12
13
|
export function AndFlowNode({ id, data }: NodeProps) {
|
|
14
|
+
const { t } = useI18n();
|
|
13
15
|
const nodeData = data as BlueprintFlowNodeData;
|
|
14
16
|
const onSelect = useBlueprintNodeSelect();
|
|
15
17
|
const executionTone = resolveBlueprintNodeExecutionTone(nodeData);
|
|
@@ -28,7 +30,7 @@ export function AndFlowNode({ id, data }: NodeProps) {
|
|
|
28
30
|
id="inA"
|
|
29
31
|
className="bp-flow-handle bp-flow-handle--target"
|
|
30
32
|
style={{ top: "35%" }}
|
|
31
|
-
title="
|
|
33
|
+
title={t("blueprint.node.andInA")}
|
|
32
34
|
/>
|
|
33
35
|
<Handle
|
|
34
36
|
type="target"
|
|
@@ -36,13 +38,13 @@ export function AndFlowNode({ id, data }: NodeProps) {
|
|
|
36
38
|
id="inB"
|
|
37
39
|
className="bp-flow-handle bp-flow-handle--target"
|
|
38
40
|
style={{ top: "65%" }}
|
|
39
|
-
title="
|
|
41
|
+
title={t("blueprint.node.andInB")}
|
|
40
42
|
/>
|
|
41
43
|
<BlueprintNodeCard
|
|
42
44
|
nodeId={id}
|
|
43
45
|
label={nodeData.label}
|
|
44
|
-
meta={resolveBlueprintNodeTypeLabel(nodeData)}
|
|
45
|
-
subtitle={resolveBlueprintNodeSummary(nodeData)}
|
|
46
|
+
meta={resolveBlueprintNodeTypeLabel(nodeData, t)}
|
|
47
|
+
subtitle={resolveBlueprintNodeSummary(nodeData, t)}
|
|
46
48
|
variant="and"
|
|
47
49
|
selected={Boolean(nodeData.isSelected)}
|
|
48
50
|
onSelect={onSelect}
|
|
@@ -52,7 +54,7 @@ export function AndFlowNode({ id, data }: NodeProps) {
|
|
|
52
54
|
position={Position.Right}
|
|
53
55
|
id="out"
|
|
54
56
|
className="bp-flow-handle bp-flow-handle--source"
|
|
55
|
-
title="
|
|
57
|
+
title={t("blueprint.node.andOut")}
|
|
56
58
|
/>
|
|
57
59
|
</div>
|
|
58
60
|
);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useI18n } from "@arronqzy/i18n/react";
|
|
1
2
|
import type { NodeProps } from "@xyflow/react";
|
|
2
3
|
|
|
3
4
|
import { resolveBlueprintNodeTypeLabel } from "../graph/document";
|
|
@@ -8,6 +9,7 @@ import type { BlueprintFlowNodeData } from "../types";
|
|
|
8
9
|
import { BlueprintNodeShell } from "./BlueprintNodeShell";
|
|
9
10
|
|
|
10
11
|
export function BlueprintFlowNode({ id, data }: NodeProps) {
|
|
12
|
+
const { t } = useI18n();
|
|
11
13
|
const nodeData = data as BlueprintFlowNodeData;
|
|
12
14
|
const onSelect = useBlueprintNodeSelect();
|
|
13
15
|
|
|
@@ -15,8 +17,8 @@ export function BlueprintFlowNode({ id, data }: NodeProps) {
|
|
|
15
17
|
<BlueprintNodeShell
|
|
16
18
|
nodeId={id}
|
|
17
19
|
label={nodeData.label}
|
|
18
|
-
meta={resolveBlueprintNodeTypeLabel(nodeData)}
|
|
19
|
-
subtitle={resolveBlueprintNodeSummary(nodeData)}
|
|
20
|
+
meta={resolveBlueprintNodeTypeLabel(nodeData, t)}
|
|
21
|
+
subtitle={resolveBlueprintNodeSummary(nodeData, t)}
|
|
20
22
|
variant="blueprint"
|
|
21
23
|
selected={Boolean(nodeData.isSelected)}
|
|
22
24
|
executionTone={resolveBlueprintNodeExecutionTone(nodeData)}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useI18n } from "@arronqzy/i18n/react";
|
|
1
2
|
import { cn } from "@arronqzy/ui";
|
|
2
3
|
|
|
3
4
|
export type BlueprintNodeCardProps = {
|
|
@@ -81,6 +82,7 @@ export function BlueprintNodeCard({
|
|
|
81
82
|
hideLeadingDot = false,
|
|
82
83
|
onSelect,
|
|
83
84
|
}: BlueprintNodeCardProps) {
|
|
85
|
+
const { t } = useI18n();
|
|
84
86
|
const v = variantStyle[variant];
|
|
85
87
|
|
|
86
88
|
return (
|
|
@@ -101,7 +103,7 @@ export function BlueprintNodeCard({
|
|
|
101
103
|
"bp-flow-drag-handle flex cursor-grab items-center gap-2 border-b border-border/50 px-2 py-1.5",
|
|
102
104
|
"bg-muted/25 text-muted-foreground active:cursor-grabbing"
|
|
103
105
|
)}
|
|
104
|
-
title="
|
|
106
|
+
title={t("blueprint.node.dragToMove")}
|
|
105
107
|
>
|
|
106
108
|
<NodeGrip />
|
|
107
109
|
{meta ? (
|
|
@@ -148,7 +150,7 @@ export function BlueprintNodeCard({
|
|
|
148
150
|
"shrink-0 rounded px-1.5 py-0.5 text-[10px] font-semibold leading-none",
|
|
149
151
|
v.badge
|
|
150
152
|
)}
|
|
151
|
-
title="
|
|
153
|
+
title={t("blueprint.node.signalSentCount")}
|
|
152
154
|
>
|
|
153
155
|
{progressLabel}
|
|
154
156
|
</span>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useI18n } from "@arronqzy/i18n/react";
|
|
1
2
|
import { Handle, Position } from "@xyflow/react";
|
|
2
3
|
import { cn } from "@arronqzy/ui";
|
|
3
4
|
|
|
@@ -17,6 +18,7 @@ export function BlueprintNodeShell({
|
|
|
17
18
|
executionTone = null,
|
|
18
19
|
...cardProps
|
|
19
20
|
}: BlueprintNodeShellProps) {
|
|
21
|
+
const { t } = useI18n();
|
|
20
22
|
return (
|
|
21
23
|
<div
|
|
22
24
|
className={cn(
|
|
@@ -30,7 +32,7 @@ export function BlueprintNodeShell({
|
|
|
30
32
|
position={Position.Left}
|
|
31
33
|
id="in"
|
|
32
34
|
className="bp-flow-handle bp-flow-handle--target"
|
|
33
|
-
title="
|
|
35
|
+
title={t("blueprint.node.signalIn")}
|
|
34
36
|
/>
|
|
35
37
|
<BlueprintNodeCard {...cardProps} selected={selected} />
|
|
36
38
|
<Handle
|
|
@@ -38,7 +40,7 @@ export function BlueprintNodeShell({
|
|
|
38
40
|
position={Position.Right}
|
|
39
41
|
id="out"
|
|
40
42
|
className="bp-flow-handle bp-flow-handle--source"
|
|
41
|
-
title="
|
|
43
|
+
title={t("blueprint.node.signalOut")}
|
|
42
44
|
/>
|
|
43
45
|
</div>
|
|
44
46
|
);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useI18n } from "@arronqzy/i18n/react";
|
|
1
2
|
import type { NodeProps } from "@xyflow/react";
|
|
2
3
|
import { cn } from "@arronqzy/ui";
|
|
3
4
|
|
|
@@ -22,6 +23,7 @@ function ClockAbortIcon({ className }: { className?: string }) {
|
|
|
22
23
|
|
|
23
24
|
/** 时钟节点:收到真信号后按配置间隔输出含当前时间的真信号 */
|
|
24
25
|
export function ClockFlowNode({ id, data }: NodeProps) {
|
|
26
|
+
const { t } = useI18n();
|
|
25
27
|
const nodeData = data as BlueprintFlowNodeData;
|
|
26
28
|
const onSelect = useBlueprintNodeSelect();
|
|
27
29
|
const onAbortClock = useBlueprintClockAbort();
|
|
@@ -36,8 +38,8 @@ export function ClockFlowNode({ id, data }: NodeProps) {
|
|
|
36
38
|
<BlueprintNodeShell
|
|
37
39
|
nodeId={id}
|
|
38
40
|
label={nodeData.label}
|
|
39
|
-
meta={resolveBlueprintNodeTypeLabel(nodeData)}
|
|
40
|
-
subtitle={resolveBlueprintNodeSummary(nodeData)}
|
|
41
|
+
meta={resolveBlueprintNodeTypeLabel(nodeData, t)}
|
|
42
|
+
subtitle={resolveBlueprintNodeSummary(nodeData, t)}
|
|
41
43
|
progressLabel={progressLabel}
|
|
42
44
|
variant="clock"
|
|
43
45
|
selected={Boolean(nodeData.isSelected)}
|
|
@@ -52,7 +54,7 @@ export function ClockFlowNode({ id, data }: NodeProps) {
|
|
|
52
54
|
"rounded border border-rose-500/50 bg-rose-500/15 text-rose-600 shadow-sm",
|
|
53
55
|
"hover:bg-rose-500/25 dark:text-rose-300"
|
|
54
56
|
)}
|
|
55
|
-
title="
|
|
57
|
+
title={t("blueprint.node.abortClock")}
|
|
56
58
|
onPointerDown={(e) => e.stopPropagation()}
|
|
57
59
|
onClick={(e) => {
|
|
58
60
|
e.stopPropagation();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useI18n } from "@arronqzy/i18n/react";
|
|
1
2
|
import type { NodeProps } from "@xyflow/react";
|
|
2
3
|
|
|
3
4
|
import { resolveBlueprintNodeTypeLabel } from "../graph/document";
|
|
@@ -8,6 +9,7 @@ import type { BlueprintFlowNodeData } from "../types";
|
|
|
8
9
|
import { BlueprintNodeShell } from "./BlueprintNodeShell";
|
|
9
10
|
|
|
10
11
|
export function FetchFlowNode({ id, data }: NodeProps) {
|
|
12
|
+
const { t } = useI18n();
|
|
11
13
|
const nodeData = data as BlueprintFlowNodeData;
|
|
12
14
|
const onSelect = useBlueprintNodeSelect();
|
|
13
15
|
|
|
@@ -15,8 +17,8 @@ export function FetchFlowNode({ id, data }: NodeProps) {
|
|
|
15
17
|
<BlueprintNodeShell
|
|
16
18
|
nodeId={id}
|
|
17
19
|
label={nodeData.label}
|
|
18
|
-
meta={resolveBlueprintNodeTypeLabel(nodeData)}
|
|
19
|
-
subtitle={resolveBlueprintNodeSummary(nodeData)}
|
|
20
|
+
meta={resolveBlueprintNodeTypeLabel(nodeData, t)}
|
|
21
|
+
subtitle={resolveBlueprintNodeSummary(nodeData, t)}
|
|
20
22
|
variant="fetch"
|
|
21
23
|
selected={Boolean(nodeData.isSelected)}
|
|
22
24
|
executionTone={resolveBlueprintNodeExecutionTone(nodeData)}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useI18n } from "@arronqzy/i18n/react";
|
|
1
2
|
import type { NodeProps } from "@xyflow/react";
|
|
2
3
|
|
|
3
4
|
import { resolveBlueprintNodeTypeLabel } from "../graph/document";
|
|
@@ -8,6 +9,7 @@ import type { BlueprintFlowNodeData } from "../types";
|
|
|
8
9
|
import { BlueprintNodeShell } from "./BlueprintNodeShell";
|
|
9
10
|
|
|
10
11
|
export function JsonFlowNode({ id, data }: NodeProps) {
|
|
12
|
+
const { t } = useI18n();
|
|
11
13
|
const nodeData = data as BlueprintFlowNodeData;
|
|
12
14
|
const onSelect = useBlueprintNodeSelect();
|
|
13
15
|
|
|
@@ -15,8 +17,8 @@ export function JsonFlowNode({ id, data }: NodeProps) {
|
|
|
15
17
|
<BlueprintNodeShell
|
|
16
18
|
nodeId={id}
|
|
17
19
|
label={nodeData.label}
|
|
18
|
-
meta={resolveBlueprintNodeTypeLabel(nodeData)}
|
|
19
|
-
subtitle={resolveBlueprintNodeSummary(nodeData)}
|
|
20
|
+
meta={resolveBlueprintNodeTypeLabel(nodeData, t)}
|
|
21
|
+
subtitle={resolveBlueprintNodeSummary(nodeData, t)}
|
|
20
22
|
variant="json"
|
|
21
23
|
selected={Boolean(nodeData.isSelected)}
|
|
22
24
|
executionTone={resolveBlueprintNodeExecutionTone(nodeData)}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useI18n } from "@arronqzy/i18n/react";
|
|
1
2
|
import { Handle, Position, type NodeProps } from "@xyflow/react";
|
|
2
3
|
import { cn } from "@arronqzy/ui";
|
|
3
4
|
|
|
@@ -10,6 +11,7 @@ import { BlueprintNodeCard } from "./BlueprintNodeCard";
|
|
|
10
11
|
|
|
11
12
|
/** 生命周期节点:无输入口,仅在对应生命周期触发时从右侧输出口发出信号 */
|
|
12
13
|
export function LifecycleFlowNode({ id, data }: NodeProps) {
|
|
14
|
+
const { t } = useI18n();
|
|
13
15
|
const nodeData = data as BlueprintFlowNodeData;
|
|
14
16
|
const onSelect = useBlueprintNodeSelect();
|
|
15
17
|
const executionTone = resolveBlueprintNodeExecutionTone(nodeData);
|
|
@@ -25,8 +27,8 @@ export function LifecycleFlowNode({ id, data }: NodeProps) {
|
|
|
25
27
|
<BlueprintNodeCard
|
|
26
28
|
nodeId={id}
|
|
27
29
|
label={nodeData.label}
|
|
28
|
-
meta={resolveBlueprintNodeTypeLabel(nodeData)}
|
|
29
|
-
subtitle={resolveBlueprintNodeSummary(nodeData)}
|
|
30
|
+
meta={resolveBlueprintNodeTypeLabel(nodeData, t)}
|
|
31
|
+
subtitle={resolveBlueprintNodeSummary(nodeData, t)}
|
|
30
32
|
variant="lifecycle"
|
|
31
33
|
selected={Boolean(nodeData.isSelected)}
|
|
32
34
|
hideLeadingDot
|
|
@@ -37,7 +39,7 @@ export function LifecycleFlowNode({ id, data }: NodeProps) {
|
|
|
37
39
|
position={Position.Right}
|
|
38
40
|
id="out"
|
|
39
41
|
className="bp-flow-handle bp-flow-handle--source"
|
|
40
|
-
title="
|
|
42
|
+
title={t("blueprint.node.lifecycleOut")}
|
|
41
43
|
/>
|
|
42
44
|
</div>
|
|
43
45
|
);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useI18n } from "@arronqzy/i18n/react";
|
|
1
2
|
import type { NodeProps } from "@xyflow/react";
|
|
2
3
|
|
|
3
4
|
import { resolveBlueprintNodeTypeLabel } from "../graph/document";
|
|
@@ -8,6 +9,7 @@ import type { BlueprintFlowNodeData } from "../types";
|
|
|
8
9
|
import { BlueprintNodeShell } from "./BlueprintNodeShell";
|
|
9
10
|
|
|
10
11
|
export function LogicFlowNode({ id, data }: NodeProps) {
|
|
12
|
+
const { t } = useI18n();
|
|
11
13
|
const nodeData = data as BlueprintFlowNodeData;
|
|
12
14
|
const onSelect = useBlueprintNodeSelect();
|
|
13
15
|
|
|
@@ -15,8 +17,8 @@ export function LogicFlowNode({ id, data }: NodeProps) {
|
|
|
15
17
|
<BlueprintNodeShell
|
|
16
18
|
nodeId={id}
|
|
17
19
|
label={nodeData.label}
|
|
18
|
-
meta={resolveBlueprintNodeTypeLabel(nodeData)}
|
|
19
|
-
subtitle={resolveBlueprintNodeSummary(nodeData)}
|
|
20
|
+
meta={resolveBlueprintNodeTypeLabel(nodeData, t)}
|
|
21
|
+
subtitle={resolveBlueprintNodeSummary(nodeData, t)}
|
|
20
22
|
variant="logic"
|
|
21
23
|
selected={Boolean(nodeData.isSelected)}
|
|
22
24
|
executionTone={resolveBlueprintNodeExecutionTone(nodeData)}
|