| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | import { | 
					
						
							|  |  |  |   memo, | 
					
						
							|  |  |  |   useCallback, | 
					
						
							|  |  |  |   useMemo, | 
					
						
							|  |  |  | } from 'react' | 
					
						
							|  |  |  | import { useTranslation } from 'react-i18next' | 
					
						
							|  |  |  | import { groupBy } from 'lodash-es' | 
					
						
							|  |  |  | import BlockIcon from '../block-icon' | 
					
						
							|  |  |  | import { BlockEnum } from '../types' | 
					
						
							|  |  |  | import { | 
					
						
							|  |  |  |   useIsChatMode, | 
					
						
							|  |  |  |   useNodesExtraData, | 
					
						
							|  |  |  | } from '../hooks' | 
					
						
							|  |  |  | import { BLOCK_CLASSIFICATIONS } from './constants' | 
					
						
							|  |  |  | import { useBlocks } from './hooks' | 
					
						
							|  |  |  | import type { ToolDefaultValue } from './types' | 
					
						
							|  |  |  | import Tooltip from '@/app/components/base/tooltip' | 
					
						
							| 
									
										
										
										
											2025-04-01 16:52:07 +08:00
										 |  |  | import Badge from '@/app/components/base/badge' | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | type BlocksProps = { | 
					
						
							|  |  |  |   searchText: string | 
					
						
							|  |  |  |   onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void | 
					
						
							|  |  |  |   availableBlocksTypes?: BlockEnum[] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | const Blocks = ({ | 
					
						
							|  |  |  |   searchText, | 
					
						
							|  |  |  |   onSelect, | 
					
						
							|  |  |  |   availableBlocksTypes = [], | 
					
						
							|  |  |  | }: BlocksProps) => { | 
					
						
							|  |  |  |   const { t } = useTranslation() | 
					
						
							|  |  |  |   const isChatMode = useIsChatMode() | 
					
						
							|  |  |  |   const nodesExtraData = useNodesExtraData() | 
					
						
							|  |  |  |   const blocks = useBlocks() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const groups = useMemo(() => { | 
					
						
							|  |  |  |     return BLOCK_CLASSIFICATIONS.reduce((acc, classification) => { | 
					
						
							|  |  |  |       const list = groupBy(blocks, 'classification')[classification].filter((block) => { | 
					
						
							|  |  |  |         if (block.type === BlockEnum.Answer && !isChatMode) | 
					
						
							|  |  |  |           return false | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return block.title.toLowerCase().includes(searchText.toLowerCase()) && availableBlocksTypes.includes(block.type) | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return { | 
					
						
							|  |  |  |         ...acc, | 
					
						
							|  |  |  |         [classification]: list, | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }, {} as Record<string, typeof blocks>) | 
					
						
							|  |  |  |   }, [blocks, isChatMode, searchText, availableBlocksTypes]) | 
					
						
							|  |  |  |   const isEmpty = Object.values(groups).every(list => !list.length) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const renderGroup = useCallback((classification: string) => { | 
					
						
							|  |  |  |     const list = groups[classification] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ( | 
					
						
							|  |  |  |       <div | 
					
						
							|  |  |  |         key={classification} | 
					
						
							|  |  |  |         className='mb-1 last-of-type:mb-0' | 
					
						
							|  |  |  |       > | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           classification !== '-' && !!list.length && ( | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |             <div className='flex h-[22px] items-start px-3 text-xs font-medium text-text-tertiary'> | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |               {t(`workflow.tabs.${classification}`)} | 
					
						
							|  |  |  |             </div> | 
					
						
							|  |  |  |           ) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           list.map(block => ( | 
					
						
							|  |  |  |             <Tooltip | 
					
						
							|  |  |  |               key={block.type} | 
					
						
							|  |  |  |               position='right' | 
					
						
							| 
									
										
										
										
											2024-12-17 12:20:49 +08:00
										 |  |  |               popupClassName='w-[200px]' | 
					
						
							| 
									
										
										
										
											2024-08-26 13:00:02 +08:00
										 |  |  |               popupContent={( | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |                 <div> | 
					
						
							| 
									
										
										
										
											2024-05-09 17:18:51 +08:00
										 |  |  |                   <BlockIcon | 
					
						
							|  |  |  |                     size='md' | 
					
						
							|  |  |  |                     className='mb-2' | 
					
						
							|  |  |  |                     type={block.type} | 
					
						
							|  |  |  |                   /> | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |                   <div className='system-md-medium mb-1 text-text-primary'>{block.title}</div> | 
					
						
							|  |  |  |                   <div className='system-xs-regular text-text-tertiary'>{nodesExtraData[block.type].about}</div> | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |                 </div> | 
					
						
							|  |  |  |               )} | 
					
						
							|  |  |  |             > | 
					
						
							|  |  |  |               <div | 
					
						
							|  |  |  |                 key={block.type} | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |                 className='flex h-8 w-full cursor-pointer items-center rounded-lg px-3 hover:bg-state-base-hover' | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |                 onClick={() => onSelect(block.type)} | 
					
						
							|  |  |  |               > | 
					
						
							|  |  |  |                 <BlockIcon | 
					
						
							| 
									
										
										
										
											2024-05-09 17:18:51 +08:00
										 |  |  |                   className='mr-2 shrink-0' | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |                   type={block.type} | 
					
						
							|  |  |  |                 /> | 
					
						
							| 
									
										
										
										
											2025-04-01 16:52:07 +08:00
										 |  |  |                 <div className='grow text-sm text-text-secondary'>{block.title}</div> | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                   block.type === BlockEnum.LoopEnd && ( | 
					
						
							|  |  |  |                     <Badge | 
					
						
							|  |  |  |                       text={t('workflow.nodes.loop.loopNode')} | 
					
						
							|  |  |  |                       className='ml-2 shrink-0' | 
					
						
							|  |  |  |                     /> | 
					
						
							|  |  |  |                   ) | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |               </div> | 
					
						
							|  |  |  |             </Tooltip> | 
					
						
							|  |  |  |           )) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       </div> | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |   }, [groups, nodesExtraData, onSelect, t]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return ( | 
					
						
							|  |  |  |     <div className='p-1'> | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         isEmpty && ( | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |           <div className='flex h-[22px] items-center px-3 text-xs font-medium text-text-tertiary'>{t('workflow.tabs.noResult')}</div> | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |         ) | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         !isEmpty && BLOCK_CLASSIFICATIONS.map(renderGroup) | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     </div> | 
					
						
							|  |  |  |   ) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export default memo(Blocks) |