feat(web): api key & space config ui upgrade
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>编辑</title>
|
||||
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>link-outlined</title>
|
||||
<g id="空间里层页面优化" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="工作台-提示词-我的历史" transform="translate(-950, -560)" stroke="#5B6167">
|
||||
<g id="编组-13备份-4" transform="translate(648, 362)">
|
||||
<g id="编辑" transform="translate(302, 198)">
|
||||
<g id="编组-16" transform="translate(2.5, 4.7)">
|
||||
<ellipse id="椭圆形" cx="6.5" cy="4.3" rx="6.5" ry="4.3"></ellipse>
|
||||
<circle id="椭圆形" cx="6.5" cy="4.3" r="1.75"></circle>
|
||||
<g id="API-Key-管理" transform="translate(-1034, -161)" stroke="#171719">
|
||||
<g id="编组-16" transform="translate(1022, 126)">
|
||||
<g id="link-outlined" transform="translate(12, 35)">
|
||||
<g id="编组-14" transform="translate(2.5, 4.15)">
|
||||
<path d="M5.50029186,2.425 C5.92116821,2.425 6.30372933,2.58703648 6.58052274,2.85122056 C6.84862719,3.1071115 7.01717088,3.4597026 7.01717088,3.85 C7.01717088,4.24027468 6.84857286,4.5929387 6.58042003,4.84890344 C6.3036418,5.11310155 5.92112667,5.27520782 5.50029186,5.27520782 C5.07946329,5.27520782 4.69695201,5.11310096 4.42017607,4.84890315 C4.15202505,4.59293829 3.98342734,4.24027444 3.98342734,3.85 C3.98342734,3.45970284 4.15197072,3.10711191 4.42007337,2.85122085 C4.69686448,2.58703707 5.07942175,2.425 5.50029186,2.425 Z" id="路径" fill-rule="nonzero"></path>
|
||||
<path d="M5.5,7.7 C8.53756612,7.7 11,5.39612383 11,3.85 C11,2.30387617 8.53756612,0 5.5,0 C2.46243388,0 0,2.26850164 0,3.85 C0,5.43149836 2.46243388,7.7 5.5,7.7 Z" id="椭圆形"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 888 B After Width: | Height: | Size: 1.5 KiB |
16
web/src/assets/images/menuNew/arrow_t_r.svg
Normal file
16
web/src/assets/images/menuNew/arrow_t_r.svg
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>编组 51</title>
|
||||
<g id="空间里层页面优化" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
|
||||
<g id="工作台-记忆看板-3" transform="translate(-1400, -140)" stroke="#A8A9AA" stroke-width="1.2">
|
||||
<g id="编组-22" transform="translate(1180, 57)">
|
||||
<g id="编组-51" transform="translate(220, 83)">
|
||||
<g id="编组-49" transform="translate(4.5, 4.5)">
|
||||
<polyline id="路径" points="0 0 7 0 7 7"></polyline>
|
||||
<line x1="7" y1="0" x2="9.71445147e-17" y2="7" id="路径-51"></line>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 938 B |
17
web/src/assets/images/menuNew/logout_red.svg
Normal file
17
web/src/assets/images/menuNew/logout_red.svg
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>退出</title>
|
||||
<g id="空间里层页面优化" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
|
||||
<g id="工作台-记忆看板-3" transform="translate(-1196, -229)" stroke="#FF5D34" stroke-width="1.2">
|
||||
<g id="编组-22" transform="translate(1180, 57)">
|
||||
<g id="退出" transform="translate(16, 172)">
|
||||
<g id="编组-7" transform="translate(2.5, 2)">
|
||||
<path d="M4,12 L2,12 C0.8954305,12 0,11.1045695 0,10 L0,2 C0,0.8954305 0.8954305,2.22044605e-16 2,0 L4,0 L4,0" id="路径"></path>
|
||||
<line x1="11" y1="6" x2="4.5" y2="6" id="路径-6"></line>
|
||||
<polyline id="路径" points="8 3 11 6 8 9"></polyline>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
19
web/src/assets/images/menuNew/settings.svg
Normal file
19
web/src/assets/images/menuNew/settings.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>设置-界面设置</title>
|
||||
<g id="空间里层页面优化" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="工作台-记忆看板-3" transform="translate(-1196, -176)">
|
||||
<g id="编组-22" transform="translate(1180, 57)">
|
||||
<g id="设置-界面设置" transform="translate(16, 119)">
|
||||
<g id="编组-2" transform="translate(2, 2)">
|
||||
<path d="M9.43360402,6.02003217 C9.70219942,5.98544974 9.97412053,5.98544974 10.2427159,6.02003217 C10.3615753,6.03694616 10.4495746,6.13920492 10.4485827,6.25925761 L10.4485827,6.97778158 C10.8355212,7.08416506 11.1878633,7.2900028 11.4705612,7.57481981 L12.0861381,7.21535276 C12.1886462,7.15532215 12.3197841,7.18070349 12.3924911,7.27464643 C12.5566377,7.49314267 12.6927553,7.73134853 12.7976622,7.98369599 C12.8417451,8.09509234 12.7980417,8.22199461 12.6947152,8.28262525 L12.0795484,8.64127201 C12.1812591,9.03280439 12.1812591,9.44382977 12.0795484,9.83536215 L12.6951253,10.1940089 C12.7984653,10.255883 12.8408681,10.3841328 12.7947775,10.4954127 C12.6902734,10.7470629 12.5545635,10.9845849 12.3908368,11.2023979 C12.3178817,11.29706 12.1858902,11.3226521 12.0828433,11.2621154 L11.4681003,10.9034823 C11.1853554,11.1882385 10.8330304,11.3940662 10.4461218,11.5005205 L10.4461218,12.2190308 C10.4472928,12.3391587 10.3591904,12.4415237 10.2402277,12.4582563 C9.97161477,12.49242 9.69975606,12.49242 9.43114314,12.4582563 C9.31227289,12.4413547 9.22425896,12.3390925 9.22524902,12.2190308 L9.22524902,11.5005069 C8.83966141,11.3929856 8.48863308,11.187108 8.20657902,10.9030585 L7.58893771,11.263756 C7.48646614,11.3234892 7.35562246,11.2983389 7.28259844,11.2048724 C7.11845115,10.9862292 6.98233473,10.7478877 6.87742727,10.4954127 C6.83256205,10.383776 6.87616574,10.2561165 6.9799505,10.195253 L7.59757815,9.83618245 C7.54895974,9.65227947 7.52310022,9.46310373 7.52057977,9.27289936 C7.51726668,9.06031128 7.54274952,8.8482532 7.59633403,8.64250245 L6.9807708,8.28344555 C6.87737248,8.2230699 6.83375833,8.09609457 6.87823389,7.98492643 C6.98279132,7.7324117 7.11893329,7.49416785 7.28340506,7.27589055 C7.35624204,7.18108729 7.48825303,7.15531561 7.59139859,7.2157629 L8.2061552,7.57481981 C8.48870496,7.29001094 8.84091669,7.08416484 9.22773725,6.97776791 L9.22773725,6.25925761 C9.22638248,6.13907231 9.31455943,6.03660714 9.43360402,6.02003217 Z M9.85567328,8.1381029 L9.83960916,8.1381029 C9.44388649,8.13394685 9.07614467,8.3416968 8.87546122,8.68278309 C8.67477776,9.02386937 8.67178651,9.44622602 8.86761874,9.79012055 C9.06345096,10.1340151 9.42821335,10.3469528 9.82395519,10.3484022 L9.85608342,10.3484022 C10.4510916,10.3389892 10.929189,9.8552216 10.9315862,9.26014377 C10.9437669,8.6534016 10.4623788,8.15138092 9.85567328,8.1381029 Z" id="形状结合" fill="#171719" fill-rule="nonzero"></path>
|
||||
<path d="M5.99499898,12 L2,12 C0.8954305,12 4.4408921e-16,11.1045695 4.4408921e-16,10 L0,2 C0,0.8954305 0.8954305,2.22044605e-16 2,0 L10,0 C11.1045695,0 12,0.8954305 12,2 L12,4.98927875 L12,4.98927875" id="路径" stroke="#171719" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
<line x1="0" y1="3.99424593" x2="12" y2="3.99424593" id="路径-2" stroke="#171719" stroke-width="1.2"></line>
|
||||
<circle id="椭圆形" fill="#171719" cx="2.2" cy="2" r="1"></circle>
|
||||
<circle id="椭圆形" fill="#171719" cx="4.4" cy="2" r="1"></circle>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
13
web/src/assets/images/menuNew/userInfo.svg
Normal file
13
web/src/assets/images/menuNew/userInfo.svg
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>账户</title>
|
||||
<g id="空间里层页面优化" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="工作台-记忆看板-3" transform="translate(-1196, -140)" fill="#171719" fill-rule="nonzero" stroke="#171719" stroke-width="0.4">
|
||||
<g id="编组-22" transform="translate(1180, 57)">
|
||||
<g id="账户" transform="translate(16, 83)">
|
||||
<path d="M8,1 C4.13400675,1 1,4.13400675 1,8 C1,11.8659932 4.13400675,15 8,15 C11.8659932,15 15,11.8659932 15,8 C14.9947583,4.13618002 11.86382,1.0052417 8,1 L8,1 Z M12.4014141,12.3271621 L12.2224629,12.517543 L12.1748711,12.2662539 C12.0428879,11.5485013 11.7289104,10.8766306 11.2629844,10.3149355 C11.1145387,10.1521744 10.8641988,10.135306 10.6952598,10.2766811 C10.5263208,10.4180561 10.4988,10.6674498 10.6328477,10.8422598 C11.1442401,11.4572317 11.4244051,12.2317168 11.4248047,13.0315371 C11.4257399,13.0442165 11.4257399,13.0569476 11.4248047,13.069627 L11.4248047,13.1419512 L11.3638828,13.1819414 C9.31720678,14.5169283 6.67517799,14.5169283 4.62850195,13.1819414 L4.56758008,13.1419648 L4.56758008,13.0334512 C4.56758008,11.1409267 6.10177432,9.60673242 7.99429883,9.60673242 C9.43633406,9.61053035 10.6698828,8.57151634 10.9112248,7.14981524 C11.1525669,5.72811413 10.3309981,4.34023189 8.96849203,3.8679425 C7.60598597,3.39565311 6.10170668,3.97731994 5.4113796,5.24338809 C4.72105252,6.50945624 5.046918,8.08901446 6.18194141,8.97850977 L6.35137695,9.10986914 L6.16099609,9.20315234 C4.9414843,9.79213158 4.07443441,10.9255913 3.82512891,12.2567383 L3.77753711,12.5080273 L3.59858594,12.3176602 C2.45876944,11.1700068 1.82010269,9.61749329 1.8223981,8 C1.81896848,5.20888419 3.68748546,2.76216731 6.38105315,2.03070823 C9.07462084,1.29924914 11.9240679,2.46476648 13.3328918,4.87423832 C14.7417157,7.28371017 14.3599179,10.338544 12.4014141,12.3271621 L12.4014141,12.3271621 Z M5.87924609,6.65787305 C5.88029543,5.48791052 6.82940261,4.5402209 7.9993654,4.54091991 C9.16932819,4.5416197 10.1173016,5.49044339 10.1169523,6.66040633 C10.1166027,7.83036928 9.16806261,8.77862695 7.99809961,8.77862695 C6.82758179,8.77757806 5.87924609,7.82839134 5.87924609,6.65787305 L5.87924609,6.65787305 Z" id="形状"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -24,4 +24,26 @@
|
||||
.header :global(.ant-breadcrumb .ant-breadcrumb-item:last-child a) {
|
||||
color: #212332;
|
||||
font-weight: 600;
|
||||
}
|
||||
.userDropdown:global(.ant-dropdown .ant-dropdown-menu),
|
||||
.userDropdown:global(.ant-dropdown-menu-submenu .ant-dropdown-menu) {
|
||||
padding: 12px 8px;
|
||||
}
|
||||
.userDropdown:global(.ant-dropdown .ant-dropdown-menu .ant-dropdown-menu-item),
|
||||
.userDropdown:global(.ant-dropdown-menu-submenu .ant-dropdown-menu .ant-dropdown-menu-item),
|
||||
.userDropdown:global(.ant-dropdown .ant-dropdown-menu .ant-dropdown-menu-submenu-title),
|
||||
.userDropdown:global(.ant-dropdown-menu-submenu .ant-dropdown-menu .ant-dropdown-menu-submenu-title) {
|
||||
padding-left: 8px;
|
||||
padding-right: 4px;
|
||||
}
|
||||
.userDropdown:global(.ant-dropdown .ant-dropdown-menu .ant-dropdown-menu-item.ant-dropdown-menu-item-danger:not(.ant-dropdown-menu-item-disabled):hover),
|
||||
.userDropdown:global(.ant-dropdown-menu-submenu .ant-dropdown-menu .ant-dropdown-menu-item.ant-dropdown-menu-item-danger:not(.ant-dropdown-menu-item-disabled):hover) {
|
||||
background-color: #F6F6F6;
|
||||
color: #FF5D34;
|
||||
}
|
||||
.userDropdown:global(.ant-dropdown .ant-dropdown-menu .ant-dropdown-menu-item-divider),
|
||||
.userDropdown:global(.ant-dropdown-menu-submenu .ant-dropdown-menu .ant-dropdown-menu-item-divider),
|
||||
.userDropdown:global(.ant-dropdown .ant-dropdown-menu .ant-dropdown-menu-submenu-title-divider),
|
||||
.userDropdown:global(.ant-dropdown-menu-submenu .ant-dropdown-menu .ant-dropdown-menu-submenu-title-divider) {
|
||||
margin: 10px 8px;
|
||||
}
|
||||
@@ -13,12 +13,12 @@
|
||||
* @component
|
||||
*/
|
||||
|
||||
import { type FC, useRef } from 'react';
|
||||
import { Layout, Dropdown, Breadcrumb } from 'antd';
|
||||
import { type FC, useRef, useState } from 'react';
|
||||
import { Layout, Dropdown, Breadcrumb, Flex } from 'antd';
|
||||
import type { MenuProps, BreadcrumbProps } from 'antd';
|
||||
import { UserOutlined, LogoutOutlined, SettingOutlined } from '@ant-design/icons';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import clsx from 'clsx';
|
||||
|
||||
import { useUser } from '@/store/user';
|
||||
import { useMenu } from '@/store/menu';
|
||||
@@ -76,27 +76,39 @@ const AppHeader: FC<{source?: 'space' | 'manage';}> = ({source = 'manage'}) => {
|
||||
const userMenuItems: MenuProps['items'] = [
|
||||
{
|
||||
key: '1',
|
||||
icon: <Flex align="center" justify="center" className="rb:size-10 rb:rounded-xl rb:bg-[#155EEF] rb:text-white">
|
||||
{/[\u4e00-\u9fa5]/.test(user.username) ? user.username.slice(0, 2) : user.username[0]}
|
||||
</Flex>,
|
||||
label: (<>
|
||||
<div>{user.username}</div>
|
||||
<div className="rb:text-[12px] rb:text-[#5B6167] rb:mt-2">{user.email}</div>
|
||||
<div className="rb:text-[#212332] rb:leading-5">{user.username}</div>
|
||||
<div className="rb:text-[12px] rb:text-[#7B8085] rb:leading-4.5 rb:mt-0.5 rb:mr-2">{user.email}</div>
|
||||
</>),
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
type: 'divider',
|
||||
className: 'rb:bg-[#EBEBEB]!'
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
icon: <UserOutlined />,
|
||||
label: t('header.userInfo'),
|
||||
icon: <div className="rb:size-4 rb:bg-cover rb:bg-[url('src/assets/images/menuNew/userInfo.svg')]"></div>,
|
||||
label: <Flex justify="space-between" align="center">
|
||||
{t('header.userInfo')}
|
||||
<div className="rb:size-4 rb:bg-cover rb:bg-[url('src/assets/images/menuNew/arrow_t_r.svg')]"></div>
|
||||
</Flex>,
|
||||
className: 'rb:text-[#212332]!',
|
||||
onClick: () => {
|
||||
userInfoModalRef.current?.handleOpen()
|
||||
},
|
||||
},
|
||||
{
|
||||
key: '4',
|
||||
icon: <SettingOutlined />,
|
||||
label: t('header.settings'),
|
||||
icon: <div className="rb:size-4 rb:bg-cover rb:bg-[url('src/assets/images/menuNew/settings.svg')]"></div>,
|
||||
label: <Flex justify="space-between" align="center">
|
||||
{t('header.settings')}
|
||||
<div className="rb:size-4 rb:bg-cover rb:bg-[url('src/assets/images/menuNew/arrow_t_r.svg')]"></div>
|
||||
</Flex>,
|
||||
className: 'rb:text-[#212332]!',
|
||||
onClick: () => {
|
||||
settingModalRef.current?.handleOpen()
|
||||
},
|
||||
@@ -104,12 +116,14 @@ const AppHeader: FC<{source?: 'space' | 'manage';}> = ({source = 'manage'}) => {
|
||||
{
|
||||
key: '5',
|
||||
type: 'divider',
|
||||
className: 'rb:bg-[#EBEBEB]!'
|
||||
},
|
||||
{
|
||||
key: '6',
|
||||
icon: <LogoutOutlined />,
|
||||
icon: <div className="rb:size-4 rb:bg-cover rb:bg-[url('src/assets/images/menuNew/logout_red.svg')]"></div>,
|
||||
label: t('header.logout'),
|
||||
danger: true,
|
||||
className: 'rb:hover:rb:bg-transparent rb:hover:text-[#FF5D34]!',
|
||||
onClick: handleLogout,
|
||||
},
|
||||
];
|
||||
@@ -147,18 +161,34 @@ const AppHeader: FC<{source?: 'space' | 'manage';}> = ({source = 'manage'}) => {
|
||||
});
|
||||
}
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const handleOpenChange = (open: boolean) => {
|
||||
setOpen(open);
|
||||
}
|
||||
return (
|
||||
<Header className={styles.header}>
|
||||
{/* Breadcrumb navigation */}
|
||||
<Breadcrumb separator="<" items={formatBreadcrumbNames() as BreadcrumbProps['items']} className="rb:font-medium!" />
|
||||
{/* User info dropdown menu */}
|
||||
<Dropdown
|
||||
menu={{
|
||||
items: userMenuItems
|
||||
}}
|
||||
>
|
||||
<div className="rb:cursor-pointer rb:font-medium">{user.username}</div>
|
||||
</Dropdown>
|
||||
{user.username && (
|
||||
<Dropdown
|
||||
menu={{
|
||||
items: userMenuItems
|
||||
}}
|
||||
onOpenChange={handleOpenChange}
|
||||
overlayClassName={styles.userDropdown}
|
||||
>
|
||||
<Flex align="center" className="rb:cursor-pointer rb:font-medium">
|
||||
<Flex align="center" justify="center" className="rb:size-8 rb:rounded-xl rb:bg-[#155EEF] rb:text-white rb:mr-2!">
|
||||
{/[\u4e00-\u9fa5]/.test(user.username) ? user.username.slice(0, 2) : user.username[0]}
|
||||
</Flex>
|
||||
<span className="rb:text-[#212332] rb:text-[12px] rb:leading-4 rb:mr-1">{user.username}</span>
|
||||
<div className={clsx("rb:size-3 rb:bg-cover rb:bg-[url('@/assets/images/common/arrow_up.svg')]", {
|
||||
'rb:rotate-180': !open,
|
||||
})}></div>
|
||||
</Flex>
|
||||
</Dropdown>
|
||||
)}
|
||||
<SettingModal
|
||||
ref={settingModalRef}
|
||||
/>
|
||||
|
||||
@@ -980,6 +980,7 @@ export const en = {
|
||||
scene_id: 'Ontology Scenario',
|
||||
},
|
||||
member: {
|
||||
memberList: 'Member List',
|
||||
username: 'Username',
|
||||
account: 'Account',
|
||||
role: 'Role',
|
||||
@@ -1908,7 +1909,8 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re
|
||||
permissionInfo: 'Permission Information',
|
||||
is_expired: 'Status',
|
||||
active: 'Active',
|
||||
inactive: 'Expired'
|
||||
inactive: 'Expired',
|
||||
noScopes: 'There is no permission information here…',
|
||||
},
|
||||
tool: {
|
||||
mcp: 'MCP Services',
|
||||
|
||||
@@ -1375,6 +1375,7 @@ export const zh = {
|
||||
scene_id: '本体场景',
|
||||
},
|
||||
member: {
|
||||
memberList: '成员列表',
|
||||
username: '用户名',
|
||||
account: '账号',
|
||||
role: '角色',
|
||||
@@ -1905,7 +1906,8 @@ export const zh = {
|
||||
permissionInfo: '授权信息',
|
||||
is_expired: '状态',
|
||||
active: '活跃',
|
||||
inactive: '过期'
|
||||
inactive: '过期',
|
||||
noScopes: '暂无权限信息…',
|
||||
},
|
||||
tool: {
|
||||
mcp: 'MCP 服务',
|
||||
|
||||
@@ -396,6 +396,11 @@ body {
|
||||
color: #FFFFFF;
|
||||
background-color: #171719;
|
||||
}
|
||||
.ant-dropdown .ant-dropdown-menu .ant-dropdown-menu-item.ant-dropdown-menu-item-danger:not(.ant-dropdown-menu-item-disabled):hover,
|
||||
.ant-dropdown-menu-submenu .ant-dropdown-menu .ant-dropdown-menu-item.ant-dropdown-menu-item-danger:not(.ant-dropdown-menu-item-disabled):hover {
|
||||
background-color: #F6F6F6;
|
||||
color: #FF5D34;
|
||||
}
|
||||
|
||||
.spin.ant-spin-nested-loading .ant-spin-container::after {
|
||||
background: transparent;
|
||||
|
||||
@@ -6,20 +6,22 @@
|
||||
*/
|
||||
import React, { useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, App, Space } from 'antd';
|
||||
import { Button, App, Dropdown, Flex } from 'antd';
|
||||
import clsx from 'clsx';
|
||||
import { DeleteOutlined, EditOutlined, EyeOutlined } from '@ant-design/icons';
|
||||
import copy from 'copy-to-clipboard'
|
||||
import type { MenuInfo } from 'rc-menu/lib/interface';
|
||||
|
||||
import type { ApiKey, ApiKeyModalRef } from './types';
|
||||
import ApiKeyModal from './components/ApiKeyModal';
|
||||
import ApiKeyDetailModal from './components/ApiKeyDetailModal';
|
||||
import RbCard from '@/components/RbCard/Card'
|
||||
import RbCard from '@/components/RbCard'
|
||||
import { getApiKeyListUrl, deleteApiKey } from '@/api/apiKey';
|
||||
import PageScrollList, { type PageScrollListRef } from '@/components/PageScrollList'
|
||||
import { formatDateTime } from '@/utils/format';
|
||||
import Tag from '@/components/Tag'
|
||||
import { maskApiKeys } from '@/utils/apiKeyReplacer';
|
||||
import RbDescriptions from '@/components/RbDescriptions';
|
||||
|
||||
/**
|
||||
* API Key Management page component
|
||||
@@ -87,59 +89,85 @@ const ApiKeyManagement: React.FC = () => {
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<div className="rb:flex rb:justify-end rb:mb-3 rb:p-4">
|
||||
<Flex justify="flex-end" className="rb:mb-3!">
|
||||
<Button type="primary" onClick={() => handleEdit()}>
|
||||
{t('apiKey.createApiKey')}
|
||||
</Button>
|
||||
</div>
|
||||
</Flex>
|
||||
|
||||
<PageScrollList<ApiKey, { is_active: boolean; type: string }>
|
||||
ref={scrollListRef}
|
||||
url={getApiKeyListUrl}
|
||||
query={{ is_active: true, type: 'service' }}
|
||||
column={2}
|
||||
column={3}
|
||||
renderItem={(apiKeyItem) => {
|
||||
return (
|
||||
<RbCard
|
||||
title={apiKeyItem.name}
|
||||
>
|
||||
{['id', 'is_expired', 'created_at'].map((key, index) => (
|
||||
<div key={key} className={clsx("rb:flex rb:justify-between rb:gap-5 rb:font-regular rb:text-[14px]", {
|
||||
'rb:mt-3': index !== 0
|
||||
})}>
|
||||
<span className="rb:text-[#5B6167] rb:w-20">{t(`apiKey.${key}`)}</span>
|
||||
<span className="rb:flex-1 rb:text-left rb:py-px rb:rounded rb:font-medium">
|
||||
{ key === 'created_at'
|
||||
? formatDateTime(apiKeyItem[key], 'YYYY-MM-DD HH:mm:ss')
|
||||
: key === 'is_expired'
|
||||
? <Tag color={apiKeyItem[key] ? 'error' : 'processing'}>{apiKeyItem[key] ? t('apiKey.inactive') : t('apiKey.active')}</Tag>
|
||||
: String(apiKeyItem[key as keyof ApiKey])
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
<RbCard
|
||||
title={
|
||||
<Flex justify="space-between">
|
||||
<Flex gap={4} vertical>
|
||||
{apiKeyItem.name}
|
||||
<Flex gap={6}>
|
||||
{apiKeyItem.scopes?.includes('memory') && <Tag>{t('apiKey.memoryEngine')}</Tag>}
|
||||
{apiKeyItem.scopes?.includes('rag') && <Tag color="success">{t('apiKey.knowledgeBase')}</Tag>}
|
||||
{!apiKeyItem.scopes?.includes('memory') && !apiKeyItem.scopes?.includes('rag') && <div>{t('apiKey.noScopes')}</div>}
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Dropdown
|
||||
menu={{
|
||||
items: [
|
||||
{
|
||||
key: 'edit',
|
||||
icon: <div className="rb:size-4 rb:bg-cover rb:cursor-pointer rb:bg-[url('@/assets/images/common/edit_bold.svg')]" />,
|
||||
label: t('common.edit'),
|
||||
onClick: () => handleEdit(apiKeyItem),
|
||||
},
|
||||
{
|
||||
key: 'view',
|
||||
icon: <div className="rb:size-4 rb:bg-cover rb:cursor-pointer rb:bg-[url('@/assets/images/common/eye.svg')]" />,
|
||||
label: t('common.view'),
|
||||
onClick: () => handleView(apiKeyItem),
|
||||
},
|
||||
{
|
||||
key: 'delete',
|
||||
danger: true,
|
||||
icon: <div className="rb:size-4 rb:bg-cover rb:cursor-pointer rb:bg-[url('@/assets/images/common/delete_red_big.svg')]" />,
|
||||
label: t('common.delete'),
|
||||
onClick: () => handleDelete(apiKeyItem),
|
||||
},
|
||||
]
|
||||
}}
|
||||
placement="bottomRight"
|
||||
>
|
||||
<div className="rb:cursor-pointer rb:size-5.5 rb:bg-[url('@/assets/images/common/more.svg')] rb:hover:bg-[url('@/assets/images/common/more_hover.svg')]"></div>
|
||||
</Dropdown>
|
||||
</Flex>
|
||||
}
|
||||
isNeedTooltip={false}
|
||||
headerClassName="rb:min-h-[78px]!"
|
||||
>
|
||||
<RbDescriptions
|
||||
items={['id', 'is_expired', 'created_at'].map(key => ({
|
||||
key,
|
||||
label: t(`apiKey.${key}`),
|
||||
children: <span className={clsx({
|
||||
'rb:font-medium': key === 'id',
|
||||
})}>
|
||||
{key === 'created_at'
|
||||
? formatDateTime(apiKeyItem[key], 'YYYY-MM-DD HH:mm:ss')
|
||||
: key === 'is_expired'
|
||||
? <Tag color={apiKeyItem[key] ? 'error' : 'processing'}>{apiKeyItem[key] ? t('apiKey.inactive') : t('apiKey.active')}</Tag>
|
||||
: String(apiKeyItem[key as keyof ApiKey])
|
||||
}
|
||||
</span>
|
||||
}))}
|
||||
/>
|
||||
|
||||
<div className="rb:flex rb:items-center rb:justify-between rb:text-[#5B6167] rb:mt-5 rb:p-[8px_16px] rb:bg-[#FFFFFF] rb:border rb:border-[#DFE4ED] rb:rounded-lg rb:leading-5">
|
||||
{maskApiKeys(apiKeyItem.api_key)}
|
||||
|
||||
<Button className="rb:px-2! rb:h-7! rb:group" onClick={() => handleCopy(apiKeyItem.api_key)}>
|
||||
<div
|
||||
className="rb:w-4 rb:h-4 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/copy.svg')] rb:group-hover:bg-[url('@/assets/images/copy_active.svg')]"
|
||||
></div>
|
||||
{t('common.copy')}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Space className="rb:pt-2 rb:min-h-6.25">
|
||||
{apiKeyItem.scopes?.includes('memory') && <Tag>{t('apiKey.memoryEngine')}</Tag>}
|
||||
{apiKeyItem.scopes?.includes('rag') && <Tag color="success">{t('apiKey.knowledgeBase')}</Tag>}
|
||||
</Space>
|
||||
|
||||
<div className="rb:mt-5 rb:flex rb:justify-end rb:gap-2.5">
|
||||
<Button icon={<EyeOutlined />} onClick={() => handleView(apiKeyItem)}></Button>
|
||||
<Button icon={<EditOutlined />} onClick={() => handleEdit(apiKeyItem)}></Button>
|
||||
<Button icon={<DeleteOutlined />} onClick={() => handleDelete(apiKeyItem)}></Button>
|
||||
</div>
|
||||
<Flex align="center" justify="space-between" className="rb:h-8! rb:mt-4! rb:py-1! rb:pl-2.5! rb:pr-1! rb:bg-[#F6F6F6] rb:rounded-md rb:leading-5">
|
||||
{maskApiKeys(apiKeyItem.api_key)}
|
||||
|
||||
<div onClick={() => handleCopy(apiKeyItem.api_key)} className="rb:cursor-pointer rb:rounded-md rb:size-6 rb:bg-[url('@/assets/images/common/copy_dark.svg')] rb:bg-size-[16px_16px] rb:bg-center rb:bg-no-repeat" style={{ backgroundColor: 'rgba(0,0,0,0.08)' }}></div>
|
||||
</Flex>
|
||||
</RbCard>
|
||||
);
|
||||
}}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @Author: ZhaoYing
|
||||
* @Date: 2026-02-03 16:42:12
|
||||
* @Last Modified by: ZhaoYing
|
||||
* @Last Modified time: 2026-03-26 15:48:43
|
||||
* @Last Modified time: 2026-03-30 11:38:42
|
||||
*/
|
||||
/**
|
||||
* Member Management Page
|
||||
@@ -106,9 +106,10 @@ const MemberManagement: React.FC = () => {
|
||||
|
||||
return (
|
||||
<div className="rb:h-full rb:overflow-hidden rb:bg-white rb:rounded-lg rb:pt-3 rb:px-3">
|
||||
<Flex justify="end" className="rb:px-1! rb:mb-3!">
|
||||
<Flex justify="space-between" align="center" className="rb:px-1! rb:mb-3!">
|
||||
<div className="rb:font-[MiSans-Bold] rb:font-bold rb:text-[#212332] rb:leading-5">{t('member.memberList')}</div>
|
||||
<Button type="primary" onClick={() => handleEdit()}>
|
||||
{t('member.createMember')}
|
||||
+ {t('member.createMember')}
|
||||
</Button>
|
||||
</Flex>
|
||||
<Table<Member>
|
||||
|
||||
@@ -188,7 +188,7 @@ const Prompt: FC = () => {
|
||||
|
||||
<RbCard
|
||||
title={t('prompt.chatTitle')}
|
||||
headerClassName="rb:min-h-[52px]! rb:font-[MiSans-Bold] rb:gont-bold"
|
||||
headerClassName="rb:min-h-[52px]! rb:font-[MiSans-Bold] rb:font-bold"
|
||||
headerType="borderless"
|
||||
bodyClassName="rb:px-4! rb:pt-0! rb:pb-3!"
|
||||
>
|
||||
@@ -249,7 +249,7 @@ const Prompt: FC = () => {
|
||||
</Flex>
|
||||
<RbCard
|
||||
title={t('prompt.conversationOptimizationPrompt')}
|
||||
headerClassName="rb:min-h-[52px]! rb:font-[MiSans-Bold] rb:gont-bold"
|
||||
headerClassName="rb:min-h-[52px]! rb:font-[MiSans-Bold] rb:font-bold"
|
||||
headerType="borderless"
|
||||
bodyClassName="rb:px-4! rb:pt-0! rb:pb-3!"
|
||||
extra={
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* @Author: ZhaoYing
|
||||
* @Date: 2026-02-03 17:48:03
|
||||
* @Last Modified by: ZhaoYing
|
||||
* @Last Modified time: 2026-03-24 17:01:59
|
||||
* @Last Modified by: ZhaoYing
|
||||
* @Last Modified time: 2026-03-30 11:36:24
|
||||
*/
|
||||
/**
|
||||
* Space Configuration Page
|
||||
@@ -15,9 +15,7 @@ import { useTranslation } from 'react-i18next';
|
||||
|
||||
import type { SpaceConfigData } from './types'
|
||||
import { getWorkspaceModels, updateWorkspaceModels } from '@/api/workspaces'
|
||||
import { getModelListUrl } from '@/api/models'
|
||||
import CustomSelect from '@/components/CustomSelect'
|
||||
import RbAlert from '@/components/RbAlert';
|
||||
import ModelSelect from '@/components/ModelSelect';
|
||||
|
||||
const SpaceConfig: FC = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -63,7 +61,9 @@ const SpaceConfig: FC = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rb:w-250 rb:bg-white rb:rounded-lg rb:py-3 rb:px-3">
|
||||
<div className="rb:bg-white rb:rounded-lg rb:p-6 rb:pb-8">
|
||||
<div className="rb:font-[MiSans-Bold] rb:font-bold rb:text-[#212332] rb:leading-5">{t('menu.spaceConfig')}</div>
|
||||
<div className="rb:text-[#5B6167] rb:text-[12px] rb:leading-4 rb:mt-2 rb:mb-6">{t('space.configAlert')}</div>
|
||||
{pageLoading
|
||||
? <Skeleton active />
|
||||
: <Form
|
||||
@@ -71,55 +71,42 @@ const SpaceConfig: FC = () => {
|
||||
layout="vertical"
|
||||
>
|
||||
<Form.Item
|
||||
label={t('space.llmModel')}
|
||||
label={t('space.llmModel')}
|
||||
className="rb:font-medium rb:text-[#212332] rb:mb-6!"
|
||||
name="llm"
|
||||
rules={[{ required: true, message: t('common.pleaseSelect') }]}
|
||||
>
|
||||
<CustomSelect
|
||||
url={getModelListUrl}
|
||||
params={{ type: 'llm', pagesize: 100, is_active: true }}
|
||||
valueKey="id"
|
||||
labelKey="name"
|
||||
hasAll={false}
|
||||
style={{width: '100%'}}
|
||||
<ModelSelect
|
||||
params={{ type: 'llm' }}
|
||||
className="rb:w-137.5!"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t('space.embeddingModel')}
|
||||
label={t('space.embeddingModel')}
|
||||
className="rb:font-medium rb:text-[#212332] rb:mb-6!"
|
||||
name="embedding"
|
||||
rules={[{ required: true, message: t('common.pleaseSelect') }]}
|
||||
>
|
||||
<CustomSelect
|
||||
url={getModelListUrl}
|
||||
params={{ type: 'embedding', pagesize: 100, is_active: true }}
|
||||
valueKey="id"
|
||||
labelKey="name"
|
||||
hasAll={false}
|
||||
style={{width: '100%'}}
|
||||
<ModelSelect
|
||||
params={{ type: 'embedding' }}
|
||||
className="rb:w-137.5!"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t('space.rerankModel')}
|
||||
label={t('space.rerankModel')}
|
||||
className="rb:font-medium rb:text-[#212332] rb:mb-6!"
|
||||
name="rerank"
|
||||
rules={[{ required: true, message: t('common.pleaseSelect') }]}
|
||||
>
|
||||
<CustomSelect
|
||||
url={getModelListUrl}
|
||||
params={{ type: 'rerank', pagesize: 100, is_active: true }}
|
||||
valueKey="id"
|
||||
labelKey="name"
|
||||
hasAll={false}
|
||||
style={{width: '100%'}}
|
||||
<ModelSelect
|
||||
params={{ type: 'rerank' }}
|
||||
className="rb:w-137.5!"
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<RbAlert>{t('space.configAlert')}</RbAlert>
|
||||
|
||||
<Form.Item className="rb:text-right">
|
||||
<Button type="primary" className="rb:mt-6" onClick={handleSave} loading={loading}>
|
||||
{t('common.save')}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
<Button type="primary" className="rb:mt-1" onClick={handleSave} loading={loading}>
|
||||
{t('common.save')}
|
||||
</Button>
|
||||
</Form>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -144,7 +144,7 @@ const UserManagement: React.FC = () => {
|
||||
return (
|
||||
<div className="rb:h-full rb:overflow-hidden rb:bg-white rb:rounded-lg rb:pt-3 rb:px-3">
|
||||
<Flex justify="space-between" align="center" className="rb:px-1! rb:mb-3!">
|
||||
<div className="rb:gont-[MiSans-Bold] rb:font-bold rb:text-[#212332] rb:leading-5">{t('user.userList')}</div>
|
||||
<div className="rb:font-[MiSans-Bold] rb:font-bold rb:text-[#212332] rb:leading-5">{t('user.userList')}</div>
|
||||
<Button type="primary" onClick={handleCreate}>
|
||||
+ {t('user.createUser')}
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user