diff --git a/web/app/components/workflow-app/index.tsx b/web/app/components/workflow-app/index.tsx
index ed16f06212..318666131b 100644
--- a/web/app/components/workflow-app/index.tsx
+++ b/web/app/components/workflow-app/index.tsx
@@ -6,6 +6,7 @@ import { useSearchParams } from 'next/navigation'
import {
useEffect,
useMemo,
+ useState,
} from 'react'
import { useStore as useAppStore } from '@/app/components/app/store'
import { FeaturesProvider } from '@/app/components/base/features'
@@ -15,10 +16,12 @@ import WorkflowWithDefaultContext from '@/app/components/workflow'
import {
WorkflowContextProvider,
} from '@/app/components/workflow/context'
+import SkillMain from '@/app/components/workflow/skill/main'
import { useWorkflowStore } from '@/app/components/workflow/store'
import { useTriggerStatusStore } from '@/app/components/workflow/store/trigger-status'
import {
SupportUploadFileTypes,
+ ViewType,
} from '@/app/components/workflow/types'
import {
initialEdges,
@@ -28,8 +31,8 @@ import { useAppContext } from '@/context/app-context'
import { fetchRunDetail } from '@/service/log'
import { useAppTriggers } from '@/service/use-tools'
import { AppModeEnum } from '@/types/app'
+import ViewPicker from '../workflow/view-picker'
import WorkflowAppMain from './components/workflow-main'
-
import { useGetRunAndTraceUrl } from './hooks/use-get-run-and-trace-url'
import {
useWorkflowInit,
@@ -37,6 +40,8 @@ import {
import { createWorkflowSlice } from './store/workflow/workflow-slice'
const WorkflowAppWithAdditionalContext = () => {
+ const [viewType, setViewType] = useState(ViewType.graph)
+
const {
data,
isLoading,
@@ -200,13 +205,25 @@ const WorkflowAppWithAdditionalContext = () => {
edges={edgesData}
nodes={nodesData}
>
-
-
+
-
+ {viewType === ViewType.graph
+ ? (
+
+
+
+ )
+ : (
+
+ )}
+
)
}
diff --git a/web/app/components/workflow/header/header-in-normal.tsx b/web/app/components/workflow/header/header-in-normal.tsx
index 52ffee4ed5..be4985fb83 100644
--- a/web/app/components/workflow/header/header-in-normal.tsx
+++ b/web/app/components/workflow/header/header-in-normal.tsx
@@ -65,7 +65,7 @@ const HeaderInNormal = ({
return (
-
+
diff --git a/web/app/components/workflow/skill/main.tsx b/web/app/components/workflow/skill/main.tsx
new file mode 100644
index 0000000000..f3ab87de51
--- /dev/null
+++ b/web/app/components/workflow/skill/main.tsx
@@ -0,0 +1,12 @@
+'use client'
+import type { FC } from 'react'
+import * as React from 'react'
+
+const SkillMain: FC = () => {
+ return (
+
+ Main
+
+ )
+}
+export default React.memo(SkillMain)
diff --git a/web/app/components/workflow/types.ts b/web/app/components/workflow/types.ts
index 75c9052bb5..d807334d86 100644
--- a/web/app/components/workflow/types.ts
+++ b/web/app/components/workflow/types.ts
@@ -517,3 +517,8 @@ export type Block = {
title: string
description?: string
}
+
+export enum ViewType {
+ graph = 'graph',
+ skill = 'skill',
+}
diff --git a/web/app/components/workflow/view-picker.tsx b/web/app/components/workflow/view-picker.tsx
new file mode 100644
index 0000000000..66a30d87d5
--- /dev/null
+++ b/web/app/components/workflow/view-picker.tsx
@@ -0,0 +1,48 @@
+'use client'
+
+import type { FC } from 'react'
+import * as React from 'react'
+import { useCallback, useMemo } from 'react'
+import { useTranslation } from 'react-i18next'
+import SegmentedControl from '@/app/components/base/segmented-control'
+import { cn } from '@/utils/classnames'
+import { ViewType } from '../workflow/types'
+
+type ViewPickerProps = {
+ value: ViewType
+ onChange: (value: ViewType) => void
+ className?: string
+}
+
+const ViewPicker: FC
= ({
+ value,
+ onChange,
+ className,
+}) => {
+ const { t } = useTranslation()
+ const options = useMemo(() => ([
+ { value: ViewType.graph, text: t('viewPicker.graph', { ns: 'workflow' }) },
+ { value: ViewType.skill, text: t('viewPicker.skill', { ns: 'workflow' }) },
+ ]), [t])
+
+ const handleChange = useCallback((nextValue: string | number | symbol) => {
+ if (nextValue === value)
+ return
+ onChange(nextValue as ViewType)
+ }, [onChange, value])
+
+ return (
+
+ )
+}
+
+export default React.memo(ViewPicker)
diff --git a/web/i18n/en-US/workflow.json b/web/i18n/en-US/workflow.json
index 407f82452a..744351e5d3 100644
--- a/web/i18n/en-US/workflow.json
+++ b/web/i18n/en-US/workflow.json
@@ -1062,5 +1062,7 @@
"versionHistory.nameThisVersion": "Name this version",
"versionHistory.releaseNotesPlaceholder": "Describe what changed",
"versionHistory.restorationTip": "After version restoration, the current draft will be overwritten.",
- "versionHistory.title": "Versions"
+ "versionHistory.title": "Versions",
+ "viewPicker.graph": "Graph",
+ "viewPicker.skill": "Skill"
}
diff --git a/web/i18n/zh-Hans/workflow.json b/web/i18n/zh-Hans/workflow.json
index b246144712..7f34761111 100644
--- a/web/i18n/zh-Hans/workflow.json
+++ b/web/i18n/zh-Hans/workflow.json
@@ -1056,5 +1056,7 @@
"versionHistory.nameThisVersion": "命名",
"versionHistory.releaseNotesPlaceholder": "请描述变更",
"versionHistory.restorationTip": "版本回滚后,当前草稿将被覆盖。",
- "versionHistory.title": "版本"
+ "versionHistory.title": "版本",
+ "viewPicker.graph": "工作流图",
+ "viewPicker.skill": "技能"
}