feat: parent child retrieval (#12106)
Signed-off-by: -LAN- <laipz8200@outlook.com> Co-authored-by: -LAN- <laipz8200@outlook.com>
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import StatusWithAction from './status-with-action'
|
||||
import { useAutoDisabledDocuments, useDocumentEnable, useInvalidDisabledDocument } from '@/service/knowledge/use-document'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
type Props = {
|
||||
datasetId: string
|
||||
}
|
||||
|
||||
const AutoDisabledDocument: FC<Props> = ({
|
||||
datasetId,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const { data, isLoading } = useAutoDisabledDocuments(datasetId)
|
||||
const invalidDisabledDocument = useInvalidDisabledDocument()
|
||||
const documentIds = data?.document_ids
|
||||
const hasDisabledDocument = documentIds && documentIds.length > 0
|
||||
const { mutateAsync: enableDocument } = useDocumentEnable()
|
||||
const handleEnableDocuments = useCallback(async () => {
|
||||
await enableDocument({ datasetId, documentIds })
|
||||
invalidDisabledDocument()
|
||||
Toast.notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
|
||||
}, [])
|
||||
if (!hasDisabledDocument || isLoading)
|
||||
return null
|
||||
|
||||
return (
|
||||
<StatusWithAction
|
||||
type='info'
|
||||
description={t('dataset.documentsDisabled', { num: documentIds?.length })}
|
||||
actionText={t('dataset.enable')}
|
||||
onAction={handleEnableDocuments}
|
||||
/>
|
||||
)
|
||||
}
|
||||
export default React.memo(AutoDisabledDocument)
|
@@ -0,0 +1,69 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useEffect, useReducer } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import useSWR from 'swr'
|
||||
import StatusWithAction from './status-with-action'
|
||||
import { getErrorDocs, retryErrorDocs } from '@/service/datasets'
|
||||
import type { IndexingStatusResponse } from '@/models/datasets'
|
||||
|
||||
type Props = {
|
||||
datasetId: string
|
||||
}
|
||||
type IIndexState = {
|
||||
value: string
|
||||
}
|
||||
type ActionType = 'retry' | 'success' | 'error'
|
||||
|
||||
type IAction = {
|
||||
type: ActionType
|
||||
}
|
||||
const indexStateReducer = (state: IIndexState, action: IAction) => {
|
||||
const actionMap = {
|
||||
retry: 'retry',
|
||||
success: 'success',
|
||||
error: 'error',
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
value: actionMap[action.type] || state.value,
|
||||
}
|
||||
}
|
||||
|
||||
const RetryButton: FC<Props> = ({ datasetId }) => {
|
||||
const { t } = useTranslation()
|
||||
const [indexState, dispatch] = useReducer(indexStateReducer, { value: 'success' })
|
||||
const { data: errorDocs, isLoading } = useSWR({ datasetId }, getErrorDocs)
|
||||
|
||||
const onRetryErrorDocs = async () => {
|
||||
dispatch({ type: 'retry' })
|
||||
const document_ids = errorDocs?.data.map((doc: IndexingStatusResponse) => doc.id) || []
|
||||
const res = await retryErrorDocs({ datasetId, document_ids })
|
||||
if (res.result === 'success')
|
||||
dispatch({ type: 'success' })
|
||||
else
|
||||
dispatch({ type: 'error' })
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (errorDocs?.total === 0)
|
||||
dispatch({ type: 'success' })
|
||||
else
|
||||
dispatch({ type: 'error' })
|
||||
}, [errorDocs?.total])
|
||||
|
||||
if (isLoading || indexState.value === 'success')
|
||||
return null
|
||||
|
||||
return (
|
||||
<StatusWithAction
|
||||
type='warning'
|
||||
description={`${errorDocs?.total} ${t('dataset.docsFailedNotice')}`}
|
||||
actionText={t('dataset.retry')}
|
||||
disabled={indexState.value === 'retry'}
|
||||
onAction={indexState.value === 'error' ? onRetryErrorDocs : () => { }}
|
||||
/>
|
||||
)
|
||||
}
|
||||
export default RetryButton
|
@@ -0,0 +1,65 @@
|
||||
'use client'
|
||||
import { RiAlertFill, RiCheckboxCircleFill, RiErrorWarningFill, RiInformation2Fill } from '@remixicon/react'
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import cn from '@/utils/classnames'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
|
||||
type Status = 'success' | 'error' | 'warning' | 'info'
|
||||
type Props = {
|
||||
type?: Status
|
||||
description: string
|
||||
actionText: string
|
||||
onAction: () => void
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
const IconMap = {
|
||||
success: {
|
||||
Icon: RiCheckboxCircleFill,
|
||||
color: 'text-text-success',
|
||||
},
|
||||
error: {
|
||||
Icon: RiErrorWarningFill,
|
||||
color: 'text-text-destructive',
|
||||
},
|
||||
warning: {
|
||||
Icon: RiAlertFill,
|
||||
color: 'text-text-warning-secondary',
|
||||
},
|
||||
info: {
|
||||
Icon: RiInformation2Fill,
|
||||
color: 'text-text-accent',
|
||||
},
|
||||
}
|
||||
|
||||
const getIcon = (type: Status) => {
|
||||
return IconMap[type]
|
||||
}
|
||||
|
||||
const StatusAction: FC<Props> = ({
|
||||
type = 'info',
|
||||
description,
|
||||
actionText,
|
||||
onAction,
|
||||
disabled,
|
||||
}) => {
|
||||
const { Icon, color } = getIcon(type)
|
||||
return (
|
||||
<div className='relative flex items-center h-[34px] rounded-lg pl-2 pr-3 border border-components-panel-border bg-components-panel-bg-blur shadow-xs'>
|
||||
<div className={`absolute inset-0 opacity-40 rounded-lg ${(type === 'success' && 'bg-[linear-gradient(92deg,rgba(23,178,106,0.25)_0%,rgba(255,255,255,0.00)_100%)]')
|
||||
|| (type === 'warning' && 'bg-[linear-gradient(92deg,rgba(247,144,9,0.25)_0%,rgba(255,255,255,0.00)_100%)]')
|
||||
|| (type === 'error' && 'bg-[linear-gradient(92deg,rgba(240,68,56,0.25)_0%,rgba(255,255,255,0.00)_100%)]')
|
||||
|| (type === 'info' && 'bg-[linear-gradient(92deg,rgba(11,165,236,0.25)_0%,rgba(255,255,255,0.00)_100%)]')
|
||||
}`}
|
||||
/>
|
||||
<div className='relative z-10 flex h-full items-center space-x-2'>
|
||||
<Icon className={cn('w-4 h-4', color)} />
|
||||
<div className='text-[13px] font-normal text-text-secondary'>{description}</div>
|
||||
<Divider type='vertical' className='!h-4' />
|
||||
<div onClick={onAction} className={cn('text-text-accent font-semibold text-[13px] cursor-pointer', disabled && 'text-text-disabled cursor-not-allowed')}>{actionText}</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default React.memo(StatusAction)
|
Reference in New Issue
Block a user