wwf
2025-05-20 938c3e5a587ce950a94964ea509b9e7f8834dfae
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import React, { useMemo } from 'react'
import { useDocumentContext } from '../index'
import SegmentCard from './segment-card'
import Empty from './common/empty'
import GeneralListSkeleton from './skeleton/general-list-skeleton'
import ParagraphListSkeleton from './skeleton/paragraph-list-skeleton'
import { useSegmentListContext } from './index'
import type { ChildChunkDetail, SegmentDetailModel } from '@/models/datasets'
import Checkbox from '@/app/components/base/checkbox'
import Divider from '@/app/components/base/divider'
 
type ISegmentListProps = {
  isLoading: boolean
  items: SegmentDetailModel[]
  selectedSegmentIds: string[]
  onSelected: (segId: string) => void
  onClick: (detail: SegmentDetailModel, isEditMode?: boolean) => void
  onChangeSwitch: (enabled: boolean, segId?: string,) => Promise<void>
  onDelete: (segId: string) => Promise<void>
  onDeleteChildChunk: (sgId: string, childChunkId: string) => Promise<void>
  handleAddNewChildChunk: (parentChunkId: string) => void
  onClickSlice: (childChunk: ChildChunkDetail) => void
  archived?: boolean
  embeddingAvailable: boolean
  onClearFilter: () => void
}
 
const SegmentList = (
  {
    ref,
    isLoading,
    items,
    selectedSegmentIds,
    onSelected,
    onClick: onClickCard,
    onChangeSwitch,
    onDelete,
    onDeleteChildChunk,
    handleAddNewChildChunk,
    onClickSlice,
    archived,
    embeddingAvailable,
    onClearFilter,
  }: ISegmentListProps & {
    ref: React.LegacyRef<HTMLDivElement>
  },
) => {
  const mode = useDocumentContext(s => s.mode)
  const parentMode = useDocumentContext(s => s.parentMode)
  const currSegment = useSegmentListContext(s => s.currSegment)
  const currChildChunk = useSegmentListContext(s => s.currChildChunk)
 
  const Skeleton = useMemo(() => {
    return (mode === 'hierarchical' && parentMode === 'paragraph') ? ParagraphListSkeleton : GeneralListSkeleton
  }, [mode, parentMode])
 
  // Loading skeleton
  if (isLoading)
    return <Skeleton />
  // Search result is empty
  if (items.length === 0) {
    return (
      <div className='h-full pl-6'>
        <Empty onClearFilter={onClearFilter} />
      </div>
    )
  }
  return (
    <div ref={ref} className={'flex grow flex-col overflow-y-auto'}>
      {
        items.map((segItem) => {
          const isLast = items[items.length - 1].id === segItem.id
          const segmentIndexFocused
            = currSegment?.segInfo?.id === segItem.id
            || (!currSegment && currChildChunk?.childChunkInfo?.segment_id === segItem.id)
          const segmentContentFocused = currSegment?.segInfo?.id === segItem.id
            || currChildChunk?.childChunkInfo?.segment_id === segItem.id
          return (
            <div key={segItem.id} className='flex items-start gap-x-2'>
              <Checkbox
                key={`${segItem.id}-checkbox`}
                className='mt-3.5 shrink-0'
                checked={selectedSegmentIds.includes(segItem.id)}
                onCheck={() => onSelected(segItem.id)}
              />
              <div className='min-w-0 grow'>
                <SegmentCard
                  key={`${segItem.id}-card`}
                  detail={segItem}
                  onClick={() => onClickCard(segItem, true)}
                  onChangeSwitch={onChangeSwitch}
                  onClickEdit={() => onClickCard(segItem, true)}
                  onDelete={onDelete}
                  onDeleteChildChunk={onDeleteChildChunk}
                  handleAddNewChildChunk={handleAddNewChildChunk}
                  onClickSlice={onClickSlice}
                  loading={false}
                  archived={archived}
                  embeddingAvailable={embeddingAvailable}
                  focused={{
                    segmentIndex: segmentIndexFocused,
                    segmentContent: segmentContentFocused,
                  }}
                />
                {!isLast && <div className='w-full px-3'>
                  <Divider type='horizontal' className='my-1 bg-divider-subtle' />
                </div>}
              </div>
            </div>
          )
        })
      }
    </div>
  )
}
 
SegmentList.displayName = 'SegmentList'
 
export default SegmentList