feat(web): ui
This commit is contained in:
@@ -89,12 +89,15 @@ const Knowledge: FC<KnowledgeProps> = ({ value = { knowledge_bases: [] }, onChan
|
|||||||
onChange?.({ ...editConfig, knowledge_bases: [...list] })
|
onChange?.({ ...editConfig, knowledge_bases: [...list] })
|
||||||
} else if (type === 'rerankerConfig') {
|
} else if (type === 'rerankerConfig') {
|
||||||
const rerankerValues = values as RerankerConfig
|
const rerankerValues = values as RerankerConfig
|
||||||
setEditConfig(prev => ({ ...prev, ...rerankerValues }))
|
setEditConfig(prev => {
|
||||||
onChange?.({
|
const next = {
|
||||||
...editConfig,
|
...prev,
|
||||||
...rerankerValues,
|
...rerankerValues,
|
||||||
reranker_id: rerankerValues.rerank_model ? rerankerValues.reranker_id : undefined,
|
reranker_id: rerankerValues.rerank_model ? rerankerValues.reranker_id : undefined,
|
||||||
reranker_top_k: rerankerValues.rerank_model ? rerankerValues.reranker_top_k : undefined,
|
reranker_top_k: rerankerValues.rerank_model ? rerankerValues.reranker_top_k : undefined,
|
||||||
|
}
|
||||||
|
onChange?.(next)
|
||||||
|
return next
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { type FC } from 'react';
|
import { type FC, type MouseEvent } from 'react';
|
||||||
import { Dropdown } from 'antd';
|
import { Dropdown } from 'antd';
|
||||||
import type { MenuProps } from 'antd';
|
import type { MenuProps } from 'antd';
|
||||||
|
|
||||||
interface MoreDropdownProps {
|
interface MoreDropdownProps {
|
||||||
items: NonNullable<MenuProps['items']>;
|
items: NonNullable<MenuProps['items']>;
|
||||||
placement?: 'bottomRight' | 'bottomLeft' | 'topRight' | 'topLeft';
|
placement?: 'bottomRight' | 'bottomLeft' | 'topRight' | 'topLeft';
|
||||||
onClick?: (e: React.MouseEvent) => void;
|
onClick?: (e: MouseEvent) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* @Author: ZhaoYing
|
* @Author: ZhaoYing
|
||||||
* @Date: 2026-02-02 15:21:14
|
* @Date: 2026-02-02 15:21:14
|
||||||
* @Last Modified by: ZhaoYing
|
* @Last Modified by: ZhaoYing
|
||||||
* @Last Modified time: 2026-03-20 20:24:43
|
* @Last Modified time: 2026-04-22 12:03:08
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* RbCard Component
|
* RbCard Component
|
||||||
@@ -67,7 +67,7 @@ const RbCard: FC<RbCardProps> = ({
|
|||||||
{title}
|
{title}
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
: <div className="rb:flex-1 rb:leading-5.5 rb:min-w-0 rb:whitespace-break-spaces rb:wrap-break-word rb:line-clamp-2">
|
: <div className={`rb:flex-1 rb:leading-5.5 rb:min-w-0 rb:whitespace-break-spaces rb:wrap-break-word rb:line-clamp-2 ${titleClassName}`}>
|
||||||
{title}
|
{title}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* @Author: ZhaoYing
|
* @Author: ZhaoYing
|
||||||
* @Date: 2026-02-02 15:29:57
|
* @Date: 2026-02-02 15:29:57
|
||||||
* @Last Modified by: ZhaoYing
|
* @Last Modified by: ZhaoYing
|
||||||
* @Last Modified time: 2026-04-22 11:39:15
|
* @Last Modified time: 2026-04-22 13:48:09
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Tag Component
|
* Tag Component
|
||||||
@@ -40,7 +40,7 @@ const colors = {
|
|||||||
/** Custom tag component with color themes */
|
/** Custom tag component with color themes */
|
||||||
const Tag: FC<TagProps> = ({ color = 'processing', children, className, variant = 'outline' }) => {
|
const Tag: FC<TagProps> = ({ color = 'processing', children, className, variant = 'outline' }) => {
|
||||||
return (
|
return (
|
||||||
<span className={`rb:inline-block rb:px-1 rb:py-0.5 rb:rounded-sm rb:text-[12px] rb:font-regular! rb:leading-4 rb:border ${colors[color]} ${className || ''}, ${variant === 'borderless' ? 'rb:border-none!' : ''}`}>
|
<span className={`rb:inline-block rb:px-1 rb:py-0.5 rb:rounded-sm rb:text-[12px] rb:font-regular! rb:leading-4 rb:border ${colors[color]} ${className || ''} ${variant === 'borderless' ? 'rb:border-none!' : ''}`}>
|
||||||
{children}
|
{children}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,6 +11,15 @@ import App from '@/App.tsx'
|
|||||||
// Synchronously import i18n config to ensure initialization before component rendering
|
// Synchronously import i18n config to ensure initialization before component rendering
|
||||||
import './i18n'
|
import './i18n'
|
||||||
|
|
||||||
|
// Fix autofill background color on focus
|
||||||
|
document.addEventListener('animationstart', (e) => {
|
||||||
|
if (e.animationName === 'onAutoFillStart') {
|
||||||
|
const input = e.target as HTMLInputElement
|
||||||
|
input.style.backgroundColor = 'transparent'
|
||||||
|
input.addEventListener('focus', () => { input.style.backgroundColor = 'transparent' }, { once: false })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// After a new release, old dynamic chunk files are deleted; force a page reload on preload error
|
// After a new release, old dynamic chunk files are deleted; force a page reload on preload error
|
||||||
window.addEventListener('vite:preloadError', () => {
|
window.addEventListener('vite:preloadError', () => {
|
||||||
console.warn('New version detected, reloading page to load latest assets...')
|
console.warn('New version detected, reloading page to load latest assets...')
|
||||||
|
|||||||
@@ -457,4 +457,14 @@ body {
|
|||||||
|
|
||||||
.pageTabs.ant-segmented .ant-segmented-item-selected {
|
.pageTabs.ant-segmented .ant-segmented-item-selected {
|
||||||
box-shadow: 0px 2px 4px 0px rgba(33, 35, 50, 0.16);
|
box-shadow: 0px 2px 4px 0px rgba(33, 35, 50, 0.16);
|
||||||
}
|
}
|
||||||
|
input:-webkit-autofill,
|
||||||
|
input:-webkit-autofill:hover,
|
||||||
|
input:-webkit-autofill:focus,
|
||||||
|
input:-webkit-autofill:active {
|
||||||
|
-webkit-box-shadow: 0 0 0 1000px transparent inset !important;
|
||||||
|
transition: background-color 5000s ease-in-out 0s !important;
|
||||||
|
animation-name: onAutoFillStart;
|
||||||
|
animation-duration: 1ms;
|
||||||
|
}
|
||||||
|
@keyframes onAutoFillStart { from {} to {} }
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
* @Author: ZhaoYing
|
* @Author: ZhaoYing
|
||||||
* @Date: 2026-02-03 15:52:50
|
* @Date: 2026-02-03 15:52:50
|
||||||
* @Last Modified by: ZhaoYing
|
* @Last Modified by: ZhaoYing
|
||||||
* @Last Modified time: 2026-04-22 11:34:06
|
* @Last Modified time: 2026-04-22 12:07:40
|
||||||
*/
|
*/
|
||||||
import React, { useRef } from 'react';
|
import React, { useRef } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@@ -95,44 +95,39 @@ const ApiKeyManagement: React.FC = () => {
|
|||||||
renderItem={(apiKeyItem) => {
|
renderItem={(apiKeyItem) => {
|
||||||
return (
|
return (
|
||||||
<RbCard
|
<RbCard
|
||||||
title={
|
title={apiKeyItem.name}
|
||||||
<Flex justify="space-between" className="rb:w-full!">
|
extra={<MoreDropdown
|
||||||
<Flex gap={4} vertical className="rb:flex-1!">
|
items={[
|
||||||
{apiKeyItem.name}
|
{
|
||||||
<Flex gap={6}>
|
key: 'edit',
|
||||||
{apiKeyItem.scopes?.includes('memory') && <Tag>{t('apiKey.memoryEngine')}</Tag>}
|
icon: <div className="rb:size-4 rb:bg-cover rb:cursor-pointer rb:bg-[url('@/assets/images/common/edit_bold.svg')]" />,
|
||||||
{apiKeyItem.scopes?.includes('rag') && <Tag color="success">{t('apiKey.knowledgeBase')}</Tag>}
|
label: t('common.edit'),
|
||||||
{!apiKeyItem.scopes?.includes('memory') && !apiKeyItem.scopes?.includes('rag') && <div className="rb:font-regular!">{t('apiKey.noScopes')}</div>}
|
onClick: () => handleEdit(apiKeyItem),
|
||||||
</Flex>
|
},
|
||||||
</Flex>
|
{
|
||||||
<MoreDropdown
|
key: 'view',
|
||||||
items={[
|
icon: <div className="rb:size-4 rb:bg-cover rb:cursor-pointer rb:bg-[url('@/assets/images/common/eye.svg')]" />,
|
||||||
{
|
label: t('common.view'),
|
||||||
key: 'edit',
|
onClick: () => handleView(apiKeyItem),
|
||||||
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: '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')]" />,
|
||||||
key: 'view',
|
label: t('common.delete'),
|
||||||
icon: <div className="rb:size-4 rb:bg-cover rb:cursor-pointer rb:bg-[url('@/assets/images/common/eye.svg')]" />,
|
onClick: () => handleDelete(apiKeyItem),
|
||||||
label: t('common.view'),
|
},
|
||||||
onClick: () => handleView(apiKeyItem),
|
]}
|
||||||
},
|
/>}
|
||||||
{
|
variant="borderless"
|
||||||
key: 'delete',
|
headerClassName="rb:min-h-[42px]!"
|
||||||
danger: true,
|
titleClassName="rb:line-clamp-1!"
|
||||||
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),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</Flex>
|
|
||||||
}
|
|
||||||
isNeedTooltip={false}
|
|
||||||
headerClassName="rb:min-h-[78px]!"
|
|
||||||
>
|
>
|
||||||
|
<Flex gap={6} className="rb:-mt-2! rb:mb-4!">
|
||||||
|
{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 className="rb:font-regular!">{t('apiKey.noScopes')}</div>}
|
||||||
|
</Flex>
|
||||||
<RbDescriptions
|
<RbDescriptions
|
||||||
items={['id', 'is_expired', 'created_at'].map(key => ({
|
items={['id', 'is_expired', 'created_at'].map(key => ({
|
||||||
key,
|
key,
|
||||||
|
|||||||
Reference in New Issue
Block a user