mirror of
https://github.com/langgenius/dify.git
synced 2026-08-30 17:11:50 +08:00
refactor(web): migrate external API input fields (#41052)
This commit is contained in:
@@ -2293,11 +2293,6 @@
|
||||
"count": 3
|
||||
}
|
||||
},
|
||||
"web/app/components/datasets/external-api/external-api-modal/Form.tsx": {
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"web/app/components/datasets/external-knowledge-base/create/ExternalApiSelect.tsx": {
|
||||
"eslint-react/set-state-in-effect": {
|
||||
"count": 1
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import type { FC } from 'react'
|
||||
import type { FC, FormEventHandler } from 'react'
|
||||
import type { CreateExternalAPIReq, FormSchema } from '../declarations'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { Input } from '@langgenius/dify-ui/input'
|
||||
import { RiBookOpenLine } from '@remixicon/react'
|
||||
import * as React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Input from '@/app/components/base/input'
|
||||
import { useDocLink } from '@/context/i18n'
|
||||
|
||||
type FormProps = {
|
||||
id: string
|
||||
onSubmit: FormEventHandler<HTMLFormElement>
|
||||
className?: string
|
||||
itemClassName?: string
|
||||
fieldLabelClassName?: string
|
||||
@@ -19,6 +21,8 @@ type FormProps = {
|
||||
|
||||
const Form: FC<FormProps> = React.memo(
|
||||
({
|
||||
id,
|
||||
onSubmit,
|
||||
className,
|
||||
itemClassName,
|
||||
fieldLabelClassName,
|
||||
@@ -78,6 +82,10 @@ const Form: FC<FormProps> = React.memo(
|
||||
</div>
|
||||
<Input
|
||||
type={type === 'secret' ? 'password' : 'text'}
|
||||
autoComplete="off"
|
||||
inputMode={variable === 'endpoint' ? 'url' : undefined}
|
||||
placeholder={t(($) => $['placeholder.input'], { ns: 'common' }) || ''}
|
||||
spellCheck={variable === 'endpoint' || type === 'secret' ? false : undefined}
|
||||
id={variable}
|
||||
name={variable}
|
||||
value={fieldValue}
|
||||
@@ -91,6 +99,8 @@ const Form: FC<FormProps> = React.memo(
|
||||
|
||||
return (
|
||||
<form
|
||||
id={id}
|
||||
onSubmit={onSubmit}
|
||||
className={cn('flex flex-col items-start justify-center gap-4 self-stretch', className)}
|
||||
>
|
||||
{formSchemas.map((formSchema) => renderField(formSchema))}
|
||||
|
||||
@@ -40,6 +40,8 @@ describe('Form', () => {
|
||||
}
|
||||
|
||||
const defaultProps = {
|
||||
id: 'external-api-form',
|
||||
onSubmit: vi.fn(),
|
||||
value: defaultValue,
|
||||
onChange: vi.fn(),
|
||||
formSchemas: defaultFormSchemas,
|
||||
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
import type { CreateExternalAPIReq } from '../../declarations'
|
||||
import { fireEvent, screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vite-plus/test'
|
||||
// Import mocked service
|
||||
import { createExternalAPI } from '@/service/datasets'
|
||||
@@ -168,6 +169,7 @@ describe('AddExternalAPIModal', () => {
|
||||
vi.mocked(createExternalAPI).mockResolvedValue(mockResponse)
|
||||
const onSave = vi.fn()
|
||||
const onCancel = vi.fn()
|
||||
const user = userEvent.setup()
|
||||
|
||||
render(<AddExternalAPIModal {...defaultProps} onSave={onSave} onCancel={onCancel} />)
|
||||
|
||||
@@ -179,8 +181,7 @@ describe('AddExternalAPIModal', () => {
|
||||
fireEvent.change(endpointInput, { target: { value: 'https://test.com' } })
|
||||
fireEvent.change(apiKeyInput, { target: { value: 'key12345' } })
|
||||
|
||||
const saveButton = screen.getByText('dataset.externalAPIForm.save').closest('button')!
|
||||
fireEvent.click(saveButton)
|
||||
await user.click(screen.getByRole('button', { name: 'dataset.externalAPIForm.save' }))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(createExternalAPI).toHaveBeenCalledWith({
|
||||
|
||||
@@ -15,7 +15,7 @@ import { IconButton } from '@langgenius/dify-ui/icon-button'
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@langgenius/dify-ui/popover'
|
||||
import { toast } from '@langgenius/dify-ui/toast'
|
||||
import { RiBook2Line, RiCloseLine, RiInformation2Line, RiLock2Fill } from '@remixicon/react'
|
||||
import { memo, useState } from 'react'
|
||||
import { memo, useId, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { createExternalAPI } from '@/service/datasets'
|
||||
import Form from './Form'
|
||||
@@ -75,6 +75,7 @@ const AddExternalAPIModal: FC<AddExternalAPIModalProps> = ({
|
||||
onEdit,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const formId = useId()
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [showConfirm, setShowConfirm] = useState(false)
|
||||
const [formData, setFormData] = useState<CreateExternalAPIReq>(() =>
|
||||
@@ -121,6 +122,15 @@ const AddExternalAPIModal: FC<AddExternalAPIModalProps> = ({
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleSubmit = () => {
|
||||
if (hasEmptyInputs || loading) return
|
||||
|
||||
if (isEditMode && (datasetBindings?.length ?? 0) > 0) setShowConfirm(true)
|
||||
else if (isEditMode && onEdit) onEdit(formData)
|
||||
else handleSave()
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open
|
||||
@@ -192,8 +202,13 @@ const AddExternalAPIModal: FC<AddExternalAPIModalProps> = ({
|
||||
<RiCloseLine aria-hidden className="h-4.5 w-4.5 shrink-0 text-text-tertiary" />
|
||||
</IconButton>
|
||||
<Form
|
||||
id={formId}
|
||||
value={formData}
|
||||
onChange={handleDataChange}
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault()
|
||||
handleSubmit()
|
||||
}}
|
||||
formSchemas={formSchemas}
|
||||
className="min-h-0 w-full flex-1 overflow-y-auto px-6 py-3"
|
||||
/>
|
||||
@@ -202,14 +217,11 @@ const AddExternalAPIModal: FC<AddExternalAPIModalProps> = ({
|
||||
{t(($) => $['externalAPIForm.cancel'], { ns: 'dataset' })}
|
||||
</Button>
|
||||
<Button
|
||||
form={formId}
|
||||
type="submit"
|
||||
variant="primary"
|
||||
onClick={() => {
|
||||
if (isEditMode && (datasetBindings?.length ?? 0) > 0) setShowConfirm(true)
|
||||
else if (isEditMode && onEdit) onEdit(formData)
|
||||
else handleSave()
|
||||
}}
|
||||
disabled={hasEmptyInputs || loading}
|
||||
loading={loading}
|
||||
disabled={hasEmptyInputs}
|
||||
>
|
||||
{t(($) => $['externalAPIForm.save'], { ns: 'dataset' })}
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user