mirror of
				https://github.com/langgenius/dify.git
				synced 2025-10-31 19:03:09 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			244 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			244 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| 'use client'
 | |
| 
 | |
| import type { FC } from 'react'
 | |
| import { useEffect } from 'react'
 | |
| import type {
 | |
|   EditorState,
 | |
| } from 'lexical'
 | |
| import {
 | |
|   $getRoot,
 | |
|   TextNode,
 | |
| } from 'lexical'
 | |
| import { CodeNode } from '@lexical/code'
 | |
| import { LexicalComposer } from '@lexical/react/LexicalComposer'
 | |
| import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'
 | |
| import { ContentEditable } from '@lexical/react/LexicalContentEditable'
 | |
| import { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary'
 | |
| import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin'
 | |
| import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin'
 | |
| // import TreeView from './plugins/tree-view'
 | |
| import Placeholder from './plugins/placeholder'
 | |
| import ComponentPickerBlock from './plugins/component-picker-block'
 | |
| import {
 | |
|   ContextBlock,
 | |
|   ContextBlockNode,
 | |
|   ContextBlockReplacementBlock,
 | |
| } from './plugins/context-block'
 | |
| import {
 | |
|   QueryBlock,
 | |
|   QueryBlockNode,
 | |
|   QueryBlockReplacementBlock,
 | |
| } from './plugins/query-block'
 | |
| import {
 | |
|   HistoryBlock,
 | |
|   HistoryBlockNode,
 | |
|   HistoryBlockReplacementBlock,
 | |
| } from './plugins/history-block'
 | |
| import {
 | |
|   WorkflowVariableBlock,
 | |
|   WorkflowVariableBlockNode,
 | |
|   WorkflowVariableBlockReplacementBlock,
 | |
| } from './plugins/workflow-variable-block'
 | |
| import VariableBlock from './plugins/variable-block'
 | |
| import VariableValueBlock from './plugins/variable-value-block'
 | |
| import { VariableValueBlockNode } from './plugins/variable-value-block/node'
 | |
| import { CustomTextNode } from './plugins/custom-text/node'
 | |
| import OnBlurBlock from './plugins/on-blur-or-focus-block'
 | |
| import UpdateBlock from './plugins/update-block'
 | |
| import { textToEditorState } from './utils'
 | |
| import type {
 | |
|   ContextBlockType,
 | |
|   ExternalToolBlockType,
 | |
|   HistoryBlockType,
 | |
|   QueryBlockType,
 | |
|   VariableBlockType,
 | |
|   WorkflowVariableBlockType,
 | |
| } from './types'
 | |
| import {
 | |
|   UPDATE_DATASETS_EVENT_EMITTER,
 | |
|   UPDATE_HISTORY_EVENT_EMITTER,
 | |
| } from './constants'
 | |
| import { useEventEmitterContextContext } from '@/context/event-emitter'
 | |
| import cn from '@/utils/classnames'
 | |
| 
 | |
| export type PromptEditorProps = {
 | |
|   instanceId?: string
 | |
|   compact?: boolean
 | |
|   wrapperClassName?: string
 | |
|   className?: string
 | |
|   placeholder?: string | JSX.Element
 | |
|   placeholderClassName?: string
 | |
|   style?: React.CSSProperties
 | |
|   value?: string
 | |
|   editable?: boolean
 | |
|   onChange?: (text: string) => void
 | |
|   onBlur?: () => void
 | |
|   onFocus?: () => void
 | |
|   contextBlock?: ContextBlockType
 | |
|   queryBlock?: QueryBlockType
 | |
|   historyBlock?: HistoryBlockType
 | |
|   variableBlock?: VariableBlockType
 | |
|   externalToolBlock?: ExternalToolBlockType
 | |
|   workflowVariableBlock?: WorkflowVariableBlockType
 | |
|   isSupportFileVar?: boolean
 | |
| }
 | |
| 
 | |
| const PromptEditor: FC<PromptEditorProps> = ({
 | |
|   instanceId,
 | |
|   compact,
 | |
|   wrapperClassName,
 | |
|   className,
 | |
|   placeholder,
 | |
|   placeholderClassName,
 | |
|   style,
 | |
|   value,
 | |
|   editable = true,
 | |
|   onChange,
 | |
|   onBlur,
 | |
|   onFocus,
 | |
|   contextBlock,
 | |
|   queryBlock,
 | |
|   historyBlock,
 | |
|   variableBlock,
 | |
|   externalToolBlock,
 | |
|   workflowVariableBlock,
 | |
|   isSupportFileVar,
 | |
| }) => {
 | |
|   const { eventEmitter } = useEventEmitterContextContext()
 | |
|   const initialConfig = {
 | |
|     namespace: 'prompt-editor',
 | |
|     nodes: [
 | |
|       CodeNode,
 | |
|       CustomTextNode,
 | |
|       {
 | |
|         replace: TextNode,
 | |
|         with: (node: TextNode) => new CustomTextNode(node.__text),
 | |
|       },
 | |
|       ContextBlockNode,
 | |
|       HistoryBlockNode,
 | |
|       QueryBlockNode,
 | |
|       WorkflowVariableBlockNode,
 | |
|       VariableValueBlockNode,
 | |
|     ],
 | |
|     editorState: textToEditorState(value || ''),
 | |
|     onError: (error: Error) => {
 | |
|       throw error
 | |
|     },
 | |
|   }
 | |
| 
 | |
|   const handleEditorChange = (editorState: EditorState) => {
 | |
|     const text = editorState.read(() => {
 | |
|       return $getRoot().getChildren().map(p => p.getTextContent()).join('\n')
 | |
|     })
 | |
|     if (onChange)
 | |
|       onChange(text)
 | |
|   }
 | |
| 
 | |
|   useEffect(() => {
 | |
|     eventEmitter?.emit({
 | |
|       type: UPDATE_DATASETS_EVENT_EMITTER,
 | |
|       payload: contextBlock?.datasets,
 | |
|     } as any)
 | |
|   }, [eventEmitter, contextBlock?.datasets])
 | |
|   useEffect(() => {
 | |
|     eventEmitter?.emit({
 | |
|       type: UPDATE_HISTORY_EVENT_EMITTER,
 | |
|       payload: historyBlock?.history,
 | |
|     } as any)
 | |
|   }, [eventEmitter, historyBlock?.history])
 | |
| 
 | |
|   return (
 | |
|     <LexicalComposer initialConfig={{ ...initialConfig, editable }}>
 | |
|       <div className={cn('relative', wrapperClassName)}>
 | |
|         <RichTextPlugin
 | |
|           contentEditable={
 | |
|             <ContentEditable
 | |
|               className={cn(
 | |
|                 'text-text-secondary outline-none',
 | |
|                 compact ? 'text-[13px] leading-5' : 'text-sm leading-6',
 | |
|                 className,
 | |
|               )}
 | |
|               style={style || {}}
 | |
|             />
 | |
|           }
 | |
|           placeholder={
 | |
|             <Placeholder
 | |
|               value={placeholder}
 | |
|               className={cn('truncate', placeholderClassName)}
 | |
|               compact={compact}
 | |
|             />
 | |
|           }
 | |
|           ErrorBoundary={LexicalErrorBoundary}
 | |
|         />
 | |
|         <ComponentPickerBlock
 | |
|           triggerString='/'
 | |
|           contextBlock={contextBlock}
 | |
|           historyBlock={historyBlock}
 | |
|           queryBlock={queryBlock}
 | |
|           variableBlock={variableBlock}
 | |
|           externalToolBlock={externalToolBlock}
 | |
|           workflowVariableBlock={workflowVariableBlock}
 | |
|           isSupportFileVar={isSupportFileVar}
 | |
|         />
 | |
|         <ComponentPickerBlock
 | |
|           triggerString='{'
 | |
|           contextBlock={contextBlock}
 | |
|           historyBlock={historyBlock}
 | |
|           queryBlock={queryBlock}
 | |
|           variableBlock={variableBlock}
 | |
|           externalToolBlock={externalToolBlock}
 | |
|           workflowVariableBlock={workflowVariableBlock}
 | |
|           isSupportFileVar={isSupportFileVar}
 | |
|         />
 | |
|         {
 | |
|           contextBlock?.show && (
 | |
|             <>
 | |
|               <ContextBlock {...contextBlock} />
 | |
|               <ContextBlockReplacementBlock {...contextBlock} />
 | |
|             </>
 | |
|           )
 | |
|         }
 | |
|         {
 | |
|           queryBlock?.show && (
 | |
|             <>
 | |
|               <QueryBlock {...queryBlock} />
 | |
|               <QueryBlockReplacementBlock />
 | |
|             </>
 | |
|           )
 | |
|         }
 | |
|         {
 | |
|           historyBlock?.show && (
 | |
|             <>
 | |
|               <HistoryBlock {...historyBlock} />
 | |
|               <HistoryBlockReplacementBlock {...historyBlock} />
 | |
|             </>
 | |
|           )
 | |
|         }
 | |
|         {
 | |
|           (variableBlock?.show || externalToolBlock?.show) && (
 | |
|             <>
 | |
|               <VariableBlock />
 | |
|               <VariableValueBlock />
 | |
|             </>
 | |
|           )
 | |
|         }
 | |
|         {
 | |
|           workflowVariableBlock?.show && (
 | |
|             <>
 | |
|               <WorkflowVariableBlock {...workflowVariableBlock} />
 | |
|               <WorkflowVariableBlockReplacementBlock {...workflowVariableBlock} />
 | |
|             </>
 | |
|           )
 | |
|         }
 | |
|         <OnChangePlugin onChange={handleEditorChange} />
 | |
|         <OnBlurBlock onBlur={onBlur} onFocus={onFocus} />
 | |
|         <UpdateBlock instanceId={instanceId} />
 | |
|         <HistoryPlugin />
 | |
|         {/* <TreeView /> */}
 | |
|       </div>
 | |
|     </LexicalComposer>
 | |
|   )
 | |
| }
 | |
| 
 | |
| export default PromptEditor
 | 
