]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-17096 Ability to display a system announcement to all users
authorGuillaume Peoc'h <guillaume.peoch@sonarsource.com>
Tue, 20 Sep 2022 15:31:22 +0000 (17:31 +0200)
committersonartech <sonartech@sonarsource.com>
Fri, 23 Sep 2022 07:56:36 +0000 (07:56 +0000)
server/sonar-web/src/main/js/app/components/GlobalContainer.tsx
server/sonar-web/src/main/js/app/components/SystemAnnouncement.css [new file with mode: 0644]
server/sonar-web/src/main/js/app/components/SystemAnnouncement.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/app/components/__tests__/SystemAnnouncement-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/types/settings.ts
sonar-core/src/main/java/org/sonar/core/config/CorePropertyDefinitions.java

index f9f4cecc2117099b9c6dcfcffb38fb5581377a17..f8d3c1d6012c2361259cc9d694d326b91247c262 100644 (file)
@@ -32,6 +32,7 @@ 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';
 
 export default function GlobalContainer() {
@@ -51,9 +52,10 @@ export default function GlobalContainer() {
                     <IndexationContextProvider>
                       <LanguagesContextProvider>
                         <MetricsContextProvider>
-                          <GlobalNav location={location} />
+                          <SystemAnnouncement />
                           <IndexationNotification />
                           <UpdateNotification dismissable={true} />
+                          <GlobalNav location={location} />
                           <Outlet />
                         </MetricsContextProvider>
                       </LanguagesContextProvider>
diff --git a/server/sonar-web/src/main/js/app/components/SystemAnnouncement.css b/server/sonar-web/src/main/js/app/components/SystemAnnouncement.css
new file mode 100644 (file)
index 0000000..6333b46
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.
+ */
+
+.system-announcement-wrapper {
+  height: 34px;
+}
+
+.system-announcement-banner {
+  position: fixed;
+  width: 100%;
+  z-index: var(--globalBannerZIndex);
+}
+
+.system-announcement-banner .alert-content {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
diff --git a/server/sonar-web/src/main/js/app/components/SystemAnnouncement.tsx b/server/sonar-web/src/main/js/app/components/SystemAnnouncement.tsx
new file mode 100644 (file)
index 0000000..65e630c
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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 { isEmpty, keyBy } from 'lodash';
+import * as React from 'react';
+import { getValues } from '../../api/settings';
+import { Alert } from '../../components/ui/Alert';
+import { GlobalSettingKeys, SettingValue } from '../../types/settings';
+import './SystemAnnouncement.css';
+
+interface State {
+  displayMessage: boolean;
+  message: string;
+}
+
+export default class SystemAnnouncement extends React.PureComponent<{}, State> {
+  state: State = { displayMessage: false, message: '' };
+
+  componentDidMount() {
+    this.getSettings();
+    document.addEventListener('visibilitychange', this.handleVisibilityChange);
+  }
+
+  componentWillUnmount() {
+    document.removeEventListener('visibilitychange', this.handleVisibilityChange);
+  }
+
+  getSettings = async () => {
+    const values: SettingValue[] = await getValues({
+      keys: [GlobalSettingKeys.DisplaySystemMessage, GlobalSettingKeys.SystemMessage].join(',')
+    });
+    const settings = keyBy(values, 'key');
+
+    this.setState({
+      displayMessage: settings[GlobalSettingKeys.DisplaySystemMessage].value === 'true',
+      message:
+        (settings[GlobalSettingKeys.SystemMessage] &&
+          settings[GlobalSettingKeys.SystemMessage].value) ||
+        ''
+    });
+  };
+
+  handleVisibilityChange = () => {
+    if (document.visibilityState === 'visible') {
+      this.getSettings();
+    }
+  };
+
+  render() {
+    const { displayMessage, message } = this.state;
+    if (!displayMessage || isEmpty(message)) {
+      return null;
+    }
+
+    return (
+      <div className="system-announcement-wrapper">
+        <Alert
+          className="system-announcement-banner"
+          title={message}
+          display="banner"
+          variant="warning">
+          {message}
+        </Alert>
+      </div>
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/SystemAnnouncement-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/SystemAnnouncement-test.tsx
new file mode 100644 (file)
index 0000000..cc837ef
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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 { fireEvent, screen } from '@testing-library/dom';
+import * as React from 'react';
+import { getValues } from '../../../api/settings';
+import { renderComponent } from '../../../helpers/testReactTestingUtils';
+import SystemAnnouncement from '../SystemAnnouncement';
+
+jest.mock('../../../api/settings', () => ({
+  getValues: jest.fn()
+}));
+
+it('should display system announcement', async () => {
+  (getValues as jest.Mock)
+    .mockResolvedValueOnce([
+      {
+        key: 'sonar.systemAnnouncement.displayMessage',
+        value: 'false',
+        inherited: true
+      }
+    ])
+    .mockResolvedValueOnce([
+      {
+        key: 'sonar.systemAnnouncement.displayMessage',
+        value: 'false',
+        inherited: true
+      }
+    ])
+    .mockResolvedValueOnce([
+      {
+        key: 'sonar.systemAnnouncement.displayMessage',
+        value: 'true'
+      }
+    ])
+    .mockResolvedValueOnce([
+      {
+        key: 'sonar.systemAnnouncement.displayMessage',
+        value: 'true'
+      },
+      {
+        key: 'sonar.systemAnnouncement.message',
+        value: ''
+      }
+    ])
+    .mockResolvedValueOnce([
+      {
+        key: 'sonar.systemAnnouncement.displayMessage',
+        value: 'true'
+      },
+      {
+        key: 'sonar.systemAnnouncement.message',
+        value: 'Foo'
+      }
+    ]);
+
+  renderSystemAnnouncement();
+
+  expect(screen.queryByRole('alert')).not.toBeInTheDocument();
+  fireEvent(document, new Event('visibilitychange'));
+  expect(screen.queryByRole('alert')).not.toBeInTheDocument();
+  fireEvent(document, new Event('visibilitychange'));
+  expect(screen.queryByRole('alert')).not.toBeInTheDocument();
+  fireEvent(document, new Event('visibilitychange'));
+  expect(screen.queryByRole('alert')).not.toBeInTheDocument();
+  fireEvent(document, new Event('visibilitychange'));
+  expect(await screen.findByRole('alert')).toBeInTheDocument();
+  expect(screen.getByText('Foo')).toBeInTheDocument();
+});
+
+function renderSystemAnnouncement() {
+  return renderComponent(<SystemAnnouncement />);
+}
index 9374cf76253451ba312a3edabdf57544e274b8f4..079c23e8b6cc619b3e787b85e18ae74532a3644b 100644 (file)
@@ -36,7 +36,9 @@ export enum GlobalSettingKeys {
   GravatarServerUrl = 'sonar.lf.gravatarServerUrl',
   RatingGrid = 'sonar.technicalDebt.ratingGrid',
   DeveloperAggregatedInfoDisabled = 'sonar.developerAggregatedInfo.disabled',
-  UpdatecenterActivated = 'sonar.updatecenter.activate'
+  UpdatecenterActivated = 'sonar.updatecenter.activate',
+  DisplaySystemMessage = 'sonar.systemAnnouncement.displayMessage',
+  SystemMessage = 'sonar.systemAnnouncement.message'
 }
 
 export type SettingDefinitionAndValue = {
index 985e312089585f942f6f0b6a1708fd775d15d3eb..397314d3c17c36c60c13b93740796c1d16ad1720 100644 (file)
@@ -94,14 +94,15 @@ public class CorePropertyDefinitions {
         .build(),
       PropertyDefinition.builder(SYSTEM_ANNOUNCEMENT_MESSAGE)
         .name("System announcement message")
-        .description("If \"Display system announcement message\" is set to True, this message will be displayed in a banner to all authenticate SonarQube users.")
+        .description("If \"Display system announcement message\" is set to True, this message will be displayed in a warning banner to all SonarQube users."
+          +" If this field is empty, no message will be displayed, even if \"Display system announcement message\" is set to True.")
         .category(CoreProperties.CATEGORY_GENERAL)
         .subCategory(SUB_SYSTEM_ANNOUNCEMENT)
         .type(TEXT)
         .build(),
       PropertyDefinition.builder(SYSTEM_ANNOUNCEMENT_DISPLAY_MESSAGE)
         .name("Display system announcement message")
-        .description("If set to True, the \"System announcement message\" will be displayed in a banner to all authenticate SonarQube users.")
+        .description("If set to True, the \"System announcement message\" will be displayed in a warning banner to all SonarQube users.")
         .defaultValue(Boolean.toString(false))
         .subCategory(SUB_SYSTEM_ANNOUNCEMENT)
         .category(CoreProperties.CATEGORY_GENERAL)