mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-10 15:56:03 +00:00
feat(web): show sub-entity name in document title on detail pages
Detail pages (plugin / MCP / pipeline / knowledge base / skill) only showed the type in the tab title. Drive the /home document title from HomeLayout, which has the selected entity name via context: '<entity> · <type> · LangBot' when a sub-entity is open, '<type> · LangBot' otherwise. The top-level hook now skips /home and only handles login/register/reset-password/wizard. Type label falls back to a route-derived i18n key on direct page loads.
This commit is contained in:
@@ -42,6 +42,7 @@ import {
|
||||
PluginInstallTaskProvider,
|
||||
PluginInstallProgressDialog,
|
||||
} from '@/app/home/plugins/components/plugin-install-task';
|
||||
import { setDocumentTitle } from '@/hooks/useDocumentTitle';
|
||||
|
||||
// Routes that belong to the "Extensions" section
|
||||
const EXTENSIONS_ROUTES = [
|
||||
@@ -52,6 +53,28 @@ const EXTENSIONS_ROUTES = [
|
||||
'/home/plugin-pages',
|
||||
];
|
||||
|
||||
// Map a /home route to the i18n key for its type-level title. Used as a robust
|
||||
// fallback for the document title on direct page loads, before the sidebar's
|
||||
// onSelectedChange has populated the local `title` state. Detail routes reuse
|
||||
// the section key (prefix match), e.g. /home/mcp?id=... -> mcp.title.
|
||||
const HOME_TITLE_KEYS: { match: (path: string) => boolean; key: string }[] = [
|
||||
{ match: (p) => p.startsWith('/home/monitoring'), key: 'monitoring.title' },
|
||||
{ match: (p) => p.startsWith('/home/bots'), key: 'bots.title' },
|
||||
{ match: (p) => p.startsWith('/home/pipelines'), key: 'pipelines.title' },
|
||||
{
|
||||
match: (p) => p.startsWith('/home/add-extension'),
|
||||
key: 'sidebar.addExtension',
|
||||
},
|
||||
{ match: (p) => p.startsWith('/home/extensions'), key: 'plugins.title' },
|
||||
{ match: (p) => p.startsWith('/home/mcp'), key: 'mcp.title' },
|
||||
{ match: (p) => p.startsWith('/home/knowledge'), key: 'knowledge.title' },
|
||||
{ match: (p) => p.startsWith('/home/skills'), key: 'skills.title' },
|
||||
{
|
||||
match: (p) => p.startsWith('/home/plugin-pages'),
|
||||
key: 'sidebar.pluginPages',
|
||||
},
|
||||
];
|
||||
|
||||
function isExtensionsRoute(pathname: string): boolean {
|
||||
return EXTENSIONS_ROUTES.some(
|
||||
(route) => pathname === route || pathname.startsWith(route + '/'),
|
||||
@@ -147,6 +170,20 @@ function HomeLayoutInner({ children }: { children: React.ReactNode }) {
|
||||
: t('sidebar.home');
|
||||
const sectionLink = isExtensions ? '/home/extensions' : '/home/monitoring';
|
||||
|
||||
// Drive the browser tab title for the /home section. The type-level label
|
||||
// prefers the sidebar-provided `title`, falling back to a route-derived key on
|
||||
// direct page loads. When a sub-entity (plugin / MCP / pipeline / KB / skill)
|
||||
// is open, its name is prepended: "<entity> · <type> · LangBot".
|
||||
useEffect(() => {
|
||||
const routeEntry = HOME_TITLE_KEYS.find((e) => e.match(pathname));
|
||||
const fallbackType =
|
||||
routeEntry && t(routeEntry.key) !== routeEntry.key
|
||||
? t(routeEntry.key)
|
||||
: null;
|
||||
const typeLabel = title || fallbackType;
|
||||
setDocumentTitle(detailEntityName, typeLabel);
|
||||
}, [pathname, title, detailEntityName, t]);
|
||||
|
||||
return (
|
||||
<SidebarProvider>
|
||||
<Suspense fallback={<div />}>
|
||||
|
||||
Reference in New Issue
Block a user