Merge pull request #148 from SuanmoSuanyangTechnology/feature/ui_zy
Feature/UI zy
This commit is contained in:
21
web/src/assets/images/workflow/deleteBg.svg
Normal file
21
web/src/assets/images/workflow/deleteBg.svg
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<title>编组 33</title>
|
||||||
|
<g id="工作流" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<g id="工作流--流程控制-条件分支" transform="translate(-1752, -352)" stroke="#5B6167">
|
||||||
|
<g id="编组-37" transform="translate(1480, 63)">
|
||||||
|
<g id="编组-35" transform="translate(8, 195)">
|
||||||
|
<g id="编组-33" transform="translate(264, 94)">
|
||||||
|
<g id="编组-32" transform="translate(3, 3.5)">
|
||||||
|
<line x1="-1.63757896e-14" y1="2" x2="10" y2="2" id="路径-29"></line>
|
||||||
|
<polyline id="路径-30" stroke-linejoin="round" points="3 1.99990611 3 0 7 0 7 2"></polyline>
|
||||||
|
<path d="M1.5,2.01228712 L1.5,8 C1.5,8.55228475 1.94771525,9 2.5,9 L7.5,9 C8.05228475,9 8.5,8.55228475 8.5,8 L8.5,2 L8.5,2" id="路径-31" stroke-linejoin="round"></path>
|
||||||
|
<line x1="4" y1="4.00683364" x2="4" y2="7.00683364" id="路径-32"></line>
|
||||||
|
<line x1="6" y1="4.00683364" x2="6" y2="7.00683364" id="路径-32"></line>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
22
web/src/assets/images/workflow/deleteBg_hover.svg
Normal file
22
web/src/assets/images/workflow/deleteBg_hover.svg
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<title>编组 33</title>
|
||||||
|
<g id="工作流" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<g id="工作流--流程控制-条件分支" transform="translate(-1752, -420)">
|
||||||
|
<g id="编组-37" transform="translate(1480, 63)">
|
||||||
|
<g id="编组-35" transform="translate(8, 195)">
|
||||||
|
<g id="编组-33" transform="translate(264, 162)">
|
||||||
|
<rect id="矩形" fill="#FF5D34" opacity="0.116987" x="0" y="0" width="16" height="16" rx="4"></rect>
|
||||||
|
<g id="编组-32" transform="translate(3, 3.5)" stroke="#FF5D34">
|
||||||
|
<line x1="-1.63757896e-14" y1="2" x2="10" y2="2" id="路径-29"></line>
|
||||||
|
<polyline id="路径-30" stroke-linejoin="round" points="3 1.99990611 3 0 7 0 7 2"></polyline>
|
||||||
|
<path d="M1.5,2.01228712 L1.5,8 C1.5,8.55228475 1.94771525,9 2.5,9 L7.5,9 C8.05228475,9 8.5,8.55228475 8.5,8 L8.5,2 L8.5,2" id="路径-31" stroke-linejoin="round"></path>
|
||||||
|
<line x1="4" y1="4.00683364" x2="4" y2="7.00683364" id="路径-32"></line>
|
||||||
|
<line x1="6" y1="4.00683364" x2="6" y2="7.00683364" id="路径-32"></line>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
18
web/src/assets/images/workflow/delete_cycle.svg
Normal file
18
web/src/assets/images/workflow/delete_cycle.svg
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<title>编组 33</title>
|
||||||
|
<g id="工作流" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<g id="工作流--AI与认知处理-大语言模型" transform="translate(-1736, -662)" stroke="#212332" stroke-width="1.1">
|
||||||
|
<g id="编组-34" transform="translate(1472, 64)">
|
||||||
|
<g id="编组-3备份-10" transform="translate(12, 409)">
|
||||||
|
<g id="选择备份" transform="translate(0, 177)">
|
||||||
|
<g id="编组-33" transform="translate(252, 12)">
|
||||||
|
<circle id="椭圆形" cx="8" cy="8" r="6.45"></circle>
|
||||||
|
<line x1="6" y1="8" x2="10" y2="8" id="路径-10" stroke-linecap="round" stroke-linejoin="round"></line>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
18
web/src/assets/images/workflow/recall.svg
Normal file
18
web/src/assets/images/workflow/recall.svg
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<title>召回</title>
|
||||||
|
<g id="工作流" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<g id="工作流--AI与认知处理-知识检索" transform="translate(-1684, -330)" stroke="#212332">
|
||||||
|
<g id="节点属性" transform="translate(1472, 64)">
|
||||||
|
<g id="编组-30" transform="translate(12, 264)">
|
||||||
|
<g id="编组-28" transform="translate(196, 0)">
|
||||||
|
<g id="召回" transform="translate(4, 2)">
|
||||||
|
<path d="M3.00336574,8.78243131 C3.31276784,9.47513403 3.79697125,10.0726443 4.39990015,10.5188863 M5.34710411,11.051994 C5.85707009,11.2602342 6.41513255,11.375 7,11.375 C7.46865477,11.375 7.92009851,11.3013108 8.34337671,11.1648869 M9.11238544,10.8321699 C9.85595277,10.4214229 10.4672402,9.80055221 10.8661626,9.04964308 M11.1846924,8.28028469 C11.3084287,7.87534253 11.375,7.44544554 11.375,7 C11.375,4.58375422 9.41624578,2.625 7,2.625 C5.30981329,2.625 3.84348335,3.58344477 3.11486142,4.98648308" id="形状"></path>
|
||||||
|
<polyline id="路径-10" stroke-linejoin="round" points="2.48490579 2.81937431 2.86401413 5.38855621 5.4725833 4.82767632"></polyline>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
18
web/src/assets/images/workflow/recall_hover.svg
Normal file
18
web/src/assets/images/workflow/recall_hover.svg
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<title>召回</title>
|
||||||
|
<g id="工作流" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<g id="工作流--AI与认知处理-知识检索" transform="translate(-1684, -330)" stroke="#155EEF">
|
||||||
|
<g id="节点属性" transform="translate(1472, 64)">
|
||||||
|
<g id="编组-30" transform="translate(12, 264)">
|
||||||
|
<g id="编组-28" transform="translate(196, 0)">
|
||||||
|
<g id="召回" transform="translate(4, 2)">
|
||||||
|
<path d="M3.00336574,8.78243131 C3.31276784,9.47513403 3.79697125,10.0726443 4.39990015,10.5188863 M5.34710411,11.051994 C5.85707009,11.2602342 6.41513255,11.375 7,11.375 C7.46865477,11.375 7.92009851,11.3013108 8.34337671,11.1648869 M9.11238544,10.8321699 C9.85595277,10.4214229 10.4672402,9.80055221 10.8661626,9.04964308 M11.1846924,8.28028469 C11.3084287,7.87534253 11.375,7.44544554 11.375,7 C11.375,4.58375422 9.41624578,2.625 7,2.625 C5.30981329,2.625 3.84348335,3.58344477 3.11486142,4.98648308" id="形状"></path>
|
||||||
|
<polyline id="路径-10" stroke-linejoin="round" points="2.48490579 2.81937431 2.86401413 5.38855621 5.4725833 4.82767632"></polyline>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
12
web/src/components/FormItem/DescWrapper.tsx
Normal file
12
web/src/components/FormItem/DescWrapper.tsx
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import clsx from "clsx";
|
||||||
|
import type { FC, ReactNode } from "react";
|
||||||
|
|
||||||
|
const DescWrapper: FC<{desc: string | ReactNode, className?: string}> = ({desc, className}) => {
|
||||||
|
return (
|
||||||
|
<div className={clsx(className, "rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:leading-4 ")}>
|
||||||
|
{desc}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DescWrapper
|
||||||
13
web/src/components/FormItem/LabelWrapper.tsx
Normal file
13
web/src/components/FormItem/LabelWrapper.tsx
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import clsx from "clsx";
|
||||||
|
import type { FC, ReactNode } from "react";
|
||||||
|
|
||||||
|
const LabelWrapper: FC<{ title: string | ReactNode, className?: string; children?: ReactNode}> = ({title, className, children}) => {
|
||||||
|
return (
|
||||||
|
<div className={clsx(className)}>
|
||||||
|
<div className="rb:text-[14px] rb:font-medium rb:leading-5">{title}</div>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LabelWrapper
|
||||||
45
web/src/components/FormItem/SwitchFormItem.tsx
Normal file
45
web/src/components/FormItem/SwitchFormItem.tsx
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import { Switch, Form, ConfigProvider } from "antd";
|
||||||
|
import useSize from 'antd/lib/config-provider/hooks/useSize'
|
||||||
|
import type { FC, ReactNode } from "react";
|
||||||
|
import { useContext } from "react";
|
||||||
|
|
||||||
|
import LabelWrapper from './LabelWrapper'
|
||||||
|
import DescWrapper from './DescWrapper'
|
||||||
|
|
||||||
|
interface SwitchFormItemProps {
|
||||||
|
title: string | ReactNode;
|
||||||
|
desc?: string | ReactNode;
|
||||||
|
name: string | string[];
|
||||||
|
size?: 'small' | 'default'
|
||||||
|
className?: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SwitchFormItem: FC<SwitchFormItemProps> = ({
|
||||||
|
title,
|
||||||
|
desc,
|
||||||
|
name,
|
||||||
|
size = 'default',
|
||||||
|
className,
|
||||||
|
disabled
|
||||||
|
}) => {
|
||||||
|
const componentSize = useSize()
|
||||||
|
console.log('componentSize', componentSize)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`${className} rb:flex rb:items-center rb:justify-between`}>
|
||||||
|
<LabelWrapper title={title}>
|
||||||
|
{desc && <DescWrapper desc={desc} className="rb:mt-2" />}
|
||||||
|
</LabelWrapper>
|
||||||
|
<Form.Item
|
||||||
|
name={name}
|
||||||
|
valuePropName="checked"
|
||||||
|
className="rb:mb-0!"
|
||||||
|
>
|
||||||
|
<Switch disabled={disabled} size={size} />
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SwitchFormItem
|
||||||
@@ -54,7 +54,7 @@ const AppHeader: FC<{source?: 'space' | 'manage';}> = ({source = 'manage'}) => {
|
|||||||
key: '1',
|
key: '1',
|
||||||
label: (<>
|
label: (<>
|
||||||
<div>{user.username}</div>
|
<div>{user.username}</div>
|
||||||
<div className="rb:text-[12px] rb:text-[#5B6167] rb:mt-[8px]">{user.email}</div>
|
<div className="rb:text-[12px] rb:text-[#5B6167] rb:mt-2">{user.email}</div>
|
||||||
</>),
|
</>),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -150,9 +150,19 @@ const RbMarkdown: FC<RbMarkdownProps> = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理键盘快捷键
|
||||||
|
const handleKeyDown = (e: React.KeyboardEvent) => {
|
||||||
|
if ((e.ctrlKey || e.metaKey) && e.key === 'c') {
|
||||||
|
const selection = window.getSelection()
|
||||||
|
if (selection && selection.toString()) {
|
||||||
|
navigator.clipboard.writeText(selection.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 预览模式
|
// 预览模式
|
||||||
return (
|
return (
|
||||||
<div className="rb:relative">
|
<div className="rb:relative" onKeyDown={handleKeyDown} tabIndex={0}>
|
||||||
<style>{`
|
<style>{`
|
||||||
.html-comment {
|
.html-comment {
|
||||||
color: #999;
|
color: #999;
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
.rb-modal .ant-modal-header {
|
.rb-modal .ant-modal-footer .ant-btn {
|
||||||
margin-bottom: 24px;
|
height: 32px !important;
|
||||||
|
padding: 0 15px !important;
|
||||||
|
font-size: 14px !important;
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
import { type FC } from 'react'
|
import { type FC } from 'react'
|
||||||
import { Modal, type ModalProps } from 'antd'
|
import { Modal, type ModalProps } from 'antd'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import './index.css'
|
||||||
const RbModal: FC<ModalProps> = ({
|
const RbModal: FC<ModalProps> = ({
|
||||||
onOk,
|
onOk,
|
||||||
onCancel,
|
onCancel,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useState, type FC, useCallback, useRef } from 'react';
|
import { useState, type FC, useCallback, useRef } from 'react';
|
||||||
import { Input } from 'antd';
|
import { Input, type InputProps } from 'antd';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import searchIcon from '@/assets/images/search.svg'
|
import searchIcon from '@/assets/images/search.svg'
|
||||||
|
|
||||||
@@ -11,6 +11,7 @@ interface SearchInputProps {
|
|||||||
defaultValue?: string;
|
defaultValue?: string;
|
||||||
style?: Record<string, string | number>;
|
style?: Record<string, string | number>;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
size?: InputProps['size']
|
||||||
}
|
}
|
||||||
|
|
||||||
const SearchInput: FC<SearchInputProps> = ({
|
const SearchInput: FC<SearchInputProps> = ({
|
||||||
@@ -79,7 +80,7 @@ const SearchInput: FC<SearchInputProps> = ({
|
|||||||
return (
|
return (
|
||||||
<Input
|
<Input
|
||||||
allowClear
|
allowClear
|
||||||
prefix={<img src={searchIcon} alt="search" className="rb:w-[16px] rb:h-[16px] rb:mr-[4px]" />}
|
prefix={<img src={searchIcon} alt="search" className="rb:w-4 rb:h-4 rb:mr-1" />}
|
||||||
placeholder={placeholder || t('user.searchPlaceholder')}
|
placeholder={placeholder || t('user.searchPlaceholder')}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
|||||||
@@ -417,7 +417,8 @@ export const en = {
|
|||||||
refresh: 'Refresh',
|
refresh: 'Refresh',
|
||||||
return: 'Return',
|
return: 'Return',
|
||||||
statusEnabled: 'Available',
|
statusEnabled: 'Available',
|
||||||
statusDisabled: 'Unavailable'
|
statusDisabled: 'Unavailable',
|
||||||
|
remove: 'Remove',
|
||||||
},
|
},
|
||||||
model: {
|
model: {
|
||||||
searchPlaceholder: 'search model…',
|
searchPlaceholder: 'search model…',
|
||||||
@@ -1798,9 +1799,11 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re
|
|||||||
temperature: 'Temperature',
|
temperature: 'Temperature',
|
||||||
max_tokens: 'Max Tokens',
|
max_tokens: 'Max Tokens',
|
||||||
context: 'Context',
|
context: 'Context',
|
||||||
|
contextPlaceholder: '{x} Set Variable',
|
||||||
memory: 'Memory',
|
memory: 'Memory',
|
||||||
enable_window: 'Memory Window',
|
enable_window: 'Memory Window',
|
||||||
inner: 'Built-in',
|
inner: 'Built-in',
|
||||||
|
messagesPlaceholder: 'Write prompts here, type "{" to insert variables, type "insert" to insert',
|
||||||
},
|
},
|
||||||
start: {
|
start: {
|
||||||
variables: 'Input Fields',
|
variables: 'Input Fields',
|
||||||
@@ -1811,7 +1814,6 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re
|
|||||||
array: 'Dropdown Options',
|
array: 'Dropdown Options',
|
||||||
object: 'Object',
|
object: 'Object',
|
||||||
|
|
||||||
addVariable: 'Add Variable',
|
|
||||||
editVariable: 'Edit Variable',
|
editVariable: 'Edit Variable',
|
||||||
variableType: 'Variable Type',
|
variableType: 'Variable Type',
|
||||||
variableName: 'Variable Name',
|
variableName: 'Variable Name',
|
||||||
@@ -1835,6 +1837,7 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re
|
|||||||
'parameter-extractor': {
|
'parameter-extractor': {
|
||||||
model_id: 'Model',
|
model_id: 'Model',
|
||||||
text: 'Input Variable',
|
text: 'Input Variable',
|
||||||
|
textPlaceholder: '{x} Set Variable',
|
||||||
params: 'Extract Parameters',
|
params: 'Extract Parameters',
|
||||||
prompt: 'Instruction',
|
prompt: 'Instruction',
|
||||||
|
|
||||||
@@ -1855,6 +1858,8 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re
|
|||||||
'array[number]': 'Array[Number]',
|
'array[number]': 'Array[Number]',
|
||||||
'array[boolean]': 'Array[Boolean]',
|
'array[boolean]': 'Array[Boolean]',
|
||||||
'array[object]': 'Array[Object]',
|
'array[object]': 'Array[Object]',
|
||||||
|
addParams: 'Add Extract Variable',
|
||||||
|
promptPlaceholder: 'Write prompts here, type "{" to insert variables, type "insert" to insert',
|
||||||
},
|
},
|
||||||
'var-aggregator': {
|
'var-aggregator': {
|
||||||
group: 'Aggregation Group',
|
group: 'Aggregation Group',
|
||||||
@@ -1924,6 +1929,7 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re
|
|||||||
loop: {
|
loop: {
|
||||||
cycle_vars: 'Loop Variables',
|
cycle_vars: 'Loop Variables',
|
||||||
condition: 'Loop Termination Condition',
|
condition: 'Loop Termination Condition',
|
||||||
|
addCondition: 'Add Condition',
|
||||||
max_loop: 'Maximum Loop Count',
|
max_loop: 'Maximum Loop Count',
|
||||||
},
|
},
|
||||||
assigner: {
|
assigner: {
|
||||||
@@ -1960,6 +1966,7 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re
|
|||||||
type: 'Type',
|
type: 'Type',
|
||||||
value: 'Value',
|
value: 'Value',
|
||||||
addCase: 'Add Condition',
|
addCase: 'Add Condition',
|
||||||
|
addVariable: 'Add Variables',
|
||||||
},
|
},
|
||||||
|
|
||||||
clear: 'Clear',
|
clear: 'Clear',
|
||||||
|
|||||||
@@ -965,7 +965,8 @@ export const zh = {
|
|||||||
refresh: '刷新',
|
refresh: '刷新',
|
||||||
return: '返回',
|
return: '返回',
|
||||||
statusEnabled: '可用',
|
statusEnabled: '可用',
|
||||||
statusDisabled: '不可用'
|
statusDisabled: '不可用',
|
||||||
|
remove: '删除',
|
||||||
},
|
},
|
||||||
product: {
|
product: {
|
||||||
applicationManagement: '应用管理',
|
applicationManagement: '应用管理',
|
||||||
@@ -1891,9 +1892,11 @@ export const zh = {
|
|||||||
temperature: '温度',
|
temperature: '温度',
|
||||||
max_tokens: '最大令牌数',
|
max_tokens: '最大令牌数',
|
||||||
context: '上下文',
|
context: '上下文',
|
||||||
|
contextPlaceholder: '{x} 设置变量',
|
||||||
memory: '记忆',
|
memory: '记忆',
|
||||||
enable_window: '记忆窗口',
|
enable_window: '记忆窗口',
|
||||||
inner: '内置',
|
inner: '内置',
|
||||||
|
messagesPlaceholder: '在此处编写提示,输入“{”插入变量,输入“insert”插入',
|
||||||
},
|
},
|
||||||
start: {
|
start: {
|
||||||
variables: '输入字段',
|
variables: '输入字段',
|
||||||
@@ -1904,7 +1907,6 @@ export const zh = {
|
|||||||
array: '下拉选项',
|
array: '下拉选项',
|
||||||
object: '对象',
|
object: '对象',
|
||||||
|
|
||||||
addVariable: '添加变量',
|
|
||||||
editVariable: '编辑变量',
|
editVariable: '编辑变量',
|
||||||
variableType: '变量类型',
|
variableType: '变量类型',
|
||||||
variableName: '变量名称',
|
variableName: '变量名称',
|
||||||
@@ -1924,10 +1926,12 @@ export const zh = {
|
|||||||
query: '查询变量',
|
query: '查询变量',
|
||||||
knowledge_retrieval: '知识库',
|
knowledge_retrieval: '知识库',
|
||||||
recallConfig: '召回测试',
|
recallConfig: '召回测试',
|
||||||
|
addKnowledge: '添加知识库'
|
||||||
},
|
},
|
||||||
'parameter-extractor': {
|
'parameter-extractor': {
|
||||||
model_id: '模型',
|
model_id: '模型',
|
||||||
text: '输入变量',
|
text: '输入变量',
|
||||||
|
textPlaceholder: '{x} 设置变量',
|
||||||
params: '提取参数',
|
params: '提取参数',
|
||||||
prompt: '指令',
|
prompt: '指令',
|
||||||
|
|
||||||
@@ -1948,6 +1952,8 @@ export const zh = {
|
|||||||
'array[number]': 'Array[Number]',
|
'array[number]': 'Array[Number]',
|
||||||
'array[boolean]': 'Array[Boolean]',
|
'array[boolean]': 'Array[Boolean]',
|
||||||
'array[object]': 'Array[Object]',
|
'array[object]': 'Array[Object]',
|
||||||
|
addParams: '添加提取变量',
|
||||||
|
promptPlaceholder: '在此处编写提示,输入“{”插入变量,输入“insert”插入',
|
||||||
},
|
},
|
||||||
'var-aggregator': {
|
'var-aggregator': {
|
||||||
group: '聚合分组',
|
group: '聚合分组',
|
||||||
@@ -2017,6 +2023,7 @@ export const zh = {
|
|||||||
loop: {
|
loop: {
|
||||||
cycle_vars: '循环变量',
|
cycle_vars: '循环变量',
|
||||||
condition: '循环终止条件',
|
condition: '循环终止条件',
|
||||||
|
addCondition: '添加条件',
|
||||||
max_loop: '最大循环次数',
|
max_loop: '最大循环次数',
|
||||||
},
|
},
|
||||||
assigner: {
|
assigner: {
|
||||||
@@ -2053,6 +2060,7 @@ export const zh = {
|
|||||||
type: '类型',
|
type: '类型',
|
||||||
value: '值',
|
value: '值',
|
||||||
addCase: '添加条件',
|
addCase: '添加条件',
|
||||||
|
addVariable: '添加变量',
|
||||||
},
|
},
|
||||||
|
|
||||||
clear: '清空',
|
clear: '清空',
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ export const lightTheme: ThemeConfig = {
|
|||||||
colorBorderSecondary: '#DFE4ED',
|
colorBorderSecondary: '#DFE4ED',
|
||||||
// colorBgContainer: '#FBFDFF',
|
// colorBgContainer: '#FBFDFF',
|
||||||
colorError: '#FF5D34',
|
colorError: '#FF5D34',
|
||||||
|
sizeSM: 12,
|
||||||
|
fontSizeSM: 12,
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
Layout: {
|
Layout: {
|
||||||
@@ -86,6 +88,7 @@ export const lightTheme: ThemeConfig = {
|
|||||||
rowSelectedBg: '#E9F1FF',
|
rowSelectedBg: '#E9F1FF',
|
||||||
rowSelectedHoverBg: '#F0F3F8',
|
rowSelectedHoverBg: '#F0F3F8',
|
||||||
cellPaddingBlock: 8,
|
cellPaddingBlock: 8,
|
||||||
|
cellFontSizeSM: 12,
|
||||||
|
|
||||||
// cellPaddingInline: 24,
|
// cellPaddingInline: 24,
|
||||||
selectionColumnWidth: 48,
|
selectionColumnWidth: 48,
|
||||||
@@ -95,6 +98,13 @@ export const lightTheme: ThemeConfig = {
|
|||||||
lastItemColor: '#212332',
|
lastItemColor: '#212332',
|
||||||
linkColor: '#5B6167',
|
linkColor: '#5B6167',
|
||||||
linkHoverColor: '#212332',
|
linkHoverColor: '#212332',
|
||||||
|
},
|
||||||
|
Input: {
|
||||||
|
inputFontSizeSM: 12,
|
||||||
|
controlHeightSM: 26
|
||||||
|
},
|
||||||
|
Select: {
|
||||||
|
lineHeightSM: 26
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { type FC, useEffect, useRef } from 'react';
|
import { type FC, useRef } from 'react';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import { Layout, Tabs, Dropdown, Button } from 'antd';
|
import { Layout, Tabs, Dropdown, Button, Flex } from 'antd';
|
||||||
import type { MenuProps } from 'antd';
|
import type { MenuProps } from 'antd';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import styles from '../index.module.css'
|
import styles from '../index.module.css'
|
||||||
@@ -141,10 +141,12 @@ const ConfigHeader: FC<ConfigHeaderProps> = ({
|
|||||||
{/* <Button type="primary">{t('workflow.export')}</Button> */}
|
{/* <Button type="primary">{t('workflow.export')}</Button> */}
|
||||||
<img src={logoutIcon} className="rb:w-4 rb:h-4 rb:cursor-pointer" onClick={goToApplication} />
|
<img src={logoutIcon} className="rb:w-4 rb:h-4 rb:cursor-pointer" onClick={goToApplication} />
|
||||||
</div>
|
</div>
|
||||||
: <div className="rb:h-8 rb:flex rb:items-center rb:justify-end rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:cursor-pointer" onClick={goToApplication}>
|
: <Flex justify="flex-end">
|
||||||
<img src={logoutIcon} className="rb:mr-2 rb:w-4 rb:h-4" />
|
<div className="rb:h-8 rb:flex rb:items-center rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:cursor-pointer" onClick={goToApplication}>
|
||||||
{t('application.returnToApplicationList')}
|
<img src={logoutIcon} className="rb:mr-2 rb:w-4 rb:h-4" />
|
||||||
</div>
|
{t('application.returnToApplicationList')}
|
||||||
|
</div>
|
||||||
|
</Flex>
|
||||||
}
|
}
|
||||||
</Header>
|
</Header>
|
||||||
<ApplicationModal
|
<ApplicationModal
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Row, Col, Form, Slider, Button, Alert, message, Switch, Space } from 'antd';
|
import { Row, Col, Form, Slider, Button, Alert, message, Space } from 'antd';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import RbCard from '@/components/RbCard/Card';
|
import RbCard from '@/components/RbCard/Card';
|
||||||
@@ -9,6 +9,7 @@ import type { ConfigForm } from './types'
|
|||||||
import CustomSelect from '@/components/CustomSelect';
|
import CustomSelect from '@/components/CustomSelect';
|
||||||
import { getModelListUrl } from '@/api/models'
|
import { getModelListUrl } from '@/api/models'
|
||||||
import Tag from '@/components/Tag'
|
import Tag from '@/components/Tag'
|
||||||
|
import SwitchFormItem from '@/components/FormItem/SwitchFormItem'
|
||||||
|
|
||||||
const configList = [
|
const configList = [
|
||||||
{
|
{
|
||||||
@@ -158,23 +159,17 @@ const EmotionEngine: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rb:flex rb:items-center rb:justify-between rb:mb-6">
|
<SwitchFormItem
|
||||||
<div>
|
title={t(`emotionEngine.${config.key}`)}
|
||||||
<span className="rb:text-[14px] rb:font-medium rb:leading-5">{t(`emotionEngine.${config.key}`)}</span>
|
name={config.key}
|
||||||
|
desc={<>
|
||||||
{config.hasSubTitle && <div className="rb:mt-1 rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:leading-4">{t(`emotionEngine.${config.key}_subTitle`)}</div>}
|
{config.hasSubTitle && <div className="rb:mt-1 rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:leading-4">{t(`emotionEngine.${config.key}_subTitle`)}</div>}
|
||||||
<div className="rb:mt-1 rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:leading-4">{t(`emotionEngine.${config.key}_desc`)}</div>
|
<div className="rb:mt-1 rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:leading-4">{t(`emotionEngine.${config.key}_desc`)}</div>
|
||||||
</div>
|
</>}
|
||||||
<Form.Item
|
className="rb:mb-6"
|
||||||
name={config.key}
|
disabled={!values?.emotion_enabled && config.key !== 'emotion_enabled'}
|
||||||
valuePropName="checked"
|
/>
|
||||||
className="rb:ml-2 rb:mb-0!"
|
|
||||||
>
|
|
||||||
<Switch
|
|
||||||
disabled={!values?.emotion_enabled && config.key !== 'emotion_enabled'} />
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
<Row gutter={16} className="rb:mt-3">
|
<Row gutter={16} className="rb:mt-3">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Row, Col, Form, Slider, Button, Space, message, Switch } from 'antd';
|
import { Row, Col, Form, Slider, Button, Space, message } from 'antd';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import RbCard from '@/components/RbCard/Card';
|
import RbCard from '@/components/RbCard/Card';
|
||||||
@@ -7,6 +7,7 @@ import strategyImpactSimulator from '@/assets/images/memory/strategyImpactSimula
|
|||||||
import LineChart from './components/LineChart'
|
import LineChart from './components/LineChart'
|
||||||
import { getMemoryForgetConfig, updateMemoryForgetConfig } from '@/api/memory'
|
import { getMemoryForgetConfig, updateMemoryForgetConfig } from '@/api/memory'
|
||||||
import type { ConfigForm } from './types'
|
import type { ConfigForm } from './types'
|
||||||
|
import SwitchFormItem from '@/components/FormItem/SwitchFormItem'
|
||||||
|
|
||||||
const configList = [
|
const configList = [
|
||||||
{
|
{
|
||||||
@@ -155,26 +156,12 @@ const ForgettingEngine: React.FC = () => {
|
|||||||
{configList.map(config => {
|
{configList.map(config => {
|
||||||
if (config.type === 'button') {
|
if (config.type === 'button') {
|
||||||
return (
|
return (
|
||||||
<div key={config.key} className="rb:mb-2">
|
<SwitchFormItem
|
||||||
<div className="rb:flex rb:items-center rb:justify-between">
|
title={t(`forgettingEngine.${config.key}`)}
|
||||||
<div>
|
name={config.name}
|
||||||
<span className="rb:text-[14px] rb:font-medium rb:leading-5">{t(`forgettingEngine.${config.key}`)}</span>
|
desc={config.type && <span>{t(`forgettingEngine.type`)}: {config.type}</span>}
|
||||||
</div>
|
className="rb:mb-2"
|
||||||
<Form.Item
|
/>
|
||||||
name={config.name}
|
|
||||||
valuePropName="checked"
|
|
||||||
className="rb:ml-2 rb:mb-0!"
|
|
||||||
>
|
|
||||||
<Switch />
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
<div className="rb:flex rb:text-[12px] rb:items-center rb:justify-between rb:text-[#5B6167] rb:leading-5">
|
|
||||||
<Space size={4}>
|
|
||||||
{config.range && <span>{t(`forgettingEngine.range`)}: {config.range?.join('-')}</span>}
|
|
||||||
{config.type && <span>{t(`forgettingEngine.type`)}: {config.type}</span>}
|
|
||||||
</Space>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
@@ -191,8 +178,6 @@ const ForgettingEngine: React.FC = () => {
|
|||||||
>
|
>
|
||||||
{config.type === 'decimal'
|
{config.type === 'decimal'
|
||||||
? <Slider tooltip={{ open: false }} max={config.range?.[1] || 1} min={config.range?.[0] || 0} step={config.step ?? 0.01} style={{ margin: '0' }} />
|
? <Slider tooltip={{ open: false }} max={config.range?.[1] || 1} min={config.range?.[0] || 0} step={config.step ?? 0.01} style={{ margin: '0' }} />
|
||||||
: config.type === 'button'
|
|
||||||
? <Switch />
|
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { getModelList } from '@/api/models';
|
|||||||
import type { Model } from '@/views/ModelManagement/types'
|
import type { Model } from '@/views/ModelManagement/types'
|
||||||
import { configList } from './constant'
|
import { configList } from './constant'
|
||||||
import Result from './components/Result'
|
import Result from './components/Result'
|
||||||
|
import SwitchFormItem from '@/components/FormItem/SwitchFormItem'
|
||||||
|
|
||||||
const keys = [
|
const keys = [
|
||||||
// 'example',
|
// 'example',
|
||||||
@@ -173,25 +174,18 @@ const MemoryExtractionEngine: FC = () => {
|
|||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="rb:text-[16px] rb:font-medium rb:leading-[22px]">{t(`memoryExtractionEngine.${vo.title}`)}</div>
|
<div className="rb:text-[16px] rb:font-medium rb:leading-5.5">{t(`memoryExtractionEngine.${vo.title}`)}</div>
|
||||||
<div className="rb:mt-1 rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:leading-4">{t(`memoryExtractionEngine.${vo.title}SubTitle`)}</div>
|
<div className="rb:mt-1 rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:leading-4">{t(`memoryExtractionEngine.${vo.title}SubTitle`)}</div>
|
||||||
|
|
||||||
{vo.list.map(config => (
|
{vo.list.map(config => (
|
||||||
<div key={config.label}>
|
<div key={config.label}>
|
||||||
{config.control === 'button' &&
|
{config.control === 'button' &&
|
||||||
<div className="rb:flex rb:items-center rb:justify-between rb:mt-6">
|
<SwitchFormItem
|
||||||
<div>
|
title={<>-{t(`memoryExtractionEngine.${config.label}`)}</>}
|
||||||
<span className="rb:text-[14px] rb:font-medium rb:leading-5">-{t(`memoryExtractionEngine.${config.label}`)}</span>
|
name={config.variableName}
|
||||||
<ConfigDesc config={config} className="rb:ml-2" />
|
desc={<ConfigDesc config={config} className="rb:ml-2" />}
|
||||||
</div>
|
className="rb:mt-6"
|
||||||
<Form.Item
|
/>
|
||||||
name={config.variableName}
|
|
||||||
valuePropName="checked"
|
|
||||||
className="rb:ml-2 rb:mb-0!"
|
|
||||||
>
|
|
||||||
<Switch />
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
{config.control === 'select' &&
|
{config.control === 'select' &&
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Row, Col, Form, App, Button, Switch, Space, Select } from 'antd';
|
import { Row, Col, Form, App, Button, Space, Select } from 'antd';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
@@ -11,6 +11,7 @@ import CustomSelect from '@/components/CustomSelect';
|
|||||||
import { getModelListUrl } from '@/api/models'
|
import { getModelListUrl } from '@/api/models'
|
||||||
import Tag from '@/components/Tag'
|
import Tag from '@/components/Tag'
|
||||||
import { useI18n } from '@/store/locale';
|
import { useI18n } from '@/store/locale';
|
||||||
|
import SwitchFormItem from '@/components/FormItem/SwitchFormItem'
|
||||||
|
|
||||||
const configList = [
|
const configList = [
|
||||||
// 启用反思引擎
|
// 启用反思引擎
|
||||||
@@ -219,21 +220,16 @@ const SelfReflectionEngine: React.FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rb:flex rb:items-center rb:justify-between rb:mb-6">
|
<SwitchFormItem
|
||||||
<div>
|
title={t(`reflectionEngine.${config.key}`)}
|
||||||
<span className="rb:text-[14px] rb:font-medium rb:leading-5">{t(`reflectionEngine.${config.key}`)}</span>
|
name={config.key}
|
||||||
|
desc={<>
|
||||||
{(config as any).hasSubTitle && <div className="rb:mt-1 rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:leading-4">{t(`reflectionEngine.${config.key}_subTitle`)}</div>}
|
{(config as any).hasSubTitle && <div className="rb:mt-1 rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:leading-4">{t(`reflectionEngine.${config.key}_subTitle`)}</div>}
|
||||||
<div className="rb:mt-1 rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:leading-4">{t(`reflectionEngine.${config.key}_desc`)}</div>
|
<div className="rb:mt-1 rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:leading-4">{t(`reflectionEngine.${config.key}_desc`)}</div>
|
||||||
</div>
|
</>}
|
||||||
<Form.Item
|
className="rb:mb-6"
|
||||||
name={config.key}
|
disabled={!values?.reflection_enabled && config.key !== 'reflection_enabled'}
|
||||||
valuePropName="checked"
|
/>
|
||||||
className="rb:ml-2 rb:mb-0!"
|
|
||||||
>
|
|
||||||
<Switch
|
|
||||||
disabled={!values?.reflection_enabled && config.key !== 'reflection_enabled'} />
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
<Row gutter={16} className="rb:mt-3">
|
<Row gutter={16} className="rb:mt-3">
|
||||||
|
|||||||
@@ -2,12 +2,13 @@ import { forwardRef, useImperativeHandle, useState } from 'react';
|
|||||||
import { Form, Input, InputNumber, Checkbox } from 'antd';
|
import { Form, Input, InputNumber, Checkbox } from 'antd';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import type { StartVariableItem, VariableConfigModalRef } from '../../types'
|
import type { VariableConfigModalRef } from '../../types'
|
||||||
|
import type { Variable } from '../Properties/VariableList/types'
|
||||||
import RbModal from '@/components/RbModal'
|
import RbModal from '@/components/RbModal'
|
||||||
|
|
||||||
interface VariableEditModalProps {
|
interface VariableEditModalProps {
|
||||||
refresh: (values: StartVariableItem[]) => void;
|
refresh: (values: Variable[]) => void;
|
||||||
variables: StartVariableItem[]
|
variables: Variable[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const VariableConfigModal = forwardRef<VariableConfigModalRef, VariableEditModalProps>(({
|
const VariableConfigModal = forwardRef<VariableConfigModalRef, VariableEditModalProps>(({
|
||||||
@@ -15,9 +16,9 @@ const VariableConfigModal = forwardRef<VariableConfigModalRef, VariableEditModal
|
|||||||
}, ref) => {
|
}, ref) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const [form] = Form.useForm<{variables: StartVariableItem[]}>();
|
const [form] = Form.useForm<{variables: Variable[]}>();
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [initialValues, setInitialValues] = useState<StartVariableItem[]>([])
|
const [initialValues, setInitialValues] = useState<Variable[]>([])
|
||||||
|
|
||||||
// 封装取消方法,添加关闭弹窗逻辑
|
// 封装取消方法,添加关闭弹窗逻辑
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
@@ -26,7 +27,7 @@ const VariableConfigModal = forwardRef<VariableConfigModalRef, VariableEditModal
|
|||||||
setLoading(false)
|
setLoading(false)
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOpen = (values: StartVariableItem[]) => {
|
const handleOpen = (values: Variable[]) => {
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
form.setFieldsValue({variables: values})
|
form.setFieldsValue({variables: values})
|
||||||
setInitialValues([...values])
|
setInitialValues([...values])
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { type FC, useState, useEffect } from 'react';
|
import { type FC, useState, useEffect, useMemo } from 'react';
|
||||||
import { LexicalComposer } from '@lexical/react/LexicalComposer';
|
import { LexicalComposer } from '@lexical/react/LexicalComposer';
|
||||||
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin';
|
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin';
|
||||||
import { ContentEditable } from '@lexical/react/LexicalContentEditable';
|
import { ContentEditable } from '@lexical/react/LexicalContentEditable';
|
||||||
@@ -25,7 +25,11 @@ interface LexicalEditorProps {
|
|||||||
options: Suggestion[];
|
options: Suggestion[];
|
||||||
variant?: 'outlined' | 'borderless';
|
variant?: 'outlined' | 'borderless';
|
||||||
height?: number;
|
height?: number;
|
||||||
|
fontSize?: number;
|
||||||
|
lineHeight?: number;
|
||||||
enableJinja2?: boolean;
|
enableJinja2?: boolean;
|
||||||
|
size?: 'default' | 'small';
|
||||||
|
type?: 'input' | 'textarea'
|
||||||
}
|
}
|
||||||
|
|
||||||
const theme = {
|
const theme = {
|
||||||
@@ -51,8 +55,9 @@ const Editor: FC<LexicalEditorProps> =({
|
|||||||
onChange,
|
onChange,
|
||||||
options,
|
options,
|
||||||
variant = 'borderless',
|
variant = 'borderless',
|
||||||
height = 60,
|
|
||||||
enableJinja2 = false,
|
enableJinja2 = false,
|
||||||
|
size = 'default',
|
||||||
|
type = 'textarea'
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
const [_count, setCount] = useState(0);
|
const [_count, setCount] = useState(0);
|
||||||
@@ -94,12 +99,9 @@ const Editor: FC<LexicalEditorProps> =({
|
|||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
.line-numbers {
|
.line-numbers {
|
||||||
background-color: #f8f9fa;
|
|
||||||
border-right: 1px solid #e1e4e8;
|
|
||||||
color: #656d76;
|
|
||||||
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
|
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 20px;
|
line-height: 16px;
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
@@ -142,6 +144,21 @@ const Editor: FC<LexicalEditorProps> =({
|
|||||||
console.error(error);
|
console.error(error);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const minheight = useMemo(() => {
|
||||||
|
if (type === 'input') {
|
||||||
|
return `${size === 'small' ? 26 : 30}px`
|
||||||
|
}
|
||||||
|
return `${size === 'small' ? 60 : 120}px`
|
||||||
|
}, [type, size])
|
||||||
|
const fontSize = useMemo(() => {
|
||||||
|
return `${size === 'small' ? 12 : 14}px`
|
||||||
|
}, [size])
|
||||||
|
const lineHeight = useMemo(() => {
|
||||||
|
return `${size === 'small' ? 16 : 20}px`
|
||||||
|
}, [size])
|
||||||
|
const placeHolderMinheight = useMemo(() => {
|
||||||
|
return `${size === 'small' ? 16 : 30}px`
|
||||||
|
}, [type, size])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LexicalComposer initialConfig={initialConfig}>
|
<LexicalComposer initialConfig={initialConfig}>
|
||||||
@@ -152,7 +169,7 @@ const Editor: FC<LexicalEditorProps> =({
|
|||||||
<div className="editor-with-line-numbers" style={{
|
<div className="editor-with-line-numbers" style={{
|
||||||
border: variant === 'borderless' ? 'none' : '1px solid #DFE4ED',
|
border: variant === 'borderless' ? 'none' : '1px solid #DFE4ED',
|
||||||
borderRadius: '6px',
|
borderRadius: '6px',
|
||||||
minHeight: `${height}px`,
|
minHeight: minheight,
|
||||||
}}>
|
}}>
|
||||||
<div className="line-numbers">
|
<div className="line-numbers">
|
||||||
<div>1</div>
|
<div>1</div>
|
||||||
@@ -160,12 +177,12 @@ const Editor: FC<LexicalEditorProps> =({
|
|||||||
<ContentEditable
|
<ContentEditable
|
||||||
className="editor-content-with-numbers"
|
className="editor-content-with-numbers"
|
||||||
style={{
|
style={{
|
||||||
minHeight: `${height}px`,
|
minHeight: minheight,
|
||||||
padding: '4px 11px',
|
padding: '4px 0',
|
||||||
outline: 'none',
|
outline: 'none',
|
||||||
resize: 'none',
|
resize: 'none',
|
||||||
fontSize: '14px',
|
fontSize: fontSize,
|
||||||
lineHeight: '20px',
|
lineHeight: lineHeight,
|
||||||
border: 'none',
|
border: 'none',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -173,14 +190,14 @@ const Editor: FC<LexicalEditorProps> =({
|
|||||||
) : (
|
) : (
|
||||||
<ContentEditable
|
<ContentEditable
|
||||||
style={{
|
style={{
|
||||||
minHeight: `${height}px`,
|
minHeight: minheight,
|
||||||
padding: variant === 'borderless' ? '0' : '4px 11px',
|
padding: variant === 'borderless' ? '0' : '4px 11px',
|
||||||
border: variant === 'borderless' ? 'none' : '1px solid #DFE4ED',
|
border: variant === 'borderless' ? 'none' : '1px solid #DFE4ED',
|
||||||
borderRadius: '6px',
|
borderRadius: '6px',
|
||||||
outline: 'none',
|
outline: 'none',
|
||||||
resize: 'none',
|
resize: 'none',
|
||||||
fontSize: '14px',
|
fontSize: fontSize,
|
||||||
lineHeight: '20px',
|
lineHeight: lineHeight,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
@@ -188,12 +205,13 @@ const Editor: FC<LexicalEditorProps> =({
|
|||||||
placeholder={
|
placeholder={
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
minHeight: placeHolderMinheight,
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: variant === 'borderless' ? '0' : '6px',
|
top: variant === 'borderless' ? '0' : '6px',
|
||||||
left: enableJinja2 ? '59px' : (variant === 'borderless' ? '0' : '11px'),
|
left: enableJinja2 ? '59px' : (variant === 'borderless' ? '0' : '11px'),
|
||||||
color: '#5B6167',
|
color: '#A8A9AA',
|
||||||
fontSize: '14px',
|
fontSize: fontSize,
|
||||||
lineHeight: '20px',
|
lineHeight: placeHolderMinheight,
|
||||||
pointerEvents: 'none',
|
pointerEvents: 'none',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -9,12 +9,21 @@ const Jinja2HighlightPlugin = () => {
|
|||||||
return editor.registerNodeTransform(TextNode, (textNode: TextNode) => {
|
return editor.registerNodeTransform(TextNode, (textNode: TextNode) => {
|
||||||
const text = textNode.getTextContent();
|
const text = textNode.getTextContent();
|
||||||
|
|
||||||
if (containsJinja2Patterns(text)) {
|
// Skip if node already has styling (prevent infinite recursion)
|
||||||
const parent = textNode.getParent();
|
if (textNode.getStyle()) return;
|
||||||
if (!parent) return;
|
|
||||||
|
// Skip if no Jinja2 patterns found
|
||||||
|
if (!containsJinja2Patterns(text)) return;
|
||||||
|
|
||||||
|
const parent = textNode.getParent();
|
||||||
|
if (!parent) return;
|
||||||
|
|
||||||
const tokens = tokenizeJinja2(text);
|
const tokens = tokenizeJinja2(text);
|
||||||
const newNodes = tokens.map(token => {
|
|
||||||
|
// Skip if no meaningful tokenization (only one text token)
|
||||||
|
if (tokens.length <= 1 || (tokens.length === 1 && tokens[0].type === 'text')) return;
|
||||||
|
|
||||||
|
const newNodes = tokens.map(token => {
|
||||||
const newNode = $createTextNode(token.text);
|
const newNode = $createTextNode(token.text);
|
||||||
|
|
||||||
switch (token.type) {
|
switch (token.type) {
|
||||||
@@ -30,16 +39,16 @@ const Jinja2HighlightPlugin = () => {
|
|||||||
newNode.setStyle('color: #008000');
|
newNode.setStyle('color: #008000');
|
||||||
break;
|
break;
|
||||||
case 'brace-0':
|
case 'brace-0':
|
||||||
newNode.setStyle('color: #d73a49; font-family: monospace; font-weight: bold;');
|
newNode.setStyle('color: #155EEF; font-family: monospace; font-weight: bold;');
|
||||||
break;
|
break;
|
||||||
case 'brace-1':
|
case 'brace-1':
|
||||||
newNode.setStyle('color: #0366d6; font-family: monospace; font-weight: bold;');
|
newNode.setStyle('color: #369F21; font-family: monospace; font-weight: bold;');
|
||||||
break;
|
break;
|
||||||
case 'brace-2':
|
case 'brace-2':
|
||||||
newNode.setStyle('color: #28a745; font-family: monospace; font-weight: bold;');
|
newNode.setStyle('color: #FF5D34; font-family: monospace; font-weight: bold;');
|
||||||
break;
|
break;
|
||||||
case 'brace-3':
|
case 'brace-3':
|
||||||
newNode.setStyle('color: #6f42c1; font-family: monospace; font-weight: bold;');
|
newNode.setStyle('color: #5B6167; font-family: monospace; font-weight: bold;');
|
||||||
break;
|
break;
|
||||||
case 'expression-0':
|
case 'expression-0':
|
||||||
case 'expression-1':
|
case 'expression-1':
|
||||||
@@ -77,7 +86,6 @@ const Jinja2HighlightPlugin = () => {
|
|||||||
newNodes[i - 1].insertAfter(newNodes[i]);
|
newNodes[i - 1].insertAfter(newNodes[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}, [editor]);
|
}, [editor]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { type FC } from 'react'
|
import { type FC } from 'react'
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Form, Input, Row, Col, Select, InputNumber, Radio } from 'antd'
|
import { Form, Input, Select, InputNumber, Radio, Button, Space } from 'antd'
|
||||||
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
|
|
||||||
import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin'
|
import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin'
|
||||||
import VariableSelect from '../VariableSelect'
|
import VariableSelect from '../VariableSelect'
|
||||||
|
|
||||||
@@ -9,6 +8,7 @@ interface AssignmentListProps {
|
|||||||
value?: Array<{ variable_selector: string; operation: string[]; value: string;}>;
|
value?: Array<{ variable_selector: string; operation: string[]; value: string;}>;
|
||||||
parentName: string;
|
parentName: string;
|
||||||
options: Suggestion[];
|
options: Suggestion[];
|
||||||
|
size?: 'small' | 'middle'
|
||||||
}
|
}
|
||||||
|
|
||||||
const operationsObj = {
|
const operationsObj = {
|
||||||
@@ -31,6 +31,7 @@ const operationsObj = {
|
|||||||
const AssignmentList: FC<AssignmentListProps> = ({
|
const AssignmentList: FC<AssignmentListProps> = ({
|
||||||
parentName,
|
parentName,
|
||||||
options = [],
|
options = [],
|
||||||
|
size = 'small'
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const form = Form.useFormInstance();
|
const form = Form.useFormInstance();
|
||||||
@@ -39,109 +40,126 @@ const AssignmentList: FC<AssignmentListProps> = ({
|
|||||||
<Form.List name={parentName}>
|
<Form.List name={parentName}>
|
||||||
{(fields, { add, remove }) => (
|
{(fields, { add, remove }) => (
|
||||||
<>
|
<>
|
||||||
<div className="rb:flex rb:justify-between">
|
<div className="rb:flex rb:items-center rb:justify-between rb:mb-2.5">
|
||||||
{t(`workflow.config.assigner.${parentName}`)}
|
<div className="rb:text-[12px] rb:leading-4.5 rb:font-medium">
|
||||||
<PlusOutlined onClick={() => add({ operation: 'cover'})} />
|
{t(`workflow.config.assigner.${parentName}`)}
|
||||||
</div>
|
</div>
|
||||||
{fields.map(({ key, name, ...restField }) => {
|
|
||||||
const variableSelector = form.getFieldValue([parentName, name, 'variable_selector']);
|
|
||||||
const selectedOption = options.find(option => `{{${option.value}}}` === variableSelector);
|
|
||||||
const dataType = selectedOption?.dataType;
|
|
||||||
const operationOptions = dataType === 'number' ? operationsObj.number : operationsObj.default;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div key={key} className="rb:mb-4">
|
|
||||||
<Row gutter={12} className="rb:mb-2!">
|
|
||||||
<Col span={14}>
|
|
||||||
<Form.Item
|
|
||||||
{...restField}
|
|
||||||
name={[name, 'variable_selector']}
|
|
||||||
noStyle
|
|
||||||
>
|
|
||||||
<VariableSelect
|
|
||||||
placeholder={t('common.pleaseSelect')}
|
|
||||||
options={options.filter(vo => vo.nodeData.type === 'loop' || vo.value.includes('conv.') || (vo.nodeData.type === 'iteration' && (vo.label === 'item' || vo.label === 'index')))}
|
|
||||||
popupMatchSelectWidth={false}
|
|
||||||
onChange={() => {
|
|
||||||
form.setFieldValue([parentName, name, 'operation'], undefined);
|
|
||||||
form.setFieldValue([parentName, name, 'value'], undefined);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={8}>
|
|
||||||
<Form.Item
|
|
||||||
{...restField}
|
|
||||||
name={[name, 'operation']}
|
|
||||||
noStyle
|
|
||||||
>
|
|
||||||
<Select
|
|
||||||
placeholder={t('common.pleaseSelect')}
|
|
||||||
options={operationOptions.map(op => ({
|
|
||||||
...op,
|
|
||||||
label: t(op.label)
|
|
||||||
}))}
|
|
||||||
popupMatchSelectWidth={false}
|
|
||||||
onChange={() => {
|
|
||||||
form.setFieldValue([parentName, name, 'value'], undefined);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={2} className="rb:flex! rb:items-center rb:justify-end">
|
|
||||||
<MinusCircleOutlined onClick={() => remove(name)} />
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
|
|
||||||
<Form.Item shouldUpdate noStyle>
|
<Button
|
||||||
{(form) => {
|
onClick={() => add({ operation: 'cover' })}
|
||||||
const operation = form.getFieldValue([parentName, name, 'operation']);
|
className="rb:py-0! rb:px-1! rb:text-[12px]!"
|
||||||
if (operation === 'clear') return null;
|
size="small"
|
||||||
|
>
|
||||||
return (
|
+ {t('workflow.config.addVariable')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Space size={10} direction="vertical" className="rb:w-full!">
|
||||||
|
{fields.map(({ key, name, ...restField }) => {
|
||||||
|
const variableSelector = form.getFieldValue([parentName, name, 'variable_selector']);
|
||||||
|
const selectedOption = options.find(option => `{{${option.value}}}` === variableSelector);
|
||||||
|
const dataType = selectedOption?.dataType;
|
||||||
|
const operationOptions = dataType === 'number' ? operationsObj.number : operationsObj.default;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={key} className="rb:flex rb:items-start">
|
||||||
|
<div className="rb:flex-1">
|
||||||
|
<div className="rb:flex rb:gap-1 rb:mb-1">
|
||||||
<Form.Item
|
<Form.Item
|
||||||
{...restField}
|
{...restField}
|
||||||
name={[name, 'value']}
|
name={[name, 'variable_selector']}
|
||||||
noStyle
|
noStyle
|
||||||
>
|
>
|
||||||
{dataType === 'number' && operation === 'cover'
|
<VariableSelect
|
||||||
? <VariableSelect
|
placeholder={t('common.pleaseSelect')}
|
||||||
placeholder={t('common.pleaseSelect')}
|
options={options.filter(vo => vo.nodeData.type === 'loop' || vo.value.includes('conv.') || (vo.nodeData.type === 'iteration' && (vo.label === 'item' || vo.label === 'index')))}
|
||||||
options={dataType ? options.filter(vo => vo.dataType === dataType) : options}
|
popupMatchSelectWidth={false}
|
||||||
popupMatchSelectWidth={false}
|
onChange={() => {
|
||||||
/>
|
form.setFieldValue([parentName, name, 'operation'], undefined);
|
||||||
: dataType === 'number'
|
form.setFieldValue([parentName, name, 'value'], undefined);
|
||||||
? <InputNumber
|
}}
|
||||||
placeholder={t('common.pleaseEnter')}
|
size={size}
|
||||||
className="rb:w-full!"
|
className="rb:w-39!"
|
||||||
onChange={(value) => form.setFieldValue([name, 'value'], value)}
|
/>
|
||||||
/>
|
|
||||||
: operation === 'assign'
|
|
||||||
? <>
|
|
||||||
{dataType === 'boolean'
|
|
||||||
? <Radio.Group block>
|
|
||||||
<Radio.Button value={true}>True</Radio.Button>
|
|
||||||
<Radio.Button value={false}>False</Radio.Button>
|
|
||||||
</Radio.Group>
|
|
||||||
: <Input.TextArea
|
|
||||||
placeholder={t('common.pleaseEnter')}
|
|
||||||
rows={3}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
</>
|
|
||||||
: <VariableSelect
|
|
||||||
placeholder={t('common.pleaseSelect')}
|
|
||||||
options={dataType ? options.filter(vo => vo.dataType === dataType) : options}
|
|
||||||
popupMatchSelectWidth={false}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
<Form.Item
|
||||||
}}
|
{...restField}
|
||||||
</Form.Item>
|
name={[name, 'operation']}
|
||||||
</div>
|
noStyle
|
||||||
)
|
>
|
||||||
})}
|
<Select
|
||||||
|
placeholder={t('common.pleaseSelect')}
|
||||||
|
options={operationOptions.map(op => ({
|
||||||
|
...op,
|
||||||
|
label: t(op.label)
|
||||||
|
}))}
|
||||||
|
popupMatchSelectWidth={false}
|
||||||
|
onChange={() => {
|
||||||
|
form.setFieldValue([parentName, name, 'value'], undefined);
|
||||||
|
}}
|
||||||
|
size={size}
|
||||||
|
className="rb:w-24!"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
<Form.Item shouldUpdate noStyle>
|
||||||
|
{(form) => {
|
||||||
|
const operation = form.getFieldValue([parentName, name, 'operation']);
|
||||||
|
if (operation === 'clear') return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
{...restField}
|
||||||
|
name={[name, 'value']}
|
||||||
|
noStyle
|
||||||
|
>
|
||||||
|
{dataType === 'number' && operation === 'cover'
|
||||||
|
? <VariableSelect
|
||||||
|
placeholder={t('common.pleaseSelect')}
|
||||||
|
options={dataType ? options.filter(vo => vo.dataType === dataType) : options}
|
||||||
|
popupMatchSelectWidth={false}
|
||||||
|
size={size}
|
||||||
|
/>
|
||||||
|
: dataType === 'number'
|
||||||
|
? <InputNumber
|
||||||
|
placeholder={t('common.pleaseEnter')}
|
||||||
|
className="rb:w-full!"
|
||||||
|
onChange={(value) => form.setFieldValue([name, 'value'], value)}
|
||||||
|
size={size}
|
||||||
|
/>
|
||||||
|
: operation === 'assign'
|
||||||
|
? <>
|
||||||
|
{dataType === 'boolean'
|
||||||
|
? <Radio.Group block size={size}>
|
||||||
|
<Radio.Button value={true}>True</Radio.Button>
|
||||||
|
<Radio.Button value={false}>False</Radio.Button>
|
||||||
|
</Radio.Group>
|
||||||
|
: <Input.TextArea
|
||||||
|
placeholder={t('common.pleaseEnter')}
|
||||||
|
rows={3}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
: <VariableSelect
|
||||||
|
placeholder={t('common.pleaseSelect')}
|
||||||
|
options={dataType ? options.filter(vo => vo.dataType === dataType) : options}
|
||||||
|
popupMatchSelectWidth={false}
|
||||||
|
size={size}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="rb:ml-1 rb:size-4 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/workflow/deleteBg.svg')] rb:hover:bg-[url('@/assets/images/workflow/deleteBg_hover.svg')]"
|
||||||
|
onClick={() => remove(name)}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Space>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Form.List>
|
</Form.List>
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { type FC } from 'react'
|
import { type FC } from 'react'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Form, Button, Select, Space, Row, Col, Divider, InputNumber, Radio, type SelectProps } from 'antd'
|
import { Form, Button, Select, Space, Divider, InputNumber, Radio, type SelectProps } from 'antd'
|
||||||
import { DeleteOutlined } from '@ant-design/icons';
|
|
||||||
|
|
||||||
import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin'
|
import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin'
|
||||||
import VariableSelect from '../VariableSelect'
|
import VariableSelect from '../VariableSelect'
|
||||||
@@ -247,37 +246,40 @@ const CaseList: FC<CaseListProps> = ({
|
|||||||
{(conditionFields, { add: addCondition, remove: removeCondition }) => {
|
{(conditionFields, { add: addCondition, remove: removeCondition }) => {
|
||||||
const logicalOperator = form.getFieldValue(name)?.[caseIndex]?.logical_operator || 'and'
|
const logicalOperator = form.getFieldValue(name)?.[caseIndex]?.logical_operator || 'and'
|
||||||
return (
|
return (
|
||||||
<div className={clsx("rb:relative rb:mb-4 rb:border rb:border-gray-200 rb:rounded rb:p-3 rb:pl-5")}>
|
<div className={clsx("rb:relative")}>
|
||||||
<div className="rb:flex rb:items-center rb:justify-between rb:mb-3">
|
<div className="rb:flex rb:items-center rb:justify-between rb:mb-2">
|
||||||
<span className="rb:font-medium">
|
<div className="rb:text-[12px] rb:leading-4.5">
|
||||||
{caseIndex === 0 ? 'IF' : 'ELIF'}<br/>
|
<span className="rb:font-medium ">{caseIndex === 0 ? 'IF' : 'ELIF'}</span>
|
||||||
{caseFields.length > 1 && <span className="rb:text-[10px] rb:text-[#5B6167]">{`CASE ${caseIndex + 1}`}</span>}
|
{caseFields.length > 1 && <span className="rb:text-[10px] rb:text-[#5B6167]"> ({`CASE ${caseIndex + 1}`})</span>}
|
||||||
</span>
|
</div>
|
||||||
|
|
||||||
<Space>
|
<Space>
|
||||||
<Button
|
<Button
|
||||||
type="dashed"
|
|
||||||
onClick={() => addCondition({})}
|
onClick={() => addCondition({})}
|
||||||
|
className="rb:py-0! rb:px-1! rb:text-[12px]!"
|
||||||
size="small"
|
size="small"
|
||||||
>
|
>
|
||||||
+ {t('workflow.config.addCase')}
|
+ {t('workflow.config.addCase')}
|
||||||
</Button>
|
</Button>
|
||||||
{caseFields.length > 1 && <DeleteOutlined
|
{caseFields.length > 1 &&
|
||||||
className="rb:text-[12px]"
|
<Button
|
||||||
onClick={() => handleRemoveCase(removeCase, caseField.name, caseIndex)}
|
className="rb:py-0! rb:px-1! rb:text-[12px]!"
|
||||||
/>}
|
onClick={() => handleRemoveCase(removeCase, caseField.name, caseIndex)}
|
||||||
|
>
|
||||||
|
{t('common.remove')}
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
{conditionFields?.length > 1 &&
|
{conditionFields?.length > 1 && <div className="rb:absolute rb:top-8 rb:bottom-4 rb:w-8.5 rb:h-[calc(100%-32px)]">
|
||||||
<>
|
<div className="rb:absolute rb:w-2.5 rb:h-[calc(50%-30px)] rb:left-5 rb:top-4 rb:z-10 rb:border-l rb:border-t rb:border-[#DFE4ED] rb:rounded-tl-[10px] rb:border-r-0"></div>
|
||||||
<div className="rb:absolute rb:w-3 rb:left-2 rb:top-15 rb:bottom-6 rb:z-10 rb:border rb:border-[#DFE4ED] rb:rounded-l-md rb:border-r-0"></div>
|
<div className="rb:absolute rb:z-10 rb:left-0 rb:top-[calc(50%-13px)]">
|
||||||
<div className="rb:absolute rb:z-10 rb:left-0 rb:top-[50%] rb:transform-[translateY(-50%)]]">
|
|
||||||
<Form.Item name={[caseField.name, 'logical_operator']} noStyle >
|
<Form.Item name={[caseField.name, 'logical_operator']} noStyle >
|
||||||
<Button size="small" className="rb:cursor-pointer" onClick={() => handleChangeLogicalOperator(caseIndex)}>{logicalOperator}</Button>
|
<Button size="small" className="rb:text-[12px]! rb:py-px! rb:px-1! rb:w-8.5! rb:h-5!" onClick={() => handleChangeLogicalOperator(caseIndex)}>{logicalOperator}</Button>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
</>
|
<div className="rb:absolute rb:w-2.5 rb:h-[calc(50%-30px)] rb:left-5 rb:bottom-4 rb:z-10 rb:border-l rb:border-b rb:border-[#DFE4ED] rb:rounded-bl-[10px] rb:border-r-0"></div>
|
||||||
}
|
</div>}
|
||||||
{conditionFields.map((conditionField, conditionIndex) => {
|
{conditionFields.map((conditionField, conditionIndex) => {
|
||||||
const cases = form.getFieldValue(name) || [];
|
const cases = form.getFieldValue(name) || [];
|
||||||
const currentCase = cases[caseIndex] || {};
|
const currentCase = cases[caseIndex] || {};
|
||||||
@@ -290,91 +292,86 @@ const CaseList: FC<CaseListProps> = ({
|
|||||||
const operatorList = operatorsObj[leftFieldType || 'default'] || operatorsObj.default || [];
|
const operatorList = operatorsObj[leftFieldType || 'default'] || operatorsObj.default || [];
|
||||||
const inputType = leftFieldType === 'number' ? currentExpression.input_type : undefined;
|
const inputType = leftFieldType === 'number' ? currentExpression.input_type : undefined;
|
||||||
return (
|
return (
|
||||||
<div key={conditionField.key} className={clsx({
|
<div key={conditionField.key} className="rb:flex rb:items-start rb:ml-9.5 rb:mb-4">
|
||||||
"rb:mb-3": conditionIndex !== conditionFields.length - 1
|
<div className="rb:flex-1 rb:bg-[#F6F8FC] rb:border rb:border-[#DFE4ED] rb:rounded-md">
|
||||||
})}>
|
<div className={clsx("rb:flex rb:gap-1 rb:p-1", {
|
||||||
<div className="rb:border rb:border-[#DFE4ED] rb:rounded-md rb:px-2 rb:py-1.5 rb:bg-white">
|
'rb:border-b rb:border-b-[#DFE4ED]': !hideRightField
|
||||||
<Row gutter={12} className="rb:mb-1">
|
})}>
|
||||||
<Col span={14}>
|
<Form.Item name={[conditionField.name, 'left']} noStyle>
|
||||||
<Form.Item name={[conditionField.name, 'left']} noStyle>
|
<VariableSelect
|
||||||
<VariableSelect
|
placeholder={t('common.pleaseSelect')}
|
||||||
placeholder={t('common.pleaseSelect')}
|
options={options}
|
||||||
options={options}
|
size="small"
|
||||||
size="small"
|
allowClear={false}
|
||||||
allowClear={false}
|
popupMatchSelectWidth={false}
|
||||||
popupMatchSelectWidth={false}
|
onChange={(val) => handleLeftFieldChange(caseIndex, conditionIndex, val)}
|
||||||
onChange={(val) => handleLeftFieldChange(caseIndex, conditionIndex, val)}
|
className="rb:bg-white! rb:w-29.5!"
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={8}>
|
|
||||||
<Form.Item name={[conditionField.name, 'operator']} noStyle>
|
|
||||||
<Select
|
|
||||||
options={operatorList.map(vo => ({
|
|
||||||
...vo,
|
|
||||||
label: t(String(vo?.label || ''))
|
|
||||||
}))}
|
|
||||||
size="small"
|
|
||||||
popupMatchSelectWidth={false}
|
|
||||||
placeholder={t('common.pleaseSelect')}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={2}>
|
|
||||||
<DeleteOutlined
|
|
||||||
className="rb:text-[12px]"
|
|
||||||
onClick={() => removeCondition(conditionField.name)}
|
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Form.Item>
|
||||||
</Row>
|
<Form.Item name={[conditionField.name, 'operator']} noStyle>
|
||||||
|
<Select
|
||||||
|
options={operatorList.map(vo => ({
|
||||||
|
...vo,
|
||||||
|
label: t(String(vo?.label || ''))
|
||||||
|
}))}
|
||||||
|
size="small"
|
||||||
|
popupMatchSelectWidth={false}
|
||||||
|
placeholder={t('common.pleaseSelect')}
|
||||||
|
className="rb:bg-white! rb:w-22!"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
|
||||||
{!hideRightField && <>
|
{!hideRightField && <div className="rb:p-1">
|
||||||
{leftFieldType === 'number'
|
{leftFieldType === 'number'
|
||||||
? <Row>
|
? <div className="rb:flex rb:items-center">
|
||||||
<Col span={12}>
|
<Form.Item name={[conditionField.name, 'input_type']} noStyle>
|
||||||
<Form.Item name={[conditionField.name, 'input_type']} noStyle>
|
<Select
|
||||||
<Select
|
placeholder={t('common.pleaseSelect')}
|
||||||
|
options={[{ value: 'Variable', label: 'Variable' }, { value: 'Constant', label: 'Constant' }]}
|
||||||
|
popupMatchSelectWidth={false}
|
||||||
|
variant="borderless"
|
||||||
|
onChange={() => handleInputTypeChange(caseIndex, conditionIndex)}
|
||||||
|
className="rb:w-18!"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Divider type="vertical" />
|
||||||
|
<Form.Item name={[conditionField.name, 'right']} noStyle>
|
||||||
|
{inputType === 'Variable'
|
||||||
|
?
|
||||||
|
<VariableSelect
|
||||||
placeholder={t('common.pleaseSelect')}
|
placeholder={t('common.pleaseSelect')}
|
||||||
options={[{ value: 'Variable', label: 'Variable' }, { value: 'Constant', label: 'Constant' }]}
|
options={options.filter(vo => vo.dataType === 'number')}
|
||||||
|
allowClear={false}
|
||||||
popupMatchSelectWidth={false}
|
popupMatchSelectWidth={false}
|
||||||
variant="borderless"
|
variant="borderless"
|
||||||
onChange={() => handleInputTypeChange(caseIndex, conditionIndex)}
|
size="small"
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
: <InputNumber
|
||||||
</Col>
|
placeholder={t('common.pleaseEnter')}
|
||||||
<Col span={12}>
|
|
||||||
<Form.Item name={[conditionField.name, 'right']} noStyle>
|
|
||||||
{inputType === 'Variable'
|
|
||||||
?
|
|
||||||
<VariableSelect
|
|
||||||
placeholder={t('common.pleaseSelect')}
|
|
||||||
options={options.filter(vo => vo.dataType === 'number')}
|
|
||||||
allowClear={false}
|
|
||||||
popupMatchSelectWidth={false}
|
|
||||||
variant="borderless"
|
variant="borderless"
|
||||||
|
className="rb:w-full!"
|
||||||
|
onChange={(value) => form.setFieldValue([name, caseIndex, 'expressions', conditionIndex, 'right'], value)}
|
||||||
/>
|
/>
|
||||||
: <InputNumber
|
}
|
||||||
placeholder={t('common.pleaseEnter')}
|
</Form.Item>
|
||||||
variant="borderless"
|
</div>
|
||||||
className="rb:w-full!"
|
|
||||||
onChange={(value) => form.setFieldValue([name, caseIndex, 'expressions', conditionIndex, 'right'], value)}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
: <Form.Item name={[conditionField.name, 'right']} noStyle>
|
: <Form.Item name={[conditionField.name, 'right']} noStyle>
|
||||||
{leftFieldType === 'boolean'
|
{leftFieldType === 'boolean'
|
||||||
? <Radio.Group block>
|
? <Radio.Group block>
|
||||||
<Radio.Button value={true}>True</Radio.Button>
|
<Radio.Button value={true}>True</Radio.Button>
|
||||||
<Radio.Button value={false}>False</Radio.Button>
|
<Radio.Button value={false}>False</Radio.Button>
|
||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
: <Editor options={options} />
|
: <Editor options={options} size="small" type="input" />
|
||||||
}
|
}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
}
|
}
|
||||||
</>}
|
</div>}
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
className="rb:ml-1 rb:size-4 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/workflow/deleteBg.svg')] rb:hover:bg-[url('@/assets/images/workflow/deleteBg_hover.svg')]"
|
||||||
|
onClick={() => removeCondition(conditionField.name)}
|
||||||
|
></div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
@@ -388,6 +385,8 @@ const CaseList: FC<CaseListProps> = ({
|
|||||||
<Button
|
<Button
|
||||||
type="dashed"
|
type="dashed"
|
||||||
block
|
block
|
||||||
|
size="middle"
|
||||||
|
className="rb:text-[12px]!"
|
||||||
onClick={() => handleAddCase(addCase)}
|
onClick={() => handleAddCase(addCase)}
|
||||||
>
|
>
|
||||||
+ ELIF
|
+ ELIF
|
||||||
@@ -395,9 +394,9 @@ const CaseList: FC<CaseListProps> = ({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Form.List>
|
</Form.List>
|
||||||
<Divider />
|
|
||||||
<div className="rb:font-medium">ELSE</div>
|
<div className="rb:font-medium rb:text-[12px] rb:mt-4 rb:leading-4.5">ELSE</div>
|
||||||
<div className="rb:text-[12px] rb:text-[#5B6167] ">{t('workflow.config.if-else.else_desc')}</div>
|
<div className="rb:text-[12px] rb:text-[#5B6167] rb:mt-2 rb:leading-4.5">{t('workflow.config.if-else.else_desc')}</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { type FC } from 'react';
|
import { type FC } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Button, Form, Space } from 'antd';
|
import { Button, Form, Space } from 'antd';
|
||||||
import { DeleteOutlined } from '@ant-design/icons';
|
|
||||||
import { Graph, Node } from '@antv/x6';
|
import { Graph, Node } from '@antv/x6';
|
||||||
|
|
||||||
import Editor from '../../Editor';
|
import Editor from '../../Editor';
|
||||||
import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin'
|
import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin'
|
||||||
|
|
||||||
@@ -151,17 +151,15 @@ const CategoryList: FC<CategoryListProps> = ({ parentName, selectedNode, graphRe
|
|||||||
const contentLength = (currentItem.class_name || '').length;
|
const contentLength = (currentItem.class_name || '').length;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={key} className="rb:border rb:border-[#DFE4ED] rb:rounded-md rb:p-3 rb:bg-[#F8F9FB]">
|
<div key={key} className="rb:border rb:border-[#DFE4ED] rb:rounded-md rb:p-2 rb:bg-[#F8F9FB]">
|
||||||
<div className="rb:flex rb:items-center rb:justify-between rb:mb-2">
|
<div className="rb:flex rb:items-center rb:justify-between rb:mb-2">
|
||||||
<div>{t('workflow.config.question-classifier.class_name')} {index + 1}</div>
|
<div className="rb:text-[12px] rb:font-medium rb:py-1 rb:leading-2">{t('workflow.config.question-classifier.class_name')} {index + 1}</div>
|
||||||
<div className="rb:flex rb:items-center rb:gap-1">
|
<div className="rb:flex rb:items-center rb:gap-1">
|
||||||
<span className="rb:text-xs rb:text-gray-500">{contentLength}</span>
|
<span className="rb:text-xs rb:text-gray-500">{contentLength}</span>
|
||||||
<Button
|
<div
|
||||||
type="text"
|
className="rb:ml-1 rb:size-4 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/workflow/deleteBg.svg')] rb:hover:bg-[url('@/assets/images/workflow/deleteBg_hover.svg')]"
|
||||||
size="small"
|
|
||||||
icon={<DeleteOutlined />}
|
|
||||||
onClick={() => handleRemoveCategory(remove, name, index)}
|
onClick={() => handleRemoveCategory(remove, name, index)}
|
||||||
/>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
@@ -172,6 +170,7 @@ const CategoryList: FC<CategoryListProps> = ({ parentName, selectedNode, graphRe
|
|||||||
<Editor
|
<Editor
|
||||||
placeholder={t('common.pleaseEnter')}
|
placeholder={t('common.pleaseEnter')}
|
||||||
options={options}
|
options={options}
|
||||||
|
size="small"
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
@@ -179,8 +178,10 @@ const CategoryList: FC<CategoryListProps> = ({ parentName, selectedNode, graphRe
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
type="dashed"
|
type="dashed"
|
||||||
|
size="middle"
|
||||||
|
block
|
||||||
onClick={() => handleAddCategory(add)}
|
onClick={() => handleAddCategory(add)}
|
||||||
className="rb:w-full"
|
className="rb:text-[12px]!"
|
||||||
>
|
>
|
||||||
+ {t('workflow.config.question-classifier.addClassName')}
|
+ {t('workflow.config.question-classifier.addClassName')}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import { type FC } from 'react'
|
import { type FC } from 'react'
|
||||||
|
import clsx from 'clsx'
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Form, Button, Select, Row, Col, InputNumber, Radio, Input, type SelectProps } from 'antd'
|
import { Form, Button, Select, InputNumber, Radio, Input, Divider, type SelectProps } from 'antd'
|
||||||
import { DeleteOutlined } from '@ant-design/icons';
|
|
||||||
|
|
||||||
import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin'
|
import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin'
|
||||||
import VariableSelect from '../VariableSelect'
|
import VariableSelect from '../VariableSelect'
|
||||||
import Editor from '../../Editor'
|
|
||||||
|
|
||||||
interface Case {
|
interface Case {
|
||||||
logical_operator: 'and' | 'or';
|
logical_operator: 'and' | 'or';
|
||||||
@@ -84,52 +83,64 @@ const ConditionList: FC<CaseListProps> = ({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Form.List name={[parentName, 'expressions']}>
|
<Form.List name={[parentName, 'expressions']}>
|
||||||
{(fields, { add, remove }) => (
|
{(fields, { add, remove }) => {
|
||||||
<div>
|
const logicalOperator = form.getFieldValue([parentName, 'logical_operator']);
|
||||||
|
return (
|
||||||
<div className="rb:relative">
|
<div className="rb:relative">
|
||||||
{fields.map((field, index) => {
|
<div className="rb:flex rb:items-center rb:justify-between rb:mb-2">
|
||||||
const expressions = form.getFieldValue([parentName, 'expressions']) || [];
|
<div className="rb:text-[12px] rb:font-medium rb:leading-4.5">
|
||||||
const currentExpression = expressions[index] || {};
|
{t('workflow.config.loop.condition')}
|
||||||
const currentOperator = currentExpression.operator;
|
</div>
|
||||||
const hideRightField = currentOperator === 'empty' || currentOperator === 'not_empty';
|
|
||||||
const leftFieldValue = currentExpression.left;
|
<Button
|
||||||
const leftFieldOption = options.find(option => `{{${option.value}}}` === leftFieldValue);
|
onClick={() => add({})}
|
||||||
const leftFieldType = leftFieldOption?.dataType;
|
className="rb:py-0! rb:px-1! rb:text-[12px]!"
|
||||||
const operatorList = operatorsObj[leftFieldType || 'default'] || operatorsObj.default || [];
|
size="small"
|
||||||
const inputType = leftFieldType === 'number' ? currentExpression.input_type : undefined;
|
>
|
||||||
const logicalOperator = form.getFieldValue([parentName, 'logical_operator']);
|
+ {t('workflow.config.loop.addCondition')}
|
||||||
|
</Button>
|
||||||
return (
|
</div>
|
||||||
<div key={field.key} className="rb:mb-3">
|
{fields?.length > 1 && <div className="rb:absolute rb:top-8 rb:bottom-4 rb:w-8.5 rb:h-[calc(100%-32px)]">
|
||||||
{index > 0 && (<>
|
<div className="rb:absolute rb:w-2.5 rb:h-[calc(50%-30px)] rb:left-5 rb:top-4 rb:z-10 rb:border-l rb:border-t rb:border-[#DFE4ED] rb:rounded-tl-[10px] rb:border-r-0"></div>
|
||||||
<div className="rb:absolute rb:w-3 rb:left-2 rb:top-3.75 rb:bottom-3.75 rb:z-10 rb:border rb:border-[#DFE4ED] rb:rounded-l-md rb:border-r-0"></div>
|
<div className="rb:absolute rb:z-10 rb:left-0 rb:top-[calc(50%-13px)]">
|
||||||
<div className="rb:absolute rb:z-10 rb:left-0 rb:top-[50%] rb:transform-[translateY(-50%)]]">
|
<Form.Item name={[parentName, 'logical_operator']} noStyle >
|
||||||
<Form.Item name={[parentName, 'logical_operator']} noStyle >
|
<Button size="small" className="rb:text-[12px]! rb:py-px! rb:px-1! rb:w-8.5! rb:h-5!" onClick={handleChangeLogicalOperator}>{logicalOperator}</Button>
|
||||||
<Button size="small" className="rb:cursor-pointer" onClick={handleChangeLogicalOperator}>{logicalOperator}</Button>
|
</Form.Item>
|
||||||
</Form.Item>
|
</div>
|
||||||
</div>
|
<div className="rb:absolute rb:w-2.5 rb:h-[calc(50%-30px)] rb:left-5 rb:bottom-4 rb:z-10 rb:border-l rb:border-b rb:border-[#DFE4ED] rb:rounded-bl-[10px] rb:border-r-0"></div>
|
||||||
</>)}
|
</div>}
|
||||||
|
{fields.map((field, index) => {
|
||||||
<div className="rb:border rb:border-[#DFE4ED] rb:rounded-md rb:p-3 rb:bg-white rb:ml-6">
|
const expressions = form.getFieldValue([parentName, 'expressions']) || [];
|
||||||
<Row gutter={8} align="middle">
|
const currentExpression = expressions[index] || {};
|
||||||
<Col span={14}>
|
const currentOperator = currentExpression.operator;
|
||||||
|
const hideRightField = currentOperator === 'empty' || currentOperator === 'not_empty';
|
||||||
|
const leftFieldValue = currentExpression.left;
|
||||||
|
const leftFieldOption = options.find(option => `{{${option.value}}}` === leftFieldValue);
|
||||||
|
const leftFieldType = leftFieldOption?.dataType;
|
||||||
|
const operatorList = operatorsObj[leftFieldType || 'default'] || operatorsObj.default || [];
|
||||||
|
const inputType = leftFieldType === 'number' ? currentExpression.input_type : undefined;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={field.key} className="rb:flex rb:items-start rb:ml-9.5 rb:mb-4">
|
||||||
|
<div className="rb:flex-1 rb:bg-[#F6F8FC] rb:border rb:border-[#DFE4ED] rb:rounded-md">
|
||||||
|
<div className={clsx("rb:flex rb:gap-1 rb:p-1", {
|
||||||
|
'rb:border-b rb:border-b-[#DFE4ED]': !hideRightField
|
||||||
|
})}>
|
||||||
<Form.Item name={[field.name, 'left']} noStyle>
|
<Form.Item name={[field.name, 'left']} noStyle>
|
||||||
<VariableSelect
|
<VariableSelect
|
||||||
options={options.filter(vo =>
|
options={options.filter(vo =>
|
||||||
vo.value.includes('sys.') ||
|
vo.value.includes('sys.') ||
|
||||||
vo.value.includes('conv.') ||
|
vo.value.includes('conv.') ||
|
||||||
vo.nodeData.type === 'loop' ||
|
vo.nodeData.type === 'loop' ||
|
||||||
(vo.nodeData.cycle && vo.nodeData.cycle === selectedNode?.id)
|
(vo.nodeData.cycle && vo.nodeData.cycle === selectedNode?.id)
|
||||||
)}
|
)}
|
||||||
size="small"
|
size="small"
|
||||||
allowClear={false}
|
allowClear={false}
|
||||||
popupMatchSelectWidth={false}
|
popupMatchSelectWidth={false}
|
||||||
|
placeholder={t('common.pleaseSelect')}
|
||||||
onChange={(val) => handleLeftFieldChange(index, val)}
|
onChange={(val) => handleLeftFieldChange(index, val)}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
|
||||||
|
|
||||||
<Col span={8}>
|
|
||||||
<Form.Item name={[field.name, 'operator']} noStyle>
|
<Form.Item name={[field.name, 'operator']} noStyle>
|
||||||
<Select
|
<Select
|
||||||
options={operatorList.map(vo => ({
|
options={operatorList.map(vo => ({
|
||||||
@@ -138,84 +149,67 @@ const ConditionList: FC<CaseListProps> = ({
|
|||||||
}))}
|
}))}
|
||||||
size="small"
|
size="small"
|
||||||
popupMatchSelectWidth={false}
|
popupMatchSelectWidth={false}
|
||||||
|
placeholder={t('common.pleaseSelect')}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</div>
|
||||||
<Col span={2}>
|
|
||||||
<DeleteOutlined
|
|
||||||
className="rb:text-gray-400 rb:cursor-pointer rb:hover:text-red-500"
|
|
||||||
onClick={() => remove(field.name)}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
|
|
||||||
{!hideRightField && <>
|
{!hideRightField && <div className="rb:p-1">
|
||||||
{leftFieldType === 'number'
|
{leftFieldType === 'number'
|
||||||
? <Col span={24}><Row>
|
? <div className="rb:flex rb:items-center">
|
||||||
<Col span={12}>
|
<Form.Item name={[field.name, 'input_type']} noStyle>
|
||||||
<Form.Item name={[field.name, 'input_type']} noStyle>
|
<Select
|
||||||
<Select
|
placeholder={t('common.pleaseSelect')}
|
||||||
|
options={[{ value: 'Variable', label: 'Variable' }, { value: 'Constant', label: 'Constant' }]}
|
||||||
|
popupMatchSelectWidth={false}
|
||||||
|
variant="borderless"
|
||||||
|
className="rb:w-full!"
|
||||||
|
onChange={() => handleInputTypeChange(index)}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Divider type="vertical" />
|
||||||
|
<Form.Item name={[field.name, 'right']} noStyle>
|
||||||
|
{inputType === 'Variable'
|
||||||
|
?
|
||||||
|
<VariableSelect
|
||||||
placeholder={t('common.pleaseSelect')}
|
placeholder={t('common.pleaseSelect')}
|
||||||
options={[{ value: 'Variable', label: 'Variable' }, { value: 'Constant', label: 'Constant' }]}
|
options={options.filter(vo => vo.dataType === 'number')}
|
||||||
|
allowClear={false}
|
||||||
popupMatchSelectWidth={false}
|
popupMatchSelectWidth={false}
|
||||||
variant="borderless"
|
variant="borderless"
|
||||||
className="rb:w-full!"
|
className="rb:w-full!"
|
||||||
onChange={() => handleInputTypeChange(index)}
|
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
: <InputNumber
|
||||||
</Col>
|
placeholder={t('common.pleaseEnter')}
|
||||||
<Col span={12}>
|
variant="borderless"
|
||||||
<Form.Item name={[field.name, 'right']} noStyle>
|
className="rb:w-full!"
|
||||||
{inputType === 'Variable'
|
onChange={(value) => form.setFieldValue([parentName, 'expressions', index, 'right'], value)}
|
||||||
?
|
/>
|
||||||
<VariableSelect
|
|
||||||
placeholder={t('common.pleaseSelect')}
|
|
||||||
options={options.filter(vo => vo.dataType === 'number')}
|
|
||||||
allowClear={false}
|
|
||||||
popupMatchSelectWidth={false}
|
|
||||||
variant="borderless"
|
|
||||||
className="rb:w-full!"
|
|
||||||
/>
|
|
||||||
: <InputNumber
|
|
||||||
placeholder={t('common.pleaseEnter')}
|
|
||||||
variant="borderless"
|
|
||||||
className="rb:w-full!"
|
|
||||||
onChange={(value) => form.setFieldValue([parentName, 'expressions', index, 'right'], value)}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
</Row></Col>
|
|
||||||
: <Col span={24}>
|
|
||||||
<Form.Item name={[field.name, 'right']} noStyle>
|
|
||||||
{leftFieldType === 'boolean'
|
|
||||||
? <Radio.Group block>
|
|
||||||
<Radio.Button value={true}>True</Radio.Button>
|
|
||||||
<Radio.Button value={false}>False</Radio.Button>
|
|
||||||
</Radio.Group>
|
|
||||||
: <Input placeholder={t('common.pleaseEnter')} />
|
|
||||||
}
|
}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</div>
|
||||||
|
: <Form.Item name={[field.name, 'right']} noStyle>
|
||||||
|
{leftFieldType === 'boolean'
|
||||||
|
? <Radio.Group block>
|
||||||
|
<Radio.Button value={true}>True</Radio.Button>
|
||||||
|
<Radio.Button value={false}>False</Radio.Button>
|
||||||
|
</Radio.Group>
|
||||||
|
: <Input placeholder={t('common.pleaseEnter')} />
|
||||||
|
}
|
||||||
|
</Form.Item>
|
||||||
}
|
}
|
||||||
</>}
|
</div>}
|
||||||
|
</div>
|
||||||
</Row>
|
<div
|
||||||
|
className="rb:ml-1 rb:size-4 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/workflow/deleteBg.svg')] rb:hover:bg-[url('@/assets/images/workflow/deleteBg_hover.svg')]"
|
||||||
|
onClick={() => remove(field.name)}
|
||||||
|
></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)
|
||||||
)
|
})}
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
<Button
|
}}
|
||||||
type="dashed"
|
|
||||||
onClick={() => add({ left: '', operator: '', right: '' })}
|
|
||||||
className="rb:w-full rb:ml-6 rb:mt-2"
|
|
||||||
icon={<span>+</span>}
|
|
||||||
>
|
|
||||||
添加条件
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Form.List>
|
</Form.List>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { type FC } from 'react'
|
import { type FC } from 'react'
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Form, Select, Row, Col, Input } from 'antd'
|
import { Form, Select, Input, Button } from 'antd'
|
||||||
import { DeleteOutlined, PlusOutlined } from '@ant-design/icons';
|
|
||||||
import VariableSelect from '../VariableSelect'
|
import VariableSelect from '../VariableSelect'
|
||||||
|
|
||||||
import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin'
|
import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin'
|
||||||
@@ -20,6 +19,7 @@ interface CycleVarsListProps {
|
|||||||
parentName: string;
|
parentName: string;
|
||||||
selectedNode?: any;
|
selectedNode?: any;
|
||||||
graphRef?: any;
|
graphRef?: any;
|
||||||
|
size?: 'small' | 'middle'
|
||||||
}
|
}
|
||||||
|
|
||||||
const types = [
|
const types = [
|
||||||
@@ -37,7 +37,8 @@ const CycleVarsList: FC<CycleVarsListProps> = ({
|
|||||||
options,
|
options,
|
||||||
parentName,
|
parentName,
|
||||||
selectedNode,
|
selectedNode,
|
||||||
graphRef
|
graphRef,
|
||||||
|
size = 'middle'
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const form = Form.useFormInstance();
|
const form = Form.useFormInstance();
|
||||||
@@ -78,62 +79,56 @@ const CycleVarsList: FC<CycleVarsListProps> = ({
|
|||||||
const availableOptions = getChildNodeVariables();
|
const availableOptions = getChildNodeVariables();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<Form.List name={parentName}>
|
||||||
|
{(fields, { add, remove }) => (
|
||||||
<Form.List name={parentName}>
|
<>
|
||||||
{(fields, { add, remove }) => (
|
<div className="rb:flex rb:items-center rb:justify-between rb:mb-3">
|
||||||
<>
|
<span className="rb:text-[12px] rb:font-medium">{t('workflow.config.loop.cycle_vars')}</span>
|
||||||
<div className="rb:flex rb:items-center rb:justify-between rb:mb-3">
|
<Button
|
||||||
<span className="rb:text-sm rb:font-medium">循环变量</span>
|
onClick={() => add({ name: '', type: 'string', input_type: 'constant', value: '' })}
|
||||||
<PlusOutlined className="rb:text-gray-400 rb:cursor-pointer rb:hover:text-blue-500" onClick={() => add({ name: '', type: 'string', input_type: 'constant', value: '' })} />
|
className="rb:py-0! rb:px-1! rb:text-[12px]!"
|
||||||
</div>
|
size="small"
|
||||||
{fields.map(({ key, name, ...field }, index) => {
|
>
|
||||||
const currentInputType = value?.[index]?.input_type;
|
+ {t('workflow.config.addVariable')}
|
||||||
|
</Button>
|
||||||
return (
|
</div>
|
||||||
<div key={key} className="rb:mb-3 rb:border rb:border-[#DFE4ED] rb:rounded-md rb:p-3 rb:bg-white">
|
{fields.map(({ key, name }, index) => {
|
||||||
<Row gutter={8} align="middle" className="rb:mb-2">
|
const currentInputType = value?.[index]?.input_type;
|
||||||
<Col span={8}>
|
|
||||||
<Form.Item name={[name, 'name']} noStyle>
|
return (
|
||||||
<Input size="small" />
|
<div key={key} className="rb:flex rb:items-start rb:mb-2">
|
||||||
</Form.Item>
|
<div className="rb:flex-1 rb:bg-[#F6F8FC] rb:border rb:border-[#DFE4ED] rb:rounded-md">
|
||||||
</Col>
|
<div className="rb:flex rb:gap-1 rb:p-1 rb:border-b rb:border-b-[#DFE4ED]">
|
||||||
<Col span={6}>
|
<Form.Item name={[name, 'name']} noStyle>
|
||||||
<Form.Item name={[name, 'type']} noStyle>
|
<Input size={size} className="rb:w-23!" placeholder={t('common.pleaseEnter')} />
|
||||||
<Select
|
</Form.Item>
|
||||||
options={types.map(key => ({
|
<Form.Item name={[name, 'type']} noStyle>
|
||||||
value: key,
|
<Select
|
||||||
label: t(`workflow.config.parameter-extractor.${key}`),
|
options={types.map(key => ({
|
||||||
}))}
|
value: key,
|
||||||
size="small"
|
label: t(`workflow.config.parameter-extractor.${key}`),
|
||||||
popupMatchSelectWidth={false}
|
}))}
|
||||||
/>
|
size={size}
|
||||||
</Form.Item>
|
popupMatchSelectWidth={false}
|
||||||
</Col>
|
className="rb:w-18.5!"
|
||||||
<Col span={8}>
|
|
||||||
<Form.Item name={[name, 'input_type']} noStyle>
|
|
||||||
<Select
|
|
||||||
placeholder="Constant"
|
|
||||||
options={[
|
|
||||||
{ label: 'Constant', value: 'constant' },
|
|
||||||
{ label: 'Variable', value: 'variable' }
|
|
||||||
]}
|
|
||||||
size="small"
|
|
||||||
popupMatchSelectWidth={false}
|
|
||||||
onChange={() => {
|
|
||||||
// 重置 value 字段
|
|
||||||
form.setFieldValue([parentName, index, 'value'], undefined);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={2}>
|
|
||||||
<DeleteOutlined
|
|
||||||
className="rb:text-gray-400 rb:cursor-pointer rb:hover:text-red-500"
|
|
||||||
onClick={() => remove(name)}
|
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Form.Item>
|
||||||
</Row>
|
<Form.Item name={[name, 'input_type']} noStyle>
|
||||||
|
<Select
|
||||||
|
placeholder="Constant"
|
||||||
|
options={[
|
||||||
|
{ label: 'Constant', value: 'constant' },
|
||||||
|
{ label: 'Variable', value: 'variable' }
|
||||||
|
]}
|
||||||
|
size={size}
|
||||||
|
popupMatchSelectWidth={false}
|
||||||
|
onChange={() => {
|
||||||
|
form.setFieldValue([parentName, index, 'value'], undefined);
|
||||||
|
}}
|
||||||
|
className="rb:w-18!"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Form.Item name={[name, 'value']} noStyle>
|
<Form.Item name={[name, 'value']} noStyle>
|
||||||
{currentInputType === 'variable' ? (
|
{currentInputType === 'variable' ? (
|
||||||
@@ -145,22 +140,29 @@ const CycleVarsList: FC<CycleVarsListProps> = ({
|
|||||||
|
|
||||||
return option.dataType === currentType
|
return option.dataType === currentType
|
||||||
})}
|
})}
|
||||||
|
variant="borderless"
|
||||||
|
size="small"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Input.TextArea
|
<Input.TextArea
|
||||||
placeholder={t('common.pleaseEnter')}
|
placeholder={t('common.pleaseEnter')}
|
||||||
rows={3}
|
rows={3}
|
||||||
className="rb:w-full"
|
className="rb:w-full"
|
||||||
|
variant="borderless"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
)
|
<div
|
||||||
})}
|
className="rb:ml-1 rb:size-4 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/workflow/deleteBg.svg')] rb:hover:bg-[url('@/assets/images/workflow/deleteBg_hover.svg')]"
|
||||||
</>
|
onClick={() => remove(name)}
|
||||||
)}
|
></div>
|
||||||
</Form.List>
|
</div>
|
||||||
</div>
|
)
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Form.List>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { type FC } from 'react'
|
import { type FC } from 'react'
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Form, Input, Button, Row, Col } from 'antd'
|
import { Form, Input, Button, Row, Col } from 'antd'
|
||||||
import { MinusCircleOutlined } from '@ant-design/icons';
|
|
||||||
import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin'
|
import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin'
|
||||||
import VariableSelect from '../VariableSelect'
|
import VariableSelect from '../VariableSelect'
|
||||||
|
|
||||||
@@ -9,13 +9,15 @@ interface GroupVariableListProps {
|
|||||||
value?: Array<{ key: string; value: string[]; }>;
|
value?: Array<{ key: string; value: string[]; }>;
|
||||||
name: string;
|
name: string;
|
||||||
options: Suggestion[];
|
options: Suggestion[];
|
||||||
isCanAdd: boolean
|
isCanAdd: boolean;
|
||||||
|
size: 'small' | 'middle'
|
||||||
}
|
}
|
||||||
|
|
||||||
const GroupVariableList: FC<GroupVariableListProps> = ({
|
const GroupVariableList: FC<GroupVariableListProps> = ({
|
||||||
name,
|
name,
|
||||||
options = [],
|
options = [],
|
||||||
isCanAdd = false
|
isCanAdd = false,
|
||||||
|
size = "middle"
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const form = Form.useFormInstance();
|
const form = Form.useFormInstance();
|
||||||
@@ -54,6 +56,7 @@ const GroupVariableList: FC<GroupVariableListProps> = ({
|
|||||||
placeholder={t('common.pleaseSelect')}
|
placeholder={t('common.pleaseSelect')}
|
||||||
options={filteredOptions}
|
options={filteredOptions}
|
||||||
mode="multiple"
|
mode="multiple"
|
||||||
|
size={size}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
@@ -76,11 +79,15 @@ const GroupVariableList: FC<GroupVariableListProps> = ({
|
|||||||
]}
|
]}
|
||||||
noStyle
|
noStyle
|
||||||
>
|
>
|
||||||
{isCanAdd ? <Input placeholder={t('common.pleaseEnter')} /> : t('workflow.config.var-aggregator.variable')}
|
{isCanAdd ? <Input placeholder={t('common.pleaseEnter')} size={size} /> : t('workflow.config.var-aggregator.variable')}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
{isCanAdd && <Col span={12} className="rb:flex! rb:items-center rb:justify-end">
|
{isCanAdd && <Col span={12} className="rb:flex! rb:items-center rb:justify-end">
|
||||||
<MinusCircleOutlined onClick={() => remove(name)} />
|
<div
|
||||||
|
className="rb:ml-1 rb:size-4 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/workflow/deleteBg.svg')] rb:hover:bg-[url('@/assets/images/workflow/deleteBg_hover.svg')]"
|
||||||
|
onClick={() => remove(name)}
|
||||||
|
></div>
|
||||||
</Col>}
|
</Col>}
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
@@ -104,16 +111,22 @@ const GroupVariableList: FC<GroupVariableListProps> = ({
|
|||||||
})()
|
})()
|
||||||
}
|
}
|
||||||
mode="multiple"
|
mode="multiple"
|
||||||
|
size={size}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
{isCanAdd && <Form.Item noStyle>
|
|
||||||
<Button type="dashed" onClick={() => add({ key: `Group${fields.length + 1}` })} block>
|
{isCanAdd && <Button
|
||||||
+ {t('workflow.config.var-aggregator.addGroup')}
|
type="dashed"
|
||||||
</Button>
|
block
|
||||||
</Form.Item>}
|
size="middle"
|
||||||
|
className="rb:text-[12px]!"
|
||||||
|
onClick={() => add({ key: `Group${fields.length + 1}` })}
|
||||||
|
>
|
||||||
|
+ {t('workflow.config.var-aggregator.addGroup')}
|
||||||
|
</Button>}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Form.List>
|
</Form.List>
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ const AuthConfigModal = forwardRef<AuthConfigModalRef, AuthConfigModalProps>(({
|
|||||||
initialValues={{
|
initialValues={{
|
||||||
auth: 'none'
|
auth: 'none'
|
||||||
}}
|
}}
|
||||||
|
size="middle"
|
||||||
>
|
>
|
||||||
<FormItem
|
<FormItem
|
||||||
name="auth"
|
name="auth"
|
||||||
@@ -102,6 +103,7 @@ const AuthConfigModal = forwardRef<AuthConfigModalRef, AuthConfigModalProps>(({
|
|||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
|
size="middle"
|
||||||
options={[
|
options={[
|
||||||
{ value: 'none', label: t('workflow.config.http-request.none') },
|
{ value: 'none', label: t('workflow.config.http-request.none') },
|
||||||
{ value: 'api_key', label: t('workflow.config.http-request.apiKey') },
|
{ value: 'api_key', label: t('workflow.config.http-request.apiKey') },
|
||||||
@@ -117,6 +119,7 @@ const AuthConfigModal = forwardRef<AuthConfigModalRef, AuthConfigModalProps>(({
|
|||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
|
size="middle"
|
||||||
options={[
|
options={[
|
||||||
{ value: 'basic', label: t('workflow.config.http-request.basic') },
|
{ value: 'basic', label: t('workflow.config.http-request.basic') },
|
||||||
{ value: 'bearer', label: t('workflow.config.http-request.bearer') },
|
{ value: 'bearer', label: t('workflow.config.http-request.bearer') },
|
||||||
@@ -132,7 +135,7 @@ const AuthConfigModal = forwardRef<AuthConfigModalRef, AuthConfigModalProps>(({
|
|||||||
{ required: true, message: t('common.pleaseEnter') }
|
{ required: true, message: t('common.pleaseEnter') }
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Input placeholder={t('common.pleaseEnter')} />
|
<Input size="middle" placeholder={t('common.pleaseEnter')} />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
}
|
}
|
||||||
<FormItem
|
<FormItem
|
||||||
@@ -142,7 +145,7 @@ const AuthConfigModal = forwardRef<AuthConfigModalRef, AuthConfigModalProps>(({
|
|||||||
{ required: true, message: t('common.pleaseEnter') }
|
{ required: true, message: t('common.pleaseEnter') }
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Input placeholder={t('common.pleaseEnter')} />
|
<Input size="middle" placeholder={t('common.pleaseEnter')} />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</>}
|
</>}
|
||||||
</Form>
|
</Form>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { useMemo } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Button, Select, Table, Form, type TableProps } from 'antd';
|
import { Button, Select, Table, Form, type TableProps } from 'antd';
|
||||||
import { PlusOutlined, DeleteOutlined } from '@ant-design/icons';
|
import { PlusOutlined } from '@ant-design/icons';
|
||||||
import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin';
|
import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin';
|
||||||
import Empty from '@/components/Empty';
|
import Empty from '@/components/Empty';
|
||||||
import VariableSelect from '../VariableSelect';
|
import VariableSelect from '../VariableSelect';
|
||||||
@@ -19,6 +18,7 @@ interface EditableTableProps {
|
|||||||
options?: Suggestion[];
|
options?: Suggestion[];
|
||||||
typeOptions?: { value: string, label: string }[]
|
typeOptions?: { value: string, label: string }[]
|
||||||
filterBooleanType?: boolean;
|
filterBooleanType?: boolean;
|
||||||
|
size?: "small"
|
||||||
}
|
}
|
||||||
|
|
||||||
const EditableTable: React.FC<EditableTableProps> = ({
|
const EditableTable: React.FC<EditableTableProps> = ({
|
||||||
@@ -26,7 +26,8 @@ const EditableTable: React.FC<EditableTableProps> = ({
|
|||||||
title,
|
title,
|
||||||
options = [],
|
options = [],
|
||||||
typeOptions = [],
|
typeOptions = [],
|
||||||
filterBooleanType = false
|
filterBooleanType = false,
|
||||||
|
size = 'small'
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@@ -38,21 +39,24 @@ const EditableTable: React.FC<EditableTableProps> = ({
|
|||||||
|
|
||||||
const getColumns = (remove: (index: number) => void): TableProps<TableRow>['columns'] => {
|
const getColumns = (remove: (index: number) => void): TableProps<TableRow>['columns'] => {
|
||||||
const hasType = typeOptions.length > 0;
|
const hasType = typeOptions.length > 0;
|
||||||
const baseWidth = hasType ? '35%' : '45%';
|
const cellClassName="rb:p-1!"
|
||||||
|
const contentClassName ="rb:w-[108px]! rb:text-[12px]!"
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
title: t('workflow.config.name'),
|
title: t('workflow.config.name'),
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
width: baseWidth,
|
className: cellClassName,
|
||||||
render: (_: any, __: TableRow, index: number) => (
|
render: (_: any, __: TableRow, index: number) => (
|
||||||
<Form.Item name={[index, 'name']} noStyle>
|
<Form.Item name={[index, 'name']} noStyle>
|
||||||
<VariableSelect
|
<VariableSelect
|
||||||
placeholder={t('common.pleaseSelect')}
|
placeholder={t('common.pleaseSelect')}
|
||||||
size="small"
|
// size="small"
|
||||||
options={options}
|
options={options}
|
||||||
filterBooleanType={filterBooleanType}
|
filterBooleanType={filterBooleanType}
|
||||||
popupMatchSelectWidth={false}
|
popupMatchSelectWidth={false}
|
||||||
|
className={contentClassName}
|
||||||
|
size={size}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
)
|
)
|
||||||
@@ -61,18 +65,20 @@ const EditableTable: React.FC<EditableTableProps> = ({
|
|||||||
title: t('workflow.config.type'),
|
title: t('workflow.config.type'),
|
||||||
dataIndex: 'type',
|
dataIndex: 'type',
|
||||||
width: '20%',
|
width: '20%',
|
||||||
|
className: cellClassName,
|
||||||
render: (_: any, __: TableRow, index: number) => (
|
render: (_: any, __: TableRow, index: number) => (
|
||||||
<Form.Item shouldUpdate noStyle>
|
<Form.Item shouldUpdate noStyle>
|
||||||
{(form) => (
|
{(form) => (
|
||||||
<Form.Item name={[index, 'type']} noStyle>
|
<Form.Item name={[index, 'type']} noStyle>
|
||||||
<Select
|
<Select
|
||||||
placeholder={t('common.pleaseSelect')}
|
placeholder={t('common.pleaseSelect')}
|
||||||
size="small"
|
// size="small"
|
||||||
options={typeOptions}
|
options={typeOptions}
|
||||||
popupMatchSelectWidth={false}
|
popupMatchSelectWidth={false}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
form.setFieldValue([...Array.isArray(parentName) ? parentName : [parentName], index, 'value'], undefined);
|
form.setFieldValue([...Array.isArray(parentName) ? parentName : [parentName], index, 'value'], undefined);
|
||||||
}}
|
}}
|
||||||
|
size={size}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
)}
|
)}
|
||||||
@@ -82,7 +88,7 @@ const EditableTable: React.FC<EditableTableProps> = ({
|
|||||||
{
|
{
|
||||||
title: t('workflow.config.value'),
|
title: t('workflow.config.value'),
|
||||||
dataIndex: 'value',
|
dataIndex: 'value',
|
||||||
width: baseWidth,
|
className: cellClassName,
|
||||||
render: (_: any, __: TableRow, index: number) => (
|
render: (_: any, __: TableRow, index: number) => (
|
||||||
<Form.Item
|
<Form.Item
|
||||||
shouldUpdate={(prevValues, currentValues) => {
|
shouldUpdate={(prevValues, currentValues) => {
|
||||||
@@ -102,10 +108,12 @@ const EditableTable: React.FC<EditableTableProps> = ({
|
|||||||
<Form.Item name={[index, 'value']} noStyle>
|
<Form.Item name={[index, 'value']} noStyle>
|
||||||
<VariableSelect
|
<VariableSelect
|
||||||
placeholder={t('common.pleaseSelect')}
|
placeholder={t('common.pleaseSelect')}
|
||||||
size="small"
|
// size="small"
|
||||||
options={filteredOptions}
|
options={filteredOptions}
|
||||||
filterBooleanType={filterBooleanType}
|
filterBooleanType={filterBooleanType}
|
||||||
popupMatchSelectWidth={false}
|
popupMatchSelectWidth={false}
|
||||||
|
className={contentClassName}
|
||||||
|
size={size}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
@@ -116,9 +124,12 @@ const EditableTable: React.FC<EditableTableProps> = ({
|
|||||||
{
|
{
|
||||||
title: '',
|
title: '',
|
||||||
dataIndex: 'actions',
|
dataIndex: 'actions',
|
||||||
width: '10%',
|
className: cellClassName,
|
||||||
render: (_: any, __: TableRow, index: number) => (
|
render: (_: any, __: TableRow, index: number) => (
|
||||||
<Button type="text" icon={<DeleteOutlined />} onClick={() => remove(index)} />
|
<div
|
||||||
|
className="rb:ml-1 rb:size-4 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/workflow/deleteBg.svg')] rb:hover:bg-[url('@/assets/images/workflow/deleteBg_hover.svg')]"
|
||||||
|
onClick={() => remove(index)}
|
||||||
|
></div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@@ -129,13 +140,11 @@ const EditableTable: React.FC<EditableTableProps> = ({
|
|||||||
<Form.List name={parentName}>
|
<Form.List name={parentName}>
|
||||||
{(fields, { add, remove }) => {
|
{(fields, { add, remove }) => {
|
||||||
const AddButton = ({ block = false }: { block?: boolean }) => (
|
const AddButton = ({ block = false }: { block?: boolean }) => (
|
||||||
<Button
|
<Button
|
||||||
type={block ? "dashed" : "text"}
|
|
||||||
icon={block ? undefined : <PlusOutlined />}
|
icon={block ? undefined : <PlusOutlined />}
|
||||||
onClick={() => add(createNewRow())}
|
onClick={() => add(createNewRow())}
|
||||||
size="small"
|
size="small"
|
||||||
block={block}
|
className={block ? "rb:mt-1 rb:text-[12px]! rb:bg-transparent!" : "rb:text-[12px]!"}
|
||||||
className={block ? "rb:mt-1" : ""}
|
|
||||||
>
|
>
|
||||||
{block && `+${t('common.add')}`}
|
{block && `+${t('common.add')}`}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -145,8 +154,8 @@ const EditableTable: React.FC<EditableTableProps> = ({
|
|||||||
<>
|
<>
|
||||||
{title && (
|
{title && (
|
||||||
<div className="rb:flex rb:items-center rb:mb-2 rb:justify-between">
|
<div className="rb:flex rb:items-center rb:mb-2 rb:justify-between">
|
||||||
<div className="rb:font-medium">{title}</div>
|
<div className="rb:font-medium rb:text-[12px] rb:leading-4.5">{title}</div>
|
||||||
<AddButton />
|
<AddButton block={true} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -161,8 +170,9 @@ const EditableTable: React.FC<EditableTableProps> = ({
|
|||||||
columns={getColumns(remove)}
|
columns={getColumns(remove)}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
size="small"
|
size="small"
|
||||||
|
rowClassName="rb:p-0! rb:bg-[#F6F8FC]!"
|
||||||
locale={{ emptyText: <Empty size={88} /> }}
|
locale={{ emptyText: <Empty size={88} /> }}
|
||||||
scroll={{ x: 'max-content' }}
|
style={{ width: '274px' }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{!title && <AddButton block />}
|
{!title && <AddButton block />}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { type FC, useRef } from "react";
|
import { type FC, useRef, useState } from "react";
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Form, Row, Col, Select, Button, Divider, InputNumber, Switch, Input } from 'antd'
|
import { Form, Row, Col, Select, Button, Divider, InputNumber, Switch, Input } from 'antd'
|
||||||
|
import { CaretDownOutlined, CaretRightOutlined, SettingOutlined } from '@ant-design/icons';
|
||||||
import Editor from '../../Editor'
|
import Editor from '../../Editor'
|
||||||
import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin'
|
import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin'
|
||||||
import AuthConfigModal from './AuthConfigModal'
|
import AuthConfigModal from './AuthConfigModal'
|
||||||
@@ -65,15 +66,23 @@ const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: an
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('HttpRequest', values)
|
const [collapsed, setCollapsed] = useState(true)
|
||||||
|
const handleToggle = () => {
|
||||||
|
setCollapsed((prev: boolean) => !prev)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="rb:flex rb:items-center rb:justify-between rb:mb-4">
|
<div className="rb:flex rb:items-center rb:justify-between rb:mb-1">
|
||||||
<div>API</div>
|
<div className="rb:font-medium rb:text-[12px] rb:leading-4.5">API</div>
|
||||||
<Button onClick={handleChangeAuth}>{t('workflow.config.http-request.auth')}</Button>
|
<Button onClick={handleChangeAuth}
|
||||||
|
size="small"
|
||||||
|
type="text"
|
||||||
|
icon={<SettingOutlined />}
|
||||||
|
className="rb:mt-1 rb:text-[12px]!"
|
||||||
|
>{t('workflow.config.http-request.auth')}: {!values?.auth?.auth_type || values?.auth?.auth_type === 'none' ? t('workflow.config.http-request.none') : t('workflow.config.http-request.apiKey')}</Button>
|
||||||
</div>
|
</div>
|
||||||
<Row gutter={16}>
|
<Row gutter={4}>
|
||||||
<Col span={8}>
|
<Col span={8}>
|
||||||
<Form.Item name="method">
|
<Form.Item name="method">
|
||||||
<Select
|
<Select
|
||||||
@@ -85,35 +94,43 @@ const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: an
|
|||||||
{ label: 'PUT', value: 'PUT' },
|
{ label: 'PUT', value: 'PUT' },
|
||||||
{ label: 'DELETE', value: 'DELETE' },
|
{ label: 'DELETE', value: 'DELETE' },
|
||||||
]}
|
]}
|
||||||
|
className="rb:bg-transparent!"
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={16}>
|
<Col span={16}>
|
||||||
<Form.Item name="url">
|
<Form.Item name="url">
|
||||||
<Editor options={options.filter(vo => vo.dataType === 'string' || vo.dataType === 'number')} variant="outlined" />
|
<Editor
|
||||||
|
options={options.filter(vo => vo.dataType === 'string' || vo.dataType === 'number')}
|
||||||
|
variant="outlined"
|
||||||
|
type="input"
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Form.Item name="auth" hidden>
|
<Form.Item name="auth" hidden>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item name="headers">
|
<Form.Item name="headers" noStyle>
|
||||||
<EditableTable
|
<EditableTable
|
||||||
|
size="small"
|
||||||
parentName="headers"
|
parentName="headers"
|
||||||
title="HEADERS"
|
title="HEADERS"
|
||||||
options={options.filter(vo => vo.dataType === 'string' || vo.dataType === 'number')}
|
options={options.filter(vo => vo.dataType === 'string' || vo.dataType === 'number')}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item name="params">
|
<Form.Item name="params" noStyle>
|
||||||
<EditableTable
|
<EditableTable
|
||||||
|
size="small"
|
||||||
parentName="params"
|
parentName="params"
|
||||||
title="PARAMS"
|
title="PARAMS"
|
||||||
options={options.filter(vo => vo.dataType === 'string' || vo.dataType === 'number')}
|
options={options.filter(vo => vo.dataType === 'string' || vo.dataType === 'number')}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item label="BODY">
|
<Form.Item label="BODY" className="rb:mb-0!">
|
||||||
<Form.Item name={['body', 'content_type']}>
|
<Form.Item name={['body', 'content_type']}>
|
||||||
<Select
|
<Select
|
||||||
placeholder={t('common.pleaseSelect')}
|
placeholder={t('common.pleaseSelect')}
|
||||||
@@ -131,6 +148,7 @@ const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: an
|
|||||||
{values?.body?.content_type === 'form-data' &&
|
{values?.body?.content_type === 'form-data' &&
|
||||||
<Form.Item name={['body', 'data']} noStyle>
|
<Form.Item name={['body', 'data']} noStyle>
|
||||||
<EditableTable
|
<EditableTable
|
||||||
|
size="small"
|
||||||
parentName={['body', 'data']}
|
parentName={['body', 'data']}
|
||||||
options={options.filter(vo => vo.dataType === 'string' || vo.dataType === 'number')}
|
options={options.filter(vo => vo.dataType === 'string' || vo.dataType === 'number')}
|
||||||
typeOptions={[
|
typeOptions={[
|
||||||
@@ -143,6 +161,7 @@ const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: an
|
|||||||
{values?.body?.content_type === 'x-www-form-urlencoded' &&
|
{values?.body?.content_type === 'x-www-form-urlencoded' &&
|
||||||
<Form.Item name={['body', 'data']} noStyle>
|
<Form.Item name={['body', 'data']} noStyle>
|
||||||
<EditableTable
|
<EditableTable
|
||||||
|
size="small"
|
||||||
parentName={['body', 'data']}
|
parentName={['body', 'data']}
|
||||||
options={options.filter(vo => vo.dataType === 'string' || vo.dataType === 'number')}
|
options={options.filter(vo => vo.dataType === 'string' || vo.dataType === 'number')}
|
||||||
filterBooleanType={true}
|
filterBooleanType={true}
|
||||||
@@ -150,7 +169,7 @@ const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: an
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
}
|
}
|
||||||
{values?.body?.content_type === 'json' &&
|
{values?.body?.content_type === 'json' &&
|
||||||
<Form.Item name={['body', 'data']}>
|
<Form.Item name={['body', 'data']} noStyle>
|
||||||
<MessageEditor
|
<MessageEditor
|
||||||
key="json"
|
key="json"
|
||||||
parentName={['body', 'data']}
|
parentName={['body', 'data']}
|
||||||
@@ -161,7 +180,7 @@ const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: an
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
}
|
}
|
||||||
{values?.body?.content_type === 'raw' &&
|
{values?.body?.content_type === 'raw' &&
|
||||||
<Form.Item name={['body', 'data']}>
|
<Form.Item name={['body', 'data']} noStyle>
|
||||||
<MessageEditor
|
<MessageEditor
|
||||||
key="raw"
|
key="raw"
|
||||||
parentName={['body', 'data']}
|
parentName={['body', 'data']}
|
||||||
@@ -172,7 +191,7 @@ const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: an
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
}
|
}
|
||||||
{values?.body?.content_type === 'binary' &&
|
{values?.body?.content_type === 'binary' &&
|
||||||
<Form.Item name={['body', 'data']}>
|
<Form.Item name={['body', 'data']} noStyle>
|
||||||
<VariableSelect
|
<VariableSelect
|
||||||
placeholder={t('common.pleaseSelect')}
|
placeholder={t('common.pleaseSelect')}
|
||||||
options={options.filter(vo => vo.dataType.includes('file'))}
|
options={options.filter(vo => vo.dataType.includes('file'))}
|
||||||
@@ -182,15 +201,19 @@ const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: an
|
|||||||
}
|
}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Form.Item layout="horizontal" name="verify_ssl" label={t('workflow.config.http-request.verify_ssl')}>
|
<Form.Item layout="horizontal" name="verify_ssl" label={t('workflow.config.http-request.verify_ssl')} className="rb:mb-0!">
|
||||||
<Switch />
|
<Switch />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
<div>{t('workflow.config.http-request.timeouts')}</div>
|
<div className="rb:font-medium rb:text-[12px] rb:leading-4.5 rb:mb-2.5 rb:cursor-pointer" onClick={handleToggle}>
|
||||||
|
{t('workflow.config.http-request.timeouts')}
|
||||||
|
{collapsed ? <CaretRightOutlined /> : <CaretDownOutlined />}
|
||||||
|
</div>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name={['timeouts', 'connect_timeout']}
|
name={['timeouts', 'connect_timeout']}
|
||||||
label={t('workflow.config.http-request.connect_timeout')}
|
label={t('workflow.config.http-request.connect_timeout')}
|
||||||
|
hidden={collapsed}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
placeholder={t('common.pleaseEnter')}
|
placeholder={t('common.pleaseEnter')}
|
||||||
@@ -201,6 +224,7 @@ const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: an
|
|||||||
<Form.Item
|
<Form.Item
|
||||||
name={['timeouts', 'read_timeout']}
|
name={['timeouts', 'read_timeout']}
|
||||||
label={t('workflow.config.http-request.read_timeout')}
|
label={t('workflow.config.http-request.read_timeout')}
|
||||||
|
hidden={collapsed}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
placeholder={t('common.pleaseEnter')}
|
placeholder={t('common.pleaseEnter')}
|
||||||
@@ -211,6 +235,7 @@ const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: an
|
|||||||
<Form.Item
|
<Form.Item
|
||||||
name={['timeouts', 'write_timeout']}
|
name={['timeouts', 'write_timeout']}
|
||||||
label={t('workflow.config.http-request.write_timeout')}
|
label={t('workflow.config.http-request.write_timeout')}
|
||||||
|
hidden={collapsed}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
placeholder={t('common.pleaseEnter')}
|
placeholder={t('common.pleaseEnter')}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { type FC, useRef, useState, useEffect } from 'react'
|
import { type FC, useRef, useState, useEffect } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Space, Button, List } from 'antd'
|
import { Space, Button } from 'antd'
|
||||||
import knowledgeEmpty from '@/assets/images/application/knowledgeEmpty.svg'
|
import knowledgeEmpty from '@/assets/images/application/knowledgeEmpty.svg'
|
||||||
import type {
|
import type {
|
||||||
KnowledgeConfigForm,
|
KnowledgeConfigForm,
|
||||||
@@ -113,49 +113,65 @@ const Knowledge: FC<{value?: KnowledgeConfig; onChange?: (config: KnowledgeConfi
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="rb:flex rb:justify-between rb:items-center">
|
<div className="rb:flex rb:items-center rb:justify-between rb:mb-2">
|
||||||
<div>{t('application.knowledgeBaseAssociation')}</div>
|
<div className="rb:text-[12px] rb:font-medium rb:leading-4.5">
|
||||||
|
{t('application.knowledgeBaseAssociation')}
|
||||||
|
</div>
|
||||||
|
|
||||||
<Space>
|
<Button
|
||||||
<Button style={{ padding: '0 8px', height: '24px' }} onClick={handleKnowledgeConfig}>{t('workflow.config.knowledge-retrieval.recallConfig')}</Button>
|
onClick={handleKnowledgeConfig}
|
||||||
<Button style={{ padding: '0 8px', height: '24px' }} onClick={handleAddKnowledge}>+</Button>
|
className="rb:py-0! rb:px-1! rb:text-[12px]! rb:group rb:gap-0.5!"
|
||||||
</Space>
|
size="small"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="rb:size-3.5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/workflow/recall.svg')] rb:group-hover:bg-[url('@/assets/images/workflow/recall_hover.svg')]"
|
||||||
|
></div>
|
||||||
|
{t('workflow.config.knowledge-retrieval.recallConfig')}
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{knowledgeList.length === 0
|
<Space size={10} direction="vertical" className="rb:w-full!">
|
||||||
? <Empty url={knowledgeEmpty} size={88} subTitle={t('application.knowledgeEmpty')} />
|
<Button
|
||||||
:
|
type="dashed"
|
||||||
<List
|
block
|
||||||
grid={{ gutter: 12, column: 1 }}
|
size="middle"
|
||||||
dataSource={knowledgeList}
|
className="rb:text-[12px]!"
|
||||||
renderItem={(item) => {
|
onClick={handleAddKnowledge}
|
||||||
if (!item.id) return null
|
>
|
||||||
return (
|
+ {t('workflow.config.knowledge-retrieval.addKnowledge')}
|
||||||
<List.Item>
|
</Button>
|
||||||
<div key={item.id} className="rb:flex rb:items-center rb:justify-between rb:p-[12px_16px] rb:bg-[#FBFDFF] rb:border rb:border-[#DFE4ED] rb:rounded-lg">
|
|
||||||
<div className="rb:font-medium rb:leading-4">
|
{knowledgeList.length === 0
|
||||||
{item.name}
|
? <Empty url={knowledgeEmpty} size={88} subTitle={t('application.knowledgeEmpty')} />
|
||||||
<Tag color={item.status === 1 ? 'success' : item.status === 0 ? 'default' : 'error'} className="rb:ml-2">
|
: knowledgeList.map(item => {
|
||||||
{item.status === 1 ? t('common.enable') : item.status === 0 ? t('common.disabled') : t('common.deleted')}
|
if (!item.id) return null
|
||||||
</Tag>
|
return (
|
||||||
<div className="rb:mt-1 rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:leading-5">{t('application.contains', {include_count: item.doc_num})}</div>
|
<div key={item.id} className="rb:text-[12px] rb:flex rb:items-center rb:justify-between rb:py-2 rb:px-2.5 rb:bg-[#F6F8FC] rb:border rb:border-[#DFE4ED] rb:rounded-lg">
|
||||||
</div>
|
<div className="">
|
||||||
<Space size={12}>
|
<span className="rb:font-medium rb:leading-4">{item.name}</span>
|
||||||
<div
|
<Tag
|
||||||
className="rb:w-6 rb:h-6 rb:cursor-pointer rb:bg-[url('@/assets/images/editBorder.svg')] rb:hover:bg-[url('@/assets/images/editBg.svg')]"
|
color={item.status === 1 ? 'success' : item.status === 0 ? 'default' : 'error'}
|
||||||
onClick={() => handleEditKnowledge(item)}
|
className="rb:ml-1 rb:py-0! rb:px-1! rb:text-[12px] rb:leading-3.5!"
|
||||||
></div>
|
>
|
||||||
<div
|
{item.status === 1 ? t('common.enable') : item.status === 0 ? t('common.disabled') : t('common.deleted')}
|
||||||
className="rb:w-6 rb:h-6 rb:cursor-pointer rb:bg-[url('@/assets/images/deleteBorder.svg')] rb:hover:bg-[url('@/assets/images/deleteBg.svg')]"
|
</Tag>
|
||||||
onClick={() => handleDeleteKnowledge(item.id)}
|
<div className="rb:mt-1 rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:leading-5">{t('application.contains', { include_count: item.doc_num })}</div>
|
||||||
></div>
|
</div>
|
||||||
</Space>
|
<Space size={12}>
|
||||||
</div>
|
<div
|
||||||
</List.Item>
|
className="rb:size-4 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/edit.svg')] rb:hover:bg-[url('@/assets/images/edit_hover.svg')]"
|
||||||
)
|
onClick={() => handleEditKnowledge(item)}
|
||||||
}}
|
></div>
|
||||||
/>
|
<div
|
||||||
}
|
className="rb:size-4 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/delete.svg')] rb:hover:bg-[url('@/assets/images/delete_hover.svg')]"
|
||||||
|
onClick={() => handleDeleteKnowledge(item.id)}
|
||||||
|
></div>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</Space>
|
||||||
{/* 全局设置 */}
|
{/* 全局设置 */}
|
||||||
<KnowledgeGlobalConfigModal
|
<KnowledgeGlobalConfigModal
|
||||||
data={editConfig}
|
data={editConfig}
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ const KnowledgeConfigModal = forwardRef<KnowledgeConfigModalRef, KnowledgeConfig
|
|||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
|
size="middle"
|
||||||
>
|
>
|
||||||
{data && (
|
{data && (
|
||||||
<div className="rb:mb-6 rb:flex rb:items-center rb:justify-between rb:border rb:rounded-lg rb:p-[17px_16px] rb:cursor-pointer rb:bg-[#F0F3F8] rb:border-[#DFE4ED] rb:text-[#212332]">
|
<div className="rb:mb-6 rb:flex rb:items-center rb:justify-between rb:border rb:rounded-lg rb:p-[17px_16px] rb:cursor-pointer rb:bg-[#F0F3F8] rb:border-[#DFE4ED] rb:text-[#212332]">
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ const KnowledgeGlobalConfigModal = forwardRef<KnowledgeGlobalConfigModalRef, Kno
|
|||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
|
size="middle"
|
||||||
>
|
>
|
||||||
<div className="rb:text-[#5B6167] rb:mb-6">{t('application.globalConfigDesc')}</div>
|
<div className="rb:text-[#5B6167] rb:mb-6">{t('application.globalConfigDesc')}</div>
|
||||||
|
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ const KnowledgeListModal = forwardRef<KnowledgeModalRef, KnowledgeModalProps>(({
|
|||||||
placeholder={t('knowledgeBase.searchPlaceholder')}
|
placeholder={t('knowledgeBase.searchPlaceholder')}
|
||||||
onSearch={handleSearch}
|
onSearch={handleSearch}
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
|
size="middle"
|
||||||
/>
|
/>
|
||||||
{filterList.length === 0
|
{filterList.length === 0
|
||||||
? <Empty />
|
? <Empty />
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { MinusCircleOutlined } from '@ant-design/icons';
|
import { Button, Form, Input, Divider } from 'antd';
|
||||||
import { Button, Form, Input, Space, Row, Col } from 'antd';
|
|
||||||
import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin'
|
import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin'
|
||||||
import VariableSelect from '../VariableSelect'
|
import VariableSelect from '../VariableSelect'
|
||||||
|
|
||||||
@@ -16,43 +15,55 @@ const MappingList: React.FC<MappingListProps> = ({ name, options }) => {
|
|||||||
<Form.List name={name}>
|
<Form.List name={name}>
|
||||||
{(fields, { add, remove }) => (
|
{(fields, { add, remove }) => (
|
||||||
<>
|
<>
|
||||||
{fields.map(({ key, name, ...restField }) => (
|
<div className="rb:flex rb:items-center rb:justify-between rb:mb-2">
|
||||||
<Row key={key} gutter={12} className="rb:mb-2">
|
<div className="rb:text-[12px] rb:font-medium rb:leading-4.5">
|
||||||
<Col span={10}>
|
{t('workflow.config.jinja-render.mapping')}
|
||||||
<Form.Item
|
</div>
|
||||||
{...restField}
|
|
||||||
name={[name, 'name']}
|
<Button
|
||||||
noStyle
|
onClick={() => add()}
|
||||||
>
|
className="rb:py-0! rb:px-1! rb:text-[12px]!"
|
||||||
<Input placeholder={t('common.pleaseEnter')} data-field-type="mapping-name" />
|
size="small"
|
||||||
</Form.Item>
|
>
|
||||||
</Col>
|
+ {t('workflow.config.addVariable')}
|
||||||
<Col span={12}>
|
|
||||||
<Form.Item
|
|
||||||
{...restField}
|
|
||||||
name={[name, 'value']}
|
|
||||||
noStyle
|
|
||||||
>
|
|
||||||
<VariableSelect
|
|
||||||
placeholder={t('common.pleaseSelect')}
|
|
||||||
options={options}
|
|
||||||
popupMatchSelectWidth={false}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={2}>
|
|
||||||
<MinusCircleOutlined onClick={() => remove(name)} />
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
))}
|
|
||||||
<Form.Item>
|
|
||||||
<Button type="dashed" onClick={() => add()} block>
|
|
||||||
+ {t('common.add')}
|
|
||||||
</Button>
|
</Button>
|
||||||
</Form.Item>
|
</div>
|
||||||
|
{fields.map(({ key, name, ...restField }) => (
|
||||||
|
<div key={key} className="rb:flex rb:items-center rb:gap-1 rb:mb-2">
|
||||||
|
<Form.Item
|
||||||
|
{...restField}
|
||||||
|
name={[name, 'name']}
|
||||||
|
noStyle
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
placeholder={t('common.pleaseEnter')}
|
||||||
|
size="small"
|
||||||
|
className="rb:w-24!"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
{...restField}
|
||||||
|
name={[name, 'value']}
|
||||||
|
noStyle
|
||||||
|
>
|
||||||
|
<VariableSelect
|
||||||
|
placeholder={t('common.pleaseSelect')}
|
||||||
|
options={options}
|
||||||
|
popupMatchSelectWidth={false}
|
||||||
|
size="small"
|
||||||
|
className="rb:w-39!"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<div
|
||||||
|
className="rb:ml-1 rb:size-4 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/workflow/deleteBg.svg')] rb:hover:bg-[url('@/assets/images/workflow/deleteBg_hover.svg')]"
|
||||||
|
onClick={() => remove(name)}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Form.List>
|
</Form.List>
|
||||||
|
<Divider />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ const MemoryConfig: FC<{ options: Suggestion[]; parentName: string; }> = ({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{values?.memory?.enable && <>
|
{values?.memory?.enable && <>
|
||||||
<div className="rb:flex rb:items-center rb:justify-between rb:py-1.5 rb:px-2 rb:bg-[#F6F8FC] rb:rounded-md rb:mb-2">
|
<div className="rb:flex rb:items-center rb:justify-between rb:py-1.5 rb:px-2 rb:text-[12px] rb:bg-[#F6F8FC] rb:rounded-md rb:mb-2">
|
||||||
{t('workflow.config.llm.memory')}
|
{t('workflow.config.llm.memory')}
|
||||||
<span>{t('workflow.config.llm.inner')}</span>
|
<span>{t('workflow.config.llm.inner')}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -40,6 +40,7 @@ const MemoryConfig: FC<{ options: Suggestion[]; parentName: string; }> = ({
|
|||||||
isArray={false}
|
isArray={false}
|
||||||
parentName={[parentName, 'messages']}
|
parentName={[parentName, 'messages']}
|
||||||
options={options}
|
options={options}
|
||||||
|
size="small"
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import { type FC, useMemo } from 'react';
|
import { type FC, useMemo } from 'react';
|
||||||
|
import clsx from 'clsx'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Input, Form, Space, Button, Row, Col, Select, type FormListOperation } from 'antd';
|
import { Input, Form, Space, Button, Row, Col, Select, type FormListOperation } from 'antd';
|
||||||
import { MinusCircleOutlined } from '@ant-design/icons';
|
|
||||||
import Editor from '../Editor'
|
import Editor from '../Editor'
|
||||||
import type { Suggestion } from '../Editor/plugin/AutocompletePlugin'
|
import type { Suggestion } from '../Editor/plugin/AutocompletePlugin'
|
||||||
|
|
||||||
interface MessageEditor {
|
interface MessageEditor {
|
||||||
options: Suggestion[];
|
options: Suggestion[];
|
||||||
title?: string
|
title?: string;
|
||||||
|
titleVariant?: 'outlined' | 'borderless';
|
||||||
isArray?: boolean;
|
isArray?: boolean;
|
||||||
parentName?: string | string[];
|
parentName?: string | string[];
|
||||||
label?: string;
|
label?: string;
|
||||||
@@ -15,6 +16,7 @@ interface MessageEditor {
|
|||||||
value?: string;
|
value?: string;
|
||||||
enableJinja2?: boolean;
|
enableJinja2?: boolean;
|
||||||
onChange?: (value?: string) => void;
|
onChange?: (value?: string) => void;
|
||||||
|
size?: 'small' | 'default'
|
||||||
}
|
}
|
||||||
const roleOptions = [
|
const roleOptions = [
|
||||||
// { label: 'SYSTEM', value: 'SYSTEM' },
|
// { label: 'SYSTEM', value: 'SYSTEM' },
|
||||||
@@ -23,11 +25,13 @@ const roleOptions = [
|
|||||||
]
|
]
|
||||||
const MessageEditor: FC<MessageEditor> = ({
|
const MessageEditor: FC<MessageEditor> = ({
|
||||||
title,
|
title,
|
||||||
|
titleVariant = 'outlined',
|
||||||
isArray = true,
|
isArray = true,
|
||||||
parentName = 'messages',
|
parentName = 'messages',
|
||||||
placeholder,
|
placeholder,
|
||||||
options,
|
options,
|
||||||
enableJinja2 = false,
|
enableJinja2 = false,
|
||||||
|
size = 'default'
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const form = Form.useFormInstance();
|
const form = Form.useFormInstance();
|
||||||
@@ -74,14 +78,16 @@ const MessageEditor: FC<MessageEditor> = ({
|
|||||||
|
|
||||||
if (!isArray) {
|
if (!isArray) {
|
||||||
return (
|
return (
|
||||||
<Space size={12} direction="vertical" className="rb:w-full rb:border rb:border-[#DFE4ED] rb:rounded-md rb:px-2 rb:py-1.5 rb:bg-white" data-editor-type={parentName === 'template' ? 'template' : undefined}>
|
<Space size={8} direction="vertical" className="rb:w-full rb:border rb:border-[#DFE4ED] rb:rounded-md rb:px-2 rb:py-1.5" data-editor-type={parentName === 'template' ? 'template' : undefined}>
|
||||||
<Row>
|
<Row>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
{title ?? t('workflow.answerDesc')}
|
<div className={clsx("rb:text-[12px] rb:font-medium rb:py-1 rb:leading-2", {
|
||||||
|
'rb:bg-[#F6F8FC] rb:border rb:border-[#DFE4ED] rb:rounded-sm rb:px-2': titleVariant === 'outlined'
|
||||||
|
})}>{title ?? t('workflow.answerDesc')}</div>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Form.Item name={parentName} noStyle>
|
<Form.Item name={parentName} noStyle>
|
||||||
<Editor enableJinja2={enableJinja2} placeholder={placeholder} options={processedOptions} />
|
<Editor size={size} enableJinja2={enableJinja2} placeholder={placeholder} options={processedOptions} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Space>
|
</Space>
|
||||||
);
|
);
|
||||||
@@ -90,7 +96,7 @@ const MessageEditor: FC<MessageEditor> = ({
|
|||||||
return (
|
return (
|
||||||
<Form.List name={parentName}>
|
<Form.List name={parentName}>
|
||||||
{(fields, { add, remove }) => (
|
{(fields, { add, remove }) => (
|
||||||
<Space size={12} direction="vertical" className="rb:w-full">
|
<Space size={8} direction="vertical" className="rb:w-full">
|
||||||
{fields.map(({ key, name, ...restField }) => {
|
{fields.map(({ key, name, ...restField }) => {
|
||||||
const fieldValue = Array.isArray(parentName)
|
const fieldValue = Array.isArray(parentName)
|
||||||
? parentName.reduce((obj, key) => obj?.[key], values)
|
? parentName.reduce((obj, key) => obj?.[key], values)
|
||||||
@@ -99,16 +105,17 @@ const MessageEditor: FC<MessageEditor> = ({
|
|||||||
const currentRole = (fieldValue?.[name]?.role || 'USER').toUpperCase();
|
const currentRole = (fieldValue?.[name]?.role || 'USER').toUpperCase();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Space key={key} size={12} direction="vertical" className="rb:w-full rb:border rb:border-[#DFE4ED] rb:rounded-md rb:px-2 rb:py-1.5 rb:bg-white">
|
<Space key={key} size={12} direction="vertical" className="rb:w-full rb:border rb:border-[#DFE4ED] rb:rounded-md rb:p-2">
|
||||||
<Row>
|
<Row>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Form.Item {...restField} name={[name, 'role']} noStyle>
|
<Form.Item {...restField} name={[name, 'role']} noStyle>
|
||||||
{currentRole === 'SYSTEM' ? (
|
{currentRole === 'SYSTEM' ? (
|
||||||
<Input disabled />
|
<Input disabled className="rb:font-medium!" />
|
||||||
) : (
|
) : (
|
||||||
<Select
|
<Select
|
||||||
options={roleOptions}
|
options={roleOptions}
|
||||||
disabled={currentRole === 'SYSTEM'}
|
disabled={currentRole === 'SYSTEM'}
|
||||||
|
className="rb:font-medium!"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
@@ -116,20 +123,23 @@ const MessageEditor: FC<MessageEditor> = ({
|
|||||||
{currentRole !== 'SYSTEM' && (
|
{currentRole !== 'SYSTEM' && (
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<div className="rb:h-full rb:flex rb:justify-end rb:items-center">
|
<div className="rb:h-full rb:flex rb:justify-end rb:items-center">
|
||||||
<MinusCircleOutlined onClick={() => remove(name)} />
|
<div
|
||||||
|
className="rb:size-4 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/workflow/delete_cycle.svg')]"
|
||||||
|
onClick={() => remove(name)}
|
||||||
|
></div>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
)}
|
)}
|
||||||
</Row>
|
</Row>
|
||||||
<Form.Item {...restField} name={[name, 'content']} noStyle>
|
<Form.Item {...restField} name={[name, 'content']} noStyle>
|
||||||
<Editor enableJinja2={enableJinja2} placeholder={placeholder} options={processedOptions} />
|
<Editor size={size} enableJinja2={enableJinja2} placeholder={placeholder} options={processedOptions} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Space>
|
</Space>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
<Form.Item noStyle>
|
<Form.Item noStyle>
|
||||||
<Button type="dashed" onClick={() => handleAdd(add)} block>
|
<Button type="dashed" size="middle" className="rb:text-[12px]!" onClick={() => handleAdd(add)} block>
|
||||||
+{t('workflow.addMessage')}
|
+ {t('workflow.addMessage')}
|
||||||
</Button>
|
</Button>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Space>
|
</Space>
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ const ParamEditModal = forwardRef<ParamEditModalRef, ParamEditModalProps>(({
|
|||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
|
size="middle"
|
||||||
scrollToFirstError={{ behavior: 'instant', block: 'end', focus: true }}
|
scrollToFirstError={{ behavior: 'instant', block: 'end', focus: true }}
|
||||||
>
|
>
|
||||||
<FormItem
|
<FormItem
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { type FC, useRef } from 'react'
|
import { type FC, useRef } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Button, Space, List } from 'antd'
|
import { Button, Space } from 'antd'
|
||||||
import Empty from '@/components/Empty'
|
|
||||||
|
|
||||||
import type { ParamItem, ParamEditModalRef } from './types'
|
import type { ParamItem, ParamEditModalRef } from './types'
|
||||||
import ParamEditModal from './ParamEditModal'
|
import ParamEditModal from './ParamEditModal'
|
||||||
@@ -41,47 +41,37 @@ const ParamsList: FC<ParamsListProps> = ({
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="rb:flex rb:justify-between rb:items-center">
|
<div className="rb:leading-4.25 rb:text-[12px] rb:font-medium rb:mb-2">
|
||||||
<div>{label}</div>
|
{label}
|
||||||
|
|
||||||
<Space>
|
|
||||||
<Button style={{ padding: '0 8px', height: '24px' }} onClick={handleAdd}>+</Button>
|
|
||||||
</Space>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{value?.length === 0
|
<Space size={10} direction="vertical" className="rb:w-full!">
|
||||||
? <Empty size={88} />
|
<Button type="dashed" block size="middle" className="rb:text-[12px]!" onClick={handleAdd}>+ {t('workflow.config.parameter-extractor.addParams')}</Button>
|
||||||
:
|
|
||||||
<List
|
|
||||||
grid={{ gutter: 12, column: 1 }}
|
|
||||||
dataSource={value}
|
|
||||||
renderItem={(item, index) => (
|
|
||||||
<List.Item>
|
|
||||||
<div key={index} className="rb:group rb:relative rb:p-[12px_16px] rb:bg-[#FBFDFF] rb:cursor-pointer rb:border rb:border-[#DFE4ED] rb:rounded-lg">
|
|
||||||
<div className="rb:flex rb:items-center rb:justify-between">
|
|
||||||
<div className="rb:leading-4">
|
|
||||||
<span className="rb:font-medium">{item.name}</span>
|
|
||||||
<span className="rb:text-[12px] rb:text-[#5B6167] rb:font-regular"> ({t(`workflow.config.parameter-extractor.${item.type}`)})</span>
|
|
||||||
</div>
|
|
||||||
<span className="rb:block rb:group-hover:hidden rb:text-[12px] rb:text-[#5B6167] rb:font-regular">{item.required ? t('workflow.config.parameter-extractor.required') : ''}</span>
|
|
||||||
|
|
||||||
</div>
|
{value?.map((item, index) => (
|
||||||
<div className="rb:mt-1 rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:leading-5 rb:wrap-break-word rb:line-clamp-1">{item.desc}</div>
|
<div
|
||||||
<Space size={12} className="rb:hidden! rb:group-hover:flex! rb:absolute rb:right-4 rb:top-[50%] rb:transform-[translateY(-50%)] rb:bg-white">
|
key={index}
|
||||||
<div
|
className="rb:cursor-pointer rb:group rb:py-2 rb:pl-2.5 rb:pr-2 rb:text-[12px] rb:flex rb:items-center rb:justify-between rb:bg-[#F6F8FC] rb:border rb:border-[#DFE4ED] rb:rounded-md"
|
||||||
className="rb:size-5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/editBorder.svg')] rb:hover:bg-[url('@/assets/images/editBg.svg')]"
|
>
|
||||||
onClick={() => handleEdit(index)}
|
<div>
|
||||||
></div>
|
<span className="rb:font-medium">{item.name}</span>
|
||||||
<div
|
<span className="rb:text-[12px] rb:text-[#5B6167] rb:font-regular"> ({t(`workflow.config.parameter-extractor.${item.type}`)}) {item.required ? t('workflow.config.parameter-extractor.required') : ''}</span>
|
||||||
className="rb:size-5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/deleteBorder.svg')] rb:hover:bg-[url('@/assets/images/deleteBg.svg')]"
|
<div className="rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:leading-4.25 rb:mt-0.5">{item.desc}</div>
|
||||||
onClick={() => handleDelete(index)}
|
</div>
|
||||||
></div>
|
|
||||||
</Space>
|
<Space size={8}>
|
||||||
</div>
|
<div
|
||||||
</List.Item>
|
className="rb:size-4 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/edit.svg')] rb:hover:bg-[url('@/assets/images/edit_hover.svg')]"
|
||||||
)}
|
onClick={() => handleEdit(index)}
|
||||||
/>
|
></div>
|
||||||
}
|
<div
|
||||||
|
className="rb:size-4 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/delete.svg')] rb:hover:bg-[url('@/assets/images/delete_hover.svg')]"
|
||||||
|
onClick={() => handleDelete(index)}
|
||||||
|
></div>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</Space>
|
||||||
|
|
||||||
<ParamEditModal
|
<ParamEditModal
|
||||||
ref={paramEditModalRef}
|
ref={paramEditModalRef}
|
||||||
|
|||||||
55
web/src/views/Workflow/components/Properties/RbSlider.tsx
Normal file
55
web/src/views/Workflow/components/Properties/RbSlider.tsx
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import type { InputNumberProps, SliderSingleProps } from 'antd';
|
||||||
|
import { Col, InputNumber, Row, Slider } from 'antd';
|
||||||
|
|
||||||
|
const RbSlider: React.FC<SliderSingleProps> = ({
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
step = 0.01,
|
||||||
|
...props
|
||||||
|
}) => {
|
||||||
|
const [curValue, setCurValue] = useState<number | undefined>(0)
|
||||||
|
useEffect(() => {
|
||||||
|
setCurValue(value)
|
||||||
|
}, [value])
|
||||||
|
const handleSliderChange = (newValue: number) => {
|
||||||
|
onChange && onChange(newValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInputChange: InputNumberProps['onChange'] = (newValue) => {
|
||||||
|
onChange && onChange(newValue as number);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Row gutter={12}>
|
||||||
|
<Col span={16}>
|
||||||
|
<Slider
|
||||||
|
{...props}
|
||||||
|
min={min}
|
||||||
|
max={max}
|
||||||
|
step={step as number}
|
||||||
|
value={curValue}
|
||||||
|
className="rb:my-0! rb:ml-2.5!"
|
||||||
|
classNames={{
|
||||||
|
rail: 'rb:h-[6px]!',
|
||||||
|
track: 'rb:h-[6px]!'
|
||||||
|
}}
|
||||||
|
onChange={handleSliderChange}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col span={8}>
|
||||||
|
<InputNumber
|
||||||
|
min={min}
|
||||||
|
max={max}
|
||||||
|
step={step as number}
|
||||||
|
value={curValue}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
className="rb:w-full!"
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default RbSlider;
|
||||||
@@ -171,6 +171,7 @@ const ToolConfig: FC<{ options: Suggestion[]; }> = ({
|
|||||||
label={t('workflow.config.tool.tool_id')}
|
label={t('workflow.config.tool.tool_id')}
|
||||||
>
|
>
|
||||||
<Cascader
|
<Cascader
|
||||||
|
placeholder={t('common.pleaseSelect')}
|
||||||
options={optionList}
|
options={optionList}
|
||||||
loadData={loadData}
|
loadData={loadData}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
@@ -187,28 +188,30 @@ const ToolConfig: FC<{ options: Suggestion[]; }> = ({
|
|||||||
label={parameter.name}
|
label={parameter.name}
|
||||||
extra={parameter.type === 'boolean' ? undefined : parameter.description}
|
extra={parameter.type === 'boolean' ? undefined : parameter.description}
|
||||||
rules={[
|
rules={[
|
||||||
{ required: parameter.required, message: t('workflow.config.tool.required') }
|
{ required: parameter.required, message: t('common.pleaseEnter') }
|
||||||
]}
|
]}
|
||||||
layout={parameter.type === 'boolean' ? 'horizontal' : 'vertical'}
|
layout={parameter.type === 'boolean' ? 'horizontal' : 'vertical'}
|
||||||
className={parameter.type === 'boolean' ? 'rb:mb-0!' : ''}
|
className={parameter.type === 'boolean' ? 'rb:mb-0!' : ''}
|
||||||
>
|
>
|
||||||
{parameter.type === 'string' && parameter.enum && parameter.enum.length > 0
|
{parameter.type === 'string' && parameter.enum && parameter.enum.length > 0
|
||||||
? <Select options={parameter.enum.map(vo => ({ value: vo, label: vo }))} placeholder={t('common.pleaseSelect')} />
|
? <Select size="small" options={parameter.enum.map(vo => ({ value: vo, label: vo }))} placeholder={t('common.pleaseSelect')} />
|
||||||
: parameter.type === 'boolean'
|
: parameter.type === 'boolean'
|
||||||
? <Switch />
|
? <Switch size="small" />
|
||||||
: parameter.type === 'integer' || parameter.type === 'number'
|
: parameter.type === 'integer' || parameter.type === 'number'
|
||||||
? <InputNumber
|
? <InputNumber
|
||||||
min={parameter.minimum}
|
min={parameter.minimum}
|
||||||
max={parameter.maximum}
|
max={parameter.maximum}
|
||||||
step={parameter.type === 'integer' ? 1 : 0.01}
|
step={parameter.type === 'integer' ? 1 : 0.01}
|
||||||
placeholder={t('common.pleaseEnter')}
|
placeholder={t('common.pleaseEnter')}
|
||||||
className="rb:w-full!"
|
className="rb:w-full!"
|
||||||
|
size="small"
|
||||||
onChange={(value) => form.setFieldValue(['tool_parameters', parameter.name], value)}
|
onChange={(value) => form.setFieldValue(['tool_parameters', parameter.name], value)}
|
||||||
/>
|
/>
|
||||||
: <Editor
|
: <Editor
|
||||||
height={32}
|
height={32}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
options={options}
|
options={options}
|
||||||
|
size="small"
|
||||||
placeholder={t('common.pleaseEnter')}
|
placeholder={t('common.pleaseEnter')}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ import { forwardRef, useImperativeHandle, useState } from 'react';
|
|||||||
import { Form, Input, Select, InputNumber, Checkbox, Tag } from 'antd';
|
import { Form, Input, Select, InputNumber, Checkbox, Tag } from 'antd';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import type { StartVariableItem, VariableEditModalRef } from '../../types'
|
import type { Variable, VariableEditModalRef } from './types'
|
||||||
import RbModal from '@/components/RbModal'
|
import RbModal from '@/components/RbModal'
|
||||||
import SortableList from '@/components/SortableList'
|
import SortableList from '@/components/SortableList'
|
||||||
|
|
||||||
const FormItem = Form.Item;
|
const FormItem = Form.Item;
|
||||||
|
|
||||||
interface VariableEditModalProps {
|
interface VariableEditModalProps {
|
||||||
refresh: (values: StartVariableItem) => void;
|
refresh: (values: Variable) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const types = [
|
const types = [
|
||||||
@@ -36,9 +36,9 @@ const VariableEditModal = forwardRef<VariableEditModalRef, VariableEditModalProp
|
|||||||
}, ref) => {
|
}, ref) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const [form] = Form.useForm<StartVariableItem>();
|
const [form] = Form.useForm<Variable>();
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [editVo, setEditVo] = useState<StartVariableItem | null>(null)
|
const [editVo, setEditVo] = useState<Variable | null>(null)
|
||||||
|
|
||||||
const values = Form.useWatch([], form);
|
const values = Form.useWatch([], form);
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ const VariableEditModal = forwardRef<VariableEditModalRef, VariableEditModalProp
|
|||||||
setEditVo(null)
|
setEditVo(null)
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOpen = (variable?: StartVariableItem) => {
|
const handleOpen = (variable?: Variable) => {
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
if (variable) {
|
if (variable) {
|
||||||
setEditVo(variable || null)
|
setEditVo(variable || null)
|
||||||
@@ -85,7 +85,7 @@ const VariableEditModal = forwardRef<VariableEditModalRef, VariableEditModalProp
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<RbModal
|
<RbModal
|
||||||
title={editVo ? t('workflow.config.start.editVariable') : t('workflow.config.start.addVariable')}
|
title={editVo ? t('workflow.config.start.editVariable') : t('workflow.config.addVariable')}
|
||||||
open={visible}
|
open={visible}
|
||||||
onCancel={handleClose}
|
onCancel={handleClose}
|
||||||
okText={t('common.save')}
|
okText={t('common.save')}
|
||||||
@@ -96,6 +96,7 @@ const VariableEditModal = forwardRef<VariableEditModalRef, VariableEditModalProp
|
|||||||
form={form}
|
form={form}
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
|
size="middle"
|
||||||
scrollToFirstError={{ behavior: 'instant', block: 'end', focus: true }}
|
scrollToFirstError={{ behavior: 'instant', block: 'end', focus: true }}
|
||||||
>
|
>
|
||||||
{/* 变量类型 */}
|
{/* 变量类型 */}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
import { type FC, useRef, useState } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { Node } from '@antv/x6';
|
||||||
|
import { Space, Button, Divider, App } from 'antd'
|
||||||
|
import type { Variable, VariableEditModalRef } from './types'
|
||||||
|
import type { NodeConfig } from '../../../types'
|
||||||
|
import VariableEditModal from './VariableEditModal'
|
||||||
|
|
||||||
|
interface VariableListProps {
|
||||||
|
selectedNode?: Node | null;
|
||||||
|
config: NodeConfig;
|
||||||
|
value?: Variable[];
|
||||||
|
parentName: string;
|
||||||
|
onChange?: (value: Variable[]) => void;
|
||||||
|
}
|
||||||
|
const VariableList: FC<VariableListProps> = ({
|
||||||
|
value = [],
|
||||||
|
onChange,
|
||||||
|
selectedNode,
|
||||||
|
config,
|
||||||
|
parentName
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const { modal } = App.useApp()
|
||||||
|
const variableModalRef = useRef<VariableEditModalRef>(null)
|
||||||
|
const [editIndex, setEditIndex] = useState<number | null>(null)
|
||||||
|
|
||||||
|
const handleAddVariable = () => {
|
||||||
|
setEditIndex(null)
|
||||||
|
variableModalRef.current?.handleOpen()
|
||||||
|
}
|
||||||
|
const handleEditVariable = (index: number, vo: Variable) => {
|
||||||
|
variableModalRef.current?.handleOpen(vo)
|
||||||
|
setEditIndex(index)
|
||||||
|
}
|
||||||
|
const handleRefreshVariable = (variable: Variable) => {
|
||||||
|
if (!selectedNode) return
|
||||||
|
|
||||||
|
if (editIndex !== null) {
|
||||||
|
const list = [...value]
|
||||||
|
list[editIndex] = variable
|
||||||
|
onChange?.(list)
|
||||||
|
} else {
|
||||||
|
console.log('VariableList', value, variable)
|
||||||
|
onChange?.([...value, variable])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const handleDeleteVariable = (index: number, vo: Variable, e: React.MouseEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
if (!selectedNode) return
|
||||||
|
|
||||||
|
modal.confirm({
|
||||||
|
title: t('common.confirmDeleteDesc', { name: vo.name }),
|
||||||
|
okText: t('common.delete'),
|
||||||
|
cancelText: t('common.cancel'),
|
||||||
|
okType: 'danger',
|
||||||
|
onOk: () => {
|
||||||
|
const list = [...value]
|
||||||
|
list.splice(index, 1)
|
||||||
|
onChange?.([...list])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Space size={10} direction="vertical" className="rb:w-full">
|
||||||
|
<div className="rb:leading-4.25 rb:text-[12px] rb:font-medium">
|
||||||
|
{t(`workflow.config.${selectedNode?.data?.type}.${parentName}`)}
|
||||||
|
</div>
|
||||||
|
<Button type="dashed" block size="middle" className="rb:text-[12px]!" onClick={handleAddVariable}>+ {t('workflow.config.addVariable')}</Button>
|
||||||
|
{Array.isArray(value) && value?.map((vo, index) =>
|
||||||
|
<div
|
||||||
|
key={`${vo.name}}-${index}`}
|
||||||
|
className="rb:cursor-pointer rb:group rb:py-2 rb:pl-2.5 rb:pr-2 rb:text-[12px] rb:flex rb:items-center rb:justify-between rb:bg-[#F6F8FC] rb:border rb:border-[#DFE4ED] rb:rounded-md"
|
||||||
|
onClick={() => handleEditVariable(index, vo)}
|
||||||
|
>
|
||||||
|
<span className="rb:font-medium">{vo.name}·{vo.description}</span>
|
||||||
|
|
||||||
|
<Space size={8}>
|
||||||
|
{vo.required && <span className="rb:py-px rb:px-2 rb:bg-[#FBFDFF] rb:border rb:border-[#DFE4ED] rb:rounded-sm">{t('workflow.config.start.required')}</span>}
|
||||||
|
<span className="rb:py-px rb:px-2 rb:bg-[#FBFDFF] rb:border rb:border-[#DFE4ED] rb:rounded-sm">{vo.type}</span>
|
||||||
|
<div
|
||||||
|
className="rb:size-3 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/close.svg')] rb:hover:bg-[url('@/assets/images/close_hover.svg')]"
|
||||||
|
onClick={(e) => handleDeleteVariable(index, vo, e)}
|
||||||
|
></div>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
</Space>
|
||||||
|
<Divider size="small" />
|
||||||
|
<Space size={10} direction="vertical" className="rb:w-full">
|
||||||
|
{config.sys?.map((vo, index) =>
|
||||||
|
<div key={index} className="rb:py-2 rb:pl-2.5 rb:pr-2 rb:text-[12px] rb:flex rb:items-center rb:justify-between rb:bg-[#F6F8FC] rb:border rb:border-[#DFE4ED] rb:rounded-md">
|
||||||
|
<span className="rb:font-medium">sys.{vo.name}</span>
|
||||||
|
<span className="rb:py-px rb:px-2 rb:bg-[#FBFDFF] rb:border rb:border-[#DFE4ED] rb:rounded-sm">{vo.type}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
|
<VariableEditModal
|
||||||
|
ref={variableModalRef}
|
||||||
|
refresh={handleRefreshVariable}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default VariableList
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
export interface Variable {
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
required: boolean;
|
||||||
|
description: string;
|
||||||
|
max_length?: number;
|
||||||
|
default?: string;
|
||||||
|
readonly?: boolean;
|
||||||
|
defaultValue?: any;
|
||||||
|
value?: any;
|
||||||
|
}
|
||||||
|
export interface VariableEditModalRef {
|
||||||
|
handleOpen: (values?: Variable) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApiExtensionModalData {
|
||||||
|
name: string;
|
||||||
|
apiEndpoint: string;
|
||||||
|
apiKey: string;
|
||||||
|
}
|
||||||
|
export interface ApiExtensionModalRef {
|
||||||
|
handleOpen: () => void;
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ interface VariableSelectProps extends SelectProps {
|
|||||||
onChange?: (value: string) => void;
|
onChange?: (value: string) => void;
|
||||||
allowClear?: boolean;
|
allowClear?: boolean;
|
||||||
filterBooleanType?: boolean;
|
filterBooleanType?: boolean;
|
||||||
|
size?: 'small' | 'middle' | 'large'
|
||||||
}
|
}
|
||||||
|
|
||||||
const VariableSelect: FC<VariableSelectProps> = ({
|
const VariableSelect: FC<VariableSelectProps> = ({
|
||||||
@@ -18,7 +19,7 @@ const VariableSelect: FC<VariableSelectProps> = ({
|
|||||||
value,
|
value,
|
||||||
allowClear = true,
|
allowClear = true,
|
||||||
onChange,
|
onChange,
|
||||||
size,
|
size = 'middle',
|
||||||
filterBooleanType = false,
|
filterBooleanType = false,
|
||||||
...resetPorps
|
...resetPorps
|
||||||
}) => {
|
}) => {
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { type FC, useEffect, useState, useRef, useMemo } from "react";
|
import { type FC, useEffect, useState, useRef, useMemo } from "react";
|
||||||
|
import clsx from 'clsx'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Graph, Node } from '@antv/x6';
|
import { Graph, Node } from '@antv/x6';
|
||||||
import { Form, Input, Button, Select, InputNumber, Slider, Space, Divider, App, Switch } from 'antd'
|
import { Form, Input, Select, InputNumber, Switch } from 'antd'
|
||||||
|
|
||||||
import type { NodeConfig, NodeProperties, StartVariableItem, VariableEditModalRef, ChatVariable } from '../../types'
|
import type { NodeConfig, NodeProperties, ChatVariable } from '../../types'
|
||||||
import Empty from '@/components/Empty';
|
import Empty from '@/components/Empty';
|
||||||
import emptyIcon from '@/assets/images/workflow/empty.png'
|
import emptyIcon from '@/assets/images/workflow/empty.png'
|
||||||
import CustomSelect from "@/components/CustomSelect";
|
import CustomSelect from "@/components/CustomSelect";
|
||||||
import VariableEditModal from './VariableEditModal';
|
|
||||||
import MessageEditor from './MessageEditor'
|
import MessageEditor from './MessageEditor'
|
||||||
import Knowledge from './Knowledge/Knowledge';
|
import Knowledge from './Knowledge/Knowledge';
|
||||||
import type { Suggestion } from '../Editor/plugin/AutocompletePlugin'
|
import type { Suggestion } from '../Editor/plugin/AutocompletePlugin'
|
||||||
@@ -23,7 +23,11 @@ import CycleVarsList from './CycleVarsList'
|
|||||||
import AssignmentList from './AssignmentList'
|
import AssignmentList from './AssignmentList'
|
||||||
import ToolConfig from './ToolConfig'
|
import ToolConfig from './ToolConfig'
|
||||||
import MemoryConfig from './MemoryConfig'
|
import MemoryConfig from './MemoryConfig'
|
||||||
|
import VariableList from './VariableList'
|
||||||
// import { calculateVariableList } from './utils/variableListCalculator'
|
// import { calculateVariableList } from './utils/variableListCalculator'
|
||||||
|
import styles from './properties.module.css'
|
||||||
|
import Editor from "../Editor";
|
||||||
|
import RbSlider from './RbSlider'
|
||||||
|
|
||||||
interface PropertiesProps {
|
interface PropertiesProps {
|
||||||
selectedNode?: Node | null;
|
selectedNode?: Node | null;
|
||||||
@@ -42,12 +46,9 @@ const Properties: FC<PropertiesProps> = ({
|
|||||||
chatVariables
|
chatVariables
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { modal } = App.useApp()
|
|
||||||
const [form] = Form.useForm<NodeConfig>();
|
const [form] = Form.useForm<NodeConfig>();
|
||||||
const [configs, setConfigs] = useState<Record<string,NodeConfig>>({} as Record<string,NodeConfig>)
|
const [configs, setConfigs] = useState<Record<string,NodeConfig>>({} as Record<string,NodeConfig>)
|
||||||
const values = Form.useWatch([], form);
|
const values = Form.useWatch([], form);
|
||||||
const variableModalRef = useRef<VariableEditModalRef>(null)
|
|
||||||
const [editIndex, setEditIndex] = useState<number | null>(null)
|
|
||||||
const [graphUpdateTrigger, setGraphUpdateTrigger] = useState(0)
|
const [graphUpdateTrigger, setGraphUpdateTrigger] = useState(0)
|
||||||
const prevMappingNamesRef = useRef<string[]>([])
|
const prevMappingNamesRef = useRef<string[]>([])
|
||||||
const prevTemplateVarsRef = useRef<string[]>([])
|
const prevTemplateVarsRef = useRef<string[]>([])
|
||||||
@@ -243,49 +244,6 @@ const Properties: FC<PropertiesProps> = ({
|
|||||||
}
|
}
|
||||||
}, [values, selectedNode, form])
|
}, [values, selectedNode, form])
|
||||||
|
|
||||||
const handleAddVariable = () => {
|
|
||||||
setEditIndex(null)
|
|
||||||
variableModalRef.current?.handleOpen()
|
|
||||||
}
|
|
||||||
const handleEditVariable = (index: number, vo: StartVariableItem) => {
|
|
||||||
variableModalRef.current?.handleOpen(vo)
|
|
||||||
setEditIndex(index)
|
|
||||||
}
|
|
||||||
const handleRefreshVariable = (value: StartVariableItem) => {
|
|
||||||
if (!selectedNode) return
|
|
||||||
|
|
||||||
if (editIndex !== null) {
|
|
||||||
const defaultValue = selectedNode.data.config.variables.defaultValue ?? []
|
|
||||||
defaultValue[editIndex] = value
|
|
||||||
selectedNode.data.config.variables.defaultValue = [...defaultValue]
|
|
||||||
} else {
|
|
||||||
const defaultValue = selectedNode.data.config.variables.defaultValue ?? []
|
|
||||||
selectedNode.data.config.variables.defaultValue = [...defaultValue, value]
|
|
||||||
}
|
|
||||||
selectedNode?.setData({ ...selectedNode.data})
|
|
||||||
|
|
||||||
setConfigs({ ...selectedNode.data.config })
|
|
||||||
}
|
|
||||||
const handleDeleteVariable = (index: number, vo: StartVariableItem) => {
|
|
||||||
if (!selectedNode) return
|
|
||||||
|
|
||||||
modal.confirm({
|
|
||||||
title: t('common.confirmDeleteDesc', { name: vo.name }),
|
|
||||||
okText: t('common.delete'),
|
|
||||||
cancelText: t('common.cancel'),
|
|
||||||
okType: 'danger',
|
|
||||||
onOk: () => {
|
|
||||||
const defaultValue = selectedNode.data.config.variables.defaultValue ?? []
|
|
||||||
defaultValue.splice(index, 1)
|
|
||||||
selectedNode.data.config.variables.defaultValue = [...defaultValue]
|
|
||||||
|
|
||||||
selectedNode?.setData({ ...selectedNode.data })
|
|
||||||
|
|
||||||
setConfigs({ ...selectedNode.data.config })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const variableList = useMemo(() => {
|
const variableList = useMemo(() => {
|
||||||
if (!selectedNode || !graphRef?.current) return [];
|
if (!selectedNode || !graphRef?.current) return [];
|
||||||
|
|
||||||
@@ -586,7 +544,7 @@ const Properties: FC<PropertiesProps> = ({
|
|||||||
break
|
break
|
||||||
case 'question-classifier':
|
case 'question-classifier':
|
||||||
const classNameKey = `${dataNodeId}_class_name`;
|
const classNameKey = `${dataNodeId}_class_name`;
|
||||||
const outputKey = `${dataNodeId}_output`;
|
// const outputKey = `${dataNodeId}_output`;
|
||||||
if (!addedKeys.has(classNameKey)) {
|
if (!addedKeys.has(classNameKey)) {
|
||||||
addedKeys.add(classNameKey);
|
addedKeys.add(classNameKey);
|
||||||
variableList.push({
|
variableList.push({
|
||||||
@@ -1039,11 +997,11 @@ const Properties: FC<PropertiesProps> = ({
|
|||||||
console.log('variableList', variableList)
|
console.log('variableList', variableList)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rb:w-75 rb:fixed rb:right-0 rb:top-16 rb:bottom-0 rb:p-3">
|
<div className={clsx("rb:w-75 rb:fixed rb:right-0 rb:top-16 rb:bottom-0 rb:p-3 rb:pb-6", styles.properties)}>
|
||||||
<div className="rb:font-medium rb:leading-5 rb:mb-3">{t('workflow.nodeProperties')}</div>
|
<div className="rb:font-medium rb:leading-5 rb:pb-3 rb:mb-3 rb:border-b rb:border-b-[#DFE4ED]">{t('workflow.nodeProperties')}</div>
|
||||||
{!selectedNode
|
{!selectedNode
|
||||||
? <Empty url={emptyIcon} size={140} className="rb:h-full rb:mx-15" title={t('workflow.empty')} />
|
? <Empty url={emptyIcon} size={140} className="rb:h-full rb:mx-15" title={t('workflow.empty')} />
|
||||||
: <Form form={form} layout="vertical" className="rb:h-[calc(100%-20px)] rb:overflow-y-auto">
|
: <Form form={form} size="small" layout="vertical" className="rb:h-[calc(100%-20px)] rb:overflow-x-hidden rb:overflow-y-auto">
|
||||||
<Form.Item name="name" label={t('workflow.nodeName')}>
|
<Form.Item name="name" label={t('workflow.nodeName')}>
|
||||||
<Input
|
<Input
|
||||||
placeholder={t('common.pleaseEnter')}
|
placeholder={t('common.pleaseEnter')}
|
||||||
@@ -1073,46 +1031,13 @@ const Properties: FC<PropertiesProps> = ({
|
|||||||
|
|
||||||
if (selectedNode?.data?.type === 'start' && key === 'variables' && config.type === 'define') {
|
if (selectedNode?.data?.type === 'start' && key === 'variables' && config.type === 'define') {
|
||||||
return (
|
return (
|
||||||
<div key={key}>
|
<Form.Item key={key} name={key}>
|
||||||
<div className="rb:flex rb:items-center rb:justify-between rb:mb-2.75">
|
<VariableList
|
||||||
<div className="rb:leading-5">
|
parentName={key}
|
||||||
{t(`workflow.config.${selectedNode?.data?.type}.${key}`)}
|
selectedNode={selectedNode}
|
||||||
</div>
|
config={config}
|
||||||
<Button style={{padding: '0 8px', height: '24px'}} onClick={handleAddVariable}>+{t('application.addVariables')}</Button>
|
/>
|
||||||
</div>
|
</Form.Item>
|
||||||
|
|
||||||
<Space size={4} direction="vertical" className="rb:w-full">
|
|
||||||
{Array.isArray(config.defaultValue) && config.defaultValue?.map((vo, index) =>
|
|
||||||
<div key={`${vo.name}}-${index}`} className="rb:p-[4px_8px] rb:text-[12px] rb:text-[#5B6167] rb:flex rb:items-center rb:justify-between rb:border rb:border-[#DFE4ED] rb:rounded-md rb:group rb:cursor-pointer">
|
|
||||||
<span>{vo.name}·{vo.description}</span>
|
|
||||||
|
|
||||||
<div className="rb:group-hover:hidden rb:flex rb:items-center rb:gap-1">
|
|
||||||
{vo.required && <span>{t('workflow.config.start.required')}</span>}
|
|
||||||
{vo.type}
|
|
||||||
</div>
|
|
||||||
<Space className="rb:hidden! rb:group-hover:flex!">
|
|
||||||
<div
|
|
||||||
className="rb:w-4.5 rb:h-4.5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/editBorder.svg')] rb:hover:bg-[url('@/assets/images/editBg.svg')]"
|
|
||||||
onClick={() => handleEditVariable(index, vo)}
|
|
||||||
></div>
|
|
||||||
<div
|
|
||||||
className="rb:w-4.5 rb:h-4.5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/deleteBorder.svg')] rb:hover:bg-[url('@/assets/images/deleteBg.svg')]"
|
|
||||||
onClick={() => handleDeleteVariable(index, vo)}
|
|
||||||
></div>
|
|
||||||
</Space>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<Divider size="small" />
|
|
||||||
{config.sys?.map((vo, index) =>
|
|
||||||
<div key={index} className="rb:p-[4px_8px] rb:text-[12px] rb:text-[#5B6167] rb:flex rb:items-center rb:justify-between rb:border rb:border-[#DFE4ED] rb:rounded-md">
|
|
||||||
<div>
|
|
||||||
<span>sys.{vo.name}</span>
|
|
||||||
</div>
|
|
||||||
{vo.type}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Space>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1143,23 +1068,12 @@ const Properties: FC<PropertiesProps> = ({
|
|||||||
key={key}
|
key={key}
|
||||||
options={contextVariableList.filter(variable => variable.nodeData?.type !== 'knowledge-retrieval')}
|
options={contextVariableList.filter(variable => variable.nodeData?.type !== 'knowledge-retrieval')}
|
||||||
parentName={key}
|
parentName={key}
|
||||||
|
placeholder={t(config.placeholder || 'common.pleaseSelect')}
|
||||||
|
size="small"
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (selectedNode?.data?.type === 'end' && key === 'output') {
|
|
||||||
return (
|
|
||||||
<Form.Item key={key} name={key}>
|
|
||||||
<MessageEditor
|
|
||||||
key={key}
|
|
||||||
isArray={false}
|
|
||||||
parentName={key}
|
|
||||||
options={variableList.filter(variable => variable.nodeData?.type !== 'knowledge-retrieval')}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.type === 'define') {
|
if (config.type === 'define') {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -1184,6 +1098,8 @@ const Properties: FC<PropertiesProps> = ({
|
|||||||
parentName={key}
|
parentName={key}
|
||||||
enableJinja2={config.enableJinja2 as boolean}
|
enableJinja2={config.enableJinja2 as boolean}
|
||||||
options={getFilteredVariableList(selectedNode?.data?.type, key)}
|
options={getFilteredVariableList(selectedNode?.data?.type, key)}
|
||||||
|
titleVariant={config.titleVariant}
|
||||||
|
size="small"
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
)
|
)
|
||||||
@@ -1206,9 +1122,9 @@ const Properties: FC<PropertiesProps> = ({
|
|||||||
name={key}
|
name={key}
|
||||||
options={getFilteredVariableList(selectedNode?.data?.type, key)}
|
options={getFilteredVariableList(selectedNode?.data?.type, key)}
|
||||||
isCanAdd={!!(values as any)?.group}
|
isCanAdd={!!(values as any)?.group}
|
||||||
|
size="small"
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (config.type === 'caseList') {
|
if (config.type === 'caseList') {
|
||||||
@@ -1226,9 +1142,7 @@ const Properties: FC<PropertiesProps> = ({
|
|||||||
|
|
||||||
if (config.type === 'mappingList') {
|
if (config.type === 'mappingList') {
|
||||||
return (
|
return (
|
||||||
<Form.Item key={key} name={key}
|
<Form.Item key={key} name={key} noStyle>
|
||||||
label={t(`workflow.config.${selectedNode?.data?.type}.${key}`)}
|
|
||||||
>
|
|
||||||
<MappingList name={key} options={getFilteredVariableList(selectedNode?.data?.type, key)} />
|
<MappingList name={key} options={getFilteredVariableList(selectedNode?.data?.type, key)} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
@@ -1238,6 +1152,7 @@ const Properties: FC<PropertiesProps> = ({
|
|||||||
return (
|
return (
|
||||||
<Form.Item key={key} name={key}>
|
<Form.Item key={key} name={key}>
|
||||||
<CycleVarsList
|
<CycleVarsList
|
||||||
|
size="small"
|
||||||
parentName={key}
|
parentName={key}
|
||||||
options={getFilteredVariableList(selectedNode?.data?.type, key)}
|
options={getFilteredVariableList(selectedNode?.data?.type, key)}
|
||||||
/>
|
/>
|
||||||
@@ -1276,87 +1191,14 @@ const Properties: FC<PropertiesProps> = ({
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (config.type === 'conditionList') {
|
||||||
return (
|
return (
|
||||||
<Form.Item
|
<Form.Item
|
||||||
key={key}
|
key={key}
|
||||||
name={key}
|
name={key}
|
||||||
label={t(`workflow.config.${selectedNode?.data?.type}.${key}`)}
|
noStyle
|
||||||
layout={config.type === 'switch' ? 'horizontal' : 'vertical'}
|
>
|
||||||
>
|
<ConditionList
|
||||||
{config.type === 'input'
|
|
||||||
? <Input placeholder={t('common.pleaseEnter')} />
|
|
||||||
: config.type === 'textarea'
|
|
||||||
? <Input.TextArea placeholder={t('common.pleaseEnter')} />
|
|
||||||
: config.type === 'select'
|
|
||||||
? <Select
|
|
||||||
options={config.needTranslation ? (config.options || []).map(vo => ({ ...vo, label: t(vo.label) })) : config.options}
|
|
||||||
placeholder={t('common.pleaseSelect')}
|
|
||||||
/>
|
|
||||||
: config.type === 'inputNumber'
|
|
||||||
? <InputNumber
|
|
||||||
placeholder={t('common.pleaseEnter')}
|
|
||||||
className="rb:w-full!"
|
|
||||||
onChange={(value) => form.setFieldValue(key, value)}
|
|
||||||
/>
|
|
||||||
: config.type === 'slider'
|
|
||||||
? <Slider min={config.min} max={config.max} step={config.step} />
|
|
||||||
: config.type === 'customSelect'
|
|
||||||
? <CustomSelect
|
|
||||||
placeholder={t('common.pleaseSelect')}
|
|
||||||
url={config.url as string}
|
|
||||||
params={config.params}
|
|
||||||
hasAll={false}
|
|
||||||
valueKey={config.valueKey}
|
|
||||||
labelKey={config.labelKey}
|
|
||||||
/>
|
|
||||||
: config.type === 'variableList'
|
|
||||||
? <VariableSelect
|
|
||||||
placeholder={t('common.pleaseSelect')}
|
|
||||||
options={(() => {
|
|
||||||
const baseVariableList = getFilteredVariableList(selectedNode?.data?.type, key);
|
|
||||||
// Apply filtering if specified in config
|
|
||||||
if (config.filterNodeTypes || config.filterVariableNames) {
|
|
||||||
return baseVariableList.filter(variable => {
|
|
||||||
const nodeTypeMatch = !config.filterNodeTypes ||
|
|
||||||
(Array.isArray(config.filterNodeTypes) && config.filterNodeTypes.includes(variable.nodeData?.type));
|
|
||||||
const variableNameMatch = !config.filterVariableNames ||
|
|
||||||
(Array.isArray(config.filterVariableNames) && config.filterVariableNames.includes(variable.label));
|
|
||||||
return nodeTypeMatch || variableNameMatch;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// Filter child nodes for iteration output
|
|
||||||
if (config.filterChildNodes && selectedNode) {
|
|
||||||
const graph = graphRef.current;
|
|
||||||
if (!graph) return [];
|
|
||||||
|
|
||||||
const nodes = graph.getNodes();
|
|
||||||
|
|
||||||
// Find child nodes whose cycle field equals parent node's ID
|
|
||||||
const childNodes = nodes.filter(node => {
|
|
||||||
const nodeData = node.getData();
|
|
||||||
return nodeData?.cycle === selectedNode.id;
|
|
||||||
});
|
|
||||||
|
|
||||||
return baseVariableList.filter(variable =>
|
|
||||||
childNodes.some(node => node.id === variable.nodeData?.id) || selectedNode?.data?.type === 'iteration' && key === 'output' && variable.value.includes('sys.')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return baseVariableList;
|
|
||||||
})()
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
: config.type === 'switch'
|
|
||||||
? <Switch onChange={key === 'group' ? () => { form.setFieldValue('group_variables', []) } : undefined} />
|
|
||||||
: config.type === 'categoryList'
|
|
||||||
? <CategoryList
|
|
||||||
parentName={key}
|
|
||||||
selectedNode={selectedNode}
|
|
||||||
graphRef={graphRef}
|
|
||||||
options={getFilteredVariableList(selectedNode?.data?.type, key)}
|
|
||||||
/>
|
|
||||||
: config.type === 'conditionList'
|
|
||||||
? <ConditionList
|
|
||||||
parentName={key}
|
parentName={key}
|
||||||
options={(() => {
|
options={(() => {
|
||||||
const cycleVars = values?.cycle_vars || [];
|
const cycleVars = values?.cycle_vars || [];
|
||||||
@@ -1375,6 +1217,93 @@ const Properties: FC<PropertiesProps> = ({
|
|||||||
graphRef={graphRef}
|
graphRef={graphRef}
|
||||||
addBtnText={t('workflow.config.addCase')}
|
addBtnText={t('workflow.config.addCase')}
|
||||||
/>
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
key={key}
|
||||||
|
name={key}
|
||||||
|
label={key === 'parallel_count' ? <span className="rb:text-[10px] rb:text-[#5B6167] rb:leading-3.5 rb:-mb-1!">{t(`workflow.config.${selectedNode?.data?.type}.${key}`)}</span> : t(`workflow.config.${selectedNode?.data?.type}.${key}`)}
|
||||||
|
layout={config.type === 'switch' ? 'horizontal' : 'vertical'}
|
||||||
|
className={key === 'parallel_count' ? 'rb:-mt-3! rb:leading-3.5!' : ''}
|
||||||
|
>
|
||||||
|
{config.type === 'input'
|
||||||
|
? <Input placeholder={t('common.pleaseEnter')} />
|
||||||
|
: config.type === 'textarea'
|
||||||
|
? <Input.TextArea placeholder={t('common.pleaseEnter')} />
|
||||||
|
: config.type === 'select'
|
||||||
|
? <Select
|
||||||
|
options={config.needTranslation ? (config.options || []).map(vo => ({ ...vo, label: t(vo.label) })) : config.options}
|
||||||
|
placeholder={t('common.pleaseSelect')}
|
||||||
|
/>
|
||||||
|
: config.type === 'inputNumber'
|
||||||
|
? <InputNumber
|
||||||
|
placeholder={t('common.pleaseEnter')}
|
||||||
|
className="rb:w-full!"
|
||||||
|
onChange={(value) => form.setFieldValue(key, value)}
|
||||||
|
/>
|
||||||
|
: config.type === 'slider'
|
||||||
|
? <RbSlider min={config.min} max={config.max} step={config.step} />
|
||||||
|
: config.type === 'customSelect'
|
||||||
|
? <CustomSelect
|
||||||
|
placeholder={t('common.pleaseSelect')}
|
||||||
|
url={config.url as string}
|
||||||
|
params={config.params}
|
||||||
|
hasAll={false}
|
||||||
|
valueKey={config.valueKey}
|
||||||
|
labelKey={config.labelKey}
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
: config.type === 'variableList'
|
||||||
|
? <VariableSelect
|
||||||
|
placeholder={t(config.placeholder || 'common.pleaseSelect')}
|
||||||
|
options={(() => {
|
||||||
|
const baseVariableList = getFilteredVariableList(selectedNode?.data?.type, key);
|
||||||
|
// Apply filtering if specified in config
|
||||||
|
if (config.filterNodeTypes || config.filterVariableNames) {
|
||||||
|
return baseVariableList.filter(variable => {
|
||||||
|
const nodeTypeMatch = !config.filterNodeTypes ||
|
||||||
|
(Array.isArray(config.filterNodeTypes) && config.filterNodeTypes.includes(variable.nodeData?.type));
|
||||||
|
const variableNameMatch = !config.filterVariableNames ||
|
||||||
|
(Array.isArray(config.filterVariableNames) && config.filterVariableNames.includes(variable.label));
|
||||||
|
return nodeTypeMatch || variableNameMatch;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Filter child nodes for iteration output
|
||||||
|
if (config.filterChildNodes && selectedNode) {
|
||||||
|
const graph = graphRef.current;
|
||||||
|
if (!graph) return [];
|
||||||
|
|
||||||
|
const nodes = graph.getNodes();
|
||||||
|
|
||||||
|
// Find child nodes whose cycle field equals parent node's ID
|
||||||
|
const childNodes = nodes.filter(node => {
|
||||||
|
const nodeData = node.getData();
|
||||||
|
return nodeData?.cycle === selectedNode.id;
|
||||||
|
});
|
||||||
|
|
||||||
|
return baseVariableList.filter(variable =>
|
||||||
|
childNodes.some(node => node.id === variable.nodeData?.id) || selectedNode?.data?.type === 'iteration' && key === 'output' && variable.value.includes('sys.')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return baseVariableList;
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
: config.type === 'switch'
|
||||||
|
? <Switch onChange={key === 'group' ? () => { form.setFieldValue('group_variables', []) } : undefined} />
|
||||||
|
: config.type === 'categoryList'
|
||||||
|
? <CategoryList
|
||||||
|
parentName={key}
|
||||||
|
selectedNode={selectedNode}
|
||||||
|
graphRef={graphRef}
|
||||||
|
options={getFilteredVariableList(selectedNode?.data?.type, key)}
|
||||||
|
/>
|
||||||
|
: config.type === 'editor'
|
||||||
|
? <Editor options={variableList} variant="outlined" size="small" />
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
@@ -1383,11 +1312,6 @@ const Properties: FC<PropertiesProps> = ({
|
|||||||
}
|
}
|
||||||
</Form>
|
</Form>
|
||||||
}
|
}
|
||||||
|
|
||||||
<VariableEditModal
|
|
||||||
ref={variableModalRef}
|
|
||||||
refresh={handleRefreshVariable}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
.properties :global(.ant-input-outlined),
|
||||||
|
.properties :global(.ant-input-number-outlined),
|
||||||
|
.properties :global(.ant-select-outlined:not(.ant-select-customize-input) .ant-select-selector),
|
||||||
|
.properties :global(.ant-input-number-outlined),
|
||||||
|
.properties :global(.ant-input-number-outlined .ant-input-number-handler-wrap) {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
.properties :global(.ant-input-outlined.ant-input-disabled),
|
||||||
|
.properties :global(.ant-input-outlined[disabled]) {
|
||||||
|
background-color: #F6F8FC;
|
||||||
|
}
|
||||||
|
.properties :global(.ant-select-single.ant-select-sm){
|
||||||
|
height: 28px;
|
||||||
|
}
|
||||||
|
.properties :global(.ant-table-wrapper .ant-table-thead>tr>th),
|
||||||
|
.properties :global(.ant-table-wrapper .ant-table-thead>tr>td),
|
||||||
|
.properties :global(.ant-table-wrapper .ant-table) {
|
||||||
|
background-color: #F6F8FC;
|
||||||
|
}
|
||||||
|
.properties :global(.ant-table-wrapper .ant-table),
|
||||||
|
.properties :global(.ant-table-container),
|
||||||
|
.properties :global(.ant-table-wrapper table) {
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
.properties :global(.ant-table-wrapper .ant-table-container table>thead>tr:first-child>*:first-child) {
|
||||||
|
border-start-start-radius: 6px;
|
||||||
|
}
|
||||||
|
.properties :global(.ant-table-wrapper .ant-table-container table>thead>tr:first-child>*:last-child) {
|
||||||
|
border-start-end-radius: 6px;
|
||||||
|
}
|
||||||
|
.properties :global(.ant-table-row:last-child .ant-table-cell:first-child) {
|
||||||
|
border-bottom-left-radius: 6px;
|
||||||
|
}
|
||||||
|
.properties :global(.ant-table-row:last-child .ant-table-cell:last-child) {
|
||||||
|
border-bottom-right-radius: 6px;
|
||||||
|
}
|
||||||
|
.properties :global(.ant-table-wrapper .ant-table) {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
.properties :global(.ant-table-wrapper .ant-table-container) {
|
||||||
|
border-start-start-radius: 6px;
|
||||||
|
border-start-end-radius: 6px;
|
||||||
|
}
|
||||||
|
.properties :global(.ant-table-container) {
|
||||||
|
/* border-left: none;
|
||||||
|
border-top: none;
|
||||||
|
border-bottom: none; */
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.properties :global(.ant-table-wrapper .ant-table-tbody>tr.ant-table-placeholder:hover>th),
|
||||||
|
.properties :global(.ant-table-wrapper .ant-table-tbody>tr.ant-table-placeholder:hover>td),
|
||||||
|
.properties :global(.ant-table-wrapper .ant-table-tbody>tr.ant-table-placeholder),
|
||||||
|
.properties :global(.ant-table-wrapper .ant-table) {
|
||||||
|
background-color: #F6F8FC;
|
||||||
|
}
|
||||||
|
.properties :global(.ant-form-item-horizontal.ant-form-item .ant-form-item-control-input-content:has(> .ant-switch:only-child, > .ant-rate:only-child)) {
|
||||||
|
display: flex;
|
||||||
|
justify-content: end;
|
||||||
|
}
|
||||||
|
.properties :global(.ant-divider-horizontal.ant-divider-sm) {
|
||||||
|
margin-block: 16px;
|
||||||
|
}
|
||||||
|
.properties :global(.ant-form-item) {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.properties :global(.ant-form-item .ant-form-item-label>label) {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.properties :global(.ant-select-single.ant-select-sm .ant-select-selector),
|
||||||
|
.properties :global(.ant-select-dropdown .ant-select-item),.properties :global(.ant-input-number-sm) {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.properties :global(.ant-input-number-out-of-range .ant-input-number-input-wrap input) {
|
||||||
|
color: #212332;
|
||||||
|
}
|
||||||
|
.properties :global(.ant-slider-horizontal .ant-slider-step) {
|
||||||
|
height: 6px;
|
||||||
|
}
|
||||||
|
.properties :global(.ant-select-single.ant-select-sm:not(.ant-select-customize-input) .ant-select-selector) {
|
||||||
|
padding: 0 4px 0 6px ;
|
||||||
|
}
|
||||||
|
.properties :global(.ant-select-single.ant-select-sm:not(.ant-select-customize-input).ant-select-show-arrow .ant-select-selection-item),
|
||||||
|
.properties :global(.ant-select-single.ant-select-sm:not(.ant-select-customize-input).ant-select-show-arrow .ant-select-selection-placeholder) {
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
.properties :global(.ant-select .ant-select-arrow) {
|
||||||
|
font-size: 10px;
|
||||||
|
inset-inline-end: 6px;
|
||||||
|
}
|
||||||
@@ -90,7 +90,7 @@ export const nodeLibrary: NodeLibrary[] = [
|
|||||||
type: "end", icon: endIcon,
|
type: "end", icon: endIcon,
|
||||||
config: {
|
config: {
|
||||||
output: {
|
output: {
|
||||||
type: 'define'
|
type: 'editor'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -125,6 +125,7 @@ export const nodeLibrary: NodeLibrary[] = [
|
|||||||
},
|
},
|
||||||
context: {
|
context: {
|
||||||
type: 'variableList',
|
type: 'variableList',
|
||||||
|
placeholder: 'workflow.config.llm.contextPlaceholder'
|
||||||
},
|
},
|
||||||
messages: {
|
messages: {
|
||||||
type: 'define',
|
type: 'define',
|
||||||
@@ -134,7 +135,8 @@ export const nodeLibrary: NodeLibrary[] = [
|
|||||||
content: undefined,
|
content: undefined,
|
||||||
readonly: true
|
readonly: true
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
|
placeholder: 'workflow.config.llm.messagesPlaceholder'
|
||||||
},
|
},
|
||||||
memory: {
|
memory: {
|
||||||
type: 'memoryConfig',
|
type: 'memoryConfig',
|
||||||
@@ -170,7 +172,8 @@ export const nodeLibrary: NodeLibrary[] = [
|
|||||||
},
|
},
|
||||||
text: {
|
text: {
|
||||||
type: 'variableList',
|
type: 'variableList',
|
||||||
filterLoopIterationVars: true
|
filterLoopIterationVars: true,
|
||||||
|
placeholder: 'workflow.config.parameter-extractor.textPlaceholder'
|
||||||
},
|
},
|
||||||
params: {
|
params: {
|
||||||
type: 'paramList',
|
type: 'paramList',
|
||||||
@@ -178,6 +181,8 @@ export const nodeLibrary: NodeLibrary[] = [
|
|||||||
prompt: {
|
prompt: {
|
||||||
type: 'messageEditor',
|
type: 'messageEditor',
|
||||||
isArray: false,
|
isArray: false,
|
||||||
|
titleVariant: 'borderless',
|
||||||
|
placeholder: 'workflow.config.parameter-extractor.promptPlaceholder'
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -189,7 +194,7 @@ export const nodeLibrary: NodeLibrary[] = [
|
|||||||
{ type: "memory-read", icon: memoryReadIcon,
|
{ type: "memory-read", icon: memoryReadIcon,
|
||||||
config: {
|
config: {
|
||||||
message: {
|
message: {
|
||||||
type: 'messageEditor',
|
type: 'editor',
|
||||||
isArray: false
|
isArray: false
|
||||||
},
|
},
|
||||||
config_id: {
|
config_id: {
|
||||||
@@ -212,7 +217,7 @@ export const nodeLibrary: NodeLibrary[] = [
|
|||||||
{ type: "memory-write", icon: memoryWriteIcon,
|
{ type: "memory-write", icon: memoryWriteIcon,
|
||||||
config: {
|
config: {
|
||||||
message: {
|
message: {
|
||||||
type: 'messageEditor',
|
type: 'editor',
|
||||||
isArray: false
|
isArray: false
|
||||||
},
|
},
|
||||||
config_id: {
|
config_id: {
|
||||||
@@ -270,7 +275,8 @@ export const nodeLibrary: NodeLibrary[] = [
|
|||||||
},
|
},
|
||||||
user_supplement_prompt: {
|
user_supplement_prompt: {
|
||||||
type: 'messageEditor',
|
type: 'messageEditor',
|
||||||
isArray: false
|
isArray: false,
|
||||||
|
titleVariant: 'borderless'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -436,6 +442,7 @@ export const nodeLibrary: NodeLibrary[] = [
|
|||||||
type: 'messageEditor',
|
type: 'messageEditor',
|
||||||
isArray: false,
|
isArray: false,
|
||||||
enableJinja2: true,
|
enableJinja2: true,
|
||||||
|
titleVariant: 'borderless',
|
||||||
defaultValue: "{{arg1}}"
|
defaultValue: "{{arg1}}"
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
|
|
||||||
import { Graph } from '@antv/x6';
|
import { Graph } from '@antv/x6';
|
||||||
import type { KnowledgeConfig } from './components/Properties/Knowledge/types'
|
import type { KnowledgeConfig } from './components/Properties/Knowledge/types'
|
||||||
|
import type { Variable } from './components/Properties/VariableList/types'
|
||||||
export interface NodeConfig {
|
export interface NodeConfig {
|
||||||
type: 'input' | 'textarea' | 'select' | 'inputNumber' | 'slider' | 'customSelect' | 'define' | 'knowledge' | 'variableList' | string;
|
type: 'input' | 'textarea' | 'select' | 'inputNumber' | 'slider' | 'customSelect' | 'define' | 'knowledge' | 'variableList' | string;
|
||||||
|
placeholder?: string;
|
||||||
|
titleVariant?: 'outlined' | 'borderless';
|
||||||
options?: { label: string; value: string }[];
|
options?: { label: string; value: string }[];
|
||||||
|
|
||||||
max?: number;
|
max?: number;
|
||||||
@@ -14,7 +17,7 @@ export interface NodeConfig {
|
|||||||
valueKey?: string;
|
valueKey?: string;
|
||||||
labelKey?: string;
|
labelKey?: string;
|
||||||
|
|
||||||
defaultValue?: any | StartVariableItem[];
|
defaultValue?: any;
|
||||||
|
|
||||||
sys?: Array<{
|
sys?: Array<{
|
||||||
name: string;
|
name: string;
|
||||||
@@ -37,6 +40,7 @@ export interface NodeProperties {
|
|||||||
id?: string;
|
id?: string;
|
||||||
config?: Record<string, NodeConfig>;
|
config?: Record<string, NodeConfig>;
|
||||||
hidden?: boolean;
|
hidden?: boolean;
|
||||||
|
cycle?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NodeLibrary {
|
export interface NodeLibrary {
|
||||||
@@ -87,27 +91,12 @@ export interface WorkflowConfig {
|
|||||||
updated_at: number;
|
updated_at: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VariableEditModalRef {
|
|
||||||
handleOpen: (values?: StartVariableItem) => void;
|
|
||||||
}
|
|
||||||
export interface StartVariableItem {
|
|
||||||
name: string;
|
|
||||||
type: string;
|
|
||||||
required: boolean;
|
|
||||||
description: string;
|
|
||||||
max_length?: number;
|
|
||||||
default?: string;
|
|
||||||
readonly?: boolean;
|
|
||||||
defaultValue?: any;
|
|
||||||
value?: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ChatRef {
|
export interface ChatRef {
|
||||||
handleOpen: () => void;
|
handleOpen: () => void;
|
||||||
}
|
}
|
||||||
export type GraphRef = React.MutableRefObject<Graph | undefined>
|
export type GraphRef = React.MutableRefObject<Graph | undefined>
|
||||||
export interface VariableConfigModalRef {
|
export interface VariableConfigModalRef {
|
||||||
handleOpen: (values: StartVariableItem[]) => void;
|
handleOpen: (values: Variable[]) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ChatVariable {
|
export interface ChatVariable {
|
||||||
|
|||||||
Reference in New Issue
Block a user