import React, { type FC, useCallback, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import { RiDeleteBinLine, RiEditLine } from '@remixicon/react' import { StatusItem } from '../../../list' import { useDocumentContext } from '../../index' import ChildSegmentList from '../child-segment-list' import Tag from '../common/tag' import Dot from '../common/dot' import { SegmentIndexTag } from '../common/segment-index-tag' import ParentChunkCardSkeleton from '../skeleton/parent-chunk-card-skeleton' import type { ChildChunkDetail, SegmentDetailModel } from '@/models/datasets' import Switch from '@/app/components/base/switch' import Divider from '@/app/components/base/divider' import { formatNumber } from '@/utils/format' import Confirm from '@/app/components/base/confirm' import cn from '@/utils/classnames' import Badge from '@/app/components/base/badge' import { isAfter } from '@/utils/time' import Tooltip from '@/app/components/base/tooltip' import ChunkContent from './chunk-content' type ISegmentCardProps = { loading: boolean detail?: SegmentDetailModel & { document?: { name: string } } onClick?: () => void onChangeSwitch?: (enabled: boolean, segId?: string) => Promise onDelete?: (segId: string) => Promise onDeleteChildChunk?: (segId: string, childChunkId: string) => Promise handleAddNewChildChunk?: (parentChunkId: string) => void onClickSlice?: (childChunk: ChildChunkDetail) => void onClickEdit?: () => void className?: string archived?: boolean embeddingAvailable?: boolean focused: { segmentIndex: boolean segmentContent: boolean } } const SegmentCard: FC = ({ detail = {}, onClick, onChangeSwitch, onDelete, onDeleteChildChunk, handleAddNewChildChunk, onClickSlice, onClickEdit, loading = true, className = '', archived, embeddingAvailable, focused, }) => { const { t } = useTranslation() const { id, position, enabled, content, sign_content, word_count, hit_count, answer, keywords, child_chunks = [], created_at, updated_at, } = detail as Required['detail'] const [showModal, setShowModal] = useState(false) const mode = useDocumentContext(s => s.mode) const parentMode = useDocumentContext(s => s.parentMode) const isGeneralMode = useMemo(() => { return mode === 'custom' }, [mode]) const isParentChildMode = useMemo(() => { return mode === 'hierarchical' }, [mode]) const isParagraphMode = useMemo(() => { return mode === 'hierarchical' && parentMode === 'paragraph' }, [mode, parentMode]) const isFullDocMode = useMemo(() => { return mode === 'hierarchical' && parentMode === 'full-doc' }, [mode, parentMode]) const chunkEdited = useMemo(() => { if (mode === 'hierarchical' && parentMode === 'full-doc') return false return isAfter(updated_at * 1000, created_at * 1000) }, [mode, parentMode, updated_at, created_at]) const contentOpacity = useMemo(() => { return (enabled || focused.segmentContent) ? '' : 'opacity-50 group-hover/card:opacity-100' }, [enabled, focused.segmentContent]) const handleClickCard = useCallback(() => { if (mode !== 'hierarchical' || parentMode !== 'full-doc') onClick?.() }, [mode, parentMode, onClick]) const wordCountText = useMemo(() => { const total = formatNumber(word_count) return `${total} ${t('datasetDocuments.segment.characters', { count: word_count })}` }, [word_count, t]) const labelPrefix = useMemo(() => { return isParentChildMode ? t('datasetDocuments.segment.parentChunk') : t('datasetDocuments.segment.chunk') }, [isParentChildMode, t]) if (loading) return return (
<>
{wordCountText}
{`${formatNumber(hit_count)} ${t('datasetDocuments.segment.hitCount')}`}
{chunkEdited && ( <> )}
{!isFullDocMode ?
{embeddingAvailable && (
{!archived && ( <>
{ e.stopPropagation() onClickEdit?.() }}>
{ e.stopPropagation() setShowModal(true) } }>
)}
) => e.stopPropagation() } className="flex items-center" > { await onChangeSwitch?.(val, id) }} />
)}
: null}
{isGeneralMode &&
{keywords?.map(keyword => )}
} { isFullDocMode ? : null } { isParagraphMode && child_chunks.length > 0 && } {showModal && { await onDelete?.(id) }} onCancel={() => setShowModal(false)} /> }
) } export default React.memo(SegmentCard)