pull/21256/merge
Good Wood 11 months ago committed by GitHub
commit 93b1fc134c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -17,3 +17,5 @@ export * from './use-workflow-interactions'
export * from './use-workflow-mode'
export * from './use-format-time-from-now'
export * from './use-workflow-refresh-draft'
export * from './use-selection-graph-menu'
export * from './use-selection-paste'

@ -1356,6 +1356,8 @@ export const useNodesInteractions = () => {
}
})
console.log(nodesToPaste, edgesToPaste)
setNodes([...nodes, ...nodesToPaste])
setEdges([...edges, ...edgesToPaste])
saveStateToHistory(WorkflowHistoryEvent.NodePaste)

@ -26,6 +26,7 @@ export const usePanelInteractions = () => {
const handleNodeContextmenuCancel = useCallback(() => {
workflowStore.setState({
nodeMenu: undefined,
selectPanelMenu: undefined,
})
}, [workflowStore])

@ -0,0 +1,36 @@
import type { MouseEvent } from 'react'
import { useCallback } from 'react'
import { useWorkflowStore } from '../store'
export const useSelectionGraphMenu = () => {
const workflowStore = useWorkflowStore()
const { setSelectPanelMenu, setNodeMenu, setPanelMenu } = workflowStore.getState()
const handleSelectPanelContextMenu = useCallback((e: MouseEvent) => {
e.preventDefault()
console.log('handleSelectPanelContextMenu', e.clientX, e.clientY)
const container = document.querySelector('#workflow-container')
const { x, y } = container!.getBoundingClientRect()
setSelectPanelMenu({
top: e.clientY - y,
left: e.clientX - x,
})
}, [setSelectPanelMenu])
const handleSelectPanelContextmenuCancel = useCallback(() => {
setSelectPanelMenu(undefined)
}, [setSelectPanelMenu])
const handleOtherContextmenuCancel = useCallback(() => {
setNodeMenu(undefined)
setPanelMenu(undefined)
}, [setNodeMenu, setPanelMenu])
return {
handleSelectPanelContextMenu,
handleSelectPanelContextmenuCancel,
handleOtherContextmenuCancel,
}
}

@ -0,0 +1,25 @@
import {
useCallback,
} from 'react'
import type {
OnSelectionChangeParams,
} from 'reactflow'
import { useOnSelectionChange } from 'reactflow'
import { useWorkflowStore } from '../store'
export const useSelectionGraph = () => {
const workflowStore = useWorkflowStore()
const { setSelectGraph } = workflowStore.getState()
const onChange = useCallback((params: OnSelectionChangeParams) => {
const { nodes, edges } = params
setSelectGraph({
nodes,
edges,
})
}, [])
useOnSelectionChange({
onChange,
})
}

@ -0,0 +1,28 @@
import type { RefObject } from 'react'
import { useEffect } from'react'
import {
useStore,
} from 'reactflow'
type UseSelectionPasteProps = {
workflowContainerRef: RefObject<HTMLDivElement>
}
export const useSelectionPaste = ({ workflowContainerRef }: UseSelectionPasteProps) => {
const domNode = useStore(s => s.domNode)
const handlePaste = (e: ClipboardEvent) => {
e.preventDefault()
console.log(e.clipboardData?.getData('text'))
}
useEffect(() => {
if (domNode) {
console.log('workflowContainerRef.current', domNode)
domNode.addEventListener('paste', handlePaste)
}
return () => {
if (domNode)
domNode.removeEventListener('paste', handlePaste)
}
}, [domNode])
}

@ -41,6 +41,7 @@ import {
useNodesSyncDraft,
usePanelInteractions,
useSelectionInteractions,
useSelectionPaste,
useShortcuts,
useWorkflow,
useWorkflowReadOnly,
@ -80,6 +81,9 @@ import Confirm from '@/app/components/base/confirm'
import DatasetsDetailProvider from './datasets-detail-store/provider'
import { HooksStoreContextProvider } from './hooks-store'
import type { Shape as HooksStoreShape } from './hooks-store'
import { useSelectionGraph } from './hooks/use-selection-graph'
import { useSelectionGraphMenu } from './hooks/use-selection-graph-menu'
import SelectPanelContextmenu from './select-panel-contextmenu'
const nodeTypes = {
[CUSTOM_NODE]: CustomNode,
@ -115,6 +119,14 @@ export const Workflow: FC<WorkflowProps> = memo(({
const nodeAnimation = useStore(s => s.nodeAnimation)
const showConfirm = useStore(s => s.showConfirm)
// add selection hook
useSelectionGraph()
// add paste hook
useSelectionPaste({
workflowContainerRef,
})
const { handleSelectPanelContextMenu } = useSelectionGraphMenu()
const {
setShowConfirm,
setControlPromptEditorRerenderKey,
@ -270,6 +282,7 @@ export const Workflow: FC<WorkflowProps> = memo(({
<Operator handleRedo={handleHistoryForward} handleUndo={handleHistoryBack} />
<PanelContextmenu />
<NodeContextmenu />
<SelectPanelContextmenu />
<HelpLine />
{
!!showConfirm && (
@ -307,6 +320,7 @@ export const Workflow: FC<WorkflowProps> = memo(({
onSelectionDrag={handleSelectionDrag}
onPaneContextMenu={handlePaneContextMenu}
connectionLineComponent={CustomConnectionLine}
onSelectionContextMenu={handleSelectPanelContextMenu}
// TODO: For LOOP node, how to distinguish between ITERATION and LOOP here? Maybe both are the same?
connectionLineContainerStyle={{ zIndex: ITERATION_CHILDREN_Z_INDEX }}
defaultViewport={viewport}
@ -345,6 +359,16 @@ export const WorkflowWithInnerContext = memo(({
hooksStore,
...restProps
}: WorkflowWithInnerContextProps) => {
const handlePaste = (e: ClipboardEvent) => {
console.log(e, 123)
}
useEffect(() => {
document.body.addEventListener('paste', handlePaste, true)
return () => {
document.body.removeEventListener('paste', handlePaste, true)
}
}, [])
return (
<HooksStoreContextProvider {...hooksStore}>
<Workflow {...restProps} />

@ -30,6 +30,8 @@ const PanelContextmenu = () => {
const { handleAddNote } = useOperator()
const { exportCheck } = useDSL()
console.log(clipboardElements, 'clipboardElements')
useEffect(() => {
if (panelMenu)
handleNodeContextmenuCancel()

@ -0,0 +1,68 @@
import {
memo,
useEffect,
useRef,
} from 'react'
import { useTranslation } from 'react-i18next'
import { useClickAway } from 'ahooks'
import ShortcutsName from './shortcuts-name'
import { useStore } from './store'
import {
useNodesInteractions,
useSelectionGraphMenu,
useWorkflowStartRun,
} from './hooks'
import { useStore as useAppStore } from '@/app/components/app/store'
const PanelContextmenu = () => {
const { t } = useTranslation()
const ref = useRef(null)
const selectPanelMenu = useStore(s => s.selectPanelMenu)
const selectGraph = useStore(s => s.selectGraph)
const clipboardElements = useStore(s => s.clipboardElements)
const { handleNodesPaste } = useNodesInteractions()
const { handleSelectPanelContextmenuCancel, handleOtherContextmenuCancel } = useSelectionGraphMenu()
const { handleStartWorkflowRun } = useWorkflowStartRun()
const appDetail = useAppStore(state => state.appDetail)
console.log(appDetail?.mode, selectGraph)
useEffect(() => {
if (selectPanelMenu)
handleOtherContextmenuCancel()
}, [selectPanelMenu, handleOtherContextmenuCancel])
useClickAway(() => {
handleSelectPanelContextmenuCancel()
}, ref)
if (!selectPanelMenu)
return null
return (
<div
className='absolute z-[9] w-[200px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg'
style={{
left: selectPanelMenu.left,
top: selectPanelMenu.top,
}}
ref={ref}
>
<div className='p-1'>
<div
className='flex h-8 cursor-pointer items-center justify-between rounded-lg px-3 text-sm text-text-secondary hover:bg-state-base-hover'
onClick={() => {
handleStartWorkflowRun()
handleSelectPanelContextmenuCancel()
}}
>
{t('workflow.common.run')}
<ShortcutsName keys={['alt', 'r']} />
</div>
</div>
</div>
)
}
export default memo(PanelContextmenu)

@ -30,6 +30,7 @@ import type { WorkflowSliceShape } from './workflow-slice'
import { createWorkflowSlice } from './workflow-slice'
import { WorkflowContext } from '@/app/components/workflow/context'
import type { WorkflowSliceShape as WorkflowAppSliceShape } from '@/app/components/workflow-app/store/workflow/workflow-slice'
import { type SelectPanelSliceShape, createSelectPanelSlice } from './select-node-panel'
export type Shape =
ChatVariableSliceShape &
@ -43,7 +44,8 @@ export type Shape =
VersionSliceShape &
WorkflowDraftSliceShape &
WorkflowSliceShape &
WorkflowAppSliceShape
WorkflowAppSliceShape &
SelectPanelSliceShape
type CreateWorkflowStoreParams = {
injectWorkflowStoreSliceFn?: StateCreator<WorkflowAppSliceShape>
@ -65,6 +67,7 @@ export const createWorkflowStore = (params: CreateWorkflowStoreParams) => {
...createWorkflowDraftSlice(...args),
...createWorkflowSlice(...args),
...(injectWorkflowStoreSliceFn?.(...args) || {} as WorkflowAppSliceShape),
...createSelectPanelSlice(...args),
}))
}

@ -0,0 +1,25 @@
import type { Edge, Node } from 'reactflow'
import type { StateCreator } from 'zustand'
export type SelectPanelSliceShape = {
selectGraph: {
nodes: Node[],
edges: Edge[],
},
selectPanelMenu?: {
top: number
left: number
},
setSelectPanelMenu: (panelMenu: SelectPanelSliceShape['selectPanelMenu']) => void,
setSelectGraph: (selectGraph: SelectPanelSliceShape['selectGraph']) => void,
}
export const createSelectPanelSlice: StateCreator<SelectPanelSliceShape> = set => ({
selectPanelMenu: undefined,
setSelectPanelMenu: selectPanelMenu => set(() => ({ selectPanelMenu })),
selectGraph: {
nodes: [],
edges: [],
},
setSelectGraph: selectGraph => set(() => ({ selectGraph })),
})
Loading…
Cancel
Save