| | |
| | | 'use client' |
| | | import type { FC, ReactNode } from 'react' |
| | | import type { FC } from 'react' |
| | | import React, { useCallback, useRef } from 'react' |
| | | import { |
| | | RiDeleteBinLine, |
| | |
| | | Clipboard, |
| | | ClipboardCheck, |
| | | } from '@/app/components/base/icons/src/vender/line/files' |
| | | import s from '@/app/components/app/configuration/config-prompt/style.module.css' |
| | | import { useEventEmitterContextContext } from '@/context/event-emitter' |
| | | 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 Switch from '@/app/components/base/switch' |
| | | import { Jinja } from '@/app/components/base/icons/src/vender/workflow' |
| | | import { useStore } from '@/app/components/workflow/store' |
| | | import { useWorkflowVariableType } from '@/app/components/workflow/hooks' |
| | | |
| | | type Props = { |
| | | className?: string |
| | | headerClassName?: string |
| | | instanceId?: string |
| | | title: string | React.JSX.Element |
| | | title: string | JSX.Element |
| | | value: string |
| | | onChange: (value: string) => void |
| | | readOnly?: boolean |
| | |
| | | onEditionTypeChange?: (editionType: EditionType) => void |
| | | varList?: Variable[] |
| | | handleAddVariable?: (payload: any) => void |
| | | containerBackgroundClassName?: string |
| | | gradientBorder?: boolean |
| | | titleTooltip?: ReactNode |
| | | inputClassName?: string |
| | | editorContainerClassName?: string |
| | | placeholder?: string |
| | | placeholderClassName?: string |
| | | titleClassName?: string |
| | | required?: boolean |
| | | } |
| | | |
| | | const Editor: FC<Props> = ({ |
| | |
| | | handleAddVariable, |
| | | onGenerated, |
| | | modelConfig, |
| | | containerBackgroundClassName: containerClassName, |
| | | gradientBorder = true, |
| | | titleTooltip, |
| | | inputClassName, |
| | | placeholder, |
| | | placeholderClassName, |
| | | titleClassName, |
| | | editorContainerClassName, |
| | | required, |
| | | }) => { |
| | | const { t } = useTranslation() |
| | | const { eventEmitter } = useEventEmitterContextContext() |
| | |
| | | eventEmitter?.emit({ type: PROMPT_EDITOR_INSERT_QUICKLY, instanceId } as any) |
| | | } |
| | | |
| | | const getVarType = useWorkflowVariableType() |
| | | |
| | | return ( |
| | | <Wrap className={cn(className, wrapClassName)} style={wrapStyle} isInNode isExpand={isExpand}> |
| | | <div ref={ref} className={cn(isFocus ? (gradientBorder && 'bg-gradient-to-r from-components-input-border-active-prompt-1 to-components-input-border-active-prompt-2') : 'bg-transparent', isExpand && 'h-full', '!rounded-[9px] p-0.5', containerClassName)}> |
| | | <div className={cn(isFocus ? 'bg-background-default' : 'bg-components-input-bg-normal', isExpand && 'flex h-full flex-col', 'rounded-lg', containerClassName)}> |
| | | <div className={cn('flex items-center justify-between pl-3 pr-2 pt-1', headerClassName)}> |
| | | <div className='flex gap-2'> |
| | | <div className={cn('text-xs font-semibold uppercase leading-4 text-text-secondary', titleClassName)}>{title} {required && <span className='text-text-destructive'>*</span>}</div> |
| | | {titleTooltip && <Tooltip popupContent={titleTooltip} />} |
| | | </div> |
| | | <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(headerClassName, 'pt-1 pl-3 pr-2 flex justify-between items-center')}> |
| | | <div className='leading-4 text-xs font-semibold text-gray-700 uppercase'>{title}</div> |
| | | <div className='flex items-center'> |
| | | <div className='text-xs font-medium leading-[18px] text-text-tertiary'>{value?.length || 0}</div> |
| | | <div className='leading-[18px] text-xs font-medium text-gray-500'>{value?.length || 0}</div> |
| | | {isSupportPromptGenerator && ( |
| | | <PromptGeneratorBtn className='ml-[5px]' onGenerated={onGenerated} modelConfig={modelConfig} /> |
| | | )} |
| | | |
| | | <div className='ml-2 mr-2 h-3 w-px bg-divider-regular'></div> |
| | | <div className='w-px h-3 ml-2 mr-2 bg-gray-200'></div> |
| | | {/* Operations */} |
| | | <div className='flex items-center space-x-[2px]'> |
| | | {isSupportJinja && ( |
| | |
| | | popupContent={ |
| | | <div> |
| | | <div>{t('workflow.common.enableJinja')}</div> |
| | | <a className='text-text-accent' target='_blank' href='https://jinja.palletsprojects.com/en/2.10.x/'>{t('workflow.common.learnMore')}</a> |
| | | <a className='text-[#155EEF]' target='_blank' href='https://jinja.palletsprojects.com/en/2.10.x/'>{t('workflow.common.learnMore')}</a> |
| | | </div> |
| | | } |
| | | needsDelay |
| | | > |
| | | <div className={cn(editionType === EditionType.jinja2 && 'border-components-button-ghost-bg-hover bg-components-button-ghost-bg-hover', 'flex h-[22px] items-center space-x-0.5 rounded-[5px] border border-transparent px-1.5 hover:border-components-button-ghost-bg-hover')}> |
| | | <Jinja className='h-3 w-6 text-text-quaternary' /> |
| | | <div className={cn(editionType === EditionType.jinja2 && 'border-black/5 bg-white', 'flex h-[22px] items-center px-1.5 rounded-[5px] border border-transparent hover:border-black/5 space-x-0.5')}> |
| | | <Jinja className='w-6 h-3 text-gray-300' /> |
| | | <Switch |
| | | size='sm' |
| | | defaultValue={editionType === EditionType.jinja2} |
| | |
| | | popupContent={`${t('workflow.common.insertVarTip')}`} |
| | | > |
| | | <ActionButton onClick={handleInsertVariable}> |
| | | <Variable02 className='h-4 w-4' /> |
| | | <Variable02 className='w-4 h-4' /> |
| | | </ActionButton> |
| | | </Tooltip> |
| | | )} |
| | | {showRemove && ( |
| | | <ActionButton onClick={onRemove}> |
| | | <RiDeleteBinLine className='h-4 w-4' /> |
| | | <RiDeleteBinLine className='w-4 h-4' /> |
| | | </ActionButton> |
| | | )} |
| | | {!isCopied |
| | | ? ( |
| | | <ActionButton onClick={handleCopy}> |
| | | <Clipboard className='h-4 w-4' /> |
| | | <Clipboard className='w-4 h-4' /> |
| | | </ActionButton> |
| | | ) |
| | | : ( |
| | | <ActionButton> |
| | | <ClipboardCheck className='h-4 w-4' /> |
| | | <ClipboardCheck className='w-4 h-4' /> |
| | | </ActionButton> |
| | | ) |
| | | } |
| | |
| | | </div> |
| | | |
| | | {/* Min: 80 Max: 560. Header: 24 */} |
| | | <div className={cn('pb-2', isExpand && 'flex grow flex-col')}> |
| | | <div className={cn('pb-2', isExpand && 'flex flex-col grow')}> |
| | | {!(isSupportJinja && editionType === EditionType.jinja2) |
| | | ? ( |
| | | <div className={cn(isExpand ? 'grow' : 'max-h-[536px]', 'relative min-h-[56px] overflow-y-auto px-3', editorContainerClassName)}> |
| | | <div className={cn(isExpand ? 'grow' : 'max-h-[536px]', 'relative px-3 min-h-[56px] overflow-y-auto')}> |
| | | <PromptEditor |
| | | key={controlPromptEditorRerenderKey} |
| | | placeholder={placeholder} |
| | | placeholderClassName={placeholderClassName} |
| | | instanceId={instanceId} |
| | | compact |
| | | className={cn('min-h-[56px]', inputClassName)} |
| | | className='min-h-[56px]' |
| | | style={isExpand ? { height: editorExpandHeight - 5 } : {}} |
| | | value={value} |
| | | contextBlock={{ |
| | |
| | | workflowVariableBlock={{ |
| | | show: true, |
| | | variables: nodesOutputVars || [], |
| | | getVarType, |
| | | workflowNodesMap: availableNodes.reduce((acc, node) => { |
| | | acc[node.id] = { |
| | | title: node.data.title, |
| | |
| | | </div> |
| | | ) |
| | | : ( |
| | | <div className={cn(isExpand ? 'grow' : 'max-h-[536px]', 'relative min-h-[56px] overflow-y-auto px-3', editorContainerClassName)}> |
| | | <div className={cn(isExpand ? 'grow' : 'max-h-[536px]', 'relative px-3 min-h-[56px] overflow-y-auto')}> |
| | | <CodeEditor |
| | | availableVars={nodesOutputVars || []} |
| | | varList={varList} |
| | |
| | | onChange={onChange} |
| | | noWrapper |
| | | isExpand={isExpand} |
| | | className={inputClassName} |
| | | /> |
| | | </div> |
| | | )} |