From d84aaff825e24a3bcd2c807ce8e2f799bb990a63 Mon Sep 17 00:00:00 2001 From: yyh Date: Wed, 4 Feb 2026 14:33:51 +0800 Subject: [PATCH] feat: add loading state to Publish button during workflow publishing Leverage React Query mutation's isPending to disable the Publish button, header trigger, and keyboard shortcut while a publish is in progress, preventing duplicate submissions even when the menu is closed and reopened. --- .../components/app/app-publisher/index.tsx | 28 +++++++++++-------- .../workflow-header/features-trigger.tsx | 3 +- web/i18n/en-US/workflow.json | 1 + web/i18n/zh-Hans/workflow.json | 1 + 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/web/app/components/app/app-publisher/index.tsx b/web/app/components/app/app-publisher/index.tsx index ab7f442ebf..54f3546fd8 100644 --- a/web/app/components/app/app-publisher/index.tsx +++ b/web/app/components/app/app-publisher/index.tsx @@ -127,6 +127,7 @@ export type AppPublisherProps = { missingStartNode?: boolean hasTriggerNode?: boolean // Whether workflow currently contains any trigger nodes (used to hide missing-start CTA when triggers exist). startNodeLimitExceeded?: boolean + publishLoading?: boolean } const PUBLISH_SHORTCUT = ['ctrl', '⇧', 'P'] @@ -150,6 +151,7 @@ const AppPublisher = ({ missingStartNode = false, hasTriggerNode = false, startNodeLimitExceeded = false, + publishLoading = false, }: AppPublisherProps) => { const { t } = useTranslation() @@ -295,7 +297,7 @@ const AppPublisher = ({ useKeyPress(`${getKeyboardKeyCodeBySystem('ctrl')}.shift.p`, (e) => { e.preventDefault() - if (publishDisabled || published) + if (publishDisabled || published || publishLoading) return handlePublish() }, { exactMatch: true, useCapture: true }) @@ -349,7 +351,8 @@ const AppPublisher = ({ {showStartNodeLimitHint && ( diff --git a/web/app/components/workflow-app/components/workflow-header/features-trigger.tsx b/web/app/components/workflow-app/components/workflow-header/features-trigger.tsx index fdfb895e2c..d313a271e7 100644 --- a/web/app/components/workflow-app/components/workflow-header/features-trigger.tsx +++ b/web/app/components/workflow-app/components/workflow-header/features-trigger.tsx @@ -136,7 +136,7 @@ const FeaturesTrigger = () => { } }, [appID, setAppDetail]) - const { mutateAsync: publishWorkflow } = usePublishWorkflow() + const { mutateAsync: publishWorkflow, isPending: isPublishing } = usePublishWorkflow() // const { validateBeforeRun } = useWorkflowRunValidation() const needWarningNodes = useChecklist(nodes, edges) @@ -229,6 +229,7 @@ const FeaturesTrigger = () => { hasTriggerNode, startNodeLimitExceeded, publishDisabled: !hasWorkflowNodes || startNodeLimitExceeded, + publishLoading: isPublishing, }} /> diff --git a/web/i18n/en-US/workflow.json b/web/i18n/en-US/workflow.json index f0b8a85c92..666d7d8507 100644 --- a/web/i18n/en-US/workflow.json +++ b/web/i18n/en-US/workflow.json @@ -223,6 +223,7 @@ "common.publishUpdate": "Publish Update", "common.published": "Published", "common.publishedAt": "Published", + "common.publishing": "Publishing...", "common.redo": "Redo", "common.restart": "Restart", "common.restore": "Restore", diff --git a/web/i18n/zh-Hans/workflow.json b/web/i18n/zh-Hans/workflow.json index 0778b66b65..012b746183 100644 --- a/web/i18n/zh-Hans/workflow.json +++ b/web/i18n/zh-Hans/workflow.json @@ -221,6 +221,7 @@ "common.publishUpdate": "发布更新", "common.published": "已发布", "common.publishedAt": "发布于", + "common.publishing": "发布中...", "common.redo": "重做", "common.restart": "重新开始", "common.restore": "恢复",