mirror of
https://github.com/langgenius/dify.git
synced 2024-11-16 11:42:29 +08:00
feat: prompt editor support auto height by content height and fix some bugs (#3712)
This commit is contained in:
parent
2867d29021
commit
f92130338b
|
@ -218,13 +218,14 @@ const ModelParameterModal: FC<ModelParameterModalProps> = ({
|
||||||
!isInWorkflow && 'px-10 pt-6 pb-8',
|
!isInWorkflow && 'px-10 pt-6 pb-8',
|
||||||
isInWorkflow && 'p-4')}>
|
isInWorkflow && 'p-4')}>
|
||||||
<div className='flex items-center justify-between h-8'>
|
<div className='flex items-center justify-between h-8'>
|
||||||
<div className={cn('font-semibold text-gray-900', isInWorkflow && 'text-[13px]')}>
|
<div className={cn('font-semibold text-gray-900 shrink-0', isInWorkflow && 'text-[13px]')}>
|
||||||
{t('common.modelProvider.model').toLocaleUpperCase()}
|
{t('common.modelProvider.model').toLocaleUpperCase()}
|
||||||
</div>
|
</div>
|
||||||
<ModelSelector
|
<ModelSelector
|
||||||
defaultModel={(provider || modelId) ? { provider, model: modelId } : undefined}
|
defaultModel={(provider || modelId) ? { provider, model: modelId } : undefined}
|
||||||
modelList={activeTextGenerationModelList}
|
modelList={activeTextGenerationModelList}
|
||||||
onSelect={handleChangeModel}
|
onSelect={handleChangeModel}
|
||||||
|
triggerClassName='max-w-[295px]'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
|
|
|
@ -47,7 +47,7 @@ const Trigger: FC<TriggerProps> = ({
|
||||||
'relative flex items-center px-2 h-8 rounded-lg cursor-pointer',
|
'relative flex items-center px-2 h-8 rounded-lg cursor-pointer',
|
||||||
!isInWorkflow && 'border hover:border-[1.5px]',
|
!isInWorkflow && 'border hover:border-[1.5px]',
|
||||||
!isInWorkflow && (disabled ? 'border-[#F79009] bg-[#FFFAEB]' : 'border-[#444CE7] bg-primary-50'),
|
!isInWorkflow && (disabled ? 'border-[#F79009] bg-[#FFFAEB]' : 'border-[#444CE7] bg-primary-50'),
|
||||||
isInWorkflow && 'bg-gray-100 border border-gray-100 hover:border-gray-200',
|
isInWorkflow && 'pr-[30px] bg-gray-100 border border-gray-100 hover:border-gray-200',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
|
@ -103,7 +103,7 @@ const Trigger: FC<TriggerProps> = ({
|
||||||
</TooltipPlus>
|
</TooltipPlus>
|
||||||
)
|
)
|
||||||
: (
|
: (
|
||||||
<SlidersH className={cn(!isInWorkflow ? 'text-indigo-600' : 'text-gray-500', 'w-4 h-4')} />
|
<SlidersH className={cn(!isInWorkflow ? 'text-indigo-600' : 'text-gray-500', 'shrink-0 w-4 h-4')} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
{isInWorkflow && (<ChevronDown className='absolute top-[9px] right-2 w-3.5 h-3.5 text-gray-500' />)}
|
{isInWorkflow && (<ChevronDown className='absolute top-[9px] right-2 w-3.5 h-3.5 text-gray-500' />)}
|
||||||
|
|
|
@ -16,6 +16,7 @@ type Props = {
|
||||||
minHeight?: number
|
minHeight?: number
|
||||||
value: string
|
value: string
|
||||||
isFocus: boolean
|
isFocus: boolean
|
||||||
|
isInNode?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const Base: FC<Props> = ({
|
const Base: FC<Props> = ({
|
||||||
|
@ -26,14 +27,16 @@ const Base: FC<Props> = ({
|
||||||
minHeight = 120,
|
minHeight = 120,
|
||||||
value,
|
value,
|
||||||
isFocus,
|
isFocus,
|
||||||
|
isInNode,
|
||||||
}) => {
|
}) => {
|
||||||
const ref = useRef<HTMLDivElement>(null)
|
const ref = useRef<HTMLDivElement>(null)
|
||||||
const {
|
const {
|
||||||
wrapClassName,
|
wrapClassName,
|
||||||
|
wrapStyle,
|
||||||
isExpand,
|
isExpand,
|
||||||
setIsExpand,
|
setIsExpand,
|
||||||
editorExpandHeight,
|
editorExpandHeight,
|
||||||
} = useToggleExpend({ ref, hasFooter: false })
|
} = useToggleExpend({ ref, hasFooter: false, isInNode })
|
||||||
|
|
||||||
const editorContentMinHeight = minHeight - 28
|
const editorContentMinHeight = minHeight - 28
|
||||||
const [editorContentHeight, setEditorContentHeight] = useState(editorContentMinHeight)
|
const [editorContentHeight, setEditorContentHeight] = useState(editorContentMinHeight)
|
||||||
|
@ -45,7 +48,7 @@ const Base: FC<Props> = ({
|
||||||
}, [value])
|
}, [value])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn(wrapClassName)}>
|
<div className={cn(wrapClassName)} style={wrapStyle}>
|
||||||
<div ref={ref} className={cn(className, isExpand && 'h-full', 'rounded-lg border', isFocus ? 'bg-white border-gray-200' : 'bg-gray-100 border-gray-100 overflow-hidden')}>
|
<div ref={ref} className={cn(className, isExpand && 'h-full', 'rounded-lg border', isFocus ? 'bg-white border-gray-200' : 'bg-gray-100 border-gray-100 overflow-hidden')}>
|
||||||
<div className='flex justify-between items-center h-7 pt-1 pl-3 pr-2'>
|
<div className='flex justify-between items-center h-7 pt-1 pl-3 pr-2'>
|
||||||
<div className='text-xs font-semibold text-gray-700'>{title}</div>
|
<div className='text-xs font-semibold text-gray-700'>{title}</div>
|
||||||
|
|
|
@ -18,6 +18,7 @@ type Props = {
|
||||||
readOnly?: boolean
|
readOnly?: boolean
|
||||||
isJSONStringifyBeauty?: boolean
|
isJSONStringifyBeauty?: boolean
|
||||||
height?: number
|
height?: number
|
||||||
|
isInNode?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const languageMap = {
|
const languageMap = {
|
||||||
|
@ -35,6 +36,7 @@ const CodeEditor: FC<Props> = ({
|
||||||
readOnly,
|
readOnly,
|
||||||
isJSONStringifyBeauty,
|
isJSONStringifyBeauty,
|
||||||
height,
|
height,
|
||||||
|
isInNode,
|
||||||
}) => {
|
}) => {
|
||||||
const [isFocus, setIsFocus] = React.useState(false)
|
const [isFocus, setIsFocus] = React.useState(false)
|
||||||
|
|
||||||
|
@ -90,6 +92,7 @@ const CodeEditor: FC<Props> = ({
|
||||||
headerRight={headerRight}
|
headerRight={headerRight}
|
||||||
isFocus={isFocus && !readOnly}
|
isFocus={isFocus && !readOnly}
|
||||||
minHeight={height || 200}
|
minHeight={height || 200}
|
||||||
|
isInNode={isInNode}
|
||||||
>
|
>
|
||||||
<>
|
<>
|
||||||
{/* https://www.npmjs.com/package/@monaco-editor/react */}
|
{/* https://www.npmjs.com/package/@monaco-editor/react */}
|
||||||
|
|
|
@ -13,6 +13,7 @@ type Props = {
|
||||||
onBlur?: () => void
|
onBlur?: () => void
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
readonly?: boolean
|
readonly?: boolean
|
||||||
|
isInNode?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const TextEditor: FC<Props> = ({
|
const TextEditor: FC<Props> = ({
|
||||||
|
@ -24,6 +25,7 @@ const TextEditor: FC<Props> = ({
|
||||||
onBlur,
|
onBlur,
|
||||||
placeholder,
|
placeholder,
|
||||||
readonly,
|
readonly,
|
||||||
|
isInNode,
|
||||||
}) => {
|
}) => {
|
||||||
const [isFocus, {
|
const [isFocus, {
|
||||||
setTrue: setIsFocus,
|
setTrue: setIsFocus,
|
||||||
|
@ -43,6 +45,7 @@ const TextEditor: FC<Props> = ({
|
||||||
headerRight={headerRight}
|
headerRight={headerRight}
|
||||||
isFocus={isFocus}
|
isFocus={isFocus}
|
||||||
minHeight={minHeight}
|
minHeight={minHeight}
|
||||||
|
isInNode={isInNode}
|
||||||
>
|
>
|
||||||
<textarea
|
<textarea
|
||||||
value={value}
|
value={value}
|
||||||
|
|
|
@ -12,14 +12,14 @@ import {
|
||||||
} from '../../../../types'
|
} from '../../../../types'
|
||||||
import ToggleExpandBtn from '@/app/components/workflow/nodes/_base/components/toggle-expand-btn'
|
import ToggleExpandBtn from '@/app/components/workflow/nodes/_base/components/toggle-expand-btn'
|
||||||
import useToggleExpend from '@/app/components/workflow/nodes/_base/hooks/use-toggle-expend'
|
import useToggleExpend from '@/app/components/workflow/nodes/_base/hooks/use-toggle-expend'
|
||||||
import PromptEditorHeightResizeWrap from '@/app/components/app/configuration/config-prompt/prompt-editor-height-resize-wrap'
|
|
||||||
import PromptEditor from '@/app/components/base/prompt-editor'
|
import PromptEditor from '@/app/components/base/prompt-editor'
|
||||||
import { Clipboard, ClipboardCheck } from '@/app/components/base/icons/src/vender/line/files'
|
import { Clipboard, ClipboardCheck } from '@/app/components/base/icons/src/vender/line/files'
|
||||||
import s from '@/app/components/app/configuration/config-prompt/style.module.css'
|
import s from '@/app/components/app/configuration/config-prompt/style.module.css'
|
||||||
import { Trash03 } from '@/app/components/base/icons/src/vender/line/general'
|
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 { useEventEmitterContextContext } from '@/context/event-emitter'
|
||||||
import { PROMPT_EDITOR_INSERT_QUICKLY } from '@/app/components/base/prompt-editor/plugins/update-block'
|
import { PROMPT_EDITOR_INSERT_QUICKLY } from '@/app/components/base/prompt-editor/plugins/update-block'
|
||||||
|
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
|
||||||
|
import TooltipPlus from '@/app/components/base/tooltip-plus'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
instanceId?: string
|
instanceId?: string
|
||||||
|
@ -66,12 +66,11 @@ const Editor: FC<Props> = ({
|
||||||
const ref = useRef<HTMLDivElement>(null)
|
const ref = useRef<HTMLDivElement>(null)
|
||||||
const {
|
const {
|
||||||
wrapClassName,
|
wrapClassName,
|
||||||
|
wrapStyle,
|
||||||
isExpand,
|
isExpand,
|
||||||
setIsExpand,
|
setIsExpand,
|
||||||
editorExpandHeight,
|
editorExpandHeight,
|
||||||
} = useToggleExpend({ ref })
|
} = useToggleExpend({ ref, isInNode: true })
|
||||||
const minHeight = 98
|
|
||||||
const [editorHeight, setEditorHeight] = React.useState(minHeight)
|
|
||||||
const [isCopied, setIsCopied] = React.useState(false)
|
const [isCopied, setIsCopied] = React.useState(false)
|
||||||
const handleCopy = useCallback(() => {
|
const handleCopy = useCallback(() => {
|
||||||
copy(value)
|
copy(value)
|
||||||
|
@ -103,7 +102,7 @@ const Editor: FC<Props> = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn(wrapClassName)}>
|
<div className={cn(wrapClassName)} style={wrapStyle}>
|
||||||
<div ref={ref} className={cn(isFocus ? s.gradientBorder : 'bg-gray-100', isExpand && 'h-full', '!rounded-[9px] p-0.5')}>
|
<div ref={ref} className={cn(isFocus ? s.gradientBorder : 'bg-gray-100', isExpand && 'h-full', '!rounded-[9px] p-0.5')}>
|
||||||
<div className={cn(isFocus ? 'bg-gray-50' : 'bg-gray-100', isExpand && 'h-full flex flex-col', 'rounded-lg')}>
|
<div className={cn(isFocus ? 'bg-gray-50' : 'bg-gray-100', isExpand && 'h-full flex flex-col', 'rounded-lg')}>
|
||||||
<div className='pt-1 pl-3 pr-2 flex justify-between h-6 items-center'>
|
<div className='pt-1 pl-3 pr-2 flex justify-between h-6 items-center'>
|
||||||
|
@ -113,6 +112,13 @@ const Editor: FC<Props> = ({
|
||||||
<div className='w-px h-3 ml-2 mr-2 bg-gray-200'></div>
|
<div className='w-px h-3 ml-2 mr-2 bg-gray-200'></div>
|
||||||
{/* Operations */}
|
{/* Operations */}
|
||||||
<div className='flex items-center space-x-2'>
|
<div className='flex items-center space-x-2'>
|
||||||
|
{!readOnly && (
|
||||||
|
<TooltipPlus
|
||||||
|
popupContent={`${t('workflow.common.insertVarTip')}`}
|
||||||
|
>
|
||||||
|
<Variable02 className='w-3.5 h-3.5 text-gray-500 cursor-pointer' onClick={handleInsertVariable} />
|
||||||
|
</TooltipPlus>
|
||||||
|
)}
|
||||||
{showRemove && (
|
{showRemove && (
|
||||||
<Trash03 className='w-3.5 h-3.5 text-gray-500 cursor-pointer' onClick={onRemove} />
|
<Trash03 className='w-3.5 h-3.5 text-gray-500 cursor-pointer' onClick={onRemove} />
|
||||||
)}
|
)}
|
||||||
|
@ -129,32 +135,12 @@ const Editor: FC<Props> = ({
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<PromptEditorHeightResizeWrap
|
|
||||||
className={cn(isExpand && 'h-0 grow', 'px-3 min-h-[102px] overflow-y-auto text-sm text-gray-700')}
|
{/* Min: 80 Max: 560. Header: 24 */}
|
||||||
height={isExpand ? editorExpandHeight : editorHeight}
|
<div className={cn('pb-2', isExpand && 'flex flex-col grow')}>
|
||||||
minHeight={minHeight}
|
<div className={cn(isExpand ? 'grow' : 'max-h-[536px]', 'px-3 min-h-[56px] overflow-y-auto')}>
|
||||||
onHeightChange={setEditorHeight}
|
|
||||||
footer={(
|
|
||||||
<div className='pl-3 pb-2 flex'>
|
|
||||||
{(isFocus || isShowInsertToolTip)
|
|
||||||
? (
|
|
||||||
<TooltipPlus
|
|
||||||
popupContent={`${t('workflow.common.insertVarTip')}`}
|
|
||||||
>
|
|
||||||
<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>
|
|
||||||
)}
|
|
||||||
hideResize={isExpand}
|
|
||||||
>
|
|
||||||
<>
|
|
||||||
<PromptEditor
|
<PromptEditor
|
||||||
instanceId={instanceId}
|
instanceId={instanceId}
|
||||||
className={cn('min-h-[84px]')}
|
|
||||||
compact
|
compact
|
||||||
style={isExpand ? { height: editorExpandHeight - 5 } : {}}
|
style={isExpand ? { height: editorExpandHeight - 5 } : {}}
|
||||||
value={value}
|
value={value}
|
||||||
|
@ -199,8 +185,9 @@ const Editor: FC<Props> = ({
|
||||||
/>
|
/>
|
||||||
{/* 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>}
|
||||||
</>
|
</div>
|
||||||
</PromptEditorHeightResizeWrap>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,20 +3,31 @@ import { useEffect, useState } from 'react'
|
||||||
type Params = {
|
type Params = {
|
||||||
ref: React.RefObject<HTMLDivElement>
|
ref: React.RefObject<HTMLDivElement>
|
||||||
hasFooter?: boolean
|
hasFooter?: boolean
|
||||||
|
isInNode?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const useToggleExpend = ({ ref, hasFooter = true }: Params) => {
|
const useToggleExpend = ({ ref, hasFooter = true, isInNode }: Params) => {
|
||||||
const [isExpand, setIsExpand] = useState(false)
|
const [isExpand, setIsExpand] = useState(false)
|
||||||
const [wrapHeight, setWrapHeight] = useState(ref.current?.clientHeight)
|
const [wrapHeight, setWrapHeight] = useState(ref.current?.clientHeight)
|
||||||
const editorExpandHeight = isExpand ? wrapHeight! - (hasFooter ? 56 : 29) : 0
|
const editorExpandHeight = isExpand ? wrapHeight! - (hasFooter ? 56 : 29) : 0
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setWrapHeight(ref.current?.clientHeight)
|
setWrapHeight(ref.current?.clientHeight)
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [isExpand])
|
}, [isExpand])
|
||||||
|
|
||||||
const wrapClassName = isExpand && 'absolute z-10 left-4 right-6 top-[52px] bottom-0 pb-4 bg-white'
|
const wrapClassName = (() => {
|
||||||
|
if (!isExpand)
|
||||||
|
return ''
|
||||||
|
|
||||||
|
if (isInNode)
|
||||||
|
return 'fixed z-10 right-[9px] top-[166px] bottom-[8px] w-[419px] p-4 bg-white rounded-xl'
|
||||||
|
|
||||||
|
return 'absolute z-10 left-4 right-6 top-[52px] bottom-0 pb-4 bg-white'
|
||||||
|
})()
|
||||||
|
const wrapStyle = isExpand ? { boxShadow: '0px 0px 12px -4px rgba(16, 24, 40, 0.05), 0px -3px 6px -2px rgba(16, 24, 40, 0.03)' } : {}
|
||||||
return {
|
return {
|
||||||
wrapClassName,
|
wrapClassName,
|
||||||
|
wrapStyle,
|
||||||
editorExpandHeight,
|
editorExpandHeight,
|
||||||
isExpand,
|
isExpand,
|
||||||
setIsExpand,
|
setIsExpand,
|
||||||
|
|
|
@ -80,6 +80,7 @@ const Panel: FC<NodePanelProps<CodeNodeType>> = ({
|
||||||
</Field>
|
</Field>
|
||||||
<Split />
|
<Split />
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
|
isInNode
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
title={
|
title={
|
||||||
<TypeSelector
|
<TypeSelector
|
||||||
|
|
|
@ -37,6 +37,7 @@ const BulkEdit: FC<Props> = ({
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<TextEditor
|
<TextEditor
|
||||||
|
isInNode
|
||||||
title={<div className='uppercase'>{t(`${i18nPrefix}.bulkEdit`)}</div>}
|
title={<div className='uppercase'>{t(`${i18nPrefix}.bulkEdit`)}</div>}
|
||||||
value={tempValue}
|
value={tempValue}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
|
|
@ -29,6 +29,7 @@ const AdvancedSetting: FC<Props> = ({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TextEditor
|
<TextEditor
|
||||||
|
isInNode
|
||||||
title={t(`${i18nPrefix}.instruction`)!}
|
title={t(`${i18nPrefix}.instruction`)!}
|
||||||
value={instruction}
|
value={instruction}
|
||||||
onChange={onInstructionChange}
|
onChange={onInstructionChange}
|
||||||
|
|
|
@ -31,6 +31,7 @@ const ClassItem: FC<Props> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TextEditor
|
<TextEditor
|
||||||
|
isInNode
|
||||||
title={<div>
|
title={<div>
|
||||||
<div className='w-[200px]'>
|
<div className='w-[200px]'>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -62,6 +62,7 @@ const Panel: FC<NodePanelProps<TemplateTransformNodeType>> = ({
|
||||||
</Field>
|
</Field>
|
||||||
<Split />
|
<Split />
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
|
isInNode
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
language={CodeLanguage.python3}
|
language={CodeLanguage.python3}
|
||||||
title={
|
title={
|
||||||
|
|
Loading…
Reference in New Issue
Block a user