feat: add sub-graph config panel with variable selection and null

handling
This commit is contained in:
zhsama 2026-01-14 03:22:42 +08:00
parent b7025ad9d6
commit b9052bc244
12 changed files with 351 additions and 97 deletions

View File

@ -1,85 +1,178 @@
'use client'
import type { FC } from 'react'
import type { WhenOutputNoneOption } from '../types'
import { memo, useCallback, useState } from 'react'
import type { Item } from '@/app/components/base/select'
import type { MentionConfig } from '@/app/components/workflow/nodes/_base/types'
import type { Node, NodeOutPutVar, ValueSelector } from '@/app/components/workflow/types'
import { RiCheckLine } from '@remixicon/react'
import { memo, useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { SimpleSelect } from '@/app/components/base/select'
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
import Field from '@/app/components/workflow/nodes/_base/components/field'
import VarReferencePicker from '@/app/components/workflow/nodes/_base/components/variable/var-reference-picker'
import Tab, { TabType } from '@/app/components/workflow/nodes/_base/components/workflow-panel/tab'
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
import { cn } from '@/utils/classnames'
type ConfigPanelProps = {
toolNodeId: string
paramKey: string
activeTab: 'settings' | 'lastRun'
onTabChange: (tab: 'settings' | 'lastRun') => void
agentName: string
extractorNodeId: string
mentionConfig: MentionConfig
availableNodes: Node[]
availableVars: NodeOutPutVar[]
onMentionConfigChange: (config: MentionConfig) => void
}
const outputVariables = [
{ name: 'text', type: 'string' },
{ name: 'structured_output', type: 'object' },
]
const ConfigPanel: FC<ConfigPanelProps> = ({
toolNodeId: _toolNodeId,
paramKey: _paramKey,
activeTab,
agentName,
extractorNodeId,
mentionConfig,
availableNodes,
availableVars,
onMentionConfigChange,
}) => {
const { t } = useTranslation()
const [whenOutputNone, setWhenOutputNone] = useState<WhenOutputNoneOption>('default')
const [tabType, setTabType] = useState<TabType>(TabType.settings)
const handleWhenOutputNoneChange = useCallback((e: React.ChangeEvent<HTMLSelectElement>) => {
setWhenOutputNone(e.target.value as WhenOutputNoneOption)
}, [])
const resolvedExtractorId = mentionConfig.extractor_node_id || extractorNodeId
if (activeTab === 'lastRun') {
return (
<div className="flex h-full items-center justify-center p-4">
<div className="text-center">
const selectedOutput = useMemo<ValueSelector>(() => {
if (!resolvedExtractorId || !mentionConfig.output_selector?.length)
return []
return [resolvedExtractorId, ...(mentionConfig.output_selector || [])]
}, [mentionConfig.output_selector, resolvedExtractorId])
const handleOutputVarChange = useCallback((value: ValueSelector | string) => {
const selector = Array.isArray(value) ? value : []
const nextExtractorId = selector[0] || resolvedExtractorId
const nextOutputSelector = selector.length > 1 ? selector.slice(1) : []
onMentionConfigChange({
...mentionConfig,
extractor_node_id: nextExtractorId,
output_selector: nextOutputSelector,
})
}, [mentionConfig, onMentionConfigChange, resolvedExtractorId])
const whenOutputNoneOptions = useMemo(() => ([
{
value: 'raise_error',
name: t('subGraphModal.whenOutputNone.error', { ns: 'workflow' }),
description: t('subGraphModal.whenOutputNone.errorDesc', { ns: 'workflow' }),
},
{
value: 'use_default',
name: t('subGraphModal.whenOutputNone.default', { ns: 'workflow' }),
description: t('subGraphModal.whenOutputNone.defaultDesc', { ns: 'workflow' }),
},
]), [t])
const handleNullStrategyChange = useCallback((item: Item) => {
if (typeof item.value !== 'string')
return
onMentionConfigChange({
...mentionConfig,
null_strategy: item.value as MentionConfig['null_strategy'],
})
}, [mentionConfig, onMentionConfigChange])
const handleDefaultValueChange = useCallback((value: string) => {
const trimmed = value.trim()
let nextValue: unknown = value
if ((trimmed.startsWith('{') && trimmed.endsWith('}')) || (trimmed.startsWith('[') && trimmed.endsWith(']'))) {
try {
nextValue = JSON.parse(trimmed)
}
catch {
nextValue = value
}
}
onMentionConfigChange({
...mentionConfig,
default_value: nextValue,
})
}, [mentionConfig, onMentionConfigChange])
return (
<div className="flex h-full flex-col">
<div className="px-4 pb-2 pt-4">
<div className="system-lg-semibold text-text-primary">
{t('subGraphModal.internalStructure', { ns: 'workflow' })}
</div>
<div className="system-sm-regular text-text-tertiary">
{t('subGraphModal.internalStructureDesc', { ns: 'workflow', name: agentName })}
</div>
</div>
<div className="px-4 pb-2">
<Tab value={tabType} onChange={setTabType} />
</div>
{tabType === TabType.lastRun && (
<div className="flex flex-1 items-center justify-center p-4">
<p className="system-sm-regular text-text-tertiary">
{t('subGraphModal.noRunHistory', { ns: 'workflow' })}
</p>
</div>
</div>
)
}
return (
<div className="space-y-4 p-4">
<Field
title={t('subGraphModal.outputVariables', { ns: 'workflow' })}
>
<div className="space-y-2">
{outputVariables.map(variable => (
<div
key={variable.name}
className="flex items-center justify-between rounded-lg bg-components-input-bg-normal px-3 py-2"
>
<span className="system-sm-medium text-text-secondary">{variable.name}</span>
<span className="system-xs-regular text-text-tertiary">{variable.type}</span>
</div>
))}
)}
{tabType === TabType.settings && (
<div className="flex-1 overflow-y-auto">
<div className="space-y-4 px-4 py-4">
<Field title={t('subGraphModal.outputVariables', { ns: 'workflow' })}>
<VarReferencePicker
nodeId={extractorNodeId}
readonly={false}
isShowNodeName
value={selectedOutput}
onChange={handleOutputVarChange}
availableNodes={availableNodes}
availableVars={availableVars}
/>
</Field>
</div>
<div className="space-y-4 px-4 py-4">
<Field title={t('subGraphModal.whenOutputIsNone', { ns: 'workflow' })}>
<SimpleSelect
items={whenOutputNoneOptions}
defaultValue={mentionConfig.null_strategy}
allowSearch={false}
notClearable
onSelect={handleNullStrategyChange}
renderOption={({ item, selected }) => (
<div className="flex items-start gap-2">
<div className="mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center">
{selected && (
<RiCheckLine className="h-4 w-4 text-[14px] text-text-accent" />
)}
</div>
<div className="min-w-0">
<div className="system-sm-medium text-text-secondary">{item.name}</div>
<div className="system-xs-regular mt-0.5 text-text-tertiary">{item.description}</div>
</div>
</div>
)}
/>
</Field>
{mentionConfig.null_strategy === 'use_default' && (
<div>
<div className="system-xs-regular text-text-tertiary">
{t('subGraphModal.defaultValueHint', { ns: 'workflow' })}
</div>
<div className={cn('mt-2 overflow-hidden rounded-lg border border-components-input-border-active bg-components-input-bg-normal p-1')}>
<CodeEditor
noWrapper
language={CodeLanguage.json}
value={mentionConfig.default_value ?? ''}
onChange={handleDefaultValueChange}
isJSONStringifyBeauty
className="min-h-[160px]"
/>
</div>
</div>
)}
</div>
</div>
</Field>
<Field
title={t('subGraphModal.whenOutputIsNone', { ns: 'workflow' })}
>
<select
className={cn(
'w-full rounded-lg border border-components-input-border-active bg-components-input-bg-normal px-3 py-2',
'system-sm-regular text-text-secondary',
'focus:border-primary-600 focus:outline-none',
)}
value={whenOutputNone}
onChange={handleWhenOutputNoneChange}
>
<option value="default">
{t('subGraphModal.whenOutputNone.default', { ns: 'workflow' })}
</option>
<option value="error">
{t('subGraphModal.whenOutputNone.error', { ns: 'workflow' })}
</option>
</select>
</Field>
)}
</div>
)
}

View File

@ -1,36 +1,72 @@
import type { FC } from 'react'
import type { SubGraphConfig } from '../types'
import type { MentionConfig } from '@/app/components/workflow/nodes/_base/types'
import type { NodeOutPutVar } from '@/app/components/workflow/types'
import { memo, useMemo } from 'react'
import { useStore as useReactFlowStore } from 'reactflow'
import { useShallow } from 'zustand/react/shallow'
import { useIsChatMode, useWorkflowVariables } from '@/app/components/workflow/hooks'
import { Panel as NodePanel } from '@/app/components/workflow/nodes'
import { useStore } from '@/app/components/workflow/store'
import { BlockEnum } from '@/app/components/workflow/types'
import ConfigPanel from './config-panel'
type SubGraphChildrenProps = {
toolNodeId: string
paramKey: string
onConfigChange: (config: Partial<SubGraphConfig>) => void
agentName: string
extractorNodeId: string
mentionConfig: MentionConfig
onMentionConfigChange: (config: MentionConfig) => void
}
const SubGraphChildren: FC<SubGraphChildrenProps> = ({
toolNodeId: _toolNodeId,
paramKey: _paramKey,
onConfigChange: _onConfigChange,
agentName,
extractorNodeId,
mentionConfig,
onMentionConfigChange,
}) => {
const selectedNode = useReactFlowStore(useShallow((s) => {
const { getNodeAvailableVars } = useWorkflowVariables()
const isChatMode = useIsChatMode()
const nodePanelWidth = useStore(s => s.nodePanelWidth)
const { selectedNode, nodes } = useReactFlowStore(useShallow((s) => {
const nodes = s.getNodes()
const currentNode = nodes.find(node => node.data.selected)
if (currentNode?.data.type === BlockEnum.LLM) {
return {
id: currentNode.id,
type: currentNode.type,
data: currentNode.data,
selectedNode: {
id: currentNode.id,
type: currentNode.type,
data: currentNode.data,
},
nodes,
}
}
return null
return {
selectedNode: null,
nodes,
}
}))
const extractorNode = useMemo(() => {
return nodes.find(node => node.data.type === BlockEnum.LLM)
}, [nodes])
const availableNodes = useMemo(() => {
return extractorNode ? [extractorNode] : []
}, [extractorNode])
const availableVars = useMemo<NodeOutPutVar[]>(() => {
if (!extractorNode)
return []
const vars = getNodeAvailableVars({
beforeNodes: [extractorNode],
isChatMode,
filterVar: () => true,
})
return vars.filter(item => item.nodeId === extractorNode.id)
}, [extractorNode, getNodeAvailableVars, isChatMode])
const nodePanel = useMemo(() => {
if (!selectedNode)
return null
@ -46,11 +82,25 @@ const SubGraphChildren: FC<SubGraphChildrenProps> = ({
return (
<div className="pointer-events-none absolute inset-y-0 right-0 z-10 flex">
{nodePanel && (
<div className="pointer-events-auto">
{nodePanel}
</div>
)}
<div className="pointer-events-auto">
{nodePanel || (
<div className="relative mr-1 h-full">
<div
className="flex h-full flex-col rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg"
style={{ width: `${nodePanelWidth}px` }}
>
<ConfigPanel
agentName={agentName}
extractorNodeId={extractorNodeId}
mentionConfig={mentionConfig}
availableNodes={availableNodes}
availableVars={availableVars}
onMentionConfigChange={onMentionConfigChange}
/>
</div>
</div>
)}
</div>
</div>
)
}

View File

@ -1,18 +1,21 @@
import type { FC } from 'react'
import type { Viewport } from 'reactflow'
import type { MentionConfig } from '@/app/components/workflow/nodes/_base/types'
import type { Edge, Node } from '@/app/components/workflow/types'
import { useCallback, useMemo } from 'react'
import { useStoreApi } from 'reactflow'
import { WorkflowWithInnerContext } from '@/app/components/workflow'
import { useAvailableNodesMetaData, useSubGraphPersistence } from '../hooks'
import { useAvailableNodesMetaData } from '../hooks'
import SubGraphChildren from './sub-graph-children'
type SubGraphMainProps = {
nodes: Node[]
edges: Edge[]
viewport: Viewport
toolNodeId: string
paramKey: string
agentName: string
extractorNodeId: string
mentionConfig: MentionConfig
onMentionConfigChange: (config: MentionConfig) => void
onSave?: (nodes: Node[], edges: Edge[]) => void
}
@ -20,13 +23,14 @@ const SubGraphMain: FC<SubGraphMainProps> = ({
nodes,
edges,
viewport,
toolNodeId,
paramKey,
agentName,
extractorNodeId,
mentionConfig,
onMentionConfigChange,
onSave,
}) => {
const reactFlowStore = useStoreApi()
const availableNodesMetaData = useAvailableNodesMetaData()
const { updateSubGraphConfig } = useSubGraphPersistence({ toolNodeId, paramKey })
const handleSyncSubGraphDraft = useCallback(() => {
const { getNodes, edges } = reactFlowStore.getState()
@ -53,9 +57,10 @@ const SubGraphMain: FC<SubGraphMainProps> = ({
interactionMode="subgraph"
>
<SubGraphChildren
toolNodeId={toolNodeId}
paramKey={paramKey}
onConfigChange={updateSubGraphConfig}
agentName={agentName}
extractorNodeId={extractorNodeId}
mentionConfig={mentionConfig}
onMentionConfigChange={onMentionConfigChange}
/>
</WorkflowWithInnerContext>
)

View File

@ -5,16 +5,27 @@ import type { InjectWorkflowStoreSliceFn } from '@/app/components/workflow/store
import type { PromptItem } from '@/app/components/workflow/types'
import { memo, useMemo } from 'react'
import WorkflowWithDefaultContext from '@/app/components/workflow'
import { NODE_WIDTH_X_OFFSET, START_INITIAL_POSITION } from '@/app/components/workflow/constants'
import { WorkflowContextProvider } from '@/app/components/workflow/context'
import { BlockEnum, EditionType, PromptRole } from '@/app/components/workflow/types'
import SubGraphMain from './components/sub-graph-main'
import { useSubGraphNodes } from './hooks'
import { createSubGraphSlice } from './store'
const SUB_GRAPH_EDGE_GAP = 180
const SUB_GRAPH_ENTRY_POSITION = {
x: START_INITIAL_POSITION.x,
y: 150,
}
const SUB_GRAPH_LLM_POSITION = {
x: SUB_GRAPH_ENTRY_POSITION.x + NODE_WIDTH_X_OFFSET - SUB_GRAPH_EDGE_GAP,
y: SUB_GRAPH_ENTRY_POSITION.y,
}
const defaultViewport: Viewport = {
x: 50,
x: SUB_GRAPH_EDGE_GAP,
y: 50,
zoom: 1,
zoom: 1.3,
}
const SubGraph: FC<SubGraphProps> = (props) => {
@ -23,6 +34,8 @@ const SubGraph: FC<SubGraphProps> = (props) => {
paramKey,
agentName,
agentNodeId,
mentionConfig,
onMentionConfigChange,
extractorNode,
toolParamValue,
onSave,
@ -41,7 +54,7 @@ const SubGraph: FC<SubGraphProps> = (props) => {
return {
id: 'subgraph-source',
type: 'custom',
position: { x: 100, y: 150 },
position: SUB_GRAPH_ENTRY_POSITION,
data: {
type: BlockEnum.Start,
title: agentName,
@ -50,8 +63,10 @@ const SubGraph: FC<SubGraphProps> = (props) => {
_connectedTargetHandleIds: [],
_subGraphEntry: true,
_iconTypeOverride: BlockEnum.Agent,
selected: false,
variables: [],
},
selected: false,
selectable: false,
draggable: false,
connectable: false,
@ -110,9 +125,11 @@ const SubGraph: FC<SubGraphProps> = (props) => {
return {
...extractorNode,
hidden: false,
position: { x: 320, y: 150 },
selected: false,
position: SUB_GRAPH_LLM_POSITION,
data: {
...extractorNode.data,
selected: false,
prompt_template: nextPromptTemplate,
},
}
@ -159,8 +176,10 @@ const SubGraph: FC<SubGraphProps> = (props) => {
nodes={nodes}
edges={edges}
viewport={defaultViewport}
toolNodeId={toolNodeId}
paramKey={paramKey}
agentName={agentName}
extractorNodeId={`${toolNodeId}_ext_${paramKey}`}
mentionConfig={mentionConfig}
onMentionConfigChange={onMentionConfigChange}
onSave={onSave}
/>
</WorkflowWithDefaultContext>

View File

@ -1,4 +1,5 @@
import type { StateCreator } from 'zustand'
import type { MentionConfig } from '@/app/components/workflow/nodes/_base/types'
import type { LLMNodeType } from '@/app/components/workflow/nodes/llm/types'
import type { Edge, Node, NodeOutPutVar, ValueSelector, VarType } from '@/app/components/workflow/types'
@ -26,6 +27,8 @@ export type SubGraphProps = {
sourceVariable: ValueSelector
agentNodeId: string
agentName: string
mentionConfig: MentionConfig
onMentionConfigChange: (config: MentionConfig) => void
extractorNode?: Node<LLMNodeType>
toolParamValue?: string
onSave?: (nodes: Node[], edges: Edge[]) => void

View File

@ -1,17 +1,19 @@
'use client'
import type { FC } from 'react'
import type { SubGraphModalProps } from './types'
import type { MentionConfig } from '@/app/components/workflow/nodes/_base/types'
import type { LLMNodeType } from '@/app/components/workflow/nodes/llm/types'
import type { ToolNodeType } from '@/app/components/workflow/nodes/tool/types'
import type { Node, PromptItem } from '@/app/components/workflow/types'
import { Dialog, DialogPanel, Transition, TransitionChild } from '@headlessui/react'
import { RiCloseLine } from '@remixicon/react'
import { noop } from 'es-toolkit/function'
import { Fragment, memo, useCallback, useMemo } from 'react'
import { Fragment, memo, useCallback, useEffect, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { useStoreApi } from 'reactflow'
import { Agent } from '@/app/components/base/icons/src/vender/workflow'
import { useNodesSyncDraft } from '@/app/components/workflow/hooks'
import { VarKindType } from '@/app/components/workflow/nodes/_base/types'
import { useStore } from '@/app/components/workflow/store'
import { EditionType, PromptRole } from '@/app/components/workflow/types'
import SubGraphCanvas from './sub-graph-canvas'
@ -38,7 +40,64 @@ const SubGraphModal: FC<SubGraphModalProps> = ({
const toolNode = useMemo(() => {
return workflowNodes.find(node => node.id === toolNodeId)
}, [toolNodeId, workflowNodes])
const toolParamValue = (toolNode?.data as ToolNodeType | undefined)?.tool_parameters?.[paramKey]?.value as string | undefined
const toolParam = (toolNode?.data as ToolNodeType | undefined)?.tool_parameters?.[paramKey]
const toolParamValue = toolParam?.value as string | undefined
const mentionConfig = useMemo<MentionConfig>(() => {
const current = toolParam?.mention_config
const rawSelector = Array.isArray(current?.output_selector) ? current!.output_selector : []
const outputSelector = rawSelector[0] === extractorNodeId ? rawSelector.slice(1) : rawSelector
return {
extractor_node_id: current?.extractor_node_id || extractorNodeId,
output_selector: outputSelector,
null_strategy: current?.null_strategy || 'use_default',
default_value: current?.default_value ?? '',
}
}, [extractorNodeId, toolParam?.mention_config])
const handleMentionConfigChange = useCallback((config: MentionConfig) => {
const { getNodes, setNodes } = reactflowStore.getState()
const nextNodes = getNodes().map((node) => {
if (node.id !== toolNodeId)
return node
const toolData = node.data as ToolNodeType
const currentParam = toolData.tool_parameters?.[paramKey]
if (!currentParam)
return node
return {
...node,
data: {
...toolData,
tool_parameters: {
...toolData.tool_parameters,
[paramKey]: {
...currentParam,
type: currentParam.type || VarKindType.mention,
mention_config: config,
},
},
},
}
})
setNodes(nextNodes)
handleSyncWorkflowDraft(true)
}, [handleSyncWorkflowDraft, paramKey, reactflowStore, toolNodeId])
useEffect(() => {
if (!toolParam || (toolParam.type && toolParam.type !== VarKindType.mention))
return
const current = toolParam.mention_config
const needsExtractor = !current?.extractor_node_id
const needsNullStrategy = !current?.null_strategy
const needsOutputSelector = !Array.isArray(current?.output_selector)
const needsDefaultValue = current?.default_value === undefined
if (needsExtractor || needsNullStrategy || needsOutputSelector || needsDefaultValue)
handleMentionConfigChange(mentionConfig)
}, [handleMentionConfigChange, mentionConfig, toolParam])
const getUserPromptText = useCallback((promptTemplate?: PromptItem[] | PromptItem) => {
if (!promptTemplate)
@ -147,6 +206,8 @@ const SubGraphModal: FC<SubGraphModalProps> = ({
sourceVariable={sourceVariable}
agentNodeId={agentNodeId}
agentName={agentName}
mentionConfig={mentionConfig}
onMentionConfigChange={handleMentionConfigChange}
extractorNode={extractorNode}
toolParamValue={toolParamValue}
onSave={handleSave}

View File

@ -10,6 +10,8 @@ const SubGraphCanvas: FC<SubGraphCanvasProps> = ({
sourceVariable,
agentNodeId,
agentName,
mentionConfig,
onMentionConfigChange,
extractorNode,
toolParamValue,
onSave,
@ -22,6 +24,8 @@ const SubGraphCanvas: FC<SubGraphCanvasProps> = ({
sourceVariable={sourceVariable}
agentNodeId={agentNodeId}
agentName={agentName}
mentionConfig={mentionConfig}
onMentionConfigChange={onMentionConfigChange}
extractorNode={extractorNode}
toolParamValue={toolParamValue}
onSave={onSave}

View File

@ -1,3 +1,4 @@
import type { MentionConfig } from '@/app/components/workflow/nodes/_base/types'
import type { LLMNodeType } from '@/app/components/workflow/nodes/llm/types'
import type { Edge as WorkflowEdge, Node as WorkflowNode } from '@/app/components/workflow/types'
@ -19,6 +20,8 @@ export type SubGraphCanvasProps = {
sourceVariable: WorkflowValueSelector
agentNodeId: string
agentName: string
mentionConfig: MentionConfig
onMentionConfigChange: (config: MentionConfig) => void
extractorNode?: WorkflowNode<LLMNodeType>
toolParamValue?: string
onSave?: (nodes: WorkflowNode[], edges: WorkflowEdge[]) => void

View File

@ -989,7 +989,9 @@
"singleRun.testRunIteration": "Test Run Iteration",
"singleRun.testRunLoop": "Test Run Loop",
"subGraphModal.canvasPlaceholder": "Click to configure the internal structure",
"subGraphModal.defaultValueHint": "Returns the value below",
"subGraphModal.internalStructure": "Internal structure",
"subGraphModal.internalStructureDesc": "Internal structure of @{{name}}",
"subGraphModal.lastRun": "LAST RUN",
"subGraphModal.noRunHistory": "No run history yet",
"subGraphModal.outputVariables": "OUTPUT VARIABLES",
@ -998,7 +1000,9 @@
"subGraphModal.title": "INTERNAL STRUCTURE",
"subGraphModal.whenOutputIsNone": "WHEN OUTPUT IS NONE",
"subGraphModal.whenOutputNone.default": "Use default value",
"subGraphModal.whenOutputNone.defaultDesc": "Continue with a default value",
"subGraphModal.whenOutputNone.error": "Raise an error",
"subGraphModal.whenOutputNone.errorDesc": "Pass the error to the outer workflow",
"subGraphModal.whenOutputNone.skip": "Skip this step",
"tabs.-": "Default",
"tabs.addAll": "Add all",

View File

@ -986,7 +986,9 @@
"singleRun.testRunIteration": "テスト実行(イテレーション)",
"singleRun.testRunLoop": "テスト実行ループ",
"subGraphModal.canvasPlaceholder": "クリックして内部構造を設定",
"subGraphModal.defaultValueHint": "以下の値を返す",
"subGraphModal.internalStructure": "内部構造",
"subGraphModal.internalStructureDesc": "@{{name}} の内部構造",
"subGraphModal.lastRun": "前回の実行",
"subGraphModal.noRunHistory": "実行履歴がありません",
"subGraphModal.outputVariables": "出力変数",
@ -995,7 +997,9 @@
"subGraphModal.title": "内部構造",
"subGraphModal.whenOutputIsNone": "出力が空の場合",
"subGraphModal.whenOutputNone.default": "デフォルト値を使用",
"subGraphModal.whenOutputNone.defaultDesc": "デフォルト値で続行",
"subGraphModal.whenOutputNone.error": "エラーを発生させる",
"subGraphModal.whenOutputNone.errorDesc": "エラーを外部ワークフローに渡す",
"subGraphModal.whenOutputNone.skip": "このステップをスキップ",
"tabs.-": "デフォルト",
"tabs.addAll": "すべてを追加する",

View File

@ -987,7 +987,9 @@
"singleRun.testRunIteration": "测试运行迭代",
"singleRun.testRunLoop": "测试运行循环",
"subGraphModal.canvasPlaceholder": "点击配置内部结构",
"subGraphModal.defaultValueHint": "返回以下值",
"subGraphModal.internalStructure": "内部结构",
"subGraphModal.internalStructureDesc": "@{{name}} 的内部结构",
"subGraphModal.lastRun": "上次运行",
"subGraphModal.noRunHistory": "暂无运行记录",
"subGraphModal.outputVariables": "输出变量",
@ -996,7 +998,9 @@
"subGraphModal.title": "内部结构",
"subGraphModal.whenOutputIsNone": "当输出为空时",
"subGraphModal.whenOutputNone.default": "使用默认值",
"subGraphModal.whenOutputNone.defaultDesc": "使用默认值继续执行",
"subGraphModal.whenOutputNone.error": "抛出错误",
"subGraphModal.whenOutputNone.errorDesc": "将错误传递给外部工作流",
"subGraphModal.whenOutputNone.skip": "跳过此步骤",
"tabs.-": "默认",
"tabs.addAll": "添加全部",

View File

@ -986,7 +986,9 @@
"singleRun.testRunIteration": "測試運行迭代",
"singleRun.testRunLoop": "測試運行循環",
"subGraphModal.canvasPlaceholder": "點擊配置內部結構",
"subGraphModal.defaultValueHint": "返回以下值",
"subGraphModal.internalStructure": "內部結構",
"subGraphModal.internalStructureDesc": "@{{name}} 的內部結構",
"subGraphModal.lastRun": "上次執行",
"subGraphModal.noRunHistory": "暫無執行記錄",
"subGraphModal.outputVariables": "輸出變數",
@ -995,7 +997,9 @@
"subGraphModal.title": "內部結構",
"subGraphModal.whenOutputIsNone": "當輸出為空時",
"subGraphModal.whenOutputNone.default": "使用預設值",
"subGraphModal.whenOutputNone.defaultDesc": "使用預設值繼續執行",
"subGraphModal.whenOutputNone.error": "拋出錯誤",
"subGraphModal.whenOutputNone.errorDesc": "將錯誤傳遞給外部工作流程",
"subGraphModal.whenOutputNone.skip": "跳過此步驟",
"tabs.-": "預設",
"tabs.addAll": "全部新增",