@arronqzy/react-blueprint 1.0.3 → 1.0.5

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.
Files changed (32) hide show
  1. package/index.ts +2 -1
  2. package/package.json +7 -6
  3. package/src/BlueprintContextMenu.tsx +5 -3
  4. package/src/BlueprintNodeConfigSidebar.tsx +56 -57
  5. package/src/components/BlueprintExecutionLogPanel.tsx +30 -28
  6. package/src/components/BlueprintLibrarySelect.tsx +11 -4
  7. package/src/components/BlueprintMetaDialog.tsx +20 -10
  8. package/src/components/BlueprintNodeSwitchTaskDialog.tsx +14 -8
  9. package/src/components/BlueprintPanelToolbar.tsx +50 -42
  10. package/src/components/ClockNodeConfigPanel.tsx +19 -12
  11. package/src/components/FetchNodeConfigPanel.tsx +36 -33
  12. package/src/components/FetchUrlAutocomplete.tsx +3 -1
  13. package/src/components/JsonNodeConfigPanel.tsx +15 -7
  14. package/src/components/LogicNodeConfigPanel.tsx +13 -7
  15. package/src/components/ViewElementMultiSelect.tsx +25 -18
  16. package/src/dev-seed.ts +2 -2
  17. package/src/fetch-config-task-store.ts +8 -2
  18. package/src/graph/document.ts +51 -14
  19. package/src/graph/node-summary.ts +32 -18
  20. package/src/hooks/useBlueprintPageLifecycle.ts +29 -1
  21. package/src/library/blueprint-io.ts +12 -3
  22. package/src/library/swagger-docs.ts +15 -5
  23. package/src/main.tsx +12 -5
  24. package/src/nodes/AndFlowNode.tsx +7 -5
  25. package/src/nodes/BlueprintFlowNode.tsx +4 -2
  26. package/src/nodes/BlueprintNodeCard.tsx +4 -2
  27. package/src/nodes/BlueprintNodeShell.tsx +4 -2
  28. package/src/nodes/ClockFlowNode.tsx +5 -3
  29. package/src/nodes/FetchFlowNode.tsx +4 -2
  30. package/src/nodes/JsonFlowNode.tsx +4 -2
  31. package/src/nodes/LifecycleFlowNode.tsx +5 -3
  32. package/src/nodes/LogicFlowNode.tsx +4 -2
@@ -1,9 +1,9 @@
1
- import {
2
- PAGE_LIFECYCLE_LABELS,
3
- resolveFetchRequestUrl,
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 "未配置 URL";
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
- `${clock.outputCount} 次`,
45
- clock.intervalSeconds > 0 ? `间隔 ${clock.intervalSeconds}s` : null,
46
- clock.emitImmediately ? "立即首发" : "延迟首发",
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 "空 JSON";
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 PAGE_LIFECYCLE_LABELS[phase] ?? phase;
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(`视图节点 ${ids[0]}`, 44);
90
+ return truncate(
91
+ t("blueprint.node.summaryViewOne", { id: ids[0] }),
92
+ 44
93
+ );
80
94
  }
81
- return `已关联 ${ids.length} 个视图节点`;
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("请输入 Swagger 文档 URL");
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 ? error.message : "无法请求 Swagger 文档"
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(`Swagger 文档请求失败: HTTP ${response.status}`);
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("返回内容为 HTML,请填写 OpenAPI/Swagger 的 JSON 地址");
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("Swagger 文档不是有效的 JSON");
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
- 右键画布添加节点 · 从右侧圆点拖到左侧圆点连线 · 初始应看到 A→B 蓝线
23
+ {t("blueprint.dev.hint")}
22
24
  </span>
23
25
  <span className="text-muted-foreground">
24
- 节点 {graph.document.nodes.length} · 边 {graph.document.edges.length}
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
- <ThemeProvider defaultTheme="light" enableSystem={false}>
41
- <DevApp />
42
- </ThemeProvider>
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="输入 A(多连线为或)"
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="输入 B(多连线为或)"
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)}