Feat: upgrade variable assigner (#11285)

Signed-off-by: -LAN- <laipz8200@outlook.com>
Co-authored-by: -LAN- <laipz8200@outlook.com>
This commit is contained in:
Yi Xiao
2024-12-03 13:56:40 +08:00
committed by GitHub
parent e79eac688a
commit e135ffc2c1
62 changed files with 1565 additions and 301 deletions

View File

@@ -33,6 +33,7 @@ export type Props = {
showFileList?: boolean
onGenerated?: (value: string) => void
showCodeGenerator?: boolean
className?: string
}
export const languageMap = {
@@ -67,6 +68,7 @@ const CodeEditor: FC<Props> = ({
showFileList,
onGenerated,
showCodeGenerator = false,
className,
}) => {
const [isFocus, setIsFocus] = React.useState(false)
const [isMounted, setIsMounted] = React.useState(false)
@@ -187,7 +189,7 @@ const CodeEditor: FC<Props> = ({
)
return (
<div className={cn(isExpand && 'h-full')}>
<div className={cn(isExpand && 'h-full', className)}>
{noWrapper
? <div className='relative no-wrapper' style={{
height: isExpand ? '100%' : (editorContentHeight) / 2 + CODE_EDITOR_LINE_HEIGHT, // In IDE, the last line can always be in lop line. So there is some blank space in the bottom.

View File

@@ -47,7 +47,6 @@ const Field: FC<Props> = ({
triggerClassName='w-4 h-4 ml-1'
/>
)}
</div>
<div className='flex'>
{operations && <div>{operations}</div>}

View File

@@ -10,7 +10,7 @@ const ListNoDataPlaceholder: FC<Props> = ({
children,
}) => {
return (
<div className='flex rounded-md bg-gray-50 items-center min-h-[42px] justify-center leading-[18px] text-xs font-normal text-gray-500'>
<div className='flex w-full rounded-[10px] bg-background-section items-center min-h-[42px] justify-center system-xs-regular text-text-tertiary'>
{children}
</div>
)

View File

@@ -0,0 +1,39 @@
'use client'
import type { FC } from 'react'
import React from 'react'
import { useTranslation } from 'react-i18next'
import VarReferenceVars from './var-reference-vars'
import type { NodeOutPutVar, ValueSelector, Var } from '@/app/components/workflow/types'
import ListEmpty from '@/app/components/base/list-empty'
type Props = {
vars: NodeOutPutVar[]
onChange: (value: ValueSelector, varDetail: Var) => void
itemWidth?: number
}
const AssignedVarReferencePopup: FC<Props> = ({
vars,
onChange,
itemWidth,
}) => {
const { t } = useTranslation()
// max-h-[300px] overflow-y-auto todo: use portal to handle long list
return (
<div className='p-1 bg-components-panel-bg-bur rounded-lg border-[0.5px] border-components-panel-border shadow-lg w-[352px]' >
{(!vars || vars.length === 0)
? <ListEmpty
title={t('workflow.nodes.assigner.noAssignedVars') || ''}
description={t('workflow.nodes.assigner.assignedVarsDescription')}
/>
: <VarReferenceVars
searchBoxClassName='mt-1'
vars={vars}
onChange={onChange}
itemWidth={itemWidth}
isSupportFileVar
/>
}
</div >
)
}
export default React.memo(AssignedVarReferencePopup)

View File

@@ -60,6 +60,9 @@ type Props = {
onRemove?: () => void
typePlaceHolder?: string
isSupportFileVar?: boolean
placeholder?: string
minWidth?: number
popupFor?: 'assigned' | 'toAssigned'
}
const VarReferencePicker: FC<Props> = ({
@@ -83,6 +86,9 @@ const VarReferencePicker: FC<Props> = ({
onRemove,
typePlaceHolder,
isSupportFileVar = true,
placeholder,
minWidth,
popupFor,
}) => {
const { t } = useTranslation()
const store = useStoreApi()
@@ -261,7 +267,7 @@ const VarReferencePicker: FC<Props> = ({
<AddButton onClick={() => { }}></AddButton>
</div>
)
: (<div ref={!isSupportConstantValue ? triggerRef : null} className={cn((open || isFocus) ? 'border-gray-300' : 'border-gray-100', 'relative group/wrap flex items-center w-full h-8', !isSupportConstantValue && 'p-1 rounded-lg bg-gray-100 border', isInTable && 'bg-transparent border-none')}>
: (<div ref={!isSupportConstantValue ? triggerRef : null} className={cn((open || isFocus) ? 'border-gray-300' : 'border-gray-100', 'relative group/wrap flex items-center w-full h-8', !isSupportConstantValue && 'p-1 rounded-lg bg-gray-100 border', isInTable && 'bg-transparent border-none', readonly && 'bg-components-input-bg-disabled')}>
{isSupportConstantValue
? <div onClick={(e) => {
e.stopPropagation()
@@ -285,7 +291,7 @@ const VarReferencePicker: FC<Props> = ({
/>
</div>
: (!hasValue && <div className='ml-1.5 mr-1'>
<Variable02 className='w-3.5 h-3.5 text-gray-400' />
<Variable02 className={`w-4 h-4 ${readonly ? 'text-components-input-text-disabled' : 'text-components-input-text-placeholder'}`} />
</div>)}
{isConstant
? (
@@ -329,17 +335,17 @@ const VarReferencePicker: FC<Props> = ({
{!hasValue && <Variable02 className='w-3.5 h-3.5' />}
{isEnv && <Env className='w-3.5 h-3.5 text-util-colors-violet-violet-600' />}
{isChatVar && <BubbleX className='w-3.5 h-3.5 text-util-colors-teal-teal-700' />}
<div className={cn('ml-0.5 text-xs font-medium truncate', (isEnv || isChatVar) && '!text-text-secondary')} title={varName} style={{
<div className={cn('ml-0.5 text-xs font-medium truncate', isEnv && '!text-text-secondary', isChatVar && 'text-util-colors-teal-teal-700')} title={varName} style={{
maxWidth: maxVarNameWidth,
}}>{varName}</div>
</div>
<div className='ml-0.5 text-xs font-normal text-gray-500 capitalize truncate' title={type} style={{
<div className='ml-0.5 capitalize truncate text-text-tertiary text-center system-xs-regular' title={type} style={{
maxWidth: maxTypeWidth,
}}>{type}</div>
{!isValidVar && <RiErrorWarningFill className='ml-0.5 w-3 h-3 text-[#D92D20]' />}
</>
)
: <div className='text-[13px] font-normal text-gray-400'>{t('workflow.common.setVarValuePlaceholder')}</div>}
: <div className={`overflow-hidden ${readonly ? 'text-components-input-text-disabled' : 'text-components-input-text-placeholder'} text-ellipsis system-sm-regular`}>{placeholder ?? t('workflow.common.setVarValuePlaceholder')}</div>}
</div>
</Tooltip>
</div>
@@ -378,12 +384,13 @@ const VarReferencePicker: FC<Props> = ({
</WrapElem>
<PortalToFollowElemContent style={{
zIndex: 100,
}}>
}} className='mt-1'>
{!isConstant && (
<VarReferencePopup
vars={outputVars}
popupFor={popupFor}
onChange={handleVarReferenceChange}
itemWidth={isAddBtnTrigger ? 260 : triggerWidth}
itemWidth={isAddBtnTrigger ? 260 : (minWidth || triggerWidth)}
isSupportFileVar={isSupportFileVar}
/>
)}

View File

@@ -1,33 +1,64 @@
'use client'
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'
type Props = {
vars: NodeOutPutVar[]
popupFor?: 'assigned' | 'toAssigned'
onChange: (value: ValueSelector, varDetail: Var) => void
itemWidth?: number
isSupportFileVar?: boolean
}
const VarReferencePopup: FC<Props> = ({
vars,
popupFor,
onChange,
itemWidth,
isSupportFileVar = true,
}) => {
const { t } = useTranslation()
const { locale } = useContext(I18n)
// max-h-[300px] overflow-y-auto todo: use portal to handle long list
return (
<div className='p-1 bg-white rounded-lg border border-gray-200 shadow-lg space-y-1' style={{
width: itemWidth || 228,
}}>
<VarReferenceVars
searchBoxClassName='mt-1'
vars={vars}
onChange={onChange}
itemWidth={itemWidth}
isSupportFileVar={isSupportFileVar}
/>
{((!vars || vars.length === 0) && popupFor)
? (popupFor === 'toAssigned'
? (
<ListEmpty
title={t('workflow.variableReference.noAvailableVars') || ''}
description={<div className='text-text-tertiary system-xs-regular'>
{t('workflow.variableReference.noVarsForOperation')}
</div>}
/>
)
: (
<ListEmpty
title={t('workflow.variableReference.noAssignedVars') || ''}
description={<div className='text-text-tertiary system-xs-regular'>
{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>
</div>}
/>
))
: <VarReferenceVars
searchBoxClassName='mt-1'
vars={vars}
onChange={onChange}
itemWidth={itemWidth}
isSupportFileVar={isSupportFileVar}
/>
}
</div >
)
}