import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { $insertNodes } from 'lexical'
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
import type {
ContextBlockType,
ExternalToolBlockType,
HistoryBlockType,
QueryBlockType,
VariableBlockType,
WorkflowVariableBlockType,
} from '../../types'
import { INSERT_CONTEXT_BLOCK_COMMAND } from '../context-block'
import { INSERT_HISTORY_BLOCK_COMMAND } from '../history-block'
import { INSERT_QUERY_BLOCK_COMMAND } from '../query-block'
import { INSERT_VARIABLE_VALUE_BLOCK_COMMAND } from '../variable-block'
import { $createCustomTextNode } from '../custom-text/node'
import { PromptMenuItem } from './prompt-option'
import { VariableMenuItem } from './variable-option'
import { PickerBlockMenuOption } from './menu'
import { File05 } from '@/app/components/base/icons/src/vender/solid/files'
import {
MessageClockCircle,
Tool03,
} from '@/app/components/base/icons/src/vender/solid/general'
import { BracketsX } from '@/app/components/base/icons/src/vender/line/development'
import { UserEdit02 } from '@/app/components/base/icons/src/vender/solid/users'
import { ArrowUpRight } from '@/app/components/base/icons/src/vender/line/arrows'
import AppIcon from '@/app/components/base/app-icon'
export const usePromptOptions = (
contextBlock?: ContextBlockType,
queryBlock?: QueryBlockType,
historyBlock?: HistoryBlockType,
) => {
const { t } = useTranslation()
const [editor] = useLexicalComposerContext()
const promptOptions: PickerBlockMenuOption[] = []
if (contextBlock?.show) {
promptOptions.push(new PickerBlockMenuOption({
key: t('common.promptEditor.context.item.title'),
group: 'prompt context',
render: ({ isSelected, onSelect, onSetHighlight }) => {
return }
disabled={!contextBlock.selectable}
isSelected={isSelected}
onClick={onSelect}
onMouseEnter={onSetHighlight}
/>
},
onSelect: () => {
if (!contextBlock?.selectable)
return
editor.dispatchCommand(INSERT_CONTEXT_BLOCK_COMMAND, undefined)
},
}))
}
if (queryBlock?.show) {
promptOptions.push(
new PickerBlockMenuOption({
key: t('common.promptEditor.query.item.title'),
group: 'prompt query',
render: ({ isSelected, onSelect, onSetHighlight }) => {
return (
}
disabled={!queryBlock.selectable}
isSelected={isSelected}
onClick={onSelect}
onMouseEnter={onSetHighlight}
/>
)
},
onSelect: () => {
if (!queryBlock?.selectable)
return
editor.dispatchCommand(INSERT_QUERY_BLOCK_COMMAND, undefined)
},
}),
)
}
if (historyBlock?.show) {
promptOptions.push(
new PickerBlockMenuOption({
key: t('common.promptEditor.history.item.title'),
group: 'prompt history',
render: ({ isSelected, onSelect, onSetHighlight }) => {
return (
}
disabled={!historyBlock.selectable
}
isSelected={isSelected}
onClick={onSelect}
onMouseEnter={onSetHighlight}
/>
)
},
onSelect: () => {
if (!historyBlock?.selectable)
return
editor.dispatchCommand(INSERT_HISTORY_BLOCK_COMMAND, undefined)
},
}),
)
}
return promptOptions
}
export const useVariableOptions = (
variableBlock?: VariableBlockType,
queryString?: string,
): PickerBlockMenuOption[] => {
const { t } = useTranslation()
const [editor] = useLexicalComposerContext()
const options = useMemo(() => {
if (!variableBlock?.variables)
return []
const baseOptions = (variableBlock.variables).map((item) => {
return new PickerBlockMenuOption({
key: item.value,
group: 'prompt variable',
render: ({ queryString, isSelected, onSelect, onSetHighlight }) => {
return (
}
queryString={queryString}
isSelected={isSelected}
onClick={onSelect}
onMouseEnter={onSetHighlight}
/>
)
},
onSelect: () => {
editor.dispatchCommand(INSERT_VARIABLE_VALUE_BLOCK_COMMAND, `{{${item.value}}}`)
},
})
})
if (!queryString)
return baseOptions
const regex = new RegExp(queryString, 'i')
return baseOptions.filter(option => regex.test(option.key))
}, [editor, queryString, variableBlock])
const addOption = useMemo(() => {
return new PickerBlockMenuOption({
key: t('common.promptEditor.variable.modal.add'),
group: 'prompt variable',
render: ({ queryString, isSelected, onSelect, onSetHighlight }) => {
return (
}
queryString={queryString}
isSelected={isSelected}
onClick={onSelect}
onMouseEnter={onSetHighlight}
/>
)
},
onSelect: () => {
editor.update(() => {
const prefixNode = $createCustomTextNode('{{')
const suffixNode = $createCustomTextNode('}}')
$insertNodes([prefixNode, suffixNode])
prefixNode.select()
})
},
})
}, [editor, t])
return useMemo(() => {
return variableBlock?.show ? [...options, addOption] : []
}, [options, addOption, variableBlock?.show])
}
export const useExternalToolOptions = (
externalToolBlockType?: ExternalToolBlockType,
queryString?: string,
) => {
const { t } = useTranslation()
const [editor] = useLexicalComposerContext()
const options = useMemo(() => {
if (!externalToolBlockType?.externalTools)
return []
const baseToolOptions = (externalToolBlockType.externalTools).map((item) => {
return new PickerBlockMenuOption({
key: item.name,
group: 'external tool',
render: ({ queryString, isSelected, onSelect, onSetHighlight }) => {
return (
}
extraElement={
{item.variableName}
}
queryString={queryString}
isSelected={isSelected}
onClick={onSelect}
onMouseEnter={onSetHighlight}
/>
)
},
onSelect: () => {
editor.dispatchCommand(INSERT_VARIABLE_VALUE_BLOCK_COMMAND, `{{${item.variableName}}}`)
},
})
})
if (!queryString)
return baseToolOptions
const regex = new RegExp(queryString, 'i')
return baseToolOptions.filter(option => regex.test(option.key))
}, [editor, queryString, externalToolBlockType])
const addOption = useMemo(() => {
return new PickerBlockMenuOption({
key: t('common.promptEditor.variable.modal.addTool'),
group: 'external tool',
render: ({ queryString, isSelected, onSelect, onSetHighlight }) => {
return (
}
extraElement={< ArrowUpRight className='w-3 h-3 text-gray-400' />}
queryString={queryString}
isSelected={isSelected}
onClick={onSelect}
onMouseEnter={onSetHighlight}
/>
)
},
onSelect: () => {
externalToolBlockType?.onAddExternalTool?.()
},
})
}, [externalToolBlockType, t])
return useMemo(() => {
return externalToolBlockType?.show ? [...options, addOption] : []
}, [options, addOption, externalToolBlockType?.show])
}
export const useOptions = (
contextBlock?: ContextBlockType,
queryBlock?: QueryBlockType,
historyBlock?: HistoryBlockType,
variableBlock?: VariableBlockType,
externalToolBlockType?: ExternalToolBlockType,
workflowVariableBlockType?: WorkflowVariableBlockType,
queryString?: string,
) => {
const promptOptions = usePromptOptions(contextBlock, queryBlock, historyBlock)
const variableOptions = useVariableOptions(variableBlock, queryString)
const externalToolOptions = useExternalToolOptions(externalToolBlockType, queryString)
const workflowVariableOptions = useMemo(() => {
if (!workflowVariableBlockType?.show)
return []
return workflowVariableBlockType.variables || []
}, [workflowVariableBlockType])
return useMemo(() => {
return {
workflowVariableOptions,
allFlattenOptions: [...promptOptions, ...variableOptions, ...externalToolOptions],
}
}, [promptOptions, variableOptions, externalToolOptions, workflowVariableOptions])
}