mirror of https://github.com/langgenius/dify.git
fix chat
This commit is contained in:
parent
5ee7fc4fde
commit
05f97f6e06
|
|
@ -1,4 +1,4 @@
|
|||
import React from 'react'
|
||||
import { memo } from 'react'
|
||||
import type { ConnectionLineComponentProps } from 'reactflow'
|
||||
import {
|
||||
Position,
|
||||
|
|
@ -36,4 +36,4 @@ const CustomConnectionLine = ({ fromX, fromY, toX, toY }: ConnectionLineComponen
|
|||
)
|
||||
}
|
||||
|
||||
export default CustomConnectionLine
|
||||
export default memo(CustomConnectionLine)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
import { useState } from 'react'
|
||||
import {
|
||||
memo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useStore } from '../store'
|
||||
import {
|
||||
useStore,
|
||||
useWorkflowStore,
|
||||
} from '../store'
|
||||
import Button from '@/app/components/base/button'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
|
|
@ -12,13 +18,17 @@ import { useStore as useAppStore } from '@/app/components/app/store'
|
|||
|
||||
const Publish = () => {
|
||||
const { t } = useTranslation()
|
||||
const workflowStore = useWorkflowStore()
|
||||
const runningStatus = useStore(s => s.runningStatus)
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const handlePublish = async () => {
|
||||
const appId = useAppStore.getState().appDetail?.id
|
||||
try {
|
||||
await publishWorkflow(`/apps/${appId}/workflows/publish`)
|
||||
const res = await publishWorkflow(`/apps/${appId}/workflows/publish`)
|
||||
|
||||
if (res)
|
||||
workflowStore.setState({ publishedAt: res.created_at })
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
|
|
@ -86,4 +96,4 @@ const Publish = () => {
|
|||
)
|
||||
}
|
||||
|
||||
export default Publish
|
||||
export default memo(Publish)
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ export const useNodesInteractions = () => {
|
|||
const connectingNodeRef = useRef<{ nodeId: string; handleType: HandleType } | null>(null)
|
||||
|
||||
const handleNodeDragStart = useCallback<NodeDragHandler>((_, node) => {
|
||||
workflowStore.setState({ nodeAnimation: false })
|
||||
const {
|
||||
runningStatus,
|
||||
} = workflowStore.getState()
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import {
|
|||
NodeRunningStatus,
|
||||
WorkflowRunningStatus,
|
||||
} from '../types'
|
||||
import { NODE_WIDTH } from '../constants'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import type { IOtherOptions } from '@/service/base'
|
||||
import { ssePost } from '@/service/base'
|
||||
|
|
@ -135,19 +134,17 @@ export const useWorkflowRun = () => {
|
|||
onNodeStarted: ({ data }) => {
|
||||
const nodes = getNodes()
|
||||
const {
|
||||
getViewport,
|
||||
setViewport,
|
||||
} = reactflow
|
||||
|
||||
const viewport = getViewport()
|
||||
const currentNodeIndex = nodes.findIndex(node => node.id === data.node_id)
|
||||
const currentNode = nodes[currentNodeIndex]
|
||||
const position = currentNode.position
|
||||
const zoom = 0.5
|
||||
const zoom = 1
|
||||
|
||||
setViewport({
|
||||
x: (clientWidth - 400 - currentNode.width!) / 2 - position.x,
|
||||
y: (clientHeight - currentNode.height!) / 2 - position.y,
|
||||
zoom,
|
||||
x: (((clientWidth - 400) / 2 - NODE_WIDTH / 2) / viewport.zoom - position.x) * zoom,
|
||||
y: ((clientHeight / 2 - currentNode.height! / 2) / viewport.zoom - position.y) * zoom,
|
||||
})
|
||||
const newNodes = produce(nodes, (draft) => {
|
||||
draft[currentNodeIndex].data._runningStatus = NodeRunningStatus.Running
|
||||
|
|
|
|||
|
|
@ -47,10 +47,12 @@ export const useIsChatMode = () => {
|
|||
export const useWorkflow = () => {
|
||||
const store = useStoreApi()
|
||||
const reactflow = useReactFlow()
|
||||
const workflowStore = useWorkflowStore()
|
||||
const nodesExtraData = useNodesExtraData()
|
||||
const { handleSyncWorkflowDraft } = useNodesSyncDraft()
|
||||
|
||||
const handleLayout = useCallback(async () => {
|
||||
workflowStore.setState({ nodeAnimation: true })
|
||||
const {
|
||||
getNodes,
|
||||
edges,
|
||||
|
|
@ -70,13 +72,16 @@ export const useWorkflow = () => {
|
|||
})
|
||||
})
|
||||
setNodes(newNodes)
|
||||
const zoom = 0.7
|
||||
setViewport({
|
||||
x: 0,
|
||||
y: 0,
|
||||
zoom: 0.8,
|
||||
zoom,
|
||||
})
|
||||
setTimeout(() => handleSyncWorkflowDraft())
|
||||
}, [store, reactflow, handleSyncWorkflowDraft])
|
||||
setTimeout(() => {
|
||||
handleSyncWorkflowDraft()
|
||||
})
|
||||
}, [store, reactflow, handleSyncWorkflowDraft, workflowStore])
|
||||
|
||||
const getTreeLeafNodes = useCallback((nodeId: string) => {
|
||||
const {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import ReactFlow, {
|
|||
} from 'reactflow'
|
||||
import type { Viewport } from 'reactflow'
|
||||
import 'reactflow/dist/style.css'
|
||||
import './style.css'
|
||||
import type {
|
||||
Edge,
|
||||
Node,
|
||||
|
|
@ -61,6 +62,7 @@ const Workflow: FC<WorkflowProps> = memo(({
|
|||
}) => {
|
||||
const showFeaturesPanel = useStore(state => state.showFeaturesPanel)
|
||||
const runningStatus = useStore(s => s.runningStatus)
|
||||
const nodeAnimation = useStore(s => s.nodeAnimation)
|
||||
const { handleSyncWorkflowDraft } = useNodesSyncDraft()
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -99,7 +101,11 @@ const Workflow: FC<WorkflowProps> = memo(({
|
|||
return (
|
||||
<div
|
||||
id='workflow-container'
|
||||
className='relative w-full min-w-[960px] h-full bg-[#F0F2F7]'
|
||||
className={`
|
||||
relative w-full min-w-[960px] h-full bg-[#F0F2F7]
|
||||
${runningStatus && 'workflow-panel-animation'}
|
||||
${nodeAnimation && 'workflow-node-animation'}
|
||||
`}
|
||||
>
|
||||
<Header />
|
||||
<Panel />
|
||||
|
|
@ -109,7 +115,6 @@ const Workflow: FC<WorkflowProps> = memo(({
|
|||
}
|
||||
<HelpLine />
|
||||
<ReactFlow
|
||||
className='workflow-inner'
|
||||
nodeTypes={nodeTypes}
|
||||
edgeTypes={edgeTypes}
|
||||
nodes={nodes}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,10 @@ const Add = ({
|
|||
>
|
||||
{
|
||||
branchName && (
|
||||
<div className='absolute left-1 -top-[7.5px] flex items-center px-0.5 h-3 bg-white text-[10px] text-gray-500 font-semibold rounded-[5px]'>
|
||||
<div
|
||||
className='absolute left-1 right-1 -top-[7.5px] flex items-center px-0.5 h-3 bg-white text-[10px] text-gray-500 font-semibold rounded-[5px] truncate'
|
||||
title={branchName.toLocaleUpperCase()}
|
||||
>
|
||||
{branchName.toLocaleUpperCase()}
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ const NextStep = ({
|
|||
selectedNode,
|
||||
}: NextStepProps) => {
|
||||
const store = useStoreApi()
|
||||
const branches = selectedNode.data._targetBranches
|
||||
const branches = selectedNode.data._targetBranches || []
|
||||
const nodeWithBranches = selectedNode.data.type === BlockEnum.IfElse || selectedNode.data.type === BlockEnum.QuestionClassifier
|
||||
const edges = useEdges()
|
||||
const outgoers = getOutgoers(selectedNode as Node, store.getState().getNodes(), edges)
|
||||
|
|
@ -36,7 +36,7 @@ const NextStep = ({
|
|||
toolProviderId={selectedNode!.data.provider_id}
|
||||
/>
|
||||
</div>
|
||||
<Line linesNumber={branches ? branches.length : 1} />
|
||||
<Line linesNumber={nodeWithBranches ? branches.length : 1} />
|
||||
<div className='grow'>
|
||||
{
|
||||
!nodeWithBranches && !!outgoers.length && (
|
||||
|
|
|
|||
|
|
@ -55,7 +55,10 @@ const Item = ({
|
|||
>
|
||||
{
|
||||
branchName && (
|
||||
<div className='absolute left-1 -top-[7.5px] flex items-center px-0.5 h-3 bg-white text-[10px] text-gray-500 font-semibold rounded-[5px]'>
|
||||
<div
|
||||
className='absolute left-1 right-1 -top-[7.5px] flex items-center px-0.5 h-3 bg-white text-[10px] text-gray-500 font-semibold rounded-[5px] truncate'
|
||||
title={branchName.toLocaleUpperCase()}
|
||||
>
|
||||
{branchName.toLocaleUpperCase()}
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,10 @@ import {
|
|||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useNodeDataUpdate } from '../../../hooks'
|
||||
import {
|
||||
useNodeDataUpdate,
|
||||
useNodesInteractions,
|
||||
} from '../../../hooks'
|
||||
import type { Node } from '../../../types'
|
||||
import { canRunBySingle } from '../../../utils'
|
||||
import PanelOperator from './panel-operator'
|
||||
|
|
@ -23,6 +26,7 @@ const NodeControl: FC<NodeControlProps> = ({
|
|||
const { t } = useTranslation()
|
||||
const [open, setOpen] = useState(false)
|
||||
const { handleNodeDataUpdate } = useNodeDataUpdate()
|
||||
const { handleNodeSelect } = useNodesInteractions()
|
||||
|
||||
const handleOpenChange = useCallback((newOpen: boolean) => {
|
||||
setOpen(newOpen)
|
||||
|
|
@ -51,6 +55,7 @@ const NodeControl: FC<NodeControlProps> = ({
|
|||
_isSingleRun: !data._isSingleRun,
|
||||
},
|
||||
})
|
||||
handleNodeSelect(id)
|
||||
}}
|
||||
>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ export const NodeComponentMap: Record<string, ComponentType<any>> = {
|
|||
[BlockEnum.VariableAssigner]: VariableAssignerNode,
|
||||
}
|
||||
|
||||
export const PanelComponentMap: Record<string, ComponentType> = {
|
||||
export const PanelComponentMap: Record<string, ComponentType<any>> = {
|
||||
[BlockEnum.Start]: StartPanel,
|
||||
[BlockEnum.End]: EndPanel,
|
||||
[BlockEnum.Answer]: AnswerPanel,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { useChat } from './hooks'
|
|||
import Chat from '@/app/components/base/chat/chat'
|
||||
import type { OnSend } from '@/app/components/base/chat/types'
|
||||
import { useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||
import { fetchConvesationMessages } from '@/service/debug'
|
||||
import { fetchSuggestedQuestions } from '@/service/debug'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
|
||||
const ChatWrapper = () => {
|
||||
|
|
@ -49,10 +49,10 @@ const ChatWrapper = () => {
|
|||
query,
|
||||
files,
|
||||
inputs: workflowStore.getState().inputs,
|
||||
conversationId,
|
||||
conversation_id: conversationId,
|
||||
},
|
||||
{
|
||||
onGetSuggestedQuestions: (conversationId, getAbortController) => fetchConvesationMessages(appId, conversationId, getAbortController),
|
||||
onGetSuggestedQuestions: (messageId, getAbortController) => fetchSuggestedQuestions(appId, messageId, getAbortController),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import type { FC } from 'react'
|
||||
import { memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useStore } from '../../store'
|
||||
import ChatWrapper from './chat-wrapper'
|
||||
|
||||
const DebugAndPreview: FC = () => {
|
||||
const DebugAndPreview = () => {
|
||||
const { t } = useTranslation()
|
||||
const showRunHistory = useStore(s => s.showRunHistory)
|
||||
|
||||
|
|
@ -28,4 +28,4 @@ const DebugAndPreview: FC = () => {
|
|||
)
|
||||
}
|
||||
|
||||
export default DebugAndPreview
|
||||
export default memo(DebugAndPreview)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ const UserInput = () => {
|
|||
})
|
||||
}
|
||||
|
||||
if (!variables.length)
|
||||
return null
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ import Run from '../run'
|
|||
import { useStore } from '../store'
|
||||
|
||||
const Record = () => {
|
||||
const { currentSequenceNumber, workflowRunId } = useStore()
|
||||
const currentSequenceNumber = useStore(s => s.currentSequenceNumber)
|
||||
const workflowRunId = useStore(s => s.workflowRunId)
|
||||
|
||||
return (
|
||||
<div className='flex flex-col w-[400px] h-full rounded-2xl border-[0.5px] border-gray-200 shadow-xl bg-white'>
|
||||
<div className='flex items-center justify-between p-4 pb-1 text-base font-semibold text-gray-900'>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import type {
|
|||
ToolInWorkflow,
|
||||
ToolsMap,
|
||||
} from './block-selector/types'
|
||||
import { Mode } from './types'
|
||||
import type {
|
||||
Edge,
|
||||
Node,
|
||||
|
|
@ -22,7 +21,6 @@ import type {
|
|||
import { WorkflowContext } from './context'
|
||||
|
||||
type State = {
|
||||
mode: Mode
|
||||
taskId: string
|
||||
currentSequenceNumber: number
|
||||
workflowRunId: string
|
||||
|
|
@ -44,10 +42,10 @@ type State = {
|
|||
}
|
||||
notInitialWorkflow: boolean
|
||||
nodesDefaultConfigs: Record<string, any>
|
||||
nodeAnimation: boolean
|
||||
}
|
||||
|
||||
type Action = {
|
||||
setMode: (mode: Mode) => void
|
||||
setTaskId: (taskId: string) => void
|
||||
setCurrentSequenceNumber: (currentSequenceNumber: number) => void
|
||||
setWorkflowRunId: (workflowRunId: string) => void
|
||||
|
|
@ -65,18 +63,17 @@ type Action = {
|
|||
setBackupDraft: (backupDraft?: State['backupDraft']) => void
|
||||
setNotInitialWorkflow: (notInitialWorkflow: boolean) => void
|
||||
setNodesDefaultConfigs: (nodesDefaultConfigs: Record<string, any>) => void
|
||||
setNodeAnimation: (nodeAnimation: boolean) => void
|
||||
}
|
||||
|
||||
export const createWorkflowStore = () => {
|
||||
return create<State & Action>(set => ({
|
||||
mode: Mode.Editing,
|
||||
taskId: '',
|
||||
setTaskId: taskId => set(() => ({ taskId })),
|
||||
currentSequenceNumber: 0,
|
||||
setCurrentSequenceNumber: currentSequenceNumber => set(() => ({ currentSequenceNumber })),
|
||||
workflowRunId: '',
|
||||
setWorkflowRunId: workflowRunId => set(() => ({ workflowRunId })),
|
||||
setMode: mode => set(() => ({ mode })),
|
||||
showRunHistory: false,
|
||||
setShowRunHistory: showRunHistory => set(() => ({ showRunHistory })),
|
||||
showFeaturesPanel: false,
|
||||
|
|
@ -105,6 +102,8 @@ export const createWorkflowStore = () => {
|
|||
setNotInitialWorkflow: notInitialWorkflow => set(() => ({ notInitialWorkflow })),
|
||||
nodesDefaultConfigs: {},
|
||||
setNodesDefaultConfigs: nodesDefaultConfigs => set(() => ({ nodesDefaultConfigs })),
|
||||
nodeAnimation: false,
|
||||
setNodeAnimation: nodeAnimation => set(() => ({ nodeAnimation })),
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
.workflow-panel-animation .react-flow__viewport {
|
||||
transition: transform 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.workflow-node-animation .react-flow__node {
|
||||
transition: transform 0.2s ease-in-out;
|
||||
}
|
||||
|
|
@ -173,11 +173,6 @@ export type NodeDefault<T> = {
|
|||
|
||||
export type OnSelectBlock = (type: BlockEnum, toolDefaultValue?: ToolDefaultValue) => void
|
||||
|
||||
export enum Mode {
|
||||
Editing = 'editing',
|
||||
Running = 'running',
|
||||
}
|
||||
|
||||
export enum WorkflowRunningStatus {
|
||||
Waiting = 'waiting',
|
||||
Running = 'running',
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ export const getLayoutByDagre = (originNodes: Node[], originEdges: Edge[]) => {
|
|||
rankdir: 'LR',
|
||||
align: 'UL',
|
||||
nodesep: 64,
|
||||
ranksep: 64,
|
||||
ranksep: 40,
|
||||
})
|
||||
nodes.forEach((node) => {
|
||||
dagreGraph.setNode(node.id, { width: node.width, height: node.height })
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ export const singleNodeRun = (appId: string, nodeId: string, params: object) =>
|
|||
}
|
||||
|
||||
export const publishWorkflow = (url: string) => {
|
||||
return post<CommonResponse>(url)
|
||||
return post<CommonResponse & { created_at: number }>(url)
|
||||
}
|
||||
|
||||
export const stopWorkflowRun = (url: string) => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue