@arronqzy/react-blueprint 1.0.1 → 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/README.md +103 -0
- package/index.ts +2 -1
- package/package.json +7 -6
- package/src/BlueprintContextMenu.tsx +5 -3
- package/src/BlueprintNodeConfigSidebar.tsx +59 -57
- package/src/blueprint.css +21 -15
- package/src/components/BlueprintExecutionLogPanel.tsx +32 -30
- 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 +40 -34
- 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/blueprint-graph.ts +5 -1
- package/src/graph/document.ts +97 -22
- package/src/graph/node-summary.ts +32 -18
- package/src/graph/sync-nodes.ts +3 -1
- package/src/hooks/useBlueprintDebugSession.ts +24 -22
- package/src/hooks/useBlueprintFlowColorMode.ts +30 -6
- 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/src/runtime/document-to-runnable-graph.ts +9 -6
|
@@ -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
|
|
|
@@ -53,8 +54,8 @@ function IconClearDb({ className }: { className?: string }) {
|
|
|
53
54
|
aria-hidden="true"
|
|
54
55
|
>
|
|
55
56
|
<ellipse cx="12" cy="6" rx="7" ry="2.5" />
|
|
56
|
-
<path d="M5 6v12c0 1.5 3.
|
|
57
|
-
<path d="M5 12c0 1.5 3.
|
|
57
|
+
<path d="M5 6v12c0 1.5 3.134 2.5 7 2.5s7-1.343 7-2.5V6" />
|
|
58
|
+
<path d="M5 12c0 1.5 3.134 2.5 7 2.5s7-1.343 7-2.5" />
|
|
58
59
|
<path d="m16 16 4 4M20 16l-4 4" />
|
|
59
60
|
</svg>
|
|
60
61
|
);
|
|
@@ -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}
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
Label,
|
|
12
12
|
Textarea,
|
|
13
13
|
} from "@arronqzy/ui";
|
|
14
|
+
import { useI18n } from "@arronqzy/i18n/react";
|
|
14
15
|
|
|
15
16
|
import type { BlueprintMetaDraft } from "../library/types";
|
|
16
17
|
|
|
@@ -29,6 +30,7 @@ export function BlueprintMetaDialog({
|
|
|
29
30
|
onOpenChange,
|
|
30
31
|
onConfirm,
|
|
31
32
|
}: BlueprintMetaDialogProps) {
|
|
33
|
+
const { t } = useI18n();
|
|
32
34
|
const [name, setName] = useState(initialMeta.name);
|
|
33
35
|
const [remark, setRemark] = useState(initialMeta.remark);
|
|
34
36
|
|
|
@@ -38,16 +40,20 @@ export function BlueprintMetaDialog({
|
|
|
38
40
|
setRemark(initialMeta.remark);
|
|
39
41
|
}, [initialMeta.name, initialMeta.remark, open]);
|
|
40
42
|
|
|
41
|
-
const title =
|
|
43
|
+
const title =
|
|
44
|
+
mode === "export"
|
|
45
|
+
? t("blueprint.dialog.exportTitle")
|
|
46
|
+
: t("blueprint.dialog.saveTitle");
|
|
42
47
|
const description =
|
|
43
48
|
mode === "export"
|
|
44
|
-
? "
|
|
45
|
-
: "
|
|
46
|
-
const confirmLabel =
|
|
49
|
+
? t("blueprint.dialog.exportDescription")
|
|
50
|
+
: t("blueprint.dialog.saveDescription");
|
|
51
|
+
const confirmLabel =
|
|
52
|
+
mode === "export" ? t("blueprint.dialog.export") : t("blueprint.dialog.save");
|
|
47
53
|
|
|
48
54
|
const handleConfirm = () => {
|
|
49
55
|
onConfirm({
|
|
50
|
-
name: name.trim() || "
|
|
56
|
+
name: name.trim() || t("blueprint.dialog.unnamedBlueprint"),
|
|
51
57
|
remark: remark.trim(),
|
|
52
58
|
});
|
|
53
59
|
onOpenChange(false);
|
|
@@ -62,29 +68,33 @@ export function BlueprintMetaDialog({
|
|
|
62
68
|
</DialogHeader>
|
|
63
69
|
<div className="space-y-3 py-1">
|
|
64
70
|
<div className="space-y-1.5">
|
|
65
|
-
<Label htmlFor="blueprint-meta-name"
|
|
71
|
+
<Label htmlFor="blueprint-meta-name">
|
|
72
|
+
{t("blueprint.dialog.blueprintName")}
|
|
73
|
+
</Label>
|
|
66
74
|
<Input
|
|
67
75
|
id="blueprint-meta-name"
|
|
68
76
|
value={name}
|
|
69
77
|
onChange={(e) => setName(e.target.value)}
|
|
70
|
-
placeholder="
|
|
78
|
+
placeholder={t("blueprint.dialog.namePlaceholder")}
|
|
71
79
|
autoFocus
|
|
72
80
|
/>
|
|
73
81
|
</div>
|
|
74
82
|
<div className="space-y-1.5">
|
|
75
|
-
<Label htmlFor="blueprint-meta-remark"
|
|
83
|
+
<Label htmlFor="blueprint-meta-remark">
|
|
84
|
+
{t("blueprint.dialog.remark")}
|
|
85
|
+
</Label>
|
|
76
86
|
<Textarea
|
|
77
87
|
id="blueprint-meta-remark"
|
|
78
88
|
value={remark}
|
|
79
89
|
onChange={(e) => setRemark(e.target.value)}
|
|
80
|
-
placeholder="
|
|
90
|
+
placeholder={t("blueprint.dialog.remarkPlaceholder")}
|
|
81
91
|
rows={3}
|
|
82
92
|
/>
|
|
83
93
|
</div>
|
|
84
94
|
</div>
|
|
85
95
|
<DialogFooter>
|
|
86
96
|
<Button type="button" variant="outline" onClick={() => onOpenChange(false)}>
|
|
87
|
-
|
|
97
|
+
{t("common.cancel")}
|
|
88
98
|
</Button>
|
|
89
99
|
<Button type="button" onClick={handleConfirm}>
|
|
90
100
|
{confirmLabel}
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
DialogHeader,
|
|
8
8
|
DialogTitle,
|
|
9
9
|
} from "@arronqzy/ui";
|
|
10
|
+
import { useI18n } from "@arronqzy/i18n/react";
|
|
10
11
|
|
|
11
12
|
export type BlueprintNodeSwitchTaskDialogProps = {
|
|
12
13
|
open: boolean;
|
|
@@ -25,31 +26,36 @@ export function BlueprintNodeSwitchTaskDialog({
|
|
|
25
26
|
onKeepTaskAndSwitch,
|
|
26
27
|
onCancelTaskAndSwitch,
|
|
27
28
|
}: BlueprintNodeSwitchTaskDialogProps) {
|
|
29
|
+
const { t } = useI18n();
|
|
28
30
|
const targetLabel =
|
|
29
|
-
toNodeId === null
|
|
31
|
+
toNodeId === null
|
|
32
|
+
? t("blueprint.dialog.cancelSelection")
|
|
33
|
+
: t("blueprint.dialog.nodeTarget", { id: toNodeId });
|
|
30
34
|
|
|
31
35
|
return (
|
|
32
36
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
33
37
|
<DialogContent className="sm:max-w-md">
|
|
34
38
|
<DialogHeader>
|
|
35
|
-
<DialogTitle
|
|
39
|
+
<DialogTitle>{t("blueprint.dialog.taskRunningTitle")}</DialogTitle>
|
|
36
40
|
<DialogDescription>
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
{t("blueprint.dialog.taskRunningDescription", {
|
|
42
|
+
fromNodeId,
|
|
43
|
+
target: targetLabel,
|
|
44
|
+
})}
|
|
39
45
|
</DialogDescription>
|
|
40
46
|
</DialogHeader>
|
|
41
47
|
<p className="text-xs text-muted-foreground">
|
|
42
|
-
|
|
48
|
+
{t("blueprint.dialog.taskSwitchHint")}
|
|
43
49
|
</p>
|
|
44
50
|
<DialogFooter className="gap-2 sm:gap-0">
|
|
45
51
|
<Button type="button" variant="outline" onClick={() => onOpenChange(false)}>
|
|
46
|
-
|
|
52
|
+
{t("blueprint.dialog.stayOnNode")}
|
|
47
53
|
</Button>
|
|
48
54
|
<Button type="button" variant="secondary" onClick={onCancelTaskAndSwitch}>
|
|
49
|
-
|
|
55
|
+
{t("blueprint.dialog.cancelAndSwitch")}
|
|
50
56
|
</Button>
|
|
51
57
|
<Button type="button" onClick={onKeepTaskAndSwitch}>
|
|
52
|
-
|
|
58
|
+
{t("blueprint.dialog.keepAndSwitch")}
|
|
53
59
|
</Button>
|
|
54
60
|
</DialogFooter>
|
|
55
61
|
</DialogContent>
|