]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-22018 Introduce active version link in footer and system apge
authorstanislavh <stanislav.honcharov@sonarsource.com>
Tue, 9 Apr 2024 09:18:48 +0000 (11:18 +0200)
committersonartech <sonartech@sonarsource.com>
Wed, 10 Apr 2024 20:02:53 +0000 (20:02 +0000)
14 files changed:
server/sonar-web/src/main/js/app/components/GlobalFooter.tsx
server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalFooter-test.tsx.snap
server/sonar-web/src/main/js/app/components/app-state/AppStateContext.tsx
server/sonar-web/src/main/js/app/components/app-state/__tests__/__snapshots__/AppStateContextProvider-test.tsx.snap
server/sonar-web/src/main/js/app/components/app-state/withAppStateContext.tsx
server/sonar-web/src/main/js/app/components/extensions/__tests__/__snapshots__/Extension-test.tsx.snap
server/sonar-web/src/main/js/app/components/indexation/__tests__/__snapshots__/IndexationContextProvider-test.tsx.snap
server/sonar-web/src/main/js/apps/system/components/PageHeader.tsx
server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/PageHeader-test.tsx.snap
server/sonar-web/src/main/js/components/shared/AppVersionStatus.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/components/shared/__tests__/AppVersionStatus-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/testMocks.ts
server/sonar-web/src/main/js/types/appstate.ts
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 20c452b06ba4eb31af6af154c1fcaadd0270ffb8..e11b18e62920687fc75817222b7f856a1be5bef2 100644 (file)
@@ -21,12 +21,13 @@ import * as React from 'react';
 import DocLink from '../../components/common/DocLink';
 import InstanceMessage from '../../components/common/InstanceMessage';
 import Link from '../../components/common/Link';
+import AppVersionStatus from '../../components/shared/AppVersionStatus';
 import { Alert } from '../../components/ui/Alert';
 import { getEdition } from '../../helpers/editions';
-import { translate, translateWithParameters } from '../../helpers/l10n';
+import { translate } from '../../helpers/l10n';
 import { AppState } from '../../types/appstate';
-import withAppStateContext from './app-state/withAppStateContext';
 import GlobalFooterBranding from './GlobalFooterBranding';
+import withAppStateContext from './app-state/withAppStateContext';
 
 export interface GlobalFooterProps {
   hideLoggedInInfo?: boolean;
@@ -55,26 +56,26 @@ export function GlobalFooter({ hideLoggedInInfo, appState }: GlobalFooterProps)
         )}
         {!hideLoggedInInfo && appState?.version && (
           <li className="page-footer-menu-item">
-            {translateWithParameters('footer.version_x', appState.version)}
+            <AppVersionStatus />
           </li>
         )}
         <li className="page-footer-menu-item">
-          <a
-            href="https://www.gnu.org/licenses/lgpl-3.0.txt"
+          <Link
+            to="https://www.gnu.org/licenses/lgpl-3.0.txt"
             rel="noopener noreferrer"
             target="_blank"
           >
             {translate('footer.license')}
-          </a>
+          </Link>
         </li>
         <li className="page-footer-menu-item">
-          <a
-            href="https://community.sonarsource.com/c/help/sq"
+          <Link
+            to="https://community.sonarsource.com/c/help/sq"
             rel="noopener noreferrer"
             target="_blank"
           >
             {translate('footer.community')}
-          </a>
+          </Link>
         </li>
         <li className="page-footer-menu-item">
           <DocLink to="/">{translate('footer.documentation')}</DocLink>
index 492e71658d25aece7b3be0938919ca8303865f53..05208a8b2a15ea1aeee4d42feb3cefd0f418bbab 100644 (file)
@@ -17,29 +17,29 @@ exports[`should display the sq version 1`] = `
     <li
       className="page-footer-menu-item"
     >
-      footer.version_x.6.4-SNAPSHOT
+      <AppVersionStatus />
     </li>
     <li
       className="page-footer-menu-item"
     >
-      <a
-        href="https://www.gnu.org/licenses/lgpl-3.0.txt"
+      <ForwardRef(Link)
         rel="noopener noreferrer"
         target="_blank"
+        to="https://www.gnu.org/licenses/lgpl-3.0.txt"
       >
         footer.license
-      </a>
+      </ForwardRef(Link)>
     </li>
     <li
       className="page-footer-menu-item"
     >
-      <a
-        href="https://community.sonarsource.com/c/help/sq"
+      <ForwardRef(Link)
         rel="noopener noreferrer"
         target="_blank"
+        to="https://community.sonarsource.com/c/help/sq"
       >
         footer.community
-      </a>
+      </ForwardRef(Link)>
     </li>
     <li
       className="page-footer-menu-item"
@@ -84,24 +84,24 @@ exports[`should not render the only logged in information 1`] = `
     <li
       className="page-footer-menu-item"
     >
-      <a
-        href="https://www.gnu.org/licenses/lgpl-3.0.txt"
+      <ForwardRef(Link)
         rel="noopener noreferrer"
         target="_blank"
+        to="https://www.gnu.org/licenses/lgpl-3.0.txt"
       >
         footer.license
-      </a>
+      </ForwardRef(Link)>
     </li>
     <li
       className="page-footer-menu-item"
     >
-      <a
-        href="https://community.sonarsource.com/c/help/sq"
+      <ForwardRef(Link)
         rel="noopener noreferrer"
         target="_blank"
+        to="https://community.sonarsource.com/c/help/sq"
       >
         footer.community
-      </a>
+      </ForwardRef(Link)>
     </li>
     <li
       className="page-footer-menu-item"
@@ -142,29 +142,29 @@ exports[`should render the only logged in information 1`] = `
     <li
       className="page-footer-menu-item"
     >
-      footer.version_x.1.0
+      <AppVersionStatus />
     </li>
     <li
       className="page-footer-menu-item"
     >
-      <a
-        href="https://www.gnu.org/licenses/lgpl-3.0.txt"
+      <ForwardRef(Link)
         rel="noopener noreferrer"
         target="_blank"
+        to="https://www.gnu.org/licenses/lgpl-3.0.txt"
       >
         footer.license
-      </a>
+      </ForwardRef(Link)>
     </li>
     <li
       className="page-footer-menu-item"
     >
-      <a
-        href="https://community.sonarsource.com/c/help/sq"
+      <ForwardRef(Link)
         rel="noopener noreferrer"
         target="_blank"
+        to="https://community.sonarsource.com/c/help/sq"
       >
         footer.community
-      </a>
+      </ForwardRef(Link)>
     </li>
     <li
       className="page-footer-menu-item"
index eeedf321fafc6ea10bcb7fc8728b5a7efa57ef12..c9ae626f0e751cf6f76245fbc4db0e6fed55ca28 100644 (file)
@@ -28,5 +28,6 @@ export const DEFAULT_APP_STATE = {
   qualifiers: [],
   settings: {},
   version: '',
+  versionEOL: '',
 };
 export const AppStateContext = React.createContext<AppState>(DEFAULT_APP_STATE);
index dbdc02fa1c41a30124c4d463cd8dd70443da4207..59a0d40fa4010c0b863501b1580df15781dae047 100644 (file)
@@ -13,6 +13,7 @@ exports[`should set value correctly 1`] = `
         "sonar.lf.logoUrl": "whatevs/",
       },
       "version": "1.0",
+      "versionEOL": "2022-01-01",
     }
   }
 />
index 8b42de904874cabd6e08d70dfc92cab4c28be20a..5a7be0e1a21b69d1b42fa6c3b8c217da7a87581c 100644 (file)
@@ -43,3 +43,7 @@ export default function withAppStateContext<P>(
     }
   };
 }
+
+export function useAppState() {
+  return React.useContext(AppStateContext);
+}
index 2aece96de2387b16e819c9836f232ef3b17ce6ae..32b49f0abe2074001ec95ce00fecdd59d1ec3b50 100644 (file)
@@ -11,6 +11,7 @@ exports[`should render React extensions correctly 1`] = `
       ],
       "settings": {},
       "version": "1.0",
+      "versionEOL": "2022-01-01",
     }
   }
   currentUser={
@@ -73,6 +74,7 @@ exports[`should render React extensions correctly 2`] = `
       ],
       "settings": {},
       "version": "1.0",
+      "versionEOL": "2022-01-01",
     }
   }
   currentUser={
index b2fda45425a8f7fd50cb9cf0c9320b2d2747e4a2..641e0b9a63e03c60515bf08a7d49683d16d5a7eb 100644 (file)
@@ -12,6 +12,7 @@ exports[`should render correctly and start polling if issue sync is needed 1`] =
       ],
       "settings": {},
       "version": "1.0",
+      "versionEOL": "2022-01-01",
     }
   }
 >
index e6b768af8e7fe1867f71347e80c3e66ba38654e2..4ebabc0abb14d56473b0cb8a03310b2d0657ff93 100644 (file)
@@ -20,6 +20,7 @@
 import * as React from 'react';
 import withAppStateContext from '../../../app/components/app-state/withAppStateContext';
 import { ClipboardButton } from '../../../components/controls/clipboard';
+import AppVersionStatus from '../../../components/shared/AppVersionStatus';
 import { Alert } from '../../../components/ui/Alert';
 import { toShortNotSoISOString } from '../../../helpers/dates';
 import { translate } from '../../../helpers/l10n';
@@ -79,7 +80,9 @@ export function PageHeader(props: Props) {
                     <th>
                       <strong>{translate('system.version')}</strong>
                     </th>
-                    <td>{version}</td>
+                    <td>
+                      <AppVersionStatus />
+                    </td>
                   </tr>
                 </tbody>
               </table>
index c8ef70f9e61d17bf05e039af06d89a746c8a4021..cad0c680de68048ccdf1bb05321b468ebd6f3fd3 100644 (file)
@@ -85,7 +85,7 @@ exports[`should render correctly 3`] = `
                 </strong>
               </th>
               <td>
-                7.7.0.1234
+                <AppVersionStatus />
               </td>
             </tr>
           </tbody>
@@ -160,7 +160,7 @@ exports[`should render correctly: on embedded database 1`] = `
                 </strong>
               </th>
               <td>
-                7.7.0.1234
+                <AppVersionStatus />
               </td>
             </tr>
           </tbody>
diff --git a/server/sonar-web/src/main/js/components/shared/AppVersionStatus.tsx b/server/sonar-web/src/main/js/components/shared/AppVersionStatus.tsx
new file mode 100644 (file)
index 0000000..91e9616
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import { FormattedMessage } from 'react-intl';
+import { useAppState } from '../../app/components/app-state/withAppStateContext';
+import { now, parseDate } from '../../helpers/dates';
+import { translate } from '../../helpers/l10n';
+import DocLink from '../common/DocLink';
+
+export default function AppVersionStatus() {
+  const { version, versionEOL } = useAppState();
+  const isActive = parseDate(versionEOL) > now();
+
+  return (
+    <FormattedMessage
+      id="footer.version"
+      defaultMessage={translate('footer.version')}
+      values={{
+        version,
+        status: (
+          <DocLink
+            to="/setup-and-upgrade/upgrade-the-server/active-versions/"
+            className="little-spacer-left"
+          >
+            {translate(`footer.version.status.${isActive ? 'active' : 'inactive'}`)}
+          </DocLink>
+        ),
+      }}
+    />
+  );
+}
diff --git a/server/sonar-web/src/main/js/components/shared/__tests__/AppVersionStatus-test.tsx b/server/sonar-web/src/main/js/components/shared/__tests__/AppVersionStatus-test.tsx
new file mode 100644 (file)
index 0000000..f60dba4
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { screen } from '@testing-library/react';
+import React from 'react';
+import AppStateContextProvider from '../../../app/components/app-state/AppStateContextProvider';
+import AppVersionStatus from '../../../components/shared/AppVersionStatus';
+import { mockAppState } from '../../../helpers/testMocks';
+import { renderComponent } from '../../../helpers/testReactTestingUtils';
+
+jest.mock('../../../helpers/dates', () => ({
+  ...jest.requireActual('../../../helpers/dates'),
+  now: () => new Date('2022-01-01'),
+}));
+
+it('should render active version if it has not reached EOL', () => {
+  renderAppVersionStatus(mockAppState({ versionEOL: '2022-01-02' }));
+
+  expect(screen.getByRole('link', { name: /footer.version.status.active/ })).toBeInTheDocument();
+});
+
+it('should render inactive version if it has reached EOL', () => {
+  renderAppVersionStatus(mockAppState({ versionEOL: '2021-12-30' }));
+
+  expect(screen.getByRole('link', { name: /footer.version.status.inactive/ })).toBeInTheDocument();
+});
+
+const renderAppVersionStatus = (appState = mockAppState()) => {
+  return renderComponent(
+    <AppStateContextProvider appState={appState}>
+      <AppVersionStatus />
+    </AppStateContextProvider>
+  );
+};
index efa1c1602a7e38a24af9c184fe9dab8183248e6a..f08cc76696341869d8b0069303a8e712d3ff9682 100644 (file)
@@ -76,6 +76,7 @@ export function mockAppState(overrides: Partial<AppState> = {}): AppState {
     qualifiers: ['TRK'],
     settings: {},
     version: '1.0',
+    versionEOL: '2022-01-01',
     ...overrides,
   };
 }
index 6d31f5b09e09ec303798ea5c8b0ccfa79d256f4f..3701a3901a1e7efc07a1d352bc8eaf0d8caa197e 100644 (file)
@@ -35,4 +35,5 @@ export interface AppState {
   standalone?: boolean;
   version: string;
   webAnalyticsJsPath?: string;
+  versionEOL: string;
 }
index fabcfb1630c7d353ea0545049377f408e483193f..30ceba145ea127526b0ed62ed32c2376ea1e64fa 100644 (file)
@@ -3531,7 +3531,9 @@ footer.security=Security
 footer.status=Status
 footer.terms=Terms
 footer.twitter=Twitter
-footer.version_x=Version {0}
+footer.version=v{version}{status}
+footer.version.status.active=ACTIVE
+footer.version.status.inactive=NO LONGER ACTIVE
 footer.web_api=Web API