wwf
2 天以前 a430284aa21e3ae1f0d5654e55b2ad2852519cc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import {
  useCallback,
} from 'react'
import { useTranslation } from 'react-i18next'
import { RiMoreFill } from '@remixicon/react'
import { intersection } from 'lodash-es'
import {
  PortalToFollowElem,
  PortalToFollowElemContent,
  PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem'
import Button from '@/app/components/base/button'
import BlockSelector from '@/app/components/workflow/block-selector'
import {
  useAvailableBlocks,
  useNodesInteractions,
} from '@/app/components/workflow/hooks'
import type {
  CommonNodeType,
  OnSelectBlock,
} from '@/app/components/workflow/types'
 
type ChangeItemProps = {
  data: CommonNodeType
  nodeId: string
  sourceHandle: string
}
const ChangeItem = ({
  data,
  nodeId,
  sourceHandle,
}: ChangeItemProps) => {
  const { t } = useTranslation()
 
  const { handleNodeChange } = useNodesInteractions()
  const {
    availablePrevBlocks,
    availableNextBlocks,
  } = useAvailableBlocks(data.type, data.isInIteration)
 
  const handleSelect = useCallback<OnSelectBlock>((type, toolDefaultValue) => {
    handleNodeChange(nodeId, type, sourceHandle, toolDefaultValue)
  }, [nodeId, sourceHandle, handleNodeChange])
 
  const renderTrigger = useCallback(() => {
    return (
      <div className='flex items-center px-2 h-8 rounded-lg cursor-pointer hover:bg-state-base-hover'>
        {t('workflow.panel.change')}
      </div>
    )
  }, [t])
 
  return (
    <BlockSelector
      onSelect={handleSelect}
      placement='top-end'
      offset={{
        mainAxis: 6,
        crossAxis: 8,
      }}
      trigger={renderTrigger}
      popupClassName='!w-[328px]'
      availableBlocksTypes={intersection(availablePrevBlocks, availableNextBlocks).filter(item => item !== data.type)}
    />
  )
}
 
type OperatorProps = {
  open: boolean
  onOpenChange: (v: boolean) => void
  data: CommonNodeType
  nodeId: string
  sourceHandle: string
}
const Operator = ({
  open,
  onOpenChange,
  data,
  nodeId,
  sourceHandle,
}: OperatorProps) => {
  const { t } = useTranslation()
  const {
    handleNodeDelete,
    handleNodeDisconnect,
  } = useNodesInteractions()
 
  return (
    <PortalToFollowElem
      placement='bottom-end'
      offset={{ mainAxis: 4, crossAxis: -4 }}
      open={open}
      onOpenChange={onOpenChange}
    >
      <PortalToFollowElemTrigger onClick={() => onOpenChange(!open)}>
        <Button className='p-0 w-6 h-6'>
          <RiMoreFill className='w-4 h-4' />
        </Button>
      </PortalToFollowElemTrigger>
      <PortalToFollowElemContent className='z-10'>
        <div className='min-w-[120px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg system-md-regular text-text-secondary'>
          <div className='p-1'>
            <ChangeItem
              data={data}
              nodeId={nodeId}
              sourceHandle={sourceHandle}
            />
            <div
              className='flex items-center px-2 h-8 rounded-lg cursor-pointer hover:bg-state-base-hover'
              onClick={() => handleNodeDisconnect(nodeId)}
            >
              {t('workflow.common.disconnect')}
            </div>
          </div>
          <div className='p-1'>
            <div
              className='flex items-center px-2 h-8 rounded-lg cursor-pointer hover:bg-state-base-hover'
              onClick={() => handleNodeDelete(nodeId)}
            >
              {t('common.operation.delete')}
            </div>
          </div>
        </div>
      </PortalToFollowElemContent>
    </PortalToFollowElem>
  )
}
 
export default Operator