From d799b351ab5a2f529fff0d607b7fa4de1678d3ab Mon Sep 17 00:00:00 2001 From: Ismail Cherri Date: Fri, 16 Aug 2024 18:11:00 +0300 Subject: [PATCH] SONAR-22708 Add calculation change banner on projects and portfolios --- .../js/app/components/GlobalContainer.tsx | 6 +- .../CalculationChangeMessage-test.tsx | 86 +++++++++++++++++++ .../CalculationChangeMessage.tsx | 60 +++++++++++++ .../js/components/ui/DismissableAlert.tsx | 2 + .../resources/org/sonar/l10n/core.properties | 3 +- 5 files changed, 154 insertions(+), 3 deletions(-) create mode 100644 server/sonar-web/src/main/js/app/components/__tests__/CalculationChangeMessage-test.tsx create mode 100644 server/sonar-web/src/main/js/app/components/calculation-notification/CalculationChangeMessage.tsx diff --git a/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx b/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx index 022125a7d71..0944705d8de 100644 --- a/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx @@ -28,15 +28,16 @@ import A11ySkipLinks from '~sonar-aligned/components/a11y/A11ySkipLinks'; import SuggestionsProvider from '../../components/embed-docs-modal/SuggestionsProvider'; import NCDAutoUpdateMessage from '../../components/new-code-definition/NCDAutoUpdateMessage'; import Workspace from '../../components/workspace/Workspace'; +import CalculationChangeMessage from './calculation-notification/CalculationChangeMessage'; import GlobalFooter from './GlobalFooter'; -import StartupModal from './StartupModal'; -import SystemAnnouncement from './SystemAnnouncement'; import IndexationContextProvider from './indexation/IndexationContextProvider'; import IndexationNotification from './indexation/IndexationNotification'; import LanguagesContextProvider from './languages/LanguagesContextProvider'; import MetricsContextProvider from './metrics/MetricsContextProvider'; import GlobalNav from './nav/global/GlobalNav'; import PromotionNotification from './promotion-notification/PromotionNotification'; +import StartupModal from './StartupModal'; +import SystemAnnouncement from './SystemAnnouncement'; import UpdateNotification from './update-notification/UpdateNotification'; /* @@ -98,6 +99,7 @@ export default function GlobalContainer() { + {/* The following is the portal anchor point for the component nav * See ComponentContainer.tsx */} diff --git a/server/sonar-web/src/main/js/app/components/__tests__/CalculationChangeMessage-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/CalculationChangeMessage-test.tsx new file mode 100644 index 00000000000..db90f56b6f1 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/__tests__/CalculationChangeMessage-test.tsx @@ -0,0 +1,86 @@ +/* + * 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 React from 'react'; +import { Outlet, Route } from 'react-router-dom'; +import { byRole, byText } from '~sonar-aligned/helpers/testSelector'; +import { ComponentQualifier } from '~sonar-aligned/types/component'; +import SettingsServiceMock from '../../../api/mocks/SettingsServiceMock'; +import { renderAppRoutes } from '../../../helpers/testReactTestingUtils'; +import { SettingsKey } from '../../../types/settings'; +import CalculationChangeMessage from '../calculation-notification/CalculationChangeMessage'; + +const ui = { + alert: byRole('alert'), + learnMoreLink: byRole('link', { name: 'learn_more open_in_new_tab' }), + + alertText: (qualifier: string) => byText(`notification.calculation_change.message.${qualifier}`), +}; + +const settingsHandler = new SettingsServiceMock(); + +beforeEach(() => { + settingsHandler.reset(); +}); + +it.each([ + ['Project', '/projects', ComponentQualifier.Project], + ['Portfolios', '/portfolios', ComponentQualifier.Portfolio], +])('should render on %s page', (_, path, qualifier) => { + render(path); + expect(ui.alert.get()).toBeInTheDocument(); + expect(ui.alertText(qualifier).get()).toBeInTheDocument(); + expect(ui.learnMoreLink.get()).toBeInTheDocument(); +}); + +it.each([ + ['Project', '/projects', ComponentQualifier.Project], + ['Portfolios', '/portfolios', ComponentQualifier.Portfolio], +])('should not render on %s page if isLegacy', (_, path, qualifier) => { + settingsHandler.set(SettingsKey.LegacyMode, 'true'); + render(path); + expect(ui.alert.get()).toBeInTheDocument(); + expect(ui.alertText(qualifier).get()).toBeInTheDocument(); + expect(ui.learnMoreLink.get()).toBeInTheDocument(); +}); + +it('should not render on other page', () => { + render('/other'); + expect(ui.alert.query()).not.toBeInTheDocument(); + expect(ui.alertText(ComponentQualifier.Project).query()).not.toBeInTheDocument(); + expect(ui.learnMoreLink.query()).not.toBeInTheDocument(); +}); + +function render(indexPath = '/projects') { + renderAppRoutes(indexPath, () => ( + + + + + } + > + Projects} /> + Portfolios} /> + Other page} /> + + )); +} diff --git a/server/sonar-web/src/main/js/app/components/calculation-notification/CalculationChangeMessage.tsx b/server/sonar-web/src/main/js/app/components/calculation-notification/CalculationChangeMessage.tsx new file mode 100644 index 00000000000..34e97a11306 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/calculation-notification/CalculationChangeMessage.tsx @@ -0,0 +1,60 @@ +/* + * 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 React from 'react'; +import { FormattedMessage } from 'react-intl'; +import { useLocation } from '~sonar-aligned/components/hoc/withRouter'; +import { ComponentQualifier } from '~sonar-aligned/types/component'; +import DocumentationLink from '../../../components/common/DocumentationLink'; +import DismissableAlert from '../../../components/ui/DismissableAlert'; +import { DocLink } from '../../../helpers/doc-links'; +import { translate } from '../../../helpers/l10n'; +import { useIsLegacyCCTMode } from '../../../queries/settings'; +import { Dict } from '../../../types/types'; + +const SHOW_MESSAGE_PATHS: Dict = { + '/projects': ComponentQualifier.Project, + '/portfolios': ComponentQualifier.Portfolio, +}; + +const ALERT_KEY = 'sonarqube.dismissed_calculation_change_alert'; + +export default function CalculationChangeMessage() { + const location = useLocation(); + const { data: isLegacy } = useIsLegacyCCTMode(); + + if (isLegacy || !Object.keys(SHOW_MESSAGE_PATHS).includes(location.pathname)) { + return null; + } + + return ( + + + {translate('learn_more')} + + ), + }} + /> + + ); +} diff --git a/server/sonar-web/src/main/js/components/ui/DismissableAlert.tsx b/server/sonar-web/src/main/js/components/ui/DismissableAlert.tsx index 60f76ff541c..f3e0125f092 100644 --- a/server/sonar-web/src/main/js/components/ui/DismissableAlert.tsx +++ b/server/sonar-web/src/main/js/components/ui/DismissableAlert.tsx @@ -38,6 +38,8 @@ export default function DismissableAlert(props: DismissableAlertProps) { React.useEffect(() => { if (get(DISMISSED_ALERT_STORAGE_KEY, alertKey) !== 'true') { setShow(true); + } else { + setShow(false); } }, [alertKey]); diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 3463c9e1c22..41ac785abeb 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -2705,6 +2705,8 @@ notification.dispatcher.SQ-MyNewIssues=My new issues notification.dispatcher.CeReportTaskFailure=Background tasks in failure on my administered projects notification.dispatcher.CeReportTaskFailure.project=Background tasks in failure notification.dispatcher.description_x=Check to receive notification for {0} +notification.calculation_change.message.TRK=The way we calculate ratings has changed and it might affect your security, reliability, maintainability and security review ratings. {link} +notification.calculation_change.message.VW=The way we calculate ratings has changed and it might affect your releasability, security, reliability, maintainability and security review ratings. {link} #------------------------------------------------------------------------------ # @@ -2725,7 +2727,6 @@ alert.tooltip.info=This is an info message. alert.dismiss=Dismiss this message - #------------------------------------------------------------------------------ # # USER -- 2.39.5