mirror of
https://github.com/langgenius/dify.git
synced 2026-05-06 10:28:10 +08:00
feat: Add conversion functionality to Knowledge Pipeline with UI and translations
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useEffect, useMemo } from 'react'
|
||||
import React, { useEffect, useMemo, useState } from 'react'
|
||||
import { usePathname } from 'next/navigation'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { RemixiconComponentType } from '@remixicon/react'
|
||||
@ -23,6 +23,8 @@ import { PipelineFill, PipelineLine } from '@/app/components/base/icons/src/vend
|
||||
import { useDatasetDetail, useDatasetRelatedApps } from '@/service/knowledge/use-dataset'
|
||||
import useDocumentTitle from '@/hooks/use-document-title'
|
||||
import ExtraInfo from '@/app/components/datasets/extra-info'
|
||||
import { useEventEmitterContextContext } from '@/context/event-emitter'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
export type IAppDetailLayoutProps = {
|
||||
children: React.ReactNode
|
||||
@ -34,9 +36,18 @@ const DatasetDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
||||
children,
|
||||
params: { datasetId },
|
||||
} = props
|
||||
const { t } = useTranslation()
|
||||
const pathname = usePathname()
|
||||
const hideSideBar = pathname.endsWith('documents/create') || pathname.endsWith('documents/create-from-pipeline')
|
||||
const { t } = useTranslation()
|
||||
const isPipelineCanvas = pathname.endsWith('/pipeline')
|
||||
const workflowCanvasMaximize = localStorage.getItem('workflow-canvas-maximize') === 'true'
|
||||
const [hideHeader, setHideHeader] = useState(workflowCanvasMaximize)
|
||||
const { eventEmitter } = useEventEmitterContextContext()
|
||||
|
||||
eventEmitter?.useSubscription((v: any) => {
|
||||
if (v?.type === 'workflow-canvas-maximize')
|
||||
setHideHeader(v.payload)
|
||||
})
|
||||
const { isCurrentWorkspaceDatasetOperator } = useAppContext()
|
||||
|
||||
const media = useBreakpoints()
|
||||
@ -75,15 +86,13 @@ const DatasetDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
||||
]
|
||||
|
||||
if (datasetRes?.provider !== 'external') {
|
||||
if (datasetRes?.runtime_mode === 'rag_pipeline') {
|
||||
baseNavigation.unshift({
|
||||
name: t('common.datasetMenus.pipeline'),
|
||||
href: `/datasets/${datasetId}/pipeline`,
|
||||
icon: PipelineLine as RemixiconComponentType,
|
||||
selectedIcon: PipelineFill as RemixiconComponentType,
|
||||
disabled: false,
|
||||
})
|
||||
}
|
||||
baseNavigation.unshift({
|
||||
name: t('common.datasetMenus.pipeline'),
|
||||
href: `/datasets/${datasetId}/pipeline`,
|
||||
icon: PipelineLine as RemixiconComponentType,
|
||||
selectedIcon: PipelineFill as RemixiconComponentType,
|
||||
disabled: false,
|
||||
})
|
||||
baseNavigation.unshift({
|
||||
name: t('common.datasetMenus.documents'),
|
||||
href: `/datasets/${datasetId}/documents`,
|
||||
@ -94,7 +103,7 @@ const DatasetDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
||||
}
|
||||
|
||||
return baseNavigation
|
||||
}, [t, datasetId, isButtonDisabledWithPipeline, datasetRes?.provider, datasetRes?.runtime_mode])
|
||||
}, [t, datasetId, isButtonDisabledWithPipeline, datasetRes?.provider])
|
||||
|
||||
useDocumentTitle(datasetRes?.name || t('common.menus.datasets'))
|
||||
|
||||
@ -110,7 +119,12 @@ const DatasetDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
||||
return <Loading type='app' />
|
||||
|
||||
return (
|
||||
<div className='flex grow overflow-hidden'>
|
||||
<div
|
||||
className={cn(
|
||||
'flex grow overflow-hidden',
|
||||
hideHeader && isPipelineCanvas ? '' : 'rounded-t-2xl border-t border-effects-highlight',
|
||||
)}
|
||||
>
|
||||
<DatasetDetailContext.Provider value={{
|
||||
indexingTechnique: datasetRes?.indexing_technique,
|
||||
dataset: datasetRes,
|
||||
|
||||
71
web/app/components/rag-pipeline/conversion.tsx
Normal file
71
web/app/components/rag-pipeline/conversion.tsx
Normal file
@ -0,0 +1,71 @@
|
||||
import React, { useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Button from '../base/button'
|
||||
import PipelineScreenShot from './screenshot'
|
||||
import Confirm from '../base/confirm'
|
||||
|
||||
const Conversion = () => {
|
||||
const { t } = useTranslation()
|
||||
const [showConfirmModal, setShowConfirmModal] = useState(false)
|
||||
|
||||
const handleConvert = useCallback(() => {
|
||||
setShowConfirmModal(false)
|
||||
// todo: Add conversion logic here
|
||||
}, [])
|
||||
|
||||
const handleShowConfirmModal = useCallback(() => {
|
||||
setShowConfirmModal(true)
|
||||
}, [])
|
||||
|
||||
const handleCancelConversion = useCallback(() => {
|
||||
setShowConfirmModal(false)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className='flex h-full w-full items-center justify-center bg-background-body p-6 pb-16'>
|
||||
<div className='flex rounded-2xl border-[0.5px] border-components-card-border bg-components-card-bg shadow-sm shadow-shadow-shadow-4'>
|
||||
<div className='flex max-w-[480px] flex-col justify-between p-10'>
|
||||
<div className='flex flex-col gap-y-2.5'>
|
||||
<div className='title-4xl-semi-bold text-text-primary'>
|
||||
{t('datasetPipeline.conversion.title')}
|
||||
</div>
|
||||
<div className='body-md-medium'>
|
||||
<span className='text-text-secondary'>{t('datasetPipeline.conversion.descriptionChunk1')}</span>
|
||||
<span className='text-text-tertiary'>{t('datasetPipeline.conversion.descriptionChunk2')}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex items-center gap-x-4'>
|
||||
<Button
|
||||
variant='primary'
|
||||
className='w-32'
|
||||
onClick={handleShowConfirmModal}
|
||||
>
|
||||
{t('datasetPipeline.operations.convert')}
|
||||
</Button>
|
||||
<span className='system-xs-regular text-text-warning'>
|
||||
{t('datasetPipeline.conversion.warning')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className='pb-8 pl-[25px] pr-0 pt-6'>
|
||||
<div className='rounded-l-xl border border-effects-highlight bg-background-default p-1 shadow-md shadow-shadow-shadow-5 backdrop-blur-[5px]'>
|
||||
<div className='overflow-hidden rounded-l-lg'>
|
||||
<PipelineScreenShot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{showConfirmModal && (
|
||||
<Confirm
|
||||
title={t('datasetPipeline.conversion.confirm.title')}
|
||||
content={t('datasetPipeline.conversion.confirm.content')}
|
||||
isShow={showConfirmModal}
|
||||
onConfirm={handleConvert}
|
||||
onCancel={handleCancelConversion}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(Conversion)
|
||||
@ -12,6 +12,8 @@ import Loading from '@/app/components/base/loading'
|
||||
import { createRagPipelineSliceSlice } from './store'
|
||||
import RagPipelineMain from './components/rag-pipeline-main'
|
||||
import { usePipelineInit } from './hooks'
|
||||
import { useDatasetDetailContextWithSelector } from '@/context/dataset-detail'
|
||||
import Conversion from './conversion'
|
||||
|
||||
const RagPipeline = () => {
|
||||
const {
|
||||
@ -53,6 +55,11 @@ const RagPipeline = () => {
|
||||
}
|
||||
|
||||
const RagPipelineWrapper = () => {
|
||||
const pipelineId = useDatasetDetailContextWithSelector(s => s.dataset?.pipeline_id)
|
||||
|
||||
if (!pipelineId)
|
||||
return <Conversion />
|
||||
|
||||
return (
|
||||
<WorkflowContextProvider
|
||||
injectWorkflowStoreSliceFn={createRagPipelineSliceSlice as InjectWorkflowStoreSliceFn}
|
||||
|
||||
22
web/app/components/rag-pipeline/screenshot.tsx
Normal file
22
web/app/components/rag-pipeline/screenshot.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import React from 'react'
|
||||
import useTheme from '@/hooks/use-theme'
|
||||
import { basePath } from '@/utils/var'
|
||||
import Image from 'next/image'
|
||||
|
||||
const PipelineScreenShot = () => {
|
||||
const { theme } = useTheme()
|
||||
|
||||
return (
|
||||
<picture>
|
||||
<source media="(resolution: 1x)" srcSet={`${basePath}/screenshots/${theme}/Pipeline.png`} />
|
||||
<source media="(resolution: 2x)" srcSet={`${basePath}/screenshots/${theme}/Pipeline@2x.png`} />
|
||||
<source media="(resolution: 3x)" srcSet={`${basePath}/screenshots/${theme}/Pipeline@3x.png`} />
|
||||
<Image
|
||||
src={`${basePath}/screenshots/${theme}/Pipeline.png`}
|
||||
alt='Pipeline Screenshot'
|
||||
width={692} height={456} />
|
||||
</picture>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(PipelineScreenShot)
|
||||
Reference in New Issue
Block a user