chore: display non-LLM settings in integration tool details (#39295)

This commit is contained in:
Joel 2026-07-20 17:52:54 +08:00 committed by GitHub
parent cb64446fa3
commit 79751f7622
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 58 additions and 10 deletions

View File

@ -61,8 +61,8 @@ const createParameter = (overrides?: Partial<ToolParameter>): ToolParameter => (
zh_Hans: 'Setting Param', zh_Hans: 'Setting Param',
}, },
human_description: { human_description: {
en_US: 'desc', en_US: 'Setting description',
zh_Hans: 'desc', zh_Hans: 'Setting description',
}, },
type: 'string', type: 'string',
form: 'config', form: 'config',
@ -91,6 +91,10 @@ const createTool = (overrides?: Partial<Tool>): Tool => ({
en_US: 'Info Param', en_US: 'Info Param',
zh_Hans: 'Info Param', zh_Hans: 'Info Param',
}, },
human_description: {
en_US: 'Info description',
zh_Hans: 'Info description',
},
form: 'llm', form: 'llm',
required: false, required: false,
}), }),
@ -181,6 +185,28 @@ describe('SettingBuiltInTool', () => {
expect(screen.getByTestId('mock-form')).toBeInTheDocument() expect(screen.getByTestId('mock-form')).toBeInTheDocument()
}) })
it('should keep the setting tab hidden when readonly by default', async () => {
renderComponent({ readonly: true })
expect(await screen.findByText('Info Param')).toBeInTheDocument()
expect(screen.queryByText('tools.setBuiltInTools.setting')).not.toBeInTheDocument()
})
it('should expose readonly setting details when explicitly enabled', async () => {
const user = userEvent.setup()
renderComponent({ readonly: true, showReadOnlySettingDetails: true })
expect(await screen.findByText('Info Param')).toBeInTheDocument()
await user.click(screen.getByText('tools.setBuiltInTools.setting'))
expect(screen.getByText('Setting Param')).toBeInTheDocument()
expect(screen.getByText('tools.setBuiltInTools.string')).toBeInTheDocument()
expect(screen.getByText('Setting description')).toBeInTheDocument()
expect(screen.queryByText('Info Param')).not.toBeInTheDocument()
expect(screen.queryByTestId('mock-form')).not.toBeInTheDocument()
expect(screen.queryByRole('button', { name: 'common.operation.save' })).not.toBeInTheDocument()
})
it('should render a masked drawer with balanced vertical offsets', async () => { it('should render a masked drawer with balanced vertical offsets', async () => {
const { baseElement } = renderComponent() const { baseElement } = renderComponent()
await waitFor(() => { await waitFor(() => {

View File

@ -44,6 +44,7 @@ type Props = Readonly<{
toolName: string toolName: string
setting?: Record<string, any> setting?: Record<string, any>
readonly?: boolean readonly?: boolean
showReadOnlySettingDetails?: boolean
onHide: () => void onHide: () => void
onSave?: (value: Record<string, any>) => void onSave?: (value: Record<string, any>) => void
credentialId?: string credentialId?: string
@ -58,6 +59,7 @@ const SettingBuiltInTool: FC<Props> = ({
toolName, toolName,
setting = {}, setting = {},
readonly, readonly,
showReadOnlySettingDetails = false,
onHide, onHide,
onSave, onSave,
credentialId, credentialId,
@ -75,6 +77,8 @@ const SettingBuiltInTool: FC<Props> = ({
const infoSchemas = formSchemas.filter((item) => item.form === 'llm') const infoSchemas = formSchemas.filter((item) => item.form === 'llm')
const settingSchemas = formSchemas.filter((item) => item.form !== 'llm') const settingSchemas = formSchemas.filter((item) => item.form !== 'llm')
const hasSetting = settingSchemas.length > 0 const hasSetting = settingSchemas.length > 0
const showSettingTab = hasSetting && (!readonly || showReadOnlySettingDetails)
const showSettingAsDetails = readonly && showReadOnlySettingDetails
const [tempSetting, setTempSetting] = useState(setting) const [tempSetting, setTempSetting] = useState(setting)
const [currType, setCurrType] = useState('info') const [currType, setCurrType] = useState('info')
const isInfoActive = currType === 'info' const isInfoActive = currType === 'info'
@ -120,12 +124,12 @@ const SettingBuiltInTool: FC<Props> = ({
return type return type
} }
const infoUI = ( const renderSchemaDetails = (schemas: typeof formSchemas) => (
<div className=""> <div className="">
{infoSchemas.length > 0 && ( {schemas.length > 0 && (
<div className="space-y-1 py-2"> <div className="space-y-1 py-2">
{infoSchemas.map((item, index) => ( {schemas.map((item) => (
<div key={index} className="py-1"> <div key={item.name} className="py-1">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<div className="code-sm-semibold text-text-secondary">{item.label[language]}</div> <div className="code-sm-semibold text-text-secondary">{item.label[language]}</div>
<div className="system-xs-regular text-text-tertiary">{getType(item.type)}</div> <div className="system-xs-regular text-text-tertiary">{getType(item.type)}</div>
@ -146,6 +150,8 @@ const SettingBuiltInTool: FC<Props> = ({
)} )}
</div> </div>
) )
const infoUI = renderSchemaDetails(infoSchemas)
const settingDetailsUI = renderSchemaDetails(settingSchemas)
const settingUI = ( const settingUI = (
<Form <Form
@ -230,7 +236,7 @@ const SettingBuiltInTool: FC<Props> = ({
{/* form */} {/* form */}
<div className="h-full"> <div className="h-full">
<div className="flex h-full flex-col"> <div className="flex h-full flex-col">
{hasSetting && !readonly ? ( {showSettingTab ? (
<TabSlider <TabSlider
className="mt-1 shrink-0 px-4" className="mt-1 shrink-0 px-4"
itemClassName="py-3" itemClassName="py-3"
@ -256,7 +262,9 @@ const SettingBuiltInTool: FC<Props> = ({
</div> </div>
)} )}
<div className="h-0 grow overflow-y-auto px-4"> <div className="h-0 grow overflow-y-auto px-4">
{isInfoActive ? infoUI : settingUI} {isInfoActive && infoUI}
{!isInfoActive && showSettingAsDetails && settingDetailsUI}
{!isInfoActive && !showSettingAsDetails && settingUI}
{!readonly && !isInfoActive && ( {!readonly && !isInfoActive && (
<div className="flex shrink-0 justify-end space-x-2 rounded-b-[10px] bg-components-panel-bg py-2"> <div className="flex shrink-0 justify-end space-x-2 rounded-b-[10px] bg-components-panel-bg py-2">
<Button <Button

View File

@ -7,8 +7,17 @@ vi.mock('@/i18n-config/language', () => ({ getLanguage: () => 'en_US' }))
vi.mock( vi.mock(
'@/app/components/app/configuration/config/agent/agent-tools/setting-built-in-tool', '@/app/components/app/configuration/config/agent/agent-tools/setting-built-in-tool',
() => ({ () => ({
default: ({ onHide }: { onHide: () => void }) => ( default: ({
<div data-testid="tool-detail"> onHide,
showReadOnlySettingDetails,
}: {
onHide: () => void
showReadOnlySettingDetails?: boolean
}) => (
<div
data-testid="tool-detail"
data-show-readonly-setting-details={showReadOnlySettingDetails}
>
<button onClick={onHide}>Close details</button> <button onClick={onHide}>Close details</button>
</div> </div>
), ),
@ -34,6 +43,10 @@ describe('ToolItem', () => {
fireEvent.click(screen.getByText('Tool label')) fireEvent.click(screen.getByText('Tool label'))
expect(screen.getByTestId('tool-detail')).toBeInTheDocument() expect(screen.getByTestId('tool-detail')).toBeInTheDocument()
expect(screen.getByTestId('tool-detail')).toHaveAttribute(
'data-show-readonly-setting-details',
'true',
)
fireEvent.click(screen.getByRole('button', { name: 'Close details' })) fireEvent.click(screen.getByRole('button', { name: 'Close details' }))
expect(screen.queryByTestId('tool-detail')).not.toBeInTheDocument() expect(screen.queryByTestId('tool-detail')).not.toBeInTheDocument()

View File

@ -43,6 +43,7 @@ const ToolItem = ({ disabled, collection, tool, isBuiltIn, isModel }: Props) =>
collection={collection} collection={collection}
toolName={tool.name} toolName={tool.name}
readonly readonly
showReadOnlySettingDetails
onHide={() => { onHide={() => {
setShowDetail(false) setShowDetail(false)
}} }}