mirror of
https://github.com/langgenius/dify.git
synced 2026-05-13 08:57:28 +08:00
feat: support picker vars files ui in editor
This commit is contained in:
parent
27de07e93d
commit
2650ceb0a6
@ -29,6 +29,8 @@ import {
|
|||||||
} from 'lexical'
|
} from 'lexical'
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
|
import { FileReferenceNode } from '@/app/components/workflow/skill/editor/skill-editor/plugins/file-reference-block/node'
|
||||||
|
import FileReferenceReplacementBlock from '@/app/components/workflow/skill/editor/skill-editor/plugins/file-reference-block/replacement-block'
|
||||||
import { useEventEmitterContextContext } from '@/context/event-emitter'
|
import { useEventEmitterContextContext } from '@/context/event-emitter'
|
||||||
import { cn } from '@/utils/classnames'
|
import { cn } from '@/utils/classnames'
|
||||||
import {
|
import {
|
||||||
@ -41,13 +43,13 @@ import {
|
|||||||
ContextBlockNode,
|
ContextBlockNode,
|
||||||
ContextBlockReplacementBlock,
|
ContextBlockReplacementBlock,
|
||||||
} from './plugins/context-block'
|
} from './plugins/context-block'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CurrentBlock,
|
CurrentBlock,
|
||||||
CurrentBlockNode,
|
CurrentBlockNode,
|
||||||
CurrentBlockReplacementBlock,
|
CurrentBlockReplacementBlock,
|
||||||
} from './plugins/current-block'
|
} from './plugins/current-block'
|
||||||
import { CustomTextNode } from './plugins/custom-text/node'
|
import { CustomTextNode } from './plugins/custom-text/node'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ErrorMessageBlock,
|
ErrorMessageBlock,
|
||||||
ErrorMessageBlockNode,
|
ErrorMessageBlockNode,
|
||||||
@ -106,6 +108,7 @@ export type PromptEditorProps = {
|
|||||||
lastRunBlock?: LastRunBlockType
|
lastRunBlock?: LastRunBlockType
|
||||||
agentBlock?: AgentBlockType
|
agentBlock?: AgentBlockType
|
||||||
isSupportFileVar?: boolean
|
isSupportFileVar?: boolean
|
||||||
|
isSupportSandbox?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const PromptEditor: FC<PromptEditorProps> = ({
|
const PromptEditor: FC<PromptEditorProps> = ({
|
||||||
@ -132,6 +135,7 @@ const PromptEditor: FC<PromptEditorProps> = ({
|
|||||||
lastRunBlock,
|
lastRunBlock,
|
||||||
agentBlock,
|
agentBlock,
|
||||||
isSupportFileVar,
|
isSupportFileVar,
|
||||||
|
isSupportSandbox,
|
||||||
}) => {
|
}) => {
|
||||||
const { eventEmitter } = useEventEmitterContextContext()
|
const { eventEmitter } = useEventEmitterContextContext()
|
||||||
const initialConfig = {
|
const initialConfig = {
|
||||||
@ -152,6 +156,7 @@ const PromptEditor: FC<PromptEditorProps> = ({
|
|||||||
CurrentBlockNode,
|
CurrentBlockNode,
|
||||||
ErrorMessageBlockNode,
|
ErrorMessageBlockNode,
|
||||||
LastRunBlockNode, // LastRunBlockNode is used for error message block replacement
|
LastRunBlockNode, // LastRunBlockNode is used for error message block replacement
|
||||||
|
...(isSupportSandbox ? [FileReferenceNode] : []),
|
||||||
],
|
],
|
||||||
editorState: textToEditorState(value || ''),
|
editorState: textToEditorState(value || ''),
|
||||||
onError: (error: Error) => {
|
onError: (error: Error) => {
|
||||||
@ -215,6 +220,7 @@ const PromptEditor: FC<PromptEditorProps> = ({
|
|||||||
errorMessageBlock={errorMessageBlock}
|
errorMessageBlock={errorMessageBlock}
|
||||||
lastRunBlock={lastRunBlock}
|
lastRunBlock={lastRunBlock}
|
||||||
isSupportFileVar={isSupportFileVar}
|
isSupportFileVar={isSupportFileVar}
|
||||||
|
isSupportSandbox={isSupportSandbox}
|
||||||
/>
|
/>
|
||||||
{(!agentBlock || agentBlock.show) && (
|
{(!agentBlock || agentBlock.show) && (
|
||||||
<ComponentPickerBlock
|
<ComponentPickerBlock
|
||||||
@ -244,6 +250,7 @@ const PromptEditor: FC<PromptEditorProps> = ({
|
|||||||
errorMessageBlock={errorMessageBlock}
|
errorMessageBlock={errorMessageBlock}
|
||||||
lastRunBlock={lastRunBlock}
|
lastRunBlock={lastRunBlock}
|
||||||
isSupportFileVar={isSupportFileVar}
|
isSupportFileVar={isSupportFileVar}
|
||||||
|
isSupportSandbox={isSupportSandbox}
|
||||||
/>
|
/>
|
||||||
{
|
{
|
||||||
contextBlock?.show && (
|
contextBlock?.show && (
|
||||||
@ -285,6 +292,7 @@ const PromptEditor: FC<PromptEditorProps> = ({
|
|||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
{isSupportSandbox && <FileReferenceReplacementBlock />}
|
||||||
{
|
{
|
||||||
currentBlock?.show && (
|
currentBlock?.show && (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@ -38,9 +38,13 @@ import {
|
|||||||
useState,
|
useState,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
import { GeneratorType } from '@/app/components/app/configuration/config/automatic/types'
|
import { GeneratorType } from '@/app/components/app/configuration/config/automatic/types'
|
||||||
|
import { SegmentedControl } from '@/app/components/base/segmented-control'
|
||||||
import AgentNodeList from '@/app/components/workflow/nodes/_base/components/agent-node-list'
|
import AgentNodeList from '@/app/components/workflow/nodes/_base/components/agent-node-list'
|
||||||
import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars'
|
import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars'
|
||||||
|
import { FilePickerPanel } from '@/app/components/workflow/skill/editor/skill-editor/plugins/file-picker-panel'
|
||||||
|
import { $createFileReferenceNode } from '@/app/components/workflow/skill/editor/skill-editor/plugins/file-reference-block/node'
|
||||||
import { BlockEnum } from '@/app/components/workflow/types'
|
import { BlockEnum } from '@/app/components/workflow/types'
|
||||||
import { useEventEmitterContextContext } from '@/context/event-emitter'
|
import { useEventEmitterContextContext } from '@/context/event-emitter'
|
||||||
import { useBasicTypeaheadTriggerMatch } from '../../hooks'
|
import { useBasicTypeaheadTriggerMatch } from '../../hooks'
|
||||||
@ -66,6 +70,7 @@ type ComponentPickerProps = {
|
|||||||
lastRunBlock?: LastRunBlockType
|
lastRunBlock?: LastRunBlockType
|
||||||
agentBlock?: AgentBlockType
|
agentBlock?: AgentBlockType
|
||||||
isSupportFileVar?: boolean
|
isSupportFileVar?: boolean
|
||||||
|
isSupportSandbox?: boolean
|
||||||
}
|
}
|
||||||
const ComponentPicker = ({
|
const ComponentPicker = ({
|
||||||
triggerString,
|
triggerString,
|
||||||
@ -80,7 +85,9 @@ const ComponentPicker = ({
|
|||||||
lastRunBlock,
|
lastRunBlock,
|
||||||
agentBlock,
|
agentBlock,
|
||||||
isSupportFileVar,
|
isSupportFileVar,
|
||||||
|
isSupportSandbox,
|
||||||
}: ComponentPickerProps) => {
|
}: ComponentPickerProps) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
const { eventEmitter } = useEventEmitterContextContext()
|
const { eventEmitter } = useEventEmitterContextContext()
|
||||||
const { refs, floatingStyles, isPositioned } = useFloating({
|
const { refs, floatingStyles, isPositioned } = useFloating({
|
||||||
placement: 'bottom-start',
|
placement: 'bottom-start',
|
||||||
@ -114,6 +121,7 @@ const ComponentPicker = ({
|
|||||||
}, [checkForTriggerMatch, editor])
|
}, [checkForTriggerMatch, editor])
|
||||||
|
|
||||||
const [queryString, setQueryString] = useState<string | null>(null)
|
const [queryString, setQueryString] = useState<string | null>(null)
|
||||||
|
const [activeTab, setActiveTab] = useState<'variables' | 'files'>('variables')
|
||||||
|
|
||||||
eventEmitter?.useSubscription((v: any) => {
|
eventEmitter?.useSubscription((v: any) => {
|
||||||
if (v.type === INSERT_VARIABLE_VALUE_BLOCK_COMMAND)
|
if (v.type === INSERT_VARIABLE_VALUE_BLOCK_COMMAND)
|
||||||
@ -153,6 +161,17 @@ const ComponentPicker = ({
|
|||||||
[editor],
|
[editor],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const handleSelectFileReference = useCallback((resourceId: string) => {
|
||||||
|
editor.update(() => {
|
||||||
|
const match = checkForTriggerMatch(triggerString, editor)
|
||||||
|
const nodeToRemove = match ? $splitNodeContainingQuery(match) : null
|
||||||
|
if (nodeToRemove)
|
||||||
|
nodeToRemove.remove()
|
||||||
|
|
||||||
|
$insertNodes([$createFileReferenceNode({ resourceId })])
|
||||||
|
})
|
||||||
|
}, [checkForTriggerMatch, editor, triggerString])
|
||||||
|
|
||||||
const handleSelectWorkflowVariable = useCallback((variables: string[]) => {
|
const handleSelectWorkflowVariable = useCallback((variables: string[]) => {
|
||||||
editor.update(() => {
|
editor.update(() => {
|
||||||
const match = getMatchFromSelection()
|
const match = getMatchFromSelection()
|
||||||
@ -227,6 +246,10 @@ const ComponentPicker = ({
|
|||||||
const isAgentTrigger = triggerString === '@' && agentBlock?.show
|
const isAgentTrigger = triggerString === '@' && agentBlock?.show
|
||||||
const showAssembleVariables = triggerString === '/'
|
const showAssembleVariables = triggerString === '/'
|
||||||
const agentNodes: AgentNode[] = useMemo(() => agentBlock?.agentNodes || [], [agentBlock?.agentNodes])
|
const agentNodes: AgentNode[] = useMemo(() => agentBlock?.agentNodes || [], [agentBlock?.agentNodes])
|
||||||
|
const handleOpen = useCallback(() => {
|
||||||
|
if (isSupportSandbox && triggerString === '/')
|
||||||
|
setActiveTab('variables')
|
||||||
|
}, [isSupportSandbox, triggerString])
|
||||||
|
|
||||||
const renderMenu = useCallback<MenuRenderFn<PickerBlockMenuOption>>((
|
const renderMenu = useCallback<MenuRenderFn<PickerBlockMenuOption>>((
|
||||||
anchorElementRef,
|
anchorElementRef,
|
||||||
@ -240,12 +263,87 @@ const ComponentPicker = ({
|
|||||||
if (!(anchorElementRef.current && (allFlattenOptions.length || workflowVariableBlock?.show)))
|
if (!(anchorElementRef.current && (allFlattenOptions.length || workflowVariableBlock?.show)))
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
const isSandboxMenu = isSupportSandbox && triggerString === '/'
|
||||||
|
|
||||||
|
if (!(anchorElementRef.current && (isSandboxMenu || allFlattenOptions.length || workflowVariableBlock?.show)))
|
||||||
|
return null
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (anchorElementRef.current)
|
if (anchorElementRef.current)
|
||||||
refs.setReference(anchorElementRef.current)
|
refs.setReference(anchorElementRef.current)
|
||||||
}, 0)
|
}, 0)
|
||||||
|
|
||||||
|
if (isSandboxMenu) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{ReactDOM.createPortal(
|
||||||
|
<div className="h-0 w-0">
|
||||||
|
<div
|
||||||
|
className="w-[300px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-2 shadow-lg"
|
||||||
|
style={{
|
||||||
|
...floatingStyles,
|
||||||
|
visibility: isPositioned ? 'visible' : 'hidden',
|
||||||
|
}}
|
||||||
|
ref={refs.setFloating}
|
||||||
|
>
|
||||||
|
<SegmentedControl
|
||||||
|
size="small"
|
||||||
|
padding="with"
|
||||||
|
activeState="accent"
|
||||||
|
className="w-full"
|
||||||
|
btnClassName="flex-1"
|
||||||
|
options={[
|
||||||
|
{
|
||||||
|
value: 'variables',
|
||||||
|
text: t('promptEditor.variable.outputToolDisabledItem.title', { ns: 'common' }),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'files',
|
||||||
|
text: t('nodes.llm.files', { ns: 'workflow' }),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
value={activeTab}
|
||||||
|
onChange={setActiveTab}
|
||||||
|
/>
|
||||||
|
<div className="mt-2">
|
||||||
|
{activeTab === 'variables' && (
|
||||||
|
<VarReferenceVars
|
||||||
|
searchBoxClassName="mt-1"
|
||||||
|
vars={workflowVariableOptions}
|
||||||
|
onChange={(variables: string[]) => {
|
||||||
|
handleSelectWorkflowVariable(variables)
|
||||||
|
handleClose()
|
||||||
|
}}
|
||||||
|
maxHeightClass="max-h-[34vh]"
|
||||||
|
isSupportFileVar={isSupportFileVar}
|
||||||
|
onClose={handleClose}
|
||||||
|
onBlur={handleClose}
|
||||||
|
showManageInputField={workflowVariableBlock?.showManageInputField}
|
||||||
|
onManageInputField={workflowVariableBlock?.onManageInputField}
|
||||||
|
autoFocus={false}
|
||||||
|
isInCodeGeneratorInstructionEditor={currentBlock?.generatorType === GeneratorType.code}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{activeTab === 'files' && (
|
||||||
|
<FilePickerPanel
|
||||||
|
onSelectNode={(node) => {
|
||||||
|
handleSelectFileReference(node.id)
|
||||||
|
handleClose()
|
||||||
|
}}
|
||||||
|
className="w-full border-0 bg-transparent p-0 shadow-none"
|
||||||
|
contentClassName="px-0"
|
||||||
|
showHeader={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>,
|
||||||
|
anchorElementRef.current,
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{
|
{
|
||||||
@ -261,79 +359,79 @@ const ComponentPicker = ({
|
|||||||
>
|
>
|
||||||
{isAgentTrigger
|
{isAgentTrigger
|
||||||
? (
|
? (
|
||||||
<AgentNodeList
|
<AgentNodeList
|
||||||
nodes={agentNodes.map(node => ({
|
nodes={agentNodes.map(node => ({
|
||||||
...node,
|
...node,
|
||||||
type: BlockEnum.Agent || BlockEnum.LLM,
|
type: BlockEnum.Agent || BlockEnum.LLM,
|
||||||
}))}
|
}))}
|
||||||
onSelect={handleSelectAgent}
|
onSelect={handleSelectAgent}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
onBlur={handleClose}
|
onBlur={handleClose}
|
||||||
maxHeightClass="max-h-[34vh]"
|
maxHeightClass="max-h-[34vh]"
|
||||||
autoFocus={false}
|
autoFocus={false}
|
||||||
hideSearch={useExternalSearch}
|
hideSearch={useExternalSearch}
|
||||||
externalSearchText={useExternalSearch ? (queryString ?? '') : undefined}
|
externalSearchText={useExternalSearch ? (queryString ?? '') : undefined}
|
||||||
enableKeyboardNavigation={useExternalSearch}
|
enableKeyboardNavigation={useExternalSearch}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
: (
|
: (
|
||||||
<>
|
<>
|
||||||
|
{
|
||||||
|
workflowVariableBlock?.show && (
|
||||||
|
<div className="p-1">
|
||||||
|
<VarReferenceVars
|
||||||
|
searchBoxClassName="mt-1"
|
||||||
|
vars={workflowVariableOptions}
|
||||||
|
onChange={(variables: string[]) => {
|
||||||
|
handleSelectWorkflowVariable(variables)
|
||||||
|
}}
|
||||||
|
maxHeightClass="max-h-[34vh]"
|
||||||
|
isSupportFileVar={isSupportFileVar}
|
||||||
|
onClose={handleClose}
|
||||||
|
onBlur={handleClose}
|
||||||
|
showManageInputField={workflowVariableBlock.showManageInputField}
|
||||||
|
onManageInputField={workflowVariableBlock.onManageInputField}
|
||||||
|
showAssembleVariables={showAssembleVariables}
|
||||||
|
onAssembleVariables={showAssembleVariables ? handleSelectAssembleVariables : undefined}
|
||||||
|
autoFocus={false}
|
||||||
|
isInCodeGeneratorInstructionEditor={currentBlock?.generatorType === GeneratorType.code}
|
||||||
|
hideSearch={useExternalSearch}
|
||||||
|
externalSearchText={useExternalSearch ? (queryString ?? '') : undefined}
|
||||||
|
enableKeyboardNavigation={useExternalSearch}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
workflowVariableBlock?.show && !!options.length && (
|
||||||
|
<div className="my-1 h-px w-full -translate-x-1 bg-divider-subtle"></div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
<div>
|
||||||
{
|
{
|
||||||
workflowVariableBlock?.show && (
|
options.map((option, index) => (
|
||||||
<div className="p-1">
|
<Fragment key={option.key}>
|
||||||
<VarReferenceVars
|
{
|
||||||
searchBoxClassName="mt-1"
|
index !== 0 && options.at(index - 1)?.group !== option.group && (
|
||||||
vars={workflowVariableOptions}
|
<div className="my-1 h-px w-full -translate-x-1 bg-divider-subtle"></div>
|
||||||
onChange={(variables: string[]) => {
|
)
|
||||||
handleSelectWorkflowVariable(variables)
|
}
|
||||||
}}
|
{option.renderMenuOption({
|
||||||
maxHeightClass="max-h-[34vh]"
|
queryString,
|
||||||
isSupportFileVar={isSupportFileVar}
|
isSelected: selectedIndex === index,
|
||||||
onClose={handleClose}
|
onSelect: () => {
|
||||||
onBlur={handleClose}
|
selectOptionAndCleanUp(option)
|
||||||
showManageInputField={workflowVariableBlock.showManageInputField}
|
},
|
||||||
onManageInputField={workflowVariableBlock.onManageInputField}
|
onSetHighlight: () => {
|
||||||
showAssembleVariables={showAssembleVariables}
|
setHighlightedIndex(index)
|
||||||
onAssembleVariables={showAssembleVariables ? handleSelectAssembleVariables : undefined}
|
},
|
||||||
autoFocus={false}
|
})}
|
||||||
isInCodeGeneratorInstructionEditor={currentBlock?.generatorType === GeneratorType.code}
|
</Fragment>
|
||||||
hideSearch={useExternalSearch}
|
))
|
||||||
externalSearchText={useExternalSearch ? (queryString ?? '') : undefined}
|
|
||||||
enableKeyboardNavigation={useExternalSearch}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
{
|
</div>
|
||||||
workflowVariableBlock?.show && !!options.length && (
|
</>
|
||||||
<div className="my-1 h-px w-full -translate-x-1 bg-divider-subtle"></div>
|
)}
|
||||||
)
|
|
||||||
}
|
|
||||||
<div>
|
|
||||||
{
|
|
||||||
options.map((option, index) => (
|
|
||||||
<Fragment key={option.key}>
|
|
||||||
{
|
|
||||||
index !== 0 && options.at(index - 1)?.group !== option.group && (
|
|
||||||
<div className="my-1 h-px w-full -translate-x-1 bg-divider-subtle"></div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
{option.renderMenuOption({
|
|
||||||
queryString,
|
|
||||||
isSelected: selectedIndex === index,
|
|
||||||
onSelect: () => {
|
|
||||||
selectOptionAndCleanUp(option)
|
|
||||||
},
|
|
||||||
onSetHighlight: () => {
|
|
||||||
setHighlightedIndex(index)
|
|
||||||
},
|
|
||||||
})}
|
|
||||||
</Fragment>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>,
|
</div>,
|
||||||
anchorElementRef.current,
|
anchorElementRef.current,
|
||||||
@ -341,13 +439,14 @@ const ComponentPicker = ({
|
|||||||
}
|
}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}, [isAgentTrigger, agentNodes, allFlattenOptions.length, workflowVariableBlock?.show, floatingStyles, isPositioned, refs, handleSelectAgent, handleClose, workflowVariableOptions, isSupportFileVar, currentBlock?.generatorType, handleSelectWorkflowVariable, queryString, workflowVariableBlock?.showManageInputField, workflowVariableBlock?.onManageInputField, showAssembleVariables, handleSelectAssembleVariables, useExternalSearch])
|
}, [isAgentTrigger, isSupportSandbox, triggerString, allFlattenOptions.length, workflowVariableBlock?.show, workflowVariableBlock.showManageInputField, workflowVariableBlock.onManageInputField, floatingStyles, isPositioned, refs, agentNodes, handleSelectAgent, handleClose, useExternalSearch, queryString, workflowVariableOptions, isSupportFileVar, showAssembleVariables, handleSelectAssembleVariables, currentBlock?.generatorType, t, activeTab, handleSelectWorkflowVariable, handleSelectFileReference])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LexicalTypeaheadMenuPlugin
|
<LexicalTypeaheadMenuPlugin
|
||||||
options={allFlattenOptions}
|
options={(isSupportSandbox && triggerString === '/') ? [] : allFlattenOptions}
|
||||||
onQueryChange={setQueryString}
|
onQueryChange={setQueryString}
|
||||||
onSelectOption={onSelectOption}
|
onSelectOption={onSelectOption}
|
||||||
|
onOpen={handleOpen}
|
||||||
// The `translate` class is used to workaround the issue that the `typeahead-menu` menu is not positioned as expected.
|
// The `translate` class is used to workaround the issue that the `typeahead-menu` menu is not positioned as expected.
|
||||||
// See also https://github.com/facebook/lexical/blob/772520509308e8ba7e4a82b6cd1996a78b3298d0/packages/lexical-react/src/shared/LexicalMenu.ts#L498
|
// See also https://github.com/facebook/lexical/blob/772520509308e8ba7e4a82b6cd1996a78b3298d0/packages/lexical-react/src/shared/LexicalMenu.ts#L498
|
||||||
//
|
//
|
||||||
|
|||||||
@ -62,6 +62,7 @@ type Props = {
|
|||||||
nodesOutputVars?: NodeOutPutVar[]
|
nodesOutputVars?: NodeOutPutVar[]
|
||||||
availableNodes?: Node[]
|
availableNodes?: Node[]
|
||||||
isSupportFileVar?: boolean
|
isSupportFileVar?: boolean
|
||||||
|
isSupportSandbox?: boolean
|
||||||
isSupportPromptGenerator?: boolean
|
isSupportPromptGenerator?: boolean
|
||||||
onGenerated?: (prompt: string) => void
|
onGenerated?: (prompt: string) => void
|
||||||
modelConfig?: ModelConfig
|
modelConfig?: ModelConfig
|
||||||
@ -102,6 +103,7 @@ const Editor: FC<Props> = ({
|
|||||||
nodesOutputVars,
|
nodesOutputVars,
|
||||||
availableNodes = [],
|
availableNodes = [],
|
||||||
isSupportFileVar,
|
isSupportFileVar,
|
||||||
|
isSupportSandbox,
|
||||||
isSupportPromptGenerator,
|
isSupportPromptGenerator,
|
||||||
isSupportJinja,
|
isSupportJinja,
|
||||||
editionType,
|
editionType,
|
||||||
@ -295,6 +297,7 @@ const Editor: FC<Props> = ({
|
|||||||
onFocus={setFocus}
|
onFocus={setFocus}
|
||||||
editable={!readOnly}
|
editable={!readOnly}
|
||||||
isSupportFileVar={isSupportFileVar}
|
isSupportFileVar={isSupportFileVar}
|
||||||
|
isSupportSandbox={isSupportSandbox}
|
||||||
/>
|
/>
|
||||||
{/* to patch Editor not support dynamic change editable status */}
|
{/* to patch Editor not support dynamic change editable status */}
|
||||||
{readOnly && <div className="absolute inset-0 z-10"></div>}
|
{readOnly && <div className="absolute inset-0 z-10"></div>}
|
||||||
|
|||||||
@ -40,6 +40,7 @@ type Props = {
|
|||||||
varList: Variable[]
|
varList: Variable[]
|
||||||
handleAddVariable: (payload: any) => void
|
handleAddVariable: (payload: any) => void
|
||||||
modelConfig?: ModelConfig
|
modelConfig?: ModelConfig
|
||||||
|
isSupportSandbox?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const roleOptions = [
|
const roleOptions = [
|
||||||
@ -82,6 +83,7 @@ const ConfigPromptItem: FC<Props> = ({
|
|||||||
varList,
|
varList,
|
||||||
handleAddVariable,
|
handleAddVariable,
|
||||||
modelConfig,
|
modelConfig,
|
||||||
|
isSupportSandbox,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const workflowStore = useWorkflowStore()
|
const workflowStore = useWorkflowStore()
|
||||||
@ -149,6 +151,7 @@ const ConfigPromptItem: FC<Props> = ({
|
|||||||
varList={varList}
|
varList={varList}
|
||||||
handleAddVariable={handleAddVariable}
|
handleAddVariable={handleAddVariable}
|
||||||
isSupportFileVar
|
isSupportFileVar
|
||||||
|
isSupportSandbox={isSupportSandbox}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { useCallback, useMemo, useRef, useState } from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { ReactSortable } from 'react-sortablejs'
|
import { ReactSortable } from 'react-sortablejs'
|
||||||
import { v4 as uuid4 } from 'uuid'
|
import { v4 as uuid4 } from 'uuid'
|
||||||
|
import { useFeatures } from '@/app/components/base/features/hooks'
|
||||||
import { DragHandle } from '@/app/components/base/icons/src/vender/line/others'
|
import { DragHandle } from '@/app/components/base/icons/src/vender/line/others'
|
||||||
import {
|
import {
|
||||||
PortalToFollowElem,
|
PortalToFollowElem,
|
||||||
@ -59,6 +60,8 @@ const ConfigPrompt: FC<Props> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const workflowStore = useWorkflowStore()
|
const workflowStore = useWorkflowStore()
|
||||||
|
const features = useFeatures(s => s.features)
|
||||||
|
const isSupportSandbox = !!features.sandbox?.enabled
|
||||||
const {
|
const {
|
||||||
setControlPromptEditorRerenderKey,
|
setControlPromptEditorRerenderKey,
|
||||||
} = workflowStore.getState()
|
} = workflowStore.getState()
|
||||||
@ -337,6 +340,7 @@ const ConfigPrompt: FC<Props> = ({
|
|||||||
varList={varList}
|
varList={varList}
|
||||||
handleAddVariable={handleAddVariable}
|
handleAddVariable={handleAddVariable}
|
||||||
modelConfig={modelConfig}
|
modelConfig={modelConfig}
|
||||||
|
isSupportSandbox={isSupportSandbox}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@ -410,6 +414,7 @@ const ConfigPrompt: FC<Props> = ({
|
|||||||
handleAddVariable={handleAddVariable}
|
handleAddVariable={handleAddVariable}
|
||||||
onGenerated={handleGenerated}
|
onGenerated={handleGenerated}
|
||||||
modelConfig={modelConfig}
|
modelConfig={modelConfig}
|
||||||
|
isSupportSandbox={isSupportSandbox}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -109,11 +109,17 @@ FilePickerTreeNode.displayName = 'FilePickerTreeNode'
|
|||||||
type FilePickerPanelProps = {
|
type FilePickerPanelProps = {
|
||||||
onSelectNode: (node: TreeNodeData) => void
|
onSelectNode: (node: TreeNodeData) => void
|
||||||
focusNodeId?: string
|
focusNodeId?: string
|
||||||
|
className?: string
|
||||||
|
contentClassName?: string
|
||||||
|
showHeader?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const FilePickerPanel: FC<FilePickerPanelProps> = ({
|
const FilePickerPanel: FC<FilePickerPanelProps> = ({
|
||||||
onSelectNode,
|
onSelectNode,
|
||||||
focusNodeId,
|
focusNodeId,
|
||||||
|
className,
|
||||||
|
contentClassName,
|
||||||
|
showHeader = true,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation('workflow')
|
const { t } = useTranslation('workflow')
|
||||||
const { data: treeData, isLoading, error } = useSkillAssetTreeData()
|
const { data: treeData, isLoading, error } = useSkillAssetTreeData()
|
||||||
@ -141,7 +147,10 @@ const FilePickerPanel: FC<FilePickerPanelProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="w-[280px] overflow-hidden rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-sm"
|
className={cn(
|
||||||
|
'w-[280px] overflow-hidden rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-sm',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
onMouseDown={(e) => {
|
onMouseDown={(e) => {
|
||||||
const target = e.target as HTMLElement
|
const target = e.target as HTMLElement
|
||||||
if (target.closest('input, textarea, select'))
|
if (target.closest('input, textarea, select'))
|
||||||
@ -149,13 +158,22 @@ const FilePickerPanel: FC<FilePickerPanelProps> = ({
|
|||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-1 px-4 pb-1 pt-1.5">
|
{showHeader && (
|
||||||
<span className="flex-1 text-[12px] font-medium uppercase leading-4 text-text-tertiary">
|
<div className="flex items-center gap-1 px-4 pb-1 pt-1.5">
|
||||||
{t('skillEditor.referenceFiles')}
|
<span className="flex-1 text-[12px] font-medium uppercase leading-4 text-text-tertiary">
|
||||||
</span>
|
{t('skillEditor.referenceFiles')}
|
||||||
<RiQuestionLine className="size-4 text-text-tertiary" aria-hidden="true" />
|
</span>
|
||||||
</div>
|
<RiQuestionLine className="size-4 text-text-tertiary" aria-hidden="true" />
|
||||||
<div ref={containerRef} className="max-h-[320px] min-h-[120px] px-2 pb-2">
|
</div>
|
||||||
|
)}
|
||||||
|
<div
|
||||||
|
ref={containerRef}
|
||||||
|
className={cn(
|
||||||
|
'max-h-[320px] min-h-[120px] px-2 pb-2',
|
||||||
|
!showHeader && 'pt-2',
|
||||||
|
contentClassName,
|
||||||
|
)}
|
||||||
|
>
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="flex h-full items-center justify-center py-6">
|
<div className="flex h-full items-center justify-center py-6">
|
||||||
<Loading type="area" />
|
<Loading type="area" />
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user