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] })
|
||||
} else if (type === 'rerankerConfig') {
|
||||
const rerankerValues = values as RerankerConfig
|
||||
setEditConfig(prev => ({ ...prev, ...rerankerValues }))
|
||||
onChange?.({
|
||||
...editConfig,
|
||||
...rerankerValues,
|
||||
reranker_id: rerankerValues.rerank_model ? rerankerValues.reranker_id : undefined,
|
||||
reranker_top_k: rerankerValues.rerank_model ? rerankerValues.reranker_top_k : undefined,
|
||||
setEditConfig(prev => {
|
||||
const next = {
|
||||
...prev,
|
||||
...rerankerValues,
|
||||
reranker_id: rerankerValues.rerank_model ? rerankerValues.reranker_id : 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 type { MenuProps } from 'antd';
|
||||
|
||||
interface MoreDropdownProps {
|
||||
items: NonNullable<MenuProps['items']>;
|
||||
placement?: 'bottomRight' | 'bottomLeft' | 'topRight' | 'topLeft';
|
||||
onClick?: (e: React.MouseEvent) => void;
|
||||
onClick?: (e: MouseEvent) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @Author: ZhaoYing
|
||||
* @Date: 2026-02-02 15:21:14
|
||||
* @Last Modified by: ZhaoYing
|
||||
* @Last Modified time: 2026-03-20 20:24:43
|
||||
* @Last Modified time: 2026-04-22 12:03:08
|
||||
*/
|
||||
/**
|
||||
* RbCard Component
|
||||
@@ -67,7 +67,7 @@ const RbCard: FC<RbCardProps> = ({
|
||||
{title}
|
||||
</div>
|
||||
</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}
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @Author: ZhaoYing
|
||||
* @Date: 2026-02-02 15:29:57
|
||||
* @Last Modified by: ZhaoYing
|
||||
* @Last Modified time: 2026-04-22 11:39:15
|
||||
* @Last Modified time: 2026-04-22 13:48:09
|
||||
*/
|
||||
/**
|
||||
* Tag Component
|
||||
@@ -40,7 +40,7 @@ const colors = {
|
||||
/** Custom tag component with color themes */
|
||||
const Tag: FC<TagProps> = ({ color = 'processing', children, className, variant = 'outline' }) => {
|
||||
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}
|
||||
</span>
|
||||
)
|
||||
|
||||
@@ -11,6 +11,15 @@ import App from '@/App.tsx'
|
||||
// Synchronously import i18n config to ensure initialization before component rendering
|
||||
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
|
||||
window.addEventListener('vite:preloadError', () => {
|
||||
console.warn('New version detected, reloading page to load latest assets...')
|
||||
|
||||
@@ -457,4 +457,14 @@ body {
|
||||
|
||||
.pageTabs.ant-segmented .ant-segmented-item-selected {
|
||||
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
|
||||
* @Date: 2026-02-03 15:52:50
|
||||
* @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 { useTranslation } from 'react-i18next';
|
||||
@@ -95,44 +95,39 @@ const ApiKeyManagement: React.FC = () => {
|
||||
renderItem={(apiKeyItem) => {
|
||||
return (
|
||||
<RbCard
|
||||
title={
|
||||
<Flex justify="space-between" className="rb:w-full!">
|
||||
<Flex gap={4} vertical className="rb:flex-1!">
|
||||
{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 className="rb:font-regular!">{t('apiKey.noScopes')}</div>}
|
||||
</Flex>
|
||||
</Flex>
|
||||
<MoreDropdown
|
||||
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),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Flex>
|
||||
}
|
||||
isNeedTooltip={false}
|
||||
headerClassName="rb:min-h-[78px]!"
|
||||
title={apiKeyItem.name}
|
||||
extra={<MoreDropdown
|
||||
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),
|
||||
},
|
||||
]}
|
||||
/>}
|
||||
variant="borderless"
|
||||
headerClassName="rb:min-h-[42px]!"
|
||||
titleClassName="rb:line-clamp-1!"
|
||||
>
|
||||
<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
|
||||
items={['id', 'is_expired', 'created_at'].map(key => ({
|
||||
key,
|
||||
|
||||
Reference in New Issue
Block a user