mirror of
https://github.com/langgenius/dify.git
synced 2026-05-03 00:48:04 +08:00
feat: panel ui
This commit is contained in:
@ -5,7 +5,6 @@ import type { ToolWithProvider } from '@/app/components/workflow/types'
|
||||
import * as React from 'react'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { createPortal } from 'react-dom'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import AppIcon from '@/app/components/base/app-icon'
|
||||
import { useSelectOrDelete } from '@/app/components/base/prompt-editor/hooks'
|
||||
import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
@ -28,6 +27,7 @@ import { canFindTool } from '@/utils'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { basePath } from '@/utils/var'
|
||||
import { DELETE_TOOL_BLOCK_COMMAND } from './index'
|
||||
import ToolHeader from './tool-header'
|
||||
|
||||
type ToolBlockComponentProps = {
|
||||
nodeKey: string
|
||||
@ -85,7 +85,6 @@ const ToolBlockComponent: FC<ToolBlockComponentProps> = ({
|
||||
}) => {
|
||||
const [ref, isSelected] = useSelectOrDelete(nodeKey, DELETE_TOOL_BLOCK_COMMAND)
|
||||
const language = useGetLanguage()
|
||||
const { t } = useTranslation()
|
||||
const { theme } = useTheme()
|
||||
const [isSettingOpen, setIsSettingOpen] = useState(false)
|
||||
const [toolValue, setToolValue] = useState<ToolValue | null>(null)
|
||||
@ -127,6 +126,17 @@ const ToolBlockComponent: FC<ToolBlockComponentProps> = ({
|
||||
}
|
||||
}, [currentProvider, currentTool, language, tool])
|
||||
|
||||
const toolDescriptionText = useMemo(() => {
|
||||
if (toolValue?.tool_description)
|
||||
return toolValue.tool_description
|
||||
if (currentTool?.description) {
|
||||
return typeof currentTool.description === 'object'
|
||||
? (currentTool.description?.[language] || '')
|
||||
: (currentTool.description || '')
|
||||
}
|
||||
return ''
|
||||
}, [currentTool?.description, language, toolValue?.tool_description])
|
||||
|
||||
const toolConfigFromMetadata = useMemo(() => {
|
||||
if (!activeTabId)
|
||||
return undefined
|
||||
@ -345,14 +355,19 @@ const ToolBlockComponent: FC<ToolBlockComponentProps> = ({
|
||||
</span>
|
||||
{portalContainer && isSettingOpen && createPortal(
|
||||
<div
|
||||
className="absolute right-4 top-4 z-[999]"
|
||||
className="absolute bottom-4 right-4 top-4 z-[999]"
|
||||
data-tool-setting-panel="true"
|
||||
>
|
||||
<div className={cn('relative max-h-[642px] min-h-20 w-[361px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur pb-4 shadow-lg backdrop-blur-sm', 'overflow-y-auto pb-2')}>
|
||||
<div className="system-xl-semibold px-4 pb-1 pt-3.5 text-text-primary">{t('detailPanel.toolSelector.toolSetting', { ns: 'plugin' })}</div>
|
||||
<div className={cn('relative h-full min-h-20 w-[361px] overflow-y-auto rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur pb-4 shadow-lg backdrop-blur-sm', 'overflow-y-auto pb-2')}>
|
||||
{currentProvider && currentTool && toolValue && (
|
||||
<>
|
||||
<div className="px-4 pb-2 text-xs text-text-tertiary">{displayLabel}</div>
|
||||
<ToolHeader
|
||||
icon={resolvedIcon}
|
||||
providerLabel={currentProvider.label?.[language] || currentProvider.name || provider}
|
||||
toolLabel={toolValue.tool_label || displayLabel}
|
||||
description={toolDescriptionText}
|
||||
onClose={() => setIsSettingOpen(false)}
|
||||
/>
|
||||
<ToolAuthorizationSection
|
||||
currentProvider={currentProvider}
|
||||
credentialId={toolValue.credential_id}
|
||||
|
||||
@ -0,0 +1,100 @@
|
||||
'use client'
|
||||
|
||||
import type { FC } from 'react'
|
||||
import type { Emoji } from '@/app/components/tools/types'
|
||||
import { RiBookOpenLine, RiCloseLine } from '@remixicon/react'
|
||||
import AppIcon from '@/app/components/base/app-icon'
|
||||
|
||||
type ToolHeaderProps = {
|
||||
icon: string | Emoji | undefined
|
||||
providerLabel: string
|
||||
toolLabel: string
|
||||
description: string
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
const ToolHeader: FC<ToolHeaderProps> = ({
|
||||
icon,
|
||||
providerLabel,
|
||||
toolLabel,
|
||||
description,
|
||||
onClose,
|
||||
}) => {
|
||||
const renderHeaderIcon = () => {
|
||||
if (!icon)
|
||||
return null
|
||||
if (typeof icon === 'string') {
|
||||
if (icon.startsWith('http') || icon.startsWith('/')) {
|
||||
return (
|
||||
<span className="flex h-5 w-5 shrink-0 items-center justify-center overflow-hidden rounded-[6px] border border-divider-subtle bg-background-default-dodge">
|
||||
<span
|
||||
className="h-full w-full bg-cover bg-center"
|
||||
style={{ backgroundImage: `url(${icon})` }}
|
||||
/>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<AppIcon
|
||||
size="xs"
|
||||
icon={icon}
|
||||
className="!h-5 !w-5 shrink-0 !rounded-[6px] !border border-divider-subtle bg-background-default-dodge"
|
||||
/>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<AppIcon
|
||||
size="xs"
|
||||
icon={icon.content}
|
||||
background={icon.background}
|
||||
className="!h-5 !w-5 shrink-0 !rounded-[6px] !border border-divider-subtle bg-background-default-dodge"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex items-start gap-1 px-3 pb-2 pt-3">
|
||||
<div className="flex flex-1 flex-col items-start">
|
||||
<div className="flex items-center gap-1 rounded-md px-1 py-1">
|
||||
{renderHeaderIcon()}
|
||||
<span className="system-xs-medium text-text-tertiary">
|
||||
{providerLabel}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-1 pt-1">
|
||||
<button
|
||||
type="button"
|
||||
className="flex h-6 w-6 items-center justify-center rounded-[6px] text-text-tertiary hover:bg-state-base-hover"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation()
|
||||
}}
|
||||
>
|
||||
<RiBookOpenLine className="h-4 w-4" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="flex h-6 w-6 items-center justify-center rounded-[6px] text-text-tertiary hover:bg-state-base-hover"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation()
|
||||
onClose()
|
||||
}}
|
||||
>
|
||||
<RiCloseLine className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-1.5 px-3 pb-2">
|
||||
<div className="system-md-semibold text-text-primary">
|
||||
{toolLabel}
|
||||
</div>
|
||||
<div className="system-sm-regular mt-2.5 text-text-secondary">
|
||||
{description}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default ToolHeader
|
||||
Reference in New Issue
Block a user