mirror of
https://github.com/langgenius/dify.git
synced 2026-04-28 20:17:29 +08:00
feat: add DSL modal header and tab components; enhance pipeline import functionality
This commit is contained in:
parent
de0cb06f8c
commit
b713218cab
@ -0,0 +1,27 @@
|
|||||||
|
import { RiCloseLine } from '@remixicon/react'
|
||||||
|
import React from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
|
type HeaderProps = {
|
||||||
|
onClose: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const Header = ({
|
||||||
|
onClose,
|
||||||
|
}: HeaderProps) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='title-2xl-semi-bold relative flex items-center justify-between pb-3 pl-6 pr-14 pt-6 text-text-primary'>
|
||||||
|
{t('app.importFromDSL')}
|
||||||
|
<div
|
||||||
|
className='absolute right-5 top-5 flex size-8 cursor-pointer items-center'
|
||||||
|
onClick={onClose}
|
||||||
|
>
|
||||||
|
<RiCloseLine className='size-[18px] text-text-tertiary' />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(Header)
|
||||||
@ -3,35 +3,29 @@ import { useMemo, useRef, useState } from 'react'
|
|||||||
import { useRouter } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
import { useContext } from 'use-context-selector'
|
import { useContext } from 'use-context-selector'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { RiCloseLine, RiCommandLine, RiCornerDownLeftLine } from '@remixicon/react'
|
|
||||||
import { useDebounceFn, useKeyPress } from 'ahooks'
|
import { useDebounceFn, useKeyPress } from 'ahooks'
|
||||||
import Button from '@/app/components/base/button'
|
import Button from '@/app/components/base/button'
|
||||||
import Input from '@/app/components/base/input'
|
import Input from '@/app/components/base/input'
|
||||||
import Modal from '@/app/components/base/modal'
|
import Modal from '@/app/components/base/modal'
|
||||||
import { ToastContext } from '@/app/components/base/toast'
|
import { ToastContext } from '@/app/components/base/toast'
|
||||||
import {
|
|
||||||
importDSL,
|
|
||||||
importDSLConfirm,
|
|
||||||
} from '@/service/apps'
|
|
||||||
import {
|
import {
|
||||||
DSLImportMode,
|
DSLImportMode,
|
||||||
DSLImportStatus,
|
DSLImportStatus,
|
||||||
} from '@/models/app'
|
} from '@/models/app'
|
||||||
import { useSelector as useAppContextWithSelector } from '@/context/app-context'
|
|
||||||
import { useProviderContextSelector } from '@/context/provider-context'
|
import { useProviderContextSelector } from '@/context/provider-context'
|
||||||
import AppsFull from '@/app/components/billing/apps-full-in-dialog'
|
import AppsFull from '@/app/components/billing/apps-full-in-dialog'
|
||||||
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
|
|
||||||
import { getRedirection } from '@/utils/app-redirection'
|
|
||||||
import cn from '@/utils/classnames'
|
|
||||||
import { usePluginDependencies } from '@/app/components/workflow/plugin-dependency/hooks'
|
import { usePluginDependencies } from '@/app/components/workflow/plugin-dependency/hooks'
|
||||||
import { noop } from 'lodash-es'
|
import { noop } from 'lodash-es'
|
||||||
import Uploader from './uploader'
|
import Uploader from './uploader'
|
||||||
|
import Header from './header'
|
||||||
|
import Tab from './tab'
|
||||||
|
import { useImportPipelineDSL, useImportPipelineDSLConfirm } from '@/service/use-pipeline'
|
||||||
|
|
||||||
type CreateFromDSLModalProps = {
|
type CreateFromDSLModalProps = {
|
||||||
show: boolean
|
show: boolean
|
||||||
onSuccess?: () => void
|
onSuccess?: () => void
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
activeTab?: string
|
activeTab?: CreateFromDSLModalTab
|
||||||
dslUrl?: string
|
dslUrl?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,14 +70,14 @@ const CreateFromDSLModal = ({
|
|||||||
setFileContent('')
|
setFileContent('')
|
||||||
}
|
}
|
||||||
|
|
||||||
const isCurrentWorkspaceEditor = useAppContextWithSelector(state => state.isCurrentWorkspaceEditor)
|
|
||||||
const plan = useProviderContextSelector(state => state.plan)
|
const plan = useProviderContextSelector(state => state.plan)
|
||||||
const enableBilling = useProviderContextSelector(state => state.enableBilling)
|
const enableBilling = useProviderContextSelector(state => state.enableBilling)
|
||||||
const isAppsFull = (enableBilling && plan.usage.buildApps >= plan.total.buildApps)
|
const isAppsFull = (enableBilling && plan.usage.buildApps >= plan.total.buildApps)
|
||||||
|
|
||||||
const isCreatingRef = useRef(false)
|
const isCreatingRef = useRef(false)
|
||||||
|
|
||||||
// todo: replace with pipeline import DSL and check plugin dependencies
|
const { mutateAsync: importDSL } = useImportPipelineDSL()
|
||||||
|
|
||||||
const onCreate = async () => {
|
const onCreate = async () => {
|
||||||
if (currentTab === CreateFromDSLModalTab.FROM_FILE && !currentFile)
|
if (currentTab === CreateFromDSLModalTab.FROM_FILE && !currentFile)
|
||||||
return
|
return
|
||||||
@ -94,7 +88,6 @@ const CreateFromDSLModal = ({
|
|||||||
isCreatingRef.current = true
|
isCreatingRef.current = true
|
||||||
try {
|
try {
|
||||||
let response
|
let response
|
||||||
|
|
||||||
if (currentTab === CreateFromDSLModalTab.FROM_FILE) {
|
if (currentTab === CreateFromDSLModalTab.FROM_FILE) {
|
||||||
response = await importDSL({
|
response = await importDSL({
|
||||||
mode: DSLImportMode.YAML_CONTENT,
|
mode: DSLImportMode.YAML_CONTENT,
|
||||||
@ -110,7 +103,7 @@ const CreateFromDSLModal = ({
|
|||||||
|
|
||||||
if (!response)
|
if (!response)
|
||||||
return
|
return
|
||||||
const { id, status, app_id, app_mode, imported_dsl_version, current_dsl_version } = response
|
const { id, status, pipeline_id, imported_dsl_version, current_dsl_version } = response
|
||||||
if (status === DSLImportStatus.COMPLETED || status === DSLImportStatus.COMPLETED_WITH_WARNINGS) {
|
if (status === DSLImportStatus.COMPLETED || status === DSLImportStatus.COMPLETED_WITH_WARNINGS) {
|
||||||
if (onSuccess)
|
if (onSuccess)
|
||||||
onSuccess()
|
onSuccess()
|
||||||
@ -122,9 +115,9 @@ const CreateFromDSLModal = ({
|
|||||||
message: t(status === DSLImportStatus.COMPLETED ? 'app.newApp.appCreated' : 'app.newApp.caution'),
|
message: t(status === DSLImportStatus.COMPLETED ? 'app.newApp.appCreated' : 'app.newApp.caution'),
|
||||||
children: status === DSLImportStatus.COMPLETED_WITH_WARNINGS && t('app.newApp.appCreateDSLWarning'),
|
children: status === DSLImportStatus.COMPLETED_WITH_WARNINGS && t('app.newApp.appCreateDSLWarning'),
|
||||||
})
|
})
|
||||||
if (app_id)
|
if (pipeline_id)
|
||||||
await handleCheckPluginDependencies(app_id)
|
await handleCheckPluginDependencies(pipeline_id, true)
|
||||||
getRedirection(isCurrentWorkspaceEditor, { id: app_id!, mode: app_mode }, push)
|
push(`datasets/${pipeline_id}/pipeline`)
|
||||||
}
|
}
|
||||||
else if (status === DSLImportStatus.PENDING) {
|
else if (status === DSLImportStatus.PENDING) {
|
||||||
setVersions({
|
setVersions({
|
||||||
@ -142,8 +135,7 @@ const CreateFromDSLModal = ({
|
|||||||
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
catch {
|
||||||
catch (e) {
|
|
||||||
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
@ -153,16 +145,13 @@ const CreateFromDSLModal = ({
|
|||||||
|
|
||||||
const { run: handleCreateApp } = useDebounceFn(onCreate, { wait: 300 })
|
const { run: handleCreateApp } = useDebounceFn(onCreate, { wait: 300 })
|
||||||
|
|
||||||
useKeyPress(['meta.enter', 'ctrl.enter'], () => {
|
|
||||||
if (show && !isAppsFull && ((currentTab === CreateFromDSLModalTab.FROM_FILE && currentFile) || (currentTab === CreateFromDSLModalTab.FROM_URL && dslUrlValue)))
|
|
||||||
handleCreateApp()
|
|
||||||
})
|
|
||||||
|
|
||||||
useKeyPress('esc', () => {
|
useKeyPress('esc', () => {
|
||||||
if (show && !showErrorModal)
|
if (show && !showErrorModal)
|
||||||
onClose()
|
onClose()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const { mutateAsync: importDSLConfirm } = useImportPipelineDSLConfirm()
|
||||||
|
|
||||||
const onDSLConfirm = async () => {
|
const onDSLConfirm = async () => {
|
||||||
try {
|
try {
|
||||||
if (!importId)
|
if (!importId)
|
||||||
@ -171,7 +160,7 @@ const CreateFromDSLModal = ({
|
|||||||
import_id: importId,
|
import_id: importId,
|
||||||
})
|
})
|
||||||
|
|
||||||
const { status, app_id, app_mode } = response
|
const { status, pipeline_id } = response
|
||||||
|
|
||||||
if (status === DSLImportStatus.COMPLETED) {
|
if (status === DSLImportStatus.COMPLETED) {
|
||||||
if (onSuccess)
|
if (onSuccess)
|
||||||
@ -183,32 +172,19 @@ const CreateFromDSLModal = ({
|
|||||||
type: 'success',
|
type: 'success',
|
||||||
message: t('app.newApp.appCreated'),
|
message: t('app.newApp.appCreated'),
|
||||||
})
|
})
|
||||||
if (app_id)
|
if (pipeline_id)
|
||||||
await handleCheckPluginDependencies(app_id)
|
await handleCheckPluginDependencies(pipeline_id, true)
|
||||||
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
|
push(`datasets/${pipeline_id}/pipeline`)
|
||||||
getRedirection(isCurrentWorkspaceEditor, { id: app_id!, mode: app_mode }, push)
|
|
||||||
}
|
}
|
||||||
else if (status === DSLImportStatus.FAILED) {
|
else if (status === DSLImportStatus.FAILED) {
|
||||||
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
catch {
|
||||||
catch (e) {
|
|
||||||
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const tabs = [
|
|
||||||
{
|
|
||||||
key: CreateFromDSLModalTab.FROM_FILE,
|
|
||||||
label: t('app.importFromDSLFile'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: CreateFromDSLModalTab.FROM_URL,
|
|
||||||
label: t('app.importFromDSLUrl'),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const buttonDisabled = useMemo(() => {
|
const buttonDisabled = useMemo(() => {
|
||||||
if (isAppsFull)
|
if (isAppsFull)
|
||||||
return true
|
return true
|
||||||
@ -226,36 +202,11 @@ const CreateFromDSLModal = ({
|
|||||||
isShow={show}
|
isShow={show}
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
>
|
>
|
||||||
<div className='title-2xl-semi-bold flex items-center justify-between pb-3 pl-6 pr-5 pt-6 text-text-primary'>
|
<Header onClose={onClose} />
|
||||||
{t('app.importFromDSL')}
|
<Tab
|
||||||
<div
|
currentTab={currentTab}
|
||||||
className='flex h-8 w-8 cursor-pointer items-center'
|
setCurrentTab={setCurrentTab}
|
||||||
onClick={() => onClose()}
|
/>
|
||||||
>
|
|
||||||
<RiCloseLine className='h-5 w-5 text-text-tertiary' />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='system-md-semibold flex h-9 items-center space-x-6 border-b border-divider-subtle px-6 text-text-tertiary'>
|
|
||||||
{
|
|
||||||
tabs.map(tab => (
|
|
||||||
<div
|
|
||||||
key={tab.key}
|
|
||||||
className={cn(
|
|
||||||
'relative flex h-full cursor-pointer items-center',
|
|
||||||
currentTab === tab.key && 'text-text-primary',
|
|
||||||
)}
|
|
||||||
onClick={() => setCurrentTab(tab.key)}
|
|
||||||
>
|
|
||||||
{tab.label}
|
|
||||||
{
|
|
||||||
currentTab === tab.key && (
|
|
||||||
<div className='absolute bottom-0 h-[2px] w-full bg-util-colors-blue-brand-blue-brand-600'></div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<div className='px-6 py-4'>
|
<div className='px-6 py-4'>
|
||||||
{
|
{
|
||||||
currentTab === CreateFromDSLModalTab.FROM_FILE && (
|
currentTab === CreateFromDSLModalTab.FROM_FILE && (
|
||||||
@ -284,19 +235,17 @@ const CreateFromDSLModal = ({
|
|||||||
<AppsFull className='mt-0' loc='app-create-dsl' />
|
<AppsFull className='mt-0' loc='app-create-dsl' />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className='flex justify-end px-6 py-5'>
|
<div className='flex justify-end gap-x-2 p-6 pt-5'>
|
||||||
<Button className='mr-2' onClick={onClose}>{t('app.newApp.Cancel')}</Button>
|
<Button onClick={onClose}>
|
||||||
|
{t('app.newApp.Cancel')}
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
disabled={buttonDisabled}
|
disabled={buttonDisabled}
|
||||||
variant='primary'
|
variant='primary'
|
||||||
onClick={handleCreateApp}
|
onClick={handleCreateApp}
|
||||||
className='gap-1'
|
className='gap-1'
|
||||||
>
|
>
|
||||||
<span>{t('app.newApp.Create')}</span>
|
<span>{t('app.newApp.import')}</span>
|
||||||
<div className='flex gap-0.5'>
|
|
||||||
<RiCommandLine size={14} className='system-kbd rounded-sm bg-components-kbd-bg-white p-0.5' />
|
|
||||||
<RiCornerDownLeftLine size={14} className='system-kbd rounded-sm bg-components-kbd-bg-white p-0.5' />
|
|
||||||
</div>
|
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
@ -0,0 +1,44 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { CreateFromDSLModalTab } from '@/app/components/app/create-from-dsl-modal'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import Item from './item'
|
||||||
|
|
||||||
|
type TabProps = {
|
||||||
|
currentTab: CreateFromDSLModalTab
|
||||||
|
setCurrentTab: (tab: CreateFromDSLModalTab) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const Tab = ({
|
||||||
|
currentTab,
|
||||||
|
setCurrentTab,
|
||||||
|
}: TabProps) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
const tabs = [
|
||||||
|
{
|
||||||
|
key: CreateFromDSLModalTab.FROM_FILE,
|
||||||
|
label: t('app.importFromDSLFile'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: CreateFromDSLModalTab.FROM_URL,
|
||||||
|
label: t('app.importFromDSLUrl'),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='system-md-semibold flex h-9 items-center gap-x-6 border-b border-divider-subtle px-6 text-text-tertiary'>
|
||||||
|
{
|
||||||
|
tabs.map(tab => (
|
||||||
|
<Item
|
||||||
|
key={tab.key}
|
||||||
|
isActive={currentTab === tab.key}
|
||||||
|
label={tab.label}
|
||||||
|
onClick={setCurrentTab.bind(null, tab.key)}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Tab
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import cn from '@/utils/classnames'
|
||||||
|
|
||||||
|
type ItemProps = {
|
||||||
|
isActive: boolean
|
||||||
|
label: string
|
||||||
|
onClick: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const Item = ({
|
||||||
|
isActive,
|
||||||
|
label,
|
||||||
|
onClick,
|
||||||
|
}: ItemProps) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
'system-md-semibold relative flex h-full cursor-pointer items-center text-text-tertiary',
|
||||||
|
isActive && 'text-text-primary',
|
||||||
|
)}
|
||||||
|
onClick={onClick}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
{
|
||||||
|
isActive && (
|
||||||
|
<div className='absolute bottom-0 h-0.5 w-full bg-util-colors-blue-brand-blue-brand-600' />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(Item)
|
||||||
@ -76,4 +76,4 @@ const CreateOptions = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default React.memo(CreateOptions)
|
export default CreateOptions
|
||||||
|
|||||||
@ -10,7 +10,7 @@ type ActionsProps = {
|
|||||||
handleShowTemplateDetails: () => void
|
handleShowTemplateDetails: () => void
|
||||||
showMoreOperations: boolean
|
showMoreOperations: boolean
|
||||||
openEditModal: () => void
|
openEditModal: () => void
|
||||||
handleExportDSL: () => void
|
handleExportDSL: (includeSecret?: boolean) => void
|
||||||
handleDelete: () => void
|
handleDelete: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,12 @@ import Modal from '@/app/components/base/modal'
|
|||||||
import EditPipelineInfo from './edit-pipeline-info'
|
import EditPipelineInfo from './edit-pipeline-info'
|
||||||
import type { PipelineTemplate } from '@/models/pipeline'
|
import type { PipelineTemplate } from '@/models/pipeline'
|
||||||
import Confirm from '@/app/components/base/confirm'
|
import Confirm from '@/app/components/base/confirm'
|
||||||
import { useDeletePipeline, useExportPipelineDSL, useImportPipelineDSL, usePipelineTemplateById } from '@/service/use-pipeline'
|
import {
|
||||||
|
useDeletePipeline,
|
||||||
|
useExportPipelineDSL,
|
||||||
|
useImportPipelineDSL,
|
||||||
|
usePipelineTemplateById,
|
||||||
|
} from '@/service/use-pipeline'
|
||||||
import { downloadFile } from '@/utils/format'
|
import { downloadFile } from '@/utils/format'
|
||||||
import Toast from '@/app/components/base/toast'
|
import Toast from '@/app/components/base/toast'
|
||||||
import { DSLImportMode } from '@/models/app'
|
import { DSLImportMode } from '@/models/app'
|
||||||
@ -30,7 +35,7 @@ const TemplateCard = ({
|
|||||||
const [showDetailModal, setShowDetailModal] = useState(false)
|
const [showDetailModal, setShowDetailModal] = useState(false)
|
||||||
|
|
||||||
const { refetch: getPipelineTemplateInfo } = usePipelineTemplateById(pipeline.id, false)
|
const { refetch: getPipelineTemplateInfo } = usePipelineTemplateById(pipeline.id, false)
|
||||||
const { mutateAsync: importPipelineDSL } = useImportPipelineDSL()
|
const { mutateAsync: importDSL } = useImportPipelineDSL()
|
||||||
const { handleCheckPluginDependencies } = usePluginDependencies()
|
const { handleCheckPluginDependencies } = usePluginDependencies()
|
||||||
|
|
||||||
const handleUseTemplate = useCallback(async () => {
|
const handleUseTemplate = useCallback(async () => {
|
||||||
@ -45,19 +50,16 @@ const TemplateCard = ({
|
|||||||
}
|
}
|
||||||
const request = {
|
const request = {
|
||||||
mode: DSLImportMode.YAML_CONTENT,
|
mode: DSLImportMode.YAML_CONTENT,
|
||||||
name: pipeline.name,
|
|
||||||
yaml_content: pipelineTemplateInfo.export_data,
|
yaml_content: pipelineTemplateInfo.export_data,
|
||||||
icon_info: pipeline.icon_info,
|
|
||||||
description: pipeline.description,
|
|
||||||
}
|
}
|
||||||
const newPipeline = await importPipelineDSL(request)
|
const newPipeline = await importDSL(request)
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message: t('app.newApp.appCreated'),
|
message: t('app.newApp.appCreated'),
|
||||||
})
|
})
|
||||||
if (newPipeline.dataset_id)
|
if (newPipeline.pipeline_id)
|
||||||
await handleCheckPluginDependencies(newPipeline.dataset_id) // todo: replace with pipeline dependency check
|
await handleCheckPluginDependencies(newPipeline.pipeline_id, true)
|
||||||
push(`dataset/${newPipeline.dataset_id}/pipeline`)
|
push(`dataset/${newPipeline.pipeline_id}/pipeline`)
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
@ -65,7 +67,7 @@ const TemplateCard = ({
|
|||||||
message: t('datasetPipeline.creation.errorTip'),
|
message: t('datasetPipeline.creation.errorTip'),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, [getPipelineTemplateInfo, importPipelineDSL, pipeline, t, push, handleCheckPluginDependencies])
|
}, [getPipelineTemplateInfo, importDSL, t, handleCheckPluginDependencies, push])
|
||||||
|
|
||||||
const handleShowTemplateDetails = useCallback(() => {
|
const handleShowTemplateDetails = useCallback(() => {
|
||||||
setShowDetailModal(true)
|
setShowDetailModal(true)
|
||||||
@ -85,9 +87,12 @@ const TemplateCard = ({
|
|||||||
|
|
||||||
const { mutateAsync: exportPipelineDSL, isPending: isExporting } = useExportPipelineDSL()
|
const { mutateAsync: exportPipelineDSL, isPending: isExporting } = useExportPipelineDSL()
|
||||||
|
|
||||||
const handleExportDSL = useCallback(async () => {
|
const handleExportDSL = useCallback(async (includeSecret = false) => {
|
||||||
if (isExporting) return
|
if (isExporting) return
|
||||||
await exportPipelineDSL(pipeline.id, {
|
await exportPipelineDSL({
|
||||||
|
pipeline_id: pipeline.id,
|
||||||
|
include_secret: includeSecret,
|
||||||
|
}, {
|
||||||
onSuccess: (res) => {
|
onSuccess: (res) => {
|
||||||
const blob = new Blob([res.data], { type: 'application/yaml' })
|
const blob = new Blob([res.data], { type: 'application/yaml' })
|
||||||
downloadFile({
|
downloadFile({
|
||||||
|
|||||||
@ -115,7 +115,7 @@ const Container = () => {
|
|||||||
onChange={e => handleKeywordsChange(e.target.value)}
|
onChange={e => handleKeywordsChange(e.target.value)}
|
||||||
onClear={() => handleKeywordsChange('')}
|
onClear={() => handleKeywordsChange('')}
|
||||||
/>
|
/>
|
||||||
<div className="h-4 w-[1px] bg-divider-regular" />
|
<div className='h-4 w-[1px] bg-divider-regular' />
|
||||||
<Button
|
<Button
|
||||||
className='shadows-shadow-xs gap-0.5'
|
className='shadows-shadow-xs gap-0.5'
|
||||||
onClick={() => setShowExternalApiPanel(true)}
|
onClick={() => setShowExternalApiPanel(true)}
|
||||||
|
|||||||
@ -1,15 +1,18 @@
|
|||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import { useStore as usePluginDependenciesStore } from './store'
|
import { useStore as usePluginDependenciesStore } from './store'
|
||||||
import { useMutationCheckDependencies } from '@/service/use-plugins'
|
import { useMutationCheckDependencies } from '@/service/use-plugins'
|
||||||
|
import { useCheckPipelineDependencies } from '@/service/use-pipeline'
|
||||||
|
|
||||||
export const usePluginDependencies = () => {
|
export const usePluginDependencies = () => {
|
||||||
const { mutateAsync } = useMutationCheckDependencies()
|
const { mutateAsync: checkWorkflowDependencies } = useMutationCheckDependencies()
|
||||||
|
const { mutateAsync: checkPipelineDependencies } = useCheckPipelineDependencies()
|
||||||
|
|
||||||
const handleCheckPluginDependencies = useCallback(async (appId: string) => {
|
const handleCheckPluginDependencies = useCallback(async (id: string, isPipeline = false) => {
|
||||||
const { leaked_dependencies } = await mutateAsync(appId)
|
const mutateAsync = isPipeline ? checkPipelineDependencies : checkWorkflowDependencies
|
||||||
|
const { leaked_dependencies } = await mutateAsync(id)
|
||||||
const { setDependencies } = usePluginDependenciesStore.getState()
|
const { setDependencies } = usePluginDependenciesStore.getState()
|
||||||
setDependencies(leaked_dependencies)
|
setDependencies(leaked_dependencies)
|
||||||
}, [mutateAsync])
|
}, [checkWorkflowDependencies, checkPipelineDependencies])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
handleCheckPluginDependencies,
|
handleCheckPluginDependencies,
|
||||||
|
|||||||
@ -75,6 +75,7 @@ const translation = {
|
|||||||
Create: 'Create',
|
Create: 'Create',
|
||||||
Cancel: 'Cancel',
|
Cancel: 'Cancel',
|
||||||
Confirm: 'Confirm',
|
Confirm: 'Confirm',
|
||||||
|
import: 'Import',
|
||||||
nameNotEmpty: 'Name cannot be empty',
|
nameNotEmpty: 'Name cannot be empty',
|
||||||
appTemplateNotSelected: 'Please select a template',
|
appTemplateNotSelected: 'Please select a template',
|
||||||
appTypeRequired: 'Please select an app type',
|
appTypeRequired: 'Please select an app type',
|
||||||
|
|||||||
@ -75,6 +75,8 @@ const translation = {
|
|||||||
hideTemplates: '返回应用类型选择',
|
hideTemplates: '返回应用类型选择',
|
||||||
Create: '创建',
|
Create: '创建',
|
||||||
Cancel: '取消',
|
Cancel: '取消',
|
||||||
|
Confirm: '确认',
|
||||||
|
import: '导入',
|
||||||
nameNotEmpty: '名称不能为空',
|
nameNotEmpty: '名称不能为空',
|
||||||
appTemplateNotSelected: '请选择应用模版',
|
appTemplateNotSelected: '请选择应用模版',
|
||||||
appTypeRequired: '请选择应用类型',
|
appTypeRequired: '请选择应用类型',
|
||||||
@ -87,7 +89,6 @@ const translation = {
|
|||||||
appCreateDSLErrorPart3: '当前应用 DSL 版本:',
|
appCreateDSLErrorPart3: '当前应用 DSL 版本:',
|
||||||
appCreateDSLErrorPart4: '系统支持 DSL 版本:',
|
appCreateDSLErrorPart4: '系统支持 DSL 版本:',
|
||||||
appCreateFailed: '应用创建失败',
|
appCreateFailed: '应用创建失败',
|
||||||
Confirm: '确认',
|
|
||||||
},
|
},
|
||||||
newAppFromTemplate: {
|
newAppFromTemplate: {
|
||||||
byCategories: '分类',
|
byCategories: '分类',
|
||||||
|
|||||||
@ -57,29 +57,49 @@ export type DeletePipelineResponse = {
|
|||||||
code: number
|
code: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ExportPipelineDSLRequest = {
|
||||||
|
pipeline_id: string
|
||||||
|
include_secret?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export type ExportPipelineDSLResponse = {
|
export type ExportPipelineDSLResponse = {
|
||||||
data: string
|
data: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ImportPipelineDSLRequest = {
|
export type ImportPipelineDSLRequest = {
|
||||||
mode: DSLImportMode
|
mode: DSLImportMode
|
||||||
name: string
|
yaml_content?: string
|
||||||
yaml_content: string
|
yaml_url?: string
|
||||||
icon_info: IconInfo
|
pipeline_id?: string
|
||||||
description: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ImportPipelineDSLResponse = {
|
export type ImportPipelineDSLResponse = {
|
||||||
id: string
|
id: string
|
||||||
status: DSLImportStatus
|
status: DSLImportStatus
|
||||||
app_mode: 'pipeline'
|
pipeline_id: string
|
||||||
dataset_id?: string
|
current_dsl_version: string
|
||||||
current_dsl_version?: string
|
imported_dsl_version: string
|
||||||
imported_dsl_version?: string
|
|
||||||
error: string
|
error: string
|
||||||
leaked_dependencies: Dependency[]
|
leaked_dependencies: Dependency[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ImportPipelineDSLConfirmRequest = {
|
||||||
|
import_id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ImportPipelineDSLConfirmResponse = {
|
||||||
|
id: string
|
||||||
|
status: DSLImportStatus
|
||||||
|
pipeline_id: string
|
||||||
|
current_dsl_version: string
|
||||||
|
imported_dsl_version: string
|
||||||
|
error: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PipelineCheckDependenciesResponse = {
|
||||||
|
leaked_dependencies: Dependency[]
|
||||||
|
}
|
||||||
|
|
||||||
export type Variables = {
|
export type Variables = {
|
||||||
type: InputVarType
|
type: InputVarType
|
||||||
label: string
|
label: string
|
||||||
|
|||||||
@ -3,9 +3,13 @@ import { useMutation, useQuery } from '@tanstack/react-query'
|
|||||||
import { del, get, patch, post } from './base'
|
import { del, get, patch, post } from './base'
|
||||||
import type {
|
import type {
|
||||||
DeletePipelineResponse,
|
DeletePipelineResponse,
|
||||||
|
ExportPipelineDSLRequest,
|
||||||
ExportPipelineDSLResponse,
|
ExportPipelineDSLResponse,
|
||||||
|
ImportPipelineDSLConfirmRequest,
|
||||||
|
ImportPipelineDSLConfirmResponse,
|
||||||
ImportPipelineDSLRequest,
|
ImportPipelineDSLRequest,
|
||||||
ImportPipelineDSLResponse,
|
ImportPipelineDSLResponse,
|
||||||
|
PipelineCheckDependenciesResponse,
|
||||||
PipelineProcessingParamsResponse,
|
PipelineProcessingParamsResponse,
|
||||||
PipelineTemplateByIdResponse,
|
PipelineTemplateByIdResponse,
|
||||||
PipelineTemplateListParams,
|
PipelineTemplateListParams,
|
||||||
@ -63,30 +67,58 @@ export const useDeletePipeline = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const useExportPipelineDSL = (
|
export const useExportPipelineDSL = (
|
||||||
mutationOptions: MutationOptions<ExportPipelineDSLResponse, Error, string> = {},
|
mutationOptions: MutationOptions<ExportPipelineDSLResponse, Error, ExportPipelineDSLRequest> = {},
|
||||||
) => {
|
) => {
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationKey: [NAME_SPACE, 'template', 'export'],
|
mutationKey: [NAME_SPACE, 'dsl-export'],
|
||||||
mutationFn: (pipelineId: string) => {
|
mutationFn: (request: ExportPipelineDSLRequest) => {
|
||||||
return get<ExportPipelineDSLResponse>(`/rag/pipeline/${pipelineId}`)
|
return get<ExportPipelineDSLResponse>(`/rag/pipeline/${request.pipeline_id}/export`, {
|
||||||
|
params: {
|
||||||
|
include_secret: !!request.include_secret,
|
||||||
|
},
|
||||||
|
})
|
||||||
},
|
},
|
||||||
...mutationOptions,
|
...mutationOptions,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: replace with real API
|
|
||||||
export const useImportPipelineDSL = (
|
export const useImportPipelineDSL = (
|
||||||
mutationOptions: MutationOptions<ImportPipelineDSLResponse, Error, ImportPipelineDSLRequest> = {},
|
mutationOptions: MutationOptions<ImportPipelineDSLResponse, Error, ImportPipelineDSLRequest> = {},
|
||||||
) => {
|
) => {
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationKey: [NAME_SPACE, 'template', 'import'],
|
mutationKey: [NAME_SPACE, 'dsl-import'],
|
||||||
mutationFn: (request: ImportPipelineDSLRequest) => {
|
mutationFn: (request: ImportPipelineDSLRequest) => {
|
||||||
return post<ImportPipelineDSLResponse>('/rag/pipeline/import', { body: request })
|
return post<ImportPipelineDSLResponse>('/rag/pipeline/imports', { body: request })
|
||||||
},
|
},
|
||||||
...mutationOptions,
|
...mutationOptions,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const useImportPipelineDSLConfirm = (
|
||||||
|
mutationOptions: MutationOptions<ImportPipelineDSLConfirmResponse, Error, ImportPipelineDSLConfirmRequest> = {},
|
||||||
|
) => {
|
||||||
|
return useMutation({
|
||||||
|
mutationKey: [NAME_SPACE, 'dsl-import-confirm'],
|
||||||
|
mutationFn: (request: ImportPipelineDSLConfirmRequest) => {
|
||||||
|
return post<ImportPipelineDSLConfirmResponse>('/rag/pipeline/import/confirm', { body: request })
|
||||||
|
},
|
||||||
|
...mutationOptions,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useCheckPipelineDependencies = (
|
||||||
|
mutationOptions: MutationOptions<PipelineCheckDependenciesResponse, Error, string> = {},
|
||||||
|
) => {
|
||||||
|
return useMutation({
|
||||||
|
mutationKey: [NAME_SPACE, 'check-dependencies'],
|
||||||
|
mutationFn: (pipelineId: string) => {
|
||||||
|
return post<PipelineCheckDependenciesResponse>(`/rag/pipelines/imports/${pipelineId}/check-dependencies`)
|
||||||
|
},
|
||||||
|
...mutationOptions,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the config of shared input fields
|
||||||
export const usePipelineProcessingParams = (pipelineId: string) => {
|
export const usePipelineProcessingParams = (pipelineId: string) => {
|
||||||
return useQuery<PipelineProcessingParamsResponse>({
|
return useQuery<PipelineProcessingParamsResponse>({
|
||||||
queryKey: [NAME_SPACE, 'pipeline-processing-params', pipelineId],
|
queryKey: [NAME_SPACE, 'pipeline-processing-params', pipelineId],
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user