@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
package/index.ts
CHANGED
|
@@ -7,7 +7,8 @@ export type {
|
|
|
7
7
|
BlueprintLibraryOption,
|
|
8
8
|
} from "./src/BlueprintNodeConfigSidebar";
|
|
9
9
|
export * from "./src/graph";
|
|
10
|
-
export {
|
|
10
|
+
export { patchNodeConfigSource } from "./src/graph/document";
|
|
11
|
+
export { resolveBlueprintConfigSource, resolveBlueprintNodeTypeLabel, getBlueprintNodeTypeLabel, getLifecyclePhaseLabel, BLUEPRINT_CONFIG_TYPE_LABEL_KEYS, BLUEPRINT_LIFECYCLE_PHASE_KEYS } from "./src/graph/document";
|
|
11
12
|
export type { BlueprintConfigSource } from "./src/graph/document";
|
|
12
13
|
export { documentToRunnableGraph } from "./src/runtime/document-to-runnable-graph";
|
|
13
14
|
export { BlueprintExecutionLogPanel } from "./src/components/BlueprintExecutionLogPanel";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arronqzy/react-blueprint",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"exports": {
|
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
"dayjs": "^1.11.13",
|
|
13
13
|
"react-dom": "^19",
|
|
14
14
|
"@xyflow/react": "^12.9.3",
|
|
15
|
-
"@arronqzy/
|
|
15
|
+
"@arronqzy/i18n": "0.1.1",
|
|
16
|
+
"@arronqzy/ui": "1.0.3",
|
|
16
17
|
"@arronqzy/react-rx-store": "1.1.2",
|
|
17
|
-
"@arronqzy/
|
|
18
|
+
"@arronqzy/blueprint-dsl": "1.0.3"
|
|
18
19
|
},
|
|
19
20
|
"devDependencies": {
|
|
20
21
|
"@types/react": "^19.0.1",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useEffect, useRef } from "react";
|
|
2
|
+
import { useI18n } from "@arronqzy/i18n/react";
|
|
2
3
|
|
|
3
4
|
export type BlueprintContextMenuState =
|
|
4
5
|
| {
|
|
@@ -35,6 +36,7 @@ export function BlueprintContextMenu({
|
|
|
35
36
|
onDeleteNode,
|
|
36
37
|
onDeleteEdge,
|
|
37
38
|
}: BlueprintContextMenuProps) {
|
|
39
|
+
const { t } = useI18n();
|
|
38
40
|
const menuRef = useRef<HTMLDivElement>(null);
|
|
39
41
|
|
|
40
42
|
useEffect(() => {
|
|
@@ -74,7 +76,7 @@ export function BlueprintContextMenu({
|
|
|
74
76
|
onClose();
|
|
75
77
|
}}
|
|
76
78
|
>
|
|
77
|
-
|
|
79
|
+
{t("blueprint.toolbar.addNode")}
|
|
78
80
|
</button>
|
|
79
81
|
) : null}
|
|
80
82
|
|
|
@@ -87,7 +89,7 @@ export function BlueprintContextMenu({
|
|
|
87
89
|
onClose();
|
|
88
90
|
}}
|
|
89
91
|
>
|
|
90
|
-
|
|
92
|
+
{t("blueprint.toolbar.deleteNode")}
|
|
91
93
|
</button>
|
|
92
94
|
) : null}
|
|
93
95
|
|
|
@@ -100,7 +102,7 @@ export function BlueprintContextMenu({
|
|
|
100
102
|
onClose();
|
|
101
103
|
}}
|
|
102
104
|
>
|
|
103
|
-
|
|
105
|
+
{t("blueprint.toolbar.deleteEdge")}
|
|
104
106
|
</button>
|
|
105
107
|
) : null}
|
|
106
108
|
</div>
|
|
@@ -9,10 +9,10 @@ import {
|
|
|
9
9
|
} from "@arronqzy/ui";
|
|
10
10
|
import {
|
|
11
11
|
LIFECYCLE_NODE_TYPE,
|
|
12
|
-
PAGE_LIFECYCLE_LABELS,
|
|
13
12
|
PAGE_LIFECYCLE_PHASES,
|
|
14
13
|
type PageLifecyclePhase,
|
|
15
14
|
} from "@arronqzy/blueprint-dsl";
|
|
15
|
+
import { useI18n } from "@arronqzy/i18n/react";
|
|
16
16
|
|
|
17
17
|
import { FetchNodeConfigPanel } from "./components/FetchNodeConfigPanel";
|
|
18
18
|
import { ClockNodeConfigPanel } from "./components/ClockNodeConfigPanel";
|
|
@@ -20,12 +20,14 @@ import { JsonNodeConfigPanel } from "./components/JsonNodeConfigPanel";
|
|
|
20
20
|
import { LogicNodeConfigPanel } from "./components/LogicNodeConfigPanel";
|
|
21
21
|
import { ViewElementMultiSelect } from "./components/ViewElementMultiSelect";
|
|
22
22
|
import {
|
|
23
|
+
getLifecyclePhaseLabel,
|
|
23
24
|
patchNodeConfigSource,
|
|
24
25
|
pruneViewElementIds,
|
|
25
26
|
resolveBlueprintConfigSource,
|
|
26
27
|
resolveViewElementIds,
|
|
27
28
|
type BlueprintConfigSource,
|
|
28
29
|
type BlueprintGraphNode,
|
|
30
|
+
type BlueprintNodeRole,
|
|
29
31
|
} from "./graph/document";
|
|
30
32
|
|
|
31
33
|
export type BlueprintViewElementOption = {
|
|
@@ -67,6 +69,16 @@ export type BlueprintNodeConfigSidebarProps = {
|
|
|
67
69
|
) => void;
|
|
68
70
|
};
|
|
69
71
|
|
|
72
|
+
const ROLE_LABEL_KEYS: Record<BlueprintNodeRole, string> = {
|
|
73
|
+
blueprint: "blueprint.config.roleBlueprint",
|
|
74
|
+
lifecycle: "blueprint.config.roleLifecycle",
|
|
75
|
+
and: "blueprint.config.roleAnd",
|
|
76
|
+
fetch: "blueprint.config.roleFetch",
|
|
77
|
+
json: "blueprint.config.roleJson",
|
|
78
|
+
logic: "blueprint.config.roleLogic",
|
|
79
|
+
clock: "blueprint.config.roleClock",
|
|
80
|
+
};
|
|
81
|
+
|
|
70
82
|
export function BlueprintNodeConfigSidebar({
|
|
71
83
|
node,
|
|
72
84
|
viewElementOptions = [],
|
|
@@ -75,6 +87,7 @@ export function BlueprintNodeConfigSidebar({
|
|
|
75
87
|
onUpdateAllowFalseSignalPropagation,
|
|
76
88
|
onUpdateNode,
|
|
77
89
|
}: BlueprintNodeConfigSidebarProps) {
|
|
90
|
+
const { t } = useI18n();
|
|
78
91
|
const configSource = resolveBlueprintConfigSource(node);
|
|
79
92
|
const linkedViewElementIds = resolveViewElementIds(node);
|
|
80
93
|
const existingViewElementIdSet = useMemo(
|
|
@@ -108,28 +121,19 @@ export function BlueprintNodeConfigSidebar({
|
|
|
108
121
|
viewElementOptions.length,
|
|
109
122
|
]);
|
|
110
123
|
|
|
124
|
+
const roleLabel = t(ROLE_LABEL_KEYS[node.role] ?? "blueprint.config.roleLogic");
|
|
125
|
+
|
|
111
126
|
return (
|
|
112
127
|
<div className="flex h-full min-h-0 flex-col overflow-hidden bg-background text-foreground">
|
|
113
128
|
<div className="shrink-0 border-b border-border px-3 py-2">
|
|
114
|
-
<div className="text-xs font-semibold"
|
|
129
|
+
<div className="text-xs font-semibold">{t("blueprint.config.title")}</div>
|
|
115
130
|
<div className="mt-0.5 text-[11px] text-muted-foreground">
|
|
116
|
-
{node.
|
|
117
|
-
? "蓝图节点"
|
|
118
|
-
: node.role === "lifecycle"
|
|
119
|
-
? "生命周期节点"
|
|
120
|
-
: node.role === "and"
|
|
121
|
-
? "并运算节点"
|
|
122
|
-
: node.role === "fetch"
|
|
123
|
-
? "数据源节点"
|
|
124
|
-
: node.role === "json"
|
|
125
|
-
? "JSON 节点"
|
|
126
|
-
: "逻辑节点"}{" "}
|
|
127
|
-
· {node.id}
|
|
131
|
+
{roleLabel} · {node.id}
|
|
128
132
|
</div>
|
|
129
133
|
</div>
|
|
130
134
|
<div className="min-h-0 flex-1 space-y-3 overflow-auto p-3 text-xs">
|
|
131
135
|
<label className="block space-y-1">
|
|
132
|
-
<span className="text-muted-foreground"
|
|
136
|
+
<span className="text-muted-foreground">{t("blueprint.config.nodeName")}</span>
|
|
133
137
|
<Input
|
|
134
138
|
value={node.label}
|
|
135
139
|
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
|
@@ -140,7 +144,7 @@ export function BlueprintNodeConfigSidebar({
|
|
|
140
144
|
</label>
|
|
141
145
|
|
|
142
146
|
<label className="block space-y-1">
|
|
143
|
-
<span className="text-muted-foreground"
|
|
147
|
+
<span className="text-muted-foreground">{t("blueprint.config.configType")}</span>
|
|
144
148
|
<Select
|
|
145
149
|
value={configSource}
|
|
146
150
|
onValueChange={(value: string) => {
|
|
@@ -163,25 +167,25 @@ export function BlueprintNodeConfigSidebar({
|
|
|
163
167
|
<SelectValue />
|
|
164
168
|
</SelectTrigger>
|
|
165
169
|
<SelectContent>
|
|
166
|
-
<SelectItem value="blueprint"
|
|
167
|
-
<SelectItem value="logic"
|
|
168
|
-
<SelectItem value="and"
|
|
169
|
-
<SelectItem value="lifecycle"
|
|
170
|
-
<SelectItem value="fetch"
|
|
171
|
-
<SelectItem value="json">
|
|
172
|
-
<SelectItem value="clock"
|
|
173
|
-
<SelectItem value="view"
|
|
170
|
+
<SelectItem value="blueprint">{t("blueprint.config.configBlueprint")}</SelectItem>
|
|
171
|
+
<SelectItem value="logic">{t("blueprint.config.configLogic")}</SelectItem>
|
|
172
|
+
<SelectItem value="and">{t("blueprint.config.configAnd")}</SelectItem>
|
|
173
|
+
<SelectItem value="lifecycle">{t("blueprint.config.configLifecycle")}</SelectItem>
|
|
174
|
+
<SelectItem value="fetch">{t("blueprint.config.configFetch")}</SelectItem>
|
|
175
|
+
<SelectItem value="json">{t("blueprint.config.configJson")}</SelectItem>
|
|
176
|
+
<SelectItem value="clock">{t("blueprint.config.configClock")}</SelectItem>
|
|
177
|
+
<SelectItem value="view">{t("blueprint.config.configView")}</SelectItem>
|
|
174
178
|
</SelectContent>
|
|
175
179
|
</Select>
|
|
176
180
|
</label>
|
|
177
181
|
|
|
178
182
|
{configSource === "view" ? (
|
|
179
183
|
<div className="block space-y-1">
|
|
180
|
-
<span className="text-muted-foreground"
|
|
184
|
+
<span className="text-muted-foreground">{t("blueprint.config.linkedViewNodes")}</span>
|
|
181
185
|
<ViewElementMultiSelect
|
|
182
186
|
options={viewElementOptions}
|
|
183
187
|
value={linkedViewElementIds}
|
|
184
|
-
placeholder="
|
|
188
|
+
placeholder={t("blueprint.config.selectViewNode")}
|
|
185
189
|
onChange={(next) =>
|
|
186
190
|
onUpdateNode(node.id, {
|
|
187
191
|
viewElementIds: next,
|
|
@@ -192,15 +196,16 @@ export function BlueprintNodeConfigSidebar({
|
|
|
192
196
|
/>
|
|
193
197
|
{linkedViewElementIds.length === 0 ? (
|
|
194
198
|
<p className="text-[11px] text-muted-foreground">
|
|
195
|
-
|
|
199
|
+
{t("blueprint.config.viewMultiHint")}
|
|
196
200
|
</p>
|
|
197
201
|
) : (
|
|
198
202
|
<p className="text-[11px] text-muted-foreground">
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
203
|
+
{t("blueprint.config.linkedViewCount", {
|
|
204
|
+
count: linkedViewElementIds.length,
|
|
205
|
+
names: linkedViewElementIds
|
|
206
|
+
.map((id) => viewElementLabelById.get(id) ?? id)
|
|
207
|
+
.join("、"),
|
|
208
|
+
})}
|
|
204
209
|
</p>
|
|
205
210
|
)}
|
|
206
211
|
</div>
|
|
@@ -208,15 +213,12 @@ export function BlueprintNodeConfigSidebar({
|
|
|
208
213
|
|
|
209
214
|
{configSource === "blueprint" ? (
|
|
210
215
|
<div className="space-y-2 rounded-md border border-border/70 bg-muted/20 p-2.5">
|
|
211
|
-
<div className="font-medium text-foreground"
|
|
216
|
+
<div className="font-medium text-foreground">{t("blueprint.config.blueprintAttrs")}</div>
|
|
212
217
|
<p className="text-[11px] text-muted-foreground">
|
|
213
|
-
|
|
214
|
-
时才会执行该蓝图;执行完成后从输出端发出
|
|
215
|
-
<strong>真信号</strong>(含嵌套蓝图输出值与当前节点信息),执行失败则发出
|
|
216
|
-
<strong>假信号</strong>。
|
|
218
|
+
{t("blueprint.config.blueprintAttrsHint")}
|
|
217
219
|
</p>
|
|
218
220
|
<label className="block space-y-1">
|
|
219
|
-
<span className="text-muted-foreground"
|
|
221
|
+
<span className="text-muted-foreground">{t("blueprint.config.refLibrary")}</span>
|
|
220
222
|
<Select
|
|
221
223
|
value={node.libraryBlueprintId ?? "__none__"}
|
|
222
224
|
onValueChange={(value: string) => {
|
|
@@ -227,10 +229,10 @@ export function BlueprintNodeConfigSidebar({
|
|
|
227
229
|
}}
|
|
228
230
|
>
|
|
229
231
|
<SelectTrigger className="h-8">
|
|
230
|
-
<SelectValue placeholder="
|
|
232
|
+
<SelectValue placeholder={t("blueprint.config.selectLibraryBlueprint")} />
|
|
231
233
|
</SelectTrigger>
|
|
232
234
|
<SelectContent className="z-[10100]">
|
|
233
|
-
<SelectItem value="__none__"
|
|
235
|
+
<SelectItem value="__none__">{t("blueprint.config.unlinked")}</SelectItem>
|
|
234
236
|
{blueprintLibraryOptions.map((opt) => (
|
|
235
237
|
<SelectItem key={opt.id} value={opt.id}>
|
|
236
238
|
{opt.label}
|
|
@@ -241,7 +243,7 @@ export function BlueprintNodeConfigSidebar({
|
|
|
241
243
|
</label>
|
|
242
244
|
{!node.libraryBlueprintId ? (
|
|
243
245
|
<p className="text-[11px] text-muted-foreground">
|
|
244
|
-
|
|
246
|
+
{t("blueprint.config.selectLibraryFirst")}
|
|
245
247
|
</p>
|
|
246
248
|
) : null}
|
|
247
249
|
<label className="flex items-start gap-2 pt-1">
|
|
@@ -254,7 +256,7 @@ export function BlueprintNodeConfigSidebar({
|
|
|
254
256
|
className="mt-0.5 h-3.5 w-3.5 shrink-0 rounded border border-input"
|
|
255
257
|
/>
|
|
256
258
|
<span className="text-[11px] leading-relaxed text-muted-foreground">
|
|
257
|
-
|
|
259
|
+
{t("blueprint.config.allowFalsePropagateBlueprint")}
|
|
258
260
|
</span>
|
|
259
261
|
</label>
|
|
260
262
|
</div>
|
|
@@ -262,15 +264,15 @@ export function BlueprintNodeConfigSidebar({
|
|
|
262
264
|
|
|
263
265
|
{configSource === "lifecycle" ? (
|
|
264
266
|
<div className="space-y-2 rounded-md border border-border/70 bg-muted/20 p-2.5">
|
|
265
|
-
<div className="font-medium text-foreground"
|
|
267
|
+
<div className="font-medium text-foreground">{t("blueprint.config.lifecycleHook")}</div>
|
|
266
268
|
<p className="text-[11px] text-muted-foreground">
|
|
267
|
-
|
|
269
|
+
{t("blueprint.config.lifecycleNoInput")}
|
|
268
270
|
{node.lifecyclePhase === "blueprintActivated"
|
|
269
|
-
? "
|
|
270
|
-
: "
|
|
271
|
+
? t("blueprint.config.lifecycleBlueprintActivatedHint")
|
|
272
|
+
: t("blueprint.config.lifecyclePageHint")}
|
|
271
273
|
</p>
|
|
272
274
|
<label className="block space-y-1">
|
|
273
|
-
<span className="text-muted-foreground"
|
|
275
|
+
<span className="text-muted-foreground">{t("blueprint.config.listenPhase")}</span>
|
|
274
276
|
<Select
|
|
275
277
|
value={node.lifecyclePhase ?? "mounted"}
|
|
276
278
|
onValueChange={(value: string) =>
|
|
@@ -288,7 +290,7 @@ export function BlueprintNodeConfigSidebar({
|
|
|
288
290
|
<SelectContent>
|
|
289
291
|
{PAGE_LIFECYCLE_PHASES.map((phase) => (
|
|
290
292
|
<SelectItem key={phase} value={phase}>
|
|
291
|
-
{
|
|
293
|
+
{getLifecyclePhaseLabel(t, phase)}
|
|
292
294
|
</SelectItem>
|
|
293
295
|
))}
|
|
294
296
|
</SelectContent>
|
|
@@ -296,7 +298,7 @@ export function BlueprintNodeConfigSidebar({
|
|
|
296
298
|
</label>
|
|
297
299
|
{node.parentId ? (
|
|
298
300
|
<p className="text-[11px] text-muted-foreground">
|
|
299
|
-
|
|
301
|
+
{t("blueprint.config.parentBlueprintNode", { id: node.parentId })}
|
|
300
302
|
</p>
|
|
301
303
|
) : null}
|
|
302
304
|
</div>
|
|
@@ -316,12 +318,9 @@ export function BlueprintNodeConfigSidebar({
|
|
|
316
318
|
|
|
317
319
|
{configSource === "and" ? (
|
|
318
320
|
<div className="space-y-2 rounded-md border border-border/70 bg-muted/20 p-2.5">
|
|
319
|
-
<div className="font-medium text-foreground"
|
|
321
|
+
<div className="font-medium text-foreground">{t("blueprint.config.andTitle")}</div>
|
|
320
322
|
<p className="text-[11px] text-muted-foreground">
|
|
321
|
-
|
|
322
|
-
每个输入口可连 n 条线,同端口任一为真则该端口视为真(或)。
|
|
323
|
-
仅当 <strong>inA 与 inB 均为真信号</strong> 时,从输出口发出真信号;
|
|
324
|
-
否则发出假信号。
|
|
323
|
+
{t("blueprint.config.andHint")}
|
|
325
324
|
</p>
|
|
326
325
|
</div>
|
|
327
326
|
) : null}
|
|
@@ -331,7 +330,7 @@ export function BlueprintNodeConfigSidebar({
|
|
|
331
330
|
<LogicNodeConfigPanel node={node} onUpdateNode={onUpdateNode} />
|
|
332
331
|
{node.parentId ? (
|
|
333
332
|
<p className="text-[11px] text-muted-foreground">
|
|
334
|
-
|
|
333
|
+
{t("blueprint.config.parentBlueprintNode", { id: node.parentId })}
|
|
335
334
|
</p>
|
|
336
335
|
) : null}
|
|
337
336
|
</>
|
|
@@ -339,7 +338,7 @@ export function BlueprintNodeConfigSidebar({
|
|
|
339
338
|
|
|
340
339
|
{configSource !== "blueprint" && configSource !== "and" ? (
|
|
341
340
|
<div className="space-y-2 rounded-md border border-border/70 bg-muted/20 p-2.5">
|
|
342
|
-
<div className="font-medium text-foreground"
|
|
341
|
+
<div className="font-medium text-foreground">{t("blueprint.config.taskChain")}</div>
|
|
343
342
|
<label className="flex items-start gap-2">
|
|
344
343
|
<input
|
|
345
344
|
type="checkbox"
|
|
@@ -350,7 +349,7 @@ export function BlueprintNodeConfigSidebar({
|
|
|
350
349
|
className="mt-0.5 h-3.5 w-3.5 shrink-0 rounded border border-input"
|
|
351
350
|
/>
|
|
352
351
|
<span className="text-[11px] leading-relaxed text-muted-foreground">
|
|
353
|
-
|
|
352
|
+
{t("blueprint.config.allowFalsePropagateDefault")}
|
|
354
353
|
</span>
|
|
355
354
|
</label>
|
|
356
355
|
</div>
|
|
@@ -17,10 +17,11 @@ import {
|
|
|
17
17
|
cn,
|
|
18
18
|
} from "@arronqzy/ui";
|
|
19
19
|
import {
|
|
20
|
-
|
|
21
|
-
type ExecutionTraceEntry,
|
|
20
|
+
type ExecutionTraceEntry,
|
|
22
21
|
type PageLifecyclePhase,
|
|
23
22
|
} from "@arronqzy/blueprint-dsl";
|
|
23
|
+
import { useI18n } from "@arronqzy/i18n/react";
|
|
24
|
+
import { getLifecyclePhaseLabel } from "../graph/document";
|
|
24
25
|
|
|
25
26
|
import type { ExecutionLogSettings } from "../library/execution-log-settings";
|
|
26
27
|
|
|
@@ -151,6 +152,7 @@ export function BlueprintExecutionLogPanel({
|
|
|
151
152
|
hasSavedRuns = false,
|
|
152
153
|
lifecyclePhase,
|
|
153
154
|
}: BlueprintExecutionLogPanelProps) {
|
|
155
|
+
const { t } = useI18n();
|
|
154
156
|
const scrollRef = useRef<HTMLDivElement>(null);
|
|
155
157
|
const bottomRef = useRef<HTMLDivElement>(null);
|
|
156
158
|
const prevEntryCountRef = useRef(entries.length);
|
|
@@ -160,8 +162,8 @@ export function BlueprintExecutionLogPanel({
|
|
|
160
162
|
|
|
161
163
|
const phaseLabel = useMemo(() => {
|
|
162
164
|
if (!lifecyclePhase) return null;
|
|
163
|
-
return
|
|
164
|
-
}, [lifecyclePhase]);
|
|
165
|
+
return getLifecyclePhaseLabel(t, lifecyclePhase as PageLifecyclePhase);
|
|
166
|
+
}, [lifecyclePhase, t]);
|
|
165
167
|
|
|
166
168
|
const latestEntryPreview = useMemo(() => {
|
|
167
169
|
const latest = entries[entries.length - 1];
|
|
@@ -211,9 +213,9 @@ export function BlueprintExecutionLogPanel({
|
|
|
211
213
|
<div className="shrink-0 border-b border-border px-3 py-2">
|
|
212
214
|
<div className="flex items-start justify-between gap-2">
|
|
213
215
|
<div className="min-w-0">
|
|
214
|
-
<div className="text-xs font-semibold"
|
|
216
|
+
<div className="text-xs font-semibold">{t("blueprint.log.title")}</div>
|
|
215
217
|
<div className="mt-0.5 text-[11px] text-muted-foreground">
|
|
216
|
-
{phaseLabel ?
|
|
218
|
+
{phaseLabel ? t("blueprint.log.simulateSceneWithPhase", { phaseLabel }) : t("blueprint.log.selectLifecycleToDebug")}
|
|
217
219
|
</div>
|
|
218
220
|
</div>
|
|
219
221
|
<div className="flex shrink-0 items-center gap-1">
|
|
@@ -223,8 +225,8 @@ export function BlueprintExecutionLogPanel({
|
|
|
223
225
|
variant="outline"
|
|
224
226
|
size="icon"
|
|
225
227
|
className="h-7 w-7 shrink-0"
|
|
226
|
-
content="
|
|
227
|
-
aria-label="
|
|
228
|
+
content={t("blueprint.log.clearIdbTooltip")}
|
|
229
|
+
aria-label={t("blueprint.log.clearIdbAria")}
|
|
228
230
|
disabled={!hasSavedRuns}
|
|
229
231
|
onClick={() => void onClearAllSaved()}
|
|
230
232
|
>
|
|
@@ -236,8 +238,8 @@ export function BlueprintExecutionLogPanel({
|
|
|
236
238
|
variant="outline"
|
|
237
239
|
size="icon"
|
|
238
240
|
className="h-7 w-7 shrink-0"
|
|
239
|
-
content="
|
|
240
|
-
aria-label="
|
|
241
|
+
content={t("blueprint.log.clearCurrentTooltip")}
|
|
242
|
+
aria-label={t("blueprint.log.clearCurrentAria")}
|
|
241
243
|
disabled={entries.length === 0}
|
|
242
244
|
onClick={onClear}
|
|
243
245
|
>
|
|
@@ -255,7 +257,7 @@ export function BlueprintExecutionLogPanel({
|
|
|
255
257
|
>
|
|
256
258
|
{entries.length === 0 ? (
|
|
257
259
|
<p className="text-[11px] text-muted-foreground">
|
|
258
|
-
|
|
260
|
+
{t("blueprint.log.emptyHint")}
|
|
259
261
|
</p>
|
|
260
262
|
) : (
|
|
261
263
|
<div className="space-y-0">
|
|
@@ -279,7 +281,7 @@ export function BlueprintExecutionLogPanel({
|
|
|
279
281
|
<div className="mt-2 grid gap-2">
|
|
280
282
|
<div>
|
|
281
283
|
<div className="mb-1 text-[10px] font-medium text-muted-foreground">
|
|
282
|
-
|
|
284
|
+
{t("blueprint.log.input")}
|
|
283
285
|
</div>
|
|
284
286
|
<pre className="max-h-32 overflow-auto rounded border border-border/60 bg-background p-2 font-mono text-[10px] leading-relaxed text-foreground">
|
|
285
287
|
{formatJson(entry.inputs)}
|
|
@@ -287,7 +289,7 @@ export function BlueprintExecutionLogPanel({
|
|
|
287
289
|
</div>
|
|
288
290
|
<div>
|
|
289
291
|
<div className="mb-1 text-[10px] font-medium text-muted-foreground">
|
|
290
|
-
|
|
292
|
+
{t("blueprint.log.output")}
|
|
291
293
|
</div>
|
|
292
294
|
<pre
|
|
293
295
|
className={cn(
|
|
@@ -322,7 +324,7 @@ export function BlueprintExecutionLogPanel({
|
|
|
322
324
|
onClick={() => scrollToBottom("smooth")}
|
|
323
325
|
>
|
|
324
326
|
<ArrowDownIcon className="h-3.5 w-3.5 shrink-0" />
|
|
325
|
-
<span className="truncate"
|
|
327
|
+
<span className="truncate">{t("blueprint.log.hasNewLogs")}</span>
|
|
326
328
|
{latestEntryPreview ? (
|
|
327
329
|
<span className="truncate opacity-90">· {latestEntryPreview}</span>
|
|
328
330
|
) : null}
|
|
@@ -338,26 +340,26 @@ export function BlueprintExecutionLogPanel({
|
|
|
338
340
|
variant="outline"
|
|
339
341
|
size="sm"
|
|
340
342
|
className="w-full"
|
|
341
|
-
content="
|
|
343
|
+
content={t("blueprint.log.saveLogTooltip")}
|
|
342
344
|
disabled={entries.length === 0}
|
|
343
345
|
onClick={onSave}
|
|
344
346
|
>
|
|
345
|
-
|
|
347
|
+
{t("blueprint.log.saveLog")}
|
|
346
348
|
</LogTooltipButton>
|
|
347
349
|
<LogTooltipButton
|
|
348
350
|
type="button"
|
|
349
351
|
variant="outline"
|
|
350
352
|
size="sm"
|
|
351
353
|
className="w-full"
|
|
352
|
-
content="
|
|
354
|
+
content={t("blueprint.log.exportJsonTooltip")}
|
|
353
355
|
disabled={entries.length === 0}
|
|
354
356
|
onClick={onExport}
|
|
355
357
|
>
|
|
356
|
-
|
|
358
|
+
{t("blueprint.log.exportJson")}
|
|
357
359
|
</LogTooltipButton>
|
|
358
360
|
</div>
|
|
359
361
|
|
|
360
|
-
<LogTooltip content="
|
|
362
|
+
<LogTooltip content={t("blueprint.log.autoSaveTooltip")}>
|
|
361
363
|
<label className="flex cursor-default items-center gap-2">
|
|
362
364
|
<input
|
|
363
365
|
type="checkbox"
|
|
@@ -366,15 +368,15 @@ export function BlueprintExecutionLogPanel({
|
|
|
366
368
|
className="h-3.5 w-3.5 rounded border border-input"
|
|
367
369
|
/>
|
|
368
370
|
<span className="text-[11px] text-muted-foreground">
|
|
369
|
-
|
|
371
|
+
{t("blueprint.log.autoSaveAfterRun")}
|
|
370
372
|
</span>
|
|
371
373
|
</label>
|
|
372
374
|
</LogTooltip>
|
|
373
375
|
|
|
374
376
|
<div className="grid grid-cols-2 gap-2">
|
|
375
|
-
<LogTooltip content="
|
|
377
|
+
<LogTooltip content={t("blueprint.log.maxSavedCountTooltip")}>
|
|
376
378
|
<div className="space-y-1">
|
|
377
|
-
<Label className="text-[11px] text-muted-foreground"
|
|
379
|
+
<Label className="text-[11px] text-muted-foreground">{t("blueprint.log.maxSavedCount")}</Label>
|
|
378
380
|
<Input
|
|
379
381
|
type="number"
|
|
380
382
|
min={1}
|
|
@@ -386,13 +388,13 @@ export function BlueprintExecutionLogPanel({
|
|
|
386
388
|
})
|
|
387
389
|
}
|
|
388
390
|
className="h-8"
|
|
389
|
-
aria-label="
|
|
391
|
+
aria-label={t("blueprint.log.maxSavedCountAria")}
|
|
390
392
|
/>
|
|
391
393
|
</div>
|
|
392
394
|
</LogTooltip>
|
|
393
|
-
<LogTooltip content="
|
|
395
|
+
<LogTooltip content={t("blueprint.log.retentionDaysTooltip")}>
|
|
394
396
|
<div className="space-y-1">
|
|
395
|
-
<Label className="text-[11px] text-muted-foreground"
|
|
397
|
+
<Label className="text-[11px] text-muted-foreground">{t("blueprint.log.retentionDays")}</Label>
|
|
396
398
|
<Input
|
|
397
399
|
type="number"
|
|
398
400
|
min={1}
|
|
@@ -404,7 +406,7 @@ export function BlueprintExecutionLogPanel({
|
|
|
404
406
|
})
|
|
405
407
|
}
|
|
406
408
|
className="h-8"
|
|
407
|
-
aria-label="
|
|
409
|
+
aria-label={t("blueprint.log.retentionDaysAria")}
|
|
408
410
|
/>
|
|
409
411
|
</div>
|
|
410
412
|
</LogTooltip>
|
|
@@ -415,10 +417,10 @@ export function BlueprintExecutionLogPanel({
|
|
|
415
417
|
variant="secondary"
|
|
416
418
|
size="sm"
|
|
417
419
|
className="w-full"
|
|
418
|
-
content="
|
|
420
|
+
content={t("blueprint.log.cleanupTooltip")}
|
|
419
421
|
onClick={onApplyRetention}
|
|
420
422
|
>
|
|
421
|
-
|
|
423
|
+
{t("blueprint.log.cleanupExpired")}
|
|
422
424
|
</LogTooltipButton>
|
|
423
425
|
</div>
|
|
424
426
|
</div>
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
SelectTrigger,
|
|
8
8
|
SelectValue,
|
|
9
9
|
} from "@arronqzy/ui";
|
|
10
|
+
import { useI18n } from "@arronqzy/i18n/react";
|
|
10
11
|
|
|
11
12
|
import type { BlueprintLibraryListItem } from "../library/types";
|
|
12
13
|
|
|
@@ -26,11 +27,13 @@ function groupItems(items: BlueprintLibraryListItem[]) {
|
|
|
26
27
|
export function BlueprintLibrarySelect({
|
|
27
28
|
items,
|
|
28
29
|
value,
|
|
29
|
-
placeholder
|
|
30
|
+
placeholder,
|
|
30
31
|
onSelect,
|
|
31
32
|
}: BlueprintLibrarySelectProps) {
|
|
33
|
+
const { t } = useI18n();
|
|
32
34
|
const { saved, imported } = groupItems(items);
|
|
33
35
|
const hasItems = items.length > 0;
|
|
36
|
+
const resolvedPlaceholder = placeholder ?? t("blueprint.toolbar.library");
|
|
34
37
|
|
|
35
38
|
return (
|
|
36
39
|
<Select
|
|
@@ -39,12 +42,16 @@ export function BlueprintLibrarySelect({
|
|
|
39
42
|
disabled={!hasItems}
|
|
40
43
|
>
|
|
41
44
|
<SelectTrigger className="h-7 w-[168px] text-xs">
|
|
42
|
-
<SelectValue
|
|
45
|
+
<SelectValue
|
|
46
|
+
placeholder={
|
|
47
|
+
hasItems ? resolvedPlaceholder : t("blueprint.toolbar.libraryEmpty")
|
|
48
|
+
}
|
|
49
|
+
/>
|
|
43
50
|
</SelectTrigger>
|
|
44
51
|
<SelectContent className="z-[10100]">
|
|
45
52
|
{saved.length > 0 ? (
|
|
46
53
|
<SelectGroup>
|
|
47
|
-
<SelectLabel
|
|
54
|
+
<SelectLabel>{t("blueprint.toolbar.saved")}</SelectLabel>
|
|
48
55
|
{saved.map((item) => (
|
|
49
56
|
<SelectItem key={item.id} value={item.id} className="text-xs">
|
|
50
57
|
{item.name}
|
|
@@ -54,7 +61,7 @@ export function BlueprintLibrarySelect({
|
|
|
54
61
|
) : null}
|
|
55
62
|
{imported.length > 0 ? (
|
|
56
63
|
<SelectGroup>
|
|
57
|
-
<SelectLabel
|
|
64
|
+
<SelectLabel>{t("blueprint.toolbar.imported")}</SelectLabel>
|
|
58
65
|
{imported.map((item) => (
|
|
59
66
|
<SelectItem key={item.id} value={item.id} className="text-xs">
|
|
60
67
|
{item.name}
|