mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-07-25 08:34:29 +08:00
This commit is contained in:
parent
d38a2c95fb
commit
40b31bafd5
@ -0,0 +1,46 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import Button from '@/app/components/base/button'
|
||||
|
||||
type DSLConfirmModalProps = {
|
||||
versions?: {
|
||||
importedVersion: string
|
||||
systemVersion: string
|
||||
}
|
||||
onCancel: () => void
|
||||
onConfirm: () => void
|
||||
confirmDisabled?: boolean
|
||||
}
|
||||
const DSLConfirmModal = ({
|
||||
versions = { importedVersion: '', systemVersion: '' },
|
||||
onCancel,
|
||||
onConfirm,
|
||||
confirmDisabled = false,
|
||||
}: DSLConfirmModalProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isShow
|
||||
onClose={() => onCancel()}
|
||||
className='w-[480px]'
|
||||
>
|
||||
<div className='flex flex-col items-start gap-2 self-stretch pb-4'>
|
||||
<div className='title-2xl-semi-bold text-text-primary'>{t('app.newApp.appCreateDSLErrorTitle')}</div>
|
||||
<div className='system-md-regular flex grow flex-col text-text-secondary'>
|
||||
<div>{t('app.newApp.appCreateDSLErrorPart1')}</div>
|
||||
<div>{t('app.newApp.appCreateDSLErrorPart2')}</div>
|
||||
<br />
|
||||
<div>{t('app.newApp.appCreateDSLErrorPart3')}<span className='system-md-medium'>{versions.importedVersion}</span></div>
|
||||
<div>{t('app.newApp.appCreateDSLErrorPart4')}<span className='system-md-medium'>{versions.systemVersion}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex items-start justify-end gap-2 self-stretch pt-6'>
|
||||
<Button variant='secondary' onClick={() => onCancel()}>{t('app.newApp.Cancel')}</Button>
|
||||
<Button variant='primary' destructive onClick={onConfirm} disabled={confirmDisabled}>{t('app.newApp.Confirm')}</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default DSLConfirmModal
|
@ -1,12 +1,10 @@
|
||||
'use client'
|
||||
|
||||
import React, { useMemo, useState } from 'react'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import useSWR from 'swr'
|
||||
import { useDebounceFn } from 'ahooks'
|
||||
import Toast from '../../base/toast'
|
||||
import s from './style.module.css'
|
||||
import cn from '@/utils/classnames'
|
||||
import ExploreContext from '@/context/explore-context'
|
||||
@ -14,17 +12,17 @@ import type { App } from '@/models/explore'
|
||||
import Category from '@/app/components/explore/category'
|
||||
import AppCard from '@/app/components/explore/app-card'
|
||||
import { fetchAppDetail, fetchAppList } from '@/service/explore'
|
||||
import { importDSL } from '@/service/apps'
|
||||
import { useTabSearchParams } from '@/hooks/use-tab-searchparams'
|
||||
import CreateAppModal from '@/app/components/explore/create-app-modal'
|
||||
import AppTypeSelector from '@/app/components/app/type-selector'
|
||||
import type { CreateAppModalProps } from '@/app/components/explore/create-app-modal'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import { getRedirection } from '@/utils/app-redirection'
|
||||
import Input from '@/app/components/base/input'
|
||||
import { DSLImportMode } from '@/models/app'
|
||||
import {
|
||||
DSLImportMode,
|
||||
} from '@/models/app'
|
||||
import { useImportDSL } from '@/hooks/use-import-dsl'
|
||||
import DSLConfirmModal from '@/app/components/app/create-from-dsl-modal/dsl-confirm-modal'
|
||||
|
||||
type AppsProps = {
|
||||
pageType?: PageType
|
||||
@ -41,8 +39,6 @@ const Apps = ({
|
||||
onSuccess,
|
||||
}: AppsProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { isCurrentWorkspaceEditor } = useAppContext()
|
||||
const { push } = useRouter()
|
||||
const { hasEditPermission } = useContext(ExploreContext)
|
||||
const allCategoriesEn = t('explore.apps.allCategories', { lng: 'en' })
|
||||
|
||||
@ -117,6 +113,14 @@ const Apps = ({
|
||||
|
||||
const [currApp, setCurrApp] = React.useState<App | null>(null)
|
||||
const [isShowCreateModal, setIsShowCreateModal] = React.useState(false)
|
||||
|
||||
const {
|
||||
handleImportDSL,
|
||||
handleImportDSLConfirm,
|
||||
versions,
|
||||
isFetching,
|
||||
} = useImportDSL()
|
||||
const [showDSLConfirmModal, setShowDSLConfirmModal] = useState(false)
|
||||
const onCreate: CreateAppModalProps['onConfirm'] = async ({
|
||||
name,
|
||||
icon_type,
|
||||
@ -127,31 +131,31 @@ const Apps = ({
|
||||
const { export_data } = await fetchAppDetail(
|
||||
currApp?.app.id as string,
|
||||
)
|
||||
try {
|
||||
const app = await importDSL({
|
||||
mode: DSLImportMode.YAML_CONTENT,
|
||||
yaml_content: export_data,
|
||||
name,
|
||||
icon_type,
|
||||
icon,
|
||||
icon_background,
|
||||
description,
|
||||
})
|
||||
setIsShowCreateModal(false)
|
||||
Toast.notify({
|
||||
type: 'success',
|
||||
message: t('app.newApp.appCreated'),
|
||||
})
|
||||
if (onSuccess)
|
||||
onSuccess()
|
||||
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
|
||||
getRedirection(isCurrentWorkspaceEditor, { id: app.app_id }, push)
|
||||
}
|
||||
catch (e) {
|
||||
Toast.notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||
const payload = {
|
||||
mode: DSLImportMode.YAML_CONTENT,
|
||||
yaml_content: export_data,
|
||||
name,
|
||||
icon_type,
|
||||
icon,
|
||||
icon_background,
|
||||
description,
|
||||
}
|
||||
await handleImportDSL(payload, {
|
||||
onSuccess: () => {
|
||||
setIsShowCreateModal(false)
|
||||
},
|
||||
onPending: () => {
|
||||
setShowDSLConfirmModal(true)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const onConfirmDSL = useCallback(async () => {
|
||||
await handleImportDSLConfirm({
|
||||
onSuccess,
|
||||
})
|
||||
}, [handleImportDSLConfirm, onSuccess])
|
||||
|
||||
if (!categories || categories.length === 0) {
|
||||
return (
|
||||
<div className="flex h-full items-center">
|
||||
@ -234,9 +238,20 @@ const Apps = ({
|
||||
appDescription={currApp?.app.description || ''}
|
||||
show={isShowCreateModal}
|
||||
onConfirm={onCreate}
|
||||
confirmDisabled={isFetching}
|
||||
onHide={() => setIsShowCreateModal(false)}
|
||||
/>
|
||||
)}
|
||||
{
|
||||
showDSLConfirmModal && (
|
||||
<DSLConfirmModal
|
||||
versions={versions}
|
||||
onCancel={() => setShowDSLConfirmModal(false)}
|
||||
onConfirm={onConfirmDSL}
|
||||
confirmDisabled={isFetching}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ export type CreateAppModalProps = {
|
||||
description: string
|
||||
use_icon_as_answer_icon?: boolean
|
||||
}) => Promise<void>
|
||||
confirmDisabled?: boolean
|
||||
onHide: () => void
|
||||
}
|
||||
|
||||
@ -48,6 +49,7 @@ const CreateAppModal = ({
|
||||
appMode,
|
||||
appUseIconAsAnswerIcon,
|
||||
onConfirm,
|
||||
confirmDisabled,
|
||||
onHide,
|
||||
}: CreateAppModalProps) => {
|
||||
const { t } = useTranslation()
|
||||
@ -145,7 +147,7 @@ const CreateAppModal = ({
|
||||
{!isEditModal && isAppsFull && <AppsFull loc='app-explore-create' />}
|
||||
</div>
|
||||
<div className='flex flex-row-reverse'>
|
||||
<Button disabled={!isEditModal && isAppsFull} className='w-24 ml-2' variant='primary' onClick={submit}>{!isEditModal ? t('common.operation.create') : t('common.operation.save')}</Button>
|
||||
<Button disabled={(!isEditModal && isAppsFull) || !name.trim() || confirmDisabled} className='w-24 ml-2' variant='primary' onClick={submit}>{!isEditModal ? t('common.operation.create') : t('common.operation.save')}</Button>
|
||||
<Button className='w-24' onClick={onHide}>{t('common.operation.cancel')}</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
158
web/hooks/use-import-dsl.ts
Normal file
158
web/hooks/use-import-dsl.ts
Normal file
@ -0,0 +1,158 @@
|
||||
import {
|
||||
useCallback,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import type {
|
||||
DSLImportMode,
|
||||
DSLImportResponse,
|
||||
} from '@/models/app'
|
||||
import { DSLImportStatus } from '@/models/app'
|
||||
import {
|
||||
importDSL,
|
||||
importDSLConfirm,
|
||||
} from '@/service/apps'
|
||||
import type { AppIconType } from '@/types/app'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
import { getRedirection } from '@/utils/app-redirection'
|
||||
import { useSelector } from '@/context/app-context'
|
||||
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
|
||||
|
||||
type DSLPayload = {
|
||||
mode: DSLImportMode
|
||||
yaml_content?: string
|
||||
yaml_url?: string
|
||||
name?: string
|
||||
icon_type?: AppIconType
|
||||
icon?: string
|
||||
icon_background?: string
|
||||
description?: string
|
||||
}
|
||||
type ResponseCallback = {
|
||||
onSuccess?: () => void
|
||||
onPending?: (payload: DSLImportResponse) => void
|
||||
onFailed?: () => void
|
||||
}
|
||||
export const useImportDSL = () => {
|
||||
const { t } = useTranslation()
|
||||
const { notify } = useToastContext()
|
||||
const [isFetching, setIsFetching] = useState(false)
|
||||
const isCurrentWorkspaceEditor = useSelector(s => s.isCurrentWorkspaceEditor)
|
||||
const { push } = useRouter()
|
||||
const [versions, setVersions] = useState<{ importedVersion: string; systemVersion: string }>()
|
||||
const importIdRef = useRef<string>('')
|
||||
|
||||
const handleImportDSL = useCallback(async (
|
||||
payload: DSLPayload,
|
||||
{
|
||||
onSuccess,
|
||||
onPending,
|
||||
onFailed,
|
||||
}: ResponseCallback,
|
||||
) => {
|
||||
if (isFetching)
|
||||
return
|
||||
setIsFetching(true)
|
||||
|
||||
try {
|
||||
const response = await importDSL(payload)
|
||||
|
||||
if (!response)
|
||||
return
|
||||
|
||||
const {
|
||||
id,
|
||||
status,
|
||||
app_id,
|
||||
imported_dsl_version,
|
||||
current_dsl_version,
|
||||
} = response
|
||||
|
||||
if (status === DSLImportStatus.COMPLETED || status === DSLImportStatus.COMPLETED_WITH_WARNINGS) {
|
||||
if (!app_id)
|
||||
return
|
||||
|
||||
notify({
|
||||
type: status === DSLImportStatus.COMPLETED ? 'success' : 'warning',
|
||||
message: t(status === DSLImportStatus.COMPLETED ? 'app.newApp.appCreated' : 'app.newApp.caution'),
|
||||
children: status === DSLImportStatus.COMPLETED_WITH_WARNINGS && t('app.newApp.appCreateDSLWarning'),
|
||||
})
|
||||
onSuccess?.()
|
||||
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
|
||||
getRedirection(isCurrentWorkspaceEditor, { id: app_id }, push)
|
||||
}
|
||||
else if (status === DSLImportStatus.PENDING) {
|
||||
setVersions({
|
||||
importedVersion: imported_dsl_version ?? '',
|
||||
systemVersion: current_dsl_version ?? '',
|
||||
})
|
||||
importIdRef.current = id
|
||||
onPending?.(response)
|
||||
}
|
||||
else {
|
||||
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||
onFailed?.()
|
||||
}
|
||||
}
|
||||
catch {
|
||||
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||
onFailed?.()
|
||||
}
|
||||
finally {
|
||||
setIsFetching(false)
|
||||
}
|
||||
}, [t, notify, isCurrentWorkspaceEditor, push, isFetching])
|
||||
|
||||
const handleImportDSLConfirm = useCallback(async (
|
||||
{
|
||||
onSuccess,
|
||||
onFailed,
|
||||
}: Pick<ResponseCallback, 'onSuccess' | 'onFailed'>,
|
||||
) => {
|
||||
if (isFetching)
|
||||
return
|
||||
setIsFetching(true)
|
||||
if (!importIdRef.current)
|
||||
return
|
||||
|
||||
try {
|
||||
const response = await importDSLConfirm({
|
||||
import_id: importIdRef.current,
|
||||
})
|
||||
|
||||
const { status, app_id } = response
|
||||
if (!app_id)
|
||||
return
|
||||
|
||||
if (status === DSLImportStatus.COMPLETED) {
|
||||
onSuccess?.()
|
||||
notify({
|
||||
type: 'success',
|
||||
message: t('app.newApp.appCreated'),
|
||||
})
|
||||
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
|
||||
getRedirection(isCurrentWorkspaceEditor, { id: app_id! }, push)
|
||||
}
|
||||
else if (status === DSLImportStatus.FAILED) {
|
||||
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||
onFailed?.()
|
||||
}
|
||||
}
|
||||
catch {
|
||||
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||
onFailed?.()
|
||||
}
|
||||
finally {
|
||||
setIsFetching(false)
|
||||
}
|
||||
}, [t, notify, isCurrentWorkspaceEditor, push, isFetching])
|
||||
|
||||
return {
|
||||
handleImportDSL,
|
||||
handleImportDSLConfirm,
|
||||
versions,
|
||||
isFetching,
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user