feat: add translation for chunks and new icons; update checkbox styles; add new segment list and segment card
parent
11679dc68a
commit
388d7918f3
@ -0,0 +1,5 @@
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="check">
|
||||
<path id="Vector 1" d="M2.5 6H9.5" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 217 B |
@ -0,0 +1,13 @@
|
||||
<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="Group">
|
||||
<path id="Vector" d="M2.5 10H0V7.5H2.5V10Z" fill="#676F83"/>
|
||||
<path id="Vector_2" d="M6.25 6.25H3.75V3.75H6.25V6.25Z" fill="#676F83"/>
|
||||
<path id="Vector_3" d="M2.5 6.25H0V3.75H2.5V6.25Z" fill="#676F83"/>
|
||||
<path id="Vector_4" d="M6.25 2.5H3.75V0H6.25V2.5Z" fill="#676F83"/>
|
||||
<path id="Vector_5" d="M2.5 2.5H0V0H2.5V2.5Z" fill="#676F83"/>
|
||||
<path id="Vector_6" d="M10 2.5H7.5V0H10V2.5Z" fill="#676F83"/>
|
||||
<path id="Vector_7" d="M9.58342 7.91663H7.91675V9.58329H9.58342V7.91663Z" fill="#676F83"/>
|
||||
<path id="Vector_8" d="M9.58342 4.16663H7.91675V5.83329H9.58342V4.16663Z" fill="#676F83"/>
|
||||
<path id="Vector_9" d="M5.83341 7.91663H4.16675V9.58329H5.83341V7.91663Z" fill="#676F83"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 792 B |
@ -0,0 +1,9 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="Icon L">
|
||||
<g id="Vector">
|
||||
<path d="M2.66602 11.3333H0.666016L3.33268 8.66667L5.99935 11.3333H3.99935L3.99935 14H2.66602L2.66602 11.3333Z" fill="#354052"/>
|
||||
<path d="M2.66602 4.66667L2.66602 2L3.99935 2L3.99935 4.66667L5.99935 4.66667L3.33268 7.33333L0.666016 4.66667L2.66602 4.66667Z" fill="#354052"/>
|
||||
<path d="M7.33268 2.66667H13.9993V4H7.33268V2.66667ZM7.33268 12H13.9993V13.3333H7.33268V12ZM5.99935 7.33333H13.9993V8.66667H5.99935V7.33333Z" fill="#354052"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 579 B |
@ -0,0 +1,116 @@
|
||||
{
|
||||
"icon": {
|
||||
"type": "element",
|
||||
"isRootNode": true,
|
||||
"name": "svg",
|
||||
"attributes": {
|
||||
"width": "10",
|
||||
"height": "10",
|
||||
"viewBox": "0 0 10 10",
|
||||
"fill": "none",
|
||||
"xmlns": "http://www.w3.org/2000/svg"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "g",
|
||||
"attributes": {
|
||||
"id": "Group"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Vector",
|
||||
"d": "M2.5 10H0V7.5H2.5V10Z",
|
||||
"fill": "#676F83"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Vector_2",
|
||||
"d": "M6.25 6.25H3.75V3.75H6.25V6.25Z",
|
||||
"fill": "#676F83"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Vector_3",
|
||||
"d": "M2.5 6.25H0V3.75H2.5V6.25Z",
|
||||
"fill": "#676F83"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Vector_4",
|
||||
"d": "M6.25 2.5H3.75V0H6.25V2.5Z",
|
||||
"fill": "#676F83"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Vector_5",
|
||||
"d": "M2.5 2.5H0V0H2.5V2.5Z",
|
||||
"fill": "#676F83"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Vector_6",
|
||||
"d": "M10 2.5H7.5V0H10V2.5Z",
|
||||
"fill": "#676F83"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Vector_7",
|
||||
"d": "M9.58342 7.91663H7.91675V9.58329H9.58342V7.91663Z",
|
||||
"fill": "#676F83"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Vector_8",
|
||||
"d": "M9.58342 4.16663H7.91675V5.83329H9.58342V4.16663Z",
|
||||
"fill": "#676F83"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Vector_9",
|
||||
"d": "M5.83341 7.91663H4.16675V9.58329H5.83341V7.91663Z",
|
||||
"fill": "#676F83"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "Chunk"
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
// GENERATE BY script
|
||||
// DON NOT EDIT IT MANUALLY
|
||||
|
||||
import * as React from 'react'
|
||||
import data from './Chunk.json'
|
||||
import IconBase from '@/app/components/base/icons/IconBase'
|
||||
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
|
||||
|
||||
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
|
||||
props,
|
||||
ref,
|
||||
) => <IconBase {...props} ref={ref} data={data as IconData} />)
|
||||
|
||||
Icon.displayName = 'Chunk'
|
||||
|
||||
export default Icon
|
||||
@ -0,0 +1,62 @@
|
||||
{
|
||||
"icon": {
|
||||
"type": "element",
|
||||
"isRootNode": true,
|
||||
"name": "svg",
|
||||
"attributes": {
|
||||
"width": "16",
|
||||
"height": "16",
|
||||
"viewBox": "0 0 16 16",
|
||||
"fill": "none",
|
||||
"xmlns": "http://www.w3.org/2000/svg"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "g",
|
||||
"attributes": {
|
||||
"id": "Icon L"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "g",
|
||||
"attributes": {
|
||||
"id": "Vector"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"d": "M2.66602 11.3333H0.666016L3.33268 8.66667L5.99935 11.3333H3.99935L3.99935 14H2.66602L2.66602 11.3333Z",
|
||||
"fill": "#354052"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"d": "M2.66602 4.66667L2.66602 2L3.99935 2L3.99935 4.66667L5.99935 4.66667L3.33268 7.33333L0.666016 4.66667L2.66602 4.66667Z",
|
||||
"fill": "#354052"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"d": "M7.33268 2.66667H13.9993V4H7.33268V2.66667ZM7.33268 12H13.9993V13.3333H7.33268V12ZM5.99935 7.33333H13.9993V8.66667H5.99935V7.33333Z",
|
||||
"fill": "#354052"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "Collapse"
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
// GENERATE BY script
|
||||
// DON NOT EDIT IT MANUALLY
|
||||
|
||||
import * as React from 'react'
|
||||
import data from './Collapse.json'
|
||||
import IconBase from '@/app/components/base/icons/IconBase'
|
||||
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
|
||||
|
||||
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
|
||||
props,
|
||||
ref,
|
||||
) => <IconBase {...props} ref={ref} data={data as IconData} />)
|
||||
|
||||
Icon.displayName = 'Collapse'
|
||||
|
||||
export default Icon
|
||||
@ -1,2 +1,4 @@
|
||||
export { default as Chunk } from './Chunk'
|
||||
export { default as Collapse } from './Collapse'
|
||||
export { default as GeneralType } from './GeneralType'
|
||||
export { default as ParentChildType } from './ParentChildType'
|
||||
|
||||
@ -0,0 +1,57 @@
|
||||
import React, { type FC } from 'react'
|
||||
import { RiCheckboxCircleLine, RiCloseCircleLine, RiDeleteBinLine } from '@remixicon/react'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
|
||||
type IBatchActionProps = {
|
||||
selectedSegmentIds: string[]
|
||||
onBatchEnable: () => Promise<void>
|
||||
onBatchDisable: () => Promise<void>
|
||||
onBatchDelete: () => Promise<void>
|
||||
onCancel: () => void
|
||||
}
|
||||
|
||||
const BatchAction: FC<IBatchActionProps> = ({
|
||||
selectedSegmentIds,
|
||||
onBatchEnable,
|
||||
onBatchDisable,
|
||||
onBatchDelete,
|
||||
onCancel,
|
||||
}) => {
|
||||
return (
|
||||
<div className='w-full flex justify-center gap-x-2 absolute bottom-16 z-20'>
|
||||
<div className='flex items-center gap-x-1 p-1 rounded-[10px] bg-components-actionbar-bg-accent border border-components-actionbar-border-accent shadow-xl shadow-shadow-shadow-5 backdrop-blur-[5px]'>
|
||||
<div className='inline-flex items-center gap-x-2 pl-2 pr-3 py-1'>
|
||||
<span className='w-5 h-5 flex items-center justify-center px-1 py-0.5 bg-text-accent rounded-md text-text-primary-on-surface text-xs font-medium'>
|
||||
{selectedSegmentIds.length}
|
||||
</span>
|
||||
<span className='text-text-accent text-[13px] font-semibold leading-[16px]'>Selected</span>
|
||||
</div>
|
||||
<Divider type='vertical' className='mx-0.5 h-3.5 bg-divider-regular' />
|
||||
<div className='flex items-center gap-x-0.5 px-3 py-2'>
|
||||
<RiCheckboxCircleLine className='w-4 h-4 text-components-button-ghost-text' />
|
||||
<button className='px-0.5 text-components-button-ghost-text text-[13px] font-medium leading-[16px]' onClick={onBatchEnable}>
|
||||
Enable
|
||||
</button>
|
||||
</div>
|
||||
<div className='flex items-center gap-x-0.5 px-3 py-2'>
|
||||
<RiCloseCircleLine className='w-4 h-4 text-components-button-ghost-text' />
|
||||
<button className='px-0.5 text-components-button-ghost-text text-[13px] font-medium leading-[16px]' onClick={onBatchDisable}>
|
||||
Disable
|
||||
</button>
|
||||
</div>
|
||||
<div className='flex items-center gap-x-0.5 px-3 py-2'>
|
||||
<RiDeleteBinLine className='w-4 h-4 text-components-button-destructive-ghost-text' />
|
||||
<button className='px-0.5 text-components-button-destructive-ghost-text text-[13px] font-medium leading-[16px]' onClick={onBatchDelete}>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
<Divider type='vertical' className='mx-0.5 h-3.5 bg-divider-regular' />
|
||||
<button className='px-3.5 py-2 text-components-button-ghost-text text-[13px] font-medium leading-[16px]' onClick={onCancel}>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(BatchAction)
|
||||
@ -0,0 +1,31 @@
|
||||
import React, { type FC } from 'react'
|
||||
import { RiLineHeight } from '@remixicon/react'
|
||||
import { useSegmentListContext } from '.'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { Collapse } from '@/app/components/base/icons/src/public/knowledge'
|
||||
|
||||
const DisplayToggle: FC = () => {
|
||||
const [isCollapsed, toggleCollapsed] = useSegmentListContext(s => [s.isCollapsed, s.toggleCollapsed])
|
||||
return (
|
||||
<Tooltip
|
||||
popupContent={isCollapsed ? 'Expand chunks' : 'Collapse chunks'}
|
||||
popupClassName='text-text-secondary system-xs-medium border-[0.5px] border-components-panel-border'
|
||||
needsDelay
|
||||
>
|
||||
<button
|
||||
className='flex items-center justify-center p-2 rounded-lg bg-components-button-secondary-bg cursor-pointer
|
||||
border-[0.5px] border-components-button-secondary-border shadow-xs shadow-shadow-shadow-3 backdrop-blur-[5px]'
|
||||
onClick={toggleCollapsed}
|
||||
>
|
||||
{
|
||||
isCollapsed
|
||||
? <RiLineHeight className='w-4 h-4 text-components-button-secondary-text' />
|
||||
: <Collapse className='w-4 h-4 text-components-button-secondary-text' />
|
||||
}
|
||||
</button>
|
||||
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(DisplayToggle)
|
||||
@ -0,0 +1,282 @@
|
||||
import React, { type FC, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiArrowRightUpLine, RiDeleteBinLine, RiEditLine } from '@remixicon/react'
|
||||
import { StatusItem } from '../../list'
|
||||
import DocumentFileIcon from '../../../common/document-file-icon'
|
||||
import { SegmentIndexTag, useSegmentListContext } from '.'
|
||||
import type { SegmentDetailModel } from '@/models/datasets'
|
||||
import Indicator from '@/app/components/header/indicator'
|
||||
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'
|
||||
|
||||
const Dot = React.memo(() => {
|
||||
return (
|
||||
<div className='text-text-quaternary text-xs font-medium'>·</div>
|
||||
)
|
||||
})
|
||||
|
||||
Dot.displayName = 'Dot'
|
||||
|
||||
const ProgressBar: FC<{ percent: number; loading: boolean }> = React.memo(({ percent, loading }) => {
|
||||
return (
|
||||
<div className=''>
|
||||
<div className=''>
|
||||
<div
|
||||
className=''
|
||||
style={{ width: `${loading ? 0 : (Math.min(percent, 1) * 100).toFixed(2)}%` }}
|
||||
/>
|
||||
</div>
|
||||
<div className=''>{loading ? null : percent.toFixed(2)}</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
ProgressBar.displayName = 'ProgressBar'
|
||||
|
||||
type DocumentTitleProps = {
|
||||
name: string
|
||||
extension?: string
|
||||
}
|
||||
|
||||
const DocumentTitle: FC<DocumentTitleProps> = React.memo(({ extension, name }) => {
|
||||
return (
|
||||
<div className=''>
|
||||
<DocumentFileIcon name={name} extension={extension} size={'sm'} />
|
||||
<span className=''>{name || '--'}</span>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
DocumentTitle.displayName = 'DocumentTitle'
|
||||
|
||||
const Tag = React.memo(({ text }: { text: string }) => {
|
||||
return (
|
||||
<div className='inline-flex items-center gap-x-0.5'>
|
||||
<span className='text-text-quaternary text-xs font-medium'>#</span>
|
||||
<span className='text-text-tertiary text-xs'>{text}</span>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
Tag.displayName = 'Tag'
|
||||
|
||||
export type UsageScene = 'doc' | 'hitTesting'
|
||||
|
||||
type ISegmentCardProps = {
|
||||
loading: boolean
|
||||
detail?: SegmentDetailModel & { document?: { name: string } }
|
||||
contentExternal?: string
|
||||
refSource?: {
|
||||
title: string
|
||||
uri: string
|
||||
}
|
||||
isExternal?: boolean
|
||||
score?: number
|
||||
onClick?: () => void
|
||||
onChangeSwitch?: (enabled: boolean, segId?: string) => Promise<void>
|
||||
onDelete?: (segId: string) => Promise<void>
|
||||
onClickEdit?: () => void
|
||||
scene?: UsageScene
|
||||
className?: string
|
||||
archived?: boolean
|
||||
embeddingAvailable?: boolean
|
||||
}
|
||||
|
||||
const SegmentCard: FC<ISegmentCardProps> = ({
|
||||
detail = {},
|
||||
contentExternal,
|
||||
isExternal,
|
||||
refSource,
|
||||
score,
|
||||
onClick,
|
||||
onChangeSwitch,
|
||||
onDelete,
|
||||
onClickEdit,
|
||||
loading = true,
|
||||
scene = 'doc',
|
||||
className = '',
|
||||
archived,
|
||||
embeddingAvailable,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const {
|
||||
id,
|
||||
position,
|
||||
enabled,
|
||||
content,
|
||||
word_count,
|
||||
hit_count,
|
||||
answer,
|
||||
keywords,
|
||||
} = detail as Required<ISegmentCardProps>['detail']
|
||||
const [showModal, setShowModal] = useState(false)
|
||||
|
||||
const isDocScene = useMemo(() => {
|
||||
return scene === 'doc'
|
||||
}, [scene])
|
||||
|
||||
// todo: change to real logic
|
||||
const chunkEdited = useMemo(() => {
|
||||
return true
|
||||
}, [])
|
||||
|
||||
const textOpacity = useMemo(() => {
|
||||
return enabled ? '' : 'opacity-50'
|
||||
}, [enabled])
|
||||
|
||||
const renderContent = () => {
|
||||
if (answer) {
|
||||
return (
|
||||
<>
|
||||
<div className='flex'>
|
||||
<div className='w-4 mr-2 text-[13px] font-medium leading-[20px] text-text-tertiary'>Q</div>
|
||||
<div className='text-text-secondary body-md-regular'>{content}</div>
|
||||
</div>
|
||||
<div className='flex'>
|
||||
<div className='w-4 mr-2 text-[13px] font-medium leading-[20px] text-text-tertiary'>A</div>
|
||||
<div className='text-text-secondary body-md-regular'>{answer}</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
if (contentExternal)
|
||||
return contentExternal
|
||||
|
||||
return content
|
||||
}
|
||||
const isCollapsed = useSegmentListContext(s => s.isCollapsed)
|
||||
|
||||
return (
|
||||
<div className={cn('p-3 pb-2.5 hover:bg-dataset-chunk-detail-card-hover-bg rounded-xl group/card', className)} onClick={() => onClick?.()}>
|
||||
<div className='relative flex items-center justify-between'>
|
||||
{isDocScene
|
||||
? <>
|
||||
<div className='flex items-center gap-x-2'>
|
||||
<SegmentIndexTag positionId={position} className={textOpacity} />
|
||||
<Dot />
|
||||
<div className={cn('text-text-tertiary system-xs-medium', textOpacity)}>{`${formatNumber(word_count)} Characters`}</div>
|
||||
<Dot />
|
||||
<div className={cn('text-text-tertiary system-xs-medium', textOpacity)}>{`${formatNumber(hit_count)} Retrieval Count`}</div>
|
||||
<Dot />
|
||||
{chunkEdited && (
|
||||
<Badge text='edited' uppercase className={textOpacity} />
|
||||
)}
|
||||
</div>
|
||||
<div className=''>
|
||||
{loading
|
||||
? (
|
||||
<Indicator color="gray" />
|
||||
)
|
||||
: (
|
||||
<>
|
||||
<StatusItem status={enabled ? 'enabled' : 'disabled'} reverse textCls="text-text-tertiary system-xs-regular" />
|
||||
{embeddingAvailable && (
|
||||
<div className="absolute -top-2.5 -right-2.5 z-20 hidden group-hover/card:flex items-center gap-x-0.5 p-1
|
||||
rounded-[10px] border-[0.5px] border-components-actionbar-border bg-components-actionbar-bg shadow-md backdrop-blur-[5px]">
|
||||
{!archived && (
|
||||
<>
|
||||
<div
|
||||
className='shrink-0 w-6 h-6 flex items-center justify-center rounded-lg hover:bg-state-base-hover cursor-pointer'
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
onClickEdit?.()
|
||||
}}>
|
||||
<RiEditLine className='w-4 h-4 text-text-tertiary' />
|
||||
</div>
|
||||
<div className='shrink-0 w-6 h-6 flex items-center justify-center rounded-lg hover:bg-state-destructive-hover cursor-pointer group/delete'
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
setShowModal(true)
|
||||
}
|
||||
}>
|
||||
<RiDeleteBinLine className='w-4 h-4 text-text-tertiary group-hover/delete:text-text-destructive' />
|
||||
</div>
|
||||
<Divider type="vertical" className="h-3.5 bg-divider-regular" />
|
||||
</>
|
||||
)}
|
||||
<div
|
||||
onClick={(e: React.MouseEvent<HTMLDivElement, MouseEvent>) =>
|
||||
e.stopPropagation()
|
||||
}
|
||||
className="flex items-center"
|
||||
>
|
||||
<Switch
|
||||
size='md'
|
||||
disabled={archived || detail.status !== 'completed'}
|
||||
defaultValue={enabled}
|
||||
onChange={async (val) => {
|
||||
await onChangeSwitch?.(val, id)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
: (
|
||||
score !== null
|
||||
? (
|
||||
<div className=''>
|
||||
<div className='' />
|
||||
<ProgressBar percent={score ?? 0} loading={loading} />
|
||||
</div>
|
||||
)
|
||||
: null
|
||||
)}
|
||||
</div>
|
||||
{loading
|
||||
? (
|
||||
<div className=''>
|
||||
<div className='' />
|
||||
</div>
|
||||
)
|
||||
: (
|
||||
isDocScene
|
||||
? <>
|
||||
<div className={cn('text-text-secondary body-md-regular -tracking-[0.07px] mt-1', textOpacity, isCollapsed ? 'line-clamp-2' : 'line-clamp-20')}>
|
||||
{renderContent()}
|
||||
</div>
|
||||
<div className={cn('flex items-center gap-x-2 pt-1.5', textOpacity)}>
|
||||
{keywords?.map(keyword => <Tag key={keyword} text={keyword} />)}
|
||||
</div>
|
||||
</>
|
||||
: <>
|
||||
<div className='text-text-secondary body-md-regular -tracking-[0.07px]'>
|
||||
{renderContent()}
|
||||
</div>
|
||||
<div className=''>
|
||||
<Divider />
|
||||
<div className="relative flex items-center w-full pb-1">
|
||||
<DocumentTitle
|
||||
name={detail?.document?.name || refSource?.title || ''}
|
||||
extension={(detail?.document?.name || refSource?.title || '').split('.').pop() || 'txt'}
|
||||
/>
|
||||
<div className=''>
|
||||
{isExternal ? t('datasetHitTesting.viewDetail') : t('datasetHitTesting.viewChart')}
|
||||
<RiArrowRightUpLine className="w-3.5 h-3.5 ml-1" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{showModal
|
||||
&& <Confirm
|
||||
isShow={showModal}
|
||||
title={t('datasetDocuments.segment.delete')}
|
||||
confirmText={t('common.operation.sure')}
|
||||
onConfirm={async () => { await onDelete?.(id) }}
|
||||
onCancel={() => setShowModal(false)}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(SegmentCard)
|
||||
@ -0,0 +1,71 @@
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import SegmentCard from './segment-card'
|
||||
import type { SegmentDetailModel } from '@/models/datasets'
|
||||
import Checkbox from '@/app/components/base/checkbox'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
|
||||
type ISegmentListProps = {
|
||||
isLoading: boolean
|
||||
items: SegmentDetailModel[]
|
||||
selectedSegmentIds: string[]
|
||||
onSelected: (segId: string) => void
|
||||
onClick: (detail: SegmentDetailModel, isEditing?: boolean) => void
|
||||
onChangeSwitch: (enabled: boolean, segId?: string,) => Promise<void>
|
||||
onDelete: (segId: string) => Promise<void>
|
||||
archived?: boolean
|
||||
embeddingAvailable: boolean
|
||||
}
|
||||
|
||||
const SegmentList: FC<ISegmentListProps> = ({
|
||||
isLoading,
|
||||
items,
|
||||
selectedSegmentIds,
|
||||
onSelected,
|
||||
onClick: onClickCard,
|
||||
onChangeSwitch,
|
||||
onDelete,
|
||||
archived,
|
||||
embeddingAvailable,
|
||||
}) => {
|
||||
if (isLoading)
|
||||
return <Loading type='app' />
|
||||
return (
|
||||
<div className='flex flex-col h-full overflow-y-auto'>
|
||||
{
|
||||
items.map((segItem) => {
|
||||
const isLast = items[items.length - 1].id === segItem.id
|
||||
return (
|
||||
<div key={segItem.id} className='flex items-start gap-x-2'>
|
||||
<Checkbox
|
||||
key={`${segItem.id}-checkbox`}
|
||||
className='shrink-0 mt-3.5'
|
||||
checked={selectedSegmentIds.includes(segItem.id)}
|
||||
onCheck={() => onSelected(segItem.id)}
|
||||
/>
|
||||
<div className='flex flex-col'>
|
||||
<SegmentCard
|
||||
key={`${segItem.id}-card`}
|
||||
detail={segItem}
|
||||
onClick={() => onClickCard(segItem)}
|
||||
onChangeSwitch={onChangeSwitch}
|
||||
onClickEdit={() => onClickCard(segItem, true)}
|
||||
onDelete={onDelete}
|
||||
loading={false}
|
||||
archived={archived}
|
||||
embeddingAvailable={embeddingAvailable}
|
||||
/>
|
||||
{!isLast && <div className='w-full px-3'>
|
||||
<Divider type='horizontal' className='bg-divider-subtle my-1' />
|
||||
</div>}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SegmentList
|
||||
Loading…
Reference in New Issue