@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.
- package/index.ts +2 -1
- package/package.json +7 -6
- 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
|
@@ -34,6 +34,8 @@ import {
|
|
|
34
34
|
useFetchDebugTask,
|
|
35
35
|
useSwaggerLoadTask,
|
|
36
36
|
} from "../fetch-config-task-store";
|
|
37
|
+
import { useI18n } from "@arronqzy/i18n/react";
|
|
38
|
+
|
|
37
39
|
import { FetchUrlAutocomplete } from "./FetchUrlAutocomplete";
|
|
38
40
|
|
|
39
41
|
function SendIcon({ className }: { className?: string }) {
|
|
@@ -145,6 +147,7 @@ function FetchDebugResponsePanel({
|
|
|
145
147
|
}: {
|
|
146
148
|
task: ReturnType<typeof useFetchDebugTask>;
|
|
147
149
|
}) {
|
|
150
|
+
const { t } = useI18n();
|
|
148
151
|
const [expanded, setExpanded] = useState(false);
|
|
149
152
|
|
|
150
153
|
if (task.status === "idle" || task.status === "loading") return null;
|
|
@@ -152,7 +155,7 @@ function FetchDebugResponsePanel({
|
|
|
152
155
|
if (task.status === "error") {
|
|
153
156
|
return (
|
|
154
157
|
<div className="rounded-md border border-destructive/40 bg-destructive/5 p-2">
|
|
155
|
-
<p className="text-[11px] text-destructive">{task.error ?? "
|
|
158
|
+
<p className="text-[11px] text-destructive">{task.error ?? t("blueprint.config.requestFailed")}</p>
|
|
156
159
|
</div>
|
|
157
160
|
);
|
|
158
161
|
}
|
|
@@ -173,7 +176,7 @@ function FetchDebugResponsePanel({
|
|
|
173
176
|
onClick={() => setExpanded((value) => !value)}
|
|
174
177
|
>
|
|
175
178
|
<ChevronIcon className="h-3.5 w-3.5 shrink-0 text-muted-foreground" expanded={expanded} />
|
|
176
|
-
<span className="text-[11px] font-medium text-foreground"
|
|
179
|
+
<span className="text-[11px] font-medium text-foreground">{t("blueprint.config.debugResponse")}</span>
|
|
177
180
|
<span
|
|
178
181
|
className={cn(
|
|
179
182
|
"rounded px-1.5 py-0.5 font-mono text-[10px]",
|
|
@@ -250,6 +253,7 @@ export function FetchNodeConfigPanel({
|
|
|
250
253
|
node,
|
|
251
254
|
onUpdateNode,
|
|
252
255
|
}: FetchNodeConfigPanelProps) {
|
|
256
|
+
const { t } = useI18n();
|
|
253
257
|
const fetchConfig = resolveNodeFetchConfig(node);
|
|
254
258
|
const endpoints = fetchConfig.swaggerEndpoints ?? [];
|
|
255
259
|
const hasSwaggerEndpoints = endpoints.length > 0;
|
|
@@ -275,7 +279,7 @@ export function FetchNodeConfigPanel({
|
|
|
275
279
|
const handleLoadSwagger = useCallback(() => {
|
|
276
280
|
const docsUrl = fetchConfig.swaggerDocsUrl?.trim();
|
|
277
281
|
if (!docsUrl) {
|
|
278
|
-
setValidationError("
|
|
282
|
+
setValidationError(t("blueprint.config.fillSwaggerUrlFirst"));
|
|
279
283
|
return;
|
|
280
284
|
}
|
|
281
285
|
|
|
@@ -305,7 +309,7 @@ export function FetchNodeConfigPanel({
|
|
|
305
309
|
const handleSendFetchDebug = useCallback(() => {
|
|
306
310
|
const url = fetchConfig.url?.trim();
|
|
307
311
|
if (!url) {
|
|
308
|
-
setFetchValidationError("
|
|
312
|
+
setFetchValidationError(t("blueprint.config.fillRequestUrlFirst"));
|
|
309
313
|
return;
|
|
310
314
|
}
|
|
311
315
|
|
|
@@ -323,14 +327,13 @@ export function FetchNodeConfigPanel({
|
|
|
323
327
|
|
|
324
328
|
return (
|
|
325
329
|
<div className="space-y-2 rounded-md border border-border/70 bg-muted/20 p-2.5">
|
|
326
|
-
<div className="font-medium text-foreground"
|
|
330
|
+
<div className="font-medium text-foreground">{t("blueprint.config.fetchTitle")}</div>
|
|
327
331
|
<p className="text-[11px] text-muted-foreground">
|
|
328
|
-
|
|
329
|
-
URL。
|
|
332
|
+
{t("blueprint.config.fetchHint")}
|
|
330
333
|
</p>
|
|
331
334
|
|
|
332
335
|
<label className="block space-y-1">
|
|
333
|
-
<span className="text-muted-foreground">
|
|
336
|
+
<span className="text-muted-foreground">{t("blueprint.config.swaggerUrlOptional")}</span>
|
|
334
337
|
<div className="flex gap-1.5">
|
|
335
338
|
<Input
|
|
336
339
|
value={fetchConfig.swaggerDocsUrl ?? ""}
|
|
@@ -350,8 +353,8 @@ export function FetchNodeConfigPanel({
|
|
|
350
353
|
variant="outline"
|
|
351
354
|
size="icon"
|
|
352
355
|
className="h-8 w-8 shrink-0 text-destructive hover:bg-destructive/10 hover:text-destructive"
|
|
353
|
-
title="
|
|
354
|
-
aria-label="
|
|
356
|
+
title={t("blueprint.config.abortParse")}
|
|
357
|
+
aria-label={t("blueprint.config.abortSwaggerAria")}
|
|
355
358
|
onClick={handleAbortSwagger}
|
|
356
359
|
>
|
|
357
360
|
<StopIcon className="h-3.5 w-3.5" />
|
|
@@ -362,7 +365,7 @@ export function FetchNodeConfigPanel({
|
|
|
362
365
|
variant="outline"
|
|
363
366
|
size="icon"
|
|
364
367
|
className="h-8 w-8 shrink-0"
|
|
365
|
-
title="
|
|
368
|
+
title={t("blueprint.config.parseSwagger")}
|
|
366
369
|
onClick={() => handleLoadSwagger()}
|
|
367
370
|
>
|
|
368
371
|
<SendIcon className="h-4 w-4" />
|
|
@@ -372,7 +375,7 @@ export function FetchNodeConfigPanel({
|
|
|
372
375
|
{loadingSwagger ? (
|
|
373
376
|
<p className="flex items-center gap-1.5 text-[11px] text-muted-foreground">
|
|
374
377
|
<LoaderIcon className="h-3.5 w-3.5 shrink-0" />
|
|
375
|
-
|
|
378
|
+
{t("blueprint.config.parsingSwagger")}
|
|
376
379
|
</p>
|
|
377
380
|
) : null}
|
|
378
381
|
{swaggerError ? (
|
|
@@ -380,14 +383,14 @@ export function FetchNodeConfigPanel({
|
|
|
380
383
|
) : null}
|
|
381
384
|
{endpoints.length > 0 ? (
|
|
382
385
|
<p className="text-[11px] text-muted-foreground">
|
|
383
|
-
|
|
386
|
+
{t("blueprint.config.parsedEndpoints", { count: endpoints.length })}
|
|
384
387
|
</p>
|
|
385
388
|
) : null}
|
|
386
389
|
</label>
|
|
387
390
|
|
|
388
391
|
<label className="block space-y-1">
|
|
389
392
|
<div className="flex items-center justify-between gap-2">
|
|
390
|
-
<span className="text-muted-foreground"
|
|
393
|
+
<span className="text-muted-foreground">{t("blueprint.config.requestUrl")}</span>
|
|
391
394
|
{hasSwaggerEndpoints ? (
|
|
392
395
|
<div className="flex rounded-md border border-border p-0.5">
|
|
393
396
|
<button
|
|
@@ -401,7 +404,7 @@ export function FetchNodeConfigPanel({
|
|
|
401
404
|
)}
|
|
402
405
|
onClick={() => setUrlInputMode("swagger")}
|
|
403
406
|
>
|
|
404
|
-
|
|
407
|
+
{t("blueprint.config.suggestApi")}
|
|
405
408
|
</button>
|
|
406
409
|
<button
|
|
407
410
|
type="button"
|
|
@@ -414,7 +417,7 @@ export function FetchNodeConfigPanel({
|
|
|
414
417
|
)}
|
|
415
418
|
onClick={() => setUrlInputMode("manual")}
|
|
416
419
|
>
|
|
417
|
-
|
|
420
|
+
{t("blueprint.config.manualInput")}
|
|
418
421
|
</button>
|
|
419
422
|
</div>
|
|
420
423
|
) : null}
|
|
@@ -428,7 +431,7 @@ export function FetchNodeConfigPanel({
|
|
|
428
431
|
)}
|
|
429
432
|
>
|
|
430
433
|
<label className="block space-y-1">
|
|
431
|
-
<span className="text-muted-foreground">
|
|
434
|
+
<span className="text-muted-foreground">{t("blueprint.config.apiHostBaseUrl")}</span>
|
|
432
435
|
<Input
|
|
433
436
|
value={fetchConfig.apiBaseUrl ?? ""}
|
|
434
437
|
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
|
@@ -442,7 +445,7 @@ export function FetchNodeConfigPanel({
|
|
|
442
445
|
/>
|
|
443
446
|
</label>
|
|
444
447
|
<label className="block space-y-1">
|
|
445
|
-
<span className="text-muted-foreground"
|
|
448
|
+
<span className="text-muted-foreground">{t("blueprint.config.selectEndpoint")}</span>
|
|
446
449
|
<div className="flex gap-1.5">
|
|
447
450
|
<div className="min-w-0 flex-1">
|
|
448
451
|
<FetchUrlAutocomplete
|
|
@@ -450,7 +453,7 @@ export function FetchNodeConfigPanel({
|
|
|
450
453
|
apiBaseUrl={fetchConfig.apiBaseUrl ?? ""}
|
|
451
454
|
endpoints={endpoints}
|
|
452
455
|
selectOnly
|
|
453
|
-
placeholder="
|
|
456
|
+
placeholder={t("blueprint.config.selectOrSearchEndpoint")}
|
|
454
457
|
onChange={(url) =>
|
|
455
458
|
onUpdateNode(node.id, patchFetchConfig(node, { url }))
|
|
456
459
|
}
|
|
@@ -470,10 +473,10 @@ export function FetchNodeConfigPanel({
|
|
|
470
473
|
disabled={loadingSwagger}
|
|
471
474
|
onSend={handleSendFetchDebug}
|
|
472
475
|
onAbort={handleAbortFetchDebug}
|
|
473
|
-
sendTitle="
|
|
474
|
-
abortTitle="
|
|
475
|
-
sendAriaLabel="
|
|
476
|
-
abortAriaLabel="
|
|
476
|
+
sendTitle={t("blueprint.config.sendDebugRequest")}
|
|
477
|
+
abortTitle={t("blueprint.config.abortRequest")}
|
|
478
|
+
sendAriaLabel={t("blueprint.config.sendDebugRequest")}
|
|
479
|
+
abortAriaLabel={t("blueprint.config.abortDebugAria")}
|
|
477
480
|
/>
|
|
478
481
|
</div>
|
|
479
482
|
</label>
|
|
@@ -494,17 +497,17 @@ export function FetchNodeConfigPanel({
|
|
|
494
497
|
disabled={loadingSwagger}
|
|
495
498
|
onSend={handleSendFetchDebug}
|
|
496
499
|
onAbort={handleAbortFetchDebug}
|
|
497
|
-
sendTitle="
|
|
498
|
-
abortTitle="
|
|
499
|
-
sendAriaLabel="
|
|
500
|
-
abortAriaLabel="
|
|
500
|
+
sendTitle={t("blueprint.config.sendDebugRequest")}
|
|
501
|
+
abortTitle={t("blueprint.config.abortRequest")}
|
|
502
|
+
sendAriaLabel={t("blueprint.config.sendDebugRequest")}
|
|
503
|
+
abortAriaLabel={t("blueprint.config.abortDebugAria")}
|
|
501
504
|
/>
|
|
502
505
|
</div>
|
|
503
506
|
)}
|
|
504
507
|
{loadingFetchDebug ? (
|
|
505
508
|
<p className="flex items-center gap-1.5 text-[11px] text-muted-foreground">
|
|
506
509
|
<LoaderIcon className="h-3.5 w-3.5 shrink-0" />
|
|
507
|
-
|
|
510
|
+
{t("blueprint.config.sendingDebug")}
|
|
508
511
|
</p>
|
|
509
512
|
) : null}
|
|
510
513
|
{fetchValidationError ? (
|
|
@@ -514,7 +517,7 @@ export function FetchNodeConfigPanel({
|
|
|
514
517
|
</label>
|
|
515
518
|
|
|
516
519
|
<label className="block space-y-1">
|
|
517
|
-
<span className="text-muted-foreground"
|
|
520
|
+
<span className="text-muted-foreground">{t("blueprint.config.requestMethod")}</span>
|
|
518
521
|
<Select
|
|
519
522
|
value={fetchConfig.method ?? "GET"}
|
|
520
523
|
onValueChange={(value: string) =>
|
|
@@ -538,7 +541,7 @@ export function FetchNodeConfigPanel({
|
|
|
538
541
|
</label>
|
|
539
542
|
|
|
540
543
|
<label className="block space-y-1">
|
|
541
|
-
<span className="text-muted-foreground"
|
|
544
|
+
<span className="text-muted-foreground">{t("blueprint.config.requestHeadersJson")}</span>
|
|
542
545
|
<textarea
|
|
543
546
|
defaultValue={JSON.stringify(fetchConfig.headers ?? {}, null, 2)}
|
|
544
547
|
key={`${node.id}-headers-${JSON.stringify(fetchConfig.headers)}`}
|
|
@@ -560,7 +563,7 @@ export function FetchNodeConfigPanel({
|
|
|
560
563
|
</label>
|
|
561
564
|
|
|
562
565
|
<label className="block space-y-1">
|
|
563
|
-
<span className="text-muted-foreground"
|
|
566
|
+
<span className="text-muted-foreground">{t("blueprint.config.requestBody")}</span>
|
|
564
567
|
<textarea
|
|
565
568
|
value={fetchConfig.body ?? ""}
|
|
566
569
|
onChange={(e) =>
|
|
@@ -671,7 +674,7 @@ export function FetchNodeConfigPanel({
|
|
|
671
674
|
|
|
672
675
|
<div className="grid grid-cols-2 gap-2">
|
|
673
676
|
<label className="block space-y-1">
|
|
674
|
-
<span className="text-muted-foreground"
|
|
677
|
+
<span className="text-muted-foreground">{t("blueprint.config.responseParse")}</span>
|
|
675
678
|
<Select
|
|
676
679
|
value={fetchConfig.responseType ?? "json"}
|
|
677
680
|
onValueChange={(value: string) =>
|
|
@@ -696,7 +699,7 @@ export function FetchNodeConfigPanel({
|
|
|
696
699
|
</Select>
|
|
697
700
|
</label>
|
|
698
701
|
<label className="block space-y-1">
|
|
699
|
-
<span className="text-muted-foreground"
|
|
702
|
+
<span className="text-muted-foreground">{t("blueprint.config.timeoutMs")}</span>
|
|
700
703
|
<Input
|
|
701
704
|
type="number"
|
|
702
705
|
min={0}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
2
2
|
import { cn } from "@arronqzy/ui";
|
|
3
|
+
import { useI18n } from "@arronqzy/i18n/react";
|
|
3
4
|
import {
|
|
4
5
|
buildEndpointSuggestions,
|
|
5
6
|
filterEndpointSuggestions,
|
|
@@ -28,6 +29,7 @@ export function FetchUrlAutocomplete({
|
|
|
28
29
|
onChange,
|
|
29
30
|
onSelectEndpoint,
|
|
30
31
|
}: FetchUrlAutocompleteProps) {
|
|
32
|
+
const { t } = useI18n();
|
|
31
33
|
const [open, setOpen] = useState(false);
|
|
32
34
|
const [activeIndex, setActiveIndex] = useState(0);
|
|
33
35
|
const [filterQuery, setFilterQuery] = useState("");
|
|
@@ -146,7 +148,7 @@ export function FetchUrlAutocomplete({
|
|
|
146
148
|
<div className="absolute z-[10150] mt-1 max-h-52 w-full overflow-auto rounded-md border border-border bg-popover py-1 text-popover-foreground shadow-md">
|
|
147
149
|
{filtered.length === 0 ? (
|
|
148
150
|
<div className="px-2 py-1.5 text-[11px] text-muted-foreground">
|
|
149
|
-
|
|
151
|
+
{t("blueprint.config.noMatchingEndpoint")}
|
|
150
152
|
</div>
|
|
151
153
|
) : (
|
|
152
154
|
filtered.map((item, index) => (
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useCallback, useMemo, useState, type ChangeEvent } from "react";
|
|
2
2
|
import { validateJsonString } from "@arronqzy/blueprint-dsl";
|
|
3
3
|
import type { JsonNodeConfig } from "@arronqzy/blueprint-dsl";
|
|
4
|
+
import { useI18n } from "@arronqzy/i18n/react";
|
|
4
5
|
|
|
5
6
|
import type { BlueprintGraphNode } from "../graph/document";
|
|
6
7
|
import { resolveNodeJsonConfig } from "../graph/document";
|
|
@@ -27,6 +28,7 @@ export function JsonNodeConfigPanel({
|
|
|
27
28
|
node,
|
|
28
29
|
onUpdateNode,
|
|
29
30
|
}: JsonNodeConfigPanelProps) {
|
|
31
|
+
const { t } = useI18n();
|
|
30
32
|
const jsonConfig = resolveNodeJsonConfig(node);
|
|
31
33
|
const [draftError, setDraftError] = useState<string | null>(null);
|
|
32
34
|
|
|
@@ -51,15 +53,17 @@ export function JsonNodeConfigPanel({
|
|
|
51
53
|
|
|
52
54
|
return (
|
|
53
55
|
<div className="space-y-2 rounded-md border border-border/70 bg-muted/20 p-2.5">
|
|
54
|
-
<div className="font-medium text-foreground">
|
|
56
|
+
<div className="font-medium text-foreground">
|
|
57
|
+
{t("blueprint.config.jsonTitle")}
|
|
58
|
+
</div>
|
|
55
59
|
<p className="text-[11px] text-muted-foreground">
|
|
56
|
-
|
|
57
|
-
array)并从输出口发出<strong>真信号</strong>;解析失败则发出
|
|
58
|
-
<strong>假信号</strong>。
|
|
60
|
+
{t("blueprint.config.jsonHint")}
|
|
59
61
|
</p>
|
|
60
62
|
|
|
61
63
|
<label className="block space-y-1">
|
|
62
|
-
<span className="text-muted-foreground">
|
|
64
|
+
<span className="text-muted-foreground">
|
|
65
|
+
{t("blueprint.config.jsonContent")}
|
|
66
|
+
</span>
|
|
63
67
|
<textarea
|
|
64
68
|
value={jsonConfig.jsonString}
|
|
65
69
|
onChange={handleChange}
|
|
@@ -69,9 +73,13 @@ export function JsonNodeConfigPanel({
|
|
|
69
73
|
placeholder={'{\n "key": "value"\n}'}
|
|
70
74
|
/>
|
|
71
75
|
{parseError ? (
|
|
72
|
-
<p className="text-[11px] text-destructive">
|
|
76
|
+
<p className="text-[11px] text-destructive">
|
|
77
|
+
{t("blueprint.config.jsonFormatError", { error: parseError })}
|
|
78
|
+
</p>
|
|
73
79
|
) : (
|
|
74
|
-
<p className="text-[11px] text-muted-foreground">
|
|
80
|
+
<p className="text-[11px] text-muted-foreground">
|
|
81
|
+
{t("blueprint.config.jsonFormatOk")}
|
|
82
|
+
</p>
|
|
75
83
|
)}
|
|
76
84
|
</label>
|
|
77
85
|
</div>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useCallback, useMemo, useState, type ChangeEvent } from "react";
|
|
2
2
|
import { validateLogicSourceCode } from "@arronqzy/blueprint-dsl";
|
|
3
3
|
import type { LogicNodeConfig } from "@arronqzy/blueprint-dsl";
|
|
4
|
+
import { useI18n } from "@arronqzy/i18n/react";
|
|
4
5
|
|
|
5
6
|
import type { BlueprintGraphNode } from "../graph/document";
|
|
6
7
|
import { resolveNodeLogicConfig } from "../graph/document";
|
|
@@ -27,6 +28,7 @@ export function LogicNodeConfigPanel({
|
|
|
27
28
|
node,
|
|
28
29
|
onUpdateNode,
|
|
29
30
|
}: LogicNodeConfigPanelProps) {
|
|
31
|
+
const { t } = useI18n();
|
|
30
32
|
const logicConfig = resolveNodeLogicConfig(node);
|
|
31
33
|
const [draftError, setDraftError] = useState<string | null>(null);
|
|
32
34
|
|
|
@@ -50,15 +52,17 @@ export function LogicNodeConfigPanel({
|
|
|
50
52
|
|
|
51
53
|
return (
|
|
52
54
|
<div className="space-y-2 rounded-md border border-border/70 bg-muted/20 p-2.5">
|
|
53
|
-
<div className="font-medium text-foreground"
|
|
55
|
+
<div className="font-medium text-foreground">
|
|
56
|
+
{t("blueprint.config.logicTitle")}
|
|
57
|
+
</div>
|
|
54
58
|
<p className="text-[11px] text-muted-foreground">
|
|
55
|
-
|
|
56
|
-
函数并执行;返回值作为<strong>真信号</strong>输出。代码语法错误或运行时报错则发出
|
|
57
|
-
<strong>假信号</strong>(错误信息为输出值)。
|
|
59
|
+
{t("blueprint.config.logicHint")}
|
|
58
60
|
</p>
|
|
59
61
|
|
|
60
62
|
<label className="block space-y-1">
|
|
61
|
-
<span className="text-muted-foreground">
|
|
63
|
+
<span className="text-muted-foreground">
|
|
64
|
+
{t("blueprint.config.jsCode")}
|
|
65
|
+
</span>
|
|
62
66
|
<textarea
|
|
63
67
|
value={logicConfig.sourceCode}
|
|
64
68
|
onChange={handleChange}
|
|
@@ -69,10 +73,12 @@ export function LogicNodeConfigPanel({
|
|
|
69
73
|
/>
|
|
70
74
|
{parseError ? (
|
|
71
75
|
<p className="text-[11px] text-destructive">
|
|
72
|
-
|
|
76
|
+
{t("blueprint.config.jsError", { error: parseError })}
|
|
73
77
|
</p>
|
|
74
78
|
) : (
|
|
75
|
-
<p className="text-[11px] text-muted-foreground">
|
|
79
|
+
<p className="text-[11px] text-muted-foreground">
|
|
80
|
+
{t("blueprint.config.jsSyntaxOk")}
|
|
81
|
+
</p>
|
|
76
82
|
)}
|
|
77
83
|
</label>
|
|
78
84
|
</div>
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
PopoverContent,
|
|
13
13
|
PopoverTrigger,
|
|
14
14
|
} from "@arronqzy/ui";
|
|
15
|
+
import { useI18n } from "@arronqzy/i18n/react";
|
|
15
16
|
|
|
16
17
|
export type ViewElementMultiSelectOption = {
|
|
17
18
|
id: string;
|
|
@@ -45,35 +46,38 @@ function ChevronDownIcon({ className }: { className?: string }) {
|
|
|
45
46
|
);
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
function resolveTriggerText(
|
|
49
|
-
value: string[],
|
|
50
|
-
labelById: Map<string, string>,
|
|
51
|
-
placeholder: string
|
|
52
|
-
): string {
|
|
53
|
-
if (value.length === 0) return placeholder;
|
|
54
|
-
const labels = value.map((id) => labelById.get(id) ?? id);
|
|
55
|
-
if (labels.length === 1) return labels[0]!;
|
|
56
|
-
const joined = labels.join("、");
|
|
57
|
-
if (joined.length <= 26) return joined;
|
|
58
|
-
return `已选 ${value.length} 项`;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
49
|
export function ViewElementMultiSelect({
|
|
62
50
|
options,
|
|
63
51
|
value,
|
|
64
52
|
onChange,
|
|
65
|
-
placeholder
|
|
53
|
+
placeholder,
|
|
66
54
|
disabled = false,
|
|
67
55
|
}: ViewElementMultiSelectProps) {
|
|
56
|
+
const { t } = useI18n();
|
|
68
57
|
const [open, setOpen] = useState(false);
|
|
58
|
+
const resolvedPlaceholder =
|
|
59
|
+
placeholder ?? t("blueprint.config.selectViewNode");
|
|
69
60
|
const labelById = useMemo(
|
|
70
61
|
() => new Map(options.map((opt) => [opt.id, opt.label])),
|
|
71
62
|
[options]
|
|
72
63
|
);
|
|
73
64
|
const selectedSet = useMemo(() => new Set(value), [value]);
|
|
74
|
-
const triggerText = resolveTriggerText(value, labelById, placeholder);
|
|
75
65
|
const emptyOptions = options.length === 0;
|
|
76
66
|
|
|
67
|
+
let triggerText = resolvedPlaceholder;
|
|
68
|
+
if (value.length > 0) {
|
|
69
|
+
const labels = value.map((id) => labelById.get(id) ?? id);
|
|
70
|
+
if (labels.length === 1) {
|
|
71
|
+
triggerText = labels[0]!;
|
|
72
|
+
} else {
|
|
73
|
+
const joined = labels.join("、");
|
|
74
|
+
triggerText =
|
|
75
|
+
joined.length <= 26
|
|
76
|
+
? joined
|
|
77
|
+
: t("blueprint.config.selectedCount", { count: value.length });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
77
81
|
const toggle = (id: string) => {
|
|
78
82
|
onChange(
|
|
79
83
|
selectedSet.has(id)
|
|
@@ -97,7 +101,7 @@ export function ViewElementMultiSelect({
|
|
|
97
101
|
)}
|
|
98
102
|
>
|
|
99
103
|
<span className="min-w-0 flex-1 truncate text-left">
|
|
100
|
-
{emptyOptions ? "
|
|
104
|
+
{emptyOptions ? t("blueprint.config.noViewOnCanvas") : triggerText}
|
|
101
105
|
</span>
|
|
102
106
|
<ChevronDownIcon className="h-4 w-4 shrink-0 opacity-50" />
|
|
103
107
|
</Button>
|
|
@@ -107,9 +111,12 @@ export function ViewElementMultiSelect({
|
|
|
107
111
|
align="start"
|
|
108
112
|
>
|
|
109
113
|
<Command>
|
|
110
|
-
<CommandInput
|
|
114
|
+
<CommandInput
|
|
115
|
+
placeholder={t("blueprint.config.searchViewNodes")}
|
|
116
|
+
className="h-9 text-xs"
|
|
117
|
+
/>
|
|
111
118
|
<CommandList>
|
|
112
|
-
<CommandEmpty
|
|
119
|
+
<CommandEmpty>{t("blueprint.config.noMatchingNodes")}</CommandEmpty>
|
|
113
120
|
<CommandGroup>
|
|
114
121
|
{options.map((opt) => {
|
|
115
122
|
const selected = selectedSet.has(opt.id);
|
package/src/dev-seed.ts
CHANGED
|
@@ -11,9 +11,9 @@ import {
|
|
|
11
11
|
/** DevApp 初始图:两个节点 + 一条连线,便于直接验证边是否渲染 */
|
|
12
12
|
export function createDevBlueprintGraph(): BlueprintGraph {
|
|
13
13
|
let graph = BlueprintGraph.empty();
|
|
14
|
-
graph = graph.addBlueprintNode({ x: 40, y: 80 }, "
|
|
14
|
+
graph = graph.addBlueprintNode({ x: 40, y: 80 }, "Node A");
|
|
15
15
|
const nodeA = graph.document.nodes[0]!;
|
|
16
|
-
graph = graph.addBlueprintNode({ x: 300, y: 80 }, "
|
|
16
|
+
graph = graph.addBlueprintNode({ x: 300, y: 80 }, "Node B");
|
|
17
17
|
const nodeB = graph.document.nodes[1]!;
|
|
18
18
|
|
|
19
19
|
const withEdge = addEdge(
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
ParsedSwaggerDocument,
|
|
7
7
|
} from "@arronqzy/blueprint-dsl";
|
|
8
8
|
import { executeFetch } from "@arronqzy/blueprint-dsl";
|
|
9
|
+
import { resolveLocale, tForLocale } from "@arronqzy/i18n";
|
|
9
10
|
|
|
10
11
|
import { loadSwaggerDocument } from "./library/swagger-docs";
|
|
11
12
|
|
|
@@ -143,7 +144,9 @@ export function startSwaggerLoadTask(params: {
|
|
|
143
144
|
}
|
|
144
145
|
|
|
145
146
|
const message =
|
|
146
|
-
error instanceof Error
|
|
147
|
+
error instanceof Error
|
|
148
|
+
? error.message
|
|
149
|
+
: tForLocale(resolveLocale())("blueprint.config.swaggerParseFailed");
|
|
147
150
|
swaggerTasks.set(params.nodeId, {
|
|
148
151
|
record: { status: "error", error: message },
|
|
149
152
|
abortController,
|
|
@@ -186,7 +189,10 @@ export function startFetchDebugTask(params: {
|
|
|
186
189
|
return;
|
|
187
190
|
}
|
|
188
191
|
|
|
189
|
-
const message =
|
|
192
|
+
const message =
|
|
193
|
+
error instanceof Error
|
|
194
|
+
? error.message
|
|
195
|
+
: tForLocale(resolveLocale())("blueprint.config.requestFailed");
|
|
190
196
|
fetchDebugTasks.set(params.nodeId, {
|
|
191
197
|
record: { status: "error", error: message },
|
|
192
198
|
abortController,
|
package/src/graph/document.ts
CHANGED
|
@@ -133,35 +133,72 @@ export function resolveRunnableNodeType(
|
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
|
|
137
|
-
|
|
136
|
+
import type { TranslateFn } from "@arronqzy/i18n";
|
|
137
|
+
import { resolveLocale, tForLocale } from "@arronqzy/i18n";
|
|
138
|
+
|
|
139
|
+
/** 画布节点顶部(拖拽区)配置类型对应的 i18n key */
|
|
140
|
+
export const BLUEPRINT_CONFIG_TYPE_LABEL_KEYS: Record<
|
|
138
141
|
BlueprintConfigSource,
|
|
139
142
|
string
|
|
140
143
|
> = {
|
|
141
|
-
blueprint: "
|
|
142
|
-
logic: "
|
|
143
|
-
and: "
|
|
144
|
-
lifecycle: "
|
|
145
|
-
view: "
|
|
146
|
-
fetch: "
|
|
147
|
-
json: "
|
|
148
|
-
clock: "
|
|
144
|
+
blueprint: "blueprint.node.typeBlueprint",
|
|
145
|
+
logic: "blueprint.node.typeLogic",
|
|
146
|
+
and: "blueprint.node.typeAnd",
|
|
147
|
+
lifecycle: "blueprint.node.typeLifecycle",
|
|
148
|
+
view: "blueprint.node.typeView",
|
|
149
|
+
fetch: "blueprint.node.typeFetch",
|
|
150
|
+
json: "blueprint.node.typeJson",
|
|
151
|
+
clock: "blueprint.node.typeClock",
|
|
149
152
|
};
|
|
150
153
|
|
|
154
|
+
export const BLUEPRINT_LIFECYCLE_PHASE_KEYS: Record<PageLifecyclePhase, string> =
|
|
155
|
+
{
|
|
156
|
+
created: "blueprint.node.phaseCreated",
|
|
157
|
+
beforeMount: "blueprint.node.phaseBeforeMount",
|
|
158
|
+
mounted: "blueprint.node.phaseMounted",
|
|
159
|
+
updated: "blueprint.node.phaseUpdated",
|
|
160
|
+
beforeDestroy: "blueprint.node.phaseBeforeDestroy",
|
|
161
|
+
destroy: "blueprint.node.phaseDestroy",
|
|
162
|
+
activated: "blueprint.node.phaseActivated",
|
|
163
|
+
deactivated: "blueprint.node.phaseDeactivated",
|
|
164
|
+
blueprintActivated: "blueprint.node.phaseBlueprintActivated",
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
function defaultTranslate(): TranslateFn {
|
|
168
|
+
return tForLocale(resolveLocale());
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export function getBlueprintNodeTypeLabel(
|
|
172
|
+
t: TranslateFn,
|
|
173
|
+
type: BlueprintConfigSource
|
|
174
|
+
): string {
|
|
175
|
+
return t(BLUEPRINT_CONFIG_TYPE_LABEL_KEYS[type]);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function getLifecyclePhaseLabel(
|
|
179
|
+
t: TranslateFn,
|
|
180
|
+
phase: PageLifecyclePhase
|
|
181
|
+
): string {
|
|
182
|
+
const key = BLUEPRINT_LIFECYCLE_PHASE_KEYS[phase];
|
|
183
|
+
return key ? t(key) : phase;
|
|
184
|
+
}
|
|
185
|
+
|
|
151
186
|
export function resolveBlueprintNodeTypeLabel(
|
|
152
187
|
node: Pick<
|
|
153
188
|
BlueprintGraphNode,
|
|
154
189
|
"role" | "nodeType" | "configSource" | "viewElementId" | "viewElementIds"
|
|
155
|
-
|
|
190
|
+
>,
|
|
191
|
+
t: TranslateFn = defaultTranslate()
|
|
156
192
|
): string {
|
|
157
|
-
return
|
|
193
|
+
return getBlueprintNodeTypeLabel(t, resolveBlueprintConfigSource(node));
|
|
158
194
|
}
|
|
159
195
|
|
|
160
196
|
/** 新建节点时的默认显示名称(与类型文案一致) */
|
|
161
197
|
export function defaultBlueprintNodeLabel(
|
|
162
|
-
configSource: BlueprintConfigSource
|
|
198
|
+
configSource: BlueprintConfigSource,
|
|
199
|
+
t: TranslateFn = defaultTranslate()
|
|
163
200
|
): string {
|
|
164
|
-
return
|
|
201
|
+
return getBlueprintNodeTypeLabel(t, configSource);
|
|
165
202
|
}
|
|
166
203
|
|
|
167
204
|
export function resolveNodeFetchConfig(
|