mirror of https://github.com/langgenius/dify.git
files
This commit is contained in:
parent
736ec55f86
commit
177be06d09
|
|
@ -0,0 +1,35 @@
|
|||
import type { FC } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useSelectOrDelete } from '../../hooks'
|
||||
import { DELETE_HITL_INPUT_BLOCK_COMMAND } from './'
|
||||
import { UserEdit02 } from '@/app/components/base/icons/src/vender/solid/users'
|
||||
|
||||
type QueryBlockComponentProps = {
|
||||
nodeKey: string
|
||||
nodeName: string
|
||||
varName: string
|
||||
}
|
||||
|
||||
const HITLInputComponent: FC<QueryBlockComponentProps> = ({
|
||||
nodeKey,
|
||||
nodeName,
|
||||
varName,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const [ref, isSelected] = useSelectOrDelete(nodeKey, DELETE_HITL_INPUT_BLOCK_COMMAND)
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
inline-flex h-6 items-center rounded-[5px] border border-transparent bg-[#FFF6ED] pl-1 pr-0.5 hover:bg-[#FFEAD5]
|
||||
${isSelected && '!border-[#FD853A]'}
|
||||
`}
|
||||
ref={ref}
|
||||
>
|
||||
<UserEdit02 className='mr-1 h-[14px] w-[14px] text-[#FD853A]' />
|
||||
{nodeName}/{varName}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default HITLInputComponent
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
useEffect,
|
||||
} from 'react'
|
||||
import type { TextNode } from 'lexical'
|
||||
import { $applyNodeReplacement } from 'lexical'
|
||||
import { mergeRegister } from '@lexical/utils'
|
||||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
||||
import { decoratorTransform } from '../../utils'
|
||||
import type { QueryBlockType } from '../../types'
|
||||
import { $createHITLInputNode } from './node'
|
||||
import {
|
||||
QueryBlockNode,
|
||||
} from '../query-block/node'
|
||||
import { CustomTextNode } from '../custom-text/node'
|
||||
import { HITL_INPUT_REG } from '@/config'
|
||||
|
||||
const REGEX = new RegExp(HITL_INPUT_REG)
|
||||
|
||||
const QueryBlockReplacementBlock = ({
|
||||
onInsert,
|
||||
}: QueryBlockType) => {
|
||||
const [editor] = useLexicalComposerContext()
|
||||
|
||||
useEffect(() => {
|
||||
if (!editor.hasNodes([QueryBlockNode]))
|
||||
throw new Error('QueryBlockNodePlugin: QueryBlockNode not registered on editor')
|
||||
}, [editor])
|
||||
|
||||
const createHITLInputBlockNode = useCallback((textNode: TextNode): QueryBlockNode => {
|
||||
if (onInsert)
|
||||
onInsert()
|
||||
const varName = textNode.getTextContent().split('.')[1]
|
||||
return $applyNodeReplacement($createHITLInputNode(varName))
|
||||
}, [onInsert])
|
||||
|
||||
const getMatch = useCallback((text: string) => {
|
||||
const matchArr = REGEX.exec(text)
|
||||
|
||||
if (matchArr === null)
|
||||
return null
|
||||
|
||||
const startOffset = matchArr.index
|
||||
const endOffset = startOffset + matchArr[0].length
|
||||
return {
|
||||
end: endOffset,
|
||||
start: startOffset,
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
REGEX.lastIndex = 0
|
||||
return mergeRegister(
|
||||
editor.registerNodeTransform(CustomTextNode, textNode => decoratorTransform(textNode, getMatch, createHITLInputBlockNode)),
|
||||
)
|
||||
}, [])
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export default memo(QueryBlockReplacementBlock)
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
import {
|
||||
memo,
|
||||
useEffect,
|
||||
} from 'react'
|
||||
import {
|
||||
createCommand,
|
||||
} from 'lexical'
|
||||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
||||
import type { QueryBlockType } from '../../types'
|
||||
import {
|
||||
HITLInputNode,
|
||||
} from './node'
|
||||
|
||||
export const INSERT_HITL_INPUT_BLOCK_COMMAND = createCommand('INSERT_HITL_INPUT_BLOCK_COMMAND')
|
||||
export const DELETE_HITL_INPUT_BLOCK_COMMAND = createCommand('DELETE_HITL_INPUT_BLOCK_COMMAND')
|
||||
|
||||
export type HITLInputProps = {
|
||||
onInsert?: () => void
|
||||
onDelete?: () => void
|
||||
}
|
||||
const HITLInputBlock = memo(({
|
||||
onInsert,
|
||||
onDelete,
|
||||
}: QueryBlockType) => {
|
||||
const [editor] = useLexicalComposerContext()
|
||||
|
||||
useEffect(() => {
|
||||
if (!editor.hasNodes([HITLInputNode]))
|
||||
throw new Error('HITLInputBlockPlugin: HITLInputBlock not registered on editor')
|
||||
}, [editor, onInsert, onDelete])
|
||||
|
||||
// TODO
|
||||
// const createHITLBlockNode = useCallback
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
HITLInputBlock.displayName = 'HITLInputBlock'
|
||||
|
||||
export { HITLInputBlock }
|
||||
export { HITLInputNode } from './node'
|
||||
export { default as HITLInputBlockReplacementBlock } from './hitl-input-block-replacement-block'
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
import type { LexicalNode, NodeKey, SerializedLexicalNode } from 'lexical'
|
||||
import { DecoratorNode } from 'lexical'
|
||||
import HILTInputBlockComponent from './component'
|
||||
|
||||
export type SerializedNode = SerializedLexicalNode & {
|
||||
variableName: string
|
||||
}
|
||||
|
||||
export class HITLInputNode extends DecoratorNode<React.JSX.Element> {
|
||||
__variableName: string
|
||||
|
||||
static getType(): string {
|
||||
return 'hitl-input-block'
|
||||
}
|
||||
|
||||
getVariableName(): string {
|
||||
const self = this.getLatest()
|
||||
return self.__variableName
|
||||
}
|
||||
|
||||
static clone(node: HITLInputNode): HITLInputNode {
|
||||
return new HITLInputNode(node.__variableName, node.__key)
|
||||
}
|
||||
|
||||
isInline(): boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
constructor(varName: string, key?: NodeKey) {
|
||||
super(key)
|
||||
|
||||
this.__variableName = varName
|
||||
}
|
||||
|
||||
createDOM(): HTMLElement {
|
||||
const div = document.createElement('div')
|
||||
div.classList.add('inline-flex', 'items-center', 'align-middle')
|
||||
return div
|
||||
}
|
||||
|
||||
updateDOM(): false {
|
||||
return false
|
||||
}
|
||||
|
||||
decorate(): React.JSX.Element {
|
||||
return <HILTInputBlockComponent nodeKey={this.getKey()} nodeName='todo' varName={this.getVariableName()} />
|
||||
}
|
||||
|
||||
static importJSON(serializedNode: SerializedNode): HITLInputNode {
|
||||
const node = $createHITLInputNode(serializedNode.variableName)
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
exportJSON(): SerializedNode {
|
||||
return {
|
||||
type: 'hitl-input-block',
|
||||
version: 1,
|
||||
variableName: this.getVariableName(),
|
||||
}
|
||||
}
|
||||
|
||||
getTextContent(): string {
|
||||
return `{{#$outputs.${this.getVariableName()}#}}`
|
||||
}
|
||||
}
|
||||
|
||||
export function $createHITLInputNode(variableName: string): HITLInputNode {
|
||||
return new HITLInputNode(variableName)
|
||||
}
|
||||
|
||||
export function $isHITLInputNode(
|
||||
node: HITLInputNode | LexicalNode | null | undefined,
|
||||
): node is HITLInputNode {
|
||||
return node instanceof HITLInputNode
|
||||
}
|
||||
Loading…
Reference in New Issue