mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-08-16 06:55:58 +08:00
feat: handle tool output ui
This commit is contained in:
parent
1193ab12fc
commit
722d35e9e7
@ -3,6 +3,8 @@ import type { FC, ReactNode } from 'react'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { FieldCollapse } from '@/app/components/workflow/nodes/_base/components/collapse'
|
||||
import TreeIndentLine from './variable/object-child-tree-panel/tree-indent-line'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type Props = {
|
||||
className?: string
|
||||
@ -41,6 +43,7 @@ type VarItemProps = {
|
||||
type: string
|
||||
description: string
|
||||
}[]
|
||||
isIndent?: boolean
|
||||
}
|
||||
|
||||
export const VarItem: FC<VarItemProps> = ({
|
||||
@ -48,29 +51,33 @@ export const VarItem: FC<VarItemProps> = ({
|
||||
type,
|
||||
description,
|
||||
subItems,
|
||||
isIndent,
|
||||
}) => {
|
||||
return (
|
||||
<div className='py-1'>
|
||||
<div className='flex justify-between'>
|
||||
<div className='flex items-center leading-[18px]'>
|
||||
<div className='code-sm-semibold text-text-secondary'>{name}</div>
|
||||
<div className='system-xs-regular ml-2 text-text-tertiary'>{type}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='system-xs-regular mt-0.5 text-text-tertiary'>
|
||||
{description}
|
||||
{subItems && (
|
||||
<div className='ml-2 border-l border-gray-200 pl-2'>
|
||||
{subItems.map((item, index) => (
|
||||
<VarItem
|
||||
key={index}
|
||||
name={item.name}
|
||||
type={item.type}
|
||||
description={item.description}
|
||||
/>
|
||||
))}
|
||||
<div className={cn('flex', isIndent && 'relative left-[-7px]')}>
|
||||
{isIndent && <TreeIndentLine depth={1} />}
|
||||
<div className='py-1'>
|
||||
<div className='flex'>
|
||||
<div className='flex items-center leading-[18px]'>
|
||||
<div className='code-sm-semibold text-text-secondary'>{name}</div>
|
||||
<div className='system-xs-regular ml-2 text-text-tertiary'>{type}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className='system-xs-regular mt-0.5 text-text-tertiary'>
|
||||
{description}
|
||||
{subItems && (
|
||||
<div className='ml-2 border-l border-gray-200 pl-2'>
|
||||
{subItems.map((item, index) => (
|
||||
<VarItem
|
||||
key={index}
|
||||
name={item.name}
|
||||
type={item.type}
|
||||
description={item.description}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
@ -15,6 +15,7 @@ type Props = {
|
||||
payload: FieldType,
|
||||
required: boolean,
|
||||
depth?: number,
|
||||
rootClassName?: string
|
||||
}
|
||||
|
||||
const Field: FC<Props> = ({
|
||||
@ -22,8 +23,10 @@ const Field: FC<Props> = ({
|
||||
payload,
|
||||
depth = 1,
|
||||
required,
|
||||
rootClassName,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const isRoot = depth === 1
|
||||
const hasChildren = payload.type === Type.object && payload.properties
|
||||
const [fold, {
|
||||
toggle: toggleFold,
|
||||
@ -40,7 +43,7 @@ const Field: FC<Props> = ({
|
||||
onClick={toggleFold}
|
||||
/>
|
||||
)}
|
||||
<div className='system-sm-medium h-6 truncate leading-6 text-text-secondary'>{name}</div>
|
||||
<div className={cn('system-sm-medium h-6 truncate leading-6 text-text-secondary', isRoot && rootClassName)}>{name}</div>
|
||||
<div className='system-xs-regular ml-3 shrink-0 leading-6 text-text-tertiary'>{getFieldType(payload)}</div>
|
||||
{required && <div className='system-2xs-medium-uppercase ml-3 leading-6 text-text-warning'>{t('app.structOutput.required')}</div>}
|
||||
</div>
|
||||
|
@ -7,10 +7,12 @@ import { useTranslation } from 'react-i18next'
|
||||
|
||||
type Props = {
|
||||
payload: StructuredOutput
|
||||
rootClassName?: string
|
||||
}
|
||||
|
||||
const ShowPanel: FC<Props> = ({
|
||||
payload,
|
||||
rootClassName,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const schema = {
|
||||
@ -28,6 +30,7 @@ const ShowPanel: FC<Props> = ({
|
||||
name={name}
|
||||
payload={schema.schema.properties![name]}
|
||||
required={!!schema.schema.required?.includes(name)}
|
||||
rootClassName={rootClassName}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
@ -4,15 +4,17 @@ import React from 'react'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type Props = {
|
||||
depth?: number
|
||||
depth?: number,
|
||||
className?: string,
|
||||
}
|
||||
|
||||
const TreeIndentLine: FC<Props> = ({
|
||||
depth = 1,
|
||||
className,
|
||||
}) => {
|
||||
const depthArray = Array.from({ length: depth }, (_, index) => index)
|
||||
return (
|
||||
<div className='ml-2.5 mr-2.5 flex space-x-[12px]'>
|
||||
<div className={cn('ml-2.5 mr-2.5 flex space-x-[12px]', className)}>
|
||||
{depthArray.map(d => (
|
||||
<div key={d} className={cn('w-px bg-divider-regular')}></div>
|
||||
))}
|
||||
|
@ -18,6 +18,7 @@ import { useToolIcon } from '@/app/components/workflow/hooks'
|
||||
import { useLogs } from '@/app/components/workflow/run/hooks'
|
||||
import formatToTracingNodeList from '@/app/components/workflow/run/utils/format-log'
|
||||
import StructureOutputItem from '@/app/components/workflow/nodes/_base/components/variable/object-child-tree-panel/show'
|
||||
import { Type } from '../llm/types'
|
||||
|
||||
const i18nPrefix = 'workflow.nodes.tool'
|
||||
|
||||
@ -52,6 +53,7 @@ const Panel: FC<NodePanelProps<ToolNodeType>> = ({
|
||||
handleStop,
|
||||
runResult,
|
||||
outputSchema,
|
||||
hasObjectOutput,
|
||||
} = useConfig(id, data)
|
||||
const toolIcon = useToolIcon(data)
|
||||
const logsParams = useLogs()
|
||||
@ -135,27 +137,45 @@ const Panel: FC<NodePanelProps<ToolNodeType>> = ({
|
||||
<>
|
||||
<VarItem
|
||||
name='text'
|
||||
type='String'
|
||||
type='string'
|
||||
description={t(`${i18nPrefix}.outputVars.text`)}
|
||||
isIndent={hasObjectOutput}
|
||||
/>
|
||||
<VarItem
|
||||
name='files'
|
||||
type='Array[File]'
|
||||
type='array[file]'
|
||||
description={t(`${i18nPrefix}.outputVars.files.title`)}
|
||||
isIndent={hasObjectOutput}
|
||||
/>
|
||||
<VarItem
|
||||
name='json'
|
||||
type='Array[Object]'
|
||||
type='array[object]'
|
||||
description={t(`${i18nPrefix}.outputVars.json`)}
|
||||
isIndent={hasObjectOutput}
|
||||
/>
|
||||
{outputSchema.map(outputItem => (
|
||||
// <VarItem
|
||||
// key={outputItem.name}
|
||||
// name={outputItem.name}
|
||||
// type={outputItem.type}
|
||||
// description={outputItem.description}
|
||||
// />
|
||||
<StructureOutputItem payload={outputItem} />
|
||||
<div key={outputItem.name}>
|
||||
{outputItem.value?.type === 'object' ? (
|
||||
<StructureOutputItem
|
||||
rootClassName='code-sm-semibold text-text-secondary'
|
||||
payload={{
|
||||
schema: {
|
||||
type: Type.object,
|
||||
properties: {
|
||||
[outputItem.name]: outputItem.value,
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
}} />
|
||||
) : (
|
||||
<VarItem
|
||||
name={outputItem.name}
|
||||
type={outputItem.type.toLocaleLowerCase()}
|
||||
description={outputItem.description}
|
||||
isIndent={hasObjectOutput}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
</OutputVars>
|
||||
|
@ -262,17 +262,33 @@ const useConfig = (id: string, payload: ToolNodeType) => {
|
||||
return []
|
||||
Object.keys(output_schema.properties).forEach((outputKey) => {
|
||||
const output = output_schema.properties[outputKey]
|
||||
res.push({
|
||||
name: outputKey,
|
||||
type: output.type === 'array'
|
||||
? `Array[${output.items?.type.slice(0, 1).toLocaleUpperCase()}${output.items?.type.slice(1)}]`
|
||||
: `${output.type.slice(0, 1).toLocaleUpperCase()}${output.type.slice(1)}`,
|
||||
description: output.description,
|
||||
})
|
||||
const type = output.type
|
||||
if (type === 'object') {
|
||||
res.push({
|
||||
name: outputKey,
|
||||
value: output,
|
||||
})
|
||||
}
|
||||
else {
|
||||
res.push({
|
||||
name: outputKey,
|
||||
type: output.type === 'array'
|
||||
? `Array[${output.items?.type.slice(0, 1).toLocaleUpperCase()}${output.items?.type.slice(1)}]`
|
||||
: `${output.type.slice(0, 1).toLocaleUpperCase()}${output.type.slice(1)}`,
|
||||
description: output.description,
|
||||
})
|
||||
}
|
||||
})
|
||||
return res
|
||||
}, [output_schema])
|
||||
|
||||
const hasObjectOutput = useMemo(() => {
|
||||
if (!output_schema)
|
||||
return false
|
||||
const properties = output_schema.properties
|
||||
return Object.keys(properties).some(key => properties[key].type === 'object')
|
||||
}, [output_schema])
|
||||
|
||||
return {
|
||||
readOnly,
|
||||
inputs,
|
||||
@ -302,6 +318,7 @@ const useConfig = (id: string, payload: ToolNodeType) => {
|
||||
handleStop,
|
||||
runResult,
|
||||
outputSchema,
|
||||
hasObjectOutput,
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user