Commit 081baae8 authored by StyleZhang's avatar StyleZhang

operator

parent a3d4befa
...@@ -4,9 +4,17 @@ import { memo } from 'react' ...@@ -4,9 +4,17 @@ import { memo } from 'react'
import Workflow from '@/app/components/workflow' import Workflow from '@/app/components/workflow'
const Page = () => { const Page = () => {
const nodes = [
{
id: '1',
type: 'custom',
position: { x: 180, y: 180 },
data: { type: 'start' },
},
]
return ( return (
<Workflow <Workflow
nodes={[]} nodes={nodes}
edges={[]} edges={[]}
/> />
) )
......
<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>
{
"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"
}
\ No newline at end of file
// 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' ...@@ -2,3 +2,4 @@ export { default as AlignLeft01 } from './AlignLeft01'
export { default as AlignRight01 } from './AlignRight01' export { default as AlignRight01 } from './AlignRight01'
export { default as Grid01 } from './Grid01' export { default as Grid01 } from './Grid01'
export { default as LayoutGrid02 } from './LayoutGrid02' 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' ...@@ -4,41 +4,38 @@ import { XClose } from '@/app/components/base/icons/src/vender/line/general'
import { import {
FeaturesChoose, FeaturesChoose,
FeaturesPanel, FeaturesPanel,
FeaturesProvider,
} from '@/app/components/base/features' } from '@/app/components/base/features'
const Features = () => { const Features = () => {
const setShowFeaturesPanel = useStore(state => state.setShowFeaturesPanel) const setShowFeaturesPanel = useStore(state => state.setShowFeaturesPanel)
return ( 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='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'>
<div className='flex items-center justify-between px-4 pt-3'> Features
Features <div className='flex items-center'>
<div className='flex items-center'> <FeaturesChoose />
<FeaturesChoose /> <div className='mx-3 w-[1px] h-[14px] bg-gray-200'></div>
<div className='mx-3 w-[1px] h-[14px] bg-gray-200'></div> <div
<div className='flex items-center justify-center w-6 h-6 cursor-pointer'
className='flex items-center justify-center w-6 h-6 cursor-pointer' onClick={() => setShowFeaturesPanel(false)}
onClick={() => setShowFeaturesPanel(false)} >
> <XClose className='w-4 h-4 text-gray-500' />
<XClose className='w-4 h-4 text-gray-500' />
</div>
</div> </div>
</div> </div>
<div className='p-4'>
<FeaturesPanel
openingStatementProps={{
onAutoAddPromptVariable: () => {},
}}
annotationProps={{
onEmbeddingChange: () => {},
onScoreChange: () => {},
}}
/>
</div>
</div> </div>
</FeaturesProvider> <div className='p-4'>
<FeaturesPanel
openingStatementProps={{
onAutoAddPromptVariable: () => {},
}}
annotationProps={{
onEmbeddingChange: () => {},
onScoreChange: () => {},
}}
/>
</div>
</div>
) )
} }
......
import type { FC } from 'react' import type { FC } from 'react'
import { import {
memo, memo,
// useEffect,
} from 'react' } from 'react'
import { useParams } from 'next/navigation' import { useParams } from 'next/navigation'
import useSWR from 'swr' import useSWR from 'swr'
...@@ -10,11 +9,9 @@ import ReactFlow, { ...@@ -10,11 +9,9 @@ import ReactFlow, {
Background, Background,
ReactFlowProvider, ReactFlowProvider,
useEdgesState, useEdgesState,
// useNodesInitialized,
useNodesState, useNodesState,
} from 'reactflow' } from 'reactflow'
import 'reactflow/dist/style.css' import 'reactflow/dist/style.css'
// import './style.css'
import type { import type {
Edge, Edge,
Node, Node,
...@@ -22,7 +19,7 @@ import type { ...@@ -22,7 +19,7 @@ import type {
import { useWorkflow } from './hooks' import { useWorkflow } from './hooks'
import Header from './header' import Header from './header'
import CustomNode from './nodes' import CustomNode from './nodes'
import ZoomInOut from './zoom-in-out' import Operator from './operator'
import CustomEdge from './custom-edge' import CustomEdge from './custom-edge'
import CustomConnectionLine from './custom-connection-line' import CustomConnectionLine from './custom-connection-line'
import Panel from './panel' import Panel from './panel'
...@@ -34,6 +31,7 @@ import { ...@@ -34,6 +31,7 @@ import {
syncWorkflowDraft, syncWorkflowDraft,
} from '@/service/workflow' } from '@/service/workflow'
import Loading from '@/app/components/base/loading' import Loading from '@/app/components/base/loading'
import { FeaturesProvider } from '@/app/components/base/features'
const nodeTypes = { const nodeTypes = {
custom: CustomNode, custom: CustomNode,
...@@ -53,11 +51,8 @@ const Workflow: FC<WorkflowProps> = memo(({ ...@@ -53,11 +51,8 @@ const Workflow: FC<WorkflowProps> = memo(({
const showFeaturesPanel = useStore(state => state.showFeaturesPanel) const showFeaturesPanel = useStore(state => state.showFeaturesPanel)
const [nodes] = useNodesState(initialNodes) const [nodes] = useNodesState(initialNodes)
const [edges, _, onEdgesChange] = useEdgesState(initialEdges) const [edges, _, onEdgesChange] = useEdgesState(initialEdges)
// const nodesInitialized = useNodesInitialized()
const { const {
// handleLayout,
handleNodeDragStart, handleNodeDragStart,
handleNodeDrag, handleNodeDrag,
handleNodeDragStop, handleNodeDragStop,
...@@ -71,18 +66,13 @@ const Workflow: FC<WorkflowProps> = memo(({ ...@@ -71,18 +66,13 @@ const Workflow: FC<WorkflowProps> = memo(({
handleEdgeDelete, handleEdgeDelete,
} = useWorkflow() } = useWorkflow()
// useEffect(() => {
// if (nodesInitialized)
// handleLayout()
// }, [nodesInitialized, handleLayout])
useKeyPress('Backspace', handleEdgeDelete) useKeyPress('Backspace', handleEdgeDelete)
return ( return (
<div className='relative w-full h-full'> <div className='relative w-full h-full'>
<Header /> <Header />
<Panel /> <Panel />
<ZoomInOut /> <Operator />
{ {
showFeaturesPanel && <Features /> showFeaturesPanel && <Features />
} }
...@@ -121,8 +111,7 @@ const WorkflowWrap: FC<WorkflowProps> = ({ ...@@ -121,8 +111,7 @@ const WorkflowWrap: FC<WorkflowProps> = ({
edges, edges,
}) => { }) => {
const appId = useParams().appId const appId = useParams().appId
const { data, isLoading, error } = useSWR(`/apps/${appId}/workflows/draft`, fetchWorkflowDraft) const { isLoading, error } = useSWR(`/apps/${appId}/workflows/draft`, fetchWorkflowDraft)
// const { data: configsData } = useSWR(`/apps/${appId}/workflows/default-workflow-block-configs`, fetchNodesDefaultConfigs)
if (error) { if (error) {
syncWorkflowDraft({ syncWorkflowDraft({
...@@ -152,10 +141,12 @@ const WorkflowWrap: FC<WorkflowProps> = ({ ...@@ -152,10 +141,12 @@ const WorkflowWrap: FC<WorkflowProps> = ({
return ( return (
<ReactFlowProvider> <ReactFlowProvider>
<Workflow <FeaturesProvider>
nodes={nodes} <Workflow
edges={edges} nodes={nodes}
/> edges={edges}
/>
</FeaturesProvider>
</ReactFlowProvider> </ReactFlowProvider>
) )
} }
......
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)
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)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment