feat: align workflow view picker layout

This commit is contained in:
yyh
2026-01-22 14:45:14 +08:00
parent 84b4fed3df
commit 4a88ffdf2a
7 changed files with 86 additions and 36 deletions

View File

@ -1,3 +1,4 @@
import type { ReactNode } from 'react'
import type {
PluginDefaultValue,
TriggerDefaultValue,
@ -65,7 +66,11 @@ const getTriggerPluginNodeData = (
}
}
const WorkflowChildren = () => {
type WorkflowChildrenProps = {
headerLeftSlot?: ReactNode
}
const WorkflowChildren = ({ headerLeftSlot }: WorkflowChildrenProps) => {
const { eventEmitter } = useEventEmitterContextContext()
const [secretEnvList, setSecretEnvList] = useState<EnvironmentVariable[]>([])
const showFeaturesPanel = useStore(s => s.showFeaturesPanel)
@ -188,7 +193,7 @@ const WorkflowChildren = () => {
/>
)
}
<WorkflowHeader />
<WorkflowHeader leftSlot={headerLeftSlot} />
<WorkflowPanel />
</>
)

View File

@ -1,3 +1,4 @@
import type { ReactNode } from 'react'
import type { HeaderProps } from '@/app/components/workflow/header'
import {
memo,
@ -12,7 +13,11 @@ import { useIsChatMode } from '../../hooks'
import ChatVariableTrigger from './chat-variable-trigger'
import FeaturesTrigger from './features-trigger'
const WorkflowHeader = () => {
type WorkflowHeaderProps = {
leftSlot?: ReactNode
}
const WorkflowHeader = ({ leftSlot }: WorkflowHeaderProps) => {
const { appDetail, setCurrentLogItem, setShowMessageLogModal } = useAppStore(useShallow(state => ({
appDetail: state.appDetail,
setCurrentLogItem: state.setCurrentLogItem,
@ -37,6 +42,7 @@ const WorkflowHeader = () => {
return {
normal: {
components: {
left: leftSlot,
middle: <FeaturesTrigger />,
chatVariableTrigger: <ChatVariableTrigger />,
},
@ -53,7 +59,7 @@ const WorkflowHeader = () => {
onRestoreSettled: resetWorkflowVersionHistory,
},
}
}, [resetWorkflowVersionHistory, isChatMode, viewHistoryProps])
}, [leftSlot, resetWorkflowVersionHistory, isChatMode, viewHistoryProps])
return (
<Header {...headerProps} />
)

View File

@ -1,3 +1,4 @@
import type { ReactNode } from 'react'
import type { WorkflowProps } from '@/app/components/workflow'
import {
useCallback,
@ -21,11 +22,14 @@ import {
} from '../hooks'
import WorkflowChildren from './workflow-children'
type WorkflowMainProps = Pick<WorkflowProps, 'nodes' | 'edges' | 'viewport'>
type WorkflowMainProps = Pick<WorkflowProps, 'nodes' | 'edges' | 'viewport'> & {
headerLeftSlot?: ReactNode
}
const WorkflowMain = ({
nodes,
edges,
viewport,
headerLeftSlot,
}: WorkflowMainProps) => {
const sandboxEnabled = useFeatures(state => state.features.sandbox?.enabled) ?? false
const featuresStore = useFeaturesStore()
@ -186,7 +190,7 @@ const WorkflowMain = ({
hooksStore={hooksStore as any}
>
<MCPToolAvailabilityProvider sandboxEnabled={sandboxEnabled}>
<WorkflowChildren />
<WorkflowChildren headerLeftSlot={headerLeftSlot} />
</MCPToolAvailabilityProvider>
</WorkflowWithInnerContext>
)

View File

@ -21,6 +21,7 @@ import WorkflowWithDefaultContext from '@/app/components/workflow'
import {
WorkflowContextProvider,
} from '@/app/components/workflow/context'
import { HeaderShell } from '@/app/components/workflow/header'
import { useWorkflowStore } from '@/app/components/workflow/store'
import { useTriggerStatusStore } from '@/app/components/workflow/store/trigger-status'
import {
@ -51,12 +52,12 @@ const SkillMain = dynamic(() => import('@/app/components/workflow/skill/main'),
})
type WorkflowViewContentProps = {
graphContent: ReactNode
renderGraph: (headerLeftSlot: ReactNode) => ReactNode
reload: () => Promise<void>
}
const WorkflowViewContent = ({
graphContent,
renderGraph,
reload,
}: WorkflowViewContentProps) => {
const features = useFeatures(s => s.features)
@ -92,27 +93,45 @@ const WorkflowViewContent = ({
}
}, [doSetViewType, refreshGraph, syncWorkflowDraftImmediately, viewType])
if (!isSupportSandbox) {
return graphContent
}
if (!isSupportSandbox)
return renderGraph(null)
const viewPicker = (
<ViewPicker
value={viewType}
onChange={handleViewTypeChange}
/>
)
const viewPickerDock = (
<HeaderShell>
<div className="flex w-full items-center justify-between">
<div className="flex items-center gap-2">
{viewPicker}
</div>
</div>
</HeaderShell>
)
return (
<div className="relative h-full w-full">
<ViewPicker
value={viewType}
onChange={handleViewTypeChange}
/>
{viewType === ViewType.graph
? (
isGraphRefreshing
? (
<div className="relative flex h-full w-full items-center justify-center">
<Loading />
</div>
<>
{viewPickerDock}
<div className="relative flex h-full w-full items-center justify-center">
<Loading />
</div>
</>
)
: graphContent
: renderGraph(viewPicker)
)
: (
<SkillMain />
<>
{viewPickerDock}
<SkillMain />
</>
)}
</div>
)
@ -243,7 +262,7 @@ const WorkflowAppWithAdditionalContext = () => {
}, [replayRunId, workflowStore, getWorkflowRunAndTraceUrl])
const isDataReady = !(!data || isLoading || isLoadingCurrentWorkspace || !currentWorkspace.id)
const GraphMain = useMemo(() => {
const renderGraph = useCallback((headerLeftSlot: ReactNode) => {
if (!isDataReady)
return null
@ -252,6 +271,7 @@ const WorkflowAppWithAdditionalContext = () => {
nodes={nodesData}
edges={edgesData}
viewport={data.graph.viewport}
headerLeftSlot={headerLeftSlot}
/>
)
}, [isDataReady, nodesData, edgesData, data])
@ -299,7 +319,7 @@ const WorkflowAppWithAdditionalContext = () => {
>
<FeaturesProvider features={initialFeatures}>
<WorkflowViewContent
graphContent={GraphMain}
renderGraph={renderGraph}
reload={reload}
/>
</FeaturesProvider>