feat: ai proxy v1 (#3898)

* feat: ai proxy v1

* perf: ai proxy channel crud

* feat: ai proxy logs

* feat: channel test

* doc

* update lock
This commit is contained in:
Archer
2025-02-27 09:56:52 +08:00
committed by GitHub
parent 3c382d1240
commit 81a06718d8
40 changed files with 2869 additions and 746 deletions

View File

@@ -98,7 +98,6 @@ const MultipleSelect = <T = any,>({
return (
<MenuItem
key={i}
{...menuItemStyles}
{...(isSelected
? {
color: 'primary.600'
@@ -114,6 +113,7 @@ const MultipleSelect = <T = any,>({
whiteSpace={'pre-wrap'}
fontSize={'sm'}
gap={2}
{...menuItemStyles}
>
<Checkbox isChecked={isSelected} />
{item.icon && <MyAvatar src={item.icon} w={'1rem'} borderRadius={'0'} />}
@@ -204,6 +204,7 @@ const MultipleSelect = <T = any,>({
}}
onClick={(e) => {
e.stopPropagation();
e.preventDefault();
onclickItem(item.value);
}}
/>
@@ -230,7 +231,6 @@ const MultipleSelect = <T = any,>({
overflowY={'auto'}
>
<MenuItem
{...menuItemStyles}
color={isSelectAll ? 'primary.600' : 'myGray.900'}
onClick={(e) => {
e.stopPropagation();
@@ -241,6 +241,7 @@ const MultipleSelect = <T = any,>({
fontSize={'sm'}
gap={2}
mb={1}
{...menuItemStyles}
>
<Checkbox isChecked={isSelectAll} />
<Box flex={'1 0 0'}>{t('common:common.All')}</Box>

View File

@@ -4,7 +4,8 @@ import React, {
useMemo,
useEffect,
useImperativeHandle,
ForwardedRef
ForwardedRef,
useState
} from 'react';
import {
Menu,
@@ -15,7 +16,8 @@ import {
MenuButton,
Box,
css,
Flex
Flex,
Input
} from '@chakra-ui/react';
import type { ButtonProps, MenuItemProps } from '@chakra-ui/react';
import MyIcon from '../Icon';
@@ -33,8 +35,10 @@ import { useScrollPagination } from '../../../hooks/useScrollPagination';
export type SelectProps<T = any> = ButtonProps & {
value?: T;
placeholder?: string;
isSearch?: boolean;
list: {
alias?: string;
icon?: string;
label: string | React.ReactNode;
description?: string;
value: T;
@@ -49,6 +53,7 @@ const MySelect = <T = any,>(
{
placeholder,
value,
isSearch = false,
width = '100%',
list = [],
onchange,
@@ -63,6 +68,7 @@ const MySelect = <T = any,>(
const ButtonRef = useRef<HTMLButtonElement>(null);
const MenuListRef = useRef<HTMLDivElement>(null);
const SelectedItemRef = useRef<HTMLDivElement>(null);
const SearchInputRef = useRef<HTMLInputElement>(null);
const menuItemStyles: MenuItemProps = {
borderRadius: 'sm',
@@ -79,6 +85,18 @@ const MySelect = <T = any,>(
const { isOpen, onOpen, onClose } = useDisclosure();
const selectItem = useMemo(() => list.find((item) => item.value === value), [list, value]);
const [search, setSearch] = useState('');
const filterList = useMemo(() => {
if (!isSearch || !search) {
return list;
}
return list.filter((item) => {
const text = `${item.label?.toString()}${item.alias}${item.value}`;
const regx = new RegExp(search, 'gi');
return regx.test(text);
});
}, [list, search, isSearch]);
useImperativeHandle(ref, () => ({
focus() {
onOpen();
@@ -90,17 +108,19 @@ const MySelect = <T = any,>(
const menu = MenuListRef.current;
const selectedItem = SelectedItemRef.current;
menu.scrollTop = selectedItem.offsetTop - menu.offsetTop - 100;
if (isSearch) {
setSearch('');
}
}
}, [isOpen]);
}, [isSearch, isOpen]);
const { runAsync: onChange, loading } = useRequest2((val: T) => onchange?.(val));
const isSelecting = loading || isLoading;
const ListRender = useMemo(() => {
return (
<>
{list.map((item, i) => (
{filterList.map((item, i) => (
<Box key={i}>
<MenuItem
{...menuItemStyles}
@@ -123,7 +143,10 @@ const MySelect = <T = any,>(
fontSize={'sm'}
display={'block'}
>
<Box>{item.label}</Box>
<Flex alignItems={'center'}>
{item.icon && <MyIcon mr={2} name={item.icon as any} w={'1rem'} />}
{item.label}
</Flex>
{item.description && (
<Box color={'myGray.500'} fontSize={'xs'}>
{item.description}
@@ -135,7 +158,9 @@ const MySelect = <T = any,>(
))}
</>
);
}, [list, value]);
}, [filterList, value]);
const isSelecting = loading || isLoading;
return (
<Box
@@ -176,8 +201,33 @@ const MySelect = <T = any,>(
{...props}
>
<Flex alignItems={'center'}>
{isSelecting && <MyIcon mr={2} name={'common/loading'} w={'16px'} />}
{selectItem?.alias || selectItem?.label || placeholder}
{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 && <MyIcon mr={2} name={selectItem.icon as any} w={'1rem'} />}
{selectItem?.alias || selectItem?.label || placeholder}
</>
)}
</Flex>
</MenuButton>