chore: url in tool description support clicking jump directly (#35163)

This commit is contained in:
Joel 2026-04-14 17:55:55 +08:00 committed by GitHub
parent 736880e046
commit d4783e8c14
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 69 additions and 2 deletions

View File

@ -78,6 +78,7 @@ describe('tool/tool-form/item', () => {
mockUseLanguage.mockReturnValue('en_US')
})
// Text input fields render their descriptions inline above the input.
it('should render text input labels and forward props to form input item', () => {
const handleChange = vi.fn()
const handleManageInputField = vi.fn()
@ -121,6 +122,31 @@ describe('tool/tool-form/item', () => {
})
})
// URL fragments inside descriptions should be rendered as external links.
it('should render URLs in descriptions as external links', () => {
render(
<ToolFormItem
readOnly={false}
nodeId="tool-node"
schema={createSchema({
tooltip: {
en_US: 'Visit https://docs.dify.ai/tools for docs',
zh_Hans: 'Visit https://docs.dify.ai/tools for docs',
},
})}
value={{}}
onChange={vi.fn()}
/>,
)
const link = screen.getByRole('link', { name: 'https://docs.dify.ai/tools' })
expect(link).toHaveAttribute('href', 'https://docs.dify.ai/tools')
expect(link).toHaveAttribute('target', '_blank')
expect(link).toHaveAttribute('rel', 'noopener noreferrer')
expect(link.parentElement).toHaveTextContent('Visit https://docs.dify.ai/tools for docs')
})
// Non-text fields keep their descriptions inside the tooltip and support JSON schema preview.
it('should show tooltip for non-description fields and open the schema modal', () => {
const objectSchema = createSchema({
name: 'tool_config',

View File

@ -1,5 +1,5 @@
'use client'
import type { FC } from 'react'
import type { FC, ReactNode } from 'react'
import type { ToolVarInputs } from '../../types'
import type { CredentialFormSchema } from '@/app/components/header/account-setting/model-provider-page/declarations'
import type { Tool } from '@/app/components/tools/types'
@ -15,6 +15,45 @@ import { useLanguage } from '@/app/components/header/account-setting/model-provi
import { SchemaModal } from '@/app/components/plugins/plugin-detail-panel/tool-selector/components'
import FormInputItem from '@/app/components/workflow/nodes/_base/components/form-input-item'
const URL_REGEX = /(https?:\/\/\S+)/g
const renderDescriptionWithLinks = (description: string): ReactNode => {
const matches = [...description.matchAll(URL_REGEX)]
if (!matches.length)
return description
const parts: ReactNode[] = []
let currentIndex = 0
matches.forEach((match, index) => {
const [url] = match
const start = match.index ?? 0
if (start > currentIndex)
parts.push(description.slice(currentIndex, start))
parts.push(
<a
key={`${url}-${index}`}
href={url}
target="_blank"
rel="noopener noreferrer"
className="text-text-accent hover:underline"
>
{url}
</a>,
)
currentIndex = start + url.length
})
if (currentIndex < description.length)
parts.push(description.slice(currentIndex))
return parts
}
type Props = {
readOnly: boolean
nodeId: string
@ -87,7 +126,9 @@ const ToolFormItem: FC<Props> = ({
)}
</div>
{showDescription && tooltip && (
<div className="body-xs-regular pb-0.5 text-text-tertiary">{tooltip[language] || tooltip.en_US}</div>
<div className="body-xs-regular break-words pb-0.5 text-text-tertiary">
{renderDescriptionWithLinks(tooltip[language] || tooltip.en_US)}
</div>
)}
</div>
<FormInputItem