Commit 2b5bc9e0 authored by JzoNg's avatar JzoNg

feat: delete segment supported

parent 340d7495
...@@ -13,6 +13,7 @@ type IInfiniteVirtualListProps = { ...@@ -13,6 +13,7 @@ type IInfiniteVirtualListProps = {
loadNextPage: () => Promise<any> // Callback function responsible for loading the next page of items. loadNextPage: () => Promise<any> // Callback function responsible for loading the next page of items.
onClick: (detail: SegmentDetailModel) => void onClick: (detail: SegmentDetailModel) => void
onChangeSwitch: (segId: string, enabled: boolean) => Promise<void> onChangeSwitch: (segId: string, enabled: boolean) => Promise<void>
onDelete: (segId: string) => Promise<void>
} }
const InfiniteVirtualList: FC<IInfiniteVirtualListProps> = ({ const InfiniteVirtualList: FC<IInfiniteVirtualListProps> = ({
...@@ -22,6 +23,7 @@ const InfiniteVirtualList: FC<IInfiniteVirtualListProps> = ({ ...@@ -22,6 +23,7 @@ const InfiniteVirtualList: FC<IInfiniteVirtualListProps> = ({
loadNextPage, loadNextPage,
onClick: onClickCard, onClick: onClickCard,
onChangeSwitch, onChangeSwitch,
onDelete,
}) => { }) => {
// If there are more items to be loaded then add an extra row to hold a loading indicator. // If there are more items to be loaded then add an extra row to hold a loading indicator.
const itemCount = hasNextPage ? items.length + 1 : items.length const itemCount = hasNextPage ? items.length + 1 : items.length
...@@ -52,6 +54,7 @@ const InfiniteVirtualList: FC<IInfiniteVirtualListProps> = ({ ...@@ -52,6 +54,7 @@ const InfiniteVirtualList: FC<IInfiniteVirtualListProps> = ({
detail={segItem} detail={segItem}
onClick={() => onClickCard(segItem)} onClick={() => onClickCard(segItem)}
onChangeSwitch={onChangeSwitch} onChangeSwitch={onChangeSwitch}
onDelete={onDelete}
loading={false} loading={false}
/> />
)) ))
......
import type { FC } from 'react' import type { FC } from 'react'
import React from 'react' import React, { useState } from 'react'
import cn from 'classnames' import cn from 'classnames'
import { ArrowUpRightIcon } from '@heroicons/react/24/outline' import { ArrowUpRightIcon } from '@heroicons/react/24/outline'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
...@@ -7,11 +7,15 @@ import { StatusItem } from '../../list' ...@@ -7,11 +7,15 @@ import { StatusItem } from '../../list'
import { DocumentTitle } from '../index' import { DocumentTitle } from '../index'
import s from './style.module.css' import s from './style.module.css'
import { SegmentIndexTag } from './index' import { SegmentIndexTag } from './index'
import Modal from '@/app/components/base/modal'
import Button from '@/app/components/base/button'
import Switch from '@/app/components/base/switch' import Switch from '@/app/components/base/switch'
import Divider from '@/app/components/base/divider' import Divider from '@/app/components/base/divider'
import Indicator from '@/app/components/header/indicator' import Indicator from '@/app/components/header/indicator'
import { formatNumber } from '@/utils/format' import { formatNumber } from '@/utils/format'
import type { SegmentDetailModel } from '@/models/datasets' import type { SegmentDetailModel } from '@/models/datasets'
import { AlertCircle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
import { Trash03 } from '@/app/components/base/icons/src/vender/line/general'
const ProgressBar: FC<{ percent: number; loading: boolean }> = ({ percent, loading }) => { const ProgressBar: FC<{ percent: number; loading: boolean }> = ({ percent, loading }) => {
return ( return (
...@@ -35,6 +39,7 @@ type ISegmentCardProps = { ...@@ -35,6 +39,7 @@ type ISegmentCardProps = {
score?: number score?: number
onClick?: () => void onClick?: () => void
onChangeSwitch?: (segId: string, enabled: boolean) => Promise<void> onChangeSwitch?: (segId: string, enabled: boolean) => Promise<void>
onDelete?: (segId: string) => Promise<void>
scene?: UsageScene scene?: UsageScene
className?: string className?: string
} }
...@@ -44,6 +49,7 @@ const SegmentCard: FC<ISegmentCardProps> = ({ ...@@ -44,6 +49,7 @@ const SegmentCard: FC<ISegmentCardProps> = ({
score, score,
onClick, onClick,
onChangeSwitch, onChangeSwitch,
onDelete,
loading = true, loading = true,
scene = 'doc', scene = 'doc',
className = '', className = '',
...@@ -60,6 +66,7 @@ const SegmentCard: FC<ISegmentCardProps> = ({ ...@@ -60,6 +66,7 @@ const SegmentCard: FC<ISegmentCardProps> = ({
answer, answer,
} = detail as any } = detail as any
const isDocScene = scene === 'doc' const isDocScene = scene === 'doc'
const [showModal, setShowModal] = useState(false)
const renderContent = () => { const renderContent = () => {
if (answer) { if (answer) {
...@@ -86,7 +93,7 @@ const SegmentCard: FC<ISegmentCardProps> = ({ ...@@ -86,7 +93,7 @@ const SegmentCard: FC<ISegmentCardProps> = ({
s.segWrapper, s.segWrapper,
(isDocScene && !enabled) ? 'bg-gray-25' : '', (isDocScene && !enabled) ? 'bg-gray-25' : '',
'group', 'group',
!loading ? 'pb-4' : '', !loading ? 'pb-4 hover:pb-[10px]' : '',
className, className,
)} )}
onClick={() => onClick?.()} onClick={() => onClick?.()}
...@@ -159,10 +166,16 @@ const SegmentCard: FC<ISegmentCardProps> = ({ ...@@ -159,10 +166,16 @@ const SegmentCard: FC<ISegmentCardProps> = ({
<div className={cn(s.commonIcon, s.targetIcon)} /> <div className={cn(s.commonIcon, s.targetIcon)} />
<div className={s.segDataText}>{formatNumber(hit_count)}</div> <div className={s.segDataText}>{formatNumber(hit_count)}</div>
</div> </div>
<div className="flex items-center"> <div className="grow flex items-center">
<div className={cn(s.commonIcon, s.bezierCurveIcon)} /> <div className={cn(s.commonIcon, s.bezierCurveIcon)} />
<div className={s.segDataText}>{index_node_hash}</div> <div className={s.segDataText}>{index_node_hash}</div>
</div> </div>
<div className='shrink-0 w-6 h-6 flex items-center justify-center rounded-md hover:bg-red-100 hover:text-red-600 cursor-pointer group/delete' onClick={(e) => {
e.stopPropagation()
setShowModal(true)
}}>
<Trash03 className='w-[14px] h-[14px] text-gray-500 group-hover/delete:text-red-600' />
</div>
</div> </div>
</> </>
: <> : <>
...@@ -187,6 +200,26 @@ const SegmentCard: FC<ISegmentCardProps> = ({ ...@@ -187,6 +200,26 @@ const SegmentCard: FC<ISegmentCardProps> = ({
</div> </div>
</> </>
)} )}
{showModal && <Modal isShow={showModal} onClose={() => setShowModal(false)} className={s.delModal} closable>
<div>
<div className={s.warningWrapper}>
<AlertCircle className='w-6 h-6 text-red-600' />
</div>
<div className='text-xl font-semibold text-gray-900 mb-1'>{t('datasetDocuments.segment.delete')}</div>
<div className='flex gap-2 justify-end'>
<Button onClick={() => setShowModal(false)}>{t('common.operation.cancel')}</Button>
<Button
type='warning'
onClick={async () => {
await onDelete?.(id)
}}
className='border-red-700 border-[0.5px]'
>
{t('common.operation.sure')}
</Button>
</div>
</div>
</Modal>}
</div> </div>
) )
} }
......
...@@ -18,7 +18,7 @@ import Input from '@/app/components/base/input' ...@@ -18,7 +18,7 @@ import Input from '@/app/components/base/input'
import { ToastContext } from '@/app/components/base/toast' import { ToastContext } from '@/app/components/base/toast'
import type { Item } from '@/app/components/base/select' import type { Item } from '@/app/components/base/select'
import { SimpleSelect } from '@/app/components/base/select' import { SimpleSelect } from '@/app/components/base/select'
import { disableSegment, enableSegment, fetchSegments, updateSegment } from '@/service/datasets' import { deleteSegment, disableSegment, enableSegment, fetchSegments, updateSegment } from '@/service/datasets'
import type { SegmentDetailModel, SegmentUpdator, SegmentsQuery, SegmentsResponse } from '@/models/datasets' import type { SegmentDetailModel, SegmentUpdator, SegmentsQuery, SegmentsResponse } from '@/models/datasets'
import { asyncRunSafe } from '@/utils' import { asyncRunSafe } from '@/utils'
import type { CommonResponse } from '@/models/common' import type { CommonResponse } from '@/models/common'
...@@ -272,6 +272,17 @@ const Completed: FC<ICompletedProps> = ({ showNewSegmentModal, onNewSegmentModal ...@@ -272,6 +272,17 @@ const Completed: FC<ICompletedProps> = ({ showNewSegmentModal, onNewSegmentModal
} }
} }
const onDelete = async (segId: string) => {
const [e] = await asyncRunSafe<CommonResponse>(deleteSegment({ datasetId, documentId, segmentId: segId }) as Promise<CommonResponse>)
if (!e) {
notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
resetList()
}
else {
notify({ type: 'error', message: t('common.actionMsg.modificationFailed') })
}
}
const handleUpdateSegment = async (segmentId: string, question: string, answer: string) => { const handleUpdateSegment = async (segmentId: string, question: string, answer: string) => {
const params: SegmentUpdator = { content: '' } const params: SegmentUpdator = { content: '' }
if (docForm === 'qa_model') { if (docForm === 'qa_model') {
...@@ -330,6 +341,7 @@ const Completed: FC<ICompletedProps> = ({ showNewSegmentModal, onNewSegmentModal ...@@ -330,6 +341,7 @@ const Completed: FC<ICompletedProps> = ({ showNewSegmentModal, onNewSegmentModal
items={allSegments} items={allSegments}
loadNextPage={getSegments} loadNextPage={getSegments}
onChangeSwitch={onChangeSwitch} onChangeSwitch={onChangeSwitch}
onDelete={onDelete}
onClick={onClickCard} onClick={onClickCard}
/> />
<Modal isShow={currSegment.showModal} onClose={() => {}} className='!max-w-[640px] !overflow-visible'> <Modal isShow={currSegment.showModal} onClose={() => {}} className='!max-w-[640px] !overflow-visible'>
......
...@@ -132,3 +132,24 @@ ...@@ -132,3 +132,24 @@
.editTip { .editTip {
box-shadow: 0px 4px 6px -2px rgba(16, 24, 40, 0.03), 0px 12px 16px -4px rgba(16, 24, 40, 0.08); box-shadow: 0px 4px 6px -2px rgba(16, 24, 40, 0.03), 0px 12px 16px -4px rgba(16, 24, 40, 0.08);
} }
.delModal {
background: linear-gradient(
180deg,
rgba(217, 45, 32, 0.05) 0%,
rgba(217, 45, 32, 0) 24.02%
),
#f9fafb;
box-shadow: 0px 20px 24px -4px rgba(16, 24, 40, 0.08),
0px 8px 8px -4px rgba(16, 24, 40, 0.03);
@apply rounded-2xl p-8;
}
.warningWrapper {
box-shadow: 0px 20px 24px -4px rgba(16, 24, 40, 0.08),
0px 8px 8px -4px rgba(16, 24, 40, 0.03);
background: rgba(255, 255, 255, 0.9);
@apply h-12 w-12 border-[0.5px] border-gray-100 rounded-xl mb-3 flex items-center justify-center;
}
.warningIcon {
@apply w-[22px] h-[22px] fill-current text-red-600;
}
...@@ -320,6 +320,7 @@ const translation = { ...@@ -320,6 +320,7 @@ const translation = {
contentEmpty: 'Content can not be empty', contentEmpty: 'Content can not be empty',
newTextSegment: 'New Text Segment', newTextSegment: 'New Text Segment',
newQaSegment: 'New Q&A Segment', newQaSegment: 'New Q&A Segment',
delete: 'Delete this segment ?',
}, },
} }
......
...@@ -319,6 +319,7 @@ const translation = { ...@@ -319,6 +319,7 @@ const translation = {
contentEmpty: '内容不能为空', contentEmpty: '内容不能为空',
newTextSegment: '新文本分段', newTextSegment: '新文本分段',
newQaSegment: '新问答分段', newQaSegment: '新问答分段',
delete: '删除这个分段?',
}, },
} }
......
...@@ -168,6 +168,10 @@ export const addSegment: Fetcher<{ data: SegmentDetailModel; doc_form: string }, ...@@ -168,6 +168,10 @@ export const addSegment: Fetcher<{ data: SegmentDetailModel; doc_form: string },
return post(`/datasets/${datasetId}/documents/${documentId}/segment`, { body }) as Promise<{ data: SegmentDetailModel; doc_form: string }> return post(`/datasets/${datasetId}/documents/${documentId}/segment`, { body }) as Promise<{ data: SegmentDetailModel; doc_form: string }>
} }
export const deleteSegment: Fetcher<CommonResponse, { datasetId: string; documentId: string; segmentId: string }> = ({ datasetId, documentId, segmentId }) => {
return del(`/datasets/${datasetId}/documents/${documentId}/segments/${segmentId}`) as Promise<CommonResponse>
}
// hit testing // hit testing
export const hitTesting: Fetcher<HitTestingResponse, { datasetId: string; queryText: string }> = ({ datasetId, queryText }) => { export const hitTesting: Fetcher<HitTestingResponse, { datasetId: string; queryText: string }> = ({ datasetId, queryText }) => {
return post(`/datasets/${datasetId}/hit-testing`, { body: { query: queryText } }) as Promise<HitTestingResponse> return post(`/datasets/${datasetId}/hit-testing`, { body: { query: queryText } }) as Promise<HitTestingResponse>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment