mirror of
https://github.com/langgenius/dify.git
synced 2026-05-04 09:28:04 +08:00
init
This commit is contained in:
14
web/app/(commonLayout)/workflow/page.tsx
Normal file
14
web/app/(commonLayout)/workflow/page.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
'use client'
|
||||
|
||||
import type { FC } from 'react'
|
||||
import { memo } from 'react'
|
||||
import Workflow from '@/app/components/workflow'
|
||||
|
||||
const Page: FC = () => {
|
||||
return (
|
||||
<div className='min-w-[720px] w-full h-full overflow-x-auto'>
|
||||
<Workflow />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default memo(Page)
|
||||
0
web/app/components/workflow/context.tsx
Normal file
0
web/app/components/workflow/context.tsx
Normal file
29
web/app/components/workflow/custom-edge.tsx
Normal file
29
web/app/components/workflow/custom-edge.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import type { EdgeProps } from 'reactflow'
|
||||
import {
|
||||
BaseEdge,
|
||||
getBezierPath,
|
||||
} from 'reactflow'
|
||||
|
||||
const CustomEdge = ({
|
||||
id,
|
||||
sourceX,
|
||||
sourceY,
|
||||
targetX,
|
||||
targetY,
|
||||
}: EdgeProps) => {
|
||||
const [edgePath] = getBezierPath({
|
||||
sourceX,
|
||||
sourceY,
|
||||
targetX,
|
||||
targetY,
|
||||
})
|
||||
console.log('edgePath', edgePath)
|
||||
|
||||
return (
|
||||
<>
|
||||
<BaseEdge id={id} path={edgePath} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default CustomEdge
|
||||
14
web/app/components/workflow/header.tsx
Normal file
14
web/app/components/workflow/header.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
const Header = () => {
|
||||
return (
|
||||
<div
|
||||
className='absolute top-0 left-0 w-full h-14 z-10'
|
||||
style={{
|
||||
background: 'linear-gradient(180deg, #F9FAFB 0%, rgba(249, 250, 251, 0.00) 100%)',
|
||||
}}
|
||||
>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Header
|
||||
15
web/app/components/workflow/hooks.ts
Normal file
15
web/app/components/workflow/hooks.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import {
|
||||
useCallback,
|
||||
useState,
|
||||
} from 'react'
|
||||
|
||||
export const useWorkflow = () => {
|
||||
const [selectedNodeId, setSelectedNodeId] = useState('')
|
||||
|
||||
const handleSelectedNodeId = useCallback((nodeId: string) => setSelectedNodeId(nodeId), [])
|
||||
|
||||
return {
|
||||
selectedNodeId,
|
||||
handleSelectedNodeId,
|
||||
}
|
||||
}
|
||||
67
web/app/components/workflow/index.tsx
Normal file
67
web/app/components/workflow/index.tsx
Normal file
@ -0,0 +1,67 @@
|
||||
import ReactFlow, {
|
||||
Background,
|
||||
} from 'reactflow'
|
||||
import 'reactflow/dist/style.css'
|
||||
import Header from './header'
|
||||
import CustomNode from './nodes'
|
||||
import CustomEdge from './custom-edge'
|
||||
|
||||
const nodeTypes = {
|
||||
custom: CustomNode,
|
||||
}
|
||||
const edgeTypes = {
|
||||
custom: CustomEdge,
|
||||
}
|
||||
|
||||
const Workflow = () => {
|
||||
return (
|
||||
<div className='relative w-full h-full'>
|
||||
<Header />
|
||||
<ReactFlow
|
||||
nodeTypes={nodeTypes}
|
||||
edgeTypes={edgeTypes}
|
||||
nodes={[
|
||||
{
|
||||
id: 'start',
|
||||
type: 'custom',
|
||||
position: { x: 330, y: 30 },
|
||||
data: { list: [] },
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
type: 'custom',
|
||||
position: { x: 400, y: 250 },
|
||||
data: { list: [] },
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'custom',
|
||||
position: { x: 100, y: 250 },
|
||||
data: { list: [] },
|
||||
},
|
||||
]}
|
||||
edges={[
|
||||
{
|
||||
id: 'e1-2',
|
||||
source: 'start',
|
||||
target: '1',
|
||||
type: 'custom',
|
||||
},
|
||||
{
|
||||
id: 'e1-3',
|
||||
source: 'start',
|
||||
target: '2',
|
||||
type: 'custom',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Background
|
||||
gap={[14, 14]}
|
||||
size={1}
|
||||
/>
|
||||
</ReactFlow>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Workflow
|
||||
42
web/app/components/workflow/nodes/_base/node.tsx
Normal file
42
web/app/components/workflow/nodes/_base/node.tsx
Normal file
@ -0,0 +1,42 @@
|
||||
import type {
|
||||
FC,
|
||||
ReactNode,
|
||||
} from 'react'
|
||||
import { memo } from 'react'
|
||||
import { Plus } from '@/app/components/base/icons/src/vender/line/general'
|
||||
|
||||
type BaseNodeProps = {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
const BaseNode: FC<BaseNodeProps> = ({
|
||||
children,
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
group relative pb-2 w-[296px] bg-[#fcfdff] border border-white rounded-2xl shadow-xs
|
||||
hover:shadow-lg
|
||||
`}
|
||||
>
|
||||
<div className='flex items-center px-3 pt-3 pb-2'>
|
||||
<div className='mr-2'></div>
|
||||
<div className='text-[13px] font-semibold text-gray-700'>START</div>
|
||||
</div>
|
||||
{children}
|
||||
<div className='px-3 pt-1 pb-1 text-xs text-gray-500'>
|
||||
Define the initial parameters for launching a workflow
|
||||
</div>
|
||||
<div
|
||||
className={`
|
||||
hidden absolute -bottom-2 left-1/2 -translate-x-1/2 group-hover:flex items-center justify-center
|
||||
w-4 h-4 rounded-full bg-primary-600 cursor-pointer z-10
|
||||
`}
|
||||
>
|
||||
<Plus className='w-2.5 h-2.5 text-white' />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(BaseNode)
|
||||
41
web/app/components/workflow/nodes/_base/panel.tsx
Normal file
41
web/app/components/workflow/nodes/_base/panel.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import type {
|
||||
FC,
|
||||
ReactNode,
|
||||
} from 'react'
|
||||
|
||||
type BasePanelProps = {
|
||||
defaultElement?: ReactNode
|
||||
inputsElement?: ReactNode
|
||||
ouputsElement?: ReactNode
|
||||
}
|
||||
|
||||
const BasePanel: FC<BasePanelProps> = ({
|
||||
defaultElement,
|
||||
inputsElement,
|
||||
ouputsElement,
|
||||
}) => {
|
||||
return (
|
||||
<div className='absolute top-2 right-2 bottom-2 w-[420px] shadow-lg border-[0.5px] border-gray-200 rounded-2xl'>
|
||||
<div className='flex items-center px-4 pt-3'>
|
||||
<div className='mr-2 w-6 h-6'></div>
|
||||
<div className='py-1 text-base text-gray-900 font-semibold '>LLM</div>
|
||||
</div>
|
||||
<div className='p-2'>
|
||||
<div className='py-[5px] pl-1.5 pr-2 text-xs text-gray-400'>
|
||||
Add description...
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex items-center px-4 h-[42px]'>
|
||||
inputs
|
||||
</div>
|
||||
<div className='py-2 border-t-[0.5px] border-b-[0.5px] border-black/5'>
|
||||
{defaultElement}
|
||||
{inputsElement}
|
||||
{ouputsElement}
|
||||
</div>
|
||||
<div className='p-4'></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default BasePanel
|
||||
29
web/app/components/workflow/nodes/index.tsx
Normal file
29
web/app/components/workflow/nodes/index.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import {
|
||||
Handle,
|
||||
Position,
|
||||
} from 'reactflow'
|
||||
import StartNode from './start/node'
|
||||
|
||||
const NodeMap = {
|
||||
'start-node': StartNode,
|
||||
}
|
||||
|
||||
const CustomNode = () => {
|
||||
return (
|
||||
<>
|
||||
<Handle
|
||||
type='target'
|
||||
position={Position.Top}
|
||||
className='!-top-0.5 !w-2 !h-0.5 !bg-primary-500 !rounded-none !border-none !min-h-[2px]'
|
||||
/>
|
||||
<StartNode />
|
||||
<Handle
|
||||
type='source'
|
||||
position={Position.Bottom}
|
||||
className='!-bottom-0.5 !w-2 !h-0.5 !bg-primary-500 !rounded-none !border-none !min-h-[2px]'
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default CustomNode
|
||||
11
web/app/components/workflow/nodes/start/node.tsx
Normal file
11
web/app/components/workflow/nodes/start/node.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import BaseNode from '../_base/node'
|
||||
|
||||
const Node = () => {
|
||||
return (
|
||||
<BaseNode>
|
||||
start node
|
||||
</BaseNode>
|
||||
)
|
||||
}
|
||||
|
||||
export default Node
|
||||
11
web/app/components/workflow/nodes/start/panel.tsx
Normal file
11
web/app/components/workflow/nodes/start/panel.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import BasePanel from '../_base/panel'
|
||||
|
||||
const Panel = () => {
|
||||
return (
|
||||
<BasePanel
|
||||
inputsElement={<div>start panel</div>}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default Panel
|
||||
0
web/app/components/workflow/types.ts
Normal file
0
web/app/components/workflow/types.ts
Normal file
Reference in New Issue
Block a user