multiple tool selector

pull/12372/head
JzoNg 1 year ago
parent a863e9f674
commit 3c85363392

@ -7,6 +7,7 @@ import ActionList from './action-list'
import ModelList from './model-list' import ModelList from './model-list'
import AgentStrategyList from './agent-strategy-list' import AgentStrategyList from './agent-strategy-list'
import Drawer from '@/app/components/base/drawer' import Drawer from '@/app/components/base/drawer'
import MultipleToolSelector from '@/app/components/plugins/plugin-detail-panel/multiple-tool-selector'
import type { PluginDetail } from '@/app/components/plugins/types' import type { PluginDetail } from '@/app/components/plugins/types'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
@ -58,13 +59,15 @@ const PluginDetailPanel: FC<Props> = ({
{!!detail.declaration.agent_strategy && <AgentStrategyList detail={detail} />} {!!detail.declaration.agent_strategy && <AgentStrategyList detail={detail} />}
{!!detail.declaration.endpoint && <EndpointList detail={detail} />} {!!detail.declaration.endpoint && <EndpointList detail={detail} />}
{!!detail.declaration.model && <ModelList detail={detail} />} {!!detail.declaration.model && <ModelList detail={detail} />}
{/* <div className='px-4 py-2'> {false && (
<MultipleToolSelector <div className='px-4 py-2'>
value={value || []} <MultipleToolSelector
label='TOOLS' value={value || []}
onChange={testChange} label='TOOLS'
/> onChange={testChange}
</div> */} />
</div>
)}
</div> </div>
</> </>
)} )}

@ -5,10 +5,11 @@ import {
RiArrowDropDownLine, RiArrowDropDownLine,
RiQuestionLine, RiQuestionLine,
} from '@remixicon/react' } from '@remixicon/react'
import type { ToolValue } from '@/app/components/plugins/plugin-detail-panel/tool-selector' import ToolSelector from '@/app/components/plugins/plugin-detail-panel/tool-selector'
import ActionButton from '@/app/components/base/action-button' import ActionButton from '@/app/components/base/action-button'
import Tooltip from '@/app/components/base/tooltip' import Tooltip from '@/app/components/base/tooltip'
import Divider from '@/app/components/base/divider' import Divider from '@/app/components/base/divider'
import type { ToolValue } from '@/app/components/plugins/plugin-detail-panel/tool-selector'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
type Props = { type Props = {
@ -18,25 +19,57 @@ type Props = {
required?: boolean required?: boolean
tooltip?: any tooltip?: any
supportCollapse?: boolean supportCollapse?: boolean
onChange: (value: ToolValue[]) => void
scope?: string scope?: string
onChange: (value: ToolValue[]) => void
} }
const MultipleToolSelector = ({ const MultipleToolSelector = ({
disabled,
value, value,
label, label,
required, required,
tooltip, tooltip,
supportCollapse, supportCollapse,
scope,
onChange,
}: Props) => { }: Props) => {
const { t } = useTranslation() const { t } = useTranslation()
// collapse control
const [collapse, setCollapse] = React.useState(false) const [collapse, setCollapse] = React.useState(false)
const handleCollapse = () => { const handleCollapse = () => {
if (supportCollapse) if (supportCollapse)
setCollapse(!collapse) setCollapse(!collapse)
} }
// add tool
const [open, setOpen] = React.useState(false)
const handleAdd = (val: ToolValue) => {
const newValue = [...value, val]
// deduplication
const deduplication = newValue.reduce((acc, cur) => {
if (!acc.find(item => item.provider_name === cur.provider_name && item.tool_name === cur.tool_name))
acc.push(cur)
return acc
}, [] as ToolValue[])
// update value
onChange(deduplication)
setOpen(false)
}
// delete tool
const handleDelete = (index: number) => {
const newValue = [...value]
newValue.splice(index, 1)
onChange(newValue)
}
// configure tool
const handleConfigure = (val: ToolValue, index: number) => {
const newValue = [...value]
newValue[index] = val
onChange(newValue)
}
return ( return (
<> <>
<div className='flex items-center mb-1'> <div className='flex items-center mb-1'>
@ -74,15 +107,38 @@ const MultipleToolSelector = ({
<Divider type='vertical' className='ml-3 mr-1 h-3' /> <Divider type='vertical' className='ml-3 mr-1 h-3' />
</> </>
)} )}
<ActionButton className='mx-1' onClick={() => {}}> {!disabled && (
<RiAddLine className='w-4 h-4' /> <ActionButton className='mx-1' onClick={() => setOpen(!open)}>
</ActionButton> <RiAddLine className='w-4 h-4' />
</ActionButton>
)}
</div> </div>
{!collapse && ( {!collapse && (
<> <>
<ToolSelector
scope={scope}
value={undefined}
onSelect={handleAdd}
controlledState={open}
onControlledStateChange={setOpen}
trigger={
<div className=''></div>
}
/>
{value.length === 0 && ( {value.length === 0 && (
<div className='p-3 flex justify-center rounded-[10px] bg-background-section text-text-tertiary system-xs-regular'>{t('plugin.detailPanel.toolSelector.empty')}</div> <div className='p-3 flex justify-center rounded-[10px] bg-background-section text-text-tertiary system-xs-regular'>{t('plugin.detailPanel.toolSelector.empty')}</div>
)} )}
{value.length > 0 && value.map((item, index) => (
<div className='mb-1' key={index}>
<ToolSelector
scope={scope}
value={item}
onSelect={item => handleConfigure(item, index)}
onDelete={() => handleDelete(index)}
supportEnableSwitch
/>
</div>
))}
</> </>
)} )}
</> </>

@ -49,10 +49,11 @@ export type ToolValue = {
} }
type Props = { type Props = {
value?: ToolValue
disabled?: boolean disabled?: boolean
placement?: Placement placement?: Placement
offset?: OffsetOptions offset?: OffsetOptions
scope?: string
value?: ToolValue
onSelect: (tool: { onSelect: (tool: {
provider_name: string provider_name: string
tool_name: string tool_name: string
@ -60,8 +61,11 @@ type Props = {
extra?: Record<string, any> extra?: Record<string, any>
}) => void }) => void
onDelete?: () => void onDelete?: () => void
supportEnableSwitch?: boolean
supportAddCustomTool?: boolean supportAddCustomTool?: boolean
scope?: string trigger?: React.ReactNode
controlledState?: boolean
onControlledStateChange?: (state: boolean) => void
} }
const ToolSelector: FC<Props> = ({ const ToolSelector: FC<Props> = ({
value, value,
@ -71,6 +75,10 @@ const ToolSelector: FC<Props> = ({
onSelect, onSelect,
onDelete, onDelete,
scope, scope,
supportEnableSwitch,
trigger,
controlledState,
onControlledStateChange,
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
const [isShow, onShowChange] = useState(false) const [isShow, onShowChange] = useState(false)
@ -98,14 +106,13 @@ const ToolSelector: FC<Props> = ({
provider_name: tool.provider_id, provider_name: tool.provider_id,
tool_name: tool.tool_name, tool_name: tool.tool_name,
parameters: paramValues, parameters: paramValues,
enabled: tool.is_team_authorization,
extra: { extra: {
description: '', description: '',
}, },
} }
onSelect(toolValue) onSelect(toolValue)
setIsShowChooseTool(false) setIsShowChooseTool(false)
// if (tool.provider_type === CollectionType.builtIn && tool.is_team_authorization)
// onShowChange(false)
} }
const handleDescriptionChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => { const handleDescriptionChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
@ -133,6 +140,13 @@ const ToolSelector: FC<Props> = ({
onSelect(toolValue as any) onSelect(toolValue as any)
} }
const handleEnabledChange = (state: boolean) => {
onSelect({
...value,
enabled: state,
} as any)
}
// authorization // authorization
const { isCurrentWorkspaceManager } = useAppContext() const { isCurrentWorkspaceManager } = useAppContext()
const [isShowSettingAuth, setShowSettingAuth] = useState(false) const [isShowSettingAuth, setShowSettingAuth] = useState(false)
@ -155,14 +169,15 @@ const ToolSelector: FC<Props> = ({
<PortalToFollowElem <PortalToFollowElem
placement={placement} placement={placement}
offset={offset} offset={offset}
open={isShow} open={trigger ? controlledState : isShow}
onOpenChange={onShowChange} onOpenChange={trigger ? onControlledStateChange : onShowChange}
> >
<PortalToFollowElemTrigger <PortalToFollowElemTrigger
className='w-full' className='w-full'
onClick={handleTriggerClick} onClick={handleTriggerClick}
> >
{!value?.provider_name && ( {trigger}
{!trigger && !value?.provider_name && (
<ToolTrigger <ToolTrigger
isConfigure isConfigure
open={isShow} open={isShow}
@ -170,16 +185,20 @@ const ToolSelector: FC<Props> = ({
provider={currentProvider} provider={currentProvider}
/> />
)} )}
{value?.provider_name && ( {!trigger && value?.provider_name && (
<ToolItem <ToolItem
open={isShow} open={isShow}
icon={currentProvider?.icon} icon={currentProvider?.icon}
providerName={value.provider_name} providerName={value.provider_name}
toolName={value.tool_name} toolName={value.tool_name}
showSwitch={supportEnableSwitch}
switchValue={value.enabled}
onSwitchChange={handleEnabledChange}
onDelete={onDelete} onDelete={onDelete}
noAuth={currentProvider && !currentProvider.is_team_authorization} noAuth={currentProvider && !currentProvider.is_team_authorization}
onAuth={() => setShowSettingAuth(true)} onAuth={() => setShowSettingAuth(true)}
// uninstalled // uninstalled TODO
// isError TODO
errorTip={<div className='space-y-1 text-xs'> errorTip={<div className='space-y-1 text-xs'>
<h3 className='text-text-primary font-semibold'>{t('workflow.nodes.agent.pluginNotInstalled')}</h3> <h3 className='text-text-primary font-semibold'>{t('workflow.nodes.agent.pluginNotInstalled')}</h3>
<p className='text-text-secondary tracking-tight'>{t('workflow.nodes.agent.pluginNotInstalledDesc')}</p> <p className='text-text-secondary tracking-tight'>{t('workflow.nodes.agent.pluginNotInstalledDesc')}</p>

@ -77,7 +77,10 @@ const ToolItem = ({
)} )}
<div <div
className='p-1 rounded-md text-text-tertiary cursor-pointer hover:text-text-destructive' className='p-1 rounded-md text-text-tertiary cursor-pointer hover:text-text-destructive'
onClick={onDelete} onClick={(e) => {
e.stopPropagation()
onDelete?.()
}}
onMouseOver={() => setIsDeleting(true)} onMouseOver={() => setIsDeleting(true)}
onMouseLeave={() => setIsDeleting(false)} onMouseLeave={() => setIsDeleting(false)}
> >
@ -85,11 +88,13 @@ const ToolItem = ({
</div> </div>
</div> </div>
{!isError && !uninstalled && !noAuth && showSwitch && ( {!isError && !uninstalled && !noAuth && showSwitch && (
<Switch <div className='mr-1' onClick={e => e.stopPropagation()}>
className='mr-1' <Switch
size='md' size='md'
defaultValue={switchValue} defaultValue={switchValue}
onChange={onSwitchChange} /> onChange={onSwitchChange}
/>
</div>
)} )}
{!isError && !uninstalled && noAuth && ( {!isError && !uninstalled && noAuth && (
<Button variant='secondary' size='small' onClick={onAuth}> <Button variant='secondary' size='small' onClick={onAuth}>

Loading…
Cancel
Save