fix(web): ui upgrade

This commit is contained in:
zhaoying
2026-03-25 13:58:25 +08:00
parent 9df41456f6
commit 2b9fd33bc8
42 changed files with 223 additions and 191 deletions

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-03-07 16:49:59
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-18 10:12:23
* @Last Modified time: 2026-03-25 11:21:59
*/
import { useEffect, useState, type FC } from 'react';
import { Select, Flex, Space } from 'antd';
@@ -20,12 +20,16 @@ interface ModelSelectProps extends SelectProps {
params?: Query;
placeholder?: string;
fontClassName?: string;
isAutoFetch?: boolean;
initialData?: Model[];
}
const ModelSelect: FC<ModelSelectProps> = ({
params,
placeholder,
fontClassName,
isAutoFetch = true,
initialData = [],
...props
}) => {
const { t } = useTranslation();
@@ -33,6 +37,7 @@ const ModelSelect: FC<ModelSelectProps> = ({
// Fetch active models whenever params change; stringify for stable deep comparison
useEffect(() => {
if (!isAutoFetch) return
getModelList({
...(params ?? {}),
pagesize: 100,
@@ -40,7 +45,7 @@ const ModelSelect: FC<ModelSelectProps> = ({
}).then((res) => {
setOptions((res as { items: Model[] }).items ?? []);
});
}, [JSON.stringify(params)]);
}, [JSON.stringify(params), isAutoFetch]);
// Render the selected value inside the trigger with logo + truncated name
const labelRender: SelectProps['labelRender'] = ({ value }) => {
@@ -58,7 +63,7 @@ const ModelSelect: FC<ModelSelectProps> = ({
return (
<Select
placeholder={placeholder ?? t('common.pleaseSelect')}
options={options}
options={[...options, ...initialData]}
fieldNames={{ label: 'name', value: 'id' }}
allowClear
popupMatchSelectWidth={false}

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-02 15:24:23
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-23 11:35:33
* @Last Modified time: 2026-03-25 11:15:26
*/
/**
* SearchInput Component
@@ -51,6 +51,7 @@ const SearchInput: FC<SearchInputProps> = ({
throttleDelay,
defaultValue = undefined,
className = '',
variant = 'filled',
...props
}) => {
const { t } = useTranslation();
@@ -115,7 +116,8 @@ const SearchInput: FC<SearchInputProps> = ({
value={value}
onChange={handleChange}
style={{ width: '300px' }}
className={`rb:border-none! ${className}`}
className={className}
variant={variant}
{...props}
/>
);

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-02 15:25:31
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-16 10:51:29
* @Last Modified time: 2026-03-25 12:32:58
*/
/**
* SiderMenu Component
@@ -298,7 +298,10 @@ const Menu: FC<{
items={menuItems}
inlineCollapsed={collapsed}
inlineIndent={10}
className="rb:max-h-[calc(100vh-136px)] rb:overflow-y-auto"
className={clsx("rb:overflow-y-auto", {
'rb:max-h-[calc(100vh-136px)]': user?.is_superuser && source === 'space',
'rb:max-h-[calc(100vh-76px)]': !(user?.is_superuser && source === 'space')
})}
/>
{/* Return to space button for superusers */}
{user?.is_superuser && source === 'space' &&

View File

@@ -2801,6 +2801,7 @@ export const zh = {
},
prompt: {
promptDesc: '输入您的原始提示词AI将帮助您优化为更专业的版本',
chatTitle: '多轮对话',
editor: '提示词生成器',
history: '我的历史',
historyDesc: '查看和管理您的提示词优化历史',

View File

@@ -351,6 +351,10 @@ body {
color: #212332;
background: #F6F6F6;
}
.ant-input-filled,
.ant-select-filled:not(.ant-select-customize-input) .ant-select-selector {
background-color: #FFFFFF;
}
.ant-checkbox .ant-checkbox-inner {
border-radius: 6px !important;
}

View File

@@ -2,9 +2,9 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 16:29:21
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-24 15:27:30
* @Last Modified time: 2026-03-25 11:34:04
*/
import { useEffect, useRef, useState, forwardRef, useImperativeHandle } from 'react';
import { useEffect, useRef, useState, forwardRef, useImperativeHandle, useMemo } from 'react';
import { useTranslation } from 'react-i18next'
import { useParams } from 'react-router-dom';
import { Row, Col, Space, Form, Input, Button, App, Spin, Flex } from 'antd'
@@ -27,7 +27,7 @@ import type {
} from './types'
import type { Variable } from './components/VariableList/types'
import type { KnowledgeConfig } from './components/Knowledge/types'
import type { ModelListItem } from '@/views/ModelManagement/types'
import type { Model } from '@/views/ModelManagement/types'
import { getModelList } from '@/api/models';
import { saveAgentConfig } from '@/api/application'
import Knowledge from './components/Knowledge/Knowledge'
@@ -43,6 +43,7 @@ import type { Skill } from '@/views/Skills/types'
import SwitchFormItem from '@/components/FormItem/SwitchFormItem'
import DescWrapper from '@/components/FormItem/DescWrapper'
import FeaturesConfig from './components/FeaturesConfig'
import { getListLogoUrl } from '@/views/ModelManagement/utils';
/**
* Agent configuration component
@@ -56,8 +57,8 @@ const Agent = forwardRef<AgentRef, { onFeaturesLoad?: (features: FeaturesConfigF
const [loading, setLoading] = useState(false)
const [data, setData] = useState<Config | null>(null);
const modelConfigModalRef = useRef<ModelConfigModalRef>(null)
const [modelList, setModelList] = useState<ModelListItem[]>([])
const [defaultModel, setDefaultModel] = useState<ModelListItem | null>(null)
const [modelList, setModelList] = useState<Model[]>([])
const [defaultModel, setDefaultModel] = useState<Model | null>(null)
const [chatList, setChatList] = useState<ChatData[]>([])
const values = Form.useWatch<Config>([], form)
const [isSave, setIsSave] = useState(false)
@@ -260,7 +261,7 @@ const Agent = forwardRef<AgentRef, { onFeaturesLoad?: (features: FeaturesConfigF
const getModels = () => {
getModelList({ type: 'llm,chat', pagesize: 100, page: 1, is_active: true })
.then(res => {
const response = res as { items: ModelListItem[] }
const response = res as { items: Model[] }
setModelList(response.items)
})
}
@@ -273,7 +274,7 @@ const Agent = forwardRef<AgentRef, { onFeaturesLoad?: (features: FeaturesConfigF
useEffect(() => {
if (values?.default_model_config_id && modelList.length > 0) {
const filterValue = modelList.find(item => item.id === values.default_model_config_id)
setDefaultModel(filterValue as ModelListItem | null)
setDefaultModel(filterValue as Model | null)
setChatList([{
label: filterValue?.name || '',
model_config_id: filterValue?.id || '',
@@ -343,7 +344,10 @@ const Agent = forwardRef<AgentRef, { onFeaturesLoad?: (features: FeaturesConfigF
const handleSaveFeaturesConfig = (value: FeaturesConfigForm) => {
form.setFieldValue('features', value)
}
console.log('values', values)
const modelLogo = useMemo(() => {
return defaultModel?.name && getListLogoUrl(defaultModel.provider, defaultModel.logo as string)
}, [defaultModel])
console.log('values', values, defaultModel)
return (
<>
{loading && <Spin fullscreen></Spin>}
@@ -353,7 +357,10 @@ const Agent = forwardRef<AgentRef, { onFeaturesLoad?: (features: FeaturesConfigF
<Flex gap={16} vertical>
<Flex align="center" justify="space-between" className="rb:p-3! rb:bg-white rb:rounded-xl">
<Button type="primary" ghost onClick={handleModelConfig} className="rb:group">
{defaultModel?.name ? <div className="rb:size-4 rb:bg-[url('@/assets/images/application/model.svg')]"></div> : null}
{modelLogo
? <img src={modelLogo} className="rb:size-4 rb:rounded-md" alt="" />
: defaultModel?.name
? <div className="rb:size-4 rb:bg-[url('@/assets/images/application/model.svg')]"></div> : null}
{defaultModel?.name || t('application.chooseModel')}
</Button>
<Space size={12}>
@@ -475,7 +482,6 @@ const Agent = forwardRef<AgentRef, { onFeaturesLoad?: (features: FeaturesConfigF
</Row>
<ModelConfigModal
modelList={modelList}
data={values}
ref={modelConfigModalRef}
refresh={refresh}

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 16:29:29
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-03 19:05:23
* @Last Modified time: 2026-03-25 11:18:09
*/
import { type FC, useState, useRef, useEffect } from 'react';
import clsx from 'clsx';
@@ -127,10 +127,10 @@ const Api: FC<{ application: Application | null }> = ({ application }) => {
<div className="rb:w-250 rb:mx-auto">
<Flex gap={20} vertical>
<RbCard
title={<Flex align="center">
title={() => (<Flex align="center">
{t('application.endpointConfiguration')}
<span className="rb:text-[#5B6167] rb:text-[12px]">({t('application.endpointConfigurationSubTitle')})</span>
</Flex>}
</Flex>)}
headerType="borderless"
headerClassName="rb:min-h-13.5!"
>
@@ -157,10 +157,10 @@ const Api: FC<{ application: Application | null }> = ({ application }) => {
</Flex>
</RbCard>
<RbCard
title={<Flex align="center">
title={() => (<Flex align="center">
{t('application.apiKeys')}
<span className="rb:text-[#5B6167] rb:text-[12px]">({t('application.apiKeySubTitle')})</span>
</Flex>}
</Flex>)}
extra={
<Button style={{padding: '0 8px', height: '24px'}} onClick={handleAdd}>+ {t('application.addApiKey')}</Button>
}

View File

@@ -19,7 +19,7 @@ import copy from 'copy-to-clipboard';
import { updatePromptMessages, createPromptSessions } from '@/api/prompt'
import type { AiPromptModalRef, AiPromptVariableModalRef, AiPromptForm } from '../types'
import RbModal from '@/components/RbModal'
import type { ModelListItem } from '@/views/ModelManagement/types'
import type { Model } from '@/views/ModelManagement/types'
import ChatContent from '@/components/Chat/ChatContent'
import Empty from '@/components/Empty'
import ConversationEmptyIcon from '@/assets/images/conversation/conversationEmpty.svg'
@@ -37,7 +37,7 @@ interface AiPromptModalProps {
/** Callback to refresh prompt with optimized value */
refresh: (value: string) => void;
/** Default model to pre-select */
defaultModel?: ModelListItem | null;
defaultModel?: Model | null;
source?: 'application' | 'skills'
}

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 16:28:07
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-24 10:59:20
* @Last Modified time: 2026-03-25 11:28:02
*/
/**
* Model Configuration Modal
@@ -11,13 +11,14 @@
*/
import { forwardRef, useImperativeHandle, useState, useEffect } from 'react';
import { Form, Select } from 'antd';
import { Form, type SelectProps } from 'antd';
import { useTranslation } from 'react-i18next';
import type { ModelConfig, ModelConfigModalRef, Config, Source } from '../types'
import type { ModelListItem } from '@/views/ModelManagement/types'
import type { Model } from '@/views/ModelManagement/types'
import RbModal from '@/components/RbModal'
import RbSlider from '@/components/RbSlider'
import ModelSelect from '@/components/ModelSelect'
const FormItem = Form.Item;
@@ -25,8 +26,6 @@ const FormItem = Form.Item;
* Component props
*/
interface ModelConfigModalProps {
/** List of available models */
modelList?: ModelListItem[];
/** Callback to update model configuration */
refresh: (values: ModelConfig, type: Source) => void;
/** Application configuration data */
@@ -51,7 +50,6 @@ const configFields = [
const ModelConfigModal = forwardRef<ModelConfigModalRef, ModelConfigModalProps>(({
refresh,
data,
modelList = []
}, ref) => {
const { t } = useTranslation();
const [visible, setVisible] = useState(false);
@@ -102,11 +100,11 @@ const ModelConfigModal = forwardRef<ModelConfigModalRef, ModelConfigModalProps>(
});
}
/** Handle model selection change */
const handleChange = (_value: string, option: ModelListItem | ModelListItem[] | undefined) => {
const handleChange: SelectProps['onChange'] = (_value, option) => {
if (source === 'chat') {
form.setFieldValue('label', (option as ModelListItem).name)
form.setFieldValue('label', (option as Model).name)
} else {
form.setFieldValue('capability', (option as ModelListItem).capability)
form.setFieldValue('capability', (option as Model).capability)
}
}
@@ -140,13 +138,8 @@ const ModelConfigModal = forwardRef<ModelConfigModalRef, ModelConfigModalProps>(
hidden={source === 'multi_agent'}
>
{source !== 'multi_agent' &&
<Select
<ModelSelect
placeholder={t('common.pleaseSelect')}
fieldNames={{
label: 'name',
value: 'id',
}}
options={modelList}
onChange={handleChange}
/>
}

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-05 10:45:08
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-24 16:59:57
* @Last Modified time: 2026-03-25 11:09:01
*/
import { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
import { List, Flex, Tooltip, Form } from 'antd';
@@ -169,6 +169,7 @@ const SkillListModal = forwardRef<SkillModalRef, SkillModalProps>(({
<SearchInput
placeholder={t('skills.searchPlaceholder')}
className="rb:w-full!"
variant="outlined"
/>
</Form.Item>
</Form>
@@ -181,9 +182,9 @@ const SkillListModal = forwardRef<SkillModalRef, SkillModalProps>(({
renderItem={(item: Skill) => (
<List.Item>
{/* Skill card with selection state styling */}
<div key={item.id} className={clsx("rb:border rb:rounded-lg rb:p-[17px_16px] rb:cursor-pointer rb:hover:bg-[#F0F3F8]", {
"rb:bg-[rgba(21,94,239,0.06)] rb:border-[#155EEF] rb:text-[#155EEF]": selectedIds.includes(item.id),
"rb:border-[#DFE4ED] rb:text-[#212332]": !selectedIds.includes(item.id),
<div key={item.id} className={clsx("rb:border rb:rounded-lg rb:p-[17px_16px] rb:cursor-pointer rb:hover:bg-[#F6F6F6]", {
"rb:border-[#171719]": selectedIds.includes(item.id),
"rb-border": !selectedIds.includes(item.id),
})} onClick={() => handleSelect(item)}>
{/* Skill name and description */}
<div className="rb:flex-1 rb:max-w-[calc(100%-60px)]">
@@ -194,7 +195,7 @@ const SkillListModal = forwardRef<SkillModalRef, SkillModalProps>(({
</Tooltip>
{/* Skill description with tooltip */}
<Tooltip title={item.description}>
<Tooltip title={item.description} placement="topLeft">
<div className="rb:h-10 rb:leading-5 rb:wrap-break-word rb:line-clamp-2">{item.description}</div>
</Tooltip>
</div>

View File

@@ -2,11 +2,11 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 16:34:12
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-18 16:15:43
* @Last Modified time: 2026-03-25 11:37:51
*/
import React, { useState, useEffect, useMemo, type MouseEvent } from 'react';
import { useTranslation } from 'react-i18next';
import { Button, App, Flex, Row, Col, Collapse } from 'antd';
import { Button, App, Flex, Collapse } from 'antd';
import clsx from 'clsx';
import type { MySharedOutItem } from './types';
@@ -112,9 +112,9 @@ const MySharing: React.FC = () => {
</Button>
),
children: (
<Row gutter={[12, 12]}>
<div className="rb:grid rb:grid-cols-4 rb:gap-3">
{items.map(item => (
<Col key={item.id} span={6} className="rb:bg-[#F6F6F6] rb:rounded-lg rb:py-3! rb:px-4! rb:relative rb:cursor-pointer" onClick={() => handleEdit(item)}>
<div key={item.id} className="rb:bg-[#F6F6F6] rb:rounded-lg rb:py-3! rb:px-4! rb:relative rb:cursor-pointer" onClick={() => handleEdit(item)}>
<div
className="rb:absolute rb:top-3 rb:right-3 rb:cursor-pointer rb:size-4 rb:bg-cover rb:bg-[url('@/assets/images/close.svg')]"
onClick={(e) => handleCancelOne(item, e)}
@@ -153,15 +153,15 @@ const MySharing: React.FC = () => {
<span>{item.source_app_is_active ? t('application.sourceActive') : t('application.sourceInactive')}</span>
</Flex>
</Flex>
</Col>
</div>
))}
</Row>
</div>
),
}]}
/>
))}
</BodyWrapper>
</Flex>
</Flex>
);
};

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 16:34:12
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-19 21:29:45
* @Last Modified time: 2026-03-25 11:16:04
*/
/**
* Application Management Page
@@ -148,6 +148,7 @@ const ApplicationManagement: React.FC = () => {
label: t(`application.${type}`),
}))}
allowClear
variant="filled"
className="rb:w-30!"
/>
</Form.Item>

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 16:56:54
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-12 16:58:14
* @Last Modified time: 2026-03-25 11:42:26
*/
/**
* Emotion Engine Configuration Page
@@ -19,13 +19,12 @@ import clsx from 'clsx';
import RbCard from '@/components/RbCard/Card';
import { getMemoryEmotionConfig, updateMemoryEmotionConfig } from '@/api/memory'
import type { ConfigForm } from './types'
import CustomSelect from '@/components/CustomSelect';
import { getModelListUrl } from '@/api/models'
import SwitchFormItem from '@/components/FormItem/SwitchFormItem'
import LabelWrapper from '@/components/FormItem/LabelWrapper'
import DescWrapper from '@/components/FormItem/DescWrapper'
import RbSlider from '@/components/RbSlider';
import RbAlert from '@/components/RbAlert';
import ModelSelect from '@/components/ModelSelect';
/**
* Configuration field definitions
@@ -37,9 +36,8 @@ const configList = [
},
{
key: 'emotion_model_id',
type: 'customSelect',
url: getModelListUrl,
params: { type: 'chat,llm', page: 1, pagesize: 100, is_active: true }, // chat,llm
type: 'modelSelect',
params: { type: 'chat,llm' }, // chat,llm
},
{
key: 'emotion_min_intensity',
@@ -174,7 +172,7 @@ const EmotionEngine: React.FC = () => {
</div>
)
}
if (config.type === 'customSelect') {
if (config.type === 'modelSelect') {
return (
<div key={config.key} className="rb:bg-[#F6F6F6] rb:rounded-xl rb:p-3">
<LabelWrapper title={t(`emotionEngine.${config.key}`)} className="rb:mb-3">
@@ -184,12 +182,8 @@ const EmotionEngine: React.FC = () => {
name={config.key}
className="rb:mb-0!"
>
<CustomSelect
url={config.url as string}
<ModelSelect
params={config.params}
valueKey='id'
labelKey='name'
hasAll={false}
disabled={!values?.emotion_enabled && config.key !== 'emotion_enabled'}
/>
</Form.Item>

View File

@@ -68,7 +68,7 @@ const TopCardList: FC<{data?: DataResponse}> = ({ data }) => {
</Flex>
<div className="rb:mt-5 rb:font-[MiSans-Bold] rb:font-bold rb:text-[24px] rb:leading-8">
{item.key === 'spaces' && String(data?.active_workspaces)}
{item.key === 'spaces' && String(data?.active_workspaces || 0)}
{item.key === 'running_apps' && String(data?.[`${item.key}` as keyof DataResponse] || item.value || 0)}
{item.key !== 'spaces' && item.key !== 'running_apps' && String(data?.[`total_${item.key}` as keyof DataResponse] || item.value || 0)}
</div>

View File

@@ -6,22 +6,24 @@
* @LastEditors: yujiangping
* @LastEditTime: 2026-01-23 19:07:36
*/
import React, { useEffect, useState } from 'react';
import React, { useEffect, useState, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { Flex } from 'antd';
import { getVersion, type versionResponse } from '@/api/common'
import Empty from '@/components/Empty';
import { useI18n } from '@/store/locale';
const VersionCard: React.FC = () => {
const { t, i18n } = useTranslation();
const { t } = useTranslation();
const { language } = useI18n()
const [versionInfo, setVersionInfo] = useState<versionResponse | null>(null);
// 获取当前语言对应的介绍信息
const getIntroduction = () => {
const introduction = useMemo(() => {
if (!versionInfo) return null;
const currentLang = i18n.language;
return currentLang === 'zh' ? versionInfo.introduction : (versionInfo.introduction_en || versionInfo.introduction);
};
return language === 'zh' ? versionInfo.introduction : (versionInfo.introduction_en || versionInfo.introduction);
}, [versionInfo, language])
useEffect(() => {
const fetchVersion = async () => {
@@ -40,13 +42,14 @@ const VersionCard: React.FC = () => {
<div className='rb:w-full rb:p-3 rb:bg-white rb:rounded-xl rb:mt-3'>
<Flex gap={4} className="rb:mb-3">
<span className="rb:font-[MiSans-Bold] rb:font-bold rb:leading-5">{t('index.latestUpdate')}</span>
<span className='rb:text-[12px] rb:text-white rb:leading-4.25 rb:pt-px rb:pl-2 rb:pr-1.75 rb:bg-[#171719] rb:rounded-lg rb:rounded-bl-none '>
{versionInfo?.version}
</span>
{versionInfo?.version &&
<span className='rb:text-[12px] rb:text-white rb:leading-4.25 rb:pt-px rb:pl-2 rb:pr-1.75 rb:bg-[#171719] rb:rounded-lg rb:rounded-bl-none '>
{versionInfo?.version}
</span>
}
</Flex>
{versionInfo && (() => {
const introduction = getIntroduction();
return introduction ? (<>
{introduction
? (<>
<div className="rb:text-[#5B6167] rb:text-[12px] rb:leading-4.5 rb:mt-1 rb:mb-2">
{t('version.releaseDate')}: {introduction.releaseDate} | {t('version.name')}: {introduction.codeName}
</div>
@@ -63,8 +66,9 @@ const VersionCard: React.FC = () => {
/>
))}
</div>
</>) : null;
})()}
</>)
: <Empty size={88} />
}
</div>
);
};

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 17:30:11
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-19 15:38:38
* @Last Modified time: 2026-03-25 11:40:38
*/
/**
* Result Component
@@ -382,7 +382,7 @@ const Result: FC<ResultProps> = ({ loading, handleSave }) => {
))}
</div>
}
if (textPreprocessingTab === 'chunking') {
if (textPreprocessingTab === 'chunking' && vo.content) {
return (
<div key={index} className="rb:leading-5">
<div className="rb:font-medium">-{t('memoryExtractionEngine.fragment')}{vo.chunk_index}:</div>

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 16:50:10
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-24 16:52:48
* @Last Modified time: 2026-03-25 12:27:51
*/
/**
* Model List View
@@ -26,7 +26,7 @@ import { getListLogoUrl } from './utils'
/**
* Model list component
*/
const ModelList = forwardRef<BaseRef, { query: any; handleEdit: (vo?: ModelListItem) => void; }> (({ query, handleEdit }, ref) => {
const ModelList = forwardRef<BaseRef, { query: any; handleEdit: (vo?: ModelListItem) => void; handleCloseModel: () => void; }>(({ query, handleEdit, handleCloseModel }, ref) => {
const { t } = useTranslation();
const keyConfigModalRef = useRef<KeyConfigModalRef>(null)
const modelListDetailRef = useRef<ModelListDetailRef>(null)
@@ -101,6 +101,7 @@ const ModelList = forwardRef<BaseRef, { query: any; handleEdit: (vo?: ModelListI
ref={modelListDetailRef}
refresh={getList}
handleEdit={handleEdit}
handleCloseConfig={handleCloseModel}
/>
</>
)

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 16:50:14
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-23 11:33:44
* @Last Modified time: 2026-03-25 12:19:24
*/
/**
* Model Square View
@@ -39,7 +39,9 @@ const ModelSquare = forwardRef <BaseRef, { query: any; }>(({ query }, ref) => {
.then(res => {
const response = res as ModelPlaza[]
setList(response || [])
setActiveProvider(response[0]?.provider || null)
if (!activeProvider) {
setActiveProvider(response[0]?.provider || null)
}
})
}

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 16:49:28
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-24 18:23:31
* @Last Modified time: 2026-03-25 12:27:33
*/
/**
* Custom Model Modal
@@ -148,6 +148,7 @@ const CustomModelModal = forwardRef<CustomModelModalRef, CustomModelModalProps>(
/** Expose methods to parent component */
useImperativeHandle(ref, () => ({
handleOpen,
handleClose
}));
return (
<RbModal

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 16:49:45
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-24 16:55:30
* @Last Modified time: 2026-03-25 12:28:07
*/
/**
* Model List Detail Drawer
@@ -31,12 +31,13 @@ interface ModelListDetailProps {
/** Callback to refresh parent list */
refresh?: () => void;
handleEdit: (vo?: ModelListItem) => void;
handleCloseConfig?: () => void;
}
/**
* Model list detail drawer component
*/
const ModelListDetail = forwardRef<ModelListDetailRef, ModelListDetailProps>(({ refresh, handleEdit }, ref) => {
const ModelListDetail = forwardRef<ModelListDetailRef, ModelListDetailProps>(({ refresh, handleEdit, handleCloseConfig }, ref) => {
const { t } = useTranslation();
const [open, setOpen] = useState(false);
const [data, setData] = useState<ProviderModelItem>({} as ProviderModelItem)
@@ -84,6 +85,8 @@ const ModelListDetail = forwardRef<ModelListDetailRef, ModelListDetailProps>(({
setType(null)
setOpen(false)
refresh?.()
multiKeyConfigModalRef.current?.handleClose()
handleCloseConfig?.()
}
/** Refresh model list */
const handleRefresh = () => {

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 16:49:55
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-11 15:11:06
* @Last Modified time: 2026-03-25 12:24:41
*/
/**
* Multi-Key Configuration Modal
@@ -95,6 +95,7 @@ const MultiKeyConfigModal = forwardRef<MultiKeyConfigModalRef, MultiKeyConfigMod
/** Expose methods to parent component */
useImperativeHandle(ref, () => ({
handleOpen,
handleClose
}));
return (

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 16:50:05
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-20 19:02:31
* @Last Modified time: 2026-03-25 12:28:07
*/
/**
* Model Management Main Page
@@ -134,7 +134,7 @@ const tabKeys = ['group', 'list', 'square']
<div className="rb:w-full rb:h-[calc(100vh-125px)] rb:overflow-y-auto">
{activeTab === 'group' && <GroupModel ref={groupRef} query={query} handleEdit={handleEdit} />}
{activeTab === 'list' && <ModelList ref={modelListRef} query={query} handleEdit={handleEdit} />}
{activeTab === 'list' && <ModelList ref={modelListRef} query={query} handleEdit={handleEdit} handleCloseModel={() => customModelModalRef.current?.handleClose() } />}
{activeTab === 'square' && <ModelSquare query={query} />}
</div>
<GroupModelModal

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 16:50:18
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-24 18:23:48
* @Last Modified time: 2026-03-25 12:28:10
*/
/**
* Type definitions for Model Management
@@ -220,6 +220,7 @@ export interface MultiKeyForm {
export interface MultiKeyConfigModalRef {
/** Open modal with model data */
handleOpen: (vo: ModelListItem, provider?: string) => void;
handleClose: () => void;
}
/**
@@ -303,6 +304,7 @@ export interface CustomModelForm {
export interface CustomModelModalRef {
/** Open modal with optional model plaza item */
handleOpen: (vo?: ModelListItem) => void;
handleClose: () => void;
}
/**

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 14:10:15
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-20 16:36:02
* @Last Modified time: 2026-03-25 13:38:59
*/
import { type FC, useState, useRef } from 'react';
import type { MenuInfo } from 'rc-menu/lib/interface';
@@ -164,7 +164,7 @@ const Ontology: FC = () => {
}}
placement="bottomRight"
>
<div className="rb:cursor-pointer rb:size-6 rb:bg-[url('@/assets/images/common/more.svg')] rb:hover:bg-[url('@/assets/images/common/more_hover.svg')]"></div>
<div onClick={(e) => e.stopPropagation()} className="rb:cursor-pointer rb:size-6 rb:bg-[url('@/assets/images/common/more.svg')] rb:hover:bg-[url('@/assets/images/common/more_hover.svg')]"></div>
</Dropdown>
</Flex>
}

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 14:10:20
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-20 16:35:14
* @Last Modified time: 2026-03-25 12:16:23
*/
import { type FC, useEffect, useState, useRef } from 'react'
import { useParams, useNavigate } from 'react-router-dom';
@@ -122,7 +122,7 @@ const Detail: FC = () => {
</Space>}
/>
<div className="rb:h-[calc(100vh-64px)] rb:overflow-y-auto rb:pb-3 rb:px-3">
<div className="rb:h-[calc(100vh-64px)] rb:overflow-y-auto rb:p-3">
<Row gutter={12} className="rb:mb-4">
<Col span={6} offset={18}>
<SearchInput

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 17:46:47
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-16 15:54:45
* @Last Modified time: 2026-03-25 11:44:16
*/
/**
* Self Reflection Engine Configuration Page
@@ -18,13 +18,12 @@ import { useTranslation } from 'react-i18next';
import RbCard from '@/components/RbCard/Card';
import { getMemoryReflectionConfig, updateMemoryReflectionConfig, pilotRunMemoryReflectionConfig } from '@/api/memory'
import type { ConfigForm, Result, ReflexionData, MemoryVerify, QualityAssessment } from './types'
import CustomSelect from '@/components/CustomSelect';
import { getModelListUrl } from '@/api/models'
import Tag from '@/components/Tag'
import { useI18n } from '@/store/locale';
import SwitchFormItem from '@/components/FormItem/SwitchFormItem'
import LabelWrapper from '@/components/FormItem/LabelWrapper'
import DescWrapper from '@/components/FormItem/DescWrapper'
import ModelSelect from '@/components/ModelSelect';
/** Configuration list */
const configList = [
@@ -36,9 +35,8 @@ const configList = [
// Reflection model
{
key: 'reflection_model_id',
type: 'customSelect',
url: getModelListUrl,
params: { type: 'chat,llm', page: 1, pagesize: 100, is_active: true }, // chat,llm
type: 'modelSelect',
params: { type: 'chat,llm' }, // chat,llm
},
// Iteration period
{
@@ -195,7 +193,7 @@ const SelfReflectionEngine: React.FC = () => {
>
<Flex vertical gap={24}>
{configList.map(config => {
if (config.type === 'customSelect') {
if (config.type === 'modelSelect') {
return (
<div key={config.key}>
<LabelWrapper title={t(`reflectionEngine.${config.key}`)} className="rb:mb-3">
@@ -205,12 +203,8 @@ const SelfReflectionEngine: React.FC = () => {
name={config.key}
className="rb:mb-0!"
>
<CustomSelect
url={config.url as string}
<ModelSelect
params={config.params}
valueKey='id'
labelKey='name'
hasAll={false}
placeholder={t('common.pleaseSelect')}
disabled={!values?.reflection_enabled && config.key !== 'reflection_enabled'}
/>

View File

@@ -1,8 +1,8 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 17:49:09
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 17:49:09
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-25 11:45:54
*/
/**
* Space Modal Component
@@ -17,13 +17,12 @@ import type { SpaceModalData, SpaceModalRef, Space, StorageType } from '../types
import RbModal from '@/components/RbModal'
import { createWorkspace } from '@/api/workspaces'
import RadioGroupCard from '@/components/RadioGroupCard'
import { getModelListUrl } from '@/api/models'
import CustomSelect from '@/components/CustomSelect'
import UploadImages from '@/components/Upload/UploadImages'
import { getFileLink } from '@/api/fileStorage'
import ragIcon from '@/assets/images/space/rag.png'
import neo4jIcon from '@/assets/images/space/neo4j.png'
import { stringRegExp } from '@/utils/validator';
import ModelSelect from '@/components/ModelSelect';
const FormItem = Form.Item;
@@ -206,12 +205,8 @@ const SpaceModal = forwardRef<SpaceModalRef, SpaceModalProps>(({
name="llm"
rules={[{ required: true, message: t('common.selectPlaceholder', { title: t('space.llmModel') }) }]}
>
<CustomSelect
url={getModelListUrl}
params={{ type: 'llm,chat', pagesize: 100, is_active: true }}
valueKey="id"
labelKey="name"
hasAll={false}
<ModelSelect
params={{ type: 'llm,chat' }}
placeholder={t('common.selectPlaceholder', { title: t('space.llmModel') })}
className="rb:w-full!"
/>
@@ -221,12 +216,8 @@ const SpaceModal = forwardRef<SpaceModalRef, SpaceModalProps>(({
name="embedding"
rules={[{ required: true, message: t('common.selectPlaceholder', { title: t('space.embeddingModel') }) }]}
>
<CustomSelect
url={getModelListUrl}
params={{ type: 'embedding', pagesize: 100, is_active: true }}
valueKey="id"
labelKey="name"
hasAll={false}
<ModelSelect
params={{ type: 'embedding' }}
placeholder={t('common.selectPlaceholder', { title: t('space.embeddingModel') })}
className="rb:w-full!"
/>
@@ -236,12 +227,8 @@ const SpaceModal = forwardRef<SpaceModalRef, SpaceModalProps>(({
name="rerank"
rules={[{ required: true, message: t('common.selectPlaceholder', { title: t('space.rerankModel') }) }]}
>
<CustomSelect
url={getModelListUrl}
params={{ type: 'rerank', pagesize: 100, is_active: true }}
valueKey="id"
labelKey="name"
hasAll={false}
<ModelSelect
params={{ type: 'rerank' }}
placeholder={t('common.selectPlaceholder', { title: t('space.rerankModel') })}
className="rb:w-full!"
/>

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 17:51:08
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-23 12:14:51
* @Last Modified time: 2026-03-25 10:41:25
*/
/**
* User Management Page
@@ -72,7 +72,7 @@ const UserManagement: React.FC = () => {
className: 'rb:text-[#212332]'
},
{
title: <>{t('user.username')}<div className="rb:text-[#5B6167] rb:text-[12px] rb:font-medium">({t(`user.subUsername`)})</div></>,
title: <>{t('user.username')}<div>({t(`user.subUsername`)})</div></>,
dataIndex: 'email',
key: 'email',
width: 210,
@@ -121,7 +121,7 @@ const UserManagement: React.FC = () => {
key: 'action',
width: 137,
render: (_, record) => (
<Flex wrap>
<Flex vertical justify="start" align="start">
{record.is_active &&
<Button
type="link"

View File

@@ -1,8 +1,8 @@
/*
* @Author: ZhaoYing
* @Date: 2026-03-16 15:00:07
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-16 15:00:07
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-25 12:09:39
*/
import { type FC, useRef, useState, useEffect } from 'react'
import { Flex, Dropdown, type MenuProps, Slider } from 'antd'
@@ -114,7 +114,7 @@ const AudioPlayer: FC<AudioPlayerProps> = ({ src, fileName, fileSize }) => {
<Flex align="center" gap={12}>
<div className="rb:w-7.5 rb:h-9 rb:bg-cover rb:bg-[url('@/assets/images/userMemory/mp3.svg')]" />
<div className="rb:flex-1">
<div className="rb:font-medium rb:leading-5 rb:text-[14px]">{fileName}</div>
<div className="rb:font-medium rb:leading-5 rb:text-[14px] rb:wrap-break-word rb:line-clamp-1">{fileName}</div>
<div className="rb:text-[#5B6167] rb:text-[12px] rb:leading-4.5">{fileSize || '-'}</div>
</div>
</Flex>

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-02-03 18:32:23
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-24 11:36:22
* @Last Modified time: 2026-03-25 12:09:53
*/
import { type FC, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
@@ -130,7 +130,7 @@ const PerceptualLastInfo: FC = () => {
'rb:bg-[#F6F6F6]': type !== key
})}
onClick={() => setType(key)}
>{key}</div>))}
>{t(`perceptualDetail.${key}`)}</div>))}
</Flex>
{loading
? <Skeleton active />
@@ -147,7 +147,7 @@ const PerceptualLastInfo: FC = () => {
<Flex gap={12} align="center">
<div className="rb:w-7.5 rb:h-9 rb:bg-cover rb:bg-[url('@/assets/images/userMemory/file.svg')]"></div>
<div>
<div className="rb:leading-5 rb:font-medium rb:mb-1">{data.file_name}</div>
<div className="rb:leading-5 rb:font-medium rb:mb-1 rb:wrap-break-word rb:line-clamp-1">{data.file_name}</div>
<div className="rb:text-[#5B6167] rb:text-[12px] rb:leading-4.5">
{fileSize || '-'}
</div>

View File

@@ -1,8 +1,8 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:31:50
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-16 15:02:00
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-25 11:50:16
*/
import { useEffect, useState, useRef, forwardRef, useImperativeHandle } from 'react'
import { useTranslation } from 'react-i18next'
@@ -83,7 +83,8 @@ const Suggestions = forwardRef<{ handleRefresh: () => void; }, { refresh: () =>
title={t('statementDetail.suggestions')}
headerType="borderless"
headerClassName="rb:min-h-[46px]! rb:font-[MiSans-Bold] rb:font-bold"
bodyClassName="rb:p-3! rb:pt-0! rb:h-[740px]"
bodyClassName="rb:p-3! rb:pt-0! rb:h-[calc(100%-46px)]! rb:overflow-y-auto!"
className="rb:h-[calc(100vh-88px)]!"
>
{suggestions?.suggestions && suggestions?.suggestions.length > 0
? <Flex vertical gap={16} className="rb:h-full! rb:overflow-y-auto!">

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-01-07 20:37:34
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-16 15:07:50
* @Last Modified time: 2026-03-25 12:05:26
*/
import { useEffect, useState, useMemo, forwardRef, useImperativeHandle, useRef } from 'react'
import { useTranslation } from 'react-i18next'
@@ -170,8 +170,8 @@ const ForgetDetail = forwardRef((_props, ref) => {
<div className="rb:text-[18px] rb:font-[MiSans-Bold] rb:font-bold rb:leading-6">{data.activation_metrics?.low_activation_nodes ?? 0}</div>
<div className="rb:text-[#5B6167] rb:text-[10px] rb:leading-3.5">{t('forgetDetail.low_nodes')}</div>
<div className="rb:bg-white rb:rounded-lg rb:mt-2">
<div className="rb:h-29.5 rb:w-full rb:bg-cover rb:bg-[url('@/assets/images/userMemory/forget.png')]"></div>
<div className="rb:bg-white rb:rounded-lg rb:mt-2 rb:h-29.5">
<div className="rb:h-29.5 rb:w-full rb:bg-contain rb:bg-no-repeat rb:bg-center rb:bg-[url('@/assets/images/userMemory/forget.png')]"></div>
</div>
</div>
</div>

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-01-08 19:46:02
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-16 14:27:58
* @Last Modified time: 2026-03-25 11:56:55
*/
import { forwardRef, useImperativeHandle, useRef, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
@@ -91,7 +91,7 @@ const ImplicitDetail = forwardRef<{ handleRefresh: () => void; }, { refresh: ()
headerType="borderless"
headerClassName="rb:min-h-[50px]! rb:font-[MiSans-Bold] rb:font-bold"
bodyClassName="rb:p-3! rb:pt-0! rb:h-[calc(100%-54px)]"
className="rb:h-[calc(100vh-84px)]!"
className="rb:h-[calc(100vh-88px)]!"
>
<RadioGroupButton
value={activeTab}

View File

@@ -1,8 +1,8 @@
/*
* @Author: ZhaoYing
* @Date: 2026-01-12 14:42:02
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-16 15:10:17
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-25 11:55:36
*/
import { type FC, useEffect, useState, useMemo, useRef } from 'react'
import clsx from 'clsx'
@@ -157,34 +157,44 @@ const WorkingDetail: FC = () => {
:(
<Row gutter={16}>
<Col span={5}>
<div id="conversation-list" className="rb:h-[calc(100vh-76px)]! rb:border-r rb:border-[#EAECEE] rb:py-3 rb:px-4 rb:overflow-y-auto">
<InfiniteScroll
dataLength={data.length}
next={loadMore}
hasMore={hasMore}
loader={null}
scrollableTarget="conversation-list"
>
{data.map(item => (
<Flex
key={item.id}
gap={12}
align="center"
className={clsx("rb:cursor-pointer rb:rounded-xl rb:h-12 rb:py-1! rb:px-3! rb:hover:bg-[#F6F6F6]", {
'rb:bg-[#171719] rb:hover:bg-[#171719]! rb:text-white': item.id === selected?.id,
})}
onClick={() => setSelected(item)}
>
<div className="rb:size-6 rb:bg-cover rb:bg-[url('@/assets/images/userMemory/chat.svg')]"></div>
<Tooltip title={item.title}>
<div className="rb:leading-5 rb:wrap-break-word rb:line-clamp-2 rb:flex-1">
{item.title}
</div>
</Tooltip>
<RbCard
title={t('workingDetail.conversation')}
headerType="borderless"
headerClassName="rb:min-h-[58px]! rb:font-[MiSans-Bold] rb:font-bold"
bodyClassName='rb:p-3! rb:pt-0! rb:h-[calc(100%-58px)]'
className="rb:h-[calc(100vh-88px)]!"
>
<div id="conversation-list" className="rb:h-full! rb:overflow-y-auto">
<InfiniteScroll
dataLength={data.length}
next={loadMore}
hasMore={hasMore}
loader={null}
scrollableTarget="conversation-list"
>
<Flex vertical gap={8}>
{data.map(item => (
<Flex
key={item.id}
gap={12}
align="center"
className={clsx("rb:cursor-pointer rb:rounded-xl rb:h-12 rb:py-1! rb:px-3! rb:hover:bg-[#F6F6F6]", {
'rb:bg-[#171719] rb:hover:bg-[#171719]! rb:text-white': item.id === selected?.id,
})}
onClick={() => setSelected(item)}
>
<div className="rb:size-6 rb:bg-cover rb:bg-[url('@/assets/images/userMemory/chat.svg')]"></div>
<Tooltip title={item.title}>
<div className="rb:leading-5 rb:break-all rb:line-clamp-2 rb:flex-1">
{item.title}
</div>
</Tooltip>
</Flex>
))}
</Flex>
))}
</InfiniteScroll>
</div>
</InfiniteScroll>
</div>
</RbCard>
</Col>
{selected && <>
<Col flex="auto" className="rb:h-full">
@@ -193,7 +203,7 @@ const WorkingDetail: FC = () => {
headerType="borderless"
headerClassName="rb:min-h-[42px]! rb:pt-4! rb:font-[MiSans-Bold] rb:font-bold"
bodyClassName='rb:p-4! rb:pt-0! rb:h-[calc(100%-42px)]'
className="rb:h-full!"
className="rb:h-[calc(100vh-88px)]!"
>
<div className="rb:text-[#5B6167] rb:leading-4.5 rb:text-[12px]">{timeRange}</div>
<Flex justify="space-between" align="center" className="rb:bg-[#F6F6F6] rb:rounded-lg rb:py-2.5! rb:pr-2.5! rb:pl-3.25! rb:mt-3!">
@@ -222,7 +232,7 @@ const WorkingDetail: FC = () => {
headerType="borderless"
headerClassName="rb:min-h-[50px]! rb:font-[MiSans-Bold] rb:font-bold rb:leading-5.5"
bodyClassName='rb:p-4! rb:pt-0! rb:h-[calc(100%-50px)] rb:overflow-y-auto!'
className="rb:h-full!"
className="rb:h-[calc(100vh-88px)]!"
>
{detailLoading
? <Skeleton active />

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2026-01-07 20:37:34
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-20 11:52:00
* @Last Modified time: 2026-03-25 11:47:31
*/
import { type FC, useState, useMemo, useRef } from 'react'
import { useParams, useNavigate } from 'react-router-dom'
@@ -114,7 +114,7 @@ const Detail: FC = () => {
</Space>
}
/>
<div className="rb:h-[calc(100vh-64px)] rb:overflow-y-auto rb:px-3 rb:pb-3">
<div className="rb:h-[calc(100vh-64px)] rb:overflow-y-auto rb:p-3">
{type === 'EMOTIONAL_MEMORY' && <StatementDetail ref={statementDetailRef} refresh={handleRefresh} />}
{type === 'FORGET_MEMORY' && <ForgetDetail ref={forgetDetailRef} />}
{type === 'IMPLICIT_MEMORY' && <ImplicitDetail ref={implicitDetailRef} refresh={handleRefresh} />}

View File

@@ -1,10 +1,14 @@
import type { FC } from 'react';
import { Select, Divider } from 'antd';
// import { Node } from '@antv/x6';
import type { GraphRef } from '../types'
import { PlusOutlined, MinusOutlined, FileAddOutlined } from '@ant-design/icons'
import clsx from 'clsx'
import { Node } from '@antv/x6';
import type { GraphRef } from '../types'
interface CanvasToolbarProps {
/** Currently selected node */
selectedNode: Node | null;
miniMapRef: React.RefObject<HTMLDivElement>;
graphRef: GraphRef;
isHandMode: boolean;
@@ -14,6 +18,7 @@ interface CanvasToolbarProps {
}
const CanvasToolbar: FC<CanvasToolbarProps> = ({
selectedNode,
miniMapRef,
graphRef,
zoomLevel,
@@ -26,9 +31,15 @@ const CanvasToolbar: FC<CanvasToolbarProps> = ({
return (
<>
{/* 小地图 */}
<div ref={miniMapRef} className="rb:absolute rb:bottom-15 rb:right-8 rb:z-1000 rb:rounded-lg rb:overflow-hidden"></div>
<div ref={miniMapRef} className={clsx("rb:absolute rb:bottom-15 rb:z-1000 rb:rounded-lg rb:overflow-hidden", {
'rb:right-8': !selectedNode,
'rb:right-95.5': selectedNode,
})}></div>
{/* 缩放控制按钮 */}
<div className="rb:h-8.5 rb:bg-[#FFFFFF] rb:border rb:border-[#DFE4ED] rb:rounded-lg rb:shadow-[0px_2px_6px_0px_rgba(33,35,50,0.15)] rb:px-3 rb:py-2 rb:absolute rb:bottom-5 rb:right-8 rb:flex rb:flex-row rb:items-center rb:gap-4 rb:z-1000">
<div className={clsx("rb:h-8.5 rb:bg-[#FFFFFF] rb:border rb:border-[#DFE4ED] rb:rounded-lg rb:shadow-[0px_2px_6px_0px_rgba(33,35,50,0.15)] rb:px-3 rb:py-2 rb:absolute rb:bottom-5 rb:flex rb:flex-row rb:items-center rb:gap-4 rb:z-1000", {
'rb:right-8': !selectedNode,
'rb:right-95.5': selectedNode,
})}>
<MinusOutlined className="rb:text-[16px] rb:cursor-pointer" onClick={() => graphRef.current?.zoom(-0.1)} />
<Select
value={Math.round(zoomLevel * 100)}

View File

@@ -13,6 +13,9 @@
border-color: rgba(91, 97, 103, 0.30);
border-radius: 8px;
}
.default:global(.ant-collapse .ant-collapse-content) {
padding-top: 12px;
}
.collapse-item {
font-size: 12px;
line-height: 16px;

View File

@@ -2,7 +2,7 @@
* @Author: ZhaoYing
* @Date: 2025-12-23 16:22:51
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-03 10:11:48
* @Last Modified time: 2026-03-25 10:58:47
*/
import { type FC, useState, useEffect, useMemo } from 'react';
import { LexicalComposer } from '@lexical/react/LexicalComposer';
@@ -185,7 +185,7 @@ const Editor: FC<LexicalEditorProps> =({
// Calculate line height based on size prop
const lineHeight = useMemo(() => {
return `${height ? 16 : size === 'small' && variant === 'borderless' ? 18 : size === 'small' ? 16 : 20}px`
return `${height ? height - 10 : size === 'small' && variant === 'borderless' ? 18 : size === 'small' ? 16 : 20}px`
}, [size])
// Calculate placeholder minimum height
@@ -228,7 +228,7 @@ const Editor: FC<LexicalEditorProps> =({
<ContentEditable
style={{
minHeight: minheight,
padding: height || variant === 'borderless' ? '0' : '6px 8px',
padding: height ? '4px 6px' : variant === 'borderless' ? '0' : '6px 8px',
border: variant === 'borderless' ? 'none' : '1px solid #EBEBEB',
borderRadius: '8px',
outline: 'none',

View File

@@ -79,7 +79,7 @@ const ConditionNode: ReactShapeConfig['component'] = ({ node }) => {
{item.expressions.length > 0 && <Flex vertical gap={2}>
{item.expressions.map((expression: any, eIndex: number) => (
<div key={eIndex} className="rb:relative">
{item.expressions.length > 1 && eIndex > 0 && <div className="rb:absolute rb:-top-2 rb:right-2 rb:text-[10px] rb:text-[#155EEF] rb:font-medium rb:leading-3.5 rb:text-right rb:pr-0.5">{item.logical_operator.toLocaleUpperCase()}</div>}
{item.expressions.length > 1 && eIndex > 0 && <div className="rb:absolute rb:-top-2 rb:right-2 rb:text-[10px] rb:text-[#155EEF] rb:font-medium rb:leading-3.5 rb:text-right rb:pr-0.5">{item.logical_operator?.toLocaleUpperCase()}</div>}
<Flex align="center" className="rb:bg-[#F0F3F8] rb:shadow-[0px_2px_4px_0px_rgba(23,23,25,0.03)] rb:rounded-md rb:py-1! rb:px-1.5! rb:text-[10px] rb:text-[#5B6167] rb:font-medium rb:leading-3.5">
{caculateIsSet(expression, 'cases')
? <>

View File

@@ -29,7 +29,7 @@ const ModelConfig: FC = () => {
{model_id && (
<RbCard
title={t('workflow.config.llm.parameterSettings')}
headerClassName="rb:min-h-8! rb:mx-2!"
headerClassName="rb:min-h-8! rb:mx-2! rb:text-[12px]!"
bodyClassName="rb:pt-[14px]! rb:px-2! rb:pb-2!"
className="rb-border! rb:mb-4!"
variant="outlined"

View File

@@ -212,10 +212,11 @@ const ToolConfig: FC<{ options: Suggestion[]; }> = ({
onChange={(value) => form.setFieldValue(['tool_parameters', parameter.name], value)}
/>
: <Editor
height={32}
variant="outlined"
options={options}
type="input"
size="small"
height={28}
options={options}
placeholder={t('common.pleaseEnter')}
/>
}

View File

@@ -73,6 +73,7 @@ const Workflow = forwardRef<WorkflowRef, { onFeaturesLoad?: (features: FeaturesC
<div ref={containerRef} className="rb:w-full rb:h-full" />
{/* 地图工具栏 */}
<CanvasToolbar
selectedNode={selectedNode}
miniMapRef={miniMapRef}
graphRef={graphRef}
isHandMode={isHandMode}