| const { handleSyncWorkflowDraft } = useNodesSyncDraft() | const { handleSyncWorkflowDraft } = useNodesSyncDraft() | ||||
| const { eventEmitter } = useEventEmitterContextContext() | const { eventEmitter } = useEventEmitterContextContext() | ||||
| const setPanelWidth = useCallback((width: number) => { | |||||
| localStorage.setItem('workflow-node-panel-width', `${width}`) | |||||
| workflowStore.setState({ panelWidth: width }) | |||||
| }, [workflowStore]) | |||||
| const handleLayout = useCallback(async () => { | const handleLayout = useCallback(async () => { | ||||
| workflowStore.setState({ nodeAnimation: true }) | workflowStore.setState({ nodeAnimation: true }) | ||||
| const { | const { | ||||
| }, [workflowStore]) | }, [workflowStore]) | ||||
| return { | return { | ||||
| setPanelWidth, | |||||
| handleLayout, | handleLayout, | ||||
| getTreeLeafNodes, | getTreeLeafNodes, | ||||
| getBeforeNodesInSameBranch, | getBeforeNodesInSameBranch, |
| minHeight?: number | minHeight?: number | ||||
| maxHeight?: number | maxHeight?: number | ||||
| onResized?: (width: number, height: number) => void | onResized?: (width: number, height: number) => void | ||||
| onResize?: (width: number, height: number) => void | |||||
| } | } | ||||
| export const useResizePanel = (params?: UseResizePanelPrarams) => { | export const useResizePanel = (params?: UseResizePanelPrarams) => { | ||||
| const { | const { | ||||
| minHeight = -Infinity, | minHeight = -Infinity, | ||||
| maxHeight = Infinity, | maxHeight = Infinity, | ||||
| onResized, | onResized, | ||||
| onResize, | |||||
| } = params || {} | } = params || {} | ||||
| const triggerRef = useRef<HTMLDivElement>(null) | const triggerRef = useRef<HTMLDivElement>(null) | ||||
| const containerRef = useRef<HTMLDivElement>(null) | const containerRef = useRef<HTMLDivElement>(null) | ||||
| if (width > maxWidth) | if (width > maxWidth) | ||||
| width = maxWidth | width = maxWidth | ||||
| containerRef.current.style.width = `${width}px` | containerRef.current.style.width = `${width}px` | ||||
| onResize?.(width, 0) | |||||
| } | } | ||||
| if (direction === 'vertical' || direction === 'both') { | if (direction === 'vertical' || direction === 'both') { | ||||
| height = maxHeight | height = maxHeight | ||||
| containerRef.current.style.height = `${height}px` | containerRef.current.style.height = `${height}px` | ||||
| onResize?.(0, height) | |||||
| } | } | ||||
| }, [ | }, [ | ||||
| direction, | direction, | ||||
| maxWidth, | maxWidth, | ||||
| minHeight, | minHeight, | ||||
| maxHeight, | maxHeight, | ||||
| onResize, | |||||
| ]) | ]) | ||||
| const handleStopResize = useCallback(() => { | const handleStopResize = useCallback(() => { |
| import { useEffect, useState } from 'react' | import { useEffect, useState } from 'react' | ||||
| import { useStore } from '@/app/components/workflow/store' | |||||
| type Params = { | type Params = { | ||||
| ref: React.RefObject<HTMLDivElement> | ref: React.RefObject<HTMLDivElement> | ||||
| const useToggleExpend = ({ ref, hasFooter = true, isInNode }: Params) => { | const useToggleExpend = ({ ref, hasFooter = true, isInNode }: Params) => { | ||||
| const [isExpand, setIsExpand] = useState(false) | const [isExpand, setIsExpand] = useState(false) | ||||
| const [wrapHeight, setWrapHeight] = useState(ref.current?.clientHeight) | const [wrapHeight, setWrapHeight] = useState(ref.current?.clientHeight) | ||||
| const panelWidth = useStore(state => state.panelWidth) | |||||
| const editorExpandHeight = isExpand ? wrapHeight! - (hasFooter ? 56 : 29) : 0 | const editorExpandHeight = isExpand ? wrapHeight! - (hasFooter ? 56 : 29) : 0 | ||||
| useEffect(() => { | useEffect(() => { | ||||
| setWrapHeight(ref.current?.clientHeight) | setWrapHeight(ref.current?.clientHeight) | ||||
| return '' | return '' | ||||
| if (isInNode) | if (isInNode) | ||||
| return 'fixed z-10 right-[9px] top-[166px] bottom-[8px] w-[419px] p-4 bg-white rounded-xl' | |||||
| return 'fixed z-10 right-[9px] top-[166px] bottom-[8px] p-4 bg-white rounded-xl' | |||||
| return 'absolute z-10 left-4 right-6 top-[52px] bottom-0 pb-4 bg-white' | return 'absolute z-10 left-4 right-6 top-[52px] bottom-0 pb-4 bg-white' | ||||
| })() | })() | ||||
| const wrapStyle = isExpand ? { boxShadow: '0px 0px 12px -4px rgba(16, 24, 40, 0.05), 0px -3px 6px -2px rgba(16, 24, 40, 0.03)' } : {} | |||||
| const wrapStyle = isExpand | |||||
| ? { | |||||
| boxShadow: '0px 0px 12px -4px rgba(16, 24, 40, 0.05), 0px -3px 6px -2px rgba(16, 24, 40, 0.03)', | |||||
| width: panelWidth - 1, | |||||
| } | |||||
| : {} | |||||
| return { | return { | ||||
| wrapClassName, | wrapClassName, | ||||
| wrapStyle, | wrapStyle, |
| useNodesReadOnly, | useNodesReadOnly, | ||||
| useNodesSyncDraft, | useNodesSyncDraft, | ||||
| useToolIcon, | useToolIcon, | ||||
| useWorkflow, | |||||
| } from '@/app/components/workflow/hooks' | } from '@/app/components/workflow/hooks' | ||||
| import { canRunBySingle } from '@/app/components/workflow/utils' | import { canRunBySingle } from '@/app/components/workflow/utils' | ||||
| import { Play } from '@/app/components/base/icons/src/vender/line/mediaAndDevices' | import { Play } from '@/app/components/base/icons/src/vender/line/mediaAndDevices' | ||||
| children, | children, | ||||
| }) => { | }) => { | ||||
| const { t } = useTranslation() | const { t } = useTranslation() | ||||
| const initPanelWidth = localStorage.getItem('workflow-node-panel-width') || 420 | |||||
| const panelWidth = localStorage.getItem('workflow-node-panel-width') ? parseFloat(localStorage.getItem('workflow-node-panel-width')!) : 420 | |||||
| const { | |||||
| setPanelWidth, | |||||
| } = useWorkflow() | |||||
| const { handleNodeSelect } = useNodesInteractions() | const { handleNodeSelect } = useNodesInteractions() | ||||
| const { handleSyncWorkflowDraft } = useNodesSyncDraft() | const { handleSyncWorkflowDraft } = useNodesSyncDraft() | ||||
| const { nodesReadOnly } = useNodesReadOnly() | const { nodesReadOnly } = useNodesReadOnly() | ||||
| const availableNextNodes = nodesExtraData[data.type].availableNextNodes | const availableNextNodes = nodesExtraData[data.type].availableNextNodes | ||||
| const toolIcon = useToolIcon(data) | const toolIcon = useToolIcon(data) | ||||
| const handleResized = useCallback((width: number) => { | |||||
| localStorage.setItem('workflow-node-panel-width', `${width}`) | |||||
| }, []) | |||||
| const handleResize = useCallback((width: number) => { | |||||
| setPanelWidth(width) | |||||
| }, [setPanelWidth]) | |||||
| const { | const { | ||||
| triggerRef, | triggerRef, | ||||
| triggerDirection: 'left', | triggerDirection: 'left', | ||||
| minWidth: 420, | minWidth: 420, | ||||
| maxWidth: 720, | maxWidth: 720, | ||||
| onResized: handleResized, | |||||
| onResize: handleResize, | |||||
| }) | }) | ||||
| const { | const { | ||||
| ref={containerRef} | ref={containerRef} | ||||
| className='relative h-full bg-white shadow-lg border-[0.5px] border-gray-200 rounded-2xl overflow-y-auto' | className='relative h-full bg-white shadow-lg border-[0.5px] border-gray-200 rounded-2xl overflow-y-auto' | ||||
| style={{ | style={{ | ||||
| width: `${initPanelWidth}px`, | |||||
| width: `${panelWidth}px`, | |||||
| }} | }} | ||||
| > | > | ||||
| <div className='sticky top-0 bg-white border-b-[0.5px] border-black/5 z-10'> | <div className='sticky top-0 bg-white border-b-[0.5px] border-black/5 z-10'> |
| import type { FC } from 'react' | import type { FC } from 'react' | ||||
| import React, { useMemo } from 'react' | |||||
| import { useStoreApi } from 'reactflow' | |||||
| import React from 'react' | |||||
| import { useTranslation } from 'react-i18next' | import { useTranslation } from 'react-i18next' | ||||
| import { BlockEnum } from '../../types' | |||||
| import MemoryConfig from '../_base/components/memory-config' | import MemoryConfig from '../_base/components/memory-config' | ||||
| import VarReferencePicker from '../_base/components/variable/var-reference-picker' | import VarReferencePicker from '../_base/components/variable/var-reference-picker' | ||||
| import useConfig from './use-config' | import useConfig from './use-config' | ||||
| data, | data, | ||||
| }) => { | }) => { | ||||
| const { t } = useTranslation() | const { t } = useTranslation() | ||||
| const store = useStoreApi() | |||||
| const startNode = useMemo(() => { | |||||
| const nodes = store.getState().getNodes() | |||||
| return nodes.find(node => node.data.type === BlockEnum.Start) | |||||
| }, [store]) | |||||
| const { | const { | ||||
| readOnly, | readOnly, |
| type Shape = { | type Shape = { | ||||
| appId: string | appId: string | ||||
| panelWidth: number | |||||
| workflowRunningData?: WorkflowRunningData | workflowRunningData?: WorkflowRunningData | ||||
| setWorkflowRunningData: (workflowData: WorkflowRunningData) => void | setWorkflowRunningData: (workflowData: WorkflowRunningData) => void | ||||
| historyWorkflowData?: HistoryWorkflowData | historyWorkflowData?: HistoryWorkflowData | ||||
| export const createWorkflowStore = () => { | export const createWorkflowStore = () => { | ||||
| return createStore<Shape>(set => ({ | return createStore<Shape>(set => ({ | ||||
| appId: '', | appId: '', | ||||
| panelWidth: localStorage.getItem('workflow-node-panel-width') ? parseFloat(localStorage.getItem('workflow-node-panel-width')!) : 420, | |||||
| workflowRunningData: undefined, | workflowRunningData: undefined, | ||||
| setWorkflowRunningData: workflowRunningData => set(() => ({ workflowRunningData })), | setWorkflowRunningData: workflowRunningData => set(() => ({ workflowRunningData })), | ||||
| historyWorkflowData: undefined, | historyWorkflowData: undefined, |