]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9802 Apply UI feedback
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>
Mon, 25 Sep 2017 12:38:35 +0000 (14:38 +0200)
committerSimon Brandhof <simon.brandhof@sonarsource.com>
Tue, 26 Sep 2017 21:49:38 +0000 (23:49 +0200)
* Add tooltips on health status

* Replace boolean icons with black check and close icons

* Move log level warning next to the title of the card

* Hide Plugins section

* Retrieve correctly log levels when sections are missing.

* Display State fields as Health status

* Update IT

16 files changed:
server/sonar-web/src/main/js/apps/system/__tests__/utils-test.ts
server/sonar-web/src/main/js/apps/system/components/info-items/HealthCard.tsx
server/sonar-web/src/main/js/apps/system/components/info-items/HealthItem.tsx
server/sonar-web/src/main/js/apps/system/components/info-items/SysInfoItem.tsx
server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthItem-test.tsx
server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/SysInfoItem-test.tsx
server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/__snapshots__/HealthCard-test.tsx.snap
server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/__snapshots__/HealthItem-test.tsx.snap
server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/__snapshots__/SysInfoItem-test.tsx.snap
server/sonar-web/src/main/js/apps/system/styles.css
server/sonar-web/src/main/js/apps/system/utils.ts
server/sonar-web/src/main/js/components/icons-components/CheckIcon.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/components/icons-components/CloseIcon.js [deleted file]
server/sonar-web/src/main/js/components/icons-components/CloseIcon.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/components/icons-components/icons.js
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index b1e915f037051be46e85ac0976f978220d51da37..98cea1804e52b9aa451fea518d64c60e1f689539 100644 (file)
@@ -67,4 +67,20 @@ describe('getSystemLogsLevel', () => {
       } as ClusterSysInfo)
     ).toBe('DEBUG');
   });
+
+  it('should not fail if the log informations are not there yet', () => {
+    expect(
+      u.getSystemLogsLevel({
+        System: { 'High Availability': true },
+        'Application Nodes': [{ Name: 'App 1' }, { Name: 'App 2' }]
+      } as ClusterSysInfo)
+    ).toBe('INFO');
+    expect(
+      u.getSystemLogsLevel({
+        System: { 'High Availability': true },
+        'Application Nodes': [{ 'Compute Engine Logging': {} }, { Name: 'App 2' }]
+      } as ClusterSysInfo)
+    ).toBe('INFO');
+    expect(u.getSystemLogsLevel({ System: {} } as SysInfo)).toBe('INFO');
+  });
 });
index ff49fc75a833bfca2d81e618da81a8e527d3da89..ec8372f5802a65fa49315ab59ddf452d33fd5f77 100644 (file)
@@ -65,19 +65,20 @@ export default class HealthCard extends React.PureComponent<Props, State> {
             <OpenCloseIcon className="little-spacer-right" open={open} />
             {this.props.name}
           </span>
+          {showLogLevelWarning && (
+            <span className="alert alert-danger spacer-left">
+              {translate('system.log_level.warning.short')}
+            </span>
+          )}
           {health && (
             <HealthItem
               biggerHealth={this.props.biggerHealth}
-              className="pull-right spacer-left"
+              className="pull-right"
               health={health}
               healthCauses={this.props.healthCauses}
+              name={this.props.name}
             />
           )}
-          {showLogLevelWarning && (
-            <span className="pull-right alert alert-danger">
-              {translate('system.log_level.warning.short')}
-            </span>
-          )}
         </div>
         {open && (
           <div
index 2edc10805e00e5ba89a45fdfc9437e93d2c1196f..933aa13b01a4868421a1a13c387add62449c9418 100644 (file)
@@ -21,24 +21,38 @@ import * as React from 'react';
 import * as classNames from 'classnames';
 import HealthCauseItem from './HealthCauseItem';
 import StatusIndicator from '../../../../components/common/StatusIndicator';
+import Tooltip from '../../../../components/controls/Tooltip';
 import { HealthType } from '../../../../api/system';
+import { translateWithParameters } from '../../../../helpers/l10n';
 
 interface Props {
   biggerHealth?: boolean;
+  name?: string;
   className?: string;
   health: HealthType;
   healthCauses?: string[];
 }
 
-export default function HealthItem({ biggerHealth, className, health, healthCauses }: Props) {
+export default function HealthItem({ biggerHealth, className, name, health, healthCauses }: Props) {
   const hasHealthCauses = healthCauses && healthCauses.length > 0 && health !== HealthType.GREEN;
+  const statusIndicator = (
+    <StatusIndicator color={health.toLowerCase()} size={biggerHealth ? 'big' : undefined} />
+  );
   return (
     <div className={classNames('system-info-health-info', className)}>
       {hasHealthCauses &&
         healthCauses!.map((cause, idx) => (
           <HealthCauseItem key={idx} className="spacer-right" health={health} healthCause={cause} />
         ))}
-      <StatusIndicator color={health.toLowerCase()} size={biggerHealth ? 'big' : undefined} />
+      {name ? (
+        <Tooltip
+          overlay={translateWithParameters('system.current_health_of_x', name)}
+          placement="left">
+          <span>{statusIndicator}</span>
+        </Tooltip>
+      ) : (
+        statusIndicator
+      )}
     </div>
   );
 }
index 12876d75940d57bc90b79b69f5a3dfcfd44a2232..bd1751ec61eb1f5cc3bb0f6b481498f44a815301 100644 (file)
@@ -19,6 +19,8 @@
  */
 import * as React from 'react';
 import { map } from 'lodash';
+import CheckIcon from '../../../../components/icons-components/CheckIcon';
+import CloseIcon from '../../../../components/icons-components/CloseIcon';
 import HealthItem from './HealthItem';
 import { HealthType, SysValue, SysValueObject } from '../../../../api/system';
 import { HEALTH_FIELD } from '../../utils';
@@ -29,7 +31,7 @@ interface Props {
 }
 
 export default function SysInfoItem({ name, value }: Props): JSX.Element {
-  if (name === HEALTH_FIELD) {
+  if (name === HEALTH_FIELD || name === 'State') {
     return <HealthItem className="no-margin" health={value as HealthType} />;
   }
   if (value instanceof Array) {
@@ -47,9 +49,9 @@ export default function SysInfoItem({ name, value }: Props): JSX.Element {
 
 function BooleanItem({ value }: { value: boolean }) {
   if (value) {
-    return <i className="icon-check" />;
+    return <CheckIcon />;
   } else {
-    return <i className="icon-delete" />;
+    return <CloseIcon />;
   }
 }
 
index 7f21d999a4e93fc3e01b05eb4c0414881b54adb3..5476278f613c0edcc86436cb439abb40523ad4ab 100644 (file)
@@ -24,7 +24,9 @@ import { HealthType } from '../../../../../api/system';
 
 it('should render correctly', () => {
   expect(
-    shallow(<HealthItem biggerHealth={true} health={HealthType.RED} healthCauses={['foo']} />)
+    shallow(
+      <HealthItem biggerHealth={true} name="Foo" health={HealthType.RED} healthCauses={['foo']} />
+    )
   ).toMatchSnapshot();
 });
 
index 2761a2ddbf983c7a393355a092fe654a3bfae09e..acbf8d43ab9e739a30e929575c9a84704959fe0f 100644 (file)
@@ -51,10 +51,10 @@ it('should render object correctly', () => {
 
 it('should render `true`', () => {
   const wrapper = mount(<SysInfoItem name="test" value={true} />);
-  expect(wrapper.find('.icon-check')).toHaveLength(1);
+  expect(wrapper.find('CheckIcon')).toHaveLength(1);
 });
 
 it('should render `false`', () => {
   const wrapper = mount(<SysInfoItem name="test" value={false} />);
-  expect(wrapper.find('.icon-delete')).toHaveLength(1);
+  expect(wrapper.find('CloseIcon')).toHaveLength(1);
 });
index 6c054721b70be7eca0441c2387ea47986cb129f3..77afaf39ea2e623b282fd0c32c5e7c1f096f2b77 100644 (file)
@@ -2,7 +2,7 @@
 
 exports[`should display the log level alert 1`] = `
 <span
-  className="pull-right alert alert-danger"
+  className="alert alert-danger spacer-left"
 >
   system.log_level.warning.short
 </span>
@@ -27,13 +27,14 @@ exports[`should display the sysinfo detail 1`] = `
     </span>
     <HealthItem
       biggerHealth={true}
-      className="pull-right spacer-left"
+      className="pull-right"
       health="RED"
       healthCauses={
         Array [
           "foo",
         ]
       }
+      name="Foobar"
     />
   </div>
   <div
@@ -63,13 +64,14 @@ exports[`should render correctly 1`] = `
     </span>
     <HealthItem
       biggerHealth={false}
-      className="pull-right spacer-left"
+      className="pull-right"
       health="RED"
       healthCauses={
         Array [
           "foo",
         ]
       }
+      name="Foobar"
     />
   </div>
 </li>
@@ -94,13 +96,14 @@ exports[`should show a main section and multiple sub sections 1`] = `
     </span>
     <HealthItem
       biggerHealth={false}
-      className="pull-right spacer-left"
+      className="pull-right"
       health="RED"
       healthCauses={
         Array [
           "foo",
         ]
       }
+      name="Foobar"
     />
   </div>
   <div
index eafb250bdd15b5fb2252871a109323bf92af59a5..81f4aa9ba6a85db347c3ae177e5faed2cd90d40d 100644 (file)
@@ -29,10 +29,17 @@ exports[`should render correctly 1`] = `
     health="RED"
     healthCause="foo"
   />
-  <StatusIndicator
-    color="red"
-    size="big"
-  />
+  <Tooltip
+    overlay="system.current_health_of_x.Foo"
+    placement="left"
+  >
+    <span>
+      <StatusIndicator
+        color="red"
+        size="big"
+      />
+    </span>
+  </Tooltip>
 </div>
 `;
 
index a1ff67c3506115412443604b69e12d4de25bf096..b02b9854bdf641e33b5fa5202e85fbbed2775b8e 100644 (file)
@@ -117,9 +117,24 @@ Array [
                         <BooleanItem
                             value={true}
                         >
-                            <i
-                                className="icon-check"
-                            />
+                            <CheckIcon>
+                                <svg
+                                    height={16}
+                                    viewBox="0 0 16 16"
+                                    width={16}
+                                    xmlns="http://www.w3.org/2000/svg"
+                                >
+                                    <path
+                                        d="M14.92 4.804q0 0.357-0.25 0.607l-7.679 7.679q-0.25 0.25-0.607 0.25t-0.607-0.25l-4.446-4.446q-0.25-0.25-0.25-0.607t0.25-0.607l1.214-1.214q0.25-0.25 0.607-0.25t0.607 0.25l2.625 2.634 5.857-5.866q0.25-0.25 0.607-0.25t0.607 0.25l1.214 1.214q0.25 0.25 0.25 0.607z"
+                                        style={
+                                            Object {
+                                                "fill": "currentColor",
+                                              }
+                                        }
+                                    />
+                                    ;
+                                </svg>
+                            </CheckIcon>
                         </BooleanItem>
                     </SysInfoItem>
                 </td>
index f34dc3fa3940420aa13b308c6974e41e34bb820a..e9b584381492a45254357d96225b5cbd0c3f1970 100644 (file)
@@ -22,7 +22,9 @@
 }
 
 .system-info-health-card .boxed-group-header > .alert {
-  margin-top: -6px;
+  display: inline-block;
+  margin-bottom: -3px;
+  margin-top: -3px;
 }
 
 .system-info-health-card .boxed-group-inner {
index 5d98c9e74f83baebde48df064bb04d1cee963bc9..5514ae4e70568a89248a9fcfdaf7b4013ddfdab5 100644 (file)
@@ -42,9 +42,11 @@ export const LOGS_LEVELS = ['INFO', 'DEBUG', 'TRACE'];
 export const HA_FIELD = 'High Availability';
 export const HEALTH_FIELD = 'Health';
 export const HEALTHCAUSES_FIELD = 'Health Causes';
+export const PLUGINS_FIELD = 'Plugins';
+export const SETTINGS_FIELD = 'Settings';
 
 export function ignoreInfoFields(sysInfoObject: SysValueObject): SysValueObject {
-  return omit(sysInfoObject, [HEALTH_FIELD, HEALTHCAUSES_FIELD, 'Name', 'Settings']);
+  return omit(sysInfoObject, [HEALTH_FIELD, HEALTHCAUSES_FIELD, 'Name', SETTINGS_FIELD]);
 }
 
 export function getHealth(sysInfoObject: SysValueObject): HealthType {
@@ -55,18 +57,21 @@ export function getHealthCauses(sysInfoObject: SysValueObject): string[] {
   return sysInfoObject[HEALTHCAUSES_FIELD] as string[];
 }
 
-export function getLogsLevel(sysInfoObject: SysValueObject): string {
-  if (sysInfoObject['Web Logging']) {
+export function getLogsLevel(sysInfoObject?: SysValueObject): string {
+  if (!sysInfoObject) {
+    return LOGS_LEVELS[0];
+  }
+  if (sysInfoObject['Web Logging'] || sysInfoObject['Compute Engine Logging']) {
     return sortBy(
       [
-        (sysInfoObject as NodeInfo)['Compute Engine Logging']['Logs Level'],
-        (sysInfoObject as NodeInfo)['Web Logging']['Logs Level']
+        getLogsLevel((sysInfoObject as NodeInfo)['Web Logging']),
+        getLogsLevel((sysInfoObject as NodeInfo)['Compute Engine Logging'])
       ],
       logLevel => LOGS_LEVELS.indexOf(logLevel)
     )[1];
   }
   if (sysInfoObject['System']) {
-    return (sysInfoObject as SysInfo)['System']['Logs Level'];
+    return getLogsLevel((sysInfoObject as SysInfo)['System']);
   }
   return (sysInfoObject['Logs Level'] || LOGS_LEVELS[0]) as string;
 }
@@ -110,9 +115,9 @@ export function getClusterMainCardSection(sysInfoData: ClusterSysInfo): SysValue
     ...sysInfoData['System'],
     ...omit(sysInfoData, [
       'Application Nodes',
-      'Plugins',
+      PLUGINS_FIELD,
       'Search Nodes',
-      'Settings',
+      SETTINGS_FIELD,
       'Statistics',
       'System'
     ])
@@ -126,7 +131,7 @@ export function getStandaloneMainSections(sysInfoData: SysInfo): SysValueObject
       sysInfoData,
       (value, key) =>
         value == null ||
-        ['Plugins', 'Settings', 'Statistics', 'System'].includes(key) ||
+        [PLUGINS_FIELD, SETTINGS_FIELD, 'Statistics', 'System'].includes(key) ||
         key.startsWith('Compute Engine') ||
         key.startsWith('Search') ||
         key.startsWith('Web')
diff --git a/server/sonar-web/src/main/js/components/icons-components/CheckIcon.tsx b/server/sonar-web/src/main/js/components/icons-components/CheckIcon.tsx
new file mode 100644 (file)
index 0000000..487fac7
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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';
+
+interface Props {
+  className?: string;
+  size?: number;
+}
+
+export default function CheckIcon({ className, size = 16 }: Props) {
+  return (
+    <svg
+      className={className}
+      xmlns="http://www.w3.org/2000/svg"
+      viewBox="0 0 16 16"
+      width={size}
+      height={size}>
+      <path
+        style={{ fill: 'currentColor' }}
+        d="M14.92 4.804q0 0.357-0.25 0.607l-7.679 7.679q-0.25 0.25-0.607 0.25t-0.607-0.25l-4.446-4.446q-0.25-0.25-0.25-0.607t0.25-0.607l1.214-1.214q0.25-0.25 0.607-0.25t0.607 0.25l2.625 2.634 5.857-5.866q0.25-0.25 0.607-0.25t0.607 0.25l1.214 1.214q0.25 0.25 0.25 0.607z"
+      />;
+    </svg>
+  );
+}
diff --git a/server/sonar-web/src/main/js/components/icons-components/CloseIcon.js b/server/sonar-web/src/main/js/components/icons-components/CloseIcon.js
deleted file mode 100644 (file)
index 7fb48b8..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 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.
- */
-// @flow
-import React from 'react';
-
-/*::
-type Props = { className?: string, size?: number };
-*/
-
-export default function CloseIcon({ className, size = 16 } /*: Props */) {
-  /* eslint-disable max-len */
-  return (
-    <svg
-      xmlns="http://www.w3.org/2000/svg"
-      className={className}
-      height={size}
-      width={size}
-      viewBox="0 0 16 16">
-      <path
-        fill="currentColor"
-        d="M12.843 11.232q0 0.357-0.25 0.607l-1.214 1.214q-0.25 0.25-0.607 0.25t-0.607-0.25l-2.625-2.625-2.625 2.625q-0.25 0.25-0.607 0.25t-0.607-0.25l-1.214-1.214q-0.25-0.25-0.25-0.607t0.25-0.607l2.625-2.625-2.625-2.625q-0.25-0.25-0.25-0.607t0.25-0.607l1.214-1.214q0.25-0.25 0.607-0.25t0.607 0.25l2.625 2.625 2.625-2.625q0.25-0.25 0.607-0.25t0.607 0.25l1.214 1.214q0.25 0.25 0.25 0.607t-0.25 0.607l-2.625 2.625 2.625 2.625q0.25 0.25 0.25 0.607z"
-      />
-    </svg>
-  );
-}
diff --git a/server/sonar-web/src/main/js/components/icons-components/CloseIcon.tsx b/server/sonar-web/src/main/js/components/icons-components/CloseIcon.tsx
new file mode 100644 (file)
index 0000000..5ab5393
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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';
+
+interface Props {
+  className?: string;
+  size?: number;
+}
+
+export default function CloseIcon({ className, size = 16 }: Props) {
+  return (
+    <svg
+      xmlns="http://www.w3.org/2000/svg"
+      className={className}
+      height={size}
+      width={size}
+      viewBox="0 0 16 16">
+      <path
+        fill="currentColor"
+        d="M12.843 11.232q0 0.357-0.25 0.607l-1.214 1.214q-0.25 0.25-0.607 0.25t-0.607-0.25l-2.625-2.625-2.625 2.625q-0.25 0.25-0.607 0.25t-0.607-0.25l-1.214-1.214q-0.25-0.25-0.25-0.607t0.25-0.607l2.625-2.625-2.625-2.625q-0.25-0.25-0.25-0.607t0.25-0.607l1.214-1.214q0.25-0.25 0.607-0.25t0.607 0.25l2.625 2.625 2.625-2.625q0.25-0.25 0.607-0.25t0.607 0.25l1.214 1.214q0.25 0.25 0.25 0.607t-0.25 0.607l-2.625 2.625 2.625 2.625q0.25 0.25 0.25 0.607z"
+      />
+    </svg>
+  );
+}
index c50065921f44100da4ffa1a92a6cb9d53e6a86f5..407323488ae60061d58cd3b555039f35c8bc96a3 100644 (file)
@@ -23,6 +23,7 @@ import _BubblesIcon from './BubblesIcon';
 import _BugIcon from './BugIcon';
 import _ChangeIcon from './ChangeIcon';
 import _ChartLegendIcon from './ChartLegendIcon';
+import _CheckIcon from './CheckIcon';
 import _CloseIcon from './CloseIcon';
 import _CodeSmellIcon from './CodeSmellIcon';
 import _DeleteIcon from './DeleteIcon';
@@ -45,6 +46,7 @@ export const BubblesIcon = _BubblesIcon;
 export const BugIcon = _BugIcon;
 export const ChangeIcon = _ChangeIcon;
 export const ChartLegendIcon = _ChartLegendIcon;
+export const CheckIcon = _CheckIcon;
 export const CloseIcon = _CloseIcon;
 export const CodeSmellIcon = _CodeSmellIcon;
 export const DeleteIcon = _DeleteIcon;
index 377cec174a193c08ad5dcc5a5d42b626156199bc..f4831a7f68f79c26ac9fcef6e5bf691c9256d512 100644 (file)
@@ -2844,6 +2844,7 @@ background_tasks.add_more_with_governance=Add more with Governance
 system.application_nodes_title=Application Nodes
 system.are_you_sure_to_restart=Are you sure you want to restart the server?
 system.cluster_log_level.info=Changes apply to all Application nodes but not to Search nodes.
+system.current_health_of_x=Current health status of {1}
 system.download_logs=Download Logs
 system.download_system_info=Download System Info
 system.is_restarting=Server is restarting. This page will be automatically refreshed.