From 1294aabbcc6260c5b3fe1a2a253371c75e8aa43b Mon Sep 17 00:00:00 2001 From: zhaoying Date: Tue, 14 Apr 2026 16:38:59 +0800 Subject: [PATCH 1/2] feat(web): update document title --- web/src/App.tsx | 55 ++++++++++++++++++++-- web/src/hooks/useBreadcrumbManager.ts | 10 ++-- web/src/routes/routes.json | 1 - web/src/store/menu.json | 15 +++--- web/src/views/ApplicationConfig/index.tsx | 11 ++++- web/src/views/MemoryManagement/index.tsx | 7 +-- web/src/views/Ontology/pages/Detail.tsx | 6 ++- web/src/views/Skills/pages/SkillConfig.tsx | 3 +- web/src/views/UserMemoryDetail/Neo4j.tsx | 17 ++++--- web/src/views/UserMemoryDetail/Rag.tsx | 6 ++- 10 files changed, 101 insertions(+), 30 deletions(-) diff --git a/web/src/App.tsx b/web/src/App.tsx index a10f9409..1af38372 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -16,7 +16,7 @@ import { ConfigProvider, App as AntdApp } from 'antd'; -import { useTranslation } from 'react-i18next'; +import i18n from 'i18next'; import { lightTheme } from './styles/antdThemeConfig.ts' import router from './routes'; @@ -29,11 +29,58 @@ import 'dayjs/plugin/utc' import { cookieUtils } from './utils/request'; import { useUser } from '@/store/user'; +import menuJson from '@/store/menu.json'; + +type MenuEntry = { path: string; i18nKey: string }; + +function flattenMenuEntries(list: any[]): MenuEntry[] { + const result: MenuEntry[] = []; + for (const item of list) { + if (item.path && item.i18nKey && item.type !== 'group') result.push({ path: item.path, i18nKey: item.i18nKey }); + if (item.subs?.length) result.push(...flattenMenuEntries(item.subs)); + } + return result; +} + +const menuEntries: MenuEntry[] = flattenMenuEntries([...menuJson.manage, ...menuJson.space]); + +function pathMatches(pattern: string, path: string): boolean { + if (pattern === path) return true; + if (pattern.includes(':')) { + return new RegExp('^' + pattern.replace(/:[\w-]+/g, '[^/]+') + '$').test(path); + } + return false; +} + +function getPageTitle(pathname: string): string { + const appName = i18n.t('memoryBear'); + const entry = menuEntries.find(e => pathMatches(e.path, pathname)); + if (!entry) return appName; + return `${i18n.t(entry.i18nKey)} - ${appName}`; +} + +const SKIP_TITLE_PATTERNS = [ + '/user-memory/detail/:id/:type', + '/forgetting-engine/:id', + '/memory-extraction-engine/:id', + '/emotion-engine/:id', + '/reflection-engine/:id', +]; + + + function App() { - const { t } = useTranslation(); const { locale, language, timeZone } = useI18n() const { checkJump } = useUser(); + useEffect(() => { + const unsubscribe = router.subscribe(({ location }) => { + if (SKIP_TITLE_PATTERNS.some(p => pathMatches(p, location.pathname))) return; + document.title = getPageTitle(location.pathname); + }); + return () => unsubscribe(); + }, []) + useEffect(() => { const authToken = cookieUtils.get('authToken') if (!authToken && !window.location.hash.includes('#/login') && !window.location.hash.includes('#/conversation/') && !window.location.hash.includes('#/jump') && !window.location.hash.includes('#/invite-register')) { @@ -44,7 +91,9 @@ function App() { }, []) useEffect(() => { - document.title = t('memoryBear') + if (!SKIP_TITLE_PATTERNS.some(p => pathMatches(p, router.state.location.pathname))) { + document.title = getPageTitle(router.state.location.pathname) + } dayjs.locale(language) localStorage.setItem('language', language) }, [language]) diff --git a/web/src/hooks/useBreadcrumbManager.ts b/web/src/hooks/useBreadcrumbManager.ts index 161fbb65..1b7cf4b2 100644 --- a/web/src/hooks/useBreadcrumbManager.ts +++ b/web/src/hooks/useBreadcrumbManager.ts @@ -1,8 +1,8 @@ /* * @Author: ZhaoYing * @Date: 2026-02-02 16:24:44 - * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-02-02 16:24:44 + * @Last Modified by: ZhaoYing + * @Last Modified time: 2026-04-14 15:52:57 */ /** * useBreadcrumbManager Hook @@ -18,6 +18,7 @@ import { useCallback } from 'react'; import { useNavigate } from 'react-router-dom'; +import { useTranslation } from 'react-i18next' import { useMenu } from '@/store/menu'; import type { MenuItem } from '@/store/menu'; @@ -53,6 +54,7 @@ export interface BreadcrumbOptions { export const useBreadcrumbManager = (options?: BreadcrumbOptions) => { const { allBreadcrumbs, setCustomBreadcrumbs } = useMenu(); const navigate = useNavigate(); + const { t } = useTranslation() /** Update breadcrumbs based on current path and type */ const updateBreadcrumbs = useCallback((breadcrumbPath: BreadcrumbPath) => { @@ -336,8 +338,8 @@ export const useBreadcrumbManager = (options?: BreadcrumbOptions) => { /** Use different keys based on breadcrumb type to implement independent breadcrumb paths */ const breadcrumbKey = breadcrumbType === 'list' ? 'space' : 'space-detail'; - - + const lastMenu = customBreadcrumbs[customBreadcrumbs.length - 1] + document.title = `${lastMenu.i18nKey ? t(lastMenu.i18nKey) : lastMenu.label} - ${t('memoryBear') }`; setCustomBreadcrumbs(customBreadcrumbs, breadcrumbKey); }, [setCustomBreadcrumbs, navigate, options?.breadcrumbType, options?.onKnowledgeBaseMenuClick, options?.onKnowledgeBaseFolderClick]); diff --git a/web/src/routes/routes.json b/web/src/routes/routes.json index 5ff1f90c..f6dc631d 100644 --- a/web/src/routes/routes.json +++ b/web/src/routes/routes.json @@ -48,7 +48,6 @@ { "path": "/application/config/:id", "element": "ApplicationConfig" }, { "path": "/application/config/:id/:source", "element": "ApplicationConfig" }, { "path": "/user-memory/neo4j/:id", "element": "Neo4jUserMemoryDetail" }, - { "path": "/statement/:id", "element": "StatementDetail" }, { "path": "/user-memory/detail/:id/:type", "element": "MemoryNodeDetail" }, { "path": "/ontology/:id", "element": "OntologyDetail" } ] diff --git a/web/src/store/menu.json b/web/src/store/menu.json index 8d30dcc4..ec80a384 100644 --- a/web/src/store/menu.json +++ b/web/src/store/menu.json @@ -6,7 +6,7 @@ "code": "workbench", "label": "workbench", "i18nKey": "menu.workbench", - "path": "/", + "path": null, "enable": true, "display": true, "level": 1, @@ -174,7 +174,7 @@ "code": "workbench", "label": "workbench", "i18nKey": "menu.workbench", - "path": "/", + "path": null, "enable": true, "display": true, "level": 1, @@ -425,15 +425,14 @@ { "id": 2211, "parent": 221, - "code": "statementDetail", + "code": "userMemoryDetail", "label": "记忆详情", - "i18nKey": "menu.statementDetail", - "path": "/statement/:id", + "i18nKey": "menu.userMemoryDetail", + "path": "/user-memory/detail/:id/:type", "enable": true, "display": false, - "level": 4, - "sort": 0, - "subs": null + "level": 3, + "sort": 0 } ] }, diff --git a/web/src/views/ApplicationConfig/index.tsx b/web/src/views/ApplicationConfig/index.tsx index a9e1df5d..fa6f9939 100644 --- a/web/src/views/ApplicationConfig/index.tsx +++ b/web/src/views/ApplicationConfig/index.tsx @@ -2,11 +2,12 @@ * @Author: ZhaoYing * @Date: 2026-02-03 16:29:37 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-26 15:37:18 + * @Last Modified time: 2026-04-14 10:01:05 */ import React, { useEffect, useState, useRef } from 'react'; import { useParams } from 'react-router-dom'; import { Flex } from 'antd' +import { useTranslation } from 'react-i18next' import ConfigHeader from './components/ConfigHeader' import type { AgentRef, ClusterRef, WorkflowRef, Config } from './types' @@ -30,6 +31,7 @@ import Logs from './Logs'; const ApplicationConfig: React.FC = () => { // Hooks const { id, source } = useParams(); + const { t } = useTranslation() // Refs for different application types const agentRef = useRef(null) @@ -95,6 +97,13 @@ const ApplicationConfig: React.FC = () => { getApplicationInfo() }, [id]) + useEffect(() => { + if (application?.name) { + const appName = t('memoryBear'); + document.title = `${application.name} - ${appName}`; + } + }, [application?.name]) + /** * Fetch application information */ diff --git a/web/src/views/MemoryManagement/index.tsx b/web/src/views/MemoryManagement/index.tsx index 1fb945b0..5bbbb8bd 100644 --- a/web/src/views/MemoryManagement/index.tsx +++ b/web/src/views/MemoryManagement/index.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 17:33:15 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-26 14:56:00 + * @Last Modified time: 2026-04-14 16:17:29 */ /** * Memory Management Page @@ -74,7 +74,8 @@ const MemoryManagement: React.FC = () => { }; /** Navigate to engine configuration page */ - const handleClick = (id: number, type: string) => { + const handleClick = (id: number, type: string, config_name: string) => { + document.title = `${config_name} - ${t('memoryBear')}`; switch (type) { case 'memoryExtractionEngine': navigate(`/memory-extraction-engine/${id}`) @@ -130,7 +131,7 @@ const MemoryManagement: React.FC = () => { align="center" justify="space-between" className="rb:cursor-pointer rb:bg-[#F6F6F6] rb:h-8 rb:rounded-lg rb:font-medium rb:leading-5 rb:pl-2! rb:pr-1! rb:hover:shadow-[0px_2px_8px_0px_rgba(23,23,25,0.16)]" - onClick={() => handleClick(item.config_id, key)} + onClick={() => handleClick(item.config_id, key, item.config_name)} > {t(`memory.${key}`)}
{ getData() }, [id, query]) + useEffect(() => { + document.title = `${data.scene_name} - ${t('memoryBear')}`; + }, [data.scene_name]) + /** * Fetch ontology class list data */ diff --git a/web/src/views/Skills/pages/SkillConfig.tsx b/web/src/views/Skills/pages/SkillConfig.tsx index 84c82378..91cd710a 100644 --- a/web/src/views/Skills/pages/SkillConfig.tsx +++ b/web/src/views/Skills/pages/SkillConfig.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-05 10:44:08 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-02-05 10:56:28 + * @Last Modified time: 2026-04-14 16:27:08 */ import { type FC, useEffect, useRef, useState } from "react"; import { useTranslation } from 'react-i18next'; @@ -71,6 +71,7 @@ const SkillConfig: FC = () => { .then(res => { form.setFieldsValue(res as SkillFormData) setData(res as SkillFormData) + document.title = `${(res as SkillFormData).name} - ${t('memoryBear')}`; }) .finally(() => { setLoading(false) diff --git a/web/src/views/UserMemoryDetail/Neo4j.tsx b/web/src/views/UserMemoryDetail/Neo4j.tsx index 51be7c8d..67ddc065 100644 --- a/web/src/views/UserMemoryDetail/Neo4j.tsx +++ b/web/src/views/UserMemoryDetail/Neo4j.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 17:57:26 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-26 18:59:53 + * @Last Modified time: 2026-04-14 16:38:21 */ /** * Neo4j User Memory Detail View @@ -22,7 +22,7 @@ import InterestDistribution from './components/InterestDistribution' import NodeStatistics from './components/NodeStatistics' import RelationshipNetwork from './components/RelationshipNetwork' import MemoryInsight from './components/MemoryInsight' -import type { EndUserProfileRef, MemoryInsightRef, AboutMeRef } from './types' +import type { EndUserProfileRef, MemoryInsightRef, AboutMeRef, EndUser } from './types' import { analyticsRefresh, } from '@/api/memory' @@ -39,8 +39,11 @@ const Neo4j: FC = () => { const [selectedKey, setSelectedKey] = useState(null) /** Update displayed name */ - const handleNameUpdate = (data: { other_name?: string; id: string }) => { - setName(data.other_name && data.other_name !== '' ? data.other_name : data.id) + const handleNameUpdate = (data?: EndUser) => { + if (!data) return + let name = data.other_name && data.other_name !== '' ? data.other_name : data.id || data.end_user_id + setName(name) + document.title = `${name} - ${t('memoryBear')}`; } /** Navigate back */ @@ -78,7 +81,7 @@ const Neo4j: FC = () => { - {
- {
- + diff --git a/web/src/views/UserMemoryDetail/Rag.tsx b/web/src/views/UserMemoryDetail/Rag.tsx index ff9069c7..a1da95d4 100644 --- a/web/src/views/UserMemoryDetail/Rag.tsx +++ b/web/src/views/UserMemoryDetail/Rag.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 17:57:11 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-31 15:29:45 + * @Last Modified time: 2026-04-14 15:56:15 */ /** * RAG User Memory Detail View @@ -97,6 +97,10 @@ const Rag: FC = () => { } const name = loading.detail ? '' : data?.name && data?.name !== '' ? data.name : id + useEffect(() => { + document.title = `${name} - ${t('memoryBear')}`; + }, [name]) + const [refreshLoading, setRefreshLoading] = useState(false) const handleRefresh = () => { if (refreshLoading || !id) return From 5e6490213d6b6b72624f6a986e3c7012d2d0b7fc Mon Sep 17 00:00:00 2001 From: zhaoying Date: Tue, 14 Apr 2026 17:03:22 +0800 Subject: [PATCH 2/2] fix(web): document title support i18n --- web/src/hooks/useBreadcrumbManager.ts | 6 ++++-- web/src/views/ApplicationConfig/index.tsx | 6 ++++-- web/src/views/EmotionEngine/index.tsx | 8 +++++++- web/src/views/ForgettingEngine/index.tsx | 9 ++++++++- .../views/MemoryExtractionEngine/components/Result.tsx | 1 + web/src/views/MemoryExtractionEngine/index.tsx | 8 +++++++- web/src/views/Ontology/pages/Detail.tsx | 6 ++++-- web/src/views/SelfReflectionEngine/index.tsx | 7 ++++++- web/src/views/Skills/pages/SkillConfig.tsx | 10 ++++++++-- web/src/views/UserMemoryDetail/Neo4j.tsx | 10 +++++++--- web/src/views/UserMemoryDetail/Rag.tsx | 6 ++++-- 11 files changed, 60 insertions(+), 17 deletions(-) diff --git a/web/src/hooks/useBreadcrumbManager.ts b/web/src/hooks/useBreadcrumbManager.ts index 1b7cf4b2..e2567cfd 100644 --- a/web/src/hooks/useBreadcrumbManager.ts +++ b/web/src/hooks/useBreadcrumbManager.ts @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-02 16:24:44 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-04-14 15:52:57 + * @Last Modified time: 2026-04-14 16:52:43 */ /** * useBreadcrumbManager Hook @@ -21,6 +21,7 @@ import { useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next' import { useMenu } from '@/store/menu'; import type { MenuItem } from '@/store/menu'; +import { useI18n } from '@/store/locale' /** Breadcrumb item interface */ export interface BreadcrumbItem { @@ -55,6 +56,7 @@ export const useBreadcrumbManager = (options?: BreadcrumbOptions) => { const { allBreadcrumbs, setCustomBreadcrumbs } = useMenu(); const navigate = useNavigate(); const { t } = useTranslation() + const { language } = useI18n() /** Update breadcrumbs based on current path and type */ const updateBreadcrumbs = useCallback((breadcrumbPath: BreadcrumbPath) => { @@ -341,7 +343,7 @@ export const useBreadcrumbManager = (options?: BreadcrumbOptions) => { const lastMenu = customBreadcrumbs[customBreadcrumbs.length - 1] document.title = `${lastMenu.i18nKey ? t(lastMenu.i18nKey) : lastMenu.label} - ${t('memoryBear') }`; setCustomBreadcrumbs(customBreadcrumbs, breadcrumbKey); - }, [setCustomBreadcrumbs, navigate, options?.breadcrumbType, options?.onKnowledgeBaseMenuClick, options?.onKnowledgeBaseFolderClick]); + }, [setCustomBreadcrumbs, navigate, options?.breadcrumbType, options?.onKnowledgeBaseMenuClick, options?.onKnowledgeBaseFolderClick, language]); return { updateBreadcrumbs, diff --git a/web/src/views/ApplicationConfig/index.tsx b/web/src/views/ApplicationConfig/index.tsx index fa6f9939..5b9bcb85 100644 --- a/web/src/views/ApplicationConfig/index.tsx +++ b/web/src/views/ApplicationConfig/index.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 16:29:37 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-04-14 10:01:05 + * @Last Modified time: 2026-04-14 16:53:27 */ import React, { useEffect, useState, useRef } from 'react'; import { useParams } from 'react-router-dom'; @@ -22,6 +22,7 @@ import Statistics from './Statistics' import TestChat from './TestChat' import type { WorkflowConfig } from '@/views/Workflow/types'; import Logs from './Logs'; +import { useI18n } from '@/store/locale' /** * Application configuration page component @@ -32,6 +33,7 @@ const ApplicationConfig: React.FC = () => { // Hooks const { id, source } = useParams(); const { t } = useTranslation() + const { language } = useI18n() // Refs for different application types const agentRef = useRef(null) @@ -102,7 +104,7 @@ const ApplicationConfig: React.FC = () => { const appName = t('memoryBear'); document.title = `${application.name} - ${appName}`; } - }, [application?.name]) + }, [application?.name, language]) /** * Fetch application information diff --git a/web/src/views/EmotionEngine/index.tsx b/web/src/views/EmotionEngine/index.tsx index 8c0188da..28933c32 100644 --- a/web/src/views/EmotionEngine/index.tsx +++ b/web/src/views/EmotionEngine/index.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 16:56:54 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-26 15:43:29 + * @Last Modified time: 2026-04-14 16:59:16 */ /** * Emotion Engine Configuration Page @@ -25,6 +25,7 @@ import DescWrapper from '@/components/FormItem/DescWrapper' import RbSlider from '@/components/RbSlider'; import RbAlert from '@/components/RbAlert'; import ModelSelect from '@/components/ModelSelect'; +import { useI18n } from '@/store/locale' /** * Configuration field definitions @@ -69,9 +70,14 @@ const EmotionEngine: React.FC = () => { const [form] = Form.useForm(); const { message: messageApi } = App.useApp(); const [loading, setLoading] = useState(false) + const { language } = useI18n() const values = Form.useWatch([], form); + useEffect(() => { + document.title = [document.title.split(' - ')[0], t('memoryBear')].join(' - ') + }, [language]) + useEffect(() => { getConfigData() }, [id]) diff --git a/web/src/views/ForgettingEngine/index.tsx b/web/src/views/ForgettingEngine/index.tsx index 0b15867e..bcd7dbc1 100644 --- a/web/src/views/ForgettingEngine/index.tsx +++ b/web/src/views/ForgettingEngine/index.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 17:00:12 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-26 15:47:37 + * @Last Modified time: 2026-04-14 16:54:38 */ /** * Forgetting Engine Configuration Page @@ -22,6 +22,7 @@ import type { ConfigForm } from './types' import SwitchFormItem from '@/components/FormItem/SwitchFormItem' import RbSlider from '@/components/RbSlider'; import DescWrapper from '@/components/FormItem/DescWrapper' +import { useI18n } from '@/store/locale' /** * Configuration field definitions @@ -109,9 +110,14 @@ const ForgettingEngine: React.FC = () => { const [form] = Form.useForm(); const { message: messageApi } = App.useApp(); const [loading, setLoading] = useState(false) + const { language } = useI18n() const values = Form.useWatch([], form); + useEffect(() => { + document.title = [document.title.split(' - ')[0], t('memoryBear')].join(' - ') + }, [language]) + useEffect(() => { getConfigData() }, []) @@ -182,6 +188,7 @@ const ForgettingEngine: React.FC = () => { if (config.type === 'button') { return ( {t(`forgettingEngine.type`)}: {config.type}} diff --git a/web/src/views/MemoryExtractionEngine/components/Result.tsx b/web/src/views/MemoryExtractionEngine/components/Result.tsx index 4d07aae9..2fa8788f 100644 --- a/web/src/views/MemoryExtractionEngine/components/Result.tsx +++ b/web/src/views/MemoryExtractionEngine/components/Result.tsx @@ -328,6 +328,7 @@ const Result: FC = ({ loading, handleSave }) => { {['processData', 'finalResult'].map(tab => (
{ const { t } = useTranslation(); const { message } = App.useApp(); const { id } = useParams() + const { language } = useI18n() const [expandedKeys, setExpandedKeys] = useState(keys) const [form] = Form.useForm() const values = Form.useWatch([], form) const [loading, setLoading] = useState(false) const [iterationPeriodDisabled, setIterationPeriodDisabled] = useState(false) + useEffect(() => { + document.title = [document.title.split(' - ')[0], t('memoryBear')].join(' - ') + }, [language]) + useEffect(() => { if (values?.reflexion_range === 'database') { form.setFieldValue('iteration_period', 24) diff --git a/web/src/views/Ontology/pages/Detail.tsx b/web/src/views/Ontology/pages/Detail.tsx index 80ce3a0f..b6ee5953 100644 --- a/web/src/views/Ontology/pages/Detail.tsx +++ b/web/src/views/Ontology/pages/Detail.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 14:10:20 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-04-14 15:54:05 + * @Last Modified time: 2026-04-14 16:55:26 */ import { type FC, useEffect, useState, useRef } from 'react' import { useParams, useNavigate } from 'react-router-dom'; @@ -18,6 +18,7 @@ import SearchInput from '@/components/SearchInput'; import OntologyClassExtractModal from '../components/OntologyClassExtractModal' import BodyWrapper from '@/components/Empty/BodyWrapper' import Tag from '@/components/Tag' +import { useI18n } from '@/store/locale' /** * Ontology detail page component @@ -29,6 +30,7 @@ const Detail: FC = () => { const navigate = useNavigate() const { id } = useParams() const { modal, message } = App.useApp() + const { language } = useI18n() // Refs const ontologyClassModalRef = useRef(null) @@ -48,7 +50,7 @@ const Detail: FC = () => { useEffect(() => { document.title = `${data.scene_name} - ${t('memoryBear')}`; - }, [data.scene_name]) + }, [data.scene_name, language]) /** * Fetch ontology class list data diff --git a/web/src/views/SelfReflectionEngine/index.tsx b/web/src/views/SelfReflectionEngine/index.tsx index bd1470c1..ef5e412c 100644 --- a/web/src/views/SelfReflectionEngine/index.tsx +++ b/web/src/views/SelfReflectionEngine/index.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 17:46:47 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-26 18:57:08 + * @Last Modified time: 2026-04-14 16:59:56 */ /** * Self Reflection Engine Configuration Page @@ -99,6 +99,10 @@ const SelfReflectionEngine: React.FC = () => { const values = Form.useWatch([], form); + useEffect(() => { + document.title = [document.title.split(' - ')[0], t('memoryBear')].join(' - ') + }, [language]) + useEffect(() => { getConfigData() }, [id]) @@ -242,6 +246,7 @@ const SelfReflectionEngine: React.FC = () => { return ( diff --git a/web/src/views/Skills/pages/SkillConfig.tsx b/web/src/views/Skills/pages/SkillConfig.tsx index 91cd710a..440356fd 100644 --- a/web/src/views/Skills/pages/SkillConfig.tsx +++ b/web/src/views/Skills/pages/SkillConfig.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-05 10:44:08 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-04-14 16:27:08 + * @Last Modified time: 2026-04-14 16:57:52 */ import { type FC, useEffect, useRef, useState } from "react"; import { useTranslation } from 'react-i18next'; @@ -17,6 +17,7 @@ import type { SkillFormData } from '../types' import { getSkillDetail, createSkill, updateSkill } from '@/api/skill' import { stringRegExp } from '@/utils/validator'; import PageHeader from '@/components/Layout/PageHeader' +import { useI18n } from '@/store/locale' /** * Skill Configuration Page Component @@ -43,6 +44,7 @@ const SkillConfig: FC = () => { const [loading, setLoading] = useState(false) const [form] = Form.useForm(); const [data, setData] = useState(null) + const { language } = useI18n() /** * Effect: Load skill data if editing existing skill @@ -71,12 +73,16 @@ const SkillConfig: FC = () => { .then(res => { form.setFieldsValue(res as SkillFormData) setData(res as SkillFormData) - document.title = `${(res as SkillFormData).name} - ${t('memoryBear')}`; }) .finally(() => { setLoading(false) }) } + + useEffect(() => { + if (!data) return; + document.title = `${data?.name} - ${t('memoryBear')}`; + }, [language, data?.name]) const aiPromptModalRef = useRef(null) diff --git a/web/src/views/UserMemoryDetail/Neo4j.tsx b/web/src/views/UserMemoryDetail/Neo4j.tsx index 67ddc065..4de310b3 100644 --- a/web/src/views/UserMemoryDetail/Neo4j.tsx +++ b/web/src/views/UserMemoryDetail/Neo4j.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 17:57:26 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-04-14 16:38:21 + * @Last Modified time: 2026-04-14 16:57:59 */ /** * Neo4j User Memory Detail View @@ -10,7 +10,7 @@ * Shows profile, interests, node statistics, relationships, and insights */ -import { type FC, useRef, useState, type MouseEvent } from 'react' +import { type FC, useRef, useState, type MouseEvent, useEffect } from 'react' import clsx from 'clsx' import { useParams, useNavigate } from 'react-router-dom' import { Flex, Popover } from 'antd' @@ -26,6 +26,7 @@ import type { EndUserProfileRef, MemoryInsightRef, AboutMeRef, EndUser } from '. import { analyticsRefresh, } from '@/api/memory' +import { useI18n } from '@/store/locale' const Neo4j: FC = () => { const { id } = useParams() @@ -33,6 +34,7 @@ const Neo4j: FC = () => { const navigate = useNavigate(); const [loading, setLoading] = useState(false) const [name, setName] = useState('') + const { language } = useI18n() const ref = useRef(null) const memoryInsightRef = useRef(null) const aboutMeRef = useRef(null) @@ -43,8 +45,10 @@ const Neo4j: FC = () => { if (!data) return let name = data.other_name && data.other_name !== '' ? data.other_name : data.id || data.end_user_id setName(name) - document.title = `${name} - ${t('memoryBear')}`; } + useEffect(() => { + document.title = `${name} - ${t('memoryBear')}`; + }, [name, language]) /** Navigate back */ const goBack = () => { diff --git a/web/src/views/UserMemoryDetail/Rag.tsx b/web/src/views/UserMemoryDetail/Rag.tsx index a1da95d4..07fb0af6 100644 --- a/web/src/views/UserMemoryDetail/Rag.tsx +++ b/web/src/views/UserMemoryDetail/Rag.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 17:57:11 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-04-14 15:56:15 + * @Last Modified time: 2026-04-14 16:56:36 */ /** * RAG User Memory Detail View @@ -26,6 +26,7 @@ import { } from '@/api/memory' import Empty from '@/components/Empty' import ConversationMemory from './components/ConversationMemory' +import { useI18n } from '@/store/locale' /** * Title component props @@ -45,6 +46,7 @@ const Title: FC = ({ title, iconClassName }) => ( const Rag: FC = () => { const { t } = useTranslation() const { id } = useParams() + const { language } = useI18n() const [data, setData] = useState(null) const [summary, setSummary] = useState('') const [loading, setLoading] = useState>({ @@ -99,7 +101,7 @@ const Rag: FC = () => { useEffect(() => { document.title = `${name} - ${t('memoryBear')}`; - }, [name]) + }, [name, language]) const [refreshLoading, setRefreshLoading] = useState(false) const handleRefresh = () => {