mirror of https://github.com/langgenius/dify.git
fix prompt editor
This commit is contained in:
parent
e08d871837
commit
45d5d259a4
|
|
@ -166,6 +166,7 @@ const Prompt: FC<ISimplePromptInput> = ({
|
|||
>
|
||||
<PromptEditor
|
||||
className='min-h-[210px]'
|
||||
compact
|
||||
value={promptTemplate}
|
||||
contextBlock={{
|
||||
show: false,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,10 @@ import {
|
|||
$getRoot,
|
||||
TextNode,
|
||||
} from 'lexical'
|
||||
import { CodeNode } from '@lexical/code'
|
||||
import {
|
||||
CodeHighlightNode,
|
||||
CodeNode,
|
||||
} from '@lexical/code'
|
||||
import { LexicalComposer } from '@lexical/react/LexicalComposer'
|
||||
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'
|
||||
import { ContentEditable } from '@lexical/react/LexicalContentEditable'
|
||||
|
|
@ -44,6 +47,7 @@ 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 CodeHighlightBlock from './plugins/code-highlight-block'
|
||||
import { textToEditorState } from './utils'
|
||||
import type {
|
||||
ContextBlockType,
|
||||
|
|
@ -61,6 +65,7 @@ import { useEventEmitterContextContext } from '@/context/event-emitter'
|
|||
|
||||
export type PromptEditorProps = {
|
||||
instanceId?: string
|
||||
compact?: boolean
|
||||
className?: string
|
||||
placeholder?: string
|
||||
placeholderClassName?: string
|
||||
|
|
@ -80,6 +85,7 @@ export type PromptEditorProps = {
|
|||
|
||||
const PromptEditor: FC<PromptEditorProps> = ({
|
||||
instanceId,
|
||||
compact,
|
||||
className,
|
||||
placeholder,
|
||||
placeholderClassName,
|
||||
|
|
@ -101,6 +107,7 @@ const PromptEditor: FC<PromptEditorProps> = ({
|
|||
namespace: 'prompt-editor',
|
||||
nodes: [
|
||||
CodeNode,
|
||||
CodeHighlightNode,
|
||||
CustomTextNode,
|
||||
{
|
||||
replace: TextNode,
|
||||
|
|
@ -141,8 +148,8 @@ const PromptEditor: FC<PromptEditorProps> = ({
|
|||
<LexicalComposer initialConfig={{ ...initialConfig, editable }}>
|
||||
<div className='relative'>
|
||||
<RichTextPlugin
|
||||
contentEditable={<ContentEditable className={`${className} outline-none text-sm text-gray-700 leading-6`} style={style || {}} />}
|
||||
placeholder={<Placeholder value={placeholder} className={placeholderClassName} />}
|
||||
contentEditable={<ContentEditable className={`${className} outline-none ${compact ? 'leading-5 text-[13px]' : 'leading-6 text-sm'} text-gray-700`} style={style || {}} />}
|
||||
placeholder={<Placeholder value={placeholder} className={placeholderClassName} compact={compact} />}
|
||||
ErrorBoundary={LexicalErrorBoundary}
|
||||
/>
|
||||
<ComponentPickerBlock
|
||||
|
|
@ -207,6 +214,7 @@ const PromptEditor: FC<PromptEditorProps> = ({
|
|||
<OnChangePlugin onChange={handleEditorChange} />
|
||||
<OnBlurBlock onBlur={onBlur} onFocus={onFocus} />
|
||||
<UpdateBlock instanceId={instanceId} />
|
||||
<CodeHighlightBlock />
|
||||
{/* <TreeView /> */}
|
||||
</div>
|
||||
</LexicalComposer>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
import { useEffect } from 'react'
|
||||
import { registerCodeHighlighting } from '@lexical/code'
|
||||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
||||
|
||||
export default function CodeHighlightPlugin() {
|
||||
const [editor] = useLexicalComposerContext()
|
||||
|
||||
useEffect(() => {
|
||||
return registerCodeHighlighting(editor)
|
||||
}, [editor])
|
||||
|
||||
return null
|
||||
}
|
||||
|
|
@ -195,7 +195,7 @@ export const useOptions = (
|
|||
variableOptions,
|
||||
externalToolOptions,
|
||||
workflowVariableOptions,
|
||||
allOptions: [...promptOptions, ...variableOptions, ...externalToolOptions, ...workflowVariableOptions],
|
||||
allOptions: [...promptOptions, ...variableOptions, ...externalToolOptions],
|
||||
}
|
||||
}, [promptOptions, variableOptions, externalToolOptions, workflowVariableOptions])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,11 +82,12 @@ const ComponentPicker = ({
|
|||
matchingString: string,
|
||||
) => {
|
||||
editor.update(() => {
|
||||
if (nodeToRemove)
|
||||
if (nodeToRemove && selectedOption?.key)
|
||||
nodeToRemove.remove()
|
||||
|
||||
if (selectedOption?.onSelect)
|
||||
selectedOption.onSelect(matchingString)
|
||||
|
||||
closeMenu()
|
||||
})
|
||||
},
|
||||
|
|
@ -104,9 +105,9 @@ const ComponentPicker = ({
|
|||
anchorElementRef,
|
||||
{ selectedIndex, selectOptionAndCleanUp, setHighlightedIndex },
|
||||
) => {
|
||||
if (anchorElementRef.current && allOptions.length) {
|
||||
if (anchorElementRef.current && (allOptions.length || workflowVariableOptions.length)) {
|
||||
return ReactDOM.createPortal(
|
||||
<div className='mt-[25px] w-[260px] bg-white rounded-lg border-[0.5px] border-gray-200 shadow-lg'>
|
||||
<div className='w-[260px] bg-white rounded-lg border-[0.5px] border-gray-200 shadow-lg'>
|
||||
{
|
||||
!!promptOptions.length && (
|
||||
<>
|
||||
|
|
@ -196,8 +197,7 @@ const ComponentPicker = ({
|
|||
<VarReferenceVars
|
||||
hideSearch
|
||||
vars={workflowVariableOptions}
|
||||
onChange={(variables: string[], item: any) => {
|
||||
selectOptionAndCleanUp(item)
|
||||
onChange={(variables: string[]) => {
|
||||
handleSelectWorkflowVariable(variables)
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,20 +1,27 @@
|
|||
import { memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import cn from 'classnames'
|
||||
|
||||
const Placeholder = ({
|
||||
compact,
|
||||
value,
|
||||
className,
|
||||
}: {
|
||||
compact?: boolean
|
||||
value?: string
|
||||
className?: string
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<div className={cn(className, 'absolute top-0 left-0 h-full w-full text-sm text-gray-300 select-none pointer-events-none leading-6')}>
|
||||
<div className={cn(
|
||||
className,
|
||||
'absolute top-0 left-0 h-full w-full text-sm text-gray-300 select-none pointer-events-none',
|
||||
compact ? 'leading-5 text-[13px]' : 'leading-6 text-sm',
|
||||
)}>
|
||||
{value || t('common.promptEditor.placeholder')}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Placeholder
|
||||
export default memo(Placeholder)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
import { $insertNodes } from 'lexical'
|
||||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
||||
import { textToEditorState } from '../utils'
|
||||
import { CustomTextNode } from './custom-text/node'
|
||||
import { useEventEmitterContextContext } from '@/context/event-emitter'
|
||||
|
||||
export const PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER = 'PROMPT_EDITOR_UPDATE_VALUE_BY_EVENT_EMITTER'
|
||||
export const PROMPT_EDITOR_INSERT_QUICKLY = 'PROMPT_EDITOR_INSERT_QUICKLY'
|
||||
|
||||
type UpdateBlockProps = {
|
||||
instanceId?: string
|
||||
|
|
@ -20,6 +23,16 @@ const UpdateBlock = ({
|
|||
}
|
||||
})
|
||||
|
||||
eventEmitter?.useSubscription((v: any) => {
|
||||
if (v.type === PROMPT_EDITOR_INSERT_QUICKLY && v.instanceId === instanceId) {
|
||||
editor.focus()
|
||||
editor.update(() => {
|
||||
const textNode = new CustomTextNode('/')
|
||||
$insertNodes([textNode])
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ const WorkflowVariableBlockComponent: FC<WorkflowVariableBlockComponentProps> =
|
|||
return (
|
||||
<div
|
||||
className={`
|
||||
mr-[2px] relative group/wrap flex items-center h-[20px] pl-0.5 pr-[3px] rounded-[5px] border
|
||||
mx-0.5 relative group/wrap flex items-center h-[18px] pl-0.5 pr-[3px] rounded-[5px] border
|
||||
${isSelected ? ' border-[#84ADFF] bg-[#F5F8FF]' : ' border-black/5 bg-white'}
|
||||
`}
|
||||
ref={ref}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import {
|
|||
useEffect,
|
||||
} from 'react'
|
||||
import {
|
||||
$getNodeByKey,
|
||||
$getPreviousSelection,
|
||||
$insertNodes,
|
||||
COMMAND_PRIORITY_EDITOR,
|
||||
createCommand,
|
||||
|
|
@ -39,9 +41,16 @@ const WorkflowVariableBlock = memo(({
|
|||
editor.registerCommand(
|
||||
INSERT_WORKFLOW_VARIABLE_BLOCK_COMMAND,
|
||||
(variables: string[]) => {
|
||||
const contextBlockNode = $createWorkflowVariableBlockNode(variables, getWorkflowNode)
|
||||
const workflowVariableBlockNode = $createWorkflowVariableBlockNode(variables, getWorkflowNode)
|
||||
const prevNodeKey = ($getPreviousSelection() as any)?.anchor?.key
|
||||
|
||||
$insertNodes([contextBlockNode])
|
||||
if (prevNodeKey) {
|
||||
const prevNode = $getNodeByKey(prevNodeKey)
|
||||
|
||||
prevNode?.remove()
|
||||
}
|
||||
|
||||
$insertNodes([workflowVariableBlockNode])
|
||||
if (onInsert)
|
||||
onInsert()
|
||||
|
||||
|
|
|
|||
|
|
@ -15,8 +15,11 @@ import { Clipboard, ClipboardCheck } from '@/app/components/base/icons/src/vende
|
|||
import s from '@/app/components/app/configuration/config-prompt/style.module.css'
|
||||
import { Trash03 } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import TooltipPlus from '@/app/components/base/tooltip-plus'
|
||||
import { useEventEmitterContextContext } from '@/context/event-emitter'
|
||||
import { PROMPT_EDITOR_INSERT_QUICKLY } from '@/app/components/base/prompt-editor/plugins/update-block'
|
||||
|
||||
type Props = {
|
||||
instanceId?: string
|
||||
title: string | JSX.Element
|
||||
value: string
|
||||
onChange: (value: string) => void
|
||||
|
|
@ -36,6 +39,7 @@ type Props = {
|
|||
}
|
||||
|
||||
const Editor: FC<Props> = ({
|
||||
instanceId,
|
||||
title,
|
||||
value,
|
||||
onChange,
|
||||
|
|
@ -51,6 +55,7 @@ const Editor: FC<Props> = ({
|
|||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const { getNode } = useWorkflow()
|
||||
const { eventEmitter } = useEventEmitterContextContext()
|
||||
|
||||
const isShowHistory = !isChatModel && isChatApp
|
||||
const isShowQuery = isShowHistory
|
||||
|
|
@ -75,6 +80,11 @@ const Editor: FC<Props> = ({
|
|||
setFalse: setBlur,
|
||||
}] = useBoolean(false)
|
||||
|
||||
const handleInsertVariable = () => {
|
||||
setFocus()
|
||||
eventEmitter?.emit({ type: PROMPT_EDITOR_INSERT_QUICKLY, instanceId } as any)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cn(wrapClassName)}>
|
||||
<div ref={ref} className={cn(isFocus ? s.gradientBorder : 'bg-gray-100', isExpand && 'h-full', '!rounded-[9px] p-0.5')}>
|
||||
|
|
@ -114,7 +124,10 @@ const Editor: FC<Props> = ({
|
|||
<TooltipPlus
|
||||
popupContent={`${t('workflow.common.insertVarTip')}`}
|
||||
>
|
||||
<div className="h-[18px] leading-[18px] px-1 rounded-md bg-gray-100 text-xs text-gray-500">{'{x} '}{t('workflow.nodes.common.insertVarTip')}</div>
|
||||
<div
|
||||
className="h-[18px] leading-[18px] px-1 rounded-md bg-gray-100 text-xs text-gray-500"
|
||||
onClick={handleInsertVariable}
|
||||
>{'{x} '}{t('workflow.nodes.common.insertVarTip')}</div>
|
||||
</TooltipPlus>)
|
||||
: <div className='h-[18px]'></div>}
|
||||
</div>
|
||||
|
|
@ -123,7 +136,9 @@ const Editor: FC<Props> = ({
|
|||
>
|
||||
<>
|
||||
<PromptEditor
|
||||
instanceId={instanceId}
|
||||
className={cn('min-h-[84px]')}
|
||||
compact
|
||||
style={isExpand ? { height: editorExpandHeight - 5 } : {}}
|
||||
value={value}
|
||||
contextBlock={{
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ const ConfigPrompt: FC<Props> = ({
|
|||
(payload as PromptItem[]).map((item, index) => {
|
||||
return (
|
||||
<Editor
|
||||
instanceId={`${nodeId}-chat-workflow-llm-prompt-editor-${item.role}-${index}`}
|
||||
key={index}
|
||||
title={
|
||||
<div className='relative left-1 flex items-center'>
|
||||
|
|
@ -160,6 +161,7 @@ const ConfigPrompt: FC<Props> = ({
|
|||
: (
|
||||
<div>
|
||||
<Editor
|
||||
instanceId={`${nodeId}-chat-workflow-llm-prompt-editor`}
|
||||
title={<span className='capitalize'>{t(`${i18nPrefix}.prompt`)}</span>}
|
||||
value={(payload as PromptItem).text}
|
||||
onChange={handleCompletionPromptChange}
|
||||
|
|
|
|||
Loading…
Reference in New Issue