mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-22 12:20:34 +00:00
Test version (#4792)
* plugin node version select (#4760) * plugin node version select * type * fix * fix * perf: version list * fix node version (#4787) * change my select * fix-ui * fix test * add test * fix * remove invalid version field * filter deprecated field * fix: claude tool call * fix: test --------- Co-authored-by: heheer <heheer@sealos.io>
This commit is contained in:
@@ -15,7 +15,6 @@ import {
|
||||
useDisclosure,
|
||||
MenuButton,
|
||||
Box,
|
||||
css,
|
||||
Flex,
|
||||
Input
|
||||
} from '@chakra-ui/react';
|
||||
@@ -32,13 +31,16 @@ import Avatar from '../Avatar';
|
||||
* list: 列表数据
|
||||
* isLoading: 是否加载中
|
||||
* ScrollData: 分页滚动数据控制器 [useScrollPagination] 的返回值
|
||||
* customOnOpen: 自定义打开回调
|
||||
* customOnClose: 自定义关闭回调
|
||||
* */
|
||||
export type SelectProps<T = any> = Omit<ButtonProps, 'onChange'> & {
|
||||
value?: T;
|
||||
valueLabel?: string | React.ReactNode;
|
||||
placeholder?: string;
|
||||
isSearch?: boolean;
|
||||
list: {
|
||||
alias?: string;
|
||||
alias?: string | React.ReactNode;
|
||||
icon?: string;
|
||||
iconSize?: string;
|
||||
label: string | React.ReactNode;
|
||||
@@ -49,18 +51,36 @@ export type SelectProps<T = any> = Omit<ButtonProps, 'onChange'> & {
|
||||
isLoading?: boolean;
|
||||
onChange?: (val: T) => any | Promise<any>;
|
||||
ScrollData?: ReturnType<typeof useScrollPagination>['ScrollData'];
|
||||
customOnOpen?: () => void;
|
||||
customOnClose?: () => void;
|
||||
};
|
||||
|
||||
export const menuItemStyles: MenuItemProps = {
|
||||
borderRadius: 'sm',
|
||||
py: 2,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
_hover: {
|
||||
backgroundColor: 'myGray.100'
|
||||
},
|
||||
_notLast: {
|
||||
mb: 1
|
||||
}
|
||||
};
|
||||
|
||||
const MySelect = <T = any,>(
|
||||
{
|
||||
placeholder,
|
||||
value,
|
||||
valueLabel,
|
||||
isSearch = false,
|
||||
width = '100%',
|
||||
list = [],
|
||||
onChange,
|
||||
isLoading = false,
|
||||
ScrollData,
|
||||
customOnOpen,
|
||||
customOnClose,
|
||||
...props
|
||||
}: SelectProps<T>,
|
||||
ref: ForwardedRef<{
|
||||
@@ -72,21 +92,19 @@ const MySelect = <T = any,>(
|
||||
const SelectedItemRef = useRef<HTMLDivElement>(null);
|
||||
const SearchInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const menuItemStyles: MenuItemProps = {
|
||||
borderRadius: 'sm',
|
||||
py: 2,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
_hover: {
|
||||
backgroundColor: 'myGray.100'
|
||||
},
|
||||
_notLast: {
|
||||
mb: 1
|
||||
}
|
||||
};
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const { isOpen, onOpen: defaultOnOpen, onClose: defaultOnClose } = useDisclosure();
|
||||
const selectItem = useMemo(() => list.find((item) => item.value === value), [list, value]);
|
||||
|
||||
const onOpen = () => {
|
||||
defaultOnOpen();
|
||||
customOnOpen?.();
|
||||
};
|
||||
|
||||
const onClose = () => {
|
||||
defaultOnClose();
|
||||
customOnClose?.();
|
||||
};
|
||||
|
||||
const [search, setSearch] = useState('');
|
||||
const filterList = useMemo(() => {
|
||||
if (!isSearch || !search) {
|
||||
@@ -105,6 +123,7 @@ const MySelect = <T = any,>(
|
||||
}
|
||||
}));
|
||||
|
||||
// Auto scroll
|
||||
useEffect(() => {
|
||||
if (isOpen && MenuListRef.current && SelectedItemRef.current) {
|
||||
const menu = MenuListRef.current;
|
||||
@@ -117,7 +136,7 @@ const MySelect = <T = any,>(
|
||||
}
|
||||
}, [isSearch, isOpen]);
|
||||
|
||||
const { runAsync: onclickChange, loading } = useRequest2((val: T) => onChange?.(val));
|
||||
const { runAsync: onClickChange, loading } = useRequest2((val: T) => onChange?.(val));
|
||||
|
||||
const ListRender = useMemo(() => {
|
||||
return (
|
||||
@@ -138,7 +157,7 @@ const MySelect = <T = any,>(
|
||||
})}
|
||||
onClick={() => {
|
||||
if (value !== item.value) {
|
||||
onclickChange(item.value);
|
||||
onClickChange(item.value);
|
||||
}
|
||||
}}
|
||||
whiteSpace={'pre-wrap'}
|
||||
@@ -161,7 +180,7 @@ const MySelect = <T = any,>(
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}, [filterList, value]);
|
||||
}, [filterList, onClickChange, value]);
|
||||
|
||||
const isSelecting = loading || isLoading;
|
||||
|
||||
@@ -200,36 +219,48 @@ const MySelect = <T = any,>(
|
||||
: {})}
|
||||
{...props}
|
||||
>
|
||||
<Flex alignItems={'center'}>
|
||||
{isSelecting && <MyIcon mr={2} name={'common/loading'} w={'1rem'} />}
|
||||
{isSearch && isOpen ? (
|
||||
<Input
|
||||
ref={SearchInputRef}
|
||||
autoFocus
|
||||
variant={'unstyled'}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
placeholder={
|
||||
selectItem?.alias ||
|
||||
(typeof selectItem?.label === 'string' ? selectItem?.label : placeholder)
|
||||
}
|
||||
size={'sm'}
|
||||
w={'100%'}
|
||||
color={'myGray.700'}
|
||||
onBlur={() => {
|
||||
setTimeout(() => {
|
||||
SearchInputRef?.current?.focus();
|
||||
}, 0);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
{selectItem?.icon && (
|
||||
<Avatar mr={2} src={selectItem.icon as any} w={selectItem.iconSize ?? '1rem'} />
|
||||
)}
|
||||
{selectItem?.alias || selectItem?.label || placeholder}
|
||||
</>
|
||||
)}
|
||||
<Flex alignItems={'center'} justifyContent="space-between" w="100%">
|
||||
<Flex alignItems={'center'}>
|
||||
{isSelecting && <MyIcon mr={2} name={'common/loading'} w={'1rem'} />}
|
||||
{valueLabel ? (
|
||||
<>{valueLabel}</>
|
||||
) : (
|
||||
<>
|
||||
{isSearch && isOpen ? (
|
||||
<Input
|
||||
ref={SearchInputRef}
|
||||
autoFocus
|
||||
variant={'unstyled'}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
placeholder={
|
||||
(typeof selectItem?.alias === 'string' ? selectItem?.alias : '') ||
|
||||
(typeof selectItem?.label === 'string' ? selectItem?.label : placeholder)
|
||||
}
|
||||
size={'sm'}
|
||||
w={'100%'}
|
||||
color={'myGray.700'}
|
||||
onBlur={() => {
|
||||
setTimeout(() => {
|
||||
SearchInputRef?.current?.focus();
|
||||
}, 0);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
{selectItem?.icon && (
|
||||
<Avatar
|
||||
mr={2}
|
||||
src={selectItem.icon as any}
|
||||
w={selectItem.iconSize ?? '1rem'}
|
||||
/>
|
||||
)}
|
||||
{selectItem?.alias || selectItem?.label || placeholder}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
</Flex>
|
||||
</MenuButton>
|
||||
|
||||
@@ -252,7 +283,7 @@ const MySelect = <T = any,>(
|
||||
'0px 2px 4px rgba(161, 167, 179, 0.25), 0px 0px 1px rgba(121, 141, 159, 0.25);'
|
||||
}
|
||||
zIndex={99}
|
||||
maxH={'40vh'}
|
||||
maxH={'45vh'}
|
||||
overflowY={'auto'}
|
||||
>
|
||||
{ScrollData ? <ScrollData>{ListRender}</ScrollData> : ListRender}
|
||||
|
@@ -190,6 +190,7 @@ export function useScrollPagination<
|
||||
params = {},
|
||||
EmptyTip,
|
||||
showErrorToast = true,
|
||||
disalbed = false,
|
||||
...props
|
||||
}: {
|
||||
scrollLoadType?: 'top' | 'bottom';
|
||||
@@ -198,6 +199,7 @@ export function useScrollPagination<
|
||||
params?: Record<string, any>;
|
||||
EmptyTip?: React.JSX.Element;
|
||||
showErrorToast?: boolean;
|
||||
disalbed?: boolean;
|
||||
} & Parameters<typeof useRequest2>[1]
|
||||
) {
|
||||
const { t } = useTranslation();
|
||||
@@ -345,10 +347,10 @@ export function useScrollPagination<
|
||||
// Reload data
|
||||
useRequest2(
|
||||
async () => {
|
||||
if (disalbed) return;
|
||||
loadData(true);
|
||||
},
|
||||
{
|
||||
manual: false,
|
||||
...props
|
||||
}
|
||||
);
|
||||
|
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"Click_to_delete_this_field": "Click to delete this field",
|
||||
"Filed_is_deprecated": "This field is deprecated",
|
||||
"MCP_tools_list_is_empty": "MCP tool not resolved",
|
||||
"MCP_tools_parse_failed": "Failed to parse MCP address",
|
||||
"MCP_tools_url": "MCP Address",
|
||||
@@ -6,7 +8,6 @@
|
||||
"MCP_tools_url_placeholder": "After filling in the MCP address, click Analysis",
|
||||
"Role_setting": "Permission",
|
||||
"Run": "Execute",
|
||||
"team_tags_set": "Team tags",
|
||||
"Team_Tags": "Team tags",
|
||||
"ai_point_price": "Billing",
|
||||
"ai_settings": "AI Configuration",
|
||||
@@ -106,6 +107,7 @@
|
||||
"no_mcp_tools_list": "No data yet, the MCP address needs to be parsed first",
|
||||
"node_not_intro": "This node is not introduced",
|
||||
"not_json_file": "Please select a JSON file",
|
||||
"not_the_newest": "Not the latest",
|
||||
"oaste_curl_string": "Enter CURL code",
|
||||
"open_auto_execute": "Enable automatic execution",
|
||||
"open_vision_function_tip": "Models with icon switches have image recognition capabilities. \nAfter being turned on, the model will parse the pictures in the file link and automatically parse the pictures in the user's question (user question ≤ 500 words).",
|
||||
@@ -138,6 +140,7 @@
|
||||
"stop_sign_placeholder": "Multiple serial numbers are separated by |, for example: aaa|stop",
|
||||
"stream_response": "Stream",
|
||||
"stream_response_tip": "Turning this switch off forces the model to use non-streaming mode and will not output content directly. \nIn the output of the AI reply, the content output by this model can be obtained for secondary processing.",
|
||||
"team_tags_set": "Team tags",
|
||||
"temperature": "Temperature",
|
||||
"temperature_tip": "Range 0~10. \nThe larger the value, the more divergent the model’s answer is; the smaller the value, the more rigorous the answer.",
|
||||
"template.hard_strict": "Strict Q&A template",
|
||||
|
@@ -96,6 +96,7 @@
|
||||
"add_new_param": "Add new param",
|
||||
"all_quotes": "All quotes",
|
||||
"all_result": "Full Results",
|
||||
"app_not_version": "This application has not been published, please publish it first",
|
||||
"back": "Back",
|
||||
"base_config": "Basic Configuration",
|
||||
"bill_already_processed": "Order has been processed",
|
||||
|
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"Click_to_delete_this_field": "点击删除该字段",
|
||||
"Filed_is_deprecated": "该字段已弃用",
|
||||
"MCP_tools_debug": "调试",
|
||||
"MCP_tools_detail": "查看详情",
|
||||
"MCP_tools_list": "工具列表",
|
||||
@@ -10,7 +12,6 @@
|
||||
"MCP_tools_url_placeholder": "填入 MCP 地址后,点击解析",
|
||||
"Role_setting": "权限设置",
|
||||
"Run": "运行",
|
||||
"team_tags_set": "团队标签",
|
||||
"Team_Tags": "团队标签",
|
||||
"ai_point_price": "AI积分计费",
|
||||
"ai_settings": "AI 配置",
|
||||
@@ -110,6 +111,7 @@
|
||||
"no_mcp_tools_list": "暂无数据,需先解析 MCP 地址",
|
||||
"node_not_intro": "这个节点没有介绍",
|
||||
"not_json_file": "请选择JSON文件",
|
||||
"not_the_newest": "非最新版",
|
||||
"oaste_curl_string": "输入 CURL 代码",
|
||||
"open_auto_execute": "启用自动执行",
|
||||
"open_vision_function_tip": "有图示开关的模型即拥有图片识别能力。若开启,模型会解析文件链接里的图片,并自动解析用户问题中的图片(用户问题≤500字时生效)。",
|
||||
@@ -143,6 +145,7 @@
|
||||
"stop_sign_placeholder": "多个序列号通过 | 隔开,例如:aaa|stop",
|
||||
"stream_response": "流输出",
|
||||
"stream_response_tip": "关闭该开关,可以强制模型使用非流模式,并且不会直接进行内容输出。可以在 AI 回复的输出中,获取本次模型输出的内容进行二次处理。",
|
||||
"team_tags_set": "团队标签",
|
||||
"temperature": "温度",
|
||||
"temperature_tip": "范围 0~10。值越大,代表模型回答越发散;值越小,代表回答越严谨。",
|
||||
"template.hard_strict": "严格问答模板",
|
||||
|
@@ -96,6 +96,7 @@
|
||||
"add_new_param": "新增参数",
|
||||
"all_quotes": "全部引用",
|
||||
"all_result": "完整结果",
|
||||
"app_not_version": " 该应用未发布过,请先发布应用",
|
||||
"back": "返回",
|
||||
"base_config": "基础配置",
|
||||
"bill_already_processed": "订单已处理",
|
||||
|
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"Click_to_delete_this_field": "點擊刪除該字段",
|
||||
"Filed_is_deprecated": "該字段已棄用",
|
||||
"MCP_tools_list_is_empty": "未解析到 MCP 工具",
|
||||
"MCP_tools_parse_failed": "解析 MCP 地址失敗",
|
||||
"MCP_tools_url": "MCP 地址",
|
||||
@@ -6,7 +8,6 @@
|
||||
"MCP_tools_url_placeholder": "填入 MCP 地址後,點擊解析",
|
||||
"Role_setting": "權限設定",
|
||||
"Run": "執行",
|
||||
"team_tags_set": "團隊標籤",
|
||||
"Team_Tags": "團隊標籤",
|
||||
"ai_point_price": "AI 積分計費",
|
||||
"ai_settings": "AI 設定",
|
||||
@@ -106,6 +107,7 @@
|
||||
"no_mcp_tools_list": "暫無數據,需先解析 MCP 地址",
|
||||
"node_not_intro": "這個節點沒有介紹",
|
||||
"not_json_file": "請選擇 JSON 檔案",
|
||||
"not_the_newest": "非最新版",
|
||||
"oaste_curl_string": "輸入 CURL 代碼",
|
||||
"open_auto_execute": "啟用自動執行",
|
||||
"open_vision_function_tip": "有圖示開關的模型即擁有圖片辨識功能。若開啟,模型會解析檔案連結中的圖片,並自動解析使用者問題中的圖片(使用者問題 ≤ 500 字時生效)。",
|
||||
@@ -138,6 +140,7 @@
|
||||
"stop_sign_placeholder": "多個序列號透過 | 隔開,例如:aaa|stop",
|
||||
"stream_response": "流輸出",
|
||||
"stream_response_tip": "關閉該開關,可以強制模型使用非流模式,並且不會直接進行內容輸出。\n可在 AI 回覆的輸出中,取得本次模型輸出的內容進行二次處理。",
|
||||
"team_tags_set": "團隊標籤",
|
||||
"temperature": "溫度",
|
||||
"temperature_tip": "範圍 0~10。\n值越大,代表模型回答越發散;值越小,代表回答越嚴謹。",
|
||||
"template.hard_strict": "嚴格問答範本",
|
||||
|
@@ -96,6 +96,7 @@
|
||||
"add_new_param": "新增參數",
|
||||
"all_quotes": "全部引用",
|
||||
"all_result": "完整結果",
|
||||
"app_not_version": "該應用未發布過,請先發布應用",
|
||||
"back": "返回",
|
||||
"base_config": "基本設定",
|
||||
"bill_already_processed": "訂單已處理",
|
||||
|
Reference in New Issue
Block a user