feat(web): http node config support editor

This commit is contained in:
zhaoying
2026-03-02 17:26:24 +08:00
parent 5abfcdfbe8
commit 81353538e5
3 changed files with 37 additions and 30 deletions

View File

@@ -30,7 +30,8 @@ export interface LexicalEditorProps {
lineHeight?: number; lineHeight?: number;
size?: 'default' | 'small'; size?: 'default' | 'small';
type?: 'input' | 'textarea', type?: 'input' | 'textarea',
language?: 'string' | 'jinja2' language?: 'string' | 'jinja2';
className?: string;
} }
const theme = { const theme = {
@@ -58,7 +59,9 @@ const Editor: FC<LexicalEditorProps> =({
variant = 'borderless', variant = 'borderless',
size = 'default', size = 'default',
type = 'textarea', type = 'textarea',
language = 'string' language = 'string',
height,
className
}) => { }) => {
const [_count, setCount] = useState(0); const [_count, setCount] = useState(0);
const [enableJinja2, setEnableJinja2] = useState(false) const [enableJinja2, setEnableJinja2] = useState(false)
@@ -156,23 +159,23 @@ const Editor: FC<LexicalEditorProps> =({
}; };
const minheight = useMemo(() => { const minheight = useMemo(() => {
if (type === 'input') { if (type === 'input') {
return `${size === 'small' ? 26 : 30}px` return `${height ? height : size === 'small' ? 28 : 30}px`
} }
return `${size === 'small' ? 60 : 120}px` return `${height ? height : size === 'small' ? 60 : 120}px`
}, [type, size]) }, [type, size, height])
const fontSize = useMemo(() => { const fontSize = useMemo(() => {
return `${size === 'small' ? 12 : 14}px` return `${size === 'small' ? 12 : 14}px`
}, [size]) }, [size])
const lineHeight = useMemo(() => { const lineHeight = useMemo(() => {
return `${size === 'small' ? 16 : 20}px` return `${height ? height : size === 'small' ? 16 : 20}px`
}, [size]) }, [size])
const placeHolderMinheight = useMemo(() => { const placeHolderMinheight = useMemo(() => {
return `${size === 'small' ? 16 : 30}px` return `${height ? height : size === 'small' ? 16 : 30}px`
}, [type, size]) }, [type, size, height])
return ( return (
<LexicalComposer initialConfig={initialConfig}> <LexicalComposer initialConfig={initialConfig}>
<div style={{ position: 'relative' }}> <div style={{ position: 'relative' }} className={className}>
<RichTextPlugin <RichTextPlugin
contentEditable={ contentEditable={
enableLineNumbers ? ( enableLineNumbers ? (

View File

@@ -1,9 +1,11 @@
import { type FC, 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 } 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 Editor from '../../Editor'
export interface TableRow { export interface TableRow {
key?: string; key?: string;
@@ -21,7 +23,7 @@ interface EditableTableProps {
size?: "small" size?: "small"
} }
const EditableTable: React.FC<EditableTableProps> = ({ const EditableTable: FC<EditableTableProps> = ({
parentName, parentName,
title, title,
options = [], options = [],
@@ -37,6 +39,13 @@ const EditableTable: React.FC<EditableTableProps> = ({
...(typeOptions.length > 0 && { type: typeOptions[0].value }) ...(typeOptions.length > 0 && { type: typeOptions[0].value })
}); });
// Filter options based on boolean type if needed
const booleanFilterOptions = useMemo(() => {
return filterBooleanType
? options.filter(option => option.dataType !== 'boolean')
: options
}, [options, filterBooleanType])
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 cellClassName="rb:p-1!" const cellClassName="rb:p-1!"
@@ -49,14 +58,12 @@ const EditableTable: React.FC<EditableTableProps> = ({
className: cellClassName, 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 <Editor
placeholder={t('common.pleaseSelect')} options={booleanFilterOptions}
// size="small" type="input"
options={options}
filterBooleanType={filterBooleanType}
popupMatchSelectWidth={false}
className={contentClassName} className={contentClassName}
size={size} size={size}
height={16}
/> />
</Form.Item> </Form.Item>
) )
@@ -101,19 +108,17 @@ const EditableTable: React.FC<EditableTableProps> = ({
{(form) => { {(form) => {
const currentType = form.getFieldValue([...Array.isArray(parentName) ? parentName : [parentName], index, 'type']); const currentType = form.getFieldValue([...Array.isArray(parentName) ? parentName : [parentName], index, 'type']);
const filteredOptions = currentType === 'file' const filteredOptions = currentType === 'file'
? options.filter(option => option.dataType === 'file') ? booleanFilterOptions.filter(option => option.dataType.includes('file'))
: options; : booleanFilterOptions;
return ( return (
<Form.Item name={[index, 'value']} noStyle> <Form.Item name={[index, 'value']} noStyle>
<VariableSelect <Editor
placeholder={t('common.pleaseSelect')}
// size="small"
options={filteredOptions} options={filteredOptions}
filterBooleanType={filterBooleanType} type="input"
popupMatchSelectWidth={false}
className={contentClassName} className={contentClassName}
size={size} size={size}
height={16}
/> />
</Form.Item> </Form.Item>
); );

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing * @Author: ZhaoYing
* @Date: 2026-02-09 18:35:43 * @Date: 2026-02-09 18:35:43
* @Last Modified by: ZhaoYing * @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-09 18:35:43 * @Last Modified time: 2026-03-02 17:24:51
*/ */
import { type FC, useRef, useState } from "react"; import { type FC, useRef, useState } from "react";
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
@@ -13,7 +13,6 @@ 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'
import type { AuthConfigModalRef, HttpRequestConfigForm } from './types' import type { AuthConfigModalRef, HttpRequestConfigForm } from './types'
import VariableSelect from "../VariableSelect";
import MessageEditor from '../MessageEditor' import MessageEditor from '../MessageEditor'
import EditableTable from './EditableTable' import EditableTable from './EditableTable'
import { portTextAttrs } from '../../../constant' import { portTextAttrs } from '../../../constant'
@@ -159,7 +158,7 @@ const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: an
<EditableTable <EditableTable
size="small" 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' || vo.dataType.includes('file'))}
typeOptions={[ typeOptions={[
{ label: 'text', value: 'text' }, { label: 'text', value: 'text' },
{ label: 'file', value: 'file' } { label: 'file', value: 'file' }
@@ -201,10 +200,10 @@ const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: an
} }
{values?.body?.content_type === 'binary' && {values?.body?.content_type === 'binary' &&
<Form.Item name={['body', 'data']} noStyle> <Form.Item name={['body', 'data']} noStyle>
<VariableSelect <Editor
placeholder={t('common.pleaseSelect')} placeholder={t('common.pleaseSelect')}
options={options.filter(vo => vo.dataType.includes('file'))} options={options.filter(vo => vo.dataType.includes('file'))}
filterBooleanType={true} type="input"
size="small" size="small"
/> />
</Form.Item> </Form.Item>