Merge branch 'feat/sprint-web-flow' into feat/tags

This commit is contained in:
谨欣
2024-08-19 10:41:25 +08:00
11 changed files with 145 additions and 101 deletions

View File

@@ -2,6 +2,9 @@ import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
const en = {
UploadData: 'Upload Data',
CodeEditor: 'Code Editor:',
openCodeEditor:'Open Code Editor',
Knowledge_Space: 'Knowledge',
space: 'space',
Vector: 'Vector',
@@ -234,6 +237,9 @@ export interface Resources {
}
const zh: Resources['translation'] = {
UploadData: '上传数据',
CodeEditor: '代码编辑:',
openCodeEditor: '打开代码编辑器',
Knowledge_Space: '知识库',
space: '知识库',
Vector: '向量',

View File

@@ -15,10 +15,11 @@ import {
RenderTreeSelect,
RenderTimePicker,
RenderTextArea,
RenderUpload,
RenderCodeEditor,
RenderPassword,
RenderVariables,
} from './node-renderer';
import { convertKeysToCamelCase } from '@/utils/flow';
interface NodeParamHandlerProps {
node: IFlowNode;
@@ -140,11 +141,13 @@ const NodeParamHandler: React.FC<NodeParamHandlerProps> = ({ node, data, label,
case 'time_picker':
return <RenderTimePicker {...props} />;
case 'tree_select':
return <RenderPassword {...props} />;
case 'password':
return <RenderTreeSelect {...props} />;
case 'variables':
return <RenderVariables {...props} />;
case 'password':
return <RenderPassword {...props} />;
case 'upload':
return <RenderUpload {...props} />;
case 'code_editor':
return <RenderCodeEditor {...props} />;
default:
return null;
}

View File

@@ -0,0 +1,67 @@
import React, { useState, useMemo } from 'react';
import { Button, Modal } from 'antd';
import Editor from '@monaco-editor/react';
import { IFlowNodeParameter } from '@/types/flow';
import { convertKeysToCamelCase } from '@/utils/flow';
import { useTranslation } from 'react-i18next';
type Props = {
data: IFlowNodeParameter;
defaultValue: any;
onChange: (value: any) => void;
};
export const RenderCodeEditor = (params: Props) => {
const { t } = useTranslation();
const { data, defaultValue, onChange } = params;
const attr = convertKeysToCamelCase(data.ui?.attr || {});
const [isModalOpen, setIsModalOpen] = useState(false);
const showModal = () => {
setIsModalOpen(true);
};
const handleOk = () => {
setIsModalOpen(false);
};
const handleCancel = () => {
setIsModalOpen(false);
};
/**
* 设置弹窗宽度
*/
const modalWidth = useMemo(() => {
if (data?.ui?.editor?.width) {
return data?.ui?.editor?.width + 100
}
return '80%';
}, [data?.ui?.editor?.width]);
return (
<div style={{ textAlign: 'center' }} className="p-2 text-sm">
<Button type="primary" onClick={showModal}>
{t('openCodeEditor')}
</Button>
<Modal title={t('openCodeEditor')} width={modalWidth} open={isModalOpen} onOk={handleOk} onCancel={handleCancel}>
<Editor
{...data?.ui?.attr}
width={data?.ui?.editor?.width || '100%'}
value={defaultValue}
style={{ padding: '10px' }}
height={data?.ui?.editor?.height || 200}
defaultLanguage={data?.ui?.language}
onChange={onChange}
theme='vs-dark'
options={{
minimap: {
enabled: false,
},
wordWrap: 'on',
}}
/>
</Modal>
</div>
);
};

View File

@@ -11,7 +11,6 @@ type Props = {
export const RenderDatePicker = (params: Props) => {
const { data, defaultValue, onChange } = params;
console.log('data', data);
const attr = convertKeysToCamelCase(data.ui?.attr || {});

View File

@@ -8,5 +8,7 @@ export * from './textarea';
export * from './slider';
export * from './time-picker';
export * from './tree-select';
export * from './codeEditor';
export * from './upload';
export * from './password';
export * from './variables';

View File

@@ -25,14 +25,14 @@ export const RenderSlider = (params: TextAreaProps) => {
{data?.ui?.show_input ? (
<Row>
<Col span={12}>
<Slider {...attr} onChange={onChangeSlider} value={typeof inputValue === 'number' ? inputValue : 0} />
<Slider className="w-full nodrag" {...attr} onChange={onChangeSlider} value={typeof inputValue === 'number' ? inputValue : 0} />
</Col>
<Col span={4}>
<InputNumber {...attr} style={{ margin: '0 16px' }} value={inputValue} onChange={onChangeSlider} />
</Col>
</Row>
) : (
<Slider {...attr} onChange={onChangeSlider} value={typeof inputValue === 'number' ? inputValue : 0} />
<Slider className="w-full nodrag" {...attr} onChange={onChangeSlider} value={typeof inputValue === 'number' ? inputValue : 0} />
)}
</>
);

View File

@@ -13,6 +13,7 @@ type TextAreaProps = {
export const RenderTextArea = (params: TextAreaProps) => {
const { data, defaultValue, onChange } = params;
const attr = convertKeysToCamelCase(data.ui?.attr || {});
return (

View File

@@ -1,107 +1,29 @@
import React, { useState } from 'react';
import { TreeSelect } from 'antd';
import type { TreeSelectProps } from 'antd';
import { IFlowNodeParameter } from '@/types/flow';
import { Label } from '@mui/icons-material';
import { convertKeysToCamelCase } from '@/utils/flow';
type TextAreaProps = {
data: IFlowNodeParameter;
defaultValue: any;
onChange: (value: any) => void;
};
const treeData = [
{
value: 'parent 1',
title: 'parent 1',
children: [
{
value: 'parent 1-0',
title: 'parent 1-0',
children: [
{
value: 'leaf1',
title: 'leaf1',
},
{
value: 'leaf2',
title: 'leaf2',
},
{
value: 'leaf3',
title: 'leaf3',
},
{
value: 'leaf4',
title: 'leaf4',
},
{
value: 'leaf5',
title: 'leaf5',
},
{
value: 'leaf6',
title: 'leaf6',
},
],
},
{
value: 'parent 1-1',
title: 'parent 1-1',
children: [
{
value: 'leaf11',
title: <b style={{ color: '#08c' }}>leaf11</b>,
},
],
},
],
},
];
export const RenderTreeSelect = (params: TextAreaProps) => {
const { data, defaultValue, onChange } = params;
// console.log(data.options);
// const [value, setValue] = useState<string>();
// const onChange = (newValue: string) => {
// setValue(newValue);
// };
const [dropdownVisible, setDropdownVisible] = useState(false);
const handleDropdownVisibleChange = (visible: boolean | ((prevState: boolean) => boolean)) => {
setDropdownVisible(visible);
// 你可以在这里执行更多的逻辑,比如发送请求、更新状态等
console.log('Dropdown is now:', visible ? 'visible' : 'hidden');
};
const focus = () => {
// console.log('focus==========');
};
const attr = convertKeysToCamelCase(data.ui?.attr || {});
return (
<div className="p-2 text-sm">
<TreeSelect
className="w-full nodrag"
fieldNames={{ label: 'label', value: 'value', children: 'children' }}
{...data.ui.attr}
{...attr}
style={{ width: '100%' }}
value={defaultValue}
treeDefaultExpandAll
onChange={onChange}
treeData={data.options}
onDropdownVisibleChange={handleDropdownVisibleChange}
/>
// TODO: Implement the TreeSelect component
// <TreeSelect
// showSearch
// style={{ width: '100%' }}
// value={value}
// dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
// placeholder="Please select"
// allowClear
// treeDefaultExpandAll
// onChange={onChange}
// treeData={treeData}
// getPopupContainer={() => document.body}
// />
</div>
);
};

View File

@@ -0,0 +1,40 @@
import React from 'react';
import { UploadOutlined } from '@ant-design/icons';
import type { UploadProps } from 'antd';
import { Button, message, Upload } from 'antd';
import { convertKeysToCamelCase } from '@/utils/flow';
import { IFlowNodeParameter } from '@/types/flow';
import { useTranslation } from 'react-i18next';
const props: UploadProps = {
name: 'file',
action: 'https://660d2bd96ddfa2943b33731c.mockapi.io/api/upload',
headers: {
authorization: 'authorization-text',
},
};
type Props = {
data: IFlowNodeParameter;
defaultValue: any;
onChange: (value: any) => void;
};
export const RenderUpload = (params: Props) => {
const { t } = useTranslation();
const { data, defaultValue, onChange } = params;
const attr = convertKeysToCamelCase(data.ui?.attr || {});
return (
<div style={{ textAlign: 'center' }} className="p-2 text-sm">
<Upload {...attr} {...props}>
<Button icon={<UploadOutlined />}>{t('UploadData')}</Button>
</Upload>
</div>
)
}

View File

@@ -54,10 +54,15 @@ export type IFlowNodeParameter = {
export type IFlowNodeParameterUI = {
ui_type: string;
language: string;
attr: {
disabled: boolean;
[key: string]: any;
};
editor: {
width: Number;
height: Number;
};
show_input: boolean;
};

View File

@@ -1,7 +1,6 @@
import { message } from 'antd';
import axios from './ctx-axios';
import { isPlainObject } from 'lodash';
const DEFAULT_HEADERS = {
'content-type': 'application/json',
};