You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.tsx 4.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import React, { useMemo } from 'react'
  2. import type { ColorMap, IndicatorProps } from '@/app/components/header/indicator'
  3. import Indicator from '@/app/components/header/indicator'
  4. import type { DocumentDisplayStatus } from '@/models/datasets'
  5. import { useContext } from 'use-context-selector'
  6. import { useIndexStatus } from './hooks'
  7. import { ToastContext } from '@/app/components/base/toast'
  8. import { useTranslation } from 'react-i18next'
  9. import { useDocumentDelete, useDocumentDisable, useDocumentEnable } from '@/service/knowledge/use-document'
  10. import type { CommonResponse } from '@/models/common'
  11. import { asyncRunSafe } from '@/utils'
  12. import { useDebounceFn } from 'ahooks'
  13. import s from '../style.module.css'
  14. import cn from '@/utils/classnames'
  15. import Tooltip from '@/app/components/base/tooltip'
  16. import Switch from '@/app/components/base/switch'
  17. import type { OperationName } from '../types'
  18. const STATUS_TEXT_COLOR_MAP: ColorMap = {
  19. green: 'text-util-colors-green-green-600',
  20. orange: 'text-util-colors-warning-warning-600',
  21. red: 'text-util-colors-red-red-600',
  22. blue: 'text-util-colors-blue-light-blue-light-600',
  23. yellow: 'text-util-colors-warning-warning-600',
  24. gray: 'text-text-tertiary',
  25. }
  26. type StatusItemProps = {
  27. status: DocumentDisplayStatus
  28. reverse?: boolean
  29. scene?: 'list' | 'detail'
  30. textCls?: string
  31. errorMessage?: string
  32. detail?: {
  33. enabled: boolean
  34. archived: boolean
  35. id: string
  36. }
  37. datasetId?: string
  38. onUpdate?: (operationName?: string) => void
  39. }
  40. const StatusItem = ({
  41. status,
  42. reverse = false,
  43. scene = 'list',
  44. textCls = '',
  45. errorMessage,
  46. datasetId = '',
  47. detail,
  48. onUpdate,
  49. }: StatusItemProps) => {
  50. const { t } = useTranslation()
  51. const { notify } = useContext(ToastContext)
  52. const DOC_INDEX_STATUS_MAP = useIndexStatus()
  53. const localStatus = status.toLowerCase() as keyof typeof DOC_INDEX_STATUS_MAP
  54. const { enabled = false, archived = false, id = '' } = detail || {}
  55. const { mutateAsync: enableDocument } = useDocumentEnable()
  56. const { mutateAsync: disableDocument } = useDocumentDisable()
  57. const { mutateAsync: deleteDocument } = useDocumentDelete()
  58. const onOperate = async (operationName: OperationName) => {
  59. let opApi = deleteDocument
  60. switch (operationName) {
  61. case 'enable':
  62. opApi = enableDocument
  63. break
  64. case 'disable':
  65. opApi = disableDocument
  66. break
  67. }
  68. const [e] = await asyncRunSafe<CommonResponse>(opApi({ datasetId, documentId: id }) as Promise<CommonResponse>)
  69. if (!e) {
  70. notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
  71. onUpdate?.(operationName)
  72. }
  73. else { notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') }) }
  74. }
  75. const { run: handleSwitch } = useDebounceFn((operationName: OperationName) => {
  76. if (operationName === 'enable' && enabled)
  77. return
  78. if (operationName === 'disable' && !enabled)
  79. return
  80. onOperate(operationName)
  81. }, { wait: 500 })
  82. const embedding = useMemo(() => {
  83. return ['queuing', 'indexing', 'paused'].includes(localStatus)
  84. }, [localStatus])
  85. return <div className={
  86. cn('flex items-center',
  87. reverse ? 'flex-row-reverse' : '',
  88. scene === 'detail' ? s.statusItemDetail : '')
  89. }>
  90. <Indicator color={DOC_INDEX_STATUS_MAP[localStatus]?.color as IndicatorProps['color']} className={reverse ? 'ml-2' : 'mr-2'} />
  91. <span className={cn(`${STATUS_TEXT_COLOR_MAP[DOC_INDEX_STATUS_MAP[localStatus].color as keyof typeof STATUS_TEXT_COLOR_MAP]} text-sm`, textCls)}>
  92. {DOC_INDEX_STATUS_MAP[localStatus]?.text}
  93. </span>
  94. {
  95. errorMessage && (
  96. <Tooltip
  97. popupContent={
  98. <div className='max-w-[260px] break-all'>{errorMessage}</div>
  99. }
  100. triggerClassName='ml-1 w-4 h-4'
  101. />
  102. )
  103. }
  104. {
  105. scene === 'detail' && (
  106. <div className='ml-1.5 flex items-center justify-between'>
  107. <Tooltip
  108. popupContent={t('datasetDocuments.list.action.enableWarning')}
  109. popupClassName='text-text-secondary system-xs-medium'
  110. disabled={!archived}
  111. >
  112. <Switch
  113. defaultValue={archived ? false : enabled}
  114. onChange={v => !archived && handleSwitch(v ? 'enable' : 'disable')}
  115. disabled={embedding || archived}
  116. size='md'
  117. />
  118. </Tooltip>
  119. </div>
  120. )
  121. }
  122. </div>
  123. }
  124. export default React.memo(StatusItem)