| 'use client' | 'use client' | ||||
| import type { FC } from 'react' | import type { FC } from 'react' | ||||
| import React from 'react' | |||||
| import React, { useState } from 'react' | |||||
| import { RiAddLine, RiDeleteBinLine, RiDraggable } from '@remixicon/react' | |||||
| import { useTranslation } from 'react-i18next' | import { useTranslation } from 'react-i18next' | ||||
| import { PlusIcon } from '@heroicons/react/24/outline' | |||||
| import { ReactSortable } from 'react-sortablejs' | import { ReactSortable } from 'react-sortablejs' | ||||
| import RemoveIcon from '../../base/icons/remove-icon' | |||||
| import s from './style.module.css' | |||||
| import cn from '@/utils/classnames' | |||||
| export type Options = string[] | export type Options = string[] | ||||
| export type IConfigSelectProps = { | export type IConfigSelectProps = { | ||||
| onChange, | onChange, | ||||
| }) => { | }) => { | ||||
| const { t } = useTranslation() | const { t } = useTranslation() | ||||
| const [focusID, setFocusID] = useState<number | null>(null) | |||||
| const [deletingID, setDeletingID] = useState<number | null>(null) | |||||
| const optionList = options.map((content, index) => { | const optionList = options.map((content, index) => { | ||||
| return ({ | return ({ | ||||
| animation={150} | animation={150} | ||||
| > | > | ||||
| {options.map((o, index) => ( | {options.map((o, index) => ( | ||||
| <div className={`${s.inputWrap} relative`} key={index}> | |||||
| <div className='handle flex h-4 w-4 cursor-grab items-center justify-center'> | |||||
| <svg width="6" height="10" viewBox="0 0 6 10" fill="none" xmlns="http://www.w3.org/2000/svg"> | |||||
| <path fillRule="evenodd" clipRule="evenodd" d="M1 2C1.55228 2 2 1.55228 2 1C2 0.447715 1.55228 0 1 0C0.447715 0 0 0.447715 0 1C0 1.55228 0.447715 2 1 2ZM1 6C1.55228 6 2 5.55228 2 5C2 4.44772 1.55228 4 1 4C0.447715 4 0 4.44772 0 5C0 5.55228 0.447715 6 1 6ZM6 1C6 1.55228 5.55228 2 5 2C4.44772 2 4 1.55228 4 1C4 0.447715 4.44772 0 5 0C5.55228 0 6 0.447715 6 1ZM5 6C5.55228 6 6 5.55228 6 5C6 4.44772 5.55228 4 5 4C4.44772 4 4 4.44772 4 5C4 5.55228 4.44772 6 5 6ZM2 9C2 9.55229 1.55228 10 1 10C0.447715 10 0 9.55229 0 9C0 8.44771 0.447715 8 1 8C1.55228 8 2 8.44771 2 9ZM5 10C5.55228 10 6 9.55229 6 9C6 8.44771 5.55228 8 5 8C4.44772 8 4 8.44771 4 9C4 9.55229 4.44772 10 5 10Z" fill="#98A2B3" /> | |||||
| </svg> | |||||
| </div> | |||||
| <div | |||||
| className={cn( | |||||
| 'group relative flex items-center rounded-lg border border-components-panel-border-subtle bg-components-panel-on-panel-item-bg pl-2.5 hover:bg-components-panel-on-panel-item-bg-hover', | |||||
| focusID === index && 'border-components-input-border-active bg-components-input-bg-active hover:border-components-input-border-active hover:bg-components-input-bg-active', | |||||
| deletingID === index && 'border-components-input-border-destructive bg-state-destructive-hover hover:border-components-input-border-destructive hover:bg-state-destructive-hover', | |||||
| )} | |||||
| key={index} | |||||
| > | |||||
| <RiDraggable className='handle h-4 w-4 cursor-grab text-text-quaternary' /> | |||||
| <input | <input | ||||
| key={index} | key={index} | ||||
| type="input" | type="input" | ||||
| return item | return item | ||||
| })) | })) | ||||
| }} | }} | ||||
| className={'h-9 w-full grow cursor-pointer border-0 bg-transparent pl-1.5 pr-8 text-sm leading-9 text-gray-900 focus:outline-none'} | |||||
| className={'h-9 w-full grow cursor-pointer overflow-x-auto rounded-lg border-0 bg-transparent pl-1.5 pr-8 text-sm leading-9 text-text-secondary focus:outline-none'} | |||||
| onFocus={() => setFocusID(index)} | |||||
| onBlur={() => setFocusID(null)} | |||||
| /> | /> | ||||
| <RemoveIcon | |||||
| className={`${s.deleteBtn} absolute right-1.5 top-1/2 h-6 w-6 translate-y-[-50%] cursor-pointer items-center justify-center rounded-md hover:bg-[#FEE4E2]`} | |||||
| <div | |||||
| className='absolute right-1.5 top-1/2 block translate-y-[-50%] cursor-pointer rounded-md p-1 text-text-tertiary hover:bg-state-destructive-hover hover:text-text-destructive' | |||||
| onClick={() => { | onClick={() => { | ||||
| onChange(options.filter((_, i) => index !== i)) | onChange(options.filter((_, i) => index !== i)) | ||||
| }} | }} | ||||
| /> | |||||
| onMouseEnter={() => setDeletingID(index)} | |||||
| onMouseLeave={() => setDeletingID(null)} | |||||
| > | |||||
| <RiDeleteBinLine className='h-3.5 w-3.5' /> | |||||
| </div> | |||||
| </div> | </div> | ||||
| ))} | ))} | ||||
| </ReactSortable> | </ReactSortable> | ||||
| <div | <div | ||||
| onClick={() => { onChange([...options, '']) }} | onClick={() => { onChange([...options, '']) }} | ||||
| className='flex h-9 cursor-pointer items-center gap-2 rounded-lg bg-gray-100 px-3 text-gray-400'> | |||||
| <PlusIcon width={16} height={16}></PlusIcon> | |||||
| <div className='text-[13px] text-gray-500'>{t('appDebug.variableConfig.addOption')}</div> | |||||
| className='mt-1 flex h-9 cursor-pointer items-center gap-2 rounded-lg bg-components-button-tertiary-bg px-3 text-components-button-tertiary-text hover:bg-components-button-tertiary-bg-hover'> | |||||
| <RiAddLine className='h-4 w-4' /> | |||||
| <div className='system-sm-medium text-[13px]'>{t('appDebug.variableConfig.addOption')}</div> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| ) | ) |
| .inputWrap { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| border-radius: 8px; | |||||
| border: 1px solid #EAECF0; | |||||
| padding-left: 10px; | |||||
| cursor: pointer; | |||||
| } | |||||
| .deleteBtn { | |||||
| display: none; | |||||
| display: flex; | |||||
| } | |||||
| .inputWrap:hover { | |||||
| box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05); | |||||
| } | |||||
| .inputWrap:hover .deleteBtn { | |||||
| display: flex; | |||||
| } |
| } | } | ||||
| return ( | return ( | ||||
| <div className={cn('flex flex-wrap', !isInWorkflow && 'min-w-[200px]', isSpecialMode ? 'rounded-lg bg-gray-100 pb-1 pl-1' : '')}> | |||||
| <div className={cn('flex flex-wrap', !isInWorkflow && 'min-w-[200px]', isSpecialMode ? 'rounded-lg bg-components-input-bg-normal pb-1 pl-1' : '')}> | |||||
| { | { | ||||
| (items || []).map((item, index) => ( | (items || []).map((item, index) => ( | ||||
| <div | <div |
| 'relative flex h-8 cursor-pointer items-center rounded-lg px-2', | 'relative flex h-8 cursor-pointer items-center rounded-lg px-2', | ||||
| !isInWorkflow && 'border ring-inset hover:ring-[0.5px]', | !isInWorkflow && 'border ring-inset hover:ring-[0.5px]', | ||||
| !isInWorkflow && (disabled ? 'border-text-warning bg-state-warning-hover ring-text-warning' : 'border-util-colors-indigo-indigo-600 bg-state-accent-hover ring-util-colors-indigo-indigo-600'), | !isInWorkflow && (disabled ? 'border-text-warning bg-state-warning-hover ring-text-warning' : 'border-util-colors-indigo-indigo-600 bg-state-accent-hover ring-util-colors-indigo-indigo-600'), | ||||
| isInWorkflow && 'border border-workflow-block-parma-bg bg-workflow-block-parma-bg pr-[30px] hover:border-gray-200', | |||||
| isInWorkflow && 'border border-workflow-block-parma-bg bg-workflow-block-parma-bg pr-[30px] hover:border-components-input-border-active', | |||||
| )} | )} | ||||
| > | > | ||||
| { | { |
| } | } | ||||
| </PortalToFollowElemTrigger> | </PortalToFollowElemTrigger> | ||||
| <PortalToFollowElemContent className='z-[1000]'> | <PortalToFollowElemContent className='z-[1000]'> | ||||
| <div className={`rounded-lg border-[0.5px] border-gray-200 bg-white shadow-lg ${popupClassName}`}> | |||||
| <div className={`rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg ${popupClassName}`}> | |||||
| <div className='px-2 pt-2' onClick={e => e.stopPropagation()}> | <div className='px-2 pt-2' onClick={e => e.stopPropagation()}> | ||||
| {activeTab === TabsEnum.Blocks && ( | {activeTab === TabsEnum.Blocks && ( | ||||
| <Input | <Input |
| </PortalToFollowElemTrigger> | </PortalToFollowElemTrigger> | ||||
| <PortalToFollowElemContent className='z-[12]'> | <PortalToFollowElemContent className='z-[12]'> | ||||
| <div | <div | ||||
| className='w-[420px] overflow-y-auto rounded-2xl border-[0.5px] border-black/5 bg-white shadow-lg' | |||||
| className='w-[420px] overflow-y-auto rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg' | |||||
| style={{ | style={{ | ||||
| maxHeight: 'calc(2 / 3 * 100vh)', | maxHeight: 'calc(2 / 3 * 100vh)', | ||||
| }} | }} | ||||
| > | > | ||||
| <div className='text-md sticky top-0 z-[1] flex h-[44px] items-center bg-white pl-4 pr-3 pt-3 font-semibold text-gray-900'> | |||||
| <div className='text-md sticky top-0 z-[1] flex h-[44px] items-center bg-components-panel-bg pl-4 pr-3 pt-3 font-semibold text-text-primary'> | |||||
| <div className='grow'>{t('workflow.panel.checklist')}{needWarningNodes.length ? `(${needWarningNodes.length})` : ''}</div> | <div className='grow'>{t('workflow.panel.checklist')}{needWarningNodes.length ? `(${needWarningNodes.length})` : ''}</div> | ||||
| <div | <div | ||||
| className='flex h-6 w-6 shrink-0 cursor-pointer items-center justify-center' | className='flex h-6 w-6 shrink-0 cursor-pointer items-center justify-center' | ||||
| onClick={() => setOpen(false)} | onClick={() => setOpen(false)} | ||||
| > | > | ||||
| <RiCloseLine className='h-4 w-4 text-gray-500' /> | |||||
| <RiCloseLine className='h-4 w-4 text-text-tertiary' /> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div className='py-2'> | <div className='py-2'> | ||||
| { | { | ||||
| !!needWarningNodes.length && ( | !!needWarningNodes.length && ( | ||||
| <> | <> | ||||
| <div className='px-4 text-xs text-gray-400'>{t('workflow.panel.checklistTip')}</div> | |||||
| <div className='px-4 text-xs text-text-tertiary'>{t('workflow.panel.checklistTip')}</div> | |||||
| <div className='px-4 py-2'> | <div className='px-4 py-2'> | ||||
| { | { | ||||
| needWarningNodes.map(node => ( | needWarningNodes.map(node => ( | ||||
| <div | <div | ||||
| key={node.id} | key={node.id} | ||||
| className='mb-2 cursor-pointer rounded-lg border-[0.5px] border-gray-200 bg-white shadow-xs last-of-type:mb-0' | |||||
| className='mb-2 cursor-pointer rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-xs last-of-type:mb-0' | |||||
| onClick={() => { | onClick={() => { | ||||
| handleNodeSelect(node.id) | handleNodeSelect(node.id) | ||||
| setOpen(false) | setOpen(false) | ||||
| }} | }} | ||||
| > | > | ||||
| <div className='flex h-9 items-center p-2 text-xs font-medium text-gray-700'> | |||||
| <div className='flex h-9 items-center p-2 text-xs font-medium text-text-secondary'> | |||||
| <BlockIcon | <BlockIcon | ||||
| type={node.type} | type={node.type} | ||||
| className='mr-1.5' | className='mr-1.5' | ||||
| {node.title} | {node.title} | ||||
| </span> | </span> | ||||
| </div> | </div> | ||||
| <div className='border-t-[0.5px] border-t-black/2'> | |||||
| <div className='border-t-[0.5px] border-divider-regular'> | |||||
| { | { | ||||
| node.unConnected && ( | node.unConnected && ( | ||||
| <div className='rounded-b-lg bg-gray-25 px-3 py-2'> | |||||
| <div className='flex text-xs leading-[18px] text-gray-500'> | |||||
| <div className='px-3 py-2 last:rounded-b-lg'> | |||||
| <div className='flex text-xs leading-[18px] text-text-tertiary'> | |||||
| <AlertTriangle className='mr-2 mt-[3px] h-3 w-3 text-[#F79009]' /> | <AlertTriangle className='mr-2 mt-[3px] h-3 w-3 text-[#F79009]' /> | ||||
| {t('workflow.common.needConnectTip')} | {t('workflow.common.needConnectTip')} | ||||
| </div> | </div> | ||||
| } | } | ||||
| { | { | ||||
| node.errorMessage && ( | node.errorMessage && ( | ||||
| <div className='rounded-b-lg bg-gray-25 px-3 py-2'> | |||||
| <div className='flex text-xs leading-[18px] text-gray-500'> | |||||
| <div className='px-3 py-2 last:rounded-b-lg'> | |||||
| <div className='flex text-xs leading-[18px] text-text-tertiary'> | |||||
| <AlertTriangle className='mr-2 mt-[3px] h-3 w-3 text-[#F79009]' /> | <AlertTriangle className='mr-2 mt-[3px] h-3 w-3 text-[#F79009]' /> | ||||
| {node.errorMessage} | {node.errorMessage} | ||||
| </div> | </div> | ||||
| } | } | ||||
| { | { | ||||
| !needWarningNodes.length && ( | !needWarningNodes.length && ( | ||||
| <div className='mx-4 mb-3 rounded-lg bg-gray-50 py-4 text-center text-xs text-gray-400'> | |||||
| <ChecklistSquare className='mx-auto mb-[5px] h-8 w-8 text-gray-300' /> | |||||
| <div className='mx-4 mb-3 rounded-lg bg-components-panel-bg py-4 text-center text-xs text-text-tertiary'> | |||||
| <ChecklistSquare className='mx-auto mb-[5px] h-8 w-8 text-text-quaternary' /> | |||||
| {t('workflow.panel.checklistResolved')} | {t('workflow.panel.checklistResolved')} | ||||
| </div> | </div> | ||||
| ) | ) |
| { | { | ||||
| withText && ( | withText && ( | ||||
| <div className={cn( | <div className={cn( | ||||
| 'flex h-8 items-center rounded-lg border-[0.5px] border-gray-200 bg-white px-3 shadow-xs', | |||||
| 'cursor-pointer text-[13px] font-medium text-primary-600', | |||||
| open && '!bg-primary-50', | |||||
| 'flex h-8 items-center rounded-lg border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg px-3 shadow-xs', | |||||
| 'cursor-pointer text-[13px] font-medium text-components-button-secondary-text hover:bg-components-button-secondary-bg-hover', | |||||
| open && 'bg-components-button-secondary-bg-hover', | |||||
| )}> | )}> | ||||
| <ClockPlay | <ClockPlay | ||||
| className={'mr-1 h-4 w-4'} | className={'mr-1 h-4 w-4'} | ||||
| </PortalToFollowElemTrigger> | </PortalToFollowElemTrigger> | ||||
| <PortalToFollowElemContent className='z-[12]'> | <PortalToFollowElemContent className='z-[12]'> | ||||
| <div | <div | ||||
| className='ml-2 flex w-[240px] flex-col overflow-y-auto rounded-xl border-[0.5px] border-gray-200 bg-white shadow-xl' | |||||
| className='ml-2 flex w-[240px] flex-col overflow-y-auto rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-xl' | |||||
| style={{ | style={{ | ||||
| maxHeight: 'calc(2 / 3 * 100vh)', | maxHeight: 'calc(2 / 3 * 100vh)', | ||||
| }} | }} | ||||
| > | > | ||||
| <div className='sticky top-0 flex items-center justify-between bg-white px-4 pt-3 text-base font-semibold text-gray-900'> | |||||
| <div className='sticky top-0 flex items-center justify-between bg-components-panel-bg px-4 pt-3 text-base font-semibold text-text-primary'> | |||||
| <div className='grow'>{t('workflow.common.runHistory')}</div> | <div className='grow'>{t('workflow.common.runHistory')}</div> | ||||
| <div | <div | ||||
| className='flex h-6 w-6 shrink-0 cursor-pointer items-center justify-center' | className='flex h-6 w-6 shrink-0 cursor-pointer items-center justify-center' | ||||
| setOpen(false) | setOpen(false) | ||||
| }} | }} | ||||
| > | > | ||||
| <RiCloseLine className='h-4 w-4 text-gray-500' /> | |||||
| <RiCloseLine className='h-4 w-4 text-text-tertiary' /> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| { | { | ||||
| { | { | ||||
| !data?.data.length && ( | !data?.data.length && ( | ||||
| <div className='py-12'> | <div className='py-12'> | ||||
| <ClockPlaySlim className='mx-auto mb-2 h-8 w-8 text-gray-300' /> | |||||
| <div className='text-center text-[13px] text-gray-400'> | |||||
| <ClockPlaySlim className='mx-auto mb-2 h-8 w-8 text-text-quaternary' /> | |||||
| <div className='text-center text-[13px] text-text-quaternary'> | |||||
| {t('workflow.common.notRunning')} | {t('workflow.common.notRunning')} | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div | <div | ||||
| key={item.id} | key={item.id} | ||||
| className={cn( | className={cn( | ||||
| 'mb-0.5 flex cursor-pointer rounded-lg px-2 py-[7px] hover:bg-primary-50', | |||||
| item.id === historyWorkflowData?.id && 'bg-primary-50', | |||||
| 'mb-0.5 flex cursor-pointer rounded-lg px-2 py-[7px] hover:bg-state-base-hover', | |||||
| item.id === historyWorkflowData?.id && 'bg-state-accent-hover hover:bg-state-accent-hover', | |||||
| )} | )} | ||||
| onClick={() => { | onClick={() => { | ||||
| workflowStore.setState({ | workflowStore.setState({ | ||||
| <div> | <div> | ||||
| <div | <div | ||||
| className={cn( | className={cn( | ||||
| 'flex items-center text-[13px] font-medium leading-[18px]', | |||||
| item.id === historyWorkflowData?.id && 'text-primary-600', | |||||
| 'flex items-center text-[13px] font-medium leading-[18px] text-text-primary', | |||||
| item.id === historyWorkflowData?.id && 'text-text-accent', | |||||
| )} | )} | ||||
| > | > | ||||
| {`Test ${isChatMode ? 'Chat' : 'Run'} #${item.sequence_number}`} | {`Test ${isChatMode ? 'Chat' : 'Run'} #${item.sequence_number}`} | ||||
| </div> | </div> | ||||
| <div className='flex items-center text-xs leading-[18px] text-gray-500'> | |||||
| <div className='flex items-center text-xs leading-[18px] text-text-tertiary'> | |||||
| {item.created_by_account?.name} · {formatTimeFromNow((item.finished_at || item.created_at) * 1000)} | {item.created_by_account?.name} · {formatTimeFromNow((item.finished_at || item.created_at) * 1000)} | ||||
| </div> | </div> | ||||
| </div> | </div> |
| const { t } = useTranslation() | const { t } = useTranslation() | ||||
| return ( | return ( | ||||
| <div className='w-[240px] rounded-lg border-[0.5px] border-gray-200 bg-white shadow-lg'> | |||||
| <div className='flex h-[34px] items-center border-b-[0.5px] border-b-gray-200 px-4 text-[13px] font-semibold text-gray-700'> | |||||
| <div className='w-[240px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg'> | |||||
| <div className='flex h-[34px] items-center border-b-[0.5px] border-b-divider-regular px-4 text-[13px] font-semibold text-text-secondary'> | |||||
| {t('workflow.nodes.variableAssigner.setAssignVariable')} | {t('workflow.nodes.variableAssigner.setAssignVariable')} | ||||
| </div> | </div> | ||||
| <div className='p-1'> | <div className='p-1'> |
| onRun(submitData) | onRun(submitData) | ||||
| }, [forms, onRun, t]) | }, [forms, onRun, t]) | ||||
| return ( | return ( | ||||
| <div className='absolute inset-0 z-10 rounded-2xl pt-10' style={{ | |||||
| backgroundColor: 'rgba(16, 24, 40, 0.20)', | |||||
| }}> | |||||
| <div className='flex h-full flex-col rounded-2xl bg-white'> | |||||
| <div className='absolute inset-0 z-10 rounded-2xl bg-background-overlay-alt pt-10'> | |||||
| <div className='flex h-full flex-col rounded-2xl bg-components-panel-bg'> | |||||
| <div className='flex h-8 shrink-0 items-center justify-between pl-4 pr-3 pt-3'> | <div className='flex h-8 shrink-0 items-center justify-between pl-4 pr-3 pt-3'> | ||||
| <div className='truncate text-base font-semibold text-gray-900'> | |||||
| <div className='truncate text-base font-semibold text-text-primary'> | |||||
| {t(`${i18nPrefix}.testRun`)} {nodeName} | {t(`${i18nPrefix}.testRun`)} {nodeName} | ||||
| </div> | </div> | ||||
| <div className='ml-2 shrink-0 cursor-pointer p-1' onClick={() => { | <div className='ml-2 shrink-0 cursor-pointer p-1' onClick={() => { | ||||
| onHide() | onHide() | ||||
| }}> | }}> | ||||
| <RiCloseLine className='h-4 w-4 text-gray-500 ' /> | |||||
| <RiCloseLine className='h-4 w-4 text-text-tertiary ' /> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| { | { | ||||
| <div className='mt-4 flex justify-between space-x-2 px-4' > | <div className='mt-4 flex justify-between space-x-2 px-4' > | ||||
| {isRunning && ( | {isRunning && ( | ||||
| <div | <div | ||||
| className='cursor-pointer rounded-lg border border-gray-200 bg-white p-2 shadow-xs' | |||||
| className='cursor-pointer rounded-lg border border-divider-regular bg-components-button-secondary-bg p-2 shadow-xs' | |||||
| onClick={onStop} | onClick={onStop} | ||||
| > | > | ||||
| <StopCircle className='h-4 w-4 text-gray-500' /> | |||||
| <StopCircle className='h-4 w-4 text-text-tertiary' /> | |||||
| </div> | </div> | ||||
| )} | )} | ||||
| <Button disabled={!isFileLoaded || isRunning} variant='primary' className='w-0 grow space-x-2' onClick={handleRun}> | <Button disabled={!isFileLoaded || isRunning} variant='primary' className='w-0 grow space-x-2' onClick={handleRun}> | ||||
| {isRunning && <RiLoader2Line className='h-4 w-4 animate-spin text-white' />} | |||||
| {isRunning && <RiLoader2Line className='h-4 w-4 animate-spin' />} | |||||
| <div>{t(`${i18nPrefix}.${isRunning ? 'running' : 'startRun'}`)}</div> | <div>{t(`${i18nPrefix}.${isRunning ? 'running' : 'startRun'}`)}</div> | ||||
| </Button> | </Button> | ||||
| </div> | </div> |
| import { | import { | ||||
| getFilesInLogs, | getFilesInLogs, | ||||
| } from '@/app/components/base/file-uploader/utils' | } from '@/app/components/base/file-uploader/utils' | ||||
| import { Theme } from '@/types/app' | |||||
| import useTheme from '@/hooks/use-theme' | |||||
| import './style.css' | import './style.css' | ||||
| import { noop } from 'lodash-es' | import { noop } from 'lodash-es' | ||||
| [CodeLanguage.json]: 'json', | [CodeLanguage.json]: 'json', | ||||
| } | } | ||||
| const DEFAULT_THEME = { | |||||
| base: 'vs', | |||||
| inherit: true, | |||||
| rules: [], | |||||
| colors: { | |||||
| 'editor.background': '#F2F4F7', // #00000000 transparent. But it will has a blue border | |||||
| }, | |||||
| } | |||||
| const CodeEditor: FC<Props> = ({ | const CodeEditor: FC<Props> = ({ | ||||
| value = '', | value = '', | ||||
| placeholder = '', | placeholder = '', | ||||
| const [isMounted, setIsMounted] = React.useState(false) | const [isMounted, setIsMounted] = React.useState(false) | ||||
| const minHeight = height || 200 | const minHeight = height || 200 | ||||
| const [editorContentHeight, setEditorContentHeight] = useState(56) | const [editorContentHeight, setEditorContentHeight] = useState(56) | ||||
| const { theme: appTheme } = useTheme() | |||||
| const valueRef = useRef(value) | const valueRef = useRef(value) | ||||
| useEffect(() => { | useEffect(() => { | ||||
| valueRef.current = value | valueRef.current = value | ||||
| setIsFocus(false) | setIsFocus(false) | ||||
| }) | }) | ||||
| monaco.editor.defineTheme('default-theme', DEFAULT_THEME) | |||||
| monaco.editor.defineTheme('blur-theme', { | |||||
| base: 'vs', | |||||
| inherit: true, | |||||
| rules: [], | |||||
| colors: { | |||||
| 'editor.background': '#F2F4F7', | |||||
| }, | |||||
| }) | |||||
| monaco.editor.defineTheme('focus-theme', { | |||||
| base: 'vs', | |||||
| inherit: true, | |||||
| rules: [], | |||||
| colors: { | |||||
| 'editor.background': '#ffffff', | |||||
| }, | |||||
| }) | |||||
| monaco.editor.setTheme('default-theme') // Fix: sometimes not load the default theme | |||||
| monaco.editor.setTheme(appTheme === Theme.light ? 'light' : 'vs-dark') // Fix: sometimes not load the default theme | |||||
| onMount?.(editor, monaco) | onMount?.(editor, monaco) | ||||
| setIsMounted(true) | setIsMounted(true) | ||||
| } | } | ||||
| })() | })() | ||||
| const theme = (() => { | |||||
| if (noWrapper) | |||||
| return 'default-theme' | |||||
| return isFocus ? 'focus-theme' : 'blur-theme' | |||||
| })() | |||||
| const theme = useMemo(() => { | |||||
| if (appTheme === Theme.light) | |||||
| return 'light' | |||||
| return 'vs-dark' | |||||
| }, [appTheme]) | |||||
| const main = ( | const main = ( | ||||
| <> | <> |
| padding-left: 0; | padding-left: 0; | ||||
| } | } | ||||
| .monaco-editor { | |||||
| background-color: transparent !important; | |||||
| outline: none !important; | |||||
| } | |||||
| .monaco-editor .monaco-editor-background { | |||||
| background-color: transparent !important; | |||||
| } | |||||
| .monaco-editor .margin { | |||||
| background-color: transparent !important; | |||||
| } | |||||
| /* hide readonly tooltip */ | /* hide readonly tooltip */ | ||||
| .monaco-editor-overlaymessage { | .monaco-editor-overlaymessage { | ||||
| display: none !important; | display: none !important; |
| return ( | return ( | ||||
| <div className='px-4 pt-2'> | <div className='px-4 pt-2'> | ||||
| <div className='rounded-[10px] bg-workflow-process-bg p-4'> | <div className='rounded-[10px] bg-workflow-process-bg p-4'> | ||||
| <div className='mb-2 flex h-8 w-8 items-center justify-center rounded-[10px] border-[0.5px] bg-components-card-bg shadow-lg'> | |||||
| <div className='mb-2 flex h-8 w-8 items-center justify-center rounded-[10px] border-[0.5px] border-components-card-border bg-components-card-bg shadow-lg'> | |||||
| <RiMindMap className='h-5 w-5 text-text-tertiary' /> | <RiMindMap className='h-5 w-5 text-text-tertiary' /> | ||||
| </div> | </div> | ||||
| <div className='system-sm-medium mb-1 text-text-secondary'> | <div className='system-sm-medium mb-1 text-text-secondary'> |
| <Tooltip | <Tooltip | ||||
| popupContent={`${t('workflow.common.insertVarTip')}`} | popupContent={`${t('workflow.common.insertVarTip')}`} | ||||
| > | > | ||||
| <div className='cursor-pointer rounded-[5px] border-[0.5px] border-black/5 bg-white p-0.5 shadow-lg hover:bg-gray-100'> | |||||
| <div className='cursor-pointer rounded-[5px] border-[0.5px] border-divider-regular bg-components-badge-white-to-dark p-0.5 shadow-lg'> | |||||
| <Variable02 className='h-3.5 w-3.5 text-components-button-secondary-accent-text' /> | <Variable02 className='h-3.5 w-3.5 text-components-button-secondary-accent-text' /> | ||||
| </div> | </div> | ||||
| </Tooltip> | </Tooltip> |
| }, [onChange]) | }, [onChange]) | ||||
| return ( | return ( | ||||
| <div className='flex items-center justify-between'> | <div className='flex items-center justify-between'> | ||||
| <div className='text-[13px] font-normal text-gray-700'>{title}</div> | |||||
| <input | |||||
| <div className='text-[13px] font-normal text-text-secondary'>{title}</div> | |||||
| <Input | |||||
| readOnly={readonly} | readOnly={readonly} | ||||
| value={value} | value={value} | ||||
| onChange={handleChange} | onChange={handleChange} | ||||
| className='h-8 w-[200px] rounded-lg border-0 bg-gray-100 px-2.5 text-[13px] leading-8 text-gray-900 placeholder:text-gray-400 focus:outline-none focus:ring-1 focus:ring-inset focus:ring-gray-200' | |||||
| className='h-8 w-[200px]' | |||||
| type='text' /> | type='text' /> | ||||
| </div> | </div> | ||||
| ) | ) | ||||
| </div> | </div> | ||||
| {canSetRoleName && ( | {canSetRoleName && ( | ||||
| <div className='mt-4'> | <div className='mt-4'> | ||||
| <div className='text-xs font-medium uppercase leading-6 text-gray-500'>{t(`${i18nPrefix}.conversationRoleName`)}</div> | |||||
| <div className='text-xs font-medium uppercase leading-6 text-text-tertiary'>{t(`${i18nPrefix}.conversationRoleName`)}</div> | |||||
| <div className='mt-1 space-y-2'> | <div className='mt-1 space-y-2'> | ||||
| <RoleItem | <RoleItem | ||||
| readonly={readonly} | readonly={readonly} |
| <div className='system-xs-regular mt-0.5 text-text-tertiary'> | <div className='system-xs-regular mt-0.5 text-text-tertiary'> | ||||
| {description} | {description} | ||||
| {subItems && ( | {subItems && ( | ||||
| <div className='ml-2 border-l border-gray-200 pl-2'> | |||||
| <div className='ml-2 border-l border-divider-regular pl-2'> | |||||
| {subItems.map((item, index) => ( | {subItems.map((item, index) => ( | ||||
| <VarItem | <VarItem | ||||
| key={index} | key={index} |
| const renderTrigger = useCallback(() => { | const renderTrigger = useCallback(() => { | ||||
| return ( | return ( | ||||
| <div className='flex h-8 w-[232px] cursor-pointer items-center rounded-lg px-3 text-sm text-gray-700 hover:bg-gray-50'> | |||||
| <div className='flex h-8 w-[232px] cursor-pointer items-center rounded-lg px-3 text-sm text-text-secondary hover:bg-state-base-hover'> | |||||
| {t('workflow.panel.changeBlock')} | {t('workflow.panel.changeBlock')} | ||||
| </div> | </div> | ||||
| ) | ) |
| const link = useNodeHelpLink(data.type) | const link = useNodeHelpLink(data.type) | ||||
| return ( | return ( | ||||
| <div className='w-[240px] rounded-lg border-[0.5px] border-gray-200 bg-white shadow-xl'> | |||||
| <div className='w-[240px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-xl'> | |||||
| { | { | ||||
| (showChangeBlock || canRunBySingle(data.type)) && ( | (showChangeBlock || canRunBySingle(data.type)) && ( | ||||
| <> | <> | ||||
| canRunBySingle(data.type) && ( | canRunBySingle(data.type) && ( | ||||
| <div | <div | ||||
| className={` | className={` | ||||
| flex h-8 cursor-pointer items-center rounded-lg px-3 text-sm text-gray-700 | |||||
| hover:bg-gray-50 | |||||
| flex h-8 cursor-pointer items-center rounded-lg px-3 text-sm text-text-secondary | |||||
| hover:bg-state-base-hover | |||||
| `} | `} | ||||
| onClick={() => { | onClick={() => { | ||||
| handleNodeSelect(id) | handleNodeSelect(id) | ||||
| ) | ) | ||||
| } | } | ||||
| </div> | </div> | ||||
| <div className='h-[1px] bg-gray-100'></div> | |||||
| <div className='h-[1px] bg-divider-regular'></div> | |||||
| </> | </> | ||||
| ) | ) | ||||
| } | } | ||||
| <> | <> | ||||
| <div className='p-1'> | <div className='p-1'> | ||||
| <div | <div | ||||
| className='flex h-8 cursor-pointer items-center justify-between rounded-lg px-3 text-sm text-gray-700 hover:bg-gray-50' | |||||
| className='flex h-8 cursor-pointer items-center justify-between rounded-lg px-3 text-sm text-text-secondary hover:bg-state-base-hover' | |||||
| onClick={() => { | onClick={() => { | ||||
| onClosePopup() | onClosePopup() | ||||
| handleNodesCopy(id) | handleNodesCopy(id) | ||||
| <ShortcutsName keys={['ctrl', 'c']} /> | <ShortcutsName keys={['ctrl', 'c']} /> | ||||
| </div> | </div> | ||||
| <div | <div | ||||
| className='flex h-8 cursor-pointer items-center justify-between rounded-lg px-3 text-sm text-gray-700 hover:bg-gray-50' | |||||
| className='flex h-8 cursor-pointer items-center justify-between rounded-lg px-3 text-sm text-text-secondary hover:bg-state-base-hover' | |||||
| onClick={() => { | onClick={() => { | ||||
| onClosePopup() | onClosePopup() | ||||
| handleNodesDuplicate(id) | handleNodesDuplicate(id) | ||||
| <ShortcutsName keys={['ctrl', 'd']} /> | <ShortcutsName keys={['ctrl', 'd']} /> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div className='h-[1px] bg-gray-100'></div> | |||||
| <div className='h-[1px] bg-divider-regular'></div> | |||||
| <div className='p-1'> | <div className='p-1'> | ||||
| <div | <div | ||||
| className={` | className={` | ||||
| flex h-8 cursor-pointer items-center justify-between rounded-lg px-3 text-sm text-gray-700 | |||||
| hover:bg-rose-50 hover:text-red-500 | |||||
| flex h-8 cursor-pointer items-center justify-between rounded-lg px-3 text-sm text-text-secondary | |||||
| hover:bg-state-destructive-hover hover:text-red-500 | |||||
| `} | `} | ||||
| onClick={() => handleNodeDelete(id)} | onClick={() => handleNodeDelete(id)} | ||||
| > | > | ||||
| <ShortcutsName keys={['del']} /> | <ShortcutsName keys={['del']} /> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div className='h-[1px] bg-gray-100'></div> | |||||
| <div className='h-[1px] bg-divider-regular'></div> | |||||
| </> | </> | ||||
| ) | ) | ||||
| } | } | ||||
| <a | <a | ||||
| href={link} | href={link} | ||||
| target='_blank' | target='_blank' | ||||
| className='flex h-8 cursor-pointer items-center rounded-lg px-3 text-sm text-gray-700 hover:bg-gray-50' | |||||
| className='flex h-8 cursor-pointer items-center rounded-lg px-3 text-sm text-text-secondary hover:bg-state-base-hover' | |||||
| > | > | ||||
| {t('workflow.panel.helpLink')} | {t('workflow.panel.helpLink')} | ||||
| </a> | </a> | ||||
| </div> | </div> | ||||
| <div className='h-[1px] bg-gray-100'></div> | |||||
| <div className='h-[1px] bg-divider-regular'></div> | |||||
| </> | </> | ||||
| ) | ) | ||||
| } | } | ||||
| <div className='p-1'> | <div className='p-1'> | ||||
| <div className='px-3 py-2 text-xs text-gray-500'> | |||||
| <div className='px-3 py-2 text-xs text-text-tertiary'> | |||||
| <div className='mb-1 flex h-[22px] items-center font-medium'> | <div className='mb-1 flex h-[22px] items-center font-medium'> | ||||
| {t('workflow.panel.about').toLocaleUpperCase()} | {t('workflow.panel.about').toLocaleUpperCase()} | ||||
| </div> | </div> | ||||
| <div className='mb-1 leading-[18px] text-gray-700'>{about}</div> | |||||
| <div className='mb-1 leading-[18px] text-text-secondary'>{about}</div> | |||||
| <div className='leading-[18px]'> | <div className='leading-[18px]'> | ||||
| {t('workflow.panel.createdBy')} {author} | {t('workflow.panel.createdBy')} {author} | ||||
| </div> | </div> |
| Clipboard, | Clipboard, | ||||
| ClipboardCheck, | ClipboardCheck, | ||||
| } from '@/app/components/base/icons/src/vender/line/files' | } 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 { 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 { Variable02 } from '@/app/components/base/icons/src/vender/solid/development' | ||||
| return ( | return ( | ||||
| <Wrap className={cn(className, wrapClassName)} style={wrapStyle} isInNode isExpand={isExpand}> | <Wrap className={cn(className, wrapClassName)} style={wrapStyle} isInNode isExpand={isExpand}> | ||||
| <div ref={ref} className={cn(isFocus ? (gradientBorder && s.gradientBorder) : 'bg-gray-100', isExpand && 'h-full', '!rounded-[9px] p-0.5', containerClassName)}> | |||||
| <div className={cn(isFocus ? 'bg-gray-50' : 'bg-gray-100', isExpand && 'flex h-full flex-col', 'rounded-lg', containerClassName)}> | |||||
| <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={cn('flex items-center justify-between pl-3 pr-2 pt-1', headerClassName)}> | ||||
| <div className='flex gap-2'> | <div className='flex gap-2'> | ||||
| <div className={cn('text-xs font-semibold uppercase leading-4 text-gray-700', titleClassName)}>{title} {required && <span className='text-red-500'>*</span>}</div> | |||||
| <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} />} | {titleTooltip && <Tooltip popupContent={titleTooltip} />} | ||||
| </div> | </div> | ||||
| <div className='flex items-center'> | <div className='flex items-center'> | ||||
| <div className='text-xs font-medium leading-[18px] text-gray-500'>{value?.length || 0}</div> | |||||
| <div className='text-xs font-medium leading-[18px] text-text-tertiary'>{value?.length || 0}</div> | |||||
| {isSupportPromptGenerator && ( | {isSupportPromptGenerator && ( | ||||
| <PromptGeneratorBtn className='ml-[5px]' onGenerated={onGenerated} modelConfig={modelConfig} /> | <PromptGeneratorBtn className='ml-[5px]' onGenerated={onGenerated} modelConfig={modelConfig} /> | ||||
| )} | )} | ||||
| <div className='ml-2 mr-2 h-3 w-px bg-gray-200'></div> | |||||
| <div className='ml-2 mr-2 h-3 w-px bg-divider-regular'></div> | |||||
| {/* Operations */} | {/* Operations */} | ||||
| <div className='flex items-center space-x-[2px]'> | <div className='flex items-center space-x-[2px]'> | ||||
| {isSupportJinja && ( | {isSupportJinja && ( | ||||
| popupContent={ | popupContent={ | ||||
| <div> | <div> | ||||
| <div>{t('workflow.common.enableJinja')}</div> | <div>{t('workflow.common.enableJinja')}</div> | ||||
| <a className='text-[#155EEF]' target='_blank' href='https://jinja.palletsprojects.com/en/2.10.x/'>{t('workflow.common.learnMore')}</a> | |||||
| <a className='text-text-accent' target='_blank' href='https://jinja.palletsprojects.com/en/2.10.x/'>{t('workflow.common.learnMore')}</a> | |||||
| </div> | </div> | ||||
| } | } | ||||
| needsDelay | needsDelay | ||||
| > | > | ||||
| <div className={cn(editionType === EditionType.jinja2 && 'border-black/5 bg-white', 'flex h-[22px] items-center space-x-0.5 rounded-[5px] border border-transparent px-1.5 hover:border-black/5')}> | |||||
| <Jinja className='h-3 w-6 text-gray-300' /> | |||||
| <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' /> | |||||
| <Switch | <Switch | ||||
| size='sm' | size='sm' | ||||
| defaultValue={editionType === EditionType.jinja2} | defaultValue={editionType === EditionType.jinja2} |
| return (<span key={index}> | return (<span key={index}> | ||||
| <span className='relative top-[-3px] leading-[16px]'>{str}</span> | <span className='relative top-[-3px] leading-[16px]'>{str}</span> | ||||
| <div className=' inline-flex h-[16px] items-center rounded-[5px] bg-white px-1.5'> | |||||
| <div className=' inline-flex h-[16px] items-center rounded-[5px] bg-components-badge-white-to-dark px-1.5'> | |||||
| {!isEnv && !isChatVar && ( | {!isEnv && !isChatVar && ( | ||||
| <div className='flex items-center'> | <div className='flex items-center'> | ||||
| <div className='p-[1px]'> | <div className='p-[1px]'> | ||||
| <VarBlockIcon | <VarBlockIcon | ||||
| className='!text-gray-900' | |||||
| className='!text-text-primary' | |||||
| type={node?.type || BlockEnum.Start} | type={node?.type || BlockEnum.Start} | ||||
| /> | /> | ||||
| </div> | </div> | ||||
| <div className='mx-0.5 max-w-[60px] truncate text-xs font-medium text-gray-700' title={node?.title}>{node?.title}</div> | |||||
| <div className='mx-0.5 max-w-[60px] truncate text-xs font-medium text-text-secondary' title={node?.title}>{node?.title}</div> | |||||
| <Line3 className='mr-0.5'></Line3> | <Line3 className='mr-0.5'></Line3> | ||||
| </div> | </div> | ||||
| )} | )} | ||||
| <div className='flex items-center text-primary-600'> | |||||
| <div className='flex items-center text-text-accent'> | |||||
| {!isEnv && !isChatVar && <Variable02 className='h-3.5 w-3.5 shrink-0' />} | {!isEnv && !isChatVar && <Variable02 className='h-3.5 w-3.5 shrink-0' />} | ||||
| {isEnv && <Env className='h-3.5 w-3.5 shrink-0 text-util-colors-violet-violet-600' />} | {isEnv && <Env className='h-3.5 w-3.5 shrink-0 text-util-colors-violet-violet-600' />} | ||||
| {isChatVar && <BubbleX className='h-3.5 w-3.5 text-util-colors-teal-teal-700' />} | {isChatVar && <BubbleX className='h-3.5 w-3.5 text-util-colors-teal-teal-700' />} | ||||
| <div className={cn('ml-0.5 max-w-[50px] truncate text-xs font-medium', (isEnv || isChatVar) && 'text-gray-900')} title={varName}>{varName}</div> | |||||
| <div className={cn('ml-0.5 max-w-[50px] truncate text-xs font-medium', (isEnv || isChatVar) && 'text-text-primary')} title={varName}>{varName}</div> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </span>) | </span>) |
| import type { FC } from 'react' | import type { FC } from 'react' | ||||
| import React from 'react' | import React from 'react' | ||||
| import { RiDeleteBinLine } from '@remixicon/react' | import { RiDeleteBinLine } from '@remixicon/react' | ||||
| import cn from '@/utils/classnames' | |||||
| import ActionButton from '@/app/components/base/action-button' | |||||
| type Props = { | type Props = { | ||||
| className?: string | className?: string | ||||
| } | } | ||||
| const Remove: FC<Props> = ({ | const Remove: FC<Props> = ({ | ||||
| className, | |||||
| onClick, | onClick, | ||||
| }) => { | }) => { | ||||
| return ( | return ( | ||||
| <div | |||||
| className={cn(className, 'cursor-pointer rounded-md p-1 text-gray-500 hover:bg-black/5 hover:text-gray-800')} | |||||
| onClick={onClick} | |||||
| > | |||||
| <RiDeleteBinLine className='h-4 w-4' /> | |||||
| </div> | |||||
| <ActionButton size='l' className='group shrink-0 hover:!bg-state-destructive-hover' onClick={onClick}> | |||||
| <RiDeleteBinLine className='h-4 w-4 text-text-tertiary group-hover:text-text-destructive' /> | |||||
| </ActionButton> | |||||
| ) | ) | ||||
| } | } | ||||
| export default React.memo(Remove) | export default React.memo(Remove) |
| retry_config?.retry_enabled && ( | retry_config?.retry_enabled && ( | ||||
| <div className='px-4 pb-2'> | <div className='px-4 pb-2'> | ||||
| <div className='mb-1 flex w-full items-center'> | <div className='mb-1 flex w-full items-center'> | ||||
| <div className='system-xs-medium-uppercase mr-2 grow'>{t('workflow.nodes.common.retry.maxRetries')}</div> | |||||
| <div className='system-xs-medium-uppercase mr-2 grow text-text-secondary'>{t('workflow.nodes.common.retry.maxRetries')}</div> | |||||
| <Slider | <Slider | ||||
| className='mr-3 w-[108px]' | className='mr-3 w-[108px]' | ||||
| value={retry_config?.max_retries || 3} | value={retry_config?.max_retries || 3} | ||||
| /> | /> | ||||
| </div> | </div> | ||||
| <div className='flex items-center'> | <div className='flex items-center'> | ||||
| <div className='system-xs-medium-uppercase mr-2 grow'>{t('workflow.nodes.common.retry.retryInterval')}</div> | |||||
| <div className='system-xs-medium-uppercase mr-2 grow text-text-secondary'>{t('workflow.nodes.common.retry.retryInterval')}</div> | |||||
| <Slider | <Slider | ||||
| className='mr-3 w-[108px]' | className='mr-3 w-[108px]' | ||||
| value={retry_config?.retry_interval || 1000} | value={retry_config?.retry_interval || 1000} |
| : ( | : ( | ||||
| <div | <div | ||||
| onClick={toggleShow} | onClick={toggleShow} | ||||
| className={cn(showOption && 'bg-black/5', 'flex h-5 cursor-pointer items-center rounded-md pl-1 pr-0.5 text-xs font-semibold text-gray-700 hover:bg-black/5')}> | |||||
| <div className={cn('text-sm font-semibold', uppercase && 'uppercase', noValue && 'text-gray-400', triggerClassName)}>{!noValue ? item?.label : placeholder}</div> | |||||
| className={cn(showOption && 'bg-state-base-hover', 'flex h-5 cursor-pointer items-center rounded-md pl-1 pr-0.5 text-xs font-semibold text-text-secondary hover:bg-state-base-hover')}> | |||||
| <div className={cn('text-sm font-semibold', uppercase && 'uppercase', noValue && 'text-text-tertiary', triggerClassName)}>{!noValue ? item?.label : placeholder}</div> | |||||
| {!readonly && <DropDownIcon className='h-3 w-3 ' />} | {!readonly && <DropDownIcon className='h-3 w-3 ' />} | ||||
| </div> | </div> | ||||
| )} | )} | ||||
| {(showOption && !readonly) && ( | {(showOption && !readonly) && ( | ||||
| <div className={cn('absolute top-[24px] z-10 w-[120px] select-none rounded-lg border border-gray-200 bg-white p-1 shadow-lg', popupClassName)}> | |||||
| <div className={cn('absolute top-[24px] z-10 w-[120px] select-none rounded-lg border border-components-panel-border bg-components-panel-bg p-1 shadow-lg', popupClassName)}> | |||||
| {list.map(item => ( | {list.map(item => ( | ||||
| <div | <div | ||||
| key={item.value} | key={item.value} | ||||
| setHide() | setHide() | ||||
| onChange(item.value) | onChange(item.value) | ||||
| }} | }} | ||||
| className={cn(itemClassName, uppercase && 'uppercase', 'flex h-[30px] min-w-[44px] cursor-pointer items-center justify-between rounded-lg px-3 text-[13px] font-medium text-gray-700 hover:bg-gray-50')} | |||||
| className={cn(itemClassName, uppercase && 'uppercase', 'flex h-[30px] min-w-[44px] cursor-pointer items-center justify-between rounded-lg px-3 text-[13px] font-medium text-text-secondary hover:bg-state-base-hover')} | |||||
| > | > | ||||
| <div>{item.label}</div> | <div>{item.label}</div> | ||||
| {showChecked && item.value === value && <Check className='h-4 w-4 text-primary-600' />} | |||||
| {showChecked && item.value === value && <Check className='h-4 w-4 text-text-primary' />} | |||||
| </div> | </div> | ||||
| )) | )) | ||||
| } | } |
| value={localValue} | value={localValue} | ||||
| onChange={e => setLocalValue(e.target.value)} | onChange={e => setLocalValue(e.target.value)} | ||||
| className={` | className={` | ||||
| system-xl-semibold mr-2 h-7 min-w-0 grow appearance-none rounded-md border border-transparent px-1 text-text-primary | |||||
| system-xl-semibold mr-2 h-7 min-w-0 grow appearance-none rounded-md border border-transparent bg-transparent px-1 text-text-primary | |||||
| outline-none focus:shadow-xs | outline-none focus:shadow-xs | ||||
| `} | `} | ||||
| placeholder={t('workflow.common.addTitle') || ''} | placeholder={t('workflow.common.addTitle') || ''} | ||||
| onBlur={handleBlur} | onBlur={handleBlur} | ||||
| className={` | className={` | ||||
| w-full resize-none appearance-none bg-transparent text-xs | w-full resize-none appearance-none bg-transparent text-xs | ||||
| leading-[18px] text-gray-900 caret-[#295EFF] | |||||
| outline-none placeholder:text-gray-400 | |||||
| leading-[18px] text-text-primary caret-[#295EFF] | |||||
| outline-none placeholder:text-text-quaternary | |||||
| `} | `} | ||||
| placeholder={t('workflow.common.addDescription') || ''} | placeholder={t('workflow.common.addDescription') || ''} | ||||
| /> | /> |
| const { t } = useTranslation() | const { t } = useTranslation() | ||||
| return ( | return ( | ||||
| <Tooltip popupContent={!isValid && t('workflow.errorMsg.invalidVariable')}> | <Tooltip popupContent={!isValid && t('workflow.errorMsg.invalidVariable')}> | ||||
| <div className={cn('border-[rgba(16, 2440,0.08)] inline-flex h-6 max-w-full items-center rounded-md border-[0.5px] bg-white px-1.5 text-xs shadow-xs', | |||||
| <div className={cn('border-[rgba(16, 2440,0.08)] inline-flex h-6 max-w-full items-center rounded-md border-[0.5px] border-divider-subtle bg-components-badge-white-to-dark px-1.5 text-xs shadow-xs', | |||||
| !isValid && 'border-red-400 !bg-[#FEF3F2]', | !isValid && 'border-red-400 !bg-[#FEF3F2]', | ||||
| )}> | )}> | ||||
| {(!isEnv && !isChatVar && <> | {(!isEnv && !isChatVar && <> | ||||
| <> | <> | ||||
| <VarBlockIcon | <VarBlockIcon | ||||
| type={node.data.type || BlockEnum.Start} | type={node.data.type || BlockEnum.Start} | ||||
| className='mr-0.5' | |||||
| className='mr-0.5 !text-text-primary' | |||||
| /> | /> | ||||
| <div | <div | ||||
| className='max-w-[60px] truncate font-medium text-text-secondary' | className='max-w-[60px] truncate font-medium text-text-secondary' |
| isSupportFileVar={isSupportFileVar} | isSupportFileVar={isSupportFileVar} | ||||
| /> | /> | ||||
| {!readonly && ( | {!readonly && ( | ||||
| <RemoveButton | |||||
| className='!bg-gray-100 !p-2 hover:!bg-gray-200' | |||||
| onClick={handleVarRemove(index)} | |||||
| /> | |||||
| <RemoveButton onClick={handleVarRemove(index)}/> | |||||
| )} | )} | ||||
| </div> | </div> | ||||
| ))} | ))} |
| }} | }} | ||||
| className='h-full grow' | className='h-full grow' | ||||
| > | > | ||||
| <div ref={isSupportConstantValue ? triggerRef : null} className={cn('h-full', isSupportConstantValue && 'flex items-center rounded-lg bg-gray-100 py-1 pl-1')}> | |||||
| <div ref={isSupportConstantValue ? triggerRef : null} className={cn('h-full', isSupportConstantValue && 'flex items-center rounded-lg bg-components-panel-bg py-1 pl-1')}> | |||||
| <Tooltip popupContent={!isValidVar && hasValue && t('workflow.errorMsg.invalidVariable')}> | <Tooltip popupContent={!isValidVar && hasValue && t('workflow.errorMsg.invalidVariable')}> | ||||
| <div className={cn('h-full items-center rounded-[5px] px-1.5', hasValue ? 'inline-flex bg-white' : 'flex')}> | |||||
| <div className={cn('h-full items-center rounded-[5px] px-1.5', hasValue ? 'inline-flex bg-components-badge-white-to-dark' : 'flex')}> | |||||
| {hasValue | {hasValue | ||||
| ? ( | ? ( | ||||
| <> | <> | ||||
| <div className='flex items-center'> | <div className='flex items-center'> | ||||
| <div className='h-3 px-[1px]'> | <div className='h-3 px-[1px]'> | ||||
| {outputVarNode?.type && <VarBlockIcon | {outputVarNode?.type && <VarBlockIcon | ||||
| className='!text-gray-900' | |||||
| className='!text-text-primary' | |||||
| type={outputVarNode.type} | type={outputVarNode.type} | ||||
| />} | />} | ||||
| </div> | </div> | ||||
| <div className='mx-0.5 truncate text-xs font-medium text-gray-700' title={outputVarNode?.title} style={{ | |||||
| <div className='mx-0.5 truncate text-xs font-medium text-text-secondary' title={outputVarNode?.title} style={{ | |||||
| maxWidth: maxNodeNameWidth, | maxWidth: maxNodeNameWidth, | ||||
| }}>{outputVarNode?.title}</div> | }}>{outputVarNode?.title}</div> | ||||
| <Line3 className='mr-0.5'></Line3> | <Line3 className='mr-0.5'></Line3> | ||||
| </div> | </div> | ||||
| )} | )} | ||||
| <div className='flex items-center text-primary-600'> | |||||
| <div className='flex items-center text-text-accent'> | |||||
| {!hasValue && <Variable02 className='h-3.5 w-3.5' />} | {!hasValue && <Variable02 className='h-3.5 w-3.5' />} | ||||
| {isEnv && <Env className='h-3.5 w-3.5 text-util-colors-violet-violet-600' />} | {isEnv && <Env className='h-3.5 w-3.5 text-util-colors-violet-violet-600' />} | ||||
| {isChatVar && <BubbleX className='h-3.5 w-3.5 text-util-colors-teal-teal-700' />} | {isChatVar && <BubbleX className='h-3.5 w-3.5 text-util-colors-teal-teal-700' />} | ||||
| <div className='system-xs-regular ml-0.5 truncate text-center capitalize text-text-tertiary' title={type} style={{ | <div className='system-xs-regular ml-0.5 truncate text-center capitalize text-text-tertiary' title={type} style={{ | ||||
| maxWidth: maxTypeWidth, | maxWidth: maxTypeWidth, | ||||
| }}>{type}</div> | }}>{type}</div> | ||||
| {!isValidVar && <RiErrorWarningFill className='ml-0.5 h-3 w-3 text-[#D92D20]' />} | |||||
| {!isValidVar && <RiErrorWarningFill className='ml-0.5 h-3 w-3 text-text-destructive' />} | |||||
| </> | </> | ||||
| ) | ) | ||||
| : <div className={`overflow-hidden ${readonly ? 'text-components-input-text-disabled' : 'text-components-input-text-placeholder'} system-sm-regular text-ellipsis`}>{placeholder ?? t('workflow.common.setVarValuePlaceholder')}</div>} | : <div className={`overflow-hidden ${readonly ? 'text-components-input-text-disabled' : 'text-components-input-text-placeholder'} system-sm-regular text-ellipsis`}>{placeholder ?? t('workflow.common.setVarValuePlaceholder')}</div>} | ||||
| </VarPickerWrap> | </VarPickerWrap> | ||||
| )} | )} | ||||
| {(hasValue && !readonly && !isInTable) && (<div | {(hasValue && !readonly && !isInTable) && (<div | ||||
| className='group invisible absolute right-1 top-[50%] h-5 translate-y-[-50%] cursor-pointer rounded-md p-1 hover:bg-black/5 group-hover/wrap:visible' | |||||
| className='group invisible absolute right-1 top-[50%] h-5 translate-y-[-50%] cursor-pointer rounded-md p-1 hover:bg-state-base-hover group-hover/wrap:visible' | |||||
| onClick={handleClearVar} | onClick={handleClearVar} | ||||
| > | > | ||||
| <RiCloseLine className='h-3.5 w-3.5 text-gray-500 group-hover:text-gray-800' /> | |||||
| <RiCloseLine className='h-3.5 w-3.5 text-text-tertiary group-hover:text-text-secondary' /> | |||||
| </div>)} | </div>)} | ||||
| {!hasValue && valueTypePlaceHolder && ( | {!hasValue && valueTypePlaceHolder && ( | ||||
| <Badge | <Badge |
| const { locale } = useContext(I18n) | const { locale } = useContext(I18n) | ||||
| // max-h-[300px] overflow-y-auto todo: use portal to handle long list | // max-h-[300px] overflow-y-auto todo: use portal to handle long list | ||||
| return ( | return ( | ||||
| <div className='space-y-1 rounded-lg border border-gray-200 bg-white p-1 shadow-lg' style={{ | |||||
| <div className='space-y-1 rounded-lg border border-components-panel-border bg-components-panel-bg p-1 shadow-lg' style={{ | |||||
| width: itemWidth || 228, | width: itemWidth || 228, | ||||
| }}> | }}> | ||||
| {((!vars || vars.length === 0) && popupFor) | {((!vars || vars.length === 0) && popupFor) |
| offset={4} | offset={4} | ||||
| > | > | ||||
| <PortalToFollowElemTrigger onClick={() => setOpen(!open)} className='w-[120px] cursor-pointer'> | <PortalToFollowElemTrigger onClick={() => setOpen(!open)} className='w-[120px] cursor-pointer'> | ||||
| <div className='flex h-8 items-center justify-between rounded-lg border-0 bg-gray-100 px-2.5 text-[13px] text-gray-900'> | |||||
| <div className='flex h-8 items-center justify-between rounded-lg border-0 bg-components-button-secondary-bg px-2.5 text-[13px] text-text-primary'> | |||||
| <div className='w-0 grow truncate capitalize' title={value}>{value}</div> | <div className='w-0 grow truncate capitalize' title={value}>{value}</div> | ||||
| <RiArrowDownSLine className='h-3.5 w-3.5 shrink-0 text-gray-700' /> | |||||
| <RiArrowDownSLine className='h-3.5 w-3.5 shrink-0 text-text-secondary' /> | |||||
| </div> | </div> | ||||
| </PortalToFollowElemTrigger> | </PortalToFollowElemTrigger> | ||||
| <PortalToFollowElemContent style={{ | <PortalToFollowElemContent style={{ | ||||
| zIndex: 100, | zIndex: 100, | ||||
| }}> | }}> | ||||
| <div className='w-[120px] rounded-lg bg-white p-1 shadow-sm'> | |||||
| <div className='w-[120px] rounded-lg bg-components-panel-bg p-1 shadow-sm'> | |||||
| {TYPES.map(type => ( | {TYPES.map(type => ( | ||||
| <div | <div | ||||
| key={type} | key={type} | ||||
| className='flex h-[30px] cursor-pointer items-center justify-between rounded-lg pl-3 pr-2 text-[13px] text-gray-900 hover:bg-gray-100' | |||||
| className='flex h-[30px] cursor-pointer items-center justify-between rounded-lg pl-3 pr-2 text-[13px] text-text-primary hover:bg-state-base-hover' | |||||
| onClick={handleChange(type)} | onClick={handleChange(type)} | ||||
| > | > | ||||
| <div className='w-0 grow truncate capitalize'>{type}</div> | <div className='w-0 grow truncate capitalize'>{type}</div> | ||||
| {type === value && <Check className='h-4 w-4 shrink-0 text-primary-600' />} | |||||
| {type === value && <Check className='h-4 w-4 shrink-0 text-text-accent' />} | |||||
| </div> | </div> | ||||
| ))} | ))} | ||||
| </div> | </div> |
| return '' | return '' | ||||
| if (isInNode) | if (isInNode) | ||||
| return 'fixed z-10 right-[9px] top-[166px] bottom-[8px] p-4 bg-white rounded-xl' | |||||
| return 'fixed z-10 right-[9px] top-[166px] bottom-[8px] p-4 bg-components-panel-bg rounded-xl' | |||||
| return 'absolute z-10 left-4 right-6 top-[52px] bottom-0 pb-4 bg-white' | |||||
| return 'absolute z-10 left-4 right-6 top-[52px] bottom-0 pb-4 bg-components-panel-bg' | |||||
| })() | })() | ||||
| const wrapStyle = isExpand | const wrapStyle = isExpand | ||||
| ? { | ? { |
| width: `${panelWidth}px`, | width: `${panelWidth}px`, | ||||
| }} | }} | ||||
| > | > | ||||
| <div className='sticky top-0 z-10 border-b-[0.5px] border-black/5 bg-components-panel-bg'> | |||||
| <div className='sticky top-0 z-10 border-b-[0.5px] border-divider-regular bg-components-panel-bg'> | |||||
| <div className='flex items-center px-4 pb-1 pt-4'> | <div className='flex items-center px-4 pb-1 pt-4'> | ||||
| <BlockIcon | <BlockIcon | ||||
| className='mr-1 shrink-0' | className='mr-1 shrink-0' | ||||
| value={data.title || ''} | value={data.title || ''} | ||||
| onBlur={handleTitleBlur} | onBlur={handleTitleBlur} | ||||
| /> | /> | ||||
| <div className='flex shrink-0 items-center text-gray-500'> | |||||
| <div className='flex shrink-0 items-center text-text-tertiary'> | |||||
| { | { | ||||
| canRunBySingle(data.type) && !nodesReadOnly && ( | canRunBySingle(data.type) && !nodesReadOnly && ( | ||||
| <Tooltip | <Tooltip | ||||
| popupClassName='mr-1' | popupClassName='mr-1' | ||||
| > | > | ||||
| <div | <div | ||||
| className='mr-1 flex h-6 w-6 cursor-pointer items-center justify-center rounded-md hover:bg-black/5' | |||||
| className='mr-1 flex h-6 w-6 cursor-pointer items-center justify-center rounded-md hover:bg-state-base-hover' | |||||
| onClick={() => { | onClick={() => { | ||||
| handleNodeDataUpdate({ id, data: { _isSingleRun: true } }) | handleNodeDataUpdate({ id, data: { _isSingleRun: true } }) | ||||
| handleSyncWorkflowDraft(true) | handleSyncWorkflowDraft(true) | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div> | <div> | ||||
| {cloneElement(children, { id, data })} | |||||
| {cloneElement(children as any, { id, data })} | |||||
| </div> | </div> | ||||
| <Split /> | <Split /> | ||||
| { | { | ||||
| } | } | ||||
| { | { | ||||
| !!availableNextBlocks.length && ( | !!availableNextBlocks.length && ( | ||||
| <div className='border-t-[0.5px] border-t-black/5 p-4'> | |||||
| <div className='border-t-[0.5px] border-divider-regular p-4'> | |||||
| <div className='system-sm-semibold-uppercase mb-1 flex items-center text-text-secondary'> | <div className='system-sm-semibold-uppercase mb-1 flex items-center text-text-secondary'> | ||||
| {t('workflow.panel.nextStep').toLocaleUpperCase()} | {t('workflow.panel.nextStep').toLocaleUpperCase()} | ||||
| </div> | </div> |
| isChatMode, | isChatMode, | ||||
| }) | }) | ||||
| return ( | return ( | ||||
| <div key={index} className='flex h-6 items-center justify-between space-x-1 rounded-md bg-gray-100 px-1 text-xs font-normal text-gray-700'> | |||||
| <div className='flex items-center text-xs font-medium text-gray-500'> | |||||
| <div key={index} className='flex h-6 items-center justify-between space-x-1 rounded-md bg-components-badge-white-to-dark px-1 text-xs font-normal text-text-secondary'> | |||||
| <div className='flex items-center text-xs font-medium text-text-tertiary'> | |||||
| {!isEnv && !isChatVar && ( | {!isEnv && !isChatVar && ( | ||||
| <> | <> | ||||
| <div className='p-[1px]'> | <div className='p-[1px]'> | ||||
| <VarBlockIcon | <VarBlockIcon | ||||
| className='!text-gray-900' | |||||
| className='!text-text-primary' | |||||
| type={node?.data.type || BlockEnum.Start} | type={node?.data.type || BlockEnum.Start} | ||||
| /> | /> | ||||
| </div> | </div> | ||||
| <Line3 className='mr-0.5'></Line3> | <Line3 className='mr-0.5'></Line3> | ||||
| </> | </> | ||||
| )} | )} | ||||
| <div className='flex items-center text-primary-600'> | |||||
| {!isEnv && !isChatVar && <Variable02 className='h-3.5 w-3.5 shrink-0 text-primary-500' />} | |||||
| <div className='flex items-center text-text-accent'> | |||||
| {!isEnv && !isChatVar && <Variable02 className='h-3.5 w-3.5 shrink-0 text-text-accent' />} | |||||
| {isEnv && <Env className='h-3.5 w-3.5 shrink-0 text-util-colors-violet-violet-600' />} | {isEnv && <Env className='h-3.5 w-3.5 shrink-0 text-util-colors-violet-violet-600' />} | ||||
| {isChatVar && <BubbleX className='h-3.5 w-3.5 text-util-colors-teal-teal-700' />} | {isChatVar && <BubbleX className='h-3.5 w-3.5 text-util-colors-teal-teal-700' />} | ||||
| <div className={cn('ml-0.5 max-w-[50px] truncate text-xs font-medium', (isEnv || isChatVar) && '!max-w-[70px] text-gray-900')}>{varName}</div> | |||||
| <div className={cn('ml-0.5 max-w-[50px] truncate text-xs font-medium', (isEnv || isChatVar) && '!max-w-[70px] text-text-primary')}>{varName}</div> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div className='text-xs font-normal text-gray-700'> | |||||
| <div className='ml-0.5 max-w-[42px] truncate text-xs font-normal capitalize text-gray-500' title={varType}>{varType}</div> | |||||
| <div className='text-xs font-normal text-text-secondary'> | |||||
| <div className='ml-0.5 max-w-[42px] truncate text-xs font-normal capitalize text-text-tertiary' title={varType}>{varType}</div> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| ) | ) |
| onChange={onMethodChange} | onChange={onMethodChange} | ||||
| options={MethodOptions} | options={MethodOptions} | ||||
| trigger={ | trigger={ | ||||
| <div className={cn(readonly && 'cursor-pointer', 'flex h-8 shrink-0 items-center rounded-lg border-black/5 bg-gray-100 px-2.5')} > | |||||
| <div className='w-12 pl-0.5 text-xs font-medium uppercase leading-[18px] text-gray-900'>{method}</div> | |||||
| {!readonly && <RiArrowDownSLine className='ml-1 h-3.5 w-3.5 text-gray-700' />} | |||||
| <div className={cn(readonly && 'cursor-pointer', 'flex h-8 shrink-0 items-center rounded-lg border border-components-button-secondary-border bg-components-button-secondary-bg px-2.5')} > | |||||
| <div className='w-12 pl-0.5 text-xs font-medium uppercase leading-[18px] text-text-primary'>{method}</div> | |||||
| {!readonly && <RiArrowDownSLine className='ml-1 h-3.5 w-3.5 text-text-secondary' />} | |||||
| </div> | </div> | ||||
| } | } | ||||
| popupClassName='top-[34px] w-[108px]' | popupClassName='top-[34px] w-[108px]' | ||||
| <Input | <Input | ||||
| instanceId='http-api-url' | instanceId='http-api-url' | ||||
| className={cn(isFocus ? 'border-gray-300 bg-gray-50 shadow-xs' : 'border-gray-100 bg-gray-100', 'w-0 grow rounded-lg border px-3 py-[6px]')} | |||||
| className={cn(isFocus ? 'border-components-input-border-active bg-components-input-bg-active shadow-xs' : 'border-components-input-border-hover bg-components-input-bg-normal', 'w-0 grow rounded-lg border px-3 py-[6px]')} | |||||
| value={url} | value={url} | ||||
| onChange={onUrlChange} | onChange={onUrlChange} | ||||
| readOnly={readonly} | readOnly={readonly} |
| const Field = ({ title, isRequired, children }: { title: string; isRequired?: boolean; children: React.JSX.Element }) => { | const Field = ({ title, isRequired, children }: { title: string; isRequired?: boolean; children: React.JSX.Element }) => { | ||||
| return ( | return ( | ||||
| <div> | <div> | ||||
| <div className='text-[13px] font-medium leading-8 text-gray-700'> | |||||
| <div className='text-[13px] font-medium leading-8 text-text-secondary'> | |||||
| {title} | {title} | ||||
| {isRequired && <span className='ml-0.5 text-[#D92D20]'>*</span>} | |||||
| {isRequired && <span className='ml-0.5 text-text-destructive'>*</span>} | |||||
| </div> | </div> | ||||
| <div>{children}</div> | <div>{children}</div> | ||||
| </div> | </div> | ||||
| <div className='flex'> | <div className='flex'> | ||||
| <Input | <Input | ||||
| instanceId='http-api-key' | instanceId='http-api-key' | ||||
| className={cn(isFocus ? 'border-gray-300 bg-gray-50 shadow-xs' : 'border-gray-100 bg-gray-100', 'w-0 grow rounded-lg border px-3 py-[6px]')} | |||||
| className={cn(isFocus ? 'border-components-input-border-active bg-components-input-bg-active shadow-xs' : 'border-components-input-border-hover bg-components-input-bg-normal', 'w-0 grow rounded-lg border px-3 py-[6px]')} | |||||
| value={tempPayload.config?.api_key || ''} | value={tempPayload.config?.api_key || ''} | ||||
| onChange={handleAPIKeyChange} | onChange={handleAPIKeyChange} | ||||
| nodesOutputVars={availableVars} | nodesOutputVars={availableVars} |
| return ( | return ( | ||||
| <div | <div | ||||
| className={cn( | className={cn( | ||||
| isSelected ? 'border-[2px] border-primary-400 bg-white shadow-xs' : 'border border-gray-100 bg-gray-25', | |||||
| 'flex h-8 w-0 grow cursor-pointer items-center justify-center rounded-lg text-[13px] font-normal text-gray-900') | |||||
| } | |||||
| 'system-sm-regular flex h-8 grow cursor-default items-center rounded-md border border-components-option-card-option-border bg-components-option-card-option-bg px-2 text-text-secondary', | |||||
| !isSelected && 'cursor-pointer hover:border-components-option-card-option-border-hover hover:bg-components-option-card-option-bg-hover hover:shadow-xs', | |||||
| isSelected && 'system-sm-medium border-[1.5px] border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg shadow-xs', | |||||
| )} | |||||
| onClick={onClick} | onClick={onClick} | ||||
| > | > | ||||
| {title} | {title} |
| import { BodyType, type HttpNodeType, Method } from '../types' | import { BodyType, type HttpNodeType, Method } from '../types' | ||||
| import Modal from '@/app/components/base/modal' | import Modal from '@/app/components/base/modal' | ||||
| import Button from '@/app/components/base/button' | import Button from '@/app/components/base/button' | ||||
| import Textarea from '@/app/components/base/textarea' | |||||
| import Toast from '@/app/components/base/toast' | import Toast from '@/app/components/base/toast' | ||||
| import { useNodesInteractions } from '@/app/components/workflow/hooks' | import { useNodesInteractions } from '@/app/components/workflow/hooks' | ||||
| className='!w-[400px] !max-w-[400px] !p-4' | className='!w-[400px] !max-w-[400px] !p-4' | ||||
| > | > | ||||
| <div> | <div> | ||||
| <textarea | |||||
| <Textarea | |||||
| value={inputString} | value={inputString} | ||||
| className='my-3 h-40 w-full grow rounded-lg border-0 bg-gray-100 p-3 text-sm text-gray-900 focus:outline-none focus:ring-1 focus:ring-inset focus:ring-gray-200' | |||||
| className='my-3 h-40 w-full grow' | |||||
| onChange={e => setInputString(e.target.value)} | onChange={e => setInputString(e.target.value)} | ||||
| placeholder={t('workflow.nodes.http.curl.placeholder')!} | placeholder={t('workflow.nodes.http.curl.placeholder')!} | ||||
| /> | /> |
| onChange={handleTypeChange} | onChange={handleTypeChange} | ||||
| disabled={readonly} | disabled={readonly} | ||||
| /> | /> | ||||
| <div className='text-[13px] font-normal leading-[18px] text-gray-700'>{bodyTextMap[t]}</div> | |||||
| <div className='text-[13px] font-normal leading-[18px] text-text-secondary'>{bodyTextMap[t]}</div> | |||||
| </label> | </label> | ||||
| ))} | ))} | ||||
| </div> | </div> |
| }, [onRemove]) | }, [onRemove]) | ||||
| return ( | return ( | ||||
| <div className={cn(className, 'hover:cursor-text hover:bg-gray-50', 'relative flex h-full')}> | |||||
| <div className={cn(className, 'hover:cursor-text hover:bg-state-base-hover', 'relative flex h-full')}> | |||||
| {(!readOnly) | {(!readOnly) | ||||
| ? ( | ? ( | ||||
| <Input | <Input | ||||
| instanceId={instanceId} | instanceId={instanceId} | ||||
| className={cn(isFocus ? 'bg-gray-100' : 'bg-width', 'w-0 grow px-3 py-1')} | |||||
| className={cn(isFocus ? 'bg-components-input-bg-active' : 'bg-width', 'w-0 grow px-3 py-1')} | |||||
| value={value} | value={value} | ||||
| onChange={onChange} | onChange={onChange} | ||||
| readOnly={readOnly} | readOnly={readOnly} | ||||
| : <div | : <div | ||||
| className="h-[18px] w-full pl-0.5 leading-[18px]" | className="h-[18px] w-full pl-0.5 leading-[18px]" | ||||
| > | > | ||||
| {!hasValue && <div className='text-xs font-normal text-gray-300'>{placeholder}</div>} | |||||
| {!hasValue && <div className='text-xs font-normal text-text-quaternary'>{placeholder}</div>} | |||||
| {hasValue && ( | {hasValue && ( | ||||
| <Input | <Input | ||||
| instanceId={instanceId} | instanceId={instanceId} | ||||
| className={cn(isFocus ? 'border-gray-300 bg-gray-50 shadow-xs' : 'border-gray-100 bg-gray-100', 'w-0 grow rounded-lg border px-3 py-[6px]')} | |||||
| className={cn(isFocus ? 'border-components-input-border-active bg-components-input-bg-active shadow-xs' : 'border-components-input-border-hover bg-components-input-bg-normal', 'w-0 grow rounded-lg border px-3 py-[6px]')} | |||||
| value={value} | value={value} | ||||
| onChange={onChange} | onChange={onChange} | ||||
| readOnly={readOnly} | readOnly={readOnly} |
| return ( | return ( | ||||
| // group class name is for hover row show remove button | // group class name is for hover row show remove button | ||||
| <div className={cn(className, 'h-min-7 group flex border-t border-gray-200')}> | |||||
| <div className={cn(className, 'h-min-7 group flex border-t border-divider-regular')}> | |||||
| <div className={cn('shrink-0 border-r border-divider-regular', isSupportFile ? 'w-[140px]' : 'w-1/2')}> | <div className={cn('shrink-0 border-r border-divider-regular', isSupportFile ? 'w-[140px]' : 'w-1/2')}> | ||||
| {!keyNotSupportVar | {!keyNotSupportVar | ||||
| ? ( | ? ( | ||||
| ) | ) | ||||
| : ( | : ( | ||||
| <input | <input | ||||
| className='system-sm-regular focus:bg-gray-100! appearance-none rounded-none border-none bg-white outline-none hover:bg-gray-50 focus:ring-0' | |||||
| className='system-sm-regular focus:bg-gray-100! appearance-none rounded-none border-none bg-transparent outline-none hover:bg-components-input-bg-hover focus:ring-0' | |||||
| value={payload.key} | value={payload.key} | ||||
| onChange={e => handleChange('key')(e.target.value)} | onChange={e => handleChange('key')(e.target.value)} | ||||
| /> | /> | ||||
| { name: 'file', value: 'file' }, | { name: 'file', value: 'file' }, | ||||
| ]} | ]} | ||||
| readonly={readonly} | readonly={readonly} | ||||
| triggerClassName='rounded-none h-7' | |||||
| triggerClassName='rounded-none h-7 text-text-primary' | |||||
| triggerClassNameFn={isOpen => isOpen ? 'bg-state-base-hover' : 'bg-transparent'} | triggerClassNameFn={isOpen => isOpen ? 'bg-state-base-hover' : 'bg-transparent'} | ||||
| popupClassName='w-[80px] h-7' | popupClassName='w-[80px] h-7' | ||||
| /> | /> |
| return ( | return ( | ||||
| <div className="space-y-1"> | <div className="space-y-1"> | ||||
| <div className="flex h-[18px] items-center space-x-2"> | <div className="flex h-[18px] items-center space-x-2"> | ||||
| <span className="text-[13px] font-medium text-gray-900">{title}</span> | |||||
| <span className="text-xs font-normal text-gray-500">{description}</span> | |||||
| <span className="text-[13px] font-medium text-text-primary">{title}</span> | |||||
| <span className="text-xs font-normal text-text-tertiary">{description}</span> | |||||
| </div> | </div> | ||||
| <Input | <Input | ||||
| type='number' | type='number' |
| return ( | return ( | ||||
| <div className='mb-1 px-3 py-1'> | <div className='mb-1 px-3 py-1'> | ||||
| <div className='flex items-start rounded-md bg-gray-100 p-1'> | |||||
| <div className='flex h-4 shrink-0 items-center rounded bg-gray-25 px-1 text-xs font-semibold uppercase text-gray-700'>{method}</div> | |||||
| <div className='flex items-start rounded-md bg-workflow-block-parma-bg p-1'> | |||||
| <div className='flex h-4 shrink-0 items-center rounded bg-components-badge-white-to-dark px-1 text-xs font-semibold uppercase text-text-secondary'>{method}</div> | |||||
| <div className='pl-1 pt-1'> | <div className='pl-1 pt-1'> | ||||
| <ReadonlyInputWithSelectVar | <ReadonlyInputWithSelectVar | ||||
| className='text-text-secondary' | |||||
| value={url} | value={url} | ||||
| nodeId={id} | nodeId={id} | ||||
| /> | /> |
| <div className='flex'> | <div className='flex'> | ||||
| <div | <div | ||||
| onClick={showAuthorization} | onClick={showAuthorization} | ||||
| className={cn(!readOnly && 'cursor-pointer hover:bg-gray-50', 'flex h-6 items-center space-x-1 rounded-md px-2 ')} | |||||
| className={cn(!readOnly && 'cursor-pointer hover:bg-state-base-hover', 'flex h-6 items-center space-x-1 rounded-md px-2 ')} | |||||
| > | > | ||||
| {!readOnly && <Settings01 className='h-3 w-3 text-gray-500' />} | |||||
| <div className='text-xs font-medium text-gray-500'> | |||||
| {!readOnly && <Settings01 className='h-3 w-3 text-text-tertiary' />} | |||||
| <div className='text-xs font-medium text-text-tertiary'> | |||||
| {t(`${i18nPrefix}.authorization.authorization`)} | {t(`${i18nPrefix}.authorization.authorization`)} | ||||
| <span className='ml-1 text-gray-700'>{t(`${i18nPrefix}.authorization.${inputs.authorization.type}`)}</span> | |||||
| <span className='ml-1 text-text-secondary'>{t(`${i18nPrefix}.authorization.${inputs.authorization.type}`)}</span> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div | <div | ||||
| onClick={showCurlPanel} | onClick={showCurlPanel} | ||||
| className={cn(!readOnly && 'cursor-pointer hover:bg-gray-50', 'flex h-6 items-center space-x-1 rounded-md px-2 ')} | |||||
| className={cn(!readOnly && 'cursor-pointer hover:bg-state-base-hover', 'flex h-6 items-center space-x-1 rounded-md px-2 ')} | |||||
| > | > | ||||
| {!readOnly && <FileArrow01 className='h-3 w-3 text-gray-500' />} | |||||
| <div className='text-xs font-medium text-gray-500'> | |||||
| {!readOnly && <FileArrow01 className='h-3 w-3 text-text-tertiary' />} | |||||
| <div className='text-xs font-medium text-text-tertiary'> | |||||
| {t(`${i18nPrefix}.curl.title`)} | {t(`${i18nPrefix}.curl.title`)} | ||||
| </div> | </div> | ||||
| </div> | </div> |
| const { t } = useTranslation() | const { t } = useTranslation() | ||||
| return ( | return ( | ||||
| <div className='nodrag relative left-[17px] top-[21px] z-[11] flex h-11 w-11 items-center justify-center rounded-2xl border border-workflow-block-border bg-white'> | |||||
| <div className='nodrag relative left-[17px] top-[21px] z-[11] flex h-11 w-11 items-center justify-center rounded-2xl border border-workflow-block-border bg-workflow-block-bg'> | |||||
| <Tooltip popupContent={t('workflow.blocks.iteration-start')} asChild={false}> | <Tooltip popupContent={t('workflow.blocks.iteration-start')} asChild={false}> | ||||
| <div className='flex h-6 w-6 items-center justify-center rounded-full border-[0.5px] border-components-panel-border-subtle bg-util-colors-blue-brand-blue-brand-500'> | <div className='flex h-6 w-6 items-center justify-center rounded-full border-[0.5px] border-components-panel-border-subtle bg-util-colors-blue-brand-blue-brand-500'> | ||||
| <RiHome5Fill className='h-3 w-3 text-text-primary-on-surface' /> | <RiHome5Fill className='h-3 w-3 text-text-primary-on-surface' /> |
| } | } | ||||
| <ActionButton | <ActionButton | ||||
| onClick={handleRemove} | onClick={handleRemove} | ||||
| state={ActionButtonState.Destructive} | |||||
| state={isDeleteHovered ? ActionButtonState.Destructive : ActionButtonState.Default} | |||||
| onMouseEnter={() => setIsDeleteHovered(true)} | onMouseEnter={() => setIsDeleteHovered(true)} | ||||
| onMouseLeave={() => setIsDeleteHovered(false)} | onMouseLeave={() => setIsDeleteHovered(false)} | ||||
| > | > |
| ) | ) | ||||
| }) | }) | ||||
| : ( | : ( | ||||
| <div className='cursor-default select-none rounded-lg bg-gray-50 p-3 text-center text-xs text-gray-500'> | |||||
| <div className='cursor-default select-none rounded-lg bg-background-section p-3 text-center text-xs text-text-tertiary'> | |||||
| {t('appDebug.datasetConfig.knowledgeTip')} | {t('appDebug.datasetConfig.knowledgeTip')} | ||||
| </div> | </div> | ||||
| ) | ) |
| </Button> | </Button> | ||||
| </PortalToFollowElemTrigger> | </PortalToFollowElemTrigger> | ||||
| <PortalToFollowElemContent style={{ zIndex: 1001 }}> | <PortalToFollowElemContent style={{ zIndex: 1001 }}> | ||||
| <div className='w-[404px] rounded-2xl border border-gray-200 bg-white px-4 pb-4 pt-3 shadow-xl'> | |||||
| <div className='w-[404px] rounded-2xl border border-components-panel-border bg-components-panel-bg px-4 pb-4 pt-3 shadow-xl'> | |||||
| <ConfigRetrievalContent | <ConfigRetrievalContent | ||||
| datasetConfigs={ | datasetConfigs={ | ||||
| { | { |
| onOpenFromPropsChange={handleOpenFromPropsChange} | onOpenFromPropsChange={handleOpenFromPropsChange} | ||||
| selectedDatasets={selectedDatasets} | selectedDatasets={selectedDatasets} | ||||
| /> | /> | ||||
| {!readOnly && (<div className='h-3 w-px bg-gray-200'></div>)} | |||||
| {!readOnly && (<div className='h-3 w-px bg-divider-regular'></div>)} | |||||
| {!readOnly && ( | {!readOnly && ( | ||||
| <AddKnowledge | <AddKnowledge | ||||
| selectedIds={inputs.dataset_ids} | selectedIds={inputs.dataset_ids} |
| <div className='flex items-start space-x-1'> | <div className='flex items-start space-x-1'> | ||||
| <Input | <Input | ||||
| instanceId='http-extract-number' | instanceId='http-extract-number' | ||||
| className={cn(isFocus ? 'border-gray-300 bg-gray-50 shadow-xs' : 'border-gray-100 bg-gray-100', 'w-0 grow rounded-lg border px-3 py-[6px]')} | |||||
| className={cn(isFocus ? 'border-components-input-border-active bg-components-input-bg-active shadow-xs' : 'border-components-input-border-hover bg-components-input-bg-normal', 'w-0 grow rounded-lg border px-3 py-[6px]')} | |||||
| value={value} | value={value} | ||||
| onChange={onChange} | onChange={onChange} | ||||
| readOnly={readOnly} | readOnly={readOnly} |
| title={ | title={ | ||||
| <div className='relative left-1 flex items-center'> | <div className='relative left-1 flex items-center'> | ||||
| {payload.role === PromptRole.system | {payload.role === PromptRole.system | ||||
| ? (<div className='relative left-[-4px] text-xs font-semibold uppercase text-gray-700'> | |||||
| ? (<div className='relative left-[-4px] text-xs font-semibold uppercase text-text-secondary'> | |||||
| SYSTEM | SYSTEM | ||||
| </div>) | </div>) | ||||
| : ( | : ( | ||||
| allOptions={roleOptions} | allOptions={roleOptions} | ||||
| options={canNotChooseSystemRole ? roleOptionsWithoutSystemRole : roleOptions} | options={canNotChooseSystemRole ? roleOptionsWithoutSystemRole : roleOptions} | ||||
| onChange={handleChatModeMessageRoleChange} | onChange={handleChatModeMessageRoleChange} | ||||
| triggerClassName='text-xs font-semibold text-gray-700 uppercase' | |||||
| itemClassName='text-[13px] font-medium text-gray-700' | |||||
| triggerClassName='text-xs font-semibold text-text-secondary uppercase' | |||||
| itemClassName='text-[13px] font-medium text-text-secondary' | |||||
| /> | /> | ||||
| )} | )} | ||||
| })() | })() | ||||
| return ( | return ( | ||||
| <div key={item.id || index} className='group relative'> | <div key={item.id || index} className='group relative'> | ||||
| {canDrag && <DragHandle className='absolute left-[-14px] top-2 hidden h-3.5 w-3.5 text-gray-400 group-hover:block' />} | |||||
| {canDrag && <DragHandle className='absolute left-[-14px] top-2 hidden h-3.5 w-3.5 text-text-quaternary group-hover:block' />} | |||||
| <ConfigPromptItem | <ConfigPromptItem | ||||
| className={cn(canDrag && 'handle')} | className={cn(canDrag && 'handle')} | ||||
| headerClassName={cn(canDrag && 'cursor-grab')} | headerClassName={cn(canDrag && 'cursor-grab')} |
| }, [onChange]) | }, [onChange]) | ||||
| return ( | return ( | ||||
| <div className='flex items-center justify-between'> | <div className='flex items-center justify-between'> | ||||
| <div className='mr-2 text-xs font-medium uppercase text-gray-500'>{t(`${i18nPrefix}.resolution.name`)}</div> | |||||
| <div className='mr-2 text-xs font-medium uppercase text-text-secondary'>{t(`${i18nPrefix}.resolution.name`)}</div> | |||||
| <div className='flex items-center space-x-1'> | <div className='flex items-center space-x-1'> | ||||
| <OptionCard | <OptionCard | ||||
| title={t(`${i18nPrefix}.resolution.high`)} | title={t(`${i18nPrefix}.resolution.high`)} |
| {/* Memory put place examples. */} | {/* Memory put place examples. */} | ||||
| {isChatMode && isChatModel && !!inputs.memory && ( | {isChatMode && isChatModel && !!inputs.memory && ( | ||||
| <div className='mt-4'> | <div className='mt-4'> | ||||
| <div className='flex h-8 items-center justify-between rounded-lg bg-gray-100 pl-3 pr-2'> | |||||
| <div className='flex h-8 items-center justify-between rounded-lg bg-components-input-bg-normal pl-3 pr-2'> | |||||
| <div className='flex items-center space-x-1'> | <div className='flex items-center space-x-1'> | ||||
| <div className='text-xs font-semibold uppercase text-gray-700'>{t('workflow.nodes.common.memories.title')}</div> | |||||
| <div className='text-xs font-semibold uppercase text-text-secondary'>{t('workflow.nodes.common.memories.title')}</div> | |||||
| <Tooltip | <Tooltip | ||||
| popupContent={t('workflow.nodes.common.memories.tip')} | popupContent={t('workflow.nodes.common.memories.tip')} | ||||
| triggerClassName='w-4 h-4' | triggerClassName='w-4 h-4' | ||||
| /> | /> | ||||
| </div> | </div> | ||||
| <div className='flex h-[18px] items-center rounded-[5px] border border-black/8 px-1 text-xs font-semibold uppercase text-gray-500'>{t('workflow.nodes.common.memories.builtIn')}</div> | |||||
| <div className='flex h-[18px] items-center rounded-[5px] border border-divider-deep bg-components-badge-bg-dimm px-1 text-xs font-semibold uppercase text-text-tertiary'>{t('workflow.nodes.common.memories.builtIn')}</div> | |||||
| </div> | </div> | ||||
| {/* Readonly User Query */} | {/* Readonly User Query */} | ||||
| <div className='mt-4'> | <div className='mt-4'> | ||||
| <Editor | <Editor | ||||
| title={<div className='flex items-center space-x-1'> | title={<div className='flex items-center space-x-1'> | ||||
| <div className='text-xs font-semibold uppercase text-gray-700'>user</div> | |||||
| <div className='text-xs font-semibold uppercase text-text-secondary'>user</div> | |||||
| <Tooltip | <Tooltip | ||||
| popupContent={ | popupContent={ | ||||
| <div className='max-w-[180px]'>{t('workflow.nodes.llm.roleDescription.user')}</div> | <div className='max-w-[180px]'>{t('workflow.nodes.llm.roleDescription.user')}</div> |
| const { t } = useTranslation() | const { t } = useTranslation() | ||||
| return ( | return ( | ||||
| <div className='nodrag group mt-1 flex h-11 w-11 items-center justify-center rounded-2xl border border-workflow-block-border bg-white'> | |||||
| <div className='nodrag group mt-1 flex h-11 w-11 items-center justify-center rounded-2xl border border-workflow-block-border bg-workflow-block-bg'> | |||||
| <Tooltip popupContent={t('workflow.blocks.loop-start')} asChild={false}> | <Tooltip popupContent={t('workflow.blocks.loop-start')} asChild={false}> | ||||
| <div className='flex h-6 w-6 items-center justify-center rounded-full border-[0.5px] border-components-panel-border-subtle bg-util-colors-blue-brand-blue-brand-500'> | <div className='flex h-6 w-6 items-center justify-center rounded-full border-[0.5px] border-components-panel-border-subtle bg-util-colors-blue-brand-blue-brand-500'> | ||||
| <RiHome5Fill className='h-3 w-3 text-text-primary-on-surface' /> | <RiHome5Fill className='h-3 w-3 text-text-primary-on-surface' /> | ||||
| const { t } = useTranslation() | const { t } = useTranslation() | ||||
| return ( | return ( | ||||
| <div className='nodrag relative left-[17px] top-[21px] z-[11] flex h-11 w-11 items-center justify-center rounded-2xl border border-workflow-block-border bg-white'> | |||||
| <div className='nodrag relative left-[17px] top-[21px] z-[11] flex h-11 w-11 items-center justify-center rounded-2xl border border-workflow-block-border bg-workflow-block-bg'> | |||||
| <Tooltip popupContent={t('workflow.blocks.loop-start')} asChild={false}> | <Tooltip popupContent={t('workflow.blocks.loop-start')} asChild={false}> | ||||
| <div className='flex h-6 w-6 items-center justify-center rounded-full border-[0.5px] border-components-panel-border-subtle bg-util-colors-blue-brand-blue-brand-500'> | <div className='flex h-6 w-6 items-center justify-center rounded-full border-[0.5px] border-components-panel-border-subtle bg-util-colors-blue-brand-blue-brand-500'> | ||||
| <RiHome5Fill className='h-3 w-3 text-text-primary-on-surface' /> | <RiHome5Fill className='h-3 w-3 text-text-primary-on-surface' /> |
| const renderTriggerElement = useCallback((open: boolean) => { | const renderTriggerElement = useCallback((open: boolean) => { | ||||
| return ( | return ( | ||||
| <div className={cn( | <div className={cn( | ||||
| 'relative inline-flex h-8 cursor-pointer items-center rounded-lg border-[0.5px] border-gray-50 bg-white px-3 text-[13px] font-medium text-gray-700 shadow-xs hover:bg-gray-200', | |||||
| `${nodesReadOnly && '!cursor-not-allowed opacity-50'}`, | |||||
| open && '!bg-gray-50', | |||||
| 'system-sm-medium relative inline-flex h-8 cursor-pointer items-center rounded-lg border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg px-3 text-components-button-secondary-text shadow-xs backdrop-blur-[5px] hover:bg-components-button-secondary-bg-hover', | |||||
| `${nodesReadOnly && '!cursor-not-allowed bg-components-button-secondary-bg-disabled'}`, | |||||
| open && 'bg-components-button-secondary-bg-hover', | |||||
| )}> | )}> | ||||
| <RiAddLine className='mr-1 h-4 w-4' /> | <RiAddLine className='mr-1 h-4 w-4' /> | ||||
| {t('workflow.common.addBlock')} | {t('workflow.common.addBlock')} |
| return ( | return ( | ||||
| <div className={cn( | <div className={cn( | ||||
| 'relative h-full min-h-[90px] w-full min-w-[240px] rounded-2xl bg-[#F0F2F7]/90', | |||||
| 'relative h-full min-h-[90px] w-full min-w-[240px] rounded-2xl bg-workflow-canvas-workflow-bg', | |||||
| )}> | )}> | ||||
| <Background | <Background | ||||
| id={`loop-background-${id}`} | id={`loop-background-${id}`} | ||||
| className='!z-0 rounded-2xl' | className='!z-0 rounded-2xl' | ||||
| gap={[14 / zoom, 14 / zoom]} | gap={[14 / zoom, 14 / zoom]} | ||||
| size={2 / zoom} | size={2 / zoom} | ||||
| color='#E4E5E7' | |||||
| color='var(--color-workflow-canvas-workflow-dot-color)' | |||||
| /> | /> | ||||
| { | { | ||||
| data._isCandidate && ( | data._isCandidate && ( |
| return ( | return ( | ||||
| <div> | <div> | ||||
| <div className={cn( | <div className={cn( | ||||
| 'flex h-6 cursor-pointer items-center rounded-md px-2 text-xs font-medium text-gray-500 hover:bg-gray-100', | |||||
| open && 'bg-gray-100', | |||||
| 'flex h-6 cursor-pointer items-center rounded-md px-2 text-xs font-medium text-text-tertiary hover:bg-state-base-hover', | |||||
| open && 'bg-state-base-hover', | |||||
| )}> | )}> | ||||
| {t(`${i18nPrefix}.importFromTool`)} | {t(`${i18nPrefix}.importFromTool`)} | ||||
| </div> | </div> |
| const { t } = useTranslation() | const { t } = useTranslation() | ||||
| return ( | return ( | ||||
| <div className='group relative rounded-lg border-[0.5px] border-gray-200 bg-white px-2.5 py-2 hover:shadow-xs'> | |||||
| <div className='group relative rounded-lg bg-components-input-bg-normal px-2.5 py-2 hover:shadow-xs'> | |||||
| <div className='flex justify-between'> | <div className='flex justify-between'> | ||||
| <div className='flex items-center'> | <div className='flex items-center'> | ||||
| <Variable02 className='h-3.5 w-3.5 text-primary-500' /> | |||||
| <div className='ml-1 text-[13px] font-medium text-gray-900'>{payload.name}</div> | |||||
| <div className='ml-2 text-xs font-normal capitalize text-gray-500'>{payload.type}</div> | |||||
| <Variable02 className='h-3.5 w-3.5 text-text-accent-secondary' /> | |||||
| <div className='ml-1 text-[13px] font-medium text-text-primary'>{payload.name}</div> | |||||
| <div className='ml-2 text-xs font-normal capitalize text-text-tertiary'>{payload.type}</div> | |||||
| </div> | </div> | ||||
| {payload.required && ( | {payload.required && ( | ||||
| <div className='text-xs font-normal uppercase leading-4 text-gray-500'>{t(`${i18nPrefix}.addExtractParameterContent.required`)}</div> | |||||
| <div className='text-xs font-normal uppercase leading-4 text-text-tertiary'>{t(`${i18nPrefix}.addExtractParameterContent.required`)}</div> | |||||
| )} | )} | ||||
| </div> | </div> | ||||
| <div className='mt-0.5 text-xs font-normal leading-[18px] text-gray-500'>{payload.description}</div> | |||||
| <div className='mt-0.5 text-xs font-normal leading-[18px] text-text-tertiary'>{payload.description}</div> | |||||
| <div | <div | ||||
| className='absolute right-1 top-0 hidden h-full w-[119px] items-center justify-end space-x-1 rounded-lg group-hover:flex' | |||||
| style={{ | |||||
| background: 'linear-gradient(270deg, #FFF 49.99%, rgba(255, 255, 255, 0.00) 98.1%)', | |||||
| }} | |||||
| className='absolute right-0 top-0 hidden h-full w-[119px] items-center justify-end space-x-1 rounded-lg bg-gradient-to-l from-components-panel-on-panel-item-bg to-background-gradient-mask-transparent pr-1 group-hover:flex' | |||||
| > | > | ||||
| <div | <div | ||||
| className='cursor-pointer rounded-md p-1 hover:bg-black/5' | |||||
| className='cursor-pointer rounded-md p-1 hover:bg-state-base-hover' | |||||
| onClick={onEdit} | onClick={onEdit} | ||||
| > | > | ||||
| <RiEditLine className='h-4 w-4 text-gray-500' /> | |||||
| <RiEditLine className='h-4 w-4 text-text-tertiary' /> | |||||
| </div> | </div> | ||||
| <div | <div | ||||
| className='cursor-pointer rounded-md p-1 hover:bg-black/5' | |||||
| className='group shrink-0 cursor-pointer rounded-md p-1 hover:!bg-state-destructive-hover' | |||||
| onClick={onDelete} | onClick={onDelete} | ||||
| > | > | ||||
| <RiDeleteBinLine className='h-4 w-4 text-gray-500' /> | |||||
| <RiDeleteBinLine className='h-4 w-4 text-text-tertiary group-hover:text-text-destructive' /> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> |
| <Select | <Select | ||||
| defaultValue={param.type} | defaultValue={param.type} | ||||
| allowSearch={false} | allowSearch={false} | ||||
| bgClassName='bg-gray-100' | |||||
| // bgClassName='bg-gray-100' | |||||
| onSelect={v => handleParamChange('type')(v.value)} | onSelect={v => handleParamChange('type')(v.value)} | ||||
| optionClassName='capitalize' | optionClassName='capitalize' | ||||
| items={ | items={ | ||||
| </Field> | </Field> | ||||
| <Field title={t(`${i18nPrefix}.addExtractParameterContent.required`)}> | <Field title={t(`${i18nPrefix}.addExtractParameterContent.required`)}> | ||||
| <> | <> | ||||
| <div className='mb-1.5 text-xs font-normal leading-[18px] text-gray-500'>{t(`${i18nPrefix}.addExtractParameterContent.requiredContent`)}</div> | |||||
| <div className='mb-1.5 text-xs font-normal leading-[18px] text-text-tertiary'>{t(`${i18nPrefix}.addExtractParameterContent.requiredContent`)}</div> | |||||
| <Switch size='l' defaultValue={param.required} onChange={handleParamChange('required')} /> | <Switch size='l' defaultValue={param.required} onChange={handleParamChange('required')} /> | ||||
| </> | </> | ||||
| </Field> | </Field> |
| {!readOnly && ( | {!readOnly && ( | ||||
| <ImportFromTool onImport={handleImportFromTool} /> | <ImportFromTool onImport={handleImportFromTool} /> | ||||
| )} | )} | ||||
| {!readOnly && (<div className='h-3 w-px bg-gray-200'></div>)} | |||||
| {!readOnly && (<div className='h-3 w-px bg-divider-regular'></div>)} | |||||
| <AddExtractParameter type='add' onSave={addExtractParameter} /> | <AddExtractParameter type='add' onSave={addExtractParameter} /> | ||||
| </div> | </div> | ||||
| ) | ) |
| hideEditVarModal() | hideEditVarModal() | ||||
| }, [onChange, hideEditVarModal]) | }, [onChange, hideEditVarModal]) | ||||
| return ( | return ( | ||||
| <div ref={ref} className='flex h-8 cursor-pointer items-center justify-between rounded-lg border border-gray-200 bg-white px-2.5 shadow-xs hover:shadow-md'> | |||||
| <div ref={ref} className='flex h-8 cursor-pointer items-center justify-between rounded-lg border border-components-panel-border-subtle bg-components-panel-on-panel-item-bg px-2.5 shadow-xs hover:shadow-md'> | |||||
| <div className='flex w-0 grow items-center space-x-1'> | <div className='flex w-0 grow items-center space-x-1'> | ||||
| <Variable02 className='h-3.5 w-3.5 text-primary-500' /> | |||||
| <div title={payload.variable} className='max-w-[130px] shrink-0 truncate text-[13px] font-medium text-gray-700'>{payload.variable}</div> | |||||
| {payload.label && (<><div className='shrink-0 text-xs font-medium text-gray-400'>·</div> | |||||
| <div title={payload.label as string} className='max-w-[130px] truncate text-[13px] font-medium text-gray-500'>{payload.label as string}</div> | |||||
| <Variable02 className='h-3.5 w-3.5 text-text-accent' /> | |||||
| <div title={payload.variable} className='max-w-[130px] shrink-0 truncate text-[13px] font-medium text-text-secondary'>{payload.variable}</div> | |||||
| {payload.label && (<><div className='shrink-0 text-xs font-medium text-text-quaternary'>·</div> | |||||
| <div title={payload.label as string} className='max-w-[130px] truncate text-[13px] font-medium text-text-tertiary'>{payload.label as string}</div> | |||||
| </>)} | </>)} | ||||
| {showLegacyBadge && ( | {showLegacyBadge && ( | ||||
| <Badge | <Badge | ||||
| ? ( | ? ( | ||||
| <> | <> | ||||
| {payload.required && ( | {payload.required && ( | ||||
| <div className='mr-2 text-xs font-normal text-gray-500'>{t('workflow.nodes.start.required')}</div> | |||||
| <div className='mr-2 text-xs font-normal text-text-tertiary'>{t('workflow.nodes.start.required')}</div> | |||||
| )} | )} | ||||
| <InputVarTypeIcon type={payload.type} className='h-3.5 w-3.5 text-gray-500' /> | |||||
| <InputVarTypeIcon type={payload.type} className='h-3.5 w-3.5 text-text-tertiary' /> | |||||
| </> | </> | ||||
| ) | ) | ||||
| : (!readonly && ( | : (!readonly && ( | ||||
| <> | <> | ||||
| <div onClick={showEditVarModal} className='mr-1 cursor-pointer rounded-md p-1 hover:bg-black/5'> | |||||
| <Edit03 className='h-4 w-4 text-gray-500' /> | |||||
| <div onClick={showEditVarModal} className='mr-1 cursor-pointer rounded-md p-1 hover:bg-state-base-hover'> | |||||
| <Edit03 className='h-4 w-4 text-text-tertiary' /> | |||||
| </div> | </div> | ||||
| <div onClick={onRemove} className='cursor-pointer rounded-md p-1 hover:bg-black/5'> | |||||
| <RiDeleteBinLine className='h-4 w-4 text-gray-500' /> | |||||
| <div onClick={onRemove} className='group cursor-pointer rounded-md p-1 hover:bg-state-destructive-hover'> | |||||
| <RiDeleteBinLine className='h-4 w-4 text-text-tertiary group-hover:text-text-destructive' /> | |||||
| </div> | </div> | ||||
| </> | </> | ||||
| ))} | ))} |
| if (list.length === 0) { | if (list.length === 0) { | ||||
| return ( | return ( | ||||
| <div className='flex h-[42px] items-center justify-center rounded-md bg-gray-50 text-xs font-normal leading-[18px] text-gray-500'> | |||||
| <div className='flex h-[42px] items-center justify-center rounded-md bg-components-panel-bg text-xs font-normal leading-[18px] text-text-tertiary'> | |||||
| {t('workflow.nodes.start.noVarTip')} | {t('workflow.nodes.start.noVarTip')} | ||||
| </div> | </div> | ||||
| ) | ) |
| <div className='mb-1 px-3 py-1'> | <div className='mb-1 px-3 py-1'> | ||||
| <div className='space-y-0.5'> | <div className='space-y-0.5'> | ||||
| {variables.map(variable => ( | {variables.map(variable => ( | ||||
| <div key={variable.variable} className='flex h-6 items-center justify-between space-x-1 rounded-md bg-gray-100 px-1 text-xs font-normal text-gray-700'> | |||||
| <div key={variable.variable} className='flex h-6 items-center justify-between space-x-1 rounded-md bg-workflow-block-parma-bg px-1'> | |||||
| <div className='flex w-0 grow items-center space-x-1'> | <div className='flex w-0 grow items-center space-x-1'> | ||||
| <Variable02 className='h-3.5 w-3.5 shrink-0 text-primary-500' /> | |||||
| <span className='w-0 grow truncate text-xs font-normal text-gray-700'>{variable.variable}</span> | |||||
| <Variable02 className='h-3.5 w-3.5 shrink-0 text-text-accent' /> | |||||
| <span className='system-xs-regular w-0 grow truncate text-text-secondary'>{variable.variable}</span> | |||||
| </div> | </div> | ||||
| <div className='ml-1 flex items-center space-x-1'> | <div className='ml-1 flex items-center space-x-1'> | ||||
| {variable.required && <span className='text-xs font-normal uppercase text-gray-500'>{t(`${i18nPrefix}.required`)}</span>} | |||||
| <InputVarTypeIcon type={variable.type} className='h-3 w-3 text-gray-500' /> | |||||
| {variable.required && <span className='system-2xs-regular-uppercase text-text-tertiary'>{t(`${i18nPrefix}.required`)}</span>} | |||||
| <InputVarTypeIcon type={variable.type} className='h-3 w-3 text-text-tertiary' /> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| ))} | ))} |
| variable: 'sys.query', | variable: 'sys.query', | ||||
| } as any} | } as any} | ||||
| rightContent={ | rightContent={ | ||||
| <div className='text-xs font-normal text-gray-500'> | |||||
| <div className='text-xs font-normal text-text-tertiary'> | |||||
| String | String | ||||
| </div> | </div> | ||||
| } | } | ||||
| variable: 'sys.files', | variable: 'sys.files', | ||||
| } as any} | } as any} | ||||
| rightContent={ | rightContent={ | ||||
| <div className='text-xs font-normal text-gray-500'> | |||||
| <div className='text-xs font-normal text-text-tertiary'> | |||||
| Array[File] | Array[File] | ||||
| </div> | </div> | ||||
| } | } | ||||
| variable: 'sys.dialogue_count', | variable: 'sys.dialogue_count', | ||||
| } as any} | } as any} | ||||
| rightContent={ | rightContent={ | ||||
| <div className='text-xs font-normal text-gray-500'> | |||||
| <div className='text-xs font-normal text-text-tertiary'> | |||||
| Number | Number | ||||
| </div> | </div> | ||||
| } | } | ||||
| variable: 'sys.conversation_id', | variable: 'sys.conversation_id', | ||||
| } as any} | } as any} | ||||
| rightContent={ | rightContent={ | ||||
| <div className='text-xs font-normal text-gray-500'> | |||||
| <div className='text-xs font-normal text-text-tertiary'> | |||||
| String | String | ||||
| </div> | </div> | ||||
| } | } | ||||
| variable: 'sys.user_id', | variable: 'sys.user_id', | ||||
| } as any} | } as any} | ||||
| rightContent={ | rightContent={ | ||||
| <div className='text-xs font-normal text-gray-500'> | |||||
| <div className='text-xs font-normal text-text-tertiary'> | |||||
| String | String | ||||
| </div> | </div> | ||||
| } | } | ||||
| variable: 'sys.app_id', | variable: 'sys.app_id', | ||||
| } as any} | } as any} | ||||
| rightContent={ | rightContent={ | ||||
| <div className='text-xs font-normal text-gray-500'> | |||||
| <div className='text-xs font-normal text-text-tertiary'> | |||||
| String | String | ||||
| </div> | </div> | ||||
| } | } | ||||
| variable: 'sys.workflow_id', | variable: 'sys.workflow_id', | ||||
| } as any} | } as any} | ||||
| rightContent={ | rightContent={ | ||||
| <div className='text-xs font-normal text-gray-500'> | |||||
| <div className='text-xs font-normal text-text-tertiary'> | |||||
| String | String | ||||
| </div> | </div> | ||||
| } | } | ||||
| variable: 'sys.workflow_run_id', | variable: 'sys.workflow_run_id', | ||||
| } as any} | } as any} | ||||
| rightContent={ | rightContent={ | ||||
| <div className='text-xs font-normal text-gray-500'> | |||||
| <div className='text-xs font-normal text-text-tertiary'> | |||||
| String | String | ||||
| </div> | </div> | ||||
| } | } |
| headerRight={ | headerRight={ | ||||
| <div className='flex items-center'> | <div className='flex items-center'> | ||||
| <a | <a | ||||
| className='flex h-[18px] items-center space-x-0.5 text-xs font-normal text-gray-500' | |||||
| className='flex h-[18px] items-center space-x-0.5 text-xs font-normal text-text-tertiary' | |||||
| href="https://jinja.palletsprojects.com/en/3.1.x/templates/" | href="https://jinja.palletsprojects.com/en/3.1.x/templates/" | ||||
| target='_blank'> | target='_blank'> | ||||
| <span>{t(`${i18nPrefix}.codeSupportTip`)}</span> | <span>{t(`${i18nPrefix}.codeSupportTip`)}</span> | ||||
| <RiQuestionLine className='h-3 w-3' /> | <RiQuestionLine className='h-3 w-3' /> | ||||
| </a> | </a> | ||||
| <div className='mx-1.5 h-3 w-px bg-gray-200'></div> | |||||
| <div className='mx-1.5 h-3 w-px bg-divider-regular'></div> | |||||
| </div> | </div> | ||||
| } | } | ||||
| value={inputs.template} | value={inputs.template} |
| <div className='mb-1 px-3 py-1'> | <div className='mb-1 px-3 py-1'> | ||||
| <div className='space-y-0.5'> | <div className='space-y-0.5'> | ||||
| {toolConfigs.map((key, index) => ( | {toolConfigs.map((key, index) => ( | ||||
| <div key={index} className='flex h-6 items-center justify-between space-x-1 rounded-md bg-gray-100 px-1 text-xs font-normal text-gray-700'> | |||||
| <div title={key} className='max-w-[100px] shrink-0 truncate text-xs font-medium uppercase text-gray-500'> | |||||
| <div key={index} className='flex h-6 items-center justify-between space-x-1 rounded-md bg-workflow-block-parma-bg px-1 text-xs font-normal text-text-secondary'> | |||||
| <div title={key} className='max-w-[100px] shrink-0 truncate text-xs font-medium uppercase text-text-tertiary'> | |||||
| {key} | {key} | ||||
| </div> | </div> | ||||
| {typeof tool_configurations[key] === 'string' && ( | {typeof tool_configurations[key] === 'string' && ( | ||||
| <div title={tool_configurations[key]} className='w-0 shrink-0 grow truncate text-right text-xs font-normal text-gray-700'> | |||||
| <div title={tool_configurations[key]} className='w-0 shrink-0 grow truncate text-right text-xs font-normal text-text-secondary'> | |||||
| {paramSchemas?.find(i => i.name === key)?.type === FormTypeEnum.secretInput ? '********' : tool_configurations[key]} | {paramSchemas?.find(i => i.name === key)?.type === FormTypeEnum.secretInput ? '********' : tool_configurations[key]} | ||||
| </div> | </div> | ||||
| )} | )} | ||||
| {typeof tool_configurations[key] === 'number' && ( | {typeof tool_configurations[key] === 'number' && ( | ||||
| <div title={tool_configurations[key].toString()} className='w-0 shrink-0 grow truncate text-right text-xs font-normal text-gray-700'> | |||||
| <div title={tool_configurations[key].toString()} className='w-0 shrink-0 grow truncate text-right text-xs font-normal text-text-secondary'> | |||||
| {tool_configurations[key]} | {tool_configurations[key]} | ||||
| </div> | </div> | ||||
| )} | )} | ||||
| {typeof tool_configurations[key] !== 'string' && tool_configurations[key]?.type === FormTypeEnum.modelSelector && ( | {typeof tool_configurations[key] !== 'string' && tool_configurations[key]?.type === FormTypeEnum.modelSelector && ( | ||||
| <div title={tool_configurations[key].model} className='w-0 shrink-0 grow truncate text-right text-xs font-normal text-gray-700'> | |||||
| <div title={tool_configurations[key].model} className='w-0 shrink-0 grow truncate text-right text-xs font-normal text-text-secondary'> | |||||
| {tool_configurations[key].model} | {tool_configurations[key].model} | ||||
| </div> | </div> | ||||
| )} | )} |
| <Form | <Form | ||||
| className='space-y-4' | className='space-y-4' | ||||
| itemClassName='!py-0' | itemClassName='!py-0' | ||||
| fieldLabelClassName='!text-[13px] !font-semibold !text-gray-700 uppercase' | |||||
| fieldLabelClassName='!text-[13px] !font-semibold !text-text-secondary uppercase' | |||||
| value={toolSettingValue} | value={toolSettingValue} | ||||
| onChange={setToolSettingValue} | onChange={setToolSettingValue} | ||||
| formSchemas={toolSettingSchema as any} | formSchemas={toolSettingSchema as any} | ||||
| isEditMode={false} | isEditMode={false} | ||||
| showOnVariableMap={{}} | showOnVariableMap={{}} | ||||
| validating={false} | validating={false} | ||||
| inputClassName='!bg-gray-50' | |||||
| // inputClassName='!bg-gray-50' | |||||
| readonly={readOnly} | readonly={readOnly} | ||||
| /> | /> | ||||
| </div> | </div> |
| > | > | ||||
| <Plus02 | <Plus02 | ||||
| className={cn( | className={cn( | ||||
| 'h-2.5 w-2.5 text-gray-500', | |||||
| 'group-hover/addvariable:text-white', | |||||
| open && '!text-white', | |||||
| 'h-2.5 w-2.5 text-text-tertiary', | |||||
| 'group-hover/addvariable:text-text-primary', | |||||
| open && '!text-text-primary', | |||||
| )} | )} | ||||
| /> | /> | ||||
| </div> | </div> |
| <div | <div | ||||
| className={cn( | className={cn( | ||||
| 'relative rounded-lg border-[1.5px] border-transparent px-1.5 pb-1.5 pt-1', | 'relative rounded-lg border-[1.5px] border-transparent px-1.5 pb-1.5 pt-1', | ||||
| showSelectionBorder && '!border-dashed !border-gray-300 bg-black/[0.02]', | |||||
| showSelectedBorder && '!border-primary-600 !bg-primary-50', | |||||
| showSelectionBorder && '!border-dashed !border-divider-subtle bg-state-base-hover', | |||||
| showSelectedBorder && '!border-text-accent !bg-util-colors-blue-blue-50', | |||||
| )} | )} | ||||
| onMouseEnter={() => groupEnabled && handleGroupItemMouseEnter(item.targetHandleId)} | onMouseEnter={() => groupEnabled && handleGroupItemMouseEnter(item.targetHandleId)} | ||||
| onMouseLeave={handleGroupItemMouseLeave} | onMouseLeave={handleGroupItemMouseLeave} | ||||
| > | > | ||||
| <div className='flex h-4 items-center justify-between text-[10px] font-medium text-gray-500'> | |||||
| <div className='flex h-4 items-center justify-between text-[10px] font-medium text-text-tertiary'> | |||||
| <span | <span | ||||
| className={cn( | className={cn( | ||||
| 'grow truncate uppercase', | 'grow truncate uppercase', | ||||
| showSelectedBorder && 'text-primary-600', | |||||
| showSelectedBorder && 'text-text-accent', | |||||
| )} | )} | ||||
| title={item.title} | title={item.title} | ||||
| > | > | ||||
| </span> | </span> | ||||
| <div className='flex items-center'> | <div className='flex items-center'> | ||||
| <span className='ml-2 shrink-0'>{item.type}</span> | <span className='ml-2 shrink-0'>{item.type}</span> | ||||
| <div className='ml-2 mr-1 h-2.5 w-[1px] bg-gray-200'></div> | |||||
| <div className='ml-2 mr-1 h-2.5 w-[1px] bg-divider-regular'></div> | |||||
| <AddVariable | <AddVariable | ||||
| availableVars={availableVars} | availableVars={availableVars} | ||||
| variableAssignerNodeId={item.variableAssignerNodeId} | variableAssignerNodeId={item.variableAssignerNodeId} | ||||
| !item.variables.length && ( | !item.variables.length && ( | ||||
| <div | <div | ||||
| className={cn( | className={cn( | ||||
| 'relative flex h-[22px] items-center justify-between space-x-1 rounded-md bg-gray-100 px-1 text-[10px] font-normal uppercase text-gray-400', | |||||
| 'relative flex h-[22px] items-center justify-between space-x-1 rounded-md bg-workflow-block-parma-bg px-1 text-[10px] font-normal uppercase text-text-tertiary', | |||||
| (showSelectedBorder || showSelectionBorder) && '!bg-black/[0.02]', | (showSelectedBorder || showSelectionBorder) && '!bg-black/[0.02]', | ||||
| )} | )} | ||||
| > | > |
| <div | <div | ||||
| className={cn( | className={cn( | ||||
| 'system-xs-medium ml-0.5 shrink truncate text-text-accent', | 'system-xs-medium ml-0.5 shrink truncate text-text-accent', | ||||
| isEnv && 'text-gray-900', | |||||
| isEnv && 'text-text-primary', | |||||
| isException && 'text-text-warning', | isException && 'text-text-warning', | ||||
| isChatVar && 'text-util-colors-teal-teal-700', | isChatVar && 'text-util-colors-teal-teal-700', | ||||
| )} | )} | ||||
| return ( | return ( | ||||
| <div className={cn( | <div className={cn( | ||||
| 'relative flex items-center gap-1 self-stretch rounded-md bg-workflow-block-parma-bg p-[3px] pl-[5px]', | 'relative flex items-center gap-1 self-stretch rounded-md bg-workflow-block-parma-bg p-[3px] pl-[5px]', | ||||
| showBorder && '!bg-black/[0.02]', | |||||
| showBorder && '!bg-state-base-hover', | |||||
| className, | className, | ||||
| )}> | )}> | ||||
| <div className='flex w-0 grow items-center'> | <div className='flex w-0 grow items-center'> | ||||
| <> | <> | ||||
| <div className='shrink-0 p-[1px]'> | <div className='shrink-0 p-[1px]'> | ||||
| <VarBlockIcon | <VarBlockIcon | ||||
| className='!text-gray-900' | |||||
| className='!text-text-primary' | |||||
| type={node.data.type} | type={node.data.type} | ||||
| /> | /> | ||||
| </div> | </div> | ||||
| <div | <div | ||||
| className='mx-0.5 shrink-[1000] truncate text-xs font-medium text-gray-700' | |||||
| className='mx-0.5 shrink-[1000] truncate text-xs font-medium text-text-secondary' | |||||
| title={node?.data.title} | title={node?.data.title} | ||||
| > | > | ||||
| {node?.data.title} | {node?.data.title} |
| </div> | </div> | ||||
| {canRemove && ( | {canRemove && ( | ||||
| <div | <div | ||||
| className='ml-0.5 hidden cursor-pointer rounded-md p-1 text-gray-500 hover:bg-[#FEE4E2] hover:text-[#D92D20] group-hover:block' | |||||
| className='ml-0.5 hidden cursor-pointer rounded-md p-1 text-text-tertiary hover:bg-state-destructive-hover hover:text-text-destructive group-hover:block' | |||||
| onClick={onRemove} | onClick={onRemove} | ||||
| > | > | ||||
| <RiDeleteBinLine | <RiDeleteBinLine |
| /> | /> | ||||
| {!readonly && ( | {!readonly && ( | ||||
| <RemoveButton | <RemoveButton | ||||
| className='!bg-gray-100 !p-2 hover:!bg-gray-200' | |||||
| onClick={handleVarRemove(index)} | onClick={handleVarRemove(index)} | ||||
| /> | /> | ||||
| )} | )} |
| {isEnableGroup && ( | {isEnableGroup && ( | ||||
| <> | <> | ||||
| <Split /> | <Split /> | ||||
| <div> | |||||
| <OutputVars> | |||||
| <> | |||||
| {inputs.advanced_settings?.groups.map((item, index) => ( | |||||
| <VarItem | |||||
| key={index} | |||||
| name={`${item.group_name}.output`} | |||||
| type={item.output_type} | |||||
| description={t(`${i18nPrefix}.outputVars.varDescribe`, { | |||||
| groupName: item.group_name, | |||||
| })} | |||||
| /> | |||||
| ))} | |||||
| </> | |||||
| </OutputVars> | |||||
| </div> | |||||
| <OutputVars> | |||||
| <> | |||||
| {inputs.advanced_settings?.groups.map((item, index) => ( | |||||
| <VarItem | |||||
| key={index} | |||||
| name={`${item.group_name}.output`} | |||||
| type={item.output_type} | |||||
| description={t(`${i18nPrefix}.outputVars.varDescribe`, { | |||||
| groupName: item.group_name, | |||||
| })} | |||||
| /> | |||||
| ))} | |||||
| </> | |||||
| </OutputVars> | |||||
| </> | </> | ||||
| )} | )} | ||||
| <RemoveEffectVarConfirm | <RemoveEffectVarConfirm |
| return ( | return ( | ||||
| <div | <div | ||||
| className={` | |||||
| flex h-full w-[420px] flex-col rounded-l-2xl border border-black/2 shadow-xl | |||||
| `} | |||||
| style={{ | |||||
| background: 'linear-gradient(156deg, rgba(242, 244, 247, 0.80) 0%, rgba(242, 244, 247, 0.00) 99.43%), var(--white, #FFF)', | |||||
| }} | |||||
| className='flex h-full w-[420px] flex-col rounded-l-2xl border border-components-panel-border bg-chatbot-bg shadow-xl' | |||||
| // style={{ | |||||
| // background: 'linear-gradient(156deg, rgba(242, 244, 247, 0.80) 0%, rgba(242, 244, 247, 0.00) 99.43%), var(--white, #FFF)', | |||||
| // }} | |||||
| > | > | ||||
| {!fetched && ( | {!fetched && ( | ||||
| <div className='flex h-full items-center justify-center'> | <div className='flex h-full items-center justify-center'> | ||||
| )} | )} | ||||
| {fetched && ( | {fetched && ( | ||||
| <> | <> | ||||
| <div className='flex shrink-0 items-center justify-between p-4 pb-1 text-base font-semibold text-gray-900'> | |||||
| <div className='flex shrink-0 items-center justify-between p-4 pb-1 text-base font-semibold text-text-primary'> | |||||
| {`TEST CHAT#${historyWorkflowData?.sequence_number}`} | {`TEST CHAT#${historyWorkflowData?.sequence_number}`} | ||||
| <div | <div | ||||
| className='flex h-6 w-6 cursor-pointer items-center justify-center' | className='flex h-6 w-6 cursor-pointer items-center justify-center' | ||||
| workflowStore.setState({ historyWorkflowData: undefined }) | workflowStore.setState({ historyWorkflowData: undefined }) | ||||
| }} | }} | ||||
| > | > | ||||
| <RiCloseLine className='h-4 w-4 text-gray-500' /> | |||||
| <RiCloseLine className='h-4 w-4 text-text-tertiary' /> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div className='h-0 grow'> | <div className='h-0 grow'> |
| <div | <div | ||||
| className={` | className={` | ||||
| rounded-xl border | rounded-xl border | ||||
| ${!expanded ? 'border-indigo-100 bg-indigo-25 shadow-none' : 'border-transparent bg-white shadow-xs'} | |||||
| ${!expanded ? 'border-components-panel-border-subtle bg-components-panel-on-panel-item-bg shadow-none' : 'border-transparent bg-white shadow-xs'} | |||||
| `} | `} | ||||
| > | > | ||||
| <div | <div | ||||
| className={` | className={` | ||||
| flex h-[18px] cursor-pointer items-center px-2 pt-4 text-[13px] font-semibold | flex h-[18px] cursor-pointer items-center px-2 pt-4 text-[13px] font-semibold | ||||
| ${!expanded ? 'text-indigo-800' : 'text-gray-800'} | |||||
| ${!expanded ? 'text-text-accent-secondary' : 'text-text-secondary'} | |||||
| `} | `} | ||||
| onClick={() => setExpanded(!expanded)} | onClick={() => setExpanded(!expanded)} | ||||
| > | > | ||||
| <RiArrowDownSLine | <RiArrowDownSLine | ||||
| className={`mr-1 h-3 w-3 ${!expanded ? '-rotate-90 text-indigo-600' : 'text-gray-300'}`} | |||||
| className={`mr-1 h-3 w-3 ${!expanded ? '-rotate-90 text-text-accent' : 'text-text-tertiary'}`} | |||||
| /> | /> | ||||
| {t('workflow.panel.userInputField').toLocaleUpperCase()} | {t('workflow.panel.userInputField').toLocaleUpperCase()} | ||||
| </div> | </div> | ||||
| <div className='px-2 pb-3 pt-1'> | <div className='px-2 pb-3 pt-1'> | ||||
| { | { | ||||
| expanded && ( | expanded && ( | ||||
| <div className='py-2 text-[13px] text-gray-900'> | |||||
| <div className='py-2 text-[13px] text-text-primary'> | |||||
| { | { | ||||
| variables.map((variable: any) => ( | variables.map((variable: any) => ( | ||||
| <div | <div |
| {expanded && <div className='absolute bottom-[-17px] right-[5px] z-10 h-3 w-3 rotate-45 border-l-[0.5px] border-t-[0.5px] border-components-panel-border-subtle bg-components-panel-on-panel-item-bg'/>} | {expanded && <div className='absolute bottom-[-17px] right-[5px] z-10 h-3 w-3 rotate-45 border-l-[0.5px] border-t-[0.5px] border-components-panel-border-subtle bg-components-panel-on-panel-item-bg'/>} | ||||
| </div> | </div> | ||||
| )} | )} | ||||
| <div className='mx-3 h-3.5 w-[1px] bg-gray-200'></div> | |||||
| <div className='mx-3 h-3.5 w-[1px] bg-divider-regular'></div> | |||||
| <div | <div | ||||
| className='flex h-6 w-6 cursor-pointer items-center justify-center' | className='flex h-6 w-6 cursor-pointer items-center justify-center' | ||||
| onClick={handleCancelDebugAndPreviewPanel} | onClick={handleCancelDebugAndPreviewPanel} | ||||
| > | > | ||||
| <RiCloseLine className='h-4 w-4 text-gray-500' /> | |||||
| <RiCloseLine className='h-4 w-4 text-text-tertiary' /> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> |
| return ( | return ( | ||||
| <div className={` | <div className={` | ||||
| flex h-full w-[420px] flex-col rounded-l-2xl border-[0.5px] border-gray-200 bg-white shadow-xl | |||||
| flex h-full w-[420px] flex-col rounded-l-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-xl | |||||
| `}> | `}> | ||||
| <div className='flex items-center justify-between p-4 pb-1 text-base font-semibold text-gray-900'> | |||||
| <div className='flex items-center justify-between p-4 pb-1 text-base font-semibold text-text-primary'> | |||||
| {`Test Run${!workflowRunningData?.result.sequence_number ? '' : `#${workflowRunningData?.result.sequence_number}`}`} | {`Test Run${!workflowRunningData?.result.sequence_number ? '' : `#${workflowRunningData?.result.sequence_number}`}`} | ||||
| <div className='cursor-pointer p-1' onClick={() => handleCancelDebugAndPreviewPanel()}> | <div className='cursor-pointer p-1' onClick={() => handleCancelDebugAndPreviewPanel()}> | ||||
| <RiCloseLine className='h-4 w-4 text-gray-500' /> | |||||
| <RiCloseLine className='h-4 w-4 text-text-tertiary' /> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div className='relative flex grow flex-col'> | <div className='relative flex grow flex-col'> | ||||
| <div className='flex shrink-0 items-center border-b-[0.5px] border-[rgba(0,0,0,0.05)] px-4'> | |||||
| <div className='flex shrink-0 items-center border-b-[0.5px] border-divider-subtle px-4'> | |||||
| {showInputsPanel && ( | {showInputsPanel && ( | ||||
| <div | <div | ||||
| className={cn( | className={cn( | ||||
| 'mr-6 cursor-pointer border-b-2 border-transparent py-3 text-[13px] font-semibold leading-[18px] text-gray-400', | |||||
| currentTab === 'INPUT' && '!border-[rgb(21,94,239)] text-gray-700', | |||||
| 'mr-6 cursor-pointer border-b-2 border-transparent py-3 text-[13px] font-semibold leading-[18px] text-text-tertiary', | |||||
| currentTab === 'INPUT' && '!border-[rgb(21,94,239)] text-text-secondary', | |||||
| )} | )} | ||||
| onClick={() => switchTab('INPUT')} | onClick={() => switchTab('INPUT')} | ||||
| >{t('runLog.input')}</div> | >{t('runLog.input')}</div> | ||||
| )} | )} | ||||
| <div | <div | ||||
| className={cn( | className={cn( | ||||
| 'mr-6 cursor-pointer border-b-2 border-transparent py-3 text-[13px] font-semibold leading-[18px] text-gray-400', | |||||
| currentTab === 'RESULT' && '!border-[rgb(21,94,239)] text-gray-700', | |||||
| 'mr-6 cursor-pointer border-b-2 border-transparent py-3 text-[13px] font-semibold leading-[18px] text-text-tertiary', | |||||
| currentTab === 'RESULT' && '!border-[rgb(21,94,239)] text-text-secondary', | |||||
| !workflowRunningData && '!cursor-not-allowed opacity-30', | !workflowRunningData && '!cursor-not-allowed opacity-30', | ||||
| )} | )} | ||||
| onClick={() => { | onClick={() => { | ||||
| >{t('runLog.result')}</div> | >{t('runLog.result')}</div> | ||||
| <div | <div | ||||
| className={cn( | className={cn( | ||||
| 'mr-6 cursor-pointer border-b-2 border-transparent py-3 text-[13px] font-semibold leading-[18px] text-gray-400', | |||||
| currentTab === 'DETAIL' && '!border-[rgb(21,94,239)] text-gray-700', | |||||
| 'mr-6 cursor-pointer border-b-2 border-transparent py-3 text-[13px] font-semibold leading-[18px] text-text-tertiary', | |||||
| currentTab === 'DETAIL' && '!border-[rgb(21,94,239)] text-text-secondary', | |||||
| !workflowRunningData && '!cursor-not-allowed opacity-30', | !workflowRunningData && '!cursor-not-allowed opacity-30', | ||||
| )} | )} | ||||
| onClick={() => { | onClick={() => { | ||||
| >{t('runLog.detail')}</div> | >{t('runLog.detail')}</div> | ||||
| <div | <div | ||||
| className={cn( | className={cn( | ||||
| 'mr-6 cursor-pointer border-b-2 border-transparent py-3 text-[13px] font-semibold leading-[18px] text-gray-400', | |||||
| currentTab === 'TRACING' && '!border-[rgb(21,94,239)] text-gray-700', | |||||
| 'mr-6 cursor-pointer border-b-2 border-transparent py-3 text-[13px] font-semibold leading-[18px] text-text-tertiary', | |||||
| currentTab === 'TRACING' && '!border-[rgb(21,94,239)] text-text-secondary', | |||||
| !workflowRunningData && '!cursor-not-allowed opacity-30', | !workflowRunningData && '!cursor-not-allowed opacity-30', | ||||
| )} | )} | ||||
| onClick={() => { | onClick={() => { |