mirror of https://github.com/langgenius/dify.git
operator
This commit is contained in:
parent
a3d4befad4
commit
081baae883
|
|
@ -4,9 +4,17 @@ import { memo } from 'react'
|
|||
import Workflow from '@/app/components/workflow'
|
||||
|
||||
const Page = () => {
|
||||
const nodes = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'custom',
|
||||
position: { x: 180, y: 180 },
|
||||
data: { type: 'start' },
|
||||
},
|
||||
]
|
||||
return (
|
||||
<Workflow
|
||||
nodes={[]}
|
||||
nodes={nodes}
|
||||
edges={[]}
|
||||
/>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="Icon">
|
||||
<g id="Vector">
|
||||
<path d="M9.33366 10.667C9.33366 9.93061 9.93061 9.33366 10.667 9.33366H12.0003C12.7367 9.33366 13.3337 9.93061 13.3337 10.667V12.0003C13.3337 12.7367 12.7367 13.3337 12.0003 13.3337H10.667C9.93061 13.3337 9.33366 12.7367 9.33366 12.0003V10.667Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M2.66699 10.667C2.66699 9.93059 3.26395 9.33366 4.00033 9.33366H5.33366C6.07004 9.33366 6.66699 9.93059 6.66699 10.667V12.0003C6.66699 12.7367 6.07004 13.3337 5.33366 13.3337H4.00033C3.26395 13.3337 2.66699 12.7367 2.66699 12.0003V10.667Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M2.66699 4.00033C2.66699 3.26395 3.26393 2.66699 4.00033 2.66699H5.33366C6.07006 2.66699 6.66699 3.26395 6.66699 4.00033V5.33366C6.66699 6.07004 6.07006 6.66699 5.33366 6.66699H4.00033C3.26393 6.66699 2.66699 6.07004 2.66699 5.33366V4.00033Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<path id="Vector_2" d="M11.6409 2.1899C11.5143 1.93674 11.153 1.93674 11.0265 2.1899L10.3544 3.53389C10.3213 3.60035 10.2673 3.65425 10.2008 3.68748L8.85684 4.35948C8.60371 4.48606 8.60371 4.84732 8.85684 4.97389L10.2008 5.64589C10.2673 5.67913 10.3213 5.73303 10.3544 5.7995L11.0265 7.14348C11.153 7.39664 11.5143 7.39664 11.6409 7.14348L12.3129 5.7995C12.3461 5.73303 12.4 5.67913 12.4665 5.64589L13.8105 4.97389C14.0636 4.84732 14.0636 4.48606 13.8105 4.35948L12.4665 3.68748C12.4 3.65425 12.3461 3.60035 12.3129 3.53389L11.6409 2.1899Z" fill="#667085"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
|
|
@ -0,0 +1,81 @@
|
|||
{
|
||||
"icon": {
|
||||
"type": "element",
|
||||
"isRootNode": true,
|
||||
"name": "svg",
|
||||
"attributes": {
|
||||
"width": "16",
|
||||
"height": "16",
|
||||
"viewBox": "0 0 16 16",
|
||||
"fill": "none",
|
||||
"xmlns": "http://www.w3.org/2000/svg"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "g",
|
||||
"attributes": {
|
||||
"id": "Icon"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "g",
|
||||
"attributes": {
|
||||
"id": "Vector"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"d": "M9.33366 10.667C9.33366 9.93061 9.93061 9.33366 10.667 9.33366H12.0003C12.7367 9.33366 13.3337 9.93061 13.3337 10.667V12.0003C13.3337 12.7367 12.7367 13.3337 12.0003 13.3337H10.667C9.93061 13.3337 9.33366 12.7367 9.33366 12.0003V10.667Z",
|
||||
"stroke": "currentColor",
|
||||
"stroke-width": "1.5",
|
||||
"stroke-linecap": "round",
|
||||
"stroke-linejoin": "round"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"d": "M2.66699 10.667C2.66699 9.93059 3.26395 9.33366 4.00033 9.33366H5.33366C6.07004 9.33366 6.66699 9.93059 6.66699 10.667V12.0003C6.66699 12.7367 6.07004 13.3337 5.33366 13.3337H4.00033C3.26395 13.3337 2.66699 12.7367 2.66699 12.0003V10.667Z",
|
||||
"stroke": "currentColor",
|
||||
"stroke-width": "1.5",
|
||||
"stroke-linecap": "round",
|
||||
"stroke-linejoin": "round"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"d": "M2.66699 4.00033C2.66699 3.26395 3.26393 2.66699 4.00033 2.66699H5.33366C6.07006 2.66699 6.66699 3.26395 6.66699 4.00033V5.33366C6.66699 6.07004 6.07006 6.66699 5.33366 6.66699H4.00033C3.26393 6.66699 2.66699 6.07004 2.66699 5.33366V4.00033Z",
|
||||
"stroke": "currentColor",
|
||||
"stroke-width": "1.5",
|
||||
"stroke-linecap": "round",
|
||||
"stroke-linejoin": "round"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Vector_2",
|
||||
"d": "M11.6409 2.1899C11.5143 1.93674 11.153 1.93674 11.0265 2.1899L10.3544 3.53389C10.3213 3.60035 10.2673 3.65425 10.2008 3.68748L8.85684 4.35948C8.60371 4.48606 8.60371 4.84732 8.85684 4.97389L10.2008 5.64589C10.2673 5.67913 10.3213 5.73303 10.3544 5.7995L11.0265 7.14348C11.153 7.39664 11.5143 7.39664 11.6409 7.14348L12.3129 5.7995C12.3461 5.73303 12.4 5.67913 12.4665 5.64589L13.8105 4.97389C14.0636 4.84732 14.0636 4.48606 13.8105 4.35948L12.4665 3.68748C12.4 3.65425 12.3461 3.60035 12.3129 3.53389L11.6409 2.1899Z",
|
||||
"fill": "currentColor"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "OrganizeGrid"
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// GENERATE BY script
|
||||
// DON NOT EDIT IT MANUALLY
|
||||
|
||||
import * as React from 'react'
|
||||
import data from './OrganizeGrid.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 = 'OrganizeGrid'
|
||||
|
||||
export default Icon
|
||||
|
|
@ -2,3 +2,4 @@ export { default as AlignLeft01 } from './AlignLeft01'
|
|||
export { default as AlignRight01 } from './AlignRight01'
|
||||
export { default as Grid01 } from './Grid01'
|
||||
export { default as LayoutGrid02 } from './LayoutGrid02'
|
||||
export { default as OrganizeGrid } from './OrganizeGrid'
|
||||
|
|
|
|||
|
|
@ -4,41 +4,38 @@ import { XClose } from '@/app/components/base/icons/src/vender/line/general'
|
|||
import {
|
||||
FeaturesChoose,
|
||||
FeaturesPanel,
|
||||
FeaturesProvider,
|
||||
} from '@/app/components/base/features'
|
||||
|
||||
const Features = () => {
|
||||
const setShowFeaturesPanel = useStore(state => state.setShowFeaturesPanel)
|
||||
|
||||
return (
|
||||
<FeaturesProvider>
|
||||
<div className='absolute top-2 left-2 bottom-2 w-[600px] rounded-2xl border-[0.5px] border-gray-200 bg-white shadow-xl z-10'>
|
||||
<div className='flex items-center justify-between px-4 pt-3'>
|
||||
Features
|
||||
<div className='flex items-center'>
|
||||
<FeaturesChoose />
|
||||
<div className='mx-3 w-[1px] h-[14px] bg-gray-200'></div>
|
||||
<div
|
||||
className='flex items-center justify-center w-6 h-6 cursor-pointer'
|
||||
onClick={() => setShowFeaturesPanel(false)}
|
||||
>
|
||||
<XClose className='w-4 h-4 text-gray-500' />
|
||||
</div>
|
||||
<div className='absolute top-2 left-2 bottom-2 w-[600px] rounded-2xl border-[0.5px] border-gray-200 bg-white shadow-xl z-10'>
|
||||
<div className='flex items-center justify-between px-4 pt-3'>
|
||||
Features
|
||||
<div className='flex items-center'>
|
||||
<FeaturesChoose />
|
||||
<div className='mx-3 w-[1px] h-[14px] bg-gray-200'></div>
|
||||
<div
|
||||
className='flex items-center justify-center w-6 h-6 cursor-pointer'
|
||||
onClick={() => setShowFeaturesPanel(false)}
|
||||
>
|
||||
<XClose className='w-4 h-4 text-gray-500' />
|
||||
</div>
|
||||
</div>
|
||||
<div className='p-4'>
|
||||
<FeaturesPanel
|
||||
openingStatementProps={{
|
||||
onAutoAddPromptVariable: () => {},
|
||||
}}
|
||||
annotationProps={{
|
||||
onEmbeddingChange: () => {},
|
||||
onScoreChange: () => {},
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</FeaturesProvider>
|
||||
<div className='p-4'>
|
||||
<FeaturesPanel
|
||||
openingStatementProps={{
|
||||
onAutoAddPromptVariable: () => {},
|
||||
}}
|
||||
annotationProps={{
|
||||
onEmbeddingChange: () => {},
|
||||
onScoreChange: () => {},
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import type { FC } from 'react'
|
||||
import {
|
||||
memo,
|
||||
// useEffect,
|
||||
} from 'react'
|
||||
import { useParams } from 'next/navigation'
|
||||
import useSWR from 'swr'
|
||||
|
|
@ -10,11 +9,9 @@ import ReactFlow, {
|
|||
Background,
|
||||
ReactFlowProvider,
|
||||
useEdgesState,
|
||||
// useNodesInitialized,
|
||||
useNodesState,
|
||||
} from 'reactflow'
|
||||
import 'reactflow/dist/style.css'
|
||||
// import './style.css'
|
||||
import type {
|
||||
Edge,
|
||||
Node,
|
||||
|
|
@ -22,7 +19,7 @@ import type {
|
|||
import { useWorkflow } from './hooks'
|
||||
import Header from './header'
|
||||
import CustomNode from './nodes'
|
||||
import ZoomInOut from './zoom-in-out'
|
||||
import Operator from './operator'
|
||||
import CustomEdge from './custom-edge'
|
||||
import CustomConnectionLine from './custom-connection-line'
|
||||
import Panel from './panel'
|
||||
|
|
@ -34,6 +31,7 @@ import {
|
|||
syncWorkflowDraft,
|
||||
} from '@/service/workflow'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import { FeaturesProvider } from '@/app/components/base/features'
|
||||
|
||||
const nodeTypes = {
|
||||
custom: CustomNode,
|
||||
|
|
@ -53,11 +51,8 @@ const Workflow: FC<WorkflowProps> = memo(({
|
|||
const showFeaturesPanel = useStore(state => state.showFeaturesPanel)
|
||||
const [nodes] = useNodesState(initialNodes)
|
||||
const [edges, _, onEdgesChange] = useEdgesState(initialEdges)
|
||||
// const nodesInitialized = useNodesInitialized()
|
||||
|
||||
const {
|
||||
// handleLayout,
|
||||
|
||||
handleNodeDragStart,
|
||||
handleNodeDrag,
|
||||
handleNodeDragStop,
|
||||
|
|
@ -71,18 +66,13 @@ const Workflow: FC<WorkflowProps> = memo(({
|
|||
handleEdgeDelete,
|
||||
} = useWorkflow()
|
||||
|
||||
// useEffect(() => {
|
||||
// if (nodesInitialized)
|
||||
// handleLayout()
|
||||
// }, [nodesInitialized, handleLayout])
|
||||
|
||||
useKeyPress('Backspace', handleEdgeDelete)
|
||||
|
||||
return (
|
||||
<div className='relative w-full h-full'>
|
||||
<Header />
|
||||
<Panel />
|
||||
<ZoomInOut />
|
||||
<Operator />
|
||||
{
|
||||
showFeaturesPanel && <Features />
|
||||
}
|
||||
|
|
@ -121,8 +111,7 @@ const WorkflowWrap: FC<WorkflowProps> = ({
|
|||
edges,
|
||||
}) => {
|
||||
const appId = useParams().appId
|
||||
const { data, isLoading, error } = useSWR(`/apps/${appId}/workflows/draft`, fetchWorkflowDraft)
|
||||
// const { data: configsData } = useSWR(`/apps/${appId}/workflows/default-workflow-block-configs`, fetchNodesDefaultConfigs)
|
||||
const { isLoading, error } = useSWR(`/apps/${appId}/workflows/draft`, fetchWorkflowDraft)
|
||||
|
||||
if (error) {
|
||||
syncWorkflowDraft({
|
||||
|
|
@ -152,10 +141,12 @@ const WorkflowWrap: FC<WorkflowProps> = ({
|
|||
|
||||
return (
|
||||
<ReactFlowProvider>
|
||||
<Workflow
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
/>
|
||||
<FeaturesProvider>
|
||||
<Workflow
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
/>
|
||||
</FeaturesProvider>
|
||||
</ReactFlowProvider>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
import { memo } from 'react'
|
||||
import ZoomInOut from './zoom-in-out'
|
||||
import { OrganizeGrid } from '@/app/components/base/icons/src/vender/line/layout'
|
||||
import TooltipPlus from '@/app/components/base/tooltip-plus'
|
||||
|
||||
const Operator = () => {
|
||||
return (
|
||||
<div className={`
|
||||
absolute left-6 bottom-6 flex items-center p-0.5
|
||||
rounded-lg border-[0.5px] border-gray-100 bg-white shadow-lg text-gray-500 z-10
|
||||
`}>
|
||||
<ZoomInOut />
|
||||
<TooltipPlus popupContent='Organize blocks'>
|
||||
<div className='ml-[1px] flex items-center justify-center w-8 h-8 cursor-pointer hover:bg-black/5 rounded-lg'>
|
||||
<OrganizeGrid className='w-4 h-4' />
|
||||
</div>
|
||||
</TooltipPlus>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(Operator)
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
import type { FC } from 'react'
|
||||
import {
|
||||
Fragment,
|
||||
memo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useReactFlow } from 'reactflow'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import { SearchLg } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import { ChevronDown } from '@/app/components/base/icons/src/vender/line/arrows'
|
||||
|
||||
const ZOOM_IN_OUT_OPTIONS = [
|
||||
[
|
||||
{
|
||||
key: 'in',
|
||||
text: 'Zoom In',
|
||||
},
|
||||
{
|
||||
key: 'out',
|
||||
text: 'Zoom Out',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
key: 'to50',
|
||||
text: 'Zoom to 50%',
|
||||
},
|
||||
{
|
||||
key: 'to100',
|
||||
text: 'Zoom to 100%',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
key: 'fit',
|
||||
text: 'Zoom to Fit',
|
||||
},
|
||||
],
|
||||
]
|
||||
|
||||
const ZoomInOut: FC = () => {
|
||||
const reactFlow = useReactFlow()
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const handleZoom = (type: string) => {
|
||||
if (type === 'in')
|
||||
reactFlow.zoomIn()
|
||||
|
||||
if (type === 'out')
|
||||
reactFlow.zoomOut()
|
||||
|
||||
if (type === 'fit')
|
||||
reactFlow.fitView()
|
||||
}
|
||||
|
||||
return (
|
||||
<PortalToFollowElem
|
||||
placement='top-start'
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
offset={4}
|
||||
>
|
||||
<PortalToFollowElemTrigger asChild onClick={() => setOpen(v => !v)}>
|
||||
<div className={`
|
||||
flex items-center px-2 h-8 cursor-pointer text-[13px] hover:bg-gray-50 rounded-lg
|
||||
${open && 'bg-gray-50'}
|
||||
`}>
|
||||
<SearchLg className='mr-1 w-4 h-4' />
|
||||
100%
|
||||
<ChevronDown className='ml-1 w-4 h-4' />
|
||||
</div>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent>
|
||||
<div className='w-[168px] rounded-lg border-[0.5px] border-gray-200 bg-white shadow-lg'>
|
||||
{
|
||||
ZOOM_IN_OUT_OPTIONS.map((options, i) => (
|
||||
<Fragment key={i}>
|
||||
{
|
||||
i !== 0 && (
|
||||
<div className='h-[1px] bg-gray-100' />
|
||||
)
|
||||
}
|
||||
<div className='p-1'>
|
||||
{
|
||||
options.map(option => (
|
||||
<div
|
||||
key={option.key}
|
||||
className='flex items-center px-3 h-8 rounded-lg hover:bg-gray-50 cursor-pointer text-sm text-gray-700'
|
||||
onClick={() => handleZoom(option.key)}
|
||||
>
|
||||
{option.text}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</Fragment>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(ZoomInOut)
|
||||
Loading…
Reference in New Issue