'use client' import type { FC } from 'react' import type { Emoji, WorkflowToolProviderOutputParameter, WorkflowToolProviderOutputSchema, WorkflowToolProviderParameter, WorkflowToolProviderRequest } from '../types' import { Button } from '@langgenius/dify-ui/button' import { cn } from '@langgenius/dify-ui/cn' import { Dialog, DialogContent, DialogTitle } from '@langgenius/dify-ui/dialog' import { toast } from '@langgenius/dify-ui/toast' import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip' import { produce } from 'immer' import * as React from 'react' import { useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import AppIcon from '@/app/components/base/app-icon' import Divider from '@/app/components/base/divider' import EmojiPickerInner from '@/app/components/base/emoji-picker/Inner' import Input from '@/app/components/base/input' import Textarea from '@/app/components/base/textarea' import LabelSelector from '@/app/components/tools/labels/selector' import ConfirmModal from '@/app/components/tools/workflow-tool/confirm-modal' import MethodSelector from '@/app/components/tools/workflow-tool/method-selector' import { buildWorkflowToolRequestPayload, getReservedWorkflowOutputParameters, getWorkflowOutputParameters, hasReservedWorkflowOutputConflict, isWorkflowToolNameValid, } from './helpers' export type WorkflowToolModalPayload = { icon: Emoji label: string name: string description: string parameters: WorkflowToolProviderParameter[] outputParameters: WorkflowToolProviderOutputParameter[] labels: string[] privacy_policy: string tool?: { output_schema?: WorkflowToolProviderOutputSchema } workflow_tool_id?: string workflow_app_id?: string } type Props = { isAdd?: boolean payload: WorkflowToolModalPayload onHide: () => void onRemove?: () => void onCreate?: (payload: WorkflowToolProviderRequest & { workflow_app_id: string }) => void onSave?: (payload: WorkflowToolProviderRequest & Partial<{ workflow_app_id: string workflow_tool_id: string }>) => void } type WorkflowToolDrawerProps = { title: string onHide: () => void children: React.ReactNode } const InfoTooltip = ({ children }: { children: React.ReactNode }) => { return ( )} />
{children}
) } const WorkflowToolDrawer = ({ title, onHide, children }: WorkflowToolDrawerProps) => { return (
{title}
{children}
) } type WorkflowToolEmojiPickerProps = { onSelect: (icon: string, background: string) => void onClose: () => void } const WorkflowToolEmojiPicker = ({ onSelect, onClose }: WorkflowToolEmojiPickerProps) => { const { t } = useTranslation() const [selectedEmoji, setSelectedEmoji] = useState('') const [selectedBackground, setSelectedBackground] = useState() return ( {t('iconPicker.emoji', { ns: 'app' })} { setSelectedEmoji(emoji) setSelectedBackground(background) }} />
) } // Add and Edit const WorkflowToolAsModal: FC = ({ isAdd, payload, onHide, onRemove, onSave, onCreate, }) => { const { t } = useTranslation() const [showEmojiPicker, setShowEmojiPicker] = useState(false) const [emoji, setEmoji] = useState(payload.icon) const [label, setLabel] = useState(payload.label) const [name, setName] = useState(payload.name) const [description, setDescription] = useState(payload.description) const [parameters, setParameters] = useState(payload.parameters) const rawOutputParameters = payload.outputParameters const outputSchema = payload.tool?.output_schema const outputParameters = useMemo( () => getWorkflowOutputParameters(rawOutputParameters, outputSchema), [rawOutputParameters, outputSchema], ) const reservedOutputParameters = useMemo( () => getReservedWorkflowOutputParameters(t), [t], ) const handleParameterChange = (key: string, value: string, index: number) => { const newData = produce(parameters, (draft: WorkflowToolProviderParameter[]) => { if (key === 'description') draft[index]!.description = value else draft[index]!.form = value }) setParameters(newData) } const [labels, setLabels] = useState(payload.labels) const handleLabelSelect = (value: string[]) => { setLabels(value) } const [privacyPolicy, setPrivacyPolicy] = useState(payload.privacy_policy) const [showModal, setShowModal] = useState(false) const onConfirm = () => { let errorMessage = '' if (!label) errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: t('createTool.name', { ns: 'tools' }) }) if (!name) errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: t('createTool.nameForToolCall', { ns: 'tools' }) }) if (!isWorkflowToolNameValid(name)) errorMessage = t('createTool.nameForToolCall', { ns: 'tools' }) + t('createTool.nameForToolCallTip', { ns: 'tools' }) if (errorMessage) { toast.error(errorMessage) return } const requestParams = buildWorkflowToolRequestPayload({ name, description, emoji, label, parameters, labels, privacyPolicy, }) if (!isAdd) { onSave?.({ ...requestParams, workflow_tool_id: payload.workflow_tool_id!, }) } else { onCreate?.({ ...requestParams, workflow_app_id: payload.workflow_app_id!, }) } } return ( <>
{/* name & icon */}
{t('createTool.name', { ns: 'tools' })} {' '} *
{ setShowEmojiPicker(true) }} className="cursor-pointer" iconType="emoji" icon={emoji.content} background={emoji.background} /> setLabel(e.target.value)} />
{/* name for tool call */}
{t('createTool.nameForToolCall', { ns: 'tools' })} {' '} * {t('createTool.nameForToolCallPlaceHolder', { ns: 'tools' })}
setName(e.target.value)} /> {!isWorkflowToolNameValid(name) && (
{t('createTool.nameForToolCallTip', { ns: 'tools' })}
)}
{/* description */}
{t('createTool.description', { ns: 'tools' })}