mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-23 06:46:40 +08:00
### What problem does this PR solve? change language Issue link: #245 - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
@ -1,3 +1,4 @@
|
||||
import { useTranslate } from '@/hooks/commonHooks';
|
||||
import { SettingOutlined } from '@ant-design/icons';
|
||||
import { Button, Flex, Typography } from 'antd';
|
||||
|
||||
@ -16,6 +17,8 @@ const SettingTitle = ({
|
||||
clickButton,
|
||||
showRightButton = false,
|
||||
}: IProps) => {
|
||||
const { t } = useTranslate('setting');
|
||||
|
||||
return (
|
||||
<Flex align="center" justify={'space-between'}>
|
||||
<div>
|
||||
@ -24,7 +27,7 @@ const SettingTitle = ({
|
||||
</div>
|
||||
{showRightButton && (
|
||||
<Button type={'primary'} onClick={clickButton}>
|
||||
<SettingOutlined></SettingOutlined> System Model Settings
|
||||
<SettingOutlined></SettingOutlined> {t('systemModelSettings')}
|
||||
</Button>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
@ -5,6 +5,7 @@ import {
|
||||
IThirdOAIModelCollection as IThirdAiModelCollection,
|
||||
} from '@/interfaces/database/llm';
|
||||
import { IUserInfo } from '@/interfaces/database/userSetting';
|
||||
import i18n from '@/locales/config';
|
||||
import userService from '@/services/userService';
|
||||
import { message } from 'antd';
|
||||
import { DvaModel } from 'umi';
|
||||
@ -47,7 +48,8 @@ const model: DvaModel<SettingModelState> = {
|
||||
const { data } = yield call(userService.setting, payload);
|
||||
const { retcode } = data;
|
||||
if (retcode === 0) {
|
||||
message.success('Modified!');
|
||||
message.success(i18n.t('message.modified'));
|
||||
|
||||
yield put({
|
||||
type: 'getUserInfo',
|
||||
});
|
||||
@ -89,7 +91,8 @@ const model: DvaModel<SettingModelState> = {
|
||||
const { data } = yield call(userService.set_tenant_info, payload);
|
||||
const { retcode } = data;
|
||||
if (retcode === 0) {
|
||||
message.success('Modified!');
|
||||
message.success(i18n.t('message.modified'));
|
||||
|
||||
yield put({
|
||||
type: 'getTenantInfo',
|
||||
});
|
||||
@ -137,7 +140,8 @@ const model: DvaModel<SettingModelState> = {
|
||||
const { data } = yield call(userService.set_api_key, payload);
|
||||
const { retcode } = data;
|
||||
if (retcode === 0) {
|
||||
message.success('Modified!');
|
||||
message.success(i18n.t('message.modified'));
|
||||
|
||||
yield put({ type: 'my_llm' });
|
||||
yield put({ type: 'factories_list' });
|
||||
yield put({
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { IModalManagerChildrenProps } from '@/components/modal-manager';
|
||||
import { useTranslate } from '@/hooks/commonHooks';
|
||||
import { Form, Input, Modal } from 'antd';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
@ -24,6 +25,7 @@ const ApiKeyModal = ({
|
||||
onOk,
|
||||
}: IProps) => {
|
||||
const [form] = Form.useForm();
|
||||
const { t } = useTranslate('setting');
|
||||
|
||||
const handleOk = async () => {
|
||||
const ret = await form.validateFields();
|
||||
@ -49,7 +51,7 @@ const ApiKeyModal = ({
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title="Modify"
|
||||
title={t('modify')}
|
||||
open={visible}
|
||||
onOk={handleOk}
|
||||
onCancel={handleCancel}
|
||||
@ -67,18 +69,18 @@ const ApiKeyModal = ({
|
||||
form={form}
|
||||
>
|
||||
<Form.Item<FieldType>
|
||||
label="Api-Key"
|
||||
label={t('apiKey')}
|
||||
name="api_key"
|
||||
tooltip="The API key can be obtained by registering the corresponding LLM supplier."
|
||||
rules={[{ required: true, message: 'Please input api key!' }]}
|
||||
tooltip={t('apiKeyTip')}
|
||||
rules={[{ required: true, message: t('apiKeyMessage') }]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
{llmFactory === 'OpenAI' && (
|
||||
<Form.Item<FieldType>
|
||||
label="Base-Url"
|
||||
label={t('baseUrl')}
|
||||
name="base_url"
|
||||
tooltip="If your API key is from OpenAI, just ignore it. Any other intermediate providers will give this base url with the API key."
|
||||
tooltip={t('baseUrlTip')}
|
||||
>
|
||||
<Input placeholder="https://api.openai.com/v1" />
|
||||
</Form.Item>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { ReactComponent as MoreModelIcon } from '@/assets/svg/more-model.svg';
|
||||
import { useSetModalState } from '@/hooks/commonHooks';
|
||||
import { useSetModalState, useTranslate } from '@/hooks/commonHooks';
|
||||
import {
|
||||
LlmItem,
|
||||
useFetchLlmFactoryListOnMount,
|
||||
@ -64,6 +64,7 @@ interface IModelCardProps {
|
||||
|
||||
const ModelCard = ({ item, clickApiKey }: IModelCardProps) => {
|
||||
const { visible, switchVisible } = useSetModalState();
|
||||
const { t } = useTranslate('setting');
|
||||
|
||||
const handleApiKeyClick = () => {
|
||||
clickApiKey(item.name);
|
||||
@ -94,7 +95,7 @@ const ModelCard = ({ item, clickApiKey }: IModelCardProps) => {
|
||||
</Button>
|
||||
<Button onClick={handleShowMoreClick}>
|
||||
<Flex gap={'small'}>
|
||||
Show more models
|
||||
{t('showMoreModels')}
|
||||
<MoreModelIcon />
|
||||
</Flex>
|
||||
</Button>
|
||||
@ -140,6 +141,7 @@ const UserSettingModel = () => {
|
||||
hideSystemSettingModal,
|
||||
showSystemSettingModal,
|
||||
} = useSubmitSystemModelSetting();
|
||||
const { t } = useTranslate('setting');
|
||||
|
||||
const handleApiKeyClick = useCallback(
|
||||
(llmFactory: string) => {
|
||||
@ -155,7 +157,7 @@ const UserSettingModel = () => {
|
||||
const items: CollapseProps['items'] = [
|
||||
{
|
||||
key: '1',
|
||||
label: 'Added models',
|
||||
label: t('addedModels'),
|
||||
children: (
|
||||
<List
|
||||
grid={{ gutter: 16, column: 1 }}
|
||||
@ -168,7 +170,7 @@ const UserSettingModel = () => {
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: 'Models to be added',
|
||||
label: t('modelsToBeAdded'),
|
||||
children: (
|
||||
<List
|
||||
grid={{
|
||||
@ -193,7 +195,7 @@ const UserSettingModel = () => {
|
||||
</Flex>
|
||||
<Divider></Divider>
|
||||
<Button type="link" onClick={handleAddModel(item.name)}>
|
||||
Add the model
|
||||
{t('addTheModel')}
|
||||
</Button>
|
||||
</Card>
|
||||
</List.Item>
|
||||
@ -208,8 +210,8 @@ const UserSettingModel = () => {
|
||||
<Spin spinning={loading}>
|
||||
<section className={styles.modelWrapper}>
|
||||
<SettingTitle
|
||||
title="Model Setting"
|
||||
description="Manage your account settings and preferences here."
|
||||
title={t('model')}
|
||||
description={t('profileDescription')}
|
||||
showRightButton
|
||||
clickButton={showSystemSettingModal}
|
||||
></SettingTitle>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { IModalManagerChildrenProps } from '@/components/modal-manager';
|
||||
import { LlmModelType } from '@/constants/knowledge';
|
||||
import { useTranslate } from '@/hooks/commonHooks';
|
||||
import { ISystemModelSettingSavingParams } from '@/hooks/llmHooks';
|
||||
import { Form, Modal, Select } from 'antd';
|
||||
import { useEffect } from 'react';
|
||||
@ -21,6 +22,7 @@ const SystemModelSettingModal = ({
|
||||
const [form] = Form.useForm();
|
||||
const { systemSetting: initialValues, allOptions } =
|
||||
useFetchSystemModelSettingOnMount(visible);
|
||||
const { t } = useTranslate('setting');
|
||||
|
||||
const handleOk = async () => {
|
||||
const values = await form.validateFields();
|
||||
@ -35,7 +37,7 @@ const SystemModelSettingModal = ({
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title="System Model Settings"
|
||||
title={t('systemModelSettings')}
|
||||
open={visible}
|
||||
onOk={handleOk}
|
||||
onCancel={hideModal}
|
||||
@ -43,25 +45,32 @@ const SystemModelSettingModal = ({
|
||||
confirmLoading={loading}
|
||||
>
|
||||
<Form form={form} onValuesChange={onFormLayoutChange} layout={'vertical'}>
|
||||
|
||||
<Form.Item label="Chat model" name="llm_id" tooltip="The default chat LLM all the newly created knowledgebase will use.">
|
||||
<Form.Item
|
||||
label={t('chatModel')}
|
||||
name="llm_id"
|
||||
tooltip={t('chatModelTip')}
|
||||
>
|
||||
<Select options={allOptions[LlmModelType.Chat]} />
|
||||
</Form.Item>
|
||||
<Form.Item label="Embedding model" name="embd_id" tooltip="The default embedding model all the newly created knowledgebase will use.">
|
||||
<Form.Item
|
||||
label={t('embeddingModel')}
|
||||
name="embd_id"
|
||||
tooltip={t('embeddingModelTip')}
|
||||
>
|
||||
<Select options={allOptions[LlmModelType.Embedding]} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="Img2txt model"
|
||||
label={t('img2txtModel')}
|
||||
name="img2txt_id"
|
||||
tooltip="The default multi-module model all the newly created knowledgebase will use. It can describe a picture or video."
|
||||
tooltip={t('img2txtModelTip')}
|
||||
>
|
||||
<Select options={allOptions[LlmModelType.Image2text]} />
|
||||
</Form.Item>
|
||||
|
||||
|
||||
<Form.Item
|
||||
label="Sequence2txt model"
|
||||
label={t('sequence2txtModel')}
|
||||
name="asr_id"
|
||||
tooltip="The default ASR model all the newly created knowledgebase will use. Use this model to translate voices to corresponding text."
|
||||
tooltip={t('sequence2txtModelTip')}
|
||||
>
|
||||
<Select options={allOptions[LlmModelType.Speech2text]} />
|
||||
</Form.Item>
|
||||
|
||||
@ -5,6 +5,7 @@ import { Button, Divider, Form, Input, Space } from 'antd';
|
||||
import SettingTitle from '../components/setting-title';
|
||||
import { useValidateSubmittable } from '../hooks';
|
||||
|
||||
import { useTranslate } from '@/hooks/commonHooks';
|
||||
import parentStyles from '../index.less';
|
||||
import styles from './index.less';
|
||||
|
||||
@ -22,6 +23,7 @@ const UserSettingPassword = () => {
|
||||
const loading = useOneNamespaceEffectsLoading('settingModel', ['setting']);
|
||||
const { form, submittable } = useValidateSubmittable();
|
||||
const saveSetting = useSaveSetting();
|
||||
const { t } = useTranslate('setting');
|
||||
|
||||
const onFinish = (values: any) => {
|
||||
const password = rsaPsw(values.password) as string;
|
||||
@ -37,8 +39,8 @@ const UserSettingPassword = () => {
|
||||
return (
|
||||
<section className={styles.passwordWrapper}>
|
||||
<SettingTitle
|
||||
title="Password"
|
||||
description="Please enter your current password to change your password."
|
||||
title={t('password')}
|
||||
description={t('passwordDescription')}
|
||||
></SettingTitle>
|
||||
<Divider />
|
||||
<Form
|
||||
@ -56,12 +58,12 @@ const UserSettingPassword = () => {
|
||||
// requiredMark={'optional'}
|
||||
>
|
||||
<Form.Item<FieldType>
|
||||
label="Current password"
|
||||
label={t('currentPassword')}
|
||||
name="password"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: 'Please input your password!',
|
||||
message: t('currentPasswordMessage'),
|
||||
whitespace: true,
|
||||
},
|
||||
]}
|
||||
@ -69,14 +71,14 @@ const UserSettingPassword = () => {
|
||||
<Input.Password />
|
||||
</Form.Item>
|
||||
<Divider />
|
||||
<Form.Item label="New password" required>
|
||||
<Form.Item label={t('newPassword')} required>
|
||||
<Form.Item<FieldType>
|
||||
noStyle
|
||||
name="new_password"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: 'Please input your password!',
|
||||
message: t('newPasswordMessage'),
|
||||
whitespace: true,
|
||||
},
|
||||
]}
|
||||
@ -84,18 +86,18 @@ const UserSettingPassword = () => {
|
||||
<Input.Password />
|
||||
</Form.Item>
|
||||
<p className={parentStyles.itemDescription}>
|
||||
Your new password must be more than 8 characters.
|
||||
{t('newPasswordDescription')}
|
||||
</p>
|
||||
</Form.Item>
|
||||
<Divider />
|
||||
<Form.Item<FieldType>
|
||||
label="Confirm new password"
|
||||
label={t('confirmPassword')}
|
||||
name="confirm_password"
|
||||
dependencies={['new_password']}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: 'Please confirm your password!',
|
||||
message: t('confirmPasswordMessage'),
|
||||
whitespace: true,
|
||||
},
|
||||
({ getFieldValue }) => ({
|
||||
@ -104,7 +106,7 @@ const UserSettingPassword = () => {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.reject(
|
||||
new Error('The new password that you entered do not match!'),
|
||||
new Error(t('confirmPasswordNonMatchMessage')),
|
||||
);
|
||||
},
|
||||
}),
|
||||
@ -120,14 +122,14 @@ const UserSettingPassword = () => {
|
||||
}
|
||||
>
|
||||
<Space>
|
||||
<Button htmlType="button">Cancel</Button>
|
||||
<Button htmlType="button">{t('cancel')}</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
htmlType="submit"
|
||||
disabled={!submittable}
|
||||
loading={loading}
|
||||
>
|
||||
Save
|
||||
{t('save', { keyPrefix: 'common' })}
|
||||
</Button>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
|
||||
@ -29,6 +29,8 @@ import {
|
||||
useValidateSubmittable,
|
||||
} from '../hooks';
|
||||
|
||||
import { useTranslate } from '@/hooks/commonHooks';
|
||||
import { useChangeLanguage } from '@/hooks/logicHooks';
|
||||
import parentStyles from '../index.less';
|
||||
import styles from './index.less';
|
||||
|
||||
@ -54,6 +56,8 @@ const UserSettingProfile = () => {
|
||||
const { form, submittable } = useValidateSubmittable();
|
||||
const loading = useSelectUserInfoLoading();
|
||||
useFetchUserInfo();
|
||||
const { t } = useTranslate('setting');
|
||||
const changeLanguage = useChangeLanguage();
|
||||
|
||||
const onFinish = async (values: any) => {
|
||||
const avatar = await getBase64FromUploadFileList(values.avatar);
|
||||
@ -72,8 +76,8 @@ const UserSettingProfile = () => {
|
||||
return (
|
||||
<section className={styles.profileWrapper}>
|
||||
<SettingTitle
|
||||
title="Profile"
|
||||
description="Update your photo and personal details here."
|
||||
title={t('profile')}
|
||||
description={t('profileDescription')}
|
||||
></SettingTitle>
|
||||
<Divider />
|
||||
<Spin spinning={loading}>
|
||||
@ -91,12 +95,12 @@ const UserSettingProfile = () => {
|
||||
autoComplete="off"
|
||||
>
|
||||
<Form.Item<FieldType>
|
||||
label="Username"
|
||||
label={t('username')}
|
||||
name="nickname"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: 'Please input your username!',
|
||||
message: t('usernameMessage'),
|
||||
whitespace: true,
|
||||
},
|
||||
]}
|
||||
@ -107,8 +111,8 @@ const UserSettingProfile = () => {
|
||||
<Form.Item<FieldType>
|
||||
label={
|
||||
<div>
|
||||
<Space>Your photo</Space>
|
||||
<div>This will be displayed on your profile.</div>
|
||||
<Space>{t('photo')}</Space>
|
||||
<div>{t('photoDescription')}</div>
|
||||
</div>
|
||||
}
|
||||
name="avatar"
|
||||
@ -126,41 +130,53 @@ const UserSettingProfile = () => {
|
||||
>
|
||||
<button style={{ border: 0, background: 'none' }} type="button">
|
||||
<PlusOutlined />
|
||||
<div style={{ marginTop: 8 }}>Upload</div>
|
||||
<div style={{ marginTop: 8 }}>
|
||||
{t('upload', { keyPrefix: 'common' })}
|
||||
</div>
|
||||
</button>
|
||||
</Upload>
|
||||
</Form.Item>
|
||||
<Divider />
|
||||
<Form.Item<FieldType>
|
||||
label="Color schema"
|
||||
label={t('colorSchema')}
|
||||
name="color_schema"
|
||||
rules={[{ required: true, message: t('colorSchemaMessage') }]}
|
||||
>
|
||||
<Select placeholder={t('colorSchemaPlaceholder')}>
|
||||
<Option value="Bright">{t('bright')}</Option>
|
||||
<Option value="Dark">{t('dark')}</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Divider />
|
||||
<Form.Item<FieldType>
|
||||
label={t('language', { keyPrefix: 'common' })}
|
||||
name="language"
|
||||
rules={[
|
||||
{ required: true, message: 'Please select your color schema!' },
|
||||
{
|
||||
required: true,
|
||||
message: t('languageMessage', { keyPrefix: 'common' }),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Select placeholder="select your color schema">
|
||||
<Option value="Bright">Bright</Option>
|
||||
<Option value="Dark">Dark</Option>
|
||||
<Select
|
||||
placeholder={t('languagePlaceholder', { keyPrefix: 'common' })}
|
||||
onChange={changeLanguage}
|
||||
>
|
||||
<Option value="English">
|
||||
{t('english', { keyPrefix: 'common' })}
|
||||
</Option>
|
||||
<Option value="Chinese">
|
||||
{t('chinese', { keyPrefix: 'common' })}
|
||||
</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Divider />
|
||||
<Form.Item<FieldType>
|
||||
label="Language"
|
||||
name="language"
|
||||
rules={[{ required: true, message: 'Please input your language!' }]}
|
||||
>
|
||||
<Select placeholder="select your language">
|
||||
<Option value="English">English</Option>
|
||||
<Option value="Chinese">Chinese</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Divider />
|
||||
<Form.Item<FieldType>
|
||||
label="Timezone"
|
||||
label={t('timezone')}
|
||||
name="timezone"
|
||||
rules={[{ required: true, message: 'Please input your timezone!' }]}
|
||||
rules={[{ required: true, message: t('timezoneMessage') }]}
|
||||
>
|
||||
<Select placeholder="select your timezone" showSearch>
|
||||
<Select placeholder={t('timezonePlaceholder')} showSearch>
|
||||
{TimezoneList.map((x) => (
|
||||
<Option value={x} key={x}>
|
||||
{x}
|
||||
@ -169,12 +185,12 @@ const UserSettingProfile = () => {
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Divider />
|
||||
<Form.Item label="Email address">
|
||||
<Form.Item label={t('email')}>
|
||||
<Form.Item<FieldType> name="email" noStyle>
|
||||
<Input disabled />
|
||||
</Form.Item>
|
||||
<p className={parentStyles.itemDescription}>
|
||||
Once registered, E-mail cannot be changed.
|
||||
{t('emailDescription')}
|
||||
</p>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
@ -184,14 +200,14 @@ const UserSettingProfile = () => {
|
||||
}
|
||||
>
|
||||
<Space>
|
||||
<Button htmlType="button">Cancel</Button>
|
||||
<Button htmlType="button">{t('cancel')}</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
htmlType="submit"
|
||||
disabled={!submittable}
|
||||
loading={submitLoading}
|
||||
>
|
||||
Save
|
||||
{t('save', { keyPrefix: 'common' })}
|
||||
</Button>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
|
||||
@ -1,17 +1,21 @@
|
||||
import { Button, Card, Flex } from 'antd';
|
||||
|
||||
import { useTranslate } from '@/hooks/commonHooks';
|
||||
import { useSelectUserInfo } from '@/hooks/userSettingHook';
|
||||
import styles from './index.less';
|
||||
|
||||
const UserSettingTeam = () => {
|
||||
const userInfo = useSelectUserInfo();
|
||||
const { t } = useTranslate('setting');
|
||||
|
||||
return (
|
||||
<div className={styles.teamWrapper}>
|
||||
<Card className={styles.teamCard}>
|
||||
<Flex align="center" justify={'space-between'}>
|
||||
<span>{userInfo.nickname} Workspace</span>
|
||||
<Button type="primary">Upgrade</Button>
|
||||
<span>
|
||||
{userInfo.nickname} {t('workspace')}
|
||||
</span>
|
||||
<Button type="primary">{t('upgrade')}</Button>
|
||||
</Flex>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
@ -7,38 +7,39 @@ import {
|
||||
UserSettingBaseKey,
|
||||
UserSettingIconMap,
|
||||
UserSettingRouteKey,
|
||||
UserSettingRouteMap,
|
||||
} from '../constants';
|
||||
|
||||
import { useTranslate } from '@/hooks/commonHooks';
|
||||
import { useLogout } from '@/hooks/userSettingHook';
|
||||
import styles from './index.less';
|
||||
|
||||
type MenuItem = Required<MenuProps>['items'][number];
|
||||
|
||||
function getItem(
|
||||
label: React.ReactNode,
|
||||
key: React.Key,
|
||||
icon?: React.ReactNode,
|
||||
children?: MenuItem[],
|
||||
type?: 'group',
|
||||
): MenuItem {
|
||||
return {
|
||||
key,
|
||||
icon,
|
||||
children,
|
||||
label,
|
||||
type,
|
||||
} as MenuItem;
|
||||
}
|
||||
|
||||
const items: MenuItem[] = Object.values(UserSettingRouteKey).map((value) =>
|
||||
getItem(UserSettingRouteMap[value], value, UserSettingIconMap[value]),
|
||||
);
|
||||
|
||||
const SideBar = () => {
|
||||
const navigate = useNavigate();
|
||||
const pathName = useSecondPathName();
|
||||
const logout = useLogout();
|
||||
const { t } = useTranslate('setting');
|
||||
|
||||
function getItem(
|
||||
label: string,
|
||||
key: React.Key,
|
||||
icon?: React.ReactNode,
|
||||
children?: MenuItem[],
|
||||
type?: 'group',
|
||||
): MenuItem {
|
||||
return {
|
||||
key,
|
||||
icon,
|
||||
children,
|
||||
label: t(label),
|
||||
type,
|
||||
} as MenuItem;
|
||||
}
|
||||
|
||||
const items: MenuItem[] = Object.values(UserSettingRouteKey).map((value) =>
|
||||
getItem(value, value, UserSettingIconMap[value]),
|
||||
);
|
||||
|
||||
const handleMenuClick: MenuProps['onClick'] = ({ key }) => {
|
||||
if (key === UserSettingRouteKey.Logout) {
|
||||
|
||||
Reference in New Issue
Block a user