Skip to content

Commit 4881f09

Browse files
authored
feat: show different page titles on different pages (#733)
1 parent 90a4d9e commit 4881f09

File tree

26 files changed

+246
-109
lines changed

26 files changed

+246
-109
lines changed

package-lock.json

Lines changed: 28 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"qs": "^6.11.0",
3333
"react-error-boundary": "^4.0.12",
3434
"react-json-inspector": "^7.1.1",
35+
"react-helmet-async": "2.0.4",
3536
"react-list": "^0.8.11",
3637
"react-monaco-editor": "^0.47.0",
3738
"react-redux": "^7.2.6",

src/containers/App/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'react';
22
import {connect} from 'react-redux';
3+
import {Helmet} from 'react-helmet-async';
34

45
import ContentWrapper, {Content} from './Content';
56
import ReduxTooltip from '../ReduxTooltip/ReduxTooltip';
@@ -30,6 +31,7 @@ export interface AppProps {
3031
function App({store, history, singleClusterMode, children, userSettings = settings}: AppProps) {
3132
return (
3233
<Providers store={store} history={history}>
34+
<Helmet defaultTitle="YDB Monitoring" titleTemplate="%s — YDB Monitoring" />
3335
<ContentWrapper>
3436
<Navigation userSettings={userSettings}>
3537
<ErrorBoundary>

src/containers/App/Providers.tsx

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {Router} from 'react-router';
44
import {QueryParamProvider} from 'use-query-params';
55
import {ReactRouter5Adapter} from 'use-query-params/adapters/react-router-5';
66
import {ThemeProvider} from '@gravity-ui/uikit';
7+
import {HelmetProvider} from 'react-helmet-async';
78

89
import {ComponentsProvider} from '../../components/ComponentsProvider/ComponentsProvider';
910
import {componentsRegistry as defaultComponentsRegistry} from '../../components/ComponentsProvider/componentsRegistry';
@@ -28,17 +29,19 @@ export function Providers({
2829
children,
2930
}: ProvidersProps) {
3031
return (
31-
<Provider store={store}>
32-
<Router history={history}>
33-
<QueryParamProvider adapter={ReactRouter5Adapter}>
34-
<Theme>
35-
<ComponentsProvider registry={componentsRegistry}>
36-
{children}
37-
</ComponentsProvider>
38-
</Theme>
39-
</QueryParamProvider>
40-
</Router>
41-
</Provider>
32+
<HelmetProvider>
33+
<Provider store={store}>
34+
<Router history={history}>
35+
<QueryParamProvider adapter={ReactRouter5Adapter}>
36+
<Theme>
37+
<ComponentsProvider registry={componentsRegistry}>
38+
{children}
39+
</ComponentsProvider>
40+
</Theme>
41+
</QueryParamProvider>
42+
</Router>
43+
</Provider>
44+
</HelmetProvider>
4245
);
4346
}
4447

src/containers/Cluster/Cluster.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {useEffect, useMemo, useRef} from 'react';
22
import {Redirect, Switch, Route, useLocation, useRouteMatch} from 'react-router';
33
import {useDispatch} from 'react-redux';
4+
import {Helmet} from 'react-helmet-async';
45
import cn from 'bem-cn-lite';
56
import qs from 'qs';
67

@@ -52,7 +53,7 @@ function Cluster({
5253

5354
const dispatch = useDispatch();
5455

55-
const activeTab = useClusterTab();
56+
const activeTabId = useClusterTab();
5657

5758
const location = useLocation();
5859
const queryParams = qs.parse(location.search, {
@@ -117,14 +118,23 @@ function Cluster({
117118
);
118119
};
119120

121+
const clusterTitle = cluster?.Name ?? clusterName ?? CLUSTER_DEFAULT_TITLE;
122+
const activeTab = useMemo(() => clusterTabs.find(({id}) => id === activeTabId), [activeTabId]);
123+
120124
return (
121125
<div className={b()} ref={container}>
126+
<Helmet
127+
defaultTitle={`${clusterTitle} — YDB Monitoring`}
128+
titleTemplate={`%s — ${clusterTitle} — YDB Monitoring`}
129+
>
130+
{activeTab ? <title>{activeTab.title}</title> : null}
131+
</Helmet>
122132
<div className={b('header')}>{getClusterTitle()}</div>
123133
<div className={b('tabs')}>
124134
<Tabs
125135
size="l"
126136
allowNotSelected={true}
127-
activeTab={activeTab}
137+
activeTab={activeTabId}
128138
items={clusterTabs}
129139
wrapTo={({id}, node) => {
130140
const path = getClusterPath(id as ClusterTab, queryParams);
@@ -197,7 +207,7 @@ function Cluster({
197207
>
198208
<Versions versionToColor={versionToColor} />
199209
</Route>
200-
<Redirect to={getLocationObjectFromHref(getClusterPath(activeTab))} />
210+
<Redirect to={getLocationObjectFromHref(getClusterPath(activeTabId))} />
201211
</Switch>
202212
</div>
203213
</div>

src/containers/Clusters/Clusters.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import {useCallback, useMemo} from 'react';
22
import {useDispatch} from 'react-redux';
3+
import {Helmet} from 'react-helmet-async';
34

45
import DataTable from '@gravity-ui/react-data-table';
5-
66
import {TableColumnSetup, Select} from '@gravity-ui/uikit';
77

88
import {Search} from '../../components/Search';
9+
import {Loader} from '../../components/Loader';
910
import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants';
1011
import {useAutofetcher} from '../../utils/hooks';
1112

@@ -35,10 +36,9 @@ import {ClustersStatistics} from './ClustersStatistics';
3536
import {CLUSTERS_COLUMNS} from './columns';
3637
import {useSelectedColumns} from './useSelectedColumns';
3738
import {b} from './shared';
39+
import i18n from './i18n';
3840

3941
import './Clusters.scss';
40-
import {Loader} from '../../components/Loader';
41-
import i18n from './i18n';
4242

4343
export function Clusters() {
4444
const dispatch = useDispatch();
@@ -103,6 +103,10 @@ export function Clusters() {
103103

104104
return (
105105
<div className={b()}>
106+
<Helmet>
107+
<title>{i18n('page_title')}</title>
108+
</Helmet>
109+
106110
<ClustersStatistics stats={aggregation} count={filteredClusters.length} />
107111
<div className={b('controls')}>
108112
<div className={b('control', {wide: true})}>

src/containers/Clusters/i18n/en.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,7 @@
1313
"statistics_load": "Load",
1414
"statistics_storage": "Storage",
1515

16-
"tooltip_no-cluster-data": "No cluster data"
16+
"tooltip_no-cluster-data": "No cluster data",
17+
18+
"page_title": "Clusters"
1719
}
Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
import {Lang, i18n} from '../../../utils/i18n';
1+
import {registerKeysets} from '../../../utils/i18n';
22

33
import en from './en.json';
44
import ru from './ru.json';
55

66
const COMPONENT = 'ydb-clusters-page';
77

8-
i18n.registerKeyset(Lang.En, COMPONENT, en);
9-
i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
10-
11-
export default i18n.keyset(COMPONENT);
8+
export default registerKeysets(COMPONENT, {ru, en});

src/containers/Clusters/i18n/ru.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,7 @@
1313
"statistics_load": "Нагрузка",
1414
"statistics_storage": "Хранилище",
1515

16-
"tooltip_no-cluster-data": "Нет данных кластера"
16+
"tooltip_no-cluster-data": "Нет данных кластера",
17+
18+
"page_title": "Кластеры"
1719
}

src/containers/Node/Node.tsx

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {useEffect, useMemo, useRef} from 'react';
22
import {useLocation, useRouteMatch} from 'react-router';
33
import cn from 'bem-cn-lite';
44
import {useDispatch} from 'react-redux';
5+
import {Helmet} from 'react-helmet-async';
56

67
import {Tabs} from '@gravity-ui/uikit';
78
import {Link} from 'react-router-dom';
@@ -52,10 +53,6 @@ function Node(props: NodeProps) {
5253
const {activeTabVerified, nodeTabs} = useMemo(() => {
5354
const hasStorage = node?.Roles?.find((el) => el === STORAGE_ROLE);
5455

55-
let actualActiveTab = activeTab;
56-
if (!hasStorage && activeTab === STORAGE) {
57-
actualActiveTab = OVERVIEW;
58-
}
5956
const nodePages = hasStorage ? NODE_PAGES : NODE_PAGES.filter((el) => el.id !== STORAGE);
6057

6158
const actualNodeTabs = nodePages.map((page) => {
@@ -65,6 +62,11 @@ function Node(props: NodeProps) {
6562
};
6663
});
6764

65+
let actualActiveTab = actualNodeTabs.find(({id}) => id === activeTab);
66+
if (!actualActiveTab) {
67+
actualActiveTab = actualNodeTabs[0];
68+
}
69+
6870
return {activeTabVerified: actualActiveTab, nodeTabs: actualNodeTabs};
6971
}, [activeTab, node]);
7072

@@ -97,7 +99,7 @@ function Node(props: NodeProps) {
9799
<Tabs
98100
size="l"
99101
items={nodeTabs}
100-
activeTab={activeTabVerified}
102+
activeTab={activeTabVerified.id}
101103
wrapTo={({id}, tabNode) => (
102104
<Link
103105
to={createHref(routes.node, {id: nodeId, activeTab: id})}
@@ -113,7 +115,7 @@ function Node(props: NodeProps) {
113115
);
114116
};
115117
const renderTabContent = () => {
116-
switch (activeTab) {
118+
switch (activeTabVerified.id) {
117119
case STORAGE: {
118120
return (
119121
<div className={b('storage')}>
@@ -145,6 +147,13 @@ function Node(props: NodeProps) {
145147
if (node) {
146148
return (
147149
<div className={b(null, props.className)} ref={container}>
150+
<Helmet
151+
titleTemplate={`%s — ${node.Host} — YDB Monitoring`}
152+
defaultTitle={`${node.Host} — YDB Monitoring`}
153+
>
154+
<title>{activeTabVerified.title}</title>
155+
</Helmet>
156+
148157
<BasicNodeViewer
149158
node={node}
150159
additionalNodesProps={props.additionalNodesProps}

0 commit comments

Comments
 (0)