]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-18068 Page <title> does not identify purpose of page
authorMathieu Suen <mathieu.suen@sonarsource.com>
Tue, 31 Jan 2023 09:43:07 +0000 (10:43 +0100)
committersonartech <sonartech@sonarsource.com>
Wed, 1 Feb 2023 20:02:56 +0000 (20:02 +0000)
server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileContainer.tsx
server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/ProfileContainer-test.tsx
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileHeader.tsx
server/sonar-web/src/main/js/apps/quality-profiles/routes.tsx
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 275deded89f75bc39a477583094bc93593a8fb46..ddc968d65a027c877dc4cc3871b672ed8e06754f 100644 (file)
@@ -22,16 +22,17 @@ import { Helmet } from 'react-helmet-async';
 import { Outlet, useSearchParams } from 'react-router-dom';
 import { useLocation } from '../../../components/hoc/withRouter';
 import ProfileHeader from '../details/ProfileHeader';
-import { QualityProfilesContextProps, withQualityProfilesContext } from '../qualityProfilesContext';
+import { useQualityProfilesContext } from '../qualityProfilesContext';
 import ProfileNotFound from './ProfileNotFound';
 
-export function ProfileContainer(props: QualityProfilesContextProps) {
+export default function ProfileContainer() {
   const [_, setSearchParams] = useSearchParams();
   const location = useLocation();
 
   const { key, language, name } = location.query;
 
-  const { profiles } = props;
+  const context = useQualityProfilesContext();
+  const { profiles } = context;
 
   // try to find a quality profile with the given key
   // if managed to find one, redirect to a new version
@@ -55,22 +56,15 @@ export function ProfileContainer(props: QualityProfilesContextProps) {
     return <ProfileNotFound />;
   }
 
-  const context: QualityProfilesContextProps = {
-    profile,
-    ...props,
-  };
-
   return (
     <div id="quality-profile">
       <Helmet defer={false} title={profile.name} />
       <ProfileHeader
         profile={profile}
         isComparable={filteredProfiles.length > 1}
-        updateProfiles={props.updateProfiles}
+        updateProfiles={context.updateProfiles}
       />
-      <Outlet context={context} />
+      <Outlet context={{ profile, ...context }} />
     </div>
   );
 }
-
-export default withQualityProfilesContext(ProfileContainer);
index b84b65c8a4b665896f321f614b036ed9a937200e..b771e089918a949736f988f943fe0b0dad00f8c2 100644 (file)
 import { render, screen } from '@testing-library/react';
 import * as React from 'react';
 import { HelmetProvider } from 'react-helmet-async';
-import { MemoryRouter, Route, Routes } from 'react-router-dom';
+import { MemoryRouter, Outlet, Route, Routes } from 'react-router-dom';
 import { mockQualityProfile } from '../../../../helpers/testMocks';
 import {
   QualityProfilesContextProps,
   withQualityProfilesContext,
 } from '../../qualityProfilesContext';
 import { Profile } from '../../types';
-import { ProfileContainer } from '../ProfileContainer';
+import ProfileContainer from '../ProfileContainer';
 
 it('should render the header and child', () => {
   const targetProfile = mockQualityProfile({ name: 'profile1' });
@@ -69,23 +69,27 @@ function Child(props: { profile?: Profile }) {
 const WrappedChild = withQualityProfilesContext(Child);
 
 function renderProfileContainer(path: string, overrides: Partial<QualityProfilesContextProps>) {
+  function ProfileOutlet(props: Partial<QualityProfilesContextProps>) {
+    const context = {
+      actions: {},
+      exporters: [],
+      languages: [],
+      profiles: [],
+      updateProfiles: jest.fn(),
+      ...props,
+    };
+
+    return <Outlet context={context} />;
+  }
+
   return render(
     <HelmetProvider context={{}}>
       <MemoryRouter initialEntries={[path]}>
         <Routes>
-          <Route
-            element={
-              <ProfileContainer
-                actions={{}}
-                exporters={[]}
-                languages={[]}
-                profiles={[]}
-                updateProfiles={jest.fn()}
-                {...overrides}
-              />
-            }
-          >
-            <Route path="*" element={<WrappedChild />} />
+          <Route element={<ProfileOutlet {...overrides} />}>
+            <Route element={<ProfileContainer />}>
+              <Route path="*" element={<WrappedChild />} />
+            </Route>
           </Route>
         </Routes>
       </MemoryRouter>
index c4b3f217a78e4771dc3463813d61170e35d63618..2ca6f42e977bef345abbab385eb9a58f15e6a775 100644 (file)
@@ -18,6 +18,7 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
+import { Helmet } from 'react-helmet-async';
 import { FormattedMessage } from 'react-intl';
 import { NavLink } from 'react-router-dom';
 import Link from '../../../components/common/Link';
@@ -31,6 +32,7 @@ import BuiltInQualityProfileBadge from '../components/BuiltInQualityProfileBadge
 import ProfileActions from '../components/ProfileActions';
 import ProfileLink from '../components/ProfileLink';
 import { PROFILE_PATH } from '../constants';
+import { QualityProfilePath } from '../routes';
 import { Profile } from '../types';
 import {
   getProfileChangelogPath,
@@ -47,9 +49,22 @@ interface Props {
 export default function ProfileHeader(props: Props) {
   const { profile, isComparable, updateProfiles } = props;
   const location = useLocation();
+  const isComparePage = location.pathname.endsWith(`/${QualityProfilePath.COMPARE}`);
+  const isChangeLogPage = location.pathname.endsWith(`/${QualityProfilePath.CHANGELOG}`);
 
   return (
     <div className="page-header quality-profile-header">
+      {(isComparePage || isChangeLogPage) && (
+        <Helmet
+          defer={false}
+          title={translateWithParameters(
+            isChangeLogPage
+              ? 'quality_profiles.page_title_changelog_x'
+              : 'quality_profiles.page_title_compare_x',
+            profile.name
+          )}
+        />
+      )}
       <div className="note spacer-bottom">
         <NavLink end={true} to={PROFILE_PATH}>
           {translate('quality_profiles.page')}
index 3b7862e10e0932e7859ed910c394e91b46a96d1c..cf20d65f63cd0d5c7169f642328f394dfffd8aa8 100644 (file)
@@ -26,13 +26,18 @@ import QualityProfilesApp from './components/QualityProfilesApp';
 import ProfileDetails from './details/ProfileDetails';
 import HomeContainer from './home/HomeContainer';
 
+export enum QualityProfilePath {
+  SHOW = 'show',
+  CHANGELOG = 'changelog',
+  COMPARE = 'compare',
+}
 const routes = () => (
   <Route path="profiles" element={<QualityProfilesApp />}>
     <Route index={true} element={<HomeContainer />} />
     <Route element={<ProfileContainer />}>
-      <Route path="show" element={<ProfileDetails />} />
-      <Route path="changelog" element={<ChangelogContainer />} />
-      <Route path="compare" element={<ComparisonContainer />} />
+      <Route path={QualityProfilePath.SHOW} element={<ProfileDetails />} />
+      <Route path={QualityProfilePath.CHANGELOG} element={<ChangelogContainer />} />
+      <Route path={QualityProfilePath.COMPARE} element={<ComparisonContainer />} />
     </Route>
   </Route>
 );
index 959e8225dfcd8aa2937ff006c8572e80f9c6f104..815aa6c421e564a2de28f180b588a6db1089a7d1 100644 (file)
@@ -1653,6 +1653,8 @@ project.info.see_more_info_on_x_locs=See more information on your {0} lines of c
 #
 #------------------------------------------------------------------------------
 
+quality_profiles.page_title_changelog_x={0} - Quality profile changelog
+quality_profiles.page_title_compare_x={0} - Quality profile comparaison
 quality_profiles.new_profile=New Quality Profile
 quality_profiles.compare_with=Compare with
 quality_profiles.filter_by=Filter profiles by