Compare commits

..

3 Commits

Author SHA1 Message Date
yyh
59912d10fc refactor(web): remove code generator React.FC 2026-08-09 17:46:48 +08:00
yyh
b975ed698e refactor(web): use css icon for code generator 2026-08-09 17:45:32 +08:00
yyh
03ca1730c7 fix(web): name code generator action 2026-08-09 17:44:35 +08:00
4 changed files with 52 additions and 25 deletions

View File

@@ -105,8 +105,10 @@ describe('ExternalAPIPanel', () => {
})
it('should render close button', () => {
render(<ExternalAPIPanel {...defaultProps} />)
expect(screen.getByRole('button', { name: 'common.operation.close' })).toBeInTheDocument()
const { container } = render(<ExternalAPIPanel {...defaultProps} />)
const closeButton =
container.querySelector('[class*="action-button"]') || screen.getAllByRole('button')[0]
expect(closeButton)!.toBeInTheDocument()
})
})
@@ -169,7 +171,11 @@ describe('ExternalAPIPanel', () => {
it('should call onClose when close button is clicked', () => {
const onClose = vi.fn()
render(<ExternalAPIPanel canManageExternalKnowledgeApi={true} onClose={onClose} />)
fireEvent.click(screen.getByRole('button', { name: 'common.operation.close' }))
// Find the close button (ActionButton with close icon)
const buttons = screen.getAllByRole('button')
const closeButton =
buttons.find((btn) => btn.querySelector('svg[class*="ri-close"]')) || buttons[0]
fireEvent.click(closeButton!)
expect(onClose).toHaveBeenCalledTimes(1)
})

View File

@@ -1,6 +1,8 @@
import { Button } from '@langgenius/dify-ui/button'
import { cn } from '@langgenius/dify-ui/cn'
import { RiAddLine, RiBookOpenLine, RiCloseLine } from '@remixicon/react'
import { useQuery, useQueryClient } from '@tanstack/react-query'
import * as React from 'react'
import { useTranslation } from 'react-i18next'
import ActionButton from '@/app/components/base/action-button'
import Loading from '@/app/components/base/loading'
@@ -14,7 +16,10 @@ type ExternalAPIPanelProps = {
onClose: () => void
}
const ExternalAPIPanel = ({ canManageExternalKnowledgeApi, onClose }: ExternalAPIPanelProps) => {
const ExternalAPIPanel: React.FC<ExternalAPIPanelProps> = ({
canManageExternalKnowledgeApi,
onClose,
}) => {
const { t } = useTranslation()
const docLink = useDocLink()
const { setShowExternalKnowledgeAPIModal } = useModalContext()
@@ -59,18 +64,15 @@ const ExternalAPIPanel = ({ canManageExternalKnowledgeApi, onClose }: ExternalAP
href={docLink('/use-dify/knowledge/external-knowledge-api')}
target="_blank"
>
<span aria-hidden className="i-ri-book-open-line size-3 text-text-accent" />
<RiBookOpenLine className="size-3 text-text-accent" />
<div className="grow body-xs-regular text-text-accent">
{t(($) => $.externalAPIPanelDocumentation, { ns: 'dataset' })}
</div>
</a>
</div>
<div className="flex items-center">
<ActionButton
aria-label={t(($) => $['operation.close'], { ns: 'common' })}
onClick={() => onClose()}
>
<span aria-hidden className="i-ri-close-line size-4 text-text-tertiary" />
<ActionButton onClick={() => onClose()}>
<RiCloseLine className="size-4 text-text-tertiary" />
</ActionButton>
</div>
</div>
@@ -81,10 +83,7 @@ const ExternalAPIPanel = ({ canManageExternalKnowledgeApi, onClose }: ExternalAP
className="flex items-center justify-center px-3 py-2"
onClick={handleOpenExternalAPIModal}
>
<span
aria-hidden
className="i-ri-add-line size-4 text-components-button-primary-text"
/>
<RiAddLine className="size-4 text-components-button-primary-text" />
<div className="system-sm-medium text-components-button-primary-text">
{t(($) => $.createExternalAPI, { ns: 'dataset' })}
</div>

View File

@@ -0,0 +1,24 @@
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
import CodeGenerateBtn from '../code-generator-button'
vi.mock('@/app/components/app/configuration/config/code-generator/get-code-generator-res', () => ({
GetCodeGeneratorResModal: () => <div role="dialog" aria-label="code generator" />,
}))
vi.mock('@/app/components/workflow/hooks-store', () => ({
useHooksStore: (selector: (state: { configsMap: { flowId: string } }) => unknown) =>
selector({ configsMap: { flowId: 'flow-1' } }),
}))
describe('CodeGenerateBtn', () => {
it('should open the code generator from the named action', async () => {
const user = userEvent.setup()
render(<CodeGenerateBtn nodeId="node-1" codeLanguages={CodeLanguage.python3} />)
await user.click(screen.getByRole('button', { name: 'appDebug.operation.automatic' }))
expect(screen.getByRole('dialog', { name: 'code generator' })).toBeInTheDocument()
})
})

View File

@@ -1,13 +1,12 @@
'use client'
import type { FC } from 'react'
import type { CodeLanguage } from '../../code/types'
import type { GenRes } from '@/service/debug'
import { cn } from '@langgenius/dify-ui/cn'
import * as React from 'react'
import { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { GetCodeGeneratorResModal } from '@/app/components/app/configuration/config/code-generator/get-code-generator-res'
import { ActionButton } from '@/app/components/base/action-button'
import { Generator } from '@/app/components/base/icons/src/vender/other'
import { AppModeEnum } from '@/types/app'
import { useHooksStore } from '../../../hooks-store'
@@ -19,13 +18,8 @@ type Props = Readonly<{
codeLanguages: CodeLanguage
}>
const CodeGenerateBtn: FC<Props> = ({
nodeId,
currentCode,
className,
codeLanguages,
onGenerated,
}) => {
const CodeGenerateBtn = ({ nodeId, currentCode, className, codeLanguages, onGenerated }: Props) => {
const { t } = useTranslation()
const [showAutomatic, setShowAutomatic] = useState(false)
const handleAutomaticRes = useCallback(
(res: GenRes) => {
@@ -38,8 +32,12 @@ const CodeGenerateBtn: FC<Props> = ({
return (
<div className={cn(className)}>
<ActionButton className="hover:bg-[#155EFF]/8" onClick={() => setShowAutomatic(true)}>
<Generator className="size-4 text-primary-600" />
<ActionButton
aria-label={t(($) => $['operation.automatic'], { ns: 'appDebug' })}
className="hover:bg-[#155EFF]/8"
onClick={() => setShowAutomatic(true)}
>
<span aria-hidden className="i-custom-vender-other-generator size-4 text-primary-600" />
</ActionButton>
{showAutomatic && (
<GetCodeGeneratorResModal