@arronqzy/vue-blueprint 0.1.16 → 0.1.17

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arronqzy/vue-blueprint",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "description": "Vue 3 blueprint editor for Abuilder (Vue Flow + Ant Design Vue)",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -19,9 +19,9 @@
19
19
  "ant-design-vue": "^4.2.6",
20
20
  "dayjs": "^1.11.13",
21
21
  "vue": "^3.5.13",
22
- "@arronqzy/blueprint-dsl": "1.0.16",
23
- "@arronqzy/vue-rx-store": "0.1.6",
24
- "@arronqzy/i18n": "0.1.16"
22
+ "@arronqzy/blueprint-dsl": "1.0.17",
23
+ "@arronqzy/i18n": "0.1.17",
24
+ "@arronqzy/vue-rx-store": "0.1.6"
25
25
  },
26
26
  "peerDependencies": {
27
27
  "vue": "^3.4.0"
@@ -31,8 +31,8 @@
31
31
  "eslint": "^8.57.0",
32
32
  "typescript": "^5.5.4",
33
33
  "vue-tsc": "^2.2.0",
34
- "@arronqzy/eslint-config": "0.0.0",
35
- "@arronqzy/typescript-config": "1.0.0"
34
+ "@arronqzy/typescript-config": "1.0.0",
35
+ "@arronqzy/eslint-config": "0.0.0"
36
36
  },
37
37
  "publishConfig": {
38
38
  "access": "public"
@@ -281,15 +281,17 @@ function toggleEventType(eventType: ViewEventType, checked: boolean) {
281
281
  <p v-if="!node.libraryBlueprintId" class="text-[11px] text-muted-foreground">
282
282
  {{ t("blueprint.config.selectLibraryFirst") }}
283
283
  </p>
284
- <label class="flex items-start gap-2 pt-1">
284
+ <label class="flex items-center gap-2 pt-1">
285
285
  <Checkbox
286
286
  :checked="allowFalseSignalPropagation"
287
- class="mt-0.5"
288
287
  @update:checked="(v) => onUpdateAllowFalseSignalPropagation?.(Boolean(v))"
289
288
  />
290
- <span class="text-[11px] leading-relaxed text-muted-foreground">
291
- {{ t("blueprint.config.allowFalsePropagateBlueprint") }}
289
+ <span class="text-[11px] text-muted-foreground">
290
+ {{ t("blueprint.config.allowFalsePropagate") }}
292
291
  </span>
292
+ <ConfigHintIcon :label="t('blueprint.config.allowFalsePropagate')">
293
+ {{ t("blueprint.config.allowFalsePropagateBlueprint") }}
294
+ </ConfigHintIcon>
293
295
  </label>
294
296
  </div>
295
297
 
@@ -426,15 +428,17 @@ function toggleEventType(eventType: ViewEventType, checked: boolean) {
426
428
  class="space-y-2 rounded-md border border-border/70 bg-muted/20 p-2.5"
427
429
  >
428
430
  <div class="font-medium text-foreground">{{ t("blueprint.config.taskChain") }}</div>
429
- <label class="flex items-start gap-2">
431
+ <label class="flex items-center gap-2">
430
432
  <Checkbox
431
433
  :checked="allowFalseSignalPropagation"
432
- class="mt-0.5"
433
434
  @update:checked="(v) => onUpdateAllowFalseSignalPropagation?.(Boolean(v))"
434
435
  />
435
- <span class="text-[11px] leading-relaxed text-muted-foreground">
436
- {{ t("blueprint.config.allowFalsePropagateDefault") }}
436
+ <span class="text-[11px] text-muted-foreground">
437
+ {{ t("blueprint.config.allowFalsePropagate") }}
437
438
  </span>
439
+ <ConfigHintIcon :label="t('blueprint.config.allowFalsePropagate')">
440
+ {{ t("blueprint.config.allowFalsePropagateDefault") }}
441
+ </ConfigHintIcon>
438
442
  </label>
439
443
  </div>
440
444
  </div>
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { computed, ref, watch } from "vue";
3
+ import ConfigHintIcon from "./ConfigHintIcon.vue";
3
4
  import { useI18n } from "@arronqzy/i18n/vue";
4
5
  import { Button, Checkbox, Input, Modal } from "ant-design-vue";
5
6
  import {
@@ -263,6 +264,9 @@ async function handleFiles(files: FileList | null) {
263
264
  <label class="ml-auto flex cursor-pointer items-center gap-2 text-[11px] text-muted-foreground">
264
265
  <Checkbox v-model:checked="persistLocalDefault" />
265
266
  {{ t("blueprint.apiCollection.persistLocal") }}
267
+ <ConfigHintIcon :label="t('blueprint.apiCollection.persistLocal')">
268
+ {{ t("blueprint.apiCollection.persistLocalHint") }}
269
+ </ConfigHintIcon>
266
270
  </label>
267
271
  <input
268
272
  ref="fileInputRef"
@@ -273,11 +277,6 @@ async function handleFiles(files: FileList | null) {
273
277
  @change="(e) => void handleFiles((e.target as HTMLInputElement).files)"
274
278
  />
275
279
  </div>
276
-
277
- <p class="mb-2 text-[11px] text-muted-foreground">
278
- {{ t("blueprint.apiCollection.persistLocalHint") }}
279
- </p>
280
-
281
280
  <pre
282
281
  v-if="error"
283
282
  class="mb-2 max-h-24 overflow-auto whitespace-pre-wrap rounded border border-destructive/40 bg-destructive/5 p-2 text-[11px] text-destructive"
@@ -2,6 +2,9 @@
2
2
  import type { BlueprintGraph } from "../graph/blueprint-graph";
3
3
  import type { BlueprintExecutionOverlay } from "../runtime/execution-overlay";
4
4
  import BlueprintCanvas from "./BlueprintCanvas.vue";
5
+ import { useBlueprintDslLocaleSync } from "../composables/useBlueprintDslLocaleSync";
6
+
7
+ useBlueprintDslLocaleSync();
5
8
 
6
9
  const props = withDefaults(
7
10
  defineProps<{
@@ -102,15 +102,17 @@ function handleEmitImmediatelyChange(checked: boolean) {
102
102
  />
103
103
  </label>
104
104
 
105
- <label class="flex items-start gap-2">
105
+ <label class="flex items-center gap-2">
106
106
  <Checkbox
107
107
  :checked="clockConfig.emitImmediately"
108
- class="mt-0.5"
109
108
  @update:checked="handleEmitImmediatelyChange"
110
109
  />
111
- <span class="text-[11px] leading-relaxed text-muted-foreground">
110
+ <span class="text-[11px] text-muted-foreground">
112
111
  {{ t("blueprint.config.emitImmediately") }}
113
112
  </span>
113
+ <ConfigHintIcon :label="t('blueprint.config.emitImmediately')">
114
+ {{ t("blueprint.config.emitImmediatelyHint") }}
115
+ </ConfigHintIcon>
114
116
  </label>
115
117
 
116
118
  <label class="block space-y-1">
@@ -28,11 +28,24 @@ const resolvedLabel = computed(() => props.label || t("common.hint"));
28
28
  type="button"
29
29
  :class="
30
30
  buttonClass ??
31
- 'inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-full border border-border text-[10px] leading-none text-muted-foreground hover:bg-accent/50'
31
+ 'inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring'
32
32
  "
33
33
  :aria-label="t('common.hintAria', { label: resolvedLabel })"
34
34
  >
35
- ?
35
+ <svg
36
+ viewBox="0 0 24 24"
37
+ fill="none"
38
+ stroke="currentColor"
39
+ stroke-width="2"
40
+ stroke-linecap="round"
41
+ stroke-linejoin="round"
42
+ class="h-3.5 w-3.5"
43
+ aria-hidden="true"
44
+ >
45
+ <circle cx="12" cy="12" r="10" />
46
+ <path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" />
47
+ <path d="M12 17h.01" />
48
+ </svg>
36
49
  </button>
37
50
  </Tooltip>
38
51
  </template>
@@ -45,7 +45,7 @@ import ConfigHintIcon from "./ConfigHintIcon.vue";
45
45
  import FetchUrlAutocomplete from "./FetchUrlAutocomplete.vue";
46
46
  import ScopeTemplateAutocompleteHost from "./ScopeTemplateAutocompleteHost.vue";
47
47
 
48
- const { t } = useI18n();
48
+ const { t, locale } = useI18n();
49
49
 
50
50
  export type FetchNodeConfigPanelProps = {
51
51
  node: BlueprintGraphNode;
@@ -113,12 +113,14 @@ const resolvedBodyPreview = computed(() => {
113
113
  if (!usesScopeTemplate.value) return "";
114
114
  return resolvedFetchConfig.value.body?.trim() ?? "";
115
115
  });
116
- const headersJsonError = computed(() =>
117
- getFetchHeadersValidationError(fetchConfig.value, incomingScope.value)
118
- );
119
- const bodyJsonError = computed(() =>
120
- getFetchBodyValidationError(fetchConfig.value.body, resolvedFetchConfig.value.body)
121
- );
116
+ const headersJsonError = computed(() => {
117
+ void locale.value;
118
+ return getFetchHeadersValidationError(fetchConfig.value, incomingScope.value);
119
+ });
120
+ const bodyJsonError = computed(() => {
121
+ void locale.value;
122
+ return getFetchBodyValidationError(fetchConfig.value.body, resolvedFetchConfig.value.body);
123
+ });
122
124
  const incomingHasPendingValue = computed(() => {
123
125
  const scope = incomingScope.value;
124
126
  if (!scope || typeof scope !== "object") return false;
@@ -411,8 +413,15 @@ function handleHeadersInput(event: Event) {
411
413
  </div>
412
414
 
413
415
  <div class="space-y-1">
414
- <span class="text-[11px] text-muted-foreground">
416
+ <span class="inline-flex items-center gap-1 text-[11px] text-muted-foreground">
415
417
  {{ t("blueprint.config.fetchSourceMode") }}
418
+ <ConfigHintIcon :label="t('blueprint.config.fetchSourceMode')">
419
+ {{
420
+ usingCollection
421
+ ? t("blueprint.config.fetchSourceCollectionHint")
422
+ : t("blueprint.config.fetchSourceDirectHint")
423
+ }}
424
+ </ConfigHintIcon>
416
425
  </span>
417
426
  <div class="flex rounded-md border border-border p-0.5">
418
427
  <button
@@ -440,13 +449,6 @@ function handleHeadersInput(event: Event) {
440
449
  {{ t("blueprint.config.fetchSourceCollection") }}
441
450
  </button>
442
451
  </div>
443
- <p class="text-[10px] text-muted-foreground">
444
- {{
445
- usingCollection
446
- ? t("blueprint.config.fetchSourceCollectionHint")
447
- : t("blueprint.config.fetchSourceDirectHint")
448
- }}
449
- </p>
450
452
  </div>
451
453
 
452
454
  <div class="space-y-1 rounded-md border border-gray-200/80 bg-white/80 p-2">
@@ -491,7 +493,12 @@ function handleHeadersInput(event: Event) {
491
493
  </Select>
492
494
  </label>
493
495
  <label class="block space-y-1">
494
- <span class="text-muted-foreground">{{ t("blueprint.config.apiCollectionEndpoint") }}</span>
496
+ <span class="inline-flex items-center gap-1 text-muted-foreground">
497
+ {{ t("blueprint.config.apiCollectionEndpoint") }}
498
+ <ConfigHintIcon :label="t('blueprint.config.apiCollectionEndpoint')">
499
+ {{ t("blueprint.config.apiCollectionFilledHint") }}
500
+ </ConfigHintIcon>
501
+ </span>
495
502
  <div class="flex gap-1.5">
496
503
  <Tooltip
497
504
  :title="selectedEndpointDescription || undefined"
@@ -544,9 +551,6 @@ function handleHeadersInput(event: Event) {
544
551
  </Button>
545
552
  </div>
546
553
  </label>
547
- <p v-if="selectedCollection" class="text-[10px] text-muted-foreground">
548
- {{ t("blueprint.config.apiCollectionFilledHint") }}
549
- </p>
550
554
  <label class="block space-y-1">
551
555
  <span class="text-muted-foreground">{{ t("blueprint.config.requestUrl") }}</span>
552
556
  <Input
@@ -8,7 +8,7 @@ import ConfigHintIcon from "./ConfigHintIcon.vue";
8
8
  import type { BlueprintGraphNode } from "../graph/document";
9
9
  import { resolveNodeLogicConfig } from "../graph/document";
10
10
 
11
- const { t } = useI18n();
11
+ const { t, locale } = useI18n();
12
12
 
13
13
  export type LogicNodeConfigPanelProps = {
14
14
  node: BlueprintGraphNode;
@@ -31,9 +31,10 @@ function patchLogicConfig(node: BlueprintGraphNode, patch: Partial<LogicNodeConf
31
31
 
32
32
  const logicConfig = computed(() => resolveNodeLogicConfig(props.node));
33
33
 
34
- const storedValidation = computed(() =>
35
- validateLogicSourceCode(logicConfig.value.sourceCode)
36
- );
34
+ const storedValidation = computed(() => {
35
+ void locale.value;
36
+ return validateLogicSourceCode(logicConfig.value.sourceCode);
37
+ });
37
38
 
38
39
  const parseError = computed(
39
40
  () => draftError.value ?? (storedValidation.value.ok ? null : storedValidation.value.error)
@@ -0,0 +1,12 @@
1
+ import { setBlueprintDslLocale } from "@arronqzy/blueprint-dsl";
2
+ import { useI18nOptional } from "@arronqzy/i18n/vue";
3
+ import { watch } from "vue";
4
+
5
+ /**
6
+ * Keeps blueprint-dsl validation / runtime messages in the app locale. `flush: "sync"`
7
+ * updates it before computeds that track the locale are re-evaluated.
8
+ */
9
+ export function useBlueprintDslLocaleSync(): void {
10
+ const { locale } = useI18nOptional();
11
+ watch(locale, (next) => setBlueprintDslLocale(next), { immediate: true, flush: "sync" });
12
+ }
@@ -207,7 +207,7 @@ export function resolveRunnableNodeType(
207
207
  }
208
208
 
209
209
  import type { TranslateFn } from "@arronqzy/i18n";
210
- import { resolveLocale, tForLocale } from "@arronqzy/i18n";
210
+ import { matchMessageInAnyLocale, relocalizeMessage, resolveLocale, tForLocale } from "@arronqzy/i18n";
211
211
 
212
212
  /** 画布节点顶部(拖拽区)配置类型对应的 i18n key */
213
213
  export const BLUEPRINT_CONFIG_TYPE_LABEL_KEYS: Record<
@@ -289,16 +289,23 @@ export function defaultBlueprintNodeLabel(
289
289
  return getBlueprintNodeTypeLabel(t, configSource);
290
290
  }
291
291
 
292
- /** 当前名称是否仍是「类型默认名」(空或等于任一类型文案) */
292
+ const BLUEPRINT_TYPE_LABEL_KEY_LIST = Object.values(BLUEPRINT_CONFIG_TYPE_LABEL_KEYS);
293
+
294
+ /** 当前名称是否仍是「类型默认名」(空或等于任一语言下的任一类型文案) */
293
295
  export function isDefaultBlueprintNodeLabel(
294
296
  label: string | undefined | null,
295
297
  t: TranslateFn = defaultTranslate()
296
298
  ): boolean {
297
299
  const trimmed = (label ?? "").trim();
298
300
  if (!trimmed) return true;
299
- return (
300
- Object.keys(BLUEPRINT_CONFIG_TYPE_LABEL_KEYS) as BlueprintConfigSource[]
301
- ).some((src) => getBlueprintNodeTypeLabel(t, src) === trimmed);
301
+ return BLUEPRINT_TYPE_LABEL_KEY_LIST.some(
302
+ (key) => t(key) === trimmed || matchMessageInAnyLocale(trimmed, key) !== null
303
+ );
304
+ }
305
+
306
+ /** 类型默认名按当前语言显示;用户自定义名称保持不变 */
307
+ export function localizeBlueprintNodeLabel(label: string, t: TranslateFn): string {
308
+ return relocalizeMessage(label, BLUEPRINT_TYPE_LABEL_KEY_LIST, t);
302
309
  }
303
310
 
304
311
  export function resolveNodeFetchConfig(
package/src/index.ts CHANGED
@@ -4,6 +4,7 @@ export { documentToRunnableGraph } from "./runtime/document-to-runnable-graph";
4
4
  export type { BlueprintExecutionOverlay } from "./runtime/execution-overlay";
5
5
  export type { BlueprintFlowNodeData } from "./types";
6
6
  export { default as BluePrintVueRoot } from "./components/BluePrintVueRoot.vue";
7
+ export { useBlueprintDslLocaleSync } from "./composables/useBlueprintDslLocaleSync";
7
8
  export { default as BlueprintCanvas } from "./components/BlueprintCanvas.vue";
8
9
  export { default as BlueprintNodeConfigSidebar } from "./BlueprintNodeConfigSidebar.vue";
9
10
  export type {
@@ -2,8 +2,9 @@
2
2
  import { useI18n } from "@arronqzy/i18n/vue";
3
3
  import { computed } from "vue";
4
4
  import { cn } from "../utils/cn";
5
+ import { localizeBlueprintNodeLabel } from "../graph/document";
5
6
 
6
- const { t } = useI18n();
7
+ const { t, locale } = useI18n();
7
8
 
8
9
  export type BlueprintNodeCardProps = {
9
10
  nodeId: string;
@@ -26,7 +27,11 @@ const emit = defineEmits<{
26
27
  select: [nodeId: string];
27
28
  }>();
28
29
 
29
- const showMeta = computed(() => Boolean(props.meta && props.meta !== props.label));
30
+ const displayLabel = computed(() => {
31
+ void locale.value;
32
+ return localizeBlueprintNodeLabel(props.label, t);
33
+ });
34
+ const showMeta = computed(() => Boolean(props.meta && props.meta !== displayLabel.value));
30
35
  </script>
31
36
 
32
37
  <template>
@@ -108,7 +113,7 @@ const showMeta = computed(() => Boolean(props.meta && props.meta !== props.label
108
113
  </span>
109
114
  <div class="bp-node-card__content">
110
115
  <div class="bp-node-card__title-row">
111
- <div class="bp-node-card__title">{{ label }}</div>
116
+ <div class="bp-node-card__title">{{ displayLabel }}</div>
112
117
  <span
113
118
  v-if="progressLabel"
114
119
  :class="cn('bp-node-card__badge', `bp-node-card__badge--${variant}`)"