mirror of
https://github.com/langgenius/dify.git
synced 2026-01-05 22:15:52 +00:00
add node-control
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="plus">
|
||||
<path id="Icon" d="M5.00004 2.08325V7.91659M2.08337 4.99992H7.91671" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 274 B |
@@ -0,0 +1,5 @@
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="Icon">
|
||||
<path id="Icon_2" d="M2.5 2.49482C2.5 2.00924 2.5 1.76644 2.60125 1.63261C2.68945 1.51601 2.82426 1.44386 2.9702 1.43515C3.13772 1.42515 3.33973 1.55982 3.74376 1.82918L9.00154 5.33436C9.33538 5.55693 9.5023 5.66821 9.56047 5.80847C9.61133 5.9311 9.61133 6.06891 9.56047 6.19154C9.5023 6.3318 9.33538 6.44308 9.00154 6.66564L3.74376 10.1708C3.33973 10.4402 3.13772 10.5749 2.9702 10.5649C2.82426 10.5561 2.68945 10.484 2.60125 10.3674C2.5 10.2336 2.5 9.99077 2.5 9.50519V2.49482Z" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 689 B |
@@ -0,0 +1,10 @@
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="Icon" clip-path="url(#clip0_467_1645)">
|
||||
<path id="Icon_2" d="M1.5 3.9C1.5 3.05992 1.5 2.63988 1.66349 2.31901C1.8073 2.03677 2.03677 1.8073 2.31901 1.66349C2.63988 1.5 3.05992 1.5 3.9 1.5H8.1C8.94008 1.5 9.36012 1.5 9.68099 1.66349C9.96323 1.8073 10.1927 2.03677 10.3365 2.31901C10.5 2.63988 10.5 3.05992 10.5 3.9V8.1C10.5 8.94008 10.5 9.36012 10.3365 9.68099C10.1927 9.96323 9.96323 10.1927 9.68099 10.3365C9.36012 10.5 8.94008 10.5 8.1 10.5H3.9C3.05992 10.5 2.63988 10.5 2.31901 10.3365C2.03677 10.1927 1.8073 9.96323 1.66349 9.68099C1.5 9.36012 1.5 8.94008 1.5 8.1V3.9Z" stroke="#667085" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_467_1645">
|
||||
<rect width="12" height="12" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 877 B |
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"icon": {
|
||||
"type": "element",
|
||||
"isRootNode": true,
|
||||
"name": "svg",
|
||||
"attributes": {
|
||||
"width": "10",
|
||||
"height": "10",
|
||||
"viewBox": "0 0 10 10",
|
||||
"fill": "none",
|
||||
"xmlns": "http://www.w3.org/2000/svg"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "g",
|
||||
"attributes": {
|
||||
"id": "plus"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Icon",
|
||||
"d": "M5.00004 2.08325V7.91659M2.08337 4.99992H7.91671",
|
||||
"stroke": "currentColor",
|
||||
"stroke-width": "1.5",
|
||||
"stroke-linecap": "round",
|
||||
"stroke-linejoin": "round"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "Plus02"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// GENERATE BY script
|
||||
// DON NOT EDIT IT MANUALLY
|
||||
|
||||
import * as React from 'react'
|
||||
import data from './Plus02.json'
|
||||
import IconBase from '@/app/components/base/icons/IconBase'
|
||||
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
|
||||
|
||||
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
|
||||
props,
|
||||
ref,
|
||||
) => <IconBase {...props} ref={ref} data={data as IconData} />)
|
||||
|
||||
Icon.displayName = 'Plus02'
|
||||
|
||||
export default Icon
|
||||
@@ -19,6 +19,7 @@ export { default as LogOut04 } from './LogOut04'
|
||||
export { default as Menu01 } from './Menu01'
|
||||
export { default as Pin01 } from './Pin01'
|
||||
export { default as Pin02 } from './Pin02'
|
||||
export { default as Plus02 } from './Plus02'
|
||||
export { default as Plus } from './Plus'
|
||||
export { default as SearchLg } from './SearchLg'
|
||||
export { default as Settings01 } from './Settings01'
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"icon": {
|
||||
"type": "element",
|
||||
"isRootNode": true,
|
||||
"name": "svg",
|
||||
"attributes": {
|
||||
"width": "12",
|
||||
"height": "12",
|
||||
"viewBox": "0 0 12 12",
|
||||
"fill": "none",
|
||||
"xmlns": "http://www.w3.org/2000/svg"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "g",
|
||||
"attributes": {
|
||||
"id": "Icon"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Icon_2",
|
||||
"d": "M2.5 2.49482C2.5 2.00924 2.5 1.76644 2.60125 1.63261C2.68945 1.51601 2.82426 1.44386 2.9702 1.43515C3.13772 1.42515 3.33973 1.55982 3.74376 1.82918L9.00154 5.33436C9.33538 5.55693 9.5023 5.66821 9.56047 5.80847C9.61133 5.9311 9.61133 6.06891 9.56047 6.19154C9.5023 6.3318 9.33538 6.44308 9.00154 6.66564L3.74376 10.1708C3.33973 10.4402 3.13772 10.5749 2.9702 10.5649C2.82426 10.5561 2.68945 10.484 2.60125 10.3674C2.5 10.2336 2.5 9.99077 2.5 9.50519V2.49482Z",
|
||||
"stroke": "currentColor",
|
||||
"stroke-width": "1.25",
|
||||
"stroke-linecap": "round",
|
||||
"stroke-linejoin": "round"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "Play"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// GENERATE BY script
|
||||
// DON NOT EDIT IT MANUALLY
|
||||
|
||||
import * as React from 'react'
|
||||
import data from './Play.json'
|
||||
import IconBase from '@/app/components/base/icons/IconBase'
|
||||
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
|
||||
|
||||
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
|
||||
props,
|
||||
ref,
|
||||
) => <IconBase {...props} ref={ref} data={data as IconData} />)
|
||||
|
||||
Icon.displayName = 'Play'
|
||||
|
||||
export default Icon
|
||||
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"icon": {
|
||||
"type": "element",
|
||||
"isRootNode": true,
|
||||
"name": "svg",
|
||||
"attributes": {
|
||||
"width": "12",
|
||||
"height": "12",
|
||||
"viewBox": "0 0 12 12",
|
||||
"fill": "none",
|
||||
"xmlns": "http://www.w3.org/2000/svg"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "g",
|
||||
"attributes": {
|
||||
"id": "Icon",
|
||||
"clip-path": "url(#clip0_467_1645)"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Icon_2",
|
||||
"d": "M1.5 3.9C1.5 3.05992 1.5 2.63988 1.66349 2.31901C1.8073 2.03677 2.03677 1.8073 2.31901 1.66349C2.63988 1.5 3.05992 1.5 3.9 1.5H8.1C8.94008 1.5 9.36012 1.5 9.68099 1.66349C9.96323 1.8073 10.1927 2.03677 10.3365 2.31901C10.5 2.63988 10.5 3.05992 10.5 3.9V8.1C10.5 8.94008 10.5 9.36012 10.3365 9.68099C10.1927 9.96323 9.96323 10.1927 9.68099 10.3365C9.36012 10.5 8.94008 10.5 8.1 10.5H3.9C3.05992 10.5 2.63988 10.5 2.31901 10.3365C2.03677 10.1927 1.8073 9.96323 1.66349 9.68099C1.5 9.36012 1.5 8.94008 1.5 8.1V3.9Z",
|
||||
"stroke": "currentColor",
|
||||
"stroke-width": "1.25",
|
||||
"stroke-linecap": "round",
|
||||
"stroke-linejoin": "round"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "defs",
|
||||
"attributes": {},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "clipPath",
|
||||
"attributes": {
|
||||
"id": "clip0_467_1645"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "rect",
|
||||
"attributes": {
|
||||
"width": "12",
|
||||
"height": "12",
|
||||
"fill": "white"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "Stop"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// GENERATE BY script
|
||||
// DON NOT EDIT IT MANUALLY
|
||||
|
||||
import * as React from 'react'
|
||||
import data from './Stop.json'
|
||||
import IconBase from '@/app/components/base/icons/IconBase'
|
||||
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
|
||||
|
||||
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
|
||||
props,
|
||||
ref,
|
||||
) => <IconBase {...props} ref={ref} data={data as IconData} />)
|
||||
|
||||
Icon.displayName = 'Stop'
|
||||
|
||||
export default Icon
|
||||
@@ -1,3 +1,5 @@
|
||||
export { default as Microphone01 } from './Microphone01'
|
||||
export { default as Play } from './Play'
|
||||
export { default as SlidersH } from './SlidersH'
|
||||
export { default as Speaker } from './Speaker'
|
||||
export { default as Stop } from './Stop'
|
||||
|
||||
@@ -18,6 +18,7 @@ export type WorkflowContextValue = {
|
||||
handleSelectedNodeIdChange: (nodeId: string) => void
|
||||
selectedNode?: Node
|
||||
handleAddNextNode: (prevNode: Node, nextNodeType: BlockEnum) => void
|
||||
handleUpdateNodeData: (nodeId: string, data: Node['data']) => void
|
||||
}
|
||||
|
||||
export const WorkflowContext = createContext<WorkflowContextValue>({
|
||||
@@ -26,5 +27,6 @@ export const WorkflowContext = createContext<WorkflowContextValue>({
|
||||
edges: [],
|
||||
handleSelectedNodeIdChange: () => {},
|
||||
handleAddNextNode: () => {},
|
||||
handleUpdateNodeData: () => {},
|
||||
})
|
||||
export const useWorkflowContext = () => useContext(WorkflowContext)
|
||||
|
||||
@@ -60,10 +60,21 @@ export const useWorkflow = (
|
||||
})
|
||||
}, [setNodes, setEdges])
|
||||
|
||||
const handleUpdateNodeData = useCallback((nodeId: string, data: Node['data']) => {
|
||||
setNodes((oldNodes) => {
|
||||
return produce(oldNodes, (draft) => {
|
||||
const node = draft.find(node => node.id === nodeId)
|
||||
if (node)
|
||||
node.data = data
|
||||
})
|
||||
})
|
||||
}, [setNodes])
|
||||
|
||||
return {
|
||||
selectedNodeId,
|
||||
selectedNode,
|
||||
handleSelectedNodeIdChange,
|
||||
handleAddNextNode,
|
||||
handleUpdateNodeData,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ const WorkflowWrap: FC<WorkflowWrapProps> = ({
|
||||
handleSelectedNodeIdChange,
|
||||
selectedNode,
|
||||
handleAddNextNode,
|
||||
handleUpdateNodeData,
|
||||
} = useWorkflow(
|
||||
nodes,
|
||||
edges,
|
||||
@@ -90,6 +91,7 @@ const WorkflowWrap: FC<WorkflowWrapProps> = ({
|
||||
nodes,
|
||||
edges,
|
||||
handleAddNextNode,
|
||||
handleUpdateNodeData,
|
||||
}}>
|
||||
<Workflow />
|
||||
</WorkflowContext.Provider>
|
||||
|
||||
42
web/app/components/workflow/node-control.tsx
Normal file
42
web/app/components/workflow/node-control.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import type { FC } from 'react'
|
||||
import { memo } from 'react'
|
||||
import {
|
||||
DotsHorizontal,
|
||||
Loading02,
|
||||
} from '@/app/components/base/icons/src/vender/line/general'
|
||||
import {
|
||||
Play,
|
||||
Stop,
|
||||
} from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
|
||||
|
||||
type NodeControlProps = {
|
||||
isRunning?: boolean
|
||||
}
|
||||
const NodeControl: FC<NodeControlProps> = ({
|
||||
isRunning,
|
||||
}) => {
|
||||
return (
|
||||
<div className='absolute left-0 -top-7 flex items-center px-0.5 h-6 bg-white rounded-lg border-[0.5px] border-gray-100 shadow-xs text-gray-500'>
|
||||
{
|
||||
isRunning && (
|
||||
<div className='flex items-center px-1 h-5 rounded-md bg-primary-50 text-xs font-medium text-primary-600'>
|
||||
<Loading02 className='mr-1 w-3 h-3 animate-spin' />
|
||||
RUNNING
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<div className='flex items-center justify-center w-5 h-5 cursor-pointer'>
|
||||
{
|
||||
isRunning
|
||||
? <Stop className='w-3 h-3' />
|
||||
: <Play className='w-3 h-3' />
|
||||
}
|
||||
</div>
|
||||
<div className='flex items-center justify-center w-5 h-5 cursor-pointer'>
|
||||
<DotsHorizontal className='w-3 h-3' />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(NodeControl)
|
||||
@@ -12,8 +12,9 @@ import type { NodeProps } from 'reactflow'
|
||||
import { getOutgoers } from 'reactflow'
|
||||
import { useWorkflowContext } from '../../context'
|
||||
import BlockSelector from '../../block-selector'
|
||||
import NodeControl from '../../node-control'
|
||||
import BlockIcon from '../../block-icon'
|
||||
import { Plus } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import { Plus02 } from '@/app/components/base/icons/src/vender/line/general'
|
||||
|
||||
type BaseNodeProps = {
|
||||
children: ReactElement
|
||||
@@ -48,7 +49,7 @@ const BaseNode: FC<BaseNodeProps> = ({
|
||||
${open && '!flex'}
|
||||
`}
|
||||
>
|
||||
<Plus className='w-2.5 h-2.5 text-white' />
|
||||
<Plus02 className='w-2.5 h-2.5 text-white' />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@@ -63,6 +64,7 @@ const BaseNode: FC<BaseNodeProps> = ({
|
||||
`}
|
||||
onClick={() => handleSelectedNodeIdChange(nodeId || '')}
|
||||
>
|
||||
<NodeControl />
|
||||
<div className='flex items-center px-3 pt-3 pb-2'>
|
||||
<BlockIcon
|
||||
className='mr-2'
|
||||
|
||||
Reference in New Issue
Block a user