mirror of
https://github.com/langgenius/dify.git
synced 2026-05-05 18:08:07 +08:00
main
This commit is contained in:
@ -19,11 +19,9 @@ import { useWorkflowStore } from '../../../store'
|
||||
import { useRenderI18nObject } from '@/hooks/use-i18n'
|
||||
import type { NodeOutPutVar } from '../../../types'
|
||||
import type { Node } from 'reactflow'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import I18n from '@/context/i18n'
|
||||
import { LanguagesSupported } from '@/i18n/language'
|
||||
import type { PluginMeta } from '@/app/components/plugins/types'
|
||||
import { noop } from 'lodash'
|
||||
import { useDocLink } from '@/context/i18n'
|
||||
|
||||
export type Strategy = {
|
||||
agent_strategy_provider_name: string
|
||||
@ -56,7 +54,7 @@ type CustomField = ToolSelectorSchema | MultipleToolSelectorSchema
|
||||
export const AgentStrategy = memo((props: AgentStrategyProps) => {
|
||||
const { strategy, onStrategyChange, formSchema, formValue, onFormValueChange, nodeOutputVars, availableNodes, nodeId, canChooseMCPTool } = props
|
||||
const { t } = useTranslation()
|
||||
const { locale } = useContext(I18n)
|
||||
const docLink = useDocLink()
|
||||
const defaultModel = useDefaultModel(ModelTypeEnum.textGeneration)
|
||||
const renderI18nObject = useRenderI18nObject()
|
||||
const workflowStore = useWorkflowStore()
|
||||
@ -71,6 +69,7 @@ export const AgentStrategy = memo((props: AgentStrategyProps) => {
|
||||
case FormTypeEnum.textInput: {
|
||||
const def = schema as CredentialFormSchemaTextInput
|
||||
const value = props.value[schema.variable] || schema.default
|
||||
const instanceId = schema.variable
|
||||
const onChange = (value: string) => {
|
||||
props.onChange({ ...props.value, [schema.variable]: value })
|
||||
}
|
||||
@ -82,6 +81,8 @@ export const AgentStrategy = memo((props: AgentStrategyProps) => {
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
onGenerated={handleGenerated}
|
||||
instanceId={instanceId}
|
||||
key={instanceId}
|
||||
title={renderI18nObject(schema.label)}
|
||||
headerClassName='bg-transparent px-0 text-text-secondary system-sm-semibold-uppercase'
|
||||
containerBackgroundClassName='bg-transparent'
|
||||
@ -122,6 +123,7 @@ export const AgentStrategy = memo((props: AgentStrategyProps) => {
|
||||
title={<>
|
||||
{renderI18nObject(def.label)} {def.required && <span className='text-red-500'>*</span>}
|
||||
</>}
|
||||
key={def.variable}
|
||||
tooltip={def.tooltip && renderI18nObject(def.tooltip)}
|
||||
inline
|
||||
>
|
||||
@ -229,11 +231,11 @@ export const AgentStrategy = memo((props: AgentStrategyProps) => {
|
||||
title={t('workflow.nodes.agent.strategy.configureTip')}
|
||||
description={<div className='text-xs text-text-tertiary'>
|
||||
{t('workflow.nodes.agent.strategy.configureTipDesc')} <br />
|
||||
<Link href={
|
||||
locale === LanguagesSupported[1]
|
||||
? 'https://docs.dify.ai/zh-hans/guides/workflow/node/agent#xuan-ze-agent-ce-le'
|
||||
: 'https://docs.dify.ai/en/guides/workflow/node/agent#select-an-agent-strategy'
|
||||
} className='text-text-accent-secondary' target='_blank'>
|
||||
<Link href={docLink('/guides/workflow/node/agent#select-an-agent-strategy', {
|
||||
'zh-Hans': '/guides/workflow/node/agent#选择-agent-策略',
|
||||
'ja-JP': '/guides/workflow/node/agent#エージェント戦略の選択',
|
||||
})}
|
||||
className='text-text-accent-secondary' target='_blank'>
|
||||
{t('workflow.nodes.agent.learnMore')}
|
||||
</Link>
|
||||
</div>}
|
||||
|
||||
@ -148,7 +148,7 @@ const CodeEditor: FC<Props> = ({
|
||||
{isShowVarPicker && (
|
||||
<div
|
||||
ref={popupRef}
|
||||
className='w-[228px] space-y-1 rounded-lg border border-gray-200 bg-white p-1 shadow-lg'
|
||||
className='w-[228px] space-y-1 rounded-lg border border-components-panel-border bg-components-panel-bg p-1 shadow-lg'
|
||||
style={{
|
||||
position: 'fixed',
|
||||
top: popupPosition.y,
|
||||
|
||||
@ -12,9 +12,10 @@ import { Theme } from '@/types/app'
|
||||
import useTheme from '@/hooks/use-theme'
|
||||
import './style.css'
|
||||
import { noop } from 'lodash-es'
|
||||
import { basePath } from '@/utils/var'
|
||||
|
||||
// load file from local instead of cdn https://github.com/suren-atoyan/monaco-react/issues/482
|
||||
loader.config({ paths: { vs: '/vs' } })
|
||||
loader.config({ paths: { vs: `${basePath}/vs` } })
|
||||
|
||||
const CODE_EDITOR_LINE_HEIGHT = 18
|
||||
|
||||
@ -139,6 +140,7 @@ const CodeEditor: FC<Props> = ({
|
||||
language={languageMap[language] || 'javascript'}
|
||||
theme={isMounted ? theme : 'default-theme'} // sometimes not load the default theme
|
||||
value={outPutValue}
|
||||
loading={<span className='text-text-primary'>Loading...</span>}
|
||||
onChange={handleEditorChange}
|
||||
// https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IEditorOptions.html
|
||||
options={{
|
||||
|
||||
@ -5,6 +5,7 @@ import Input from '@/app/components/base/input'
|
||||
import { VarType } from '@/app/components/workflow/types'
|
||||
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
|
||||
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
|
||||
import { useDocLink } from '@/context/i18n'
|
||||
|
||||
type DefaultValueProps = {
|
||||
forms: DefaultValueForm[]
|
||||
@ -15,6 +16,7 @@ const DefaultValue = ({
|
||||
onFormChange,
|
||||
}: DefaultValueProps) => {
|
||||
const { t } = useTranslation()
|
||||
const docLink = useDocLink()
|
||||
const getFormChangeHandler = useCallback(({ key, type }: DefaultValueForm) => {
|
||||
return (payload: any) => {
|
||||
let value
|
||||
@ -34,7 +36,9 @@ const DefaultValue = ({
|
||||
{t('workflow.nodes.common.errorHandle.defaultValue.desc')}
|
||||
|
||||
<a
|
||||
href='https://docs.dify.ai/en/guides/workflow/error-handling/README'
|
||||
href={docLink('/guides/workflow/error-handling/README', {
|
||||
'zh-Hans': '/guides/workflow/error-handling/readme',
|
||||
})}
|
||||
target='_blank'
|
||||
className='text-text-accent'
|
||||
>
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import { RiMindMap } from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useDocLink } from '@/context/i18n'
|
||||
|
||||
const FailBranchCard = () => {
|
||||
const { t } = useTranslation()
|
||||
const docLink = useDocLink()
|
||||
|
||||
return (
|
||||
<div className='px-4 pt-2'>
|
||||
@ -17,7 +19,7 @@ const FailBranchCard = () => {
|
||||
{t('workflow.nodes.common.errorHandle.failBranch.customizeTip')}
|
||||
|
||||
<a
|
||||
href='https://docs.dify.ai/guides/workflow/error-handling'
|
||||
href={docLink('/guides/workflow/error-handling/error-type')}
|
||||
target='_blank'
|
||||
className='text-text-accent'
|
||||
>
|
||||
|
||||
@ -24,7 +24,7 @@ const HelpLink = ({
|
||||
<a
|
||||
href={link}
|
||||
target='_blank'
|
||||
className='mr-1 flex h-6 w-6 items-center justify-center'
|
||||
className='mr-1 flex h-6 w-6 items-center justify-center rounded-md hover:bg-state-base-hover'
|
||||
>
|
||||
<RiBookOpenLine className='h-4 w-4 text-gray-500' />
|
||||
</a>
|
||||
|
||||
@ -91,6 +91,9 @@ const Editor: FC<Props> = ({
|
||||
acc[node.id] = {
|
||||
title: node.data.title,
|
||||
type: node.data.type,
|
||||
width: node.width,
|
||||
height: node.height,
|
||||
position: node.position,
|
||||
}
|
||||
if (node.data.type === BlockEnum.Start) {
|
||||
acc.sys = {
|
||||
|
||||
@ -0,0 +1,54 @@
|
||||
import { memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiCrosshairLine } from '@remixicon/react'
|
||||
import type { XYPosition } from 'reactflow'
|
||||
import { useReactFlow, useStoreApi } from 'reactflow'
|
||||
import TooltipPlus from '@/app/components/base/tooltip'
|
||||
import { useNodesSyncDraft } from '@/app/components/workflow-app/hooks'
|
||||
|
||||
type NodePositionProps = {
|
||||
nodePosition: XYPosition,
|
||||
nodeWidth?: number | null,
|
||||
nodeHeight?: number | null,
|
||||
}
|
||||
const NodePosition = ({
|
||||
nodePosition,
|
||||
nodeWidth,
|
||||
nodeHeight,
|
||||
}: NodePositionProps) => {
|
||||
const { t } = useTranslation()
|
||||
const reactflow = useReactFlow()
|
||||
const store = useStoreApi()
|
||||
const { doSyncWorkflowDraft } = useNodesSyncDraft()
|
||||
|
||||
if (!nodePosition || !nodeWidth || !nodeHeight) return null
|
||||
|
||||
const workflowContainer = document.getElementById('workflow-container')
|
||||
const { transform } = store.getState()
|
||||
const zoom = transform[2]
|
||||
|
||||
const { clientWidth, clientHeight } = workflowContainer!
|
||||
const { setViewport } = reactflow
|
||||
|
||||
return (
|
||||
<TooltipPlus
|
||||
popupContent={t('workflow.panel.moveToThisNode')}
|
||||
>
|
||||
<div
|
||||
className='mr-1 flex h-6 w-6 cursor-pointer items-center justify-center rounded-md hover:bg-state-base-hover'
|
||||
onClick={() => {
|
||||
setViewport({
|
||||
x: (clientWidth - 400 - nodeWidth * zoom) / 2 - nodePosition.x * zoom,
|
||||
y: (clientHeight - nodeHeight * zoom) / 2 - nodePosition.y * zoom,
|
||||
zoom: transform[2],
|
||||
})
|
||||
doSyncWorkflowDraft()
|
||||
}}
|
||||
>
|
||||
<RiCrosshairLine className='h-4 w-4 text-text-tertiary' />
|
||||
</div>
|
||||
</TooltipPlus>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(NodePosition)
|
||||
@ -259,6 +259,9 @@ const Editor: FC<Props> = ({
|
||||
acc[node.id] = {
|
||||
title: node.data.title,
|
||||
type: node.data.type,
|
||||
width: node.width,
|
||||
height: node.height,
|
||||
position: node.position,
|
||||
}
|
||||
if (node.data.type === BlockEnum.Start) {
|
||||
acc.sys = {
|
||||
|
||||
@ -15,7 +15,7 @@ import { pluginManifestToCardPluginProps } from '@/app/components/plugins/instal
|
||||
import { Badge as Badge2, BadgeState } from '@/app/components/base/badge/index'
|
||||
import Link from 'next/link'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { marketplaceUrlPrefix } from '@/config'
|
||||
import { MARKETPLACE_URL_PREFIX } from '@/config'
|
||||
|
||||
export type SwitchPluginVersionProps = {
|
||||
uniqueIdentifier: string
|
||||
@ -82,7 +82,7 @@ export const SwitchPluginVersion: FC<SwitchPluginVersionProps> = (props) => {
|
||||
modalBottomLeft={
|
||||
<Link
|
||||
className='flex items-center justify-center gap-1'
|
||||
href={`${marketplaceUrlPrefix}/plugins/${pluginDetail.declaration.author}/${pluginDetail.declaration.name}`}
|
||||
href={`${MARKETPLACE_URL_PREFIX}/plugins/${pluginDetail.declaration.author}/${pluginDetail.declaration.name}`}
|
||||
target='_blank'
|
||||
>
|
||||
<span className='system-xs-regular text-xs text-text-accent'>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { useMemo } from 'react'
|
||||
import { useNodes } from 'reactflow'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { useNodes, useReactFlow, useStoreApi } from 'reactflow'
|
||||
import { capitalize } from 'lodash-es'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiErrorWarningFill } from '@remixicon/react'
|
||||
@ -48,12 +48,42 @@ const VariableTag = ({
|
||||
const variableName = isSystemVar(valueSelector) ? valueSelector.slice(0).join('.') : valueSelector.slice(1).join('.')
|
||||
const isException = isExceptionVariable(variableName, node?.data.type)
|
||||
|
||||
const reactflow = useReactFlow()
|
||||
const store = useStoreApi()
|
||||
|
||||
const handleVariableJump = useCallback(() => {
|
||||
const workflowContainer = document.getElementById('workflow-container')
|
||||
const {
|
||||
clientWidth,
|
||||
clientHeight,
|
||||
} = workflowContainer!
|
||||
|
||||
const {
|
||||
setViewport,
|
||||
} = reactflow
|
||||
const { transform } = store.getState()
|
||||
const zoom = transform[2]
|
||||
const position = node.position
|
||||
setViewport({
|
||||
x: (clientWidth - 400 - node.width! * zoom) / 2 - position!.x * zoom,
|
||||
y: (clientHeight - node.height! * zoom) / 2 - position!.y * zoom,
|
||||
zoom: transform[2],
|
||||
})
|
||||
}, [node, reactflow, store])
|
||||
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<Tooltip popupContent={!isValid && t('workflow.errorMsg.invalidVariable')}>
|
||||
<div className={cn('border-[rgba(16, 2440,0.08)] inline-flex h-6 max-w-full items-center rounded-md border-[0.5px] border-divider-subtle bg-components-badge-white-to-dark px-1.5 text-xs shadow-xs',
|
||||
!isValid && 'border-red-400 !bg-[#FEF3F2]',
|
||||
)}>
|
||||
)}
|
||||
onClick={(e) => {
|
||||
if (e.metaKey || e.ctrlKey) {
|
||||
e.stopPropagation()
|
||||
handleVariableJump()
|
||||
}
|
||||
}}
|
||||
>
|
||||
{(!isEnv && !isChatVar && <>
|
||||
{node && (
|
||||
<>
|
||||
|
||||
@ -50,7 +50,7 @@ const ConstantField: FC<Props> = ({
|
||||
{schema.type === FormTypeEnum.textNumber && (
|
||||
<input
|
||||
type='number'
|
||||
className='h-8 w-full overflow-hidden rounded-lg bg-gray-100 p-2 text-[13px] font-normal leading-8 text-gray-900 placeholder:text-gray-400 focus:outline-none'
|
||||
className='h-8 w-full overflow-hidden rounded-lg bg-workflow-block-parma-bg p-2 text-[13px] font-normal leading-8 text-text-secondary placeholder:text-gray-400 focus:outline-none'
|
||||
value={value}
|
||||
onChange={handleStaticChange}
|
||||
readOnly={readonly}
|
||||
|
||||
@ -613,6 +613,7 @@ const getIterationItemType = ({
|
||||
const isSystem = isSystemVar(valueSelector)
|
||||
|
||||
const targetVar = isSystem ? beforeNodesOutputVars.find(v => v.isStartNode) : beforeNodesOutputVars.find(v => v.nodeId === outputVarNodeId)
|
||||
|
||||
if (!targetVar)
|
||||
return VarType.string
|
||||
|
||||
@ -623,9 +624,9 @@ const getIterationItemType = ({
|
||||
arrayType = curr.find((v: any) => v.variable === (valueSelector).join('.'))?.type
|
||||
}
|
||||
else {
|
||||
for (let i = 1; i < valueSelector.length - 1; i++) {
|
||||
for (let i = 1; i < valueSelector.length; i++) {
|
||||
const key = valueSelector[i]
|
||||
const isLast = i === valueSelector.length - 2
|
||||
const isLast = i === valueSelector.length - 1
|
||||
curr = Array.isArray(curr) ? curr.find(v => v.variable === key) : []
|
||||
|
||||
if (isLast)
|
||||
|
||||
@ -8,6 +8,8 @@ import VarReferencePicker from './var-reference-picker'
|
||||
import Input from '@/app/components/base/input'
|
||||
import type { ValueSelector, Var, Variable } from '@/app/components/workflow/types'
|
||||
import { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types'
|
||||
import { checkKeys } from '@/utils/var'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
|
||||
type Props = {
|
||||
nodeId: string
|
||||
@ -36,9 +38,27 @@ const VarList: FC<Props> = ({
|
||||
|
||||
const handleVarNameChange = useCallback((index: number) => {
|
||||
return (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
onVarNameChange?.(list[index].variable, e.target.value)
|
||||
const newKey = e.target.value
|
||||
const { isValid, errorKey, errorMessageKey } = checkKeys([newKey], true)
|
||||
if (!isValid) {
|
||||
Toast.notify({
|
||||
type: 'error',
|
||||
message: t(`appDebug.varKeyError.${errorMessageKey}`, { key: errorKey }),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (list.map(item => item.variable?.trim()).includes(newKey.trim())) {
|
||||
Toast.notify({
|
||||
type: 'error',
|
||||
message: t('appDebug.varKeyError.keyAlreadyExists', { key: newKey }),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
onVarNameChange?.(list[index].variable, newKey)
|
||||
const newList = produce(list, (draft) => {
|
||||
draft[index].variable = e.target.value
|
||||
draft[index].variable = newKey
|
||||
})
|
||||
onChange(newList)
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ import {
|
||||
RiMoreLine,
|
||||
} from '@remixicon/react'
|
||||
import produce from 'immer'
|
||||
import { useStoreApi } from 'reactflow'
|
||||
import { useReactFlow, useStoreApi } from 'reactflow'
|
||||
import RemoveButton from '../remove-button'
|
||||
import useAvailableVarList from '../../hooks/use-available-var-list'
|
||||
import VarReferencePopup from './var-reference-popup'
|
||||
@ -111,6 +111,9 @@ const VarReferencePicker: FC<Props> = ({
|
||||
passedInAvailableNodes,
|
||||
filterVar,
|
||||
})
|
||||
|
||||
const reactflow = useReactFlow()
|
||||
|
||||
const startNode = availableNodes.find((node: any) => {
|
||||
return node.data.type === BlockEnum.Start
|
||||
})
|
||||
@ -172,7 +175,11 @@ const VarReferencePicker: FC<Props> = ({
|
||||
if (isSystemVar(value as ValueSelector))
|
||||
return startNode?.data
|
||||
|
||||
return getNodeInfoById(availableNodes, outputVarNodeId)?.data
|
||||
const node = getNodeInfoById(availableNodes, outputVarNodeId)?.data
|
||||
return {
|
||||
...node,
|
||||
id: outputVarNodeId,
|
||||
}
|
||||
}, [value, hasValue, isConstant, isIterationVar, iterationNode, availableNodes, outputVarNodeId, startNode, isLoopVar, loopNode])
|
||||
|
||||
const isShowAPart = (value as ValueSelector).length > 2
|
||||
@ -237,6 +244,28 @@ const VarReferencePicker: FC<Props> = ({
|
||||
onChange([], varKindType)
|
||||
}, [onChange, varKindType])
|
||||
|
||||
const handleVariableJump = useCallback((nodeId: string) => {
|
||||
const currentNodeIndex = availableNodes.findIndex(node => node.id === nodeId)
|
||||
const currentNode = availableNodes[currentNodeIndex]
|
||||
|
||||
const workflowContainer = document.getElementById('workflow-container')
|
||||
const {
|
||||
clientWidth,
|
||||
clientHeight,
|
||||
} = workflowContainer!
|
||||
const {
|
||||
setViewport,
|
||||
} = reactflow
|
||||
const { transform } = store.getState()
|
||||
const zoom = transform[2]
|
||||
const position = currentNode.position
|
||||
setViewport({
|
||||
x: (clientWidth - 400 - currentNode.width! * zoom) / 2 - position.x * zoom,
|
||||
y: (clientHeight - currentNode.height! * zoom) / 2 - position.y * zoom,
|
||||
zoom: transform[2],
|
||||
})
|
||||
}, [availableNodes, reactflow, store])
|
||||
|
||||
const type = getCurrentVariableType({
|
||||
parentNode: isInIteration ? iterationNode : loopNode,
|
||||
valueSelector: value as ValueSelector,
|
||||
@ -357,7 +386,12 @@ const VarReferencePicker: FC<Props> = ({
|
||||
? (
|
||||
<>
|
||||
{isShowNodeName && !isEnv && !isChatVar && (
|
||||
<div className='flex items-center'>
|
||||
<div className='flex items-center' onClick={(e) => {
|
||||
if (e.metaKey || e.ctrlKey) {
|
||||
e.stopPropagation()
|
||||
handleVariableJump(outputVarNode?.id)
|
||||
}
|
||||
}}>
|
||||
<div className='h-3 px-[1px]'>
|
||||
{outputVarNode?.type && <VarBlockIcon
|
||||
className='!text-text-primary'
|
||||
|
||||
@ -2,12 +2,10 @@
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import VarReferenceVars from './var-reference-vars'
|
||||
import type { NodeOutPutVar, ValueSelector, Var } from '@/app/components/workflow/types'
|
||||
import ListEmpty from '@/app/components/base/list-empty'
|
||||
import { LanguagesSupported } from '@/i18n/language'
|
||||
import I18n from '@/context/i18n'
|
||||
import { useDocLink } from '@/context/i18n'
|
||||
|
||||
type Props = {
|
||||
vars: NodeOutPutVar[]
|
||||
@ -26,7 +24,7 @@ const VarReferencePopup: FC<Props> = ({
|
||||
zIndex,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const { locale } = useContext(I18n)
|
||||
const docLink = useDocLink()
|
||||
// max-h-[300px] overflow-y-auto todo: use portal to handle long list
|
||||
return (
|
||||
<div className='space-y-1 rounded-lg border border-components-panel-border bg-components-panel-bg p-1 shadow-lg' style={{
|
||||
@ -49,7 +47,12 @@ const VarReferencePopup: FC<Props> = ({
|
||||
{t('workflow.variableReference.assignedVarsDescription')}
|
||||
<a target='_blank' rel='noopener noreferrer'
|
||||
className='text-text-accent-secondary'
|
||||
href={locale !== LanguagesSupported[1] ? 'https://docs.dify.ai/guides/workflow/variables#conversation-variables' : `https://docs.dify.ai/${locale.toLowerCase()}/guides/workflow/variables#hui-hua-bian-liang`}>{t('workflow.variableReference.conversationVars')}</a>
|
||||
href={docLink('/guides/workflow/variables#conversation-variables', {
|
||||
'zh-Hans': '/guides/workflow/variables#会话变量',
|
||||
'ja-JP': '/guides/workflow/variables#会話変数',
|
||||
})}>
|
||||
{t('workflow.variableReference.conversationVars')}
|
||||
</a>
|
||||
</div>}
|
||||
/>
|
||||
))
|
||||
|
||||
@ -143,7 +143,7 @@ const Item: FC<ItemProps> = ({
|
||||
ref={itemRef}
|
||||
className={cn(
|
||||
(isObj || isStructureOutput) ? ' pr-1' : 'pr-[18px]',
|
||||
isHovering && ((isObj || isStructureOutput) ? 'bg-primary-50' : 'bg-state-base-hover'),
|
||||
isHovering && ((isObj || isStructureOutput) ? 'bg-components-panel-on-panel-item-bg-hover' : 'bg-state-base-hover'),
|
||||
'relative flex h-6 w-full cursor-pointer items-center rounded-md pl-3')
|
||||
}
|
||||
onClick={handleChosen}
|
||||
@ -263,6 +263,7 @@ type Props = {
|
||||
onClose?: () => void
|
||||
onBlur?: () => void
|
||||
zIndex?: number
|
||||
autoFocus?: boolean
|
||||
}
|
||||
const VarReferenceVars: FC<Props> = ({
|
||||
hideSearch,
|
||||
@ -275,6 +276,7 @@ const VarReferenceVars: FC<Props> = ({
|
||||
onClose,
|
||||
onBlur,
|
||||
zIndex,
|
||||
autoFocus = true,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const [searchText, setSearchText] = useState('')
|
||||
@ -327,7 +329,7 @@ const VarReferenceVars: FC<Props> = ({
|
||||
onKeyDown={handleKeyDown}
|
||||
onClear={() => setSearchText('')}
|
||||
onBlur={onBlur}
|
||||
autoFocus
|
||||
autoFocus={autoFocus}
|
||||
/>
|
||||
</div>
|
||||
<div className='relative left-[-4px] h-[0.5px] bg-black/5' style={{
|
||||
|
||||
@ -43,7 +43,7 @@ const VarReferencePicker: FC<Props> = ({
|
||||
offset={4}
|
||||
>
|
||||
<PortalToFollowElemTrigger onClick={() => setOpen(!open)} className='w-[120px] cursor-pointer'>
|
||||
<div className='flex h-8 items-center justify-between rounded-lg border-0 bg-components-button-secondary-bg px-2.5 text-[13px] text-text-primary'>
|
||||
<div className='flex h-8 items-center justify-between rounded-lg border-0 bg-components-input-bg-normal px-2.5 text-[13px] text-text-primary'>
|
||||
<div className='w-0 grow truncate capitalize' title={value}>{value}</div>
|
||||
<RiArrowDownSLine className='h-3.5 w-3.5 shrink-0 text-text-secondary' />
|
||||
</div>
|
||||
|
||||
@ -1,14 +1,12 @@
|
||||
import { useMemo } from 'react'
|
||||
import { useGetLanguage } from '@/context/i18n'
|
||||
import { useDocLink, useGetLanguage } from '@/context/i18n'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
|
||||
export const useNodeHelpLink = (nodeType: BlockEnum) => {
|
||||
const language = useGetLanguage()
|
||||
const docLink = useDocLink()
|
||||
const prefixLink = useMemo(() => {
|
||||
if (language === 'zh_Hans')
|
||||
return 'https://docs.dify.ai/zh-hans/guides/workflow/node/'
|
||||
|
||||
return 'https://docs.dify.ai/en/guides/workflow/node/'
|
||||
return docLink('/guides/workflow/node/')
|
||||
}, [language])
|
||||
const linkMap = useMemo(() => {
|
||||
if (language === 'zh_Hans') {
|
||||
|
||||
@ -16,6 +16,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import NextStep from './components/next-step'
|
||||
import PanelOperator from './components/panel-operator'
|
||||
import HelpLink from './components/help-link'
|
||||
import NodePosition from './components/node-position'
|
||||
import {
|
||||
DescriptionInput,
|
||||
TitleInput,
|
||||
@ -55,6 +56,9 @@ const BasePanel: FC<BasePanelProps> = ({
|
||||
id,
|
||||
data,
|
||||
children,
|
||||
position,
|
||||
width,
|
||||
height,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const { showMessageLogModal } = useAppStore(useShallow(state => ({
|
||||
@ -150,6 +154,7 @@ const BasePanel: FC<BasePanelProps> = ({
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
<NodePosition nodePosition={position} nodeWidth={width} nodeHeight={height}></NodePosition>
|
||||
<HelpLink nodeType={data.type} />
|
||||
<PanelOperator id={id} data={data} showHelpLink={false} />
|
||||
<div className='mx-3 h-3.5 w-[1px] bg-divider-regular' />
|
||||
|
||||
Reference in New Issue
Block a user