feat: implement create dataset pipeline forms and modals
parent
cfb6d59513
commit
de0cb06f8c
@ -0,0 +1,75 @@
|
||||
import React, { useCallback, useEffect, useState } from 'react'
|
||||
import type { CreateDatasetReq } from '@/models/datasets'
|
||||
import { ChunkingMode, DatasetPermission } from '@/models/datasets'
|
||||
import { useMembers } from '@/service/use-common'
|
||||
import { useCreatePipelineDataset } from '@/service/knowledge/use-create-dataset'
|
||||
import type { Member } from '@/models/common'
|
||||
import CreateForm from '../create-form'
|
||||
import type { CreateFormData } from '@/models/pipeline'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
|
||||
type CreateFromScratchModalProps = {
|
||||
show: boolean
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
const CreateFromScratchModal = ({
|
||||
show,
|
||||
onClose,
|
||||
}: CreateFromScratchModalProps) => {
|
||||
const [memberList, setMemberList] = useState<Member[]>([])
|
||||
const { data: members } = useMembers()
|
||||
|
||||
useEffect(() => {
|
||||
if (members?.accounts)
|
||||
setMemberList(members.accounts)
|
||||
}, [members])
|
||||
|
||||
const { mutateAsync: createEmptyDataset } = useCreatePipelineDataset()
|
||||
|
||||
const handleCreate = useCallback(async (payload: CreateFormData) => {
|
||||
const { name, appIcon, description, permission, selectedMemberIDs } = payload
|
||||
const request: CreateDatasetReq = {
|
||||
name,
|
||||
description,
|
||||
icon_info: {
|
||||
icon_type: appIcon.type,
|
||||
icon: appIcon.type === 'image' ? appIcon.fileId : appIcon.icon,
|
||||
icon_background: appIcon.type === 'image' ? undefined : appIcon.background,
|
||||
icon_url: appIcon.type === 'image' ? appIcon.url : undefined,
|
||||
},
|
||||
doc_form: ChunkingMode.text,
|
||||
permission,
|
||||
}
|
||||
// Handle permission
|
||||
if (request.permission === DatasetPermission.partialMembers) {
|
||||
const selectedMemberList = selectedMemberIDs.map((id) => {
|
||||
return {
|
||||
user_id: id,
|
||||
role: memberList.find(member => member.id === id)?.role,
|
||||
}
|
||||
})
|
||||
request.partial_member_list = selectedMemberList
|
||||
}
|
||||
await createEmptyDataset(request, {
|
||||
onSettled: () => {
|
||||
onClose?.()
|
||||
},
|
||||
})
|
||||
}, [createEmptyDataset, memberList, onClose])
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isShow={show}
|
||||
onClose={onClose}
|
||||
className='max-w-[520px] p-0'
|
||||
>
|
||||
<CreateForm
|
||||
onCreate={handleCreate}
|
||||
onClose={onClose}
|
||||
/>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default CreateFromScratchModal
|
||||
@ -0,0 +1,70 @@
|
||||
import Button from '@/app/components/base/button'
|
||||
import { RiAddLine, RiArrowRightUpLine, RiMoreFill } from '@remixicon/react'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Operations from './operations'
|
||||
import CustomPopover from '@/app/components/base/popover'
|
||||
|
||||
type ActionsProps = {
|
||||
handleApplyTemplate: () => void
|
||||
handleShowTemplateDetails: () => void
|
||||
showMoreOperations: boolean
|
||||
openEditModal: () => void
|
||||
handleExportDSL: () => void
|
||||
handleDelete: () => void
|
||||
}
|
||||
|
||||
const Actions = ({
|
||||
handleApplyTemplate,
|
||||
handleShowTemplateDetails,
|
||||
showMoreOperations,
|
||||
openEditModal,
|
||||
handleExportDSL,
|
||||
handleDelete,
|
||||
}: ActionsProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<div className='absolute bottom-0 left-0 z-10 hidden w-full items-center gap-x-1 bg-pipeline-template-card-hover-bg p-4 pt-8 group-hover:flex'>
|
||||
<Button
|
||||
variant='primary'
|
||||
onClick={handleApplyTemplate}
|
||||
className='grow gap-x-0.5'
|
||||
>
|
||||
<RiAddLine className='size-4' />
|
||||
<span className='px-0.5'>{t('datasetPipeline.operations.choose')}</span>
|
||||
</Button>
|
||||
<Button
|
||||
variant='secondary'
|
||||
onClick={handleShowTemplateDetails}
|
||||
className='grow gap-x-0.5'
|
||||
>
|
||||
<RiArrowRightUpLine className='size-4' />
|
||||
<span className='px-0.5'>{t('datasetPipeline.operations.details')}</span>
|
||||
</Button>
|
||||
{
|
||||
showMoreOperations && (
|
||||
<CustomPopover
|
||||
htmlContent={
|
||||
<Operations
|
||||
openEditModal={openEditModal}
|
||||
onExport={handleExportDSL}
|
||||
onDelete={handleDelete}
|
||||
/>
|
||||
}
|
||||
className={'z-20 min-w-[160px]'}
|
||||
popupClassName={'rounded-xl bg-none shadow-none ring-0 min-w-[160px]'}
|
||||
position='br'
|
||||
trigger='click'
|
||||
btnElement={
|
||||
<RiMoreFill className='size-4 text-text-tertiary' />
|
||||
}
|
||||
btnClassName='size-8 cursor-pointer justify-center rounded-lg p-0 shadow-xs shadow-shadow-shadow-3'
|
||||
/>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(Actions)
|
||||
@ -0,0 +1,74 @@
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import CreateForm from '../../create-form'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import type { CreateFormData } from '@/models/pipeline'
|
||||
import { ChunkingMode, type CreateDatasetReq, DatasetPermission } from '@/models/datasets'
|
||||
import { useCreatePipelineDataset } from '@/service/knowledge/use-create-dataset'
|
||||
import type { Member } from '@/models/common'
|
||||
import { useMembers } from '@/service/use-common'
|
||||
|
||||
type ApplyTemplateModalProps = {
|
||||
show: boolean
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
const ApplyTemplateModal = ({
|
||||
show,
|
||||
onClose,
|
||||
}: ApplyTemplateModalProps) => {
|
||||
const [memberList, setMemberList] = useState<Member[]>([])
|
||||
const { data: members } = useMembers()
|
||||
|
||||
useEffect(() => {
|
||||
if (members?.accounts)
|
||||
setMemberList(members.accounts)
|
||||
}, [members])
|
||||
|
||||
const { mutateAsync: createEmptyDataset } = useCreatePipelineDataset() // todo: yaml content
|
||||
|
||||
const handleCreate = useCallback(async (payload: CreateFormData) => {
|
||||
const { name, appIcon, description, permission, selectedMemberIDs } = payload
|
||||
const request: CreateDatasetReq = {
|
||||
name,
|
||||
description,
|
||||
icon_info: {
|
||||
icon_type: appIcon.type,
|
||||
icon: appIcon.type === 'image' ? appIcon.fileId : appIcon.icon,
|
||||
icon_background: appIcon.type === 'image' ? undefined : appIcon.background,
|
||||
icon_url: appIcon.type === 'image' ? appIcon.url : undefined,
|
||||
},
|
||||
doc_form: ChunkingMode.text,
|
||||
permission,
|
||||
}
|
||||
// Handle permission
|
||||
if (request.permission === DatasetPermission.partialMembers) {
|
||||
const selectedMemberList = selectedMemberIDs.map((id) => {
|
||||
return {
|
||||
user_id: id,
|
||||
role: memberList.find(member => member.id === id)?.role,
|
||||
}
|
||||
})
|
||||
request.partial_member_list = selectedMemberList
|
||||
}
|
||||
await createEmptyDataset(request, {
|
||||
onSettled: () => {
|
||||
onClose?.()
|
||||
},
|
||||
})
|
||||
}, [createEmptyDataset, memberList, onClose])
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isShow={show}
|
||||
onClose={onClose}
|
||||
className='max-w-[520px] p-0'
|
||||
>
|
||||
<CreateForm
|
||||
onCreate={handleCreate}
|
||||
onClose={onClose}
|
||||
/>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default ApplyTemplateModal
|
||||
@ -0,0 +1,61 @@
|
||||
import AppIcon from '@/app/components/base/app-icon'
|
||||
import { General } from '@/app/components/base/icons/src/public/knowledge/dataset-card'
|
||||
import type { ChunkingMode, IconInfo } from '@/models/datasets'
|
||||
import { DOC_FORM_ICON_WITH_BG, DOC_FORM_TEXT } from '@/models/datasets'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
type ContentProps = {
|
||||
name: string
|
||||
description: string
|
||||
iconInfo: IconInfo
|
||||
docForm: ChunkingMode
|
||||
}
|
||||
|
||||
const Content = ({
|
||||
name,
|
||||
description,
|
||||
iconInfo,
|
||||
docForm,
|
||||
}: ContentProps) => {
|
||||
const { t } = useTranslation()
|
||||
const Icon = DOC_FORM_ICON_WITH_BG[docForm] || General
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='flex items-center gap-x-3 p-4 pb-2'>
|
||||
<div className='relative shrink-0'>
|
||||
<AppIcon
|
||||
size='large'
|
||||
iconType={iconInfo.icon_type}
|
||||
icon={iconInfo.icon}
|
||||
background={iconInfo.icon_type === 'image' ? undefined : iconInfo.icon_background}
|
||||
imageUrl={iconInfo.icon_type === 'image' ? iconInfo.icon_url : undefined}
|
||||
/>
|
||||
<div className='absolute -bottom-1 -right-1 z-10'>
|
||||
<Icon className='size-4' />
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex grow flex-col gap-y-1 py-px'>
|
||||
<div
|
||||
className='system-md-semibold truncate text-text-secondary'
|
||||
title={name}
|
||||
>
|
||||
{name}
|
||||
</div>
|
||||
<div className='system-2xs-medium-uppercase text-text-tertiary'>
|
||||
{t(`dataset.chunkingMode.${DOC_FORM_TEXT[docForm]}`)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p
|
||||
className='system-xs-regular line-clamp-3 grow px-4 py-1 text-text-tertiary'
|
||||
title={description}
|
||||
>
|
||||
{description}
|
||||
</p>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(Content)
|
||||
Loading…
Reference in New Issue