mirror of
https://github.com/csunny/DB-GPT.git
synced 2025-09-12 12:37:14 +00:00
style: optimize code of flow (#1817)
This commit is contained in:
@@ -5,7 +5,7 @@ import RequiredIcon from './required-icon';
|
|||||||
import NodeHandler from './node-handler';
|
import NodeHandler from './node-handler';
|
||||||
import { InfoCircleOutlined } from '@ant-design/icons';
|
import { InfoCircleOutlined } from '@ant-design/icons';
|
||||||
import { RenderSelect, RenderSlider, RenderTreeSelect, RenderTimePicker, RenderTextArea, RenderCascader } from './node-renderer';
|
import { RenderSelect, RenderSlider, RenderTreeSelect, RenderTimePicker, RenderTextArea, RenderCascader } from './node-renderer';
|
||||||
import { uiAtrrtUnderlineToHump } from '@/utils/flow'
|
import { uiAtrrtUnderlineToHump } from '@/utils/flow';
|
||||||
interface NodeParamHandlerProps {
|
interface NodeParamHandlerProps {
|
||||||
node: IFlowNode;
|
node: IFlowNode;
|
||||||
data: IFlowNodeParameter;
|
data: IFlowNodeParameter;
|
||||||
@@ -104,25 +104,20 @@ const NodeParamHandler: React.FC<NodeParamHandlerProps> = ({ node, data, label,
|
|||||||
function renderNodeWithUiParam(data: IFlowNodeParameter) {
|
function renderNodeWithUiParam(data: IFlowNodeParameter) {
|
||||||
let defaultValue = data.value !== null && data.value !== undefined ? data.value : data.default;
|
let defaultValue = data.value !== null && data.value !== undefined ? data.value : data.default;
|
||||||
if (data?.ui?.attr) {
|
if (data?.ui?.attr) {
|
||||||
uiAtrrtUnderlineToHump(data.ui.attr)
|
uiAtrrtUnderlineToHump(data.ui.attr);
|
||||||
}
|
}
|
||||||
// TODO: 根据ui_type渲染不同的组件
|
// TODO: 根据ui_type渲染不同的组件
|
||||||
switch (data?.ui?.ui_type) {
|
switch (data?.ui?.ui_type) {
|
||||||
case 'select':
|
case 'select':
|
||||||
return <RenderSelect data={data} defaultValue={defaultValue} onChange={onChange} />;
|
return <RenderSelect data={data} defaultValue={defaultValue} onChange={onChange} />;
|
||||||
break
|
|
||||||
case 'text_area':
|
case 'text_area':
|
||||||
return <RenderTextArea data={data} defaultValue={defaultValue} onChange={onChange} />;
|
return <RenderTextArea data={data} defaultValue={defaultValue} onChange={onChange} />;
|
||||||
break
|
|
||||||
case 'slider':
|
case 'slider':
|
||||||
return <RenderSlider data={data} defaultValue={defaultValue} onChange={onChange} />;
|
return <RenderSlider data={data} defaultValue={defaultValue} onChange={onChange} />;
|
||||||
break
|
|
||||||
case 'time_picker':
|
case 'time_picker':
|
||||||
return <RenderTimePicker data={data} defaultValue={defaultValue} onChange={onChange} />;
|
return <RenderTimePicker data={data} defaultValue={defaultValue} onChange={onChange} />;
|
||||||
break
|
|
||||||
case 'tree_select':
|
case 'tree_select':
|
||||||
return <RenderTreeSelect data={data} defaultValue={defaultValue} onChange={onChange} />;
|
return <RenderTreeSelect data={data} defaultValue={defaultValue} onChange={onChange} />;
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,4 +129,3 @@ const NodeParamHandler: React.FC<NodeParamHandlerProps> = ({ node, data, label,
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default NodeParamHandler;
|
export default NodeParamHandler;
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
export * from "./select";
|
export * from './select';
|
||||||
export * from "./cascader";
|
export * from './cascader';
|
||||||
export * from "./textarea";
|
export * from './textarea';
|
||||||
export * from "./slider";
|
export * from './slider';
|
||||||
export * from "./timePicker";
|
export * from './timePicker';
|
||||||
export * from "./treeSelect";
|
export * from './treeSelect';
|
||||||
|
@@ -1,21 +1,23 @@
|
|||||||
import { IFlowNodeParameter } from "@/types/flow";
|
import { IFlowNodeParameter } from '@/types/flow';
|
||||||
import { Select } from "antd";
|
import { Select } from 'antd';
|
||||||
|
|
||||||
type SelectProps = {
|
type SelectProps = {
|
||||||
data: IFlowNodeParameter;
|
data: IFlowNodeParameter;
|
||||||
defaultValue: any;
|
defaultValue: any;
|
||||||
onChange: (value: any) => void;
|
onChange: (value: any) => void;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const RenderSelect = (params: SelectProps) => {
|
export const RenderSelect = (params: SelectProps) => {
|
||||||
const { data, defaultValue, onChange } = params;
|
const { data, defaultValue, onChange } = params;
|
||||||
|
|
||||||
return data.options?.length > 0 && (
|
return (
|
||||||
<Select
|
data.options?.length > 0 && (
|
||||||
className="w-full nodrag"
|
<Select
|
||||||
defaultValue={defaultValue}
|
className="w-full nodrag"
|
||||||
options={data.options.map((item: any) => ({ label: item.label, value: item.value }))}
|
defaultValue={defaultValue}
|
||||||
onChange={onChange}
|
options={data.options.map((item: any) => ({ label: item.label, value: item.value }))}
|
||||||
/>
|
onChange={onChange}
|
||||||
)
|
/>
|
||||||
}
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
@@ -1,53 +1,38 @@
|
|||||||
import { IFlowNodeParameter } from "@/types/flow";
|
import { IFlowNodeParameter } from '@/types/flow';
|
||||||
import { Col, InputNumber, Row, Slider, Space } from 'antd';
|
import { Col, InputNumber, Row, Slider, Space } from 'antd';
|
||||||
import { uiAtrrtUnderlineToHump } from '@/utils/flow'
|
|
||||||
import type { InputNumberProps } from 'antd';
|
import type { InputNumberProps } from 'antd';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
|
||||||
type TextAreaProps = {
|
type TextAreaProps = {
|
||||||
data: IFlowNodeParameter;
|
data: IFlowNodeParameter;
|
||||||
defaultValue: any;
|
defaultValue: any;
|
||||||
onChange: (value: any) => void;
|
onChange: (value: any) => void;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const RenderSlider = (params: TextAreaProps) => {
|
export const RenderSlider = (params: TextAreaProps) => {
|
||||||
const { data, defaultValue, onChange } = params;
|
const { data, defaultValue, onChange } = params;
|
||||||
|
|
||||||
const [inputValue, setInputValue] = useState(defaultValue);
|
const [inputValue, setInputValue] = useState(defaultValue);
|
||||||
|
|
||||||
|
const onChangeSlider: InputNumberProps['onChange'] = (newValue) => {
|
||||||
|
setInputValue(newValue as number);
|
||||||
|
onChange(newValue as number);
|
||||||
|
};
|
||||||
|
|
||||||
const onChangeSlider: InputNumberProps['onChange'] = (newValue) => {
|
|
||||||
setInputValue(newValue as number);
|
|
||||||
onChange(newValue as number)
|
|
||||||
};
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{data?.ui?.show_input ? <Row>
|
{data?.ui?.show_input ? (
|
||||||
<Col span={12}>
|
<Row>
|
||||||
<Slider
|
<Col span={12}>
|
||||||
{...data.ui.attr}
|
<Slider {...data.ui.attr} onChange={onChangeSlider} value={typeof inputValue === 'number' ? inputValue : 0} />
|
||||||
onChange={onChangeSlider}
|
</Col>
|
||||||
value={typeof inputValue === 'number' ? inputValue : 0}
|
<Col span={4}>
|
||||||
/>
|
<InputNumber {...data.ui.attr} style={{ margin: '0 16px' }} value={inputValue} onChange={onChangeSlider} />
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={4}>
|
</Row>
|
||||||
<InputNumber
|
) : (
|
||||||
{...data.ui.attr}
|
<Slider {...data.ui.attr} onChange={onChangeSlider} value={typeof inputValue === 'number' ? inputValue : 0} />
|
||||||
style={{ margin: '0 16px' }}
|
)}
|
||||||
value={inputValue}
|
|
||||||
onChange={onChangeSlider}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>:
|
|
||||||
<Slider
|
|
||||||
{...data.ui.attr}
|
|
||||||
onChange={onChangeSlider}
|
|
||||||
value={typeof inputValue === 'number' ? inputValue : 0}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
@@ -1,53 +1,36 @@
|
|||||||
import { IFlowNodeParameter } from "@/types/flow";
|
import { IFlowNodeParameter } from '@/types/flow';
|
||||||
import { Col, InputNumber, Row, Slider, Space } from 'antd';
|
import { Col, InputNumber, Row, Slider, Space } from 'antd';
|
||||||
import { uiAtrrtUnderlineToHump } from '@/utils/flow'
|
|
||||||
import type { InputNumberProps } from 'antd';
|
import type { InputNumberProps } from 'antd';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
|
||||||
type TextAreaProps = {
|
type TextAreaProps = {
|
||||||
data: IFlowNodeParameter;
|
data: IFlowNodeParameter;
|
||||||
defaultValue: any;
|
defaultValue: any;
|
||||||
onChange: (value: any) => void;
|
onChange: (value: any) => void;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const RenderSlider = (params: TextAreaProps) => {
|
export const RenderSlider = (params: TextAreaProps) => {
|
||||||
const { data, defaultValue, onChange } = params;
|
const { data, defaultValue, onChange } = params;
|
||||||
|
const [inputValue, setInputValue] = useState(defaultValue);
|
||||||
|
|
||||||
const [inputValue, setInputValue] = useState(defaultValue);
|
const onChangeSlider: InputNumberProps['onChange'] = (newValue) => {
|
||||||
|
setInputValue(newValue as number);
|
||||||
const onChangeSlider: InputNumberProps['onChange'] = (newValue) => {
|
onChange(newValue as number);
|
||||||
setInputValue(newValue as number);
|
};
|
||||||
onChange(newValue as number)
|
|
||||||
};
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{data?.ui?.show_input ? <Row>
|
{data?.ui?.show_input ? (
|
||||||
<Col span={12}>
|
<Row>
|
||||||
<Slider
|
<Col span={12}>
|
||||||
{...data.ui.attr}
|
<Slider {...data.ui.attr} onChange={onChangeSlider} value={typeof inputValue === 'number' ? inputValue : 0} />
|
||||||
onChange={onChangeSlider}
|
</Col>
|
||||||
value={typeof inputValue === 'number' ? inputValue : 0}
|
<Col span={4}>
|
||||||
/>
|
<InputNumber {...data.ui.attr} style={{ margin: '0 16px' }} value={inputValue} onChange={onChangeSlider} />
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={4}>
|
</Row>
|
||||||
<InputNumber
|
) : (
|
||||||
{...data.ui.attr}
|
<Slider {...data.ui.attr} onChange={onChangeSlider} value={typeof inputValue === 'number' ? inputValue : 0} />
|
||||||
style={{ margin: '0 16px' }}
|
)}
|
||||||
value={inputValue}
|
|
||||||
onChange={onChangeSlider}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>:
|
|
||||||
<Slider
|
|
||||||
{...data.ui.attr}
|
|
||||||
onChange={onChangeSlider}
|
|
||||||
value={typeof inputValue === 'number' ? inputValue : 0}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { IFlowNodeParameter } from "@/types/flow";
|
import { IFlowNodeParameter } from '@/types/flow';
|
||||||
import { Input } from 'antd';
|
import { Input } from 'antd';
|
||||||
import { uiAtrrtUnderlineToHump } from '@/utils/flow'
|
import { uiAtrrtUnderlineToHump } from '@/utils/flow';
|
||||||
|
|
||||||
const { TextArea } = Input;
|
const { TextArea } = Input;
|
||||||
|
|
||||||
@@ -8,15 +8,11 @@ type TextAreaProps = {
|
|||||||
data: IFlowNodeParameter;
|
data: IFlowNodeParameter;
|
||||||
defaultValue: any;
|
defaultValue: any;
|
||||||
onChange: (value: any) => void;
|
onChange: (value: any) => void;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
export const RenderTextArea = (params: TextAreaProps) => {
|
export const RenderTextArea = (params: TextAreaProps) => {
|
||||||
const { data, defaultValue, onChange } = params;
|
const { data, defaultValue, onChange } = params;
|
||||||
if(data?.ui?.autosize){
|
uiAtrrtUnderlineToHump(data?.ui?.attr?.autosize || {});
|
||||||
uiAtrrtUnderlineToHump(data.ui.autosize)
|
|
||||||
}
|
return <TextArea {...data.ui.attr} defaultValue={defaultValue} onChange={(e) => onChange(e.target.value)} {...data.ui.autosize} rows={4} />;
|
||||||
return (
|
};
|
||||||
<TextArea {...data.ui.attr} defaultValue={defaultValue} onChange={(e) => onChange(e.target.value)} {...data.ui.autosize} rows={4} />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
@@ -1,34 +1,23 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import type { TimePickerProps } from 'antd';
|
import type { TimePickerProps } from 'antd';
|
||||||
import { TimePicker } from 'antd';
|
import { TimePicker } from 'antd';
|
||||||
|
import { IFlowNodeParameter } from '@/types/flow';
|
||||||
|
|
||||||
import { IFlowNodeParameter } from "@/types/flow";
|
|
||||||
|
|
||||||
type TextAreaProps = {
|
type TextAreaProps = {
|
||||||
data: IFlowNodeParameter;
|
data: IFlowNodeParameter;
|
||||||
defaultValue: any;
|
defaultValue: any;
|
||||||
onChange: (value: any) => void;
|
onChange: (value: any) => void;
|
||||||
}
|
};
|
||||||
export const RenderTimePicker = (params: TextAreaProps) => {
|
export const RenderTimePicker = (params: TextAreaProps) => {
|
||||||
const { data, defaultValue, onChange } = params;
|
const { data, defaultValue, onChange } = params;
|
||||||
const [value, setValue] = useState(defaultValue);
|
const [value, setValue] = useState(defaultValue);
|
||||||
|
|
||||||
// dayjs.extend(customParseFormat);
|
// dayjs.extend(customParseFormat);
|
||||||
|
|
||||||
const onChangeTime: TimePickerProps['onChange'] = (time, timeString) => {
|
const onChangeTime: TimePickerProps['onChange'] = (time, timeString) => {
|
||||||
// console.log(timeString);
|
onChange(timeString);
|
||||||
onChange(timeString)
|
setValue(time);
|
||||||
setValue(time)
|
};
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return <TimePicker style={{ width: '100%' }} {...data.ui.attr} value={value} onChange={onChangeTime} />;
|
||||||
<TimePicker
|
};
|
||||||
style={{ width: '100%' }}
|
|
||||||
{...data.ui.attr} value={value}
|
|
||||||
onChange={onChangeTime} />
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@@ -1,94 +1,97 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { TreeSelect } from 'antd';
|
import { TreeSelect } from 'antd';
|
||||||
import type { TreeSelectProps } from 'antd';
|
import type { TreeSelectProps } from 'antd';
|
||||||
import { IFlowNodeParameter } from "@/types/flow";
|
import { IFlowNodeParameter } from '@/types/flow';
|
||||||
import { Label } from '@mui/icons-material';
|
import { Label } from '@mui/icons-material';
|
||||||
|
|
||||||
type TextAreaProps = {
|
type TextAreaProps = {
|
||||||
data: IFlowNodeParameter;
|
data: IFlowNodeParameter;
|
||||||
defaultValue: any;
|
defaultValue: any;
|
||||||
onChange: (value: any) => void;
|
onChange: (value: any) => void;
|
||||||
}
|
};
|
||||||
const treeData = [
|
const treeData = [
|
||||||
{
|
{
|
||||||
value: 'parent 1',
|
value: 'parent 1',
|
||||||
title: 'parent 1',
|
title: 'parent 1',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
value: 'parent 1-0',
|
value: 'parent 1-0',
|
||||||
title: 'parent 1-0',
|
title: 'parent 1-0',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
value: 'leaf1',
|
value: 'leaf1',
|
||||||
title: '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',
|
value: 'leaf2',
|
||||||
title: 'parent 1-1',
|
title: 'leaf2',
|
||||||
children: [
|
},
|
||||||
{
|
{
|
||||||
value: 'leaf11',
|
value: 'leaf3',
|
||||||
title: <b style={{ color: '#08c' }}>leaf11</b>,
|
title: 'leaf3',
|
||||||
},
|
},
|
||||||
],
|
{
|
||||||
},
|
value: 'leaf4',
|
||||||
],
|
title: 'leaf4',
|
||||||
},
|
},
|
||||||
];
|
{
|
||||||
export const RenderTreeSelect = (params: TextAreaProps) => {
|
value: 'leaf5',
|
||||||
const { data, defaultValue, onChange } = params;
|
title: 'leaf5',
|
||||||
// console.log(data.options);
|
},
|
||||||
// const [value, setValue] = useState<string>();
|
{
|
||||||
|
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) => {
|
// const onChange = (newValue: string) => {
|
||||||
// setValue(newValue);
|
// setValue(newValue);
|
||||||
// };
|
// };
|
||||||
const [dropdownVisible, setDropdownVisible] = useState(false);
|
const [dropdownVisible, setDropdownVisible] = useState(false);
|
||||||
|
|
||||||
const handleDropdownVisibleChange = (visible) => {
|
|
||||||
setDropdownVisible(visible);
|
|
||||||
// 你可以在这里执行更多的逻辑,比如发送请求、更新状态等
|
|
||||||
console.log('Dropdown is now:', visible ? 'visible' : 'hidden');
|
|
||||||
};
|
|
||||||
const focuss = ()=>{
|
|
||||||
console.log('focus==========');
|
|
||||||
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<TreeSelect
|
|
||||||
fieldNames={{ label: 'label', value: 'value', children: 'children' }}
|
|
||||||
{...data.ui.attr}
|
|
||||||
style={{ width: '100%' }}
|
|
||||||
value={defaultValue}
|
|
||||||
treeDefaultExpandAll
|
|
||||||
onChange={onChange}
|
|
||||||
treeData={data.options}
|
|
||||||
onDropdownVisibleChange={handleDropdownVisibleChange}
|
|
||||||
|
|
||||||
/>
|
const handleDropdownVisibleChange = (visible: boolean | ((prevState: boolean) => boolean)) => {
|
||||||
|
setDropdownVisible(visible);
|
||||||
|
|
||||||
// <TreeSelect
|
// 你可以在这里执行更多的逻辑,比如发送请求、更新状态等
|
||||||
|
console.log('Dropdown is now:', visible ? 'visible' : 'hidden');
|
||||||
|
};
|
||||||
|
|
||||||
|
const focus = () => {
|
||||||
|
// console.log('focus==========');
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TreeSelect
|
||||||
|
fieldNames={{ label: 'label', value: 'value', children: 'children' }}
|
||||||
|
{...data.ui.attr}
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
value={defaultValue}
|
||||||
|
treeDefaultExpandAll
|
||||||
|
onChange={onChange}
|
||||||
|
treeData={data.options}
|
||||||
|
onDropdownVisibleChange={handleDropdownVisibleChange}
|
||||||
|
/>
|
||||||
|
|
||||||
|
// TODO: Implement the TreeSelect component
|
||||||
|
// <TreeSelect
|
||||||
// showSearch
|
// showSearch
|
||||||
// style={{ width: '100%' }}
|
// style={{ width: '100%' }}
|
||||||
// value={value}
|
// value={value}
|
||||||
@@ -100,5 +103,5 @@ type TextAreaProps = {
|
|||||||
// treeData={treeData}
|
// treeData={treeData}
|
||||||
// getPopupContainer={() => document.body}
|
// getPopupContainer={() => document.body}
|
||||||
// />
|
// />
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
@@ -58,12 +58,6 @@ export type IFlowNodeParameterUI = {
|
|||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
};
|
};
|
||||||
autosize: {
|
|
||||||
minRows: number;
|
|
||||||
maxRows: number;
|
|
||||||
min_rows: number;
|
|
||||||
max_rows: number;
|
|
||||||
};
|
|
||||||
show_input: boolean;
|
show_input: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user