feat(web): workflow switch

This commit is contained in:
JzoNg
2026-04-03 14:22:50 +08:00
parent 61e257b2a8
commit 6651c1c5da
3 changed files with 107 additions and 3 deletions

View File

@@ -21,6 +21,11 @@ import {
PortalToFollowElemContent,
PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem'
import {
Tooltip as UITooltip,
TooltipContent as UITooltipContent,
TooltipTrigger as UITooltipTrigger,
} from '@/app/components/base/ui/tooltip'
import UpgradeBtn from '@/app/components/billing/upgrade-btn'
import WorkflowToolConfigureButton from '@/app/components/tools/workflow-tool/configure-button'
import { appDefaultIconBackground } from '@/config'
@@ -31,7 +36,8 @@ import { AccessMode } from '@/models/access-control'
import { useAppWhiteListSubjects, useGetUserCanAccessApp } from '@/service/access-control'
import { fetchAppDetailDirect } from '@/service/apps'
import { fetchInstalledAppList } from '@/service/explore'
import { AppModeEnum } from '@/types/app'
import { useConvertWorkflowTypeMutation } from '@/service/use-apps'
import { AppModeEnum, AppTypeEnum } from '@/types/app'
import { basePath } from '@/utils/var'
import Divider from '../../base/divider'
import Loading from '../../base/loading'
@@ -108,6 +114,21 @@ export type AppPublisherProps = {
const PUBLISH_SHORTCUT = ['ctrl', '⇧', 'P']
const WORKFLOW_TYPE_SWITCH_CONFIG = {
[AppTypeEnum.WORKFLOW]: {
targetType: AppTypeEnum.EVALUATION,
publishLabelKey: 'common.publishAsEvaluationWorkflow',
switchLabelKey: 'common.switchToEvaluationWorkflow',
tipKey: 'common.switchToEvaluationWorkflowTip',
},
[AppTypeEnum.EVALUATION]: {
targetType: AppTypeEnum.WORKFLOW,
publishLabelKey: 'common.publishAsStandardWorkflow',
switchLabelKey: 'common.switchToStandardWorkflow',
tipKey: 'common.switchToStandardWorkflowTip',
},
} as const
const AppPublisher = ({
disabled = false,
publishDisabled = false,
@@ -142,10 +163,13 @@ const AppPublisher = ({
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
const { formatTimeFromNow } = useFormatTimeFromNow()
const { app_base_url: appBaseURL = '', access_token: accessToken = '' } = appDetail?.site ?? {}
const { mutateAsync: convertWorkflowType, isPending: isConvertingWorkflowType } = useConvertWorkflowTypeMutation()
const appMode = (appDetail?.mode !== AppModeEnum.COMPLETION && appDetail?.mode !== AppModeEnum.WORKFLOW) ? AppModeEnum.CHAT : appDetail.mode
const appURL = `${appBaseURL}${basePath}/${appMode}/${accessToken}`
const isChatApp = [AppModeEnum.CHAT, AppModeEnum.AGENT_CHAT, AppModeEnum.COMPLETION].includes(appDetail?.mode || AppModeEnum.CHAT)
const workflowTypeSwitchConfig = appDetail?.type ? WORKFLOW_TYPE_SWITCH_CONFIG[appDetail.type as keyof typeof WORKFLOW_TYPE_SWITCH_CONFIG] : undefined
const isEvaluationWorkflowType = appDetail?.type === AppTypeEnum.EVALUATION
const { data: userCanAccessApp, isLoading: isGettingUserCanAccessApp, refetch } = useGetUserCanAccessApp({ appId: appDetail?.id, enabled: false })
const { data: appAccessSubjects, isLoading: isGettingAppWhiteListSubjects } = useAppWhiteListSubjects(appDetail?.id, open && systemFeatures.webapp_auth.enabled && appDetail?.access_mode === AccessMode.SPECIFIC_GROUPS_MEMBERS)
@@ -236,6 +260,35 @@ const AppPublisher = ({
}
}, [appDetail, setAppDetail])
const handleWorkflowTypeSwitch = useCallback(async () => {
if (!appDetail?.id || !workflowTypeSwitchConfig)
return
try {
await convertWorkflowType({
params: {
appId: appDetail.id,
},
query: {
target_type: workflowTypeSwitchConfig.targetType,
},
})
if (!publishedAt)
await handlePublish()
const latestAppDetail = await fetchAppDetailDirect({
url: '/apps',
id: appDetail.id,
})
setAppDetail(latestAppDetail)
if (publishedAt)
setOpen(false)
}
catch { }
}, [appDetail?.id, convertWorkflowType, handlePublish, publishedAt, setAppDetail, workflowTypeSwitchConfig])
useKeyPress(`${getKeyboardKeyCodeBySystem('ctrl')}.shift.p`, (e) => {
e.preventDefault()
if (publishDisabled || published)
@@ -336,6 +389,45 @@ const AppPublisher = ({
)
}
</Button>
{workflowTypeSwitchConfig && (
<button
type="button"
className="flex h-8 w-full items-center justify-center gap-0.5 rounded-lg px-3 py-2 text-text-tertiary system-sm-medium hover:bg-state-base-hover disabled:cursor-not-allowed disabled:opacity-50"
onClick={handleWorkflowTypeSwitch}
disabled={publishDisabled || published || isConvertingWorkflowType}
>
<span className="px-0.5">
{t(
publishedAt
? workflowTypeSwitchConfig.switchLabelKey
: workflowTypeSwitchConfig.publishLabelKey,
{ ns: 'workflow' },
)}
</span>
<UITooltip>
<UITooltipTrigger
render={(
<span
aria-label={t(workflowTypeSwitchConfig.tipKey, { ns: 'workflow' })}
className="flex h-4 w-4 items-center justify-center text-text-quaternary hover:text-text-tertiary"
onClick={(e) => {
e.preventDefault()
e.stopPropagation()
}}
>
<span className="i-ri-question-line h-3.5 w-3.5" />
</span>
)}
/>
<UITooltipContent
placement="top"
popupClassName="w-[180px]"
>
{t(workflowTypeSwitchConfig.tipKey, { ns: 'workflow' })}
</UITooltipContent>
</UITooltip>
</button>
)}
{showStartNodeLimitHint && (
<div className="mt-3 flex flex-col items-stretch">
<p
@@ -357,9 +449,9 @@ const AppPublisher = ({
</>
)}
</div>
{(systemFeatures.webapp_auth.enabled && (isGettingUserCanAccessApp || isGettingAppWhiteListSubjects))
{!isEvaluationWorkflowType && (systemFeatures.webapp_auth.enabled && (isGettingUserCanAccessApp || isGettingAppWhiteListSubjects))
? <div className="py-2"><Loading /></div>
: (
: !isEvaluationWorkflowType && (
<>
<Divider className="my-0" />
{systemFeatures.webapp_auth.enabled && (

View File

@@ -198,6 +198,8 @@
"common.previewPlaceholder": "Enter content in the box below to start debugging the Chatbot",
"common.processData": "Process Data",
"common.publish": "Publish",
"common.publishAsEvaluationWorkflow": "Publish as Evaluation Workflow",
"common.publishAsStandardWorkflow": "Publish as Standard Workflow",
"common.publishUpdate": "Publish Update",
"common.published": "Published",
"common.publishedAt": "Published",
@@ -213,6 +215,10 @@
"common.searchVar": "Search variable",
"common.setVarValuePlaceholder": "Set variable",
"common.showRunHistory": "Show Run History",
"common.switchToEvaluationWorkflow": "Switch to Evaluation Workflow",
"common.switchToEvaluationWorkflowTip": "Turns this workflow into a custom evaluator for batch testing. Disables public Web App access.",
"common.switchToStandardWorkflow": "Switch to Standard Workflow",
"common.switchToStandardWorkflowTip": "Turns this evaluator back into a standard workflow and restores public Web App access.",
"common.syncingData": "Syncing data, just a few seconds.",
"common.tagBound": "Number of apps using this tag",
"common.undo": "Undo",

View File

@@ -198,6 +198,8 @@
"common.previewPlaceholder": "在下面的框中输入内容开始调试聊天机器人",
"common.processData": "数据处理",
"common.publish": "发布",
"common.publishAsEvaluationWorkflow": "发布为评测工作流",
"common.publishAsStandardWorkflow": "发布为标准工作流",
"common.publishUpdate": "发布更新",
"common.published": "已发布",
"common.publishedAt": "发布于",
@@ -213,6 +215,10 @@
"common.searchVar": "搜索变量",
"common.setVarValuePlaceholder": "设置变量值",
"common.showRunHistory": "显示运行历史",
"common.switchToEvaluationWorkflow": "切换为评测工作流",
"common.switchToEvaluationWorkflowTip": "将当前工作流转换为批量测试用的自定义评测器,并禁用公开 Web App 访问。",
"common.switchToStandardWorkflow": "切换为标准工作流",
"common.switchToStandardWorkflowTip": "将当前评测器转换回标准工作流,并恢复公开 Web App 访问。",
"common.syncingData": "同步数据中,只需几秒钟。",
"common.tagBound": "使用此标签的应用数量",
"common.undo": "撤销",