aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web
diff options
context:
space:
mode:
authorstanislavh <stanislav.honcharov@sonarsource.com>2023-02-13 11:44:11 +0100
committersonartech <sonartech@sonarsource.com>2023-02-13 20:02:53 +0000
commit982ba2999674768245cc20150fc37c6259204b39 (patch)
treea5b8db35737f983b32549d437599f56a5e415273 /server/sonar-web
parent3dd53167b7bf957fac4c456a154d341980af923d (diff)
downloadsonarqube-982ba2999674768245cc20150fc37c6259204b39.tar.gz
sonarqube-982ba2999674768245cc20150fc37c6259204b39.zip
SONAR-18128 SONAR-18358 SONAR-18368 Page titles do not identify purpose of pages
Diffstat (limited to 'server/sonar-web')
-rw-r--r--server/sonar-web/src/main/js/app/components/AdminContainer.tsx12
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/AdminContainer-test.tsx.snap3
-rw-r--r--server/sonar-web/src/main/js/app/utils/startReactApp.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/__tests__/CodingRules-it.ts2
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesApp.tsx (renamed from server/sonar-web/src/main/js/apps/coding-rules/components/App.tsx)28
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/CodingRulesApp-test.tsx (renamed from server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/App-test.tsx)8
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/CodingRulesApp-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/App-test.tsx.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/routes.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/ComponentMeasuresApp.tsx (renamed from server/sonar-web/src/main/js/apps/component-measures/components/App.tsx)25
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/__tests__/ComponentMeasuresApp-test.tsx (renamed from server/sonar-web/src/main/js/apps/component-measures/components/__tests__/App-test.tsx)8
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/ComponentMeasuresApp-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/App-test.tsx.snap)6
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/routes.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx13
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/components/App.tsx11
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileContainer.tsx10
15 files changed, 77 insertions, 61 deletions
diff --git a/server/sonar-web/src/main/js/app/components/AdminContainer.tsx b/server/sonar-web/src/main/js/app/components/AdminContainer.tsx
index bcc5dc09267..82ab8d97641 100644
--- a/server/sonar-web/src/main/js/app/components/AdminContainer.tsx
+++ b/server/sonar-web/src/main/js/app/components/AdminContainer.tsx
@@ -24,7 +24,7 @@ import { getSettingsNavigation } from '../../api/navigation';
import { getPendingPlugins } from '../../api/plugins';
import { getSystemStatus, waitSystemUPStatus } from '../../api/system';
import handleRequiredAuthorization from '../../app/utils/handleRequiredAuthorization';
-import { translate } from '../../helpers/l10n';
+import { translate, translateWithParameters } from '../../helpers/l10n';
import { AdminPagesContext } from '../../types/admin';
import { AppState } from '../../types/appstate';
import { PendingPluginResult } from '../../types/plugins';
@@ -119,13 +119,17 @@ export class AdminContainer extends React.PureComponent<AdminContainerProps, Sta
}
const { pendingPlugins, systemStatus } = this.state;
- const defaultTitle = translate('layout.settings');
-
const adminPagesContext: AdminPagesContext = { adminPages };
return (
<div>
- <Helmet defaultTitle={defaultTitle} defer={false} titleTemplate={`%s - ${defaultTitle}`} />
+ <Helmet
+ defer={false}
+ titleTemplate={translateWithParameters(
+ 'page_title.template.with_category',
+ translate('layout.settings')
+ )}
+ />
<SettingsNav
extensions={adminPages}
fetchPendingPlugins={this.fetchPendingPlugins}
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/AdminContainer-test.tsx.snap b/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/AdminContainer-test.tsx.snap
index 5b721b10020..6d04b34fa6d 100644
--- a/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/AdminContainer-test.tsx.snap
+++ b/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/AdminContainer-test.tsx.snap
@@ -3,11 +3,10 @@
exports[`should render correctly 1`] = `
<div>
<Helmet
- defaultTitle="layout.settings"
defer={false}
encodeSpecialCharacters={true}
prioritizeSeoTags={false}
- titleTemplate="%s - layout.settings"
+ titleTemplate="page_title.template.with_category.layout.settings"
/>
<WithLocation
extensions={[]}
diff --git a/server/sonar-web/src/main/js/app/utils/startReactApp.tsx b/server/sonar-web/src/main/js/app/utils/startReactApp.tsx
index c34ad1b5e8b..490a7f9043a 100644
--- a/server/sonar-web/src/main/js/app/utils/startReactApp.tsx
+++ b/server/sonar-web/src/main/js/app/utils/startReactApp.tsx
@@ -19,7 +19,7 @@
*/
import * as React from 'react';
import { render } from 'react-dom';
-import { HelmetProvider } from 'react-helmet-async';
+import { Helmet, HelmetProvider } from 'react-helmet-async';
import { IntlProvider } from 'react-intl';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import accountRoutes from '../../apps/account/routes';
@@ -57,6 +57,7 @@ import tutorialsRoutes from '../../apps/tutorials/routes';
import usersRoutes from '../../apps/users/routes';
import webAPIRoutes from '../../apps/web-api/routes';
import webhooksRoutes from '../../apps/webhooks/routes';
+import { translate } from '../../helpers/l10n';
import { getBaseUrl } from '../../helpers/system';
import { AppState } from '../../types/appstate';
import { Feature } from '../../types/features';
@@ -185,6 +186,7 @@ export default function startReactApp(
<IntlProvider defaultLocale={lang} locale={lang}>
<GlobalMessagesContainer />
<BrowserRouter basename={getBaseUrl()}>
+ <Helmet titleTemplate={translate('page_title.template.default')} />
<Routes>
{renderRedirects()}
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/__tests__/CodingRules-it.ts b/server/sonar-web/src/main/js/apps/coding-rules/__tests__/CodingRules-it.ts
index 00fe9b0ff43..9750dfc6762 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/__tests__/CodingRules-it.ts
+++ b/server/sonar-web/src/main/js/apps/coding-rules/__tests__/CodingRules-it.ts
@@ -75,7 +75,7 @@ it('should show open rule with default description section', async () => {
expect(
await screen.findByRole('heading', { level: 1, name: 'Awsome java rule' })
).toBeInTheDocument();
- expect(document.title).toEqual('coding_rule.page.Java.Awsome java rule');
+ expect(document.title).toEqual('page_title.template.with_category.coding_rules.page');
expect(screen.getByText('Why')).toBeInTheDocument();
expect(screen.getByText('Because')).toBeInTheDocument();
});
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/App.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesApp.tsx
index c69234ee29c..79dcc48d547 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/App.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesApp.tsx
@@ -96,7 +96,7 @@ interface State {
rules: Rule[];
}
-export class App extends React.PureComponent<Props, State> {
+export class CodingRulesApp extends React.PureComponent<Props, State> {
mounted = false;
constructor(props: Props) {
@@ -562,16 +562,20 @@ export class App extends React.PureComponent<Props, State> {
return (
<>
<Suggestions suggestions="coding_rules" />
- <Helmet
- defer={false}
- title={
- openRule
- ? translateWithParameters('coding_rule.page', openRule.langName, openRule.name)
- : translate('coding_rules.page')
- }
- >
- <meta content="noindex" name="robots" />
- </Helmet>
+ {openRule ? (
+ <Helmet
+ defer={false}
+ title={translateWithParameters('coding_rule.page', openRule.langName, openRule.name)}
+ titleTemplate={translateWithParameters(
+ 'page_title.template.with_category',
+ translate('coding_rules.page')
+ )}
+ />
+ ) : (
+ <Helmet defer={false} title={translate('coding_rules.page')}>
+ <meta content="noindex" name="robots" />
+ </Helmet>
+ )}
<div className="layout-page" id="coding-rules-page">
<ScreenPositionHelper className="layout-page-side-outer">
{({ top }) => (
@@ -715,4 +719,4 @@ function parseFacets(rawFacets: { property: string; values: { count: number; val
return facets;
}
-export default withRouter(withCurrentUserContext(App));
+export default withRouter(withCurrentUserContext(CodingRulesApp));
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/CodingRulesApp-test.tsx
index aa18b5cba52..09ccc3496a5 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/App-test.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/CodingRulesApp-test.tsx
@@ -29,7 +29,7 @@ import {
mockRouter,
} from '../../../../helpers/testMocks';
import { waitAndUpdate } from '../../../../helpers/testUtils';
-import { App } from '../App';
+import { CodingRulesApp } from '../CodingRulesApp';
jest.mock('../../../../components/common/ScreenPositionHelper');
@@ -105,9 +105,9 @@ describe('renderBulkButton', () => {
});
});
-function shallowRender(props: Partial<App['props']> = {}) {
- return shallow<App>(
- <App
+function shallowRender(props: Partial<CodingRulesApp['props']> = {}) {
+ return shallow<CodingRulesApp>(
+ <CodingRulesApp
currentUser={mockCurrentUser({
isLoggedIn: true,
})}
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/CodingRulesApp-test.tsx.snap
index 08da9918375..08da9918375 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/App-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/CodingRulesApp-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/routes.tsx b/server/sonar-web/src/main/js/apps/coding-rules/routes.tsx
index 2e9bb7a9355..5ba7f224b13 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/routes.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/routes.tsx
@@ -20,7 +20,7 @@
import React, { useEffect } from 'react';
import { Route, useLocation, useNavigate } from 'react-router-dom';
import { RawQuery } from '../../types/types';
-import App from './components/App';
+import CodingRulesApp from './components/CodingRulesApp';
import { parseQuery, serializeQuery } from './query';
const EXPECTED_SPLIT_PARTS = 2;
@@ -56,7 +56,7 @@ function HashEditWrapper() {
}
}, [location, navigate]);
- return <App />;
+ return <CodingRulesApp />;
}
const routes = () => <Route path="coding_rules" element={<HashEditWrapper />} />;
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/App.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/ComponentMeasuresApp.tsx
index 922fa2d0906..b5d7f9da79c 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/components/App.tsx
+++ b/server/sonar-web/src/main/js/apps/component-measures/components/ComponentMeasuresApp.tsx
@@ -33,11 +33,7 @@ import { enhanceMeasure } from '../../../components/measure/utils';
import '../../../components/search-navigator.css';
import { Alert } from '../../../components/ui/Alert';
import { getBranchLikeQuery, isPullRequest, isSameBranchLike } from '../../../helpers/branch-like';
-import {
- getLocalizedMetricDomain,
- translate,
- translateWithParameters,
-} from '../../../helpers/l10n';
+import { translate } from '../../../helpers/l10n';
import {
addSideBarClass,
addWhitePageClass,
@@ -64,7 +60,6 @@ import {
hasFullMeasures,
hasTree,
hasTreemap,
- isProjectOverview,
parseQuery,
Query,
serializeQuery,
@@ -89,7 +84,7 @@ interface State {
metrics: Dict<Metric>;
}
-export class App extends React.PureComponent<Props, State> {
+export class ComponentMeasuresApp extends React.PureComponent<Props, State> {
mounted = false;
state: State;
@@ -174,18 +169,6 @@ export class App extends React.PureComponent<Props, State> {
);
}
- getHelmetTitle = (query: Query, displayOverview: boolean, metric?: Metric) => {
- if (displayOverview && query.metric) {
- return isProjectOverview(query.metric)
- ? translate('component_measures.overview.project_overview.facet')
- : translateWithParameters(
- 'component_measures.domain_x_overview',
- getLocalizedMetricDomain(query.metric)
- );
- }
- return metric ? metric.name : translate('layout.measures');
- };
-
getSelectedMetric = (query: Query, displayOverview: boolean) => {
if (displayOverview) {
return undefined;
@@ -310,7 +293,7 @@ export class App extends React.PureComponent<Props, State> {
return (
<div id="component-measures">
<Suggestions suggestions="component_measures" />
- <Helmet defer={false} title={this.getHelmetTitle(query, displayOverview, metric)} />
+ <Helmet defer={false} title={translate('layout.measures')} />
{measures.length > 0 ? (
<div className="layout-page">
<ScreenPositionHelper className="layout-page-side-outer">
@@ -368,7 +351,7 @@ const AlertContent = styled.div`
* is that we can't use the usual withComponentContext HOC, because the type
* of `component` isn't the same. It probably used to work because of the lazy loading
*/
-const WrappedApp = withRouter(withBranchStatusActions(App));
+const WrappedApp = withRouter(withBranchStatusActions(ComponentMeasuresApp));
function AppWithComponentContext() {
const { branchLike, component } = React.useContext(ComponentContext);
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/ComponentMeasuresApp-test.tsx
index 373b501acf9..f7751cebc97 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/App-test.tsx
+++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/ComponentMeasuresApp-test.tsx
@@ -27,7 +27,7 @@ import { mockComponent } from '../../../../helpers/mocks/component';
import { mockIssue, mockLocation, mockRouter } from '../../../../helpers/testMocks';
import { waitAndUpdate } from '../../../../helpers/testUtils';
import { ComponentQualifier } from '../../../../types/component';
-import { App } from '../App';
+import { ComponentMeasuresApp } from '../ComponentMeasuresApp';
jest.mock('../../../../api/metrics', () => ({
getAllMetrics: jest.fn().mockResolvedValue([
@@ -151,9 +151,9 @@ it.each([
}
);
-function shallowRender(props: Partial<App['props']> = {}) {
- return shallow<App>(
- <App
+function shallowRender(props: Partial<ComponentMeasuresApp['props']> = {}) {
+ return shallow<ComponentMeasuresApp>(
+ <ComponentMeasuresApp
branchLike={mockMainBranch()}
component={mockComponent({ key: 'foo', name: 'Foo' })}
fetchBranchStatus={jest.fn()}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/ComponentMeasuresApp-test.tsx.snap
index 523e596b871..671b12b6fdf 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/App-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/component-measures/components/__tests__/__snapshots__/ComponentMeasuresApp-test.tsx.snap
@@ -11,7 +11,7 @@ exports[`should not render drilldown for estimated duplications 1`] = `
defer={false}
encodeSpecialCharacters={true}
prioritizeSeoTags={false}
- title="Coverage"
+ title="layout.measures"
/>
<div
className="layout-page"
@@ -49,7 +49,7 @@ exports[`should render a message when there are no measures 1`] = `
defer={false}
encodeSpecialCharacters={true}
prioritizeSeoTags={false}
- title="Coverage"
+ title="layout.measures"
/>
<MeasuresEmpty />
</div>
@@ -123,7 +123,7 @@ exports[`should render correctly 1`] = `
defer={false}
encodeSpecialCharacters={true}
prioritizeSeoTags={false}
- title="Coverage"
+ title="layout.measures"
/>
<div
className="layout-page"
diff --git a/server/sonar-web/src/main/js/apps/component-measures/routes.tsx b/server/sonar-web/src/main/js/apps/component-measures/routes.tsx
index edee717bbb5..4e1e0411f4d 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/routes.tsx
+++ b/server/sonar-web/src/main/js/apps/component-measures/routes.tsx
@@ -22,11 +22,11 @@ import { Navigate, Route, useParams, useSearchParams } from 'react-router-dom';
import NavigateWithParams from '../../app/utils/NavigateWithParams';
import { omitNil } from '../../helpers/request';
import { searchParamsToQuery } from '../../helpers/urls';
-import App from './components/App';
+import ComponentMeasuresApp from './components/ComponentMeasuresApp';
const routes = () => (
<Route path="component_measures">
- <Route index={true} element={<App />} />
+ <Route index={true} element={<ComponentMeasuresApp />} />
<Route
path="domain/:domainName"
element={
diff --git a/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx b/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx
index 4a3ee0c5980..35c82364238 100644
--- a/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx
@@ -1164,7 +1164,18 @@ export class App extends React.PureComponent<Props, State> {
id="issues-page"
>
<Suggestions suggestions="issues" />
- <Helmet defer={false} title={openIssue ? openIssue.message : translate('issues.page')} />
+ {openIssue ? (
+ <Helmet
+ defer={false}
+ title={openIssue.message}
+ titleTemplate={translateWithParameters(
+ 'page_title.template.with_category',
+ translate('issues.page')
+ )}
+ />
+ ) : (
+ <Helmet defer={false} title={translate('issues.page')} />
+ )}
<h1 className="a11y-hidden">{translate('issues.page')}</h1>
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/App.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/App.tsx
index 87cb5a6097c..a0ce8d48ab9 100644
--- a/server/sonar-web/src/main/js/apps/quality-gates/components/App.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-gates/components/App.tsx
@@ -25,7 +25,7 @@ import ScreenPositionHelper from '../../../components/common/ScreenPositionHelpe
import Suggestions from '../../../components/embed-docs-modal/Suggestions';
import '../../../components/search-navigator.css';
import DeferredSpinner from '../../../components/ui/DeferredSpinner';
-import { translate } from '../../../helpers/l10n';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
import {
addSideBarClass,
addWhitePageClass,
@@ -113,11 +113,16 @@ class App extends React.PureComponent<Props, State> {
render() {
const { name } = this.props;
const { canCreate, qualityGates } = this.state;
- const defaultTitle = translate('quality_gates.page');
return (
<>
- <Helmet defaultTitle={defaultTitle} defer={false} titleTemplate={`%s - ${defaultTitle}`} />
+ <Helmet
+ defer={false}
+ titleTemplate={translateWithParameters(
+ 'page_title.template.with_category',
+ translate('quality_gates.page')
+ )}
+ />
<div className="layout-page" id="quality-gates-page">
<Suggestions suggestions="quality_gates" />
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileContainer.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileContainer.tsx
index 5588a4d15b9..77ac4b8d845 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileContainer.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileContainer.tsx
@@ -21,6 +21,7 @@ import * as React from 'react';
import { Helmet } from 'react-helmet-async';
import { Outlet, useSearchParams } from 'react-router-dom';
import { useLocation } from '../../../components/hoc/withRouter';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
import ProfileHeader from '../details/ProfileHeader';
import { useQualityProfilesContext } from '../qualityProfilesContext';
import ProfileNotFound from './ProfileNotFound';
@@ -58,7 +59,14 @@ export default function ProfileContainer() {
return (
<div id="quality-profile">
- <Helmet defer={false} title={profile.name} />
+ <Helmet
+ defer={false}
+ title={profile.name}
+ titleTemplate={translateWithParameters(
+ 'page_title.template.with_category',
+ translate('quality_profiles.page')
+ )}
+ />
<ProfileHeader
profile={profile}
isComparable={filteredProfiles.length > 1}