Feat/plugins (#12547)

Co-authored-by: AkaraChen <akarachen@outlook.com>
Co-authored-by: Yi <yxiaoisme@gmail.com>
Co-authored-by: Joel <iamjoel007@gmail.com>
Co-authored-by: JzoNg <jzongcode@gmail.com>
Co-authored-by: twwu <twwu@dify.ai>
Co-authored-by: kurokobo <kuro664@gmail.com>
Co-authored-by: Hiroshi Fujita <fujita-h@users.noreply.github.com>
This commit is contained in:
zxhlyh
2025-01-09 18:47:41 +08:00
committed by GitHub
parent e4c4490175
commit 3c014f3ae5
719 changed files with 48585 additions and 8553 deletions

View File

@ -12,7 +12,7 @@ import Button from '@/app/components/base/button'
import { ToastContext } from '@/app/components/base/toast'
import { createEmptyDataset } from '@/service/datasets'
type IProps = {
interface IProps {
show: boolean
onHide: () => void
}

View File

@ -23,7 +23,7 @@ import classNames from '@/utils/classnames'
type IStepOneProps = {
datasetId?: string
dataSourceType?: DataSourceType
dataSourceTypeDisable: Boolean
dataSourceTypeDisable: boolean
hasConnection: boolean
onSetting: () => void
files: FileItem[]

View File

@ -6,7 +6,7 @@ import cn from '@/utils/classnames'
import Popover from '@/app/components/base/popover'
import { languages } from '@/i18n/language'
export type ILanguageSelectProps = {
export interface ILanguageSelectProps {
currentLanguage: string
onSelect: (language: string) => void
disabled?: boolean

View File

@ -5,7 +5,7 @@ import cn from '@/utils/classnames'
import Checkbox from '@/app/components/base/checkbox'
import Tooltip from '@/app/components/base/tooltip'
type Props = {
interface Props {
className?: string
isChecked: boolean
onChange: (isChecked: boolean) => void

View File

@ -4,7 +4,7 @@ import React from 'react'
import cn from '@/utils/classnames'
import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
type Props = {
interface Props {
className?: string
title: string
errorMsg?: string

View File

@ -5,7 +5,7 @@ import Input from './input'
import cn from '@/utils/classnames'
import Tooltip from '@/app/components/base/tooltip'
type Props = {
interface Props {
className?: string
label: string
labelClassName?: string

View File

@ -2,7 +2,7 @@
import type { FC } from 'react'
import React, { useCallback } from 'react'
type Props = {
interface Props {
value: string | number
onChange: (value: string | number) => void
placeholder?: string
@ -20,7 +20,7 @@ const Input: FC<Props> = ({
const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value
if (isNumber) {
let numberValue = parseInt(value, 10) // integer only
let numberValue = Number.parseInt(value, 10) // integer only
if (isNaN(numberValue)) {
onChange('')
return

View File

@ -8,7 +8,7 @@ import { Settings04 } from '@/app/components/base/icons/src/vender/line/general'
import { ChevronRight } from '@/app/components/base/icons/src/vender/line/arrows'
const I18N_PREFIX = 'datasetCreation.stepOne.website'
type Props = {
interface Props {
className?: string
children: React.ReactNode
controlFoldOptions?: number

View File

@ -7,7 +7,7 @@ import Button from '@/app/components/base/button'
const I18N_PREFIX = 'datasetCreation.stepOne.website'
type Props = {
interface Props {
isRunning: boolean
onRun: (url: string) => void
}

View File

@ -6,7 +6,7 @@ import cn from '@/utils/classnames'
import type { CrawlResultItem as CrawlResultItemType } from '@/models/datasets'
import Checkbox from '@/app/components/base/checkbox'
type Props = {
interface Props {
payload: CrawlResultItemType
isChecked: boolean
isPreview: boolean

View File

@ -9,7 +9,7 @@ import type { CrawlResultItem } from '@/models/datasets'
const I18N_PREFIX = 'datasetCreation.stepOne.website'
type Props = {
interface Props {
className?: string
list: CrawlResultItem[]
checkedList: CrawlResultItem[]

View File

@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'
import cn from '@/utils/classnames'
import { RowStruct } from '@/app/components/base/icons/src/public/other'
type Props = {
interface Props {
className?: string
crawledNum: number
totalNum: number

View File

@ -79,7 +79,7 @@ export const useSegmentListContext = (selector: (value: SegmentListContextValue)
return useContextSelector(SegmentListContext, selector)
}
type ICompletedProps = {
interface ICompletedProps {
embeddingAvailable: boolean
showNewSegmentModal: boolean
onNewSegmentModalChange: (state: boolean) => void

View File

@ -29,7 +29,7 @@ const map2Options = (map: { [key: string]: string }) => {
return Object.keys(map).map(key => ({ value: key, name: map[key] }))
}
type IFieldInfoProps = {
interface IFieldInfoProps {
label: string
value?: string
valueIcon?: ReactNode
@ -117,7 +117,7 @@ const IconButton: FC<{
)
}
type IMetadataProps = {
interface IMetadataProps {
docDetail?: FullDocumentDetail
loading: boolean
onUpdate: () => void

View File

@ -0,0 +1,156 @@
import { memo, useState } from 'react'
import type { FC } from 'react'
import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
import { useParams } from 'next/navigation'
import { RiCloseLine } from '@remixicon/react'
import Modal from '@/app/components/base/modal'
import Button from '@/app/components/base/button'
import AutoHeightTextarea from '@/app/components/base/auto-height-textarea/common'
import { Hash02 } from '@/app/components/base/icons/src/vender/line/general'
import { ToastContext } from '@/app/components/base/toast'
import type { SegmentUpdater } from '@/models/datasets'
import { addSegment } from '@/service/datasets'
import TagInput from '@/app/components/base/tag-input'
type NewSegmentModalProps = {
isShow: boolean
onCancel: () => void
docForm: string
onSave: () => void
}
const NewSegmentModal: FC<NewSegmentModalProps> = ({
isShow,
onCancel,
docForm,
onSave,
}) => {
const { t } = useTranslation()
const { notify } = useContext(ToastContext)
const [question, setQuestion] = useState('')
const [answer, setAnswer] = useState('')
const { datasetId, documentId } = useParams()
const [keywords, setKeywords] = useState<string[]>([])
const [loading, setLoading] = useState(false)
const handleCancel = () => {
setQuestion('')
setAnswer('')
onCancel()
setKeywords([])
}
const handleSave = async () => {
const params: SegmentUpdater = { content: '' }
if (docForm === 'qa_model') {
if (!question.trim())
return notify({ type: 'error', message: t('datasetDocuments.segment.questionEmpty') })
if (!answer.trim())
return notify({ type: 'error', message: t('datasetDocuments.segment.answerEmpty') })
params.content = question
params.answer = answer
}
else {
if (!question.trim())
return notify({ type: 'error', message: t('datasetDocuments.segment.contentEmpty') })
params.content = question
}
if (keywords?.length)
params.keywords = keywords
setLoading(true)
try {
await addSegment({ datasetId, documentId, body: params })
notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
handleCancel()
onSave()
}
finally {
setLoading(false)
}
}
const renderContent = () => {
if (docForm === 'qa_model') {
return (
<>
<div className='mb-1 text-xs font-medium text-gray-500'>QUESTION</div>
<AutoHeightTextarea
outerClassName='mb-4'
className='leading-6 text-md text-gray-800'
value={question}
placeholder={t('datasetDocuments.segment.questionPlaceholder') || ''}
onChange={e => setQuestion(e.target.value)}
autoFocus
/>
<div className='mb-1 text-xs font-medium text-gray-500'>ANSWER</div>
<AutoHeightTextarea
outerClassName='mb-4'
className='leading-6 text-md text-gray-800'
value={answer}
placeholder={t('datasetDocuments.segment.answerPlaceholder') || ''}
onChange={e => setAnswer(e.target.value)}
/>
</>
)
}
return (
<AutoHeightTextarea
className='leading-6 text-md text-gray-800'
value={question}
placeholder={t('datasetDocuments.segment.contentPlaceholder') || ''}
onChange={e => setQuestion(e.target.value)}
autoFocus
/>
)
}
return (
<Modal isShow={isShow} onClose={() => { }} className='pt-8 px-8 pb-6 !max-w-[640px] !rounded-xl'>
<div className={'flex flex-col relative'}>
<div className='absolute right-0 -top-0.5 flex items-center h-6'>
<div className='flex justify-center items-center w-6 h-6 cursor-pointer' onClick={handleCancel}>
<RiCloseLine className='w-4 h-4 text-gray-500' />
</div>
</div>
<div className='mb-[14px]'>
<span className='inline-flex items-center px-1.5 h-5 border border-gray-200 rounded-md'>
<Hash02 className='mr-0.5 w-3 h-3 text-gray-400' />
<span className='text-[11px] font-medium text-gray-500 italic'>
{
docForm === 'qa_model'
? t('datasetDocuments.segment.newQaSegment')
: t('datasetDocuments.segment.newTextSegment')
}
</span>
</span>
</div>
<div className='mb-4 py-1.5 h-[420px] overflow-auto'>{renderContent()}</div>
<div className='text-xs font-medium text-gray-500'>{t('datasetDocuments.segment.keywords')}</div>
<div className='mb-8'>
<TagInput items={keywords} onChange={newKeywords => setKeywords(newKeywords)} />
</div>
<div className='flex justify-end space-x-2'>
<Button
onClick={handleCancel}>
{t('common.operation.cancel')}
</Button>
<Button
variant='primary'
onClick={handleSave}
disabled={loading}
>
{t('common.operation.save')}
</Button>
</div>
</div>
</Modal>
)
}
export default memo(NewSegmentModal)

View File

@ -16,7 +16,7 @@ import { ModelTypeEnum } from '@/app/components/header/account-setting/model-pro
import type { NotionPage } from '@/models/common'
import { useDocumentDetail, useInvalidDocumentDetailKey } from '@/service/knowledge/use-document'
type DocumentSettingsProps = {
interface DocumentSettingsProps {
datasetId: string
documentId: string
}

View File

@ -73,7 +73,7 @@ const EmptyElement: FC<{ canAdd: boolean; onClick: () => void; type?: 'upload' |
</div>
}
type IDocumentsProps = {
interface IDocumentsProps {
datasetId: string
}

View File

@ -9,7 +9,7 @@ import Button from '@/app/components/base/button'
import Input from '@/app/components/base/input'
import { renameDocumentName } from '@/service/datasets'
type Props = {
interface Props {
datasetId: string
documentId: string
name: string

View File

@ -87,4 +87,6 @@ const Form: FC<FormProps> = React.memo(({
)
})
Form.displayName = 'Form'
export default Form

View File

@ -15,7 +15,7 @@ import { asyncRunSafe } from '@/utils'
import { RETRIEVE_METHOD, type RetrievalConfig } from '@/types/app'
import promptS from '@/app/components/app/configuration/config-prompt/style.module.css'
type TextAreaWithButtonIProps = {
interface TextAreaWithButtonIProps {
datasetId: string
onUpdateList: () => void
setHitResult: (res: HitTestingResponse) => void

View File

@ -14,7 +14,7 @@ import { ToastContext } from '@/app/components/base/toast'
import type { DataSet } from '@/models/datasets'
import { updateDatasetSetting } from '@/service/datasets'
type RenameDatasetModalProps = {
interface RenameDatasetModalProps {
show: boolean
dataset: DataSet
onSuccess?: () => void

View File

@ -19,7 +19,7 @@ import { ApiConnectionMod } from '@/app/components/base/icons/src/vender/solid/d
import { updateDatasetSetting } from '@/service/datasets'
import { type DataSetListResponse } from '@/models/datasets'
import DatasetDetailContext from '@/context/dataset-detail'
import { type RetrievalConfig } from '@/types/app'
import type { RetrievalConfig } from '@/types/app'
import { useAppContext } from '@/context/app-context'
import { isReRankModelSelected } from '@/app/components/datasets/common/check-rerank-model'
import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector'

View File

@ -15,7 +15,7 @@ import { Users01, UsersPlus } from '@/app/components/base/icons/src/vender/solid
import type { DatasetPermission } from '@/models/datasets'
import { useAppContext } from '@/context/app-context'
import type { Member } from '@/models/common'
export type RoleSelectorProps = {
export interface RoleSelectorProps {
disabled?: boolean
permission?: DatasetPermission
value: string[]