diff --git a/web/app/components/snippets/components/snippet-main.tsx b/web/app/components/snippets/components/snippet-main.tsx
index 770404acca..795d644752 100644
--- a/web/app/components/snippets/components/snippet-main.tsx
+++ b/web/app/components/snippets/components/snippet-main.tsx
@@ -23,6 +23,8 @@ import { useStore as useAppStore } from '@/app/components/app/store'
import { toast } from '@/app/components/base/ui/toast'
import Evaluation from '@/app/components/evaluation'
import { WorkflowWithInnerContext } from '@/app/components/workflow'
+import { useAvailableNodesMetaData } from '@/app/components/workflow-app/hooks'
+import { BlockEnum } from '@/app/components/workflow/types'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import { useConfigsMap } from '../hooks/use-configs-map'
import { useNodesSyncDraft } from '../hooks/use-nodes-sync-draft'
@@ -66,6 +68,25 @@ const SnippetMain = ({
} = useNodesSyncDraft(snippetId)
const { handleRefreshWorkflowDraft } = useSnippetRefreshDraft(snippetId)
const configsMap = useConfigsMap(snippetId)
+ const workflowAvailableNodesMetaData = useAvailableNodesMetaData()
+ const availableNodesMetaData = useMemo(() => {
+ const nodes = workflowAvailableNodesMetaData.nodes.filter(node =>
+ node.metaData.type !== BlockEnum.HumanInput && node.metaData.type !== BlockEnum.End)
+
+ if (!workflowAvailableNodesMetaData.nodesMap)
+ return { nodes }
+
+ const {
+ [BlockEnum.HumanInput]: _humanInput,
+ [BlockEnum.End]: _end,
+ ...nodesMap
+ } = workflowAvailableNodesMetaData.nodesMap
+
+ return {
+ nodes,
+ nodesMap,
+ }
+ }, [workflowAvailableNodesMetaData])
const setAppSidebarExpand = useAppStore(state => state.setAppSidebarExpand)
const {
editingField,
@@ -150,9 +171,10 @@ const SnippetMain = ({
doSyncWorkflowDraft,
syncWorkflowDraftWhenPageClose,
handleRefreshWorkflowDraft,
+ availableNodesMetaData,
configsMap,
}
- }, [configsMap, doSyncWorkflowDraft, handleRefreshWorkflowDraft, syncWorkflowDraftWhenPageClose])
+ }, [availableNodesMetaData, configsMap, doSyncWorkflowDraft, handleRefreshWorkflowDraft, syncWorkflowDraftWhenPageClose])
return (
@@ -190,7 +212,7 @@ const SnippetMain = ({
nodes={nodes}
edges={edges}
viewport={viewport ?? graph.viewport}
- hooksStore={hooksStore}
+ hooksStore={hooksStore as any}
>
{
const { t } = useTranslation()
const shouldShowStartTab = !noStart
- const shouldDisableStartTab = !forceEnableStartTab && hasUserInputNode
+ const shouldDisableStartTab = disableStartTab || (!forceEnableStartTab && hasUserInputNode)
+ const startDisabledTip = disableStartTab
+ ? t('tabs.startNotSupportedTip', { ns: 'workflow' })
+ : t('tabs.startDisabledTip', { ns: 'workflow' })
const tabs = useMemo(() => {
const tabConfigs = [{
key: TabsEnum.Blocks,
@@ -71,6 +76,7 @@ export const useTabs = ({
name: t('tabs.start', { ns: 'workflow' }),
show: shouldShowStartTab,
disabled: shouldDisableStartTab,
+ disabledTip: shouldDisableStartTab ? startDisabledTip : undefined,
}, {
key: TabsEnum.Snippets,
name: t('tabs.snippets', { ns: 'workflow' }),
@@ -78,7 +84,7 @@ export const useTabs = ({
}]
return tabConfigs.filter(tab => tab.show)
- }, [t, noBlocks, noSources, noTools, shouldShowStartTab, shouldDisableStartTab])
+ }, [t, noBlocks, noSources, noTools, shouldShowStartTab, shouldDisableStartTab, startDisabledTip])
const getValidTabKey = useCallback((targetKey?: TabsEnum) => {
if (!targetKey)
diff --git a/web/app/components/workflow/block-selector/main.tsx b/web/app/components/workflow/block-selector/main.tsx
index 9511d02e16..cf647d9d67 100644
--- a/web/app/components/workflow/block-selector/main.tsx
+++ b/web/app/components/workflow/block-selector/main.tsx
@@ -30,7 +30,9 @@ import {
PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem'
import SearchBox from '@/app/components/plugins/marketplace/search-box'
+import { useHooksStore } from '@/app/components/workflow/hooks-store'
import useNodes from '@/app/components/workflow/store/workflow/use-nodes'
+import { FlowType } from '@/types/common'
import { BlockEnum, isTriggerNode } from '../types'
import { useTabs } from './hooks'
import Snippets from './snippets'
@@ -89,6 +91,7 @@ const NodeSelector: FC = ({
}) => {
const { t } = useTranslation()
const nodes = useNodes()
+ const flowType = useHooksStore(s => s.configsMap?.flowType)
const [searchText, setSearchText] = useState('')
const [snippetsLoading, setSnippetsLoading] = useState(() => Boolean(openFromProps) && defaultActiveTab === TabsEnum.Snippets)
const [tags, setTags] = useState([])
@@ -122,6 +125,7 @@ const NodeSelector: FC = ({
// Default rule: user input option is only available when no Start node nor Trigger node exists on canvas.
const defaultAllowUserInputSelection = !hasUserInputNode && !hasTriggerNode
const canSelectUserInput = allowUserInputSelection ?? defaultAllowUserInputSelection
+ const disableStartTab = flowType === FlowType.snippet
const {
activeTab,
setActiveTab,
@@ -133,6 +137,7 @@ const NodeSelector: FC = ({
noStart: !showStartTab,
defaultActiveTab,
hasUserInputNode,
+ disableStartTab,
forceEnableStartTab,
})
const open = openFromProps === undefined ? localOpen : openFromProps
diff --git a/web/app/components/workflow/block-selector/tabs.tsx b/web/app/components/workflow/block-selector/tabs.tsx
index b1ca318fd2..b0658d371c 100644
--- a/web/app/components/workflow/block-selector/tabs.tsx
+++ b/web/app/components/workflow/block-selector/tabs.tsx
@@ -34,6 +34,7 @@ export type TabsProps = {
key: TabsEnum
name: string
disabled?: boolean
+ disabledTip?: string
}>
filterElem: React.ReactNode
noBlocks?: boolean
@@ -225,7 +226,7 @@ const Tabs: FC = ({
tab={tab}
activeTab={activeTab}
onActiveTabChange={onActiveTabChange}
- disabledTip={disabledTip}
+ disabledTip={tab.disabledTip || disabledTip}
/>
))
}
diff --git a/web/eslint-suppressions.json b/web/eslint-suppressions.json
index 98d2976f8e..d787164407 100644
--- a/web/eslint-suppressions.json
+++ b/web/eslint-suppressions.json
@@ -177,6 +177,11 @@
"count": 2
}
},
+ "app/(commonLayout)/snippets/[snippetId]/page.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/(humanInputLayout)/form/[token]/form.tsx": {
"react/set-state-in-effect": {
"count": 1
@@ -4917,6 +4922,11 @@
"count": 2
}
},
+ "app/components/evaluation/index.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/explore/banner/banner-item.tsx": {
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
@@ -6686,6 +6696,11 @@
"count": 2
}
},
+ "app/components/snippets/components/snippet-main.tsx": {
+ "ts/no-explicit-any": {
+ "count": 1
+ }
+ },
"app/components/tools/edit-custom-collection-modal/config-credentials.tsx": {
"no-restricted-imports": {
"count": 1
@@ -10487,6 +10502,11 @@
"count": 7
}
},
+ "service/use-evaluation.ts": {
+ "no-barrel-files/no-barrel-files": {
+ "count": 2
+ }
+ },
"service/use-flow.ts": {
"react/no-unnecessary-use-prefix": {
"count": 1
diff --git a/web/i18n/en-US/workflow.json b/web/i18n/en-US/workflow.json
index a6803329ff..586db51ad5 100644
--- a/web/i18n/en-US/workflow.json
+++ b/web/i18n/en-US/workflow.json
@@ -1148,6 +1148,7 @@
"tabs.sources": "Sources",
"tabs.start": "Start",
"tabs.startDisabledTip": "Trigger node and user input node are mutually exclusive.",
+ "tabs.startNotSupportedTip": "The Start tab is not supported in snippets.",
"tabs.tools": "Tools",
"tabs.transform": "Transform",
"tabs.usePlugin": "Select tool",
diff --git a/web/i18n/zh-Hans/workflow.json b/web/i18n/zh-Hans/workflow.json
index e98af59a4c..ae8fd5305d 100644
--- a/web/i18n/zh-Hans/workflow.json
+++ b/web/i18n/zh-Hans/workflow.json
@@ -1148,6 +1148,7 @@
"tabs.sources": "数据源",
"tabs.start": "开始",
"tabs.startDisabledTip": "触发节点与用户输入节点互斥。",
+ "tabs.startNotSupportedTip": "Snippet 暂不支持 Start 标签。",
"tabs.tools": "工具",
"tabs.transform": "转换",
"tabs.usePlugin": "选择工具",