feat: prompt editor support auto height by content height and fix some bugs (#3712)

This commit is contained in:
Joel 2024-04-23 17:46:59 +08:00 committed by GitHub
parent 2867d29021
commit f92130338b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 52 additions and 39 deletions

View File

@ -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>
{ {

View File

@ -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' />)}

View File

@ -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>

View File

@ -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 */}

View File

@ -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}

View File

@ -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>

View File

@ -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,

View File

@ -80,6 +80,7 @@ const Panel: FC<NodePanelProps<CodeNodeType>> = ({
</Field> </Field>
<Split /> <Split />
<CodeEditor <CodeEditor
isInNode
readOnly={readOnly} readOnly={readOnly}
title={ title={
<TypeSelector <TypeSelector

View File

@ -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}

View File

@ -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}

View File

@ -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

View File

@ -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={