feat: introduce trigger functionality (#27644)

Signed-off-by: lyzno1 <yuanyouhuilyz@gmail.com>
Co-authored-by: Stream <Stream_2@qq.com>
Co-authored-by: lyzno1 <92089059+lyzno1@users.noreply.github.com>
Co-authored-by: zhsama <torvalds@linux.do>
Co-authored-by: Harry <xh001x@hotmail.com>
Co-authored-by: lyzno1 <yuanyouhuilyz@gmail.com>
Co-authored-by: yessenia <yessenia.contact@gmail.com>
Co-authored-by: hjlarry <hjlarry@163.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: WTW0313 <twwu@dify.ai>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Yeuoly
2025-11-12 17:59:37 +08:00
committed by GitHub
parent ca7794305b
commit b76e17b25d
785 changed files with 41186 additions and 3725 deletions

View File

@@ -26,11 +26,11 @@ import { fetchWorkflowDraft } from '@/service/workflow'
import ContentDialog from '@/app/components/base/content-dialog'
import Button from '@/app/components/base/button'
import CardView from '@/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/card-view'
import Divider from '../base/divider'
import type { Operation } from './app-operations'
import AppOperations from './app-operations'
import dynamic from 'next/dynamic'
import cn from '@/utils/classnames'
import { AppModeEnum } from '@/types/app'
const SwitchAppModal = dynamic(() => import('@/app/components/app/switch-app-modal'), {
ssr: false,
@@ -158,7 +158,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
const exportCheck = async () => {
if (!appDetail)
return
if (appDetail.mode !== 'workflow' && appDetail.mode !== 'advanced-chat') {
if (appDetail.mode !== AppModeEnum.WORKFLOW && appDetail.mode !== AppModeEnum.ADVANCED_CHAT) {
onExport()
return
}
@@ -208,7 +208,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
if (!appDetail)
return null
const operations = [
const primaryOperations = [
{
id: 'edit',
title: t('app.editApp'),
@@ -235,7 +235,11 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
icon: <RiFileDownloadLine />,
onClick: exportCheck,
},
(appDetail.mode !== 'agent-chat' && (appDetail.mode === 'advanced-chat' || appDetail.mode === 'workflow')) ? {
]
const secondaryOperations: Operation[] = [
// Import DSL (conditional)
...(appDetail.mode !== AppModeEnum.AGENT_CHAT && (appDetail.mode === AppModeEnum.ADVANCED_CHAT || appDetail.mode === AppModeEnum.WORKFLOW)) ? [{
id: 'import',
title: t('workflow.common.importDSL'),
icon: <RiFileUploadLine />,
@@ -244,18 +248,39 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
onDetailExpand?.(false)
setShowImportDSLModal(true)
},
} : undefined,
(appDetail.mode !== 'agent-chat' && (appDetail.mode === 'completion' || appDetail.mode === 'chat')) ? {
id: 'switch',
title: t('app.switch'),
icon: <RiExchange2Line />,
}] : [],
// Divider
{
id: 'divider-1',
title: '',
icon: <></>,
onClick: () => { /* divider has no action */ },
type: 'divider' as const,
},
// Delete operation
{
id: 'delete',
title: t('common.operation.delete'),
icon: <RiDeleteBinLine />,
onClick: () => {
setOpen(false)
onDetailExpand?.(false)
setShowSwitchModal(true)
setShowConfirmDelete(true)
},
} : undefined,
].filter((op): op is Operation => Boolean(op))
},
]
// Keep the switch operation separate as it's not part of the main operations
const switchOperation = (appDetail.mode !== AppModeEnum.AGENT_CHAT && (appDetail.mode === AppModeEnum.COMPLETION || appDetail.mode === AppModeEnum.CHAT)) ? {
id: 'switch',
title: t('app.switch'),
icon: <RiExchange2Line />,
onClick: () => {
setOpen(false)
onDetailExpand?.(false)
setShowSwitchModal(true)
},
} : null
return (
<div>
@@ -298,7 +323,12 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
<div className='flex w-full'>
<div className='system-md-semibold truncate whitespace-nowrap text-text-secondary'>{appDetail.name}</div>
</div>
<div className='system-2xs-medium-uppercase whitespace-nowrap text-text-tertiary'>{appDetail.mode === 'advanced-chat' ? t('app.types.advanced') : appDetail.mode === 'agent-chat' ? t('app.types.agent') : appDetail.mode === 'chat' ? t('app.types.chatbot') : appDetail.mode === 'completion' ? t('app.types.completion') : t('app.types.workflow')}</div>
<div className='system-2xs-medium-uppercase whitespace-nowrap text-text-tertiary'>
{appDetail.mode === AppModeEnum.ADVANCED_CHAT ? t('app.types.advanced')
: appDetail.mode === AppModeEnum.AGENT_CHAT ? t('app.types.agent')
: appDetail.mode === AppModeEnum.CHAT ? t('app.types.chatbot')
: appDetail.mode === AppModeEnum.COMPLETION ? t('app.types.completion')
: t('app.types.workflow')}</div>
</div>
)}
</div>
@@ -323,7 +353,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
/>
<div className='flex flex-1 flex-col items-start justify-center overflow-hidden'>
<div className='system-md-semibold w-full truncate text-text-secondary'>{appDetail.name}</div>
<div className='system-2xs-medium-uppercase text-text-tertiary'>{appDetail.mode === 'advanced-chat' ? t('app.types.advanced') : appDetail.mode === 'agent-chat' ? t('app.types.agent') : appDetail.mode === 'chat' ? t('app.types.chatbot') : appDetail.mode === 'completion' ? t('app.types.completion') : t('app.types.workflow')}</div>
<div className='system-2xs-medium-uppercase text-text-tertiary'>{appDetail.mode === AppModeEnum.ADVANCED_CHAT ? t('app.types.advanced') : appDetail.mode === AppModeEnum.AGENT_CHAT ? t('app.types.agent') : appDetail.mode === AppModeEnum.CHAT ? t('app.types.chatbot') : appDetail.mode === AppModeEnum.COMPLETION ? t('app.types.completion') : t('app.types.workflow')}</div>
</div>
</div>
{/* description */}
@@ -333,7 +363,8 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
{/* operations */}
<AppOperations
gap={4}
operations={operations}
primaryOperations={primaryOperations}
secondaryOperations={secondaryOperations}
/>
</div>
<CardView
@@ -341,22 +372,20 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
isInPanel={true}
className='flex flex-1 flex-col gap-2 overflow-auto px-2 py-1'
/>
<Divider />
<div className='flex min-h-fit shrink-0 flex-col items-start justify-center gap-3 self-stretch pb-2'>
<Button
size={'medium'}
variant={'ghost'}
className='gap-0.5'
onClick={() => {
setOpen(false)
onDetailExpand?.(false)
setShowConfirmDelete(true)
}}
>
<RiDeleteBinLine className='h-4 w-4 text-text-tertiary' />
<span className='system-sm-medium text-text-tertiary'>{t('common.operation.deleteApp')}</span>
</Button>
</div>
{/* Switch operation (if available) */}
{switchOperation && (
<div className='flex min-h-fit shrink-0 flex-col items-start justify-center gap-3 self-stretch pb-2'>
<Button
size={'medium'}
variant={'ghost'}
className='gap-0.5'
onClick={switchOperation.onClick}
>
{switchOperation.icon}
<span className='system-sm-medium text-text-tertiary'>{switchOperation.title}</span>
</Button>
</div>
)}
</ContentDialog>
{showSwitchModal && (
<SwitchAppModal