Skip to content

Commit af9448e

Browse files
perzeusszxhlyh
andauthored
feat: undo/redo for workflow editor (langgenius#3927)
Co-authored-by: StyleZhang <[email protected]>
1 parent d0fe56a commit af9448e

38 files changed

+2054
-783
lines changed

ArrowUturnLeft.svg

+3
Loading

web/app/components/base/icons/assets/vender/line/arrows/flip-backward.svg

-3
This file was deleted.

web/app/components/base/icons/assets/vender/line/arrows/flip-forward.svg

-5
This file was deleted.

web/app/components/base/icons/src/vender/line/arrows/FlipBackward.json

-29
This file was deleted.

web/app/components/base/icons/src/vender/line/arrows/FlipBackward.tsx

-16
This file was deleted.

web/app/components/base/icons/src/vender/line/arrows/FlipForward.json

-39
This file was deleted.

web/app/components/base/icons/src/vender/line/arrows/FlipForward.tsx

-16
This file was deleted.

web/app/components/base/icons/src/vender/line/arrows/index.ts

-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ export { default as ArrowUpRight } from './ArrowUpRight'
33
export { default as ChevronDownDouble } from './ChevronDownDouble'
44
export { default as ChevronRight } from './ChevronRight'
55
export { default as ChevronSelectorVertical } from './ChevronSelectorVertical'
6-
export { default as FlipBackward } from './FlipBackward'
7-
export { default as FlipForward } from './FlipForward'
86
export { default as RefreshCcw01 } from './RefreshCcw01'
97
export { default as RefreshCw05 } from './RefreshCw05'
108
export { default as ReverseLeft } from './ReverseLeft'

web/app/components/workflow/candidate-node.tsx

+7-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
useStore,
1313
useWorkflowStore,
1414
} from './store'
15-
import { useNodesInteractions } from './hooks'
15+
import { WorkflowHistoryEvent, useNodesInteractions, useWorkflowHistory } from './hooks'
1616
import { CUSTOM_NODE } from './constants'
1717
import CustomNode from './nodes'
1818
import CustomNoteNode from './note-node'
@@ -26,6 +26,7 @@ const CandidateNode = () => {
2626
const mousePosition = useStore(s => s.mousePosition)
2727
const { zoom } = useViewport()
2828
const { handleNodeSelect } = useNodesInteractions()
29+
const { saveStateToHistory } = useWorkflowHistory()
2930

3031
useEventListener('click', (e) => {
3132
const { candidateNode, mousePosition } = workflowStore.getState()
@@ -53,6 +54,11 @@ const CandidateNode = () => {
5354
})
5455
})
5556
setNodes(newNodes)
57+
if (candidateNode.type === CUSTOM_NOTE_NODE)
58+
saveStateToHistory(WorkflowHistoryEvent.NoteAdd)
59+
else
60+
saveStateToHistory(WorkflowHistoryEvent.NodeAdd)
61+
5662
workflowStore.setState({ candidateNode: undefined })
5763

5864
if (candidateNode.type === CUSTOM_NOTE_NODE)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import type { FC } from 'react'
2+
import { memo, useEffect, useState } from 'react'
3+
import { useTranslation } from 'react-i18next'
4+
import {
5+
RiArrowGoBackLine,
6+
RiArrowGoForwardFill,
7+
} from '@remixicon/react'
8+
import TipPopup from '../operator/tip-popup'
9+
import { useWorkflowHistoryStore } from '../workflow-history-store'
10+
import { useNodesReadOnly } from '@/app/components/workflow/hooks'
11+
import ViewWorkflowHistory from '@/app/components/workflow/header/view-workflow-history'
12+
13+
export type UndoRedoProps = { handleUndo: () => void; handleRedo: () => void }
14+
const UndoRedo: FC<UndoRedoProps> = ({ handleUndo, handleRedo }) => {
15+
const { t } = useTranslation()
16+
const { store } = useWorkflowHistoryStore()
17+
const [buttonsDisabled, setButtonsDisabled] = useState({ undo: true, redo: true })
18+
19+
useEffect(() => {
20+
const unsubscribe = store.temporal.subscribe((state) => {
21+
setButtonsDisabled({
22+
undo: state.pastStates.length === 0,
23+
redo: state.futureStates.length === 0,
24+
})
25+
})
26+
return () => unsubscribe()
27+
}, [store])
28+
29+
const { nodesReadOnly } = useNodesReadOnly()
30+
31+
return (
32+
<div className='flex items-center p-0.5 rounded-lg border-[0.5px] border-gray-100 bg-white shadow-lg text-gray-500'>
33+
<TipPopup title={t('workflow.common.undo')!} >
34+
<div
35+
data-tooltip-id='workflow.undo'
36+
className={`
37+
flex items-center px-1.5 w-8 h-8 rounded-md text-[13px] font-medium
38+
hover:bg-black/5 hover:text-gray-700 cursor-pointer select-none
39+
${(nodesReadOnly || buttonsDisabled.undo) && 'hover:bg-transparent opacity-50 !cursor-not-allowed'}
40+
`}
41+
onClick={() => !nodesReadOnly && !buttonsDisabled.undo && handleUndo()}
42+
>
43+
<RiArrowGoBackLine className='h-4 w-4' />
44+
</div>
45+
</TipPopup>
46+
<TipPopup title={t('workflow.common.redo')!} >
47+
<div
48+
data-tooltip-id='workflow.redo'
49+
className={`
50+
flex items-center px-1.5 w-8 h-8 rounded-md text-[13px] font-medium
51+
hover:bg-black/5 hover:text-gray-700 cursor-pointer select-none
52+
${(nodesReadOnly || buttonsDisabled.redo) && 'hover:bg-transparent opacity-50 !cursor-not-allowed'}
53+
`}
54+
onClick={() => !nodesReadOnly && !buttonsDisabled.redo && handleRedo()}
55+
>
56+
<RiArrowGoForwardFill className='h-4 w-4' />
57+
</div>
58+
</TipPopup>
59+
<div className="mx-[3px] w-[1px] h-3.5 bg-gray-200"></div>
60+
<ViewWorkflowHistory />
61+
</div>
62+
)
63+
}
64+
65+
export default memo(UndoRedo)

0 commit comments

Comments
 (0)