Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins
This commit is contained in:
commit
b8e4580074
@ -1,10 +1,9 @@
|
|||||||
import React, { useMemo } from 'react'
|
import React, { useMemo } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import ToolItem from '@/app/components/tools/provider/tool-item'
|
import StrategyItem from '@/app/components/plugins/plugin-detail-panel/strategy-item'
|
||||||
import {
|
import {
|
||||||
useAllToolProviders,
|
useStrategyProviderDetail,
|
||||||
useBuiltinTools,
|
} from '@/service/use-strategy'
|
||||||
} from '@/service/use-tools'
|
|
||||||
import type { PluginDetail } from '@/app/components/plugins/types'
|
import type { PluginDetail } from '@/app/components/plugins/types'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -17,31 +16,31 @@ const AgentStrategyList = ({
|
|||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const providerBriefInfo = detail.declaration.agent_strategy.identity
|
const providerBriefInfo = detail.declaration.agent_strategy.identity
|
||||||
const providerKey = `${detail.plugin_id}/${providerBriefInfo.name}`
|
const providerKey = `${detail.plugin_id}/${providerBriefInfo.name}`
|
||||||
const { data: collectionList = [] } = useAllToolProviders()
|
const { data: strategyProviderDetail } = useStrategyProviderDetail(providerKey)
|
||||||
|
|
||||||
const provider = useMemo(() => {
|
const strategyList = useMemo(() => {
|
||||||
return collectionList.find(collection => collection.name === providerKey)
|
if (!strategyProviderDetail)
|
||||||
}, [collectionList, providerKey])
|
return []
|
||||||
const { data } = useBuiltinTools(providerKey)
|
|
||||||
|
|
||||||
if (!data || !provider)
|
return strategyProviderDetail.declaration.strategies
|
||||||
|
}, [strategyProviderDetail])
|
||||||
|
|
||||||
|
if (!strategyProviderDetail)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='px-4 pt-2 pb-4'>
|
<div className='px-4 pt-2 pb-4'>
|
||||||
<div className='mb-1 py-1'>
|
<div className='mb-1 py-1'>
|
||||||
<div className='mb-1 h-6 flex items-center justify-between text-text-secondary system-sm-semibold-uppercase'>
|
<div className='mb-1 h-6 flex items-center justify-between text-text-secondary system-sm-semibold-uppercase'>
|
||||||
{t('plugin.detailPanel.strategyNum', { num: data.length, strategy: data.length > 1 ? 'strategies' : 'strategy' })}
|
{t('plugin.detailPanel.strategyNum', { num: strategyList.length, strategy: strategyList.length > 1 ? 'strategies' : 'strategy' })}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex flex-col gap-2'>
|
<div className='flex flex-col gap-2'>
|
||||||
{data.map(tool => (
|
{strategyList.map(strategyDetail => (
|
||||||
<ToolItem
|
<StrategyItem
|
||||||
key={`${detail.plugin_id}${tool.name}`}
|
key={`${strategyDetail.identity.provider}${strategyDetail.identity.name}`}
|
||||||
collection={provider}
|
provider={strategyProviderDetail.declaration.identity}
|
||||||
tool={tool}
|
detail={strategyDetail}
|
||||||
isBuiltIn
|
|
||||||
isModel={false}
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -0,0 +1,165 @@
|
|||||||
|
'use client'
|
||||||
|
import type { FC } from 'react'
|
||||||
|
import React, { useMemo } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { useContext } from 'use-context-selector'
|
||||||
|
import {
|
||||||
|
RiArrowLeftLine,
|
||||||
|
RiCloseLine,
|
||||||
|
} from '@remixicon/react'
|
||||||
|
import Drawer from '@/app/components/base/drawer'
|
||||||
|
import ActionButton from '@/app/components/base/action-button'
|
||||||
|
import Icon from '@/app/components/plugins/card/base/card-icon'
|
||||||
|
import Description from '@/app/components/plugins/card/base/description'
|
||||||
|
import Divider from '@/app/components/base/divider'
|
||||||
|
import type {
|
||||||
|
StrategyDetail,
|
||||||
|
} from '@/app/components/plugins/types'
|
||||||
|
import type { Locale } from '@/i18n'
|
||||||
|
import I18n from '@/context/i18n'
|
||||||
|
import { getLanguage } from '@/i18n/language'
|
||||||
|
import cn from '@/utils/classnames'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
provider: {
|
||||||
|
author: string
|
||||||
|
name: string
|
||||||
|
description: Record<Locale, string>
|
||||||
|
icon: string
|
||||||
|
label: Record<Locale, string>
|
||||||
|
tags: string[]
|
||||||
|
}
|
||||||
|
detail: StrategyDetail
|
||||||
|
onHide: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const StrategyDetail: FC<Props> = ({
|
||||||
|
provider,
|
||||||
|
detail,
|
||||||
|
onHide,
|
||||||
|
}) => {
|
||||||
|
const { locale } = useContext(I18n)
|
||||||
|
const language = getLanguage(locale)
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
const outputSchema = useMemo(() => {
|
||||||
|
const res: any[] = []
|
||||||
|
if (!detail.output_schema)
|
||||||
|
return []
|
||||||
|
Object.keys(detail.output_schema.properties).forEach((outputKey) => {
|
||||||
|
const output = detail.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,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}, [detail.output_schema])
|
||||||
|
|
||||||
|
const getType = (type: string) => {
|
||||||
|
if (type === 'number-input')
|
||||||
|
return t('tools.setBuiltInTools.number')
|
||||||
|
if (type === 'text-input')
|
||||||
|
return t('tools.setBuiltInTools.string')
|
||||||
|
if (type === 'file')
|
||||||
|
return t('tools.setBuiltInTools.file')
|
||||||
|
if (type === 'array[tools]')
|
||||||
|
return 'multiple-tool-select'
|
||||||
|
return type
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Drawer
|
||||||
|
isOpen
|
||||||
|
clickOutsideNotOpen={false}
|
||||||
|
onClose={onHide}
|
||||||
|
footer={null}
|
||||||
|
mask={false}
|
||||||
|
positionCenter={false}
|
||||||
|
panelClassname={cn('justify-start mt-[64px] mr-2 mb-2 !w-[420px] !max-w-[420px] !p-0 !bg-components-panel-bg rounded-2xl border-[0.5px] border-components-panel-border shadow-xl')}
|
||||||
|
>
|
||||||
|
<>
|
||||||
|
{/* header */}
|
||||||
|
<div className='relative p-4 pb-3 border-b border-divider-subtle'>
|
||||||
|
<div className='absolute top-3 right-3'>
|
||||||
|
<ActionButton onClick={onHide}>
|
||||||
|
<RiCloseLine className='w-4 h-4' />
|
||||||
|
</ActionButton>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className='mb-2 flex items-center gap-1 text-text-accent-secondary system-xs-semibold-uppercase cursor-pointer'
|
||||||
|
onClick={onHide}
|
||||||
|
>
|
||||||
|
<RiArrowLeftLine className='w-4 h-4' />
|
||||||
|
BACK
|
||||||
|
</div>
|
||||||
|
<div className='flex items-center gap-1'>
|
||||||
|
<Icon size='tiny' className='w-6 h-6' src={provider.icon} />
|
||||||
|
<div className=''>{provider.label[language]}</div>
|
||||||
|
</div>
|
||||||
|
<div className='mt-1 text-text-primary system-md-semibold'>{detail.identity.label[language]}</div>
|
||||||
|
<Description className='mt-3' text={detail.description[language]} descriptionLineRows={2}></Description>
|
||||||
|
</div>
|
||||||
|
{/* form */}
|
||||||
|
<div className='h-full'>
|
||||||
|
<div className='flex flex-col h-full overflow-y-auto'>
|
||||||
|
<div className='p-4 pb-1 text-text-primary system-sm-semibold-uppercase'>{t('tools.setBuiltInTools.parameters')}</div>
|
||||||
|
<div className='px-4'>
|
||||||
|
{detail.parameters.length > 0 && (
|
||||||
|
<div className='py-2 space-y-1'>
|
||||||
|
{detail.parameters.map((item: any, index) => (
|
||||||
|
<div key={index} className='py-1'>
|
||||||
|
<div className='flex items-center gap-2'>
|
||||||
|
<div className='text-text-secondary code-sm-semibold'>{item.label[language]}</div>
|
||||||
|
<div className='text-text-tertiary system-xs-regular'>
|
||||||
|
{getType(item.type)}
|
||||||
|
</div>
|
||||||
|
{item.required && (
|
||||||
|
<div className='text-text-warning-secondary system-xs-medium'>{t('tools.setBuiltInTools.required')}</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{item.human_description && (
|
||||||
|
<div className='mt-0.5 text-text-tertiary system-xs-regular'>
|
||||||
|
{item.human_description?.[language]}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{detail.output_schema && (
|
||||||
|
<>
|
||||||
|
<div className='px-4'>
|
||||||
|
<Divider className="!mt-2" />
|
||||||
|
</div>
|
||||||
|
<div className='p-4 pb-1 text-text-primary system-sm-semibold-uppercase'>OUTPUT</div>
|
||||||
|
{outputSchema.length > 0 && (
|
||||||
|
<div className='py-2 space-y-1'>
|
||||||
|
{outputSchema.map((outputItem, index) => (
|
||||||
|
<div key={index} className='py-1'>
|
||||||
|
<div className='flex items-center gap-2'>
|
||||||
|
<div className='text-text-secondary code-sm-semibold'>{outputItem.name}</div>
|
||||||
|
<div className='text-text-tertiary system-xs-regular'>{outputItem.type}</div>
|
||||||
|
</div>
|
||||||
|
{outputItem.description && (
|
||||||
|
<div className='mt-0.5 text-text-tertiary system-xs-regular'>
|
||||||
|
{outputItem.description}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
</Drawer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default StrategyDetail
|
@ -0,0 +1,52 @@
|
|||||||
|
'use client'
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
import { useContext } from 'use-context-selector'
|
||||||
|
import StrategyDetailPanel from './strategy-detail'
|
||||||
|
import type {
|
||||||
|
StrategyDetail,
|
||||||
|
} from '@/app/components/plugins/types'
|
||||||
|
import type { Locale } from '@/i18n'
|
||||||
|
import I18n from '@/context/i18n'
|
||||||
|
import { getLanguage } from '@/i18n/language'
|
||||||
|
import cn from '@/utils/classnames'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
provider: {
|
||||||
|
author: string
|
||||||
|
name: string
|
||||||
|
description: Record<Locale, string>
|
||||||
|
icon: string
|
||||||
|
label: Record<Locale, string>
|
||||||
|
tags: string[]
|
||||||
|
}
|
||||||
|
detail: StrategyDetail
|
||||||
|
}
|
||||||
|
|
||||||
|
const StrategyItem = ({
|
||||||
|
provider,
|
||||||
|
detail,
|
||||||
|
}: Props) => {
|
||||||
|
const { locale } = useContext(I18n)
|
||||||
|
const language = getLanguage(locale)
|
||||||
|
const [showDetail, setShowDetail] = useState(false)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className={cn('mb-2 px-4 py-3 bg-components-panel-item-bg rounded-xl border-[0.5px] border-components-panel-border-subtle shadow-xs cursor-pointer hover:bg-components-panel-on-panel-item-bg-hover')}
|
||||||
|
onClick={() => setShowDetail(true)}
|
||||||
|
>
|
||||||
|
<div className='pb-0.5 text-text-secondary system-md-semibold'>{detail.identity.label[language]}</div>
|
||||||
|
<div className='text-text-tertiary system-xs-regular line-clamp-2' title={detail.description[language]}>{detail.description[language]}</div>
|
||||||
|
</div>
|
||||||
|
{showDetail && (
|
||||||
|
<StrategyDetailPanel
|
||||||
|
provider={provider}
|
||||||
|
detail={detail}
|
||||||
|
onHide={() => setShowDetail(false)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default StrategyItem
|
@ -379,6 +379,8 @@ export type VersionProps = {
|
|||||||
export type StrategyParamItem = {
|
export type StrategyParamItem = {
|
||||||
name: string
|
name: string
|
||||||
label: Record<Locale, string>
|
label: Record<Locale, string>
|
||||||
|
human_description: Record<Locale, string>
|
||||||
|
llm_description: string
|
||||||
placeholder: Record<Locale, string>
|
placeholder: Record<Locale, string>
|
||||||
type: string
|
type: string
|
||||||
scope: string
|
scope: string
|
||||||
|
Loading…
Reference in New Issue
Block a user