]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10611 use new help tooltips across the app (#203)
authorStas Vilchik <stas.vilchik@sonarsource.com>
Wed, 2 May 2018 15:41:34 +0000 (17:41 +0200)
committerSonarTech <sonartech@sonarsource.com>
Thu, 3 May 2018 18:20:51 +0000 (20:20 +0200)
78 files changed:
server/sonar-docs/src/tooltips/branches/no-branch-support.md [new file with mode: 0644]
server/sonar-docs/src/tooltips/branches/single-branch.md [new file with mode: 0644]
server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/QualityProfilePage.java
server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopup.tsx
server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopupHelper.tsx
server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx
server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/__snapshots__/EmbedDocsPopup-test.tsx.snap
server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranch.tsx
server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranchesMenu.tsx
server/sonar-web/src/main/js/app/components/nav/component/NoBranchSupportPopup.tsx [deleted file]
server/sonar-web/src/main/js/app/components/nav/component/SingleBranchHelperPopup.tsx [deleted file]
server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBranch-test.tsx
server/sonar-web/src/main/js/app/components/nav/component/__tests__/NoBranchSupportPopup-test.tsx [deleted file]
server/sonar-web/src/main/js/app/components/nav/component/__tests__/SingleBranchHelperPopup-test.tsx [deleted file]
server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBranch-test.tsx.snap
server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBranchesMenu-test.tsx.snap
server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/NoBranchSupportPopup-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/SingleBranchHelperPopup-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx
server/sonar-web/src/main/js/app/styles/init/icons.css
server/sonar-web/src/main/js/app/utils/exposeLibraries.ts
server/sonar-web/src/main/js/apps/background-tasks/components/NoWorkersSupportPopup.tsx
server/sonar-web/src/main/js/apps/background-tasks/components/Workers.tsx
server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/Workers-test.tsx.snap
server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.js
server/sonar-web/src/main/js/apps/documentation/components/App.tsx
server/sonar-web/src/main/js/apps/documentation/styles.css [new file with mode: 0644]
server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx
server/sonar-web/src/main/js/apps/overview/qualityGate/QualityGate.js
server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/QualityGate-test.js.snap
server/sonar-web/src/main/js/apps/permission-templates/components/ListHeader.js
server/sonar-web/src/main/js/apps/permissions/shared/components/PermissionHeader.tsx
server/sonar-web/src/main/js/apps/permissions/styles.css
server/sonar-web/src/main/js/apps/projectBranches/components/App.tsx
server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/App-test.tsx.snap
server/sonar-web/src/main/js/apps/projects/visualizations/Risk.tsx
server/sonar-web/src/main/js/apps/projects/visualizations/SimpleBubbleChart.tsx
server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Risk-test.tsx.snap
server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/SimpleBubbleChart-test.tsx.snap
server/sonar-web/src/main/js/apps/projectsManagement/Search.tsx
server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Search-test.tsx.snap
server/sonar-web/src/main/js/apps/quality-gates/components/BuiltInQualityGateBadge.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/DetailsHeader.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/List.js
server/sonar-web/src/main/js/apps/quality-profiles/components/BuiltInQualityProfileBadge.tsx
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritanceBox.tsx
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesDeprecatedWarning.tsx
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesSonarWayComparison.tsx
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesDeprecatedWarning-test.tsx.snap
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesSonarWayComparison-test.tsx.snap
server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.tsx
server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.css
server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.tsx
server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/OAuthProviders-test.tsx.snap
server/sonar-web/src/main/js/apps/web-api/components/Search.tsx
server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Search-test.tsx.snap
server/sonar-web/src/main/js/apps/webhooks/components/PageHeader.tsx
server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/PageHeader-test.tsx.snap
server/sonar-web/src/main/js/components/common/BranchStatus.tsx
server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/BranchStatus-test.tsx.snap
server/sonar-web/src/main/js/components/controls/HelpTooltip.css [new file with mode: 0644]
server/sonar-web/src/main/js/components/controls/HelpTooltip.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/components/controls/Popup.tsx [deleted file]
server/sonar-web/src/main/js/components/controls/Tooltip.css
server/sonar-web/src/main/js/components/controls/Tooltip.tsx
server/sonar-web/src/main/js/components/controls/__tests__/Tooltip-test.tsx
server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Tooltip-test.tsx.snap
server/sonar-web/src/main/js/components/docs/DocImg.tsx
server/sonar-web/src/main/js/components/docs/DocInclude.tsx
server/sonar-web/src/main/js/components/docs/DocLink.tsx
server/sonar-web/src/main/js/components/docs/DocTooltip.tsx
server/sonar-web/src/main/js/components/docs/__tests__/DocTooltip-test.tsx
server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocLink-test.tsx.snap
server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltip-test.tsx.snap
server/sonar-web/src/main/js/components/facet/FacetHeader.tsx
server/sonar-web/src/main/js/components/facet/__tests__/__snapshots__/FacetHeader-test.tsx.snap
server/sonar-web/src/main/js/components/icons-components/HelpIcon.tsx
sonar-core/src/main/resources/org/sonar/l10n/core.properties

diff --git a/server/sonar-docs/src/tooltips/branches/no-branch-support.md b/server/sonar-docs/src/tooltips/branches/no-branch-support.md
new file mode 100644 (file)
index 0000000..8285421
--- /dev/null
@@ -0,0 +1,7 @@
+**Get the most out of SonarQube with branches analysis**
+
+Analyze each branch of your project separately with the Developer Edition.
+
+---
+
+[Learn More](https://redirect.sonarsource.com/editions/developer.html)
diff --git a/server/sonar-docs/src/tooltips/branches/single-branch.md b/server/sonar-docs/src/tooltips/branches/single-branch.md
new file mode 100644 (file)
index 0000000..c4184a2
--- /dev/null
@@ -0,0 +1,7 @@
+**Learn how to analyze branches in SonarQube**
+
+Quickly setup branch analysis and get separate insights for each of your branches and pull requests.
+
+---
+
+[Branches Documentation](/branches/index)
index 9dbb657f824458bd81ba9d555e6d66831307b95c..2184ce4a581b6704893fcedf18a217d092ce45f3 100644 (file)
@@ -30,13 +30,13 @@ public class QualityProfilePage {
   public QualityProfilePage shouldHaveMissingSonarWayRules(Integer nbRules) {
     Selenide.$(".quality-profile-rules-sonarway-missing")
       .shouldBe(Condition.visible)
-      .$("a").shouldHave(Condition.text(nbRules.toString()));
+      .shouldHave(Condition.text(nbRules.toString()));
     return this;
   }
 
   public RulesPage showMissingSonarWayRules() {
     Selenide.$(".quality-profile-rules-sonarway-missing")
-      .shouldBe(Condition.visible).$("a").click();
+      .shouldBe(Condition.visible).$("[data-test=\"rules\"]").click();
     return Selenide.page(RulesPage.class);
   }
 
index ac864c7dea10d3f7ca0d4816f85a1ff0b527c013..637a95e3fca45fd820ecff9aa7cffff3e3fa2ed6 100644 (file)
@@ -21,11 +21,13 @@ import * as React from 'react';
 import * as PropTypes from 'prop-types';
 import { Link } from 'react-router';
 import { SuggestionLink } from './SuggestionsProvider';
+import { CurrentUser, isLoggedIn } from '../../types';
 import BubblePopup, { BubblePopupPosition } from '../../../components/common/BubblePopup';
 import { translate } from '../../../helpers/l10n';
 import { getBaseUrl } from '../../../helpers/urls';
 
 interface Props {
+  currentUser: CurrentUser;
   onClose: () => void;
   popupPosition?: BubblePopupPosition;
   suggestions: Array<SuggestionLink>;
@@ -93,6 +95,7 @@ export default class EmbedDocsPopup extends React.PureComponent<Props> {
             translate('embed_docs.contact_form')
           )}
         </li>
+        <li className="divider" />
         {this.renderTitle(translate('embed_docs.stay_connected'))}
         <li>
           {this.renderIconLink('https://about.sonarcloud.io/news/', 'sc-icon.svg', 'Product News')}
@@ -107,11 +110,13 @@ export default class EmbedDocsPopup extends React.PureComponent<Props> {
   renderSonarQubeLinks() {
     return (
       <React.Fragment>
-        <li>
-          <a href="#" onClick={this.onAnalyzeProjectClick}>
-            {translate('embed_docs.analyze_new_project')}
-          </a>
-        </li>
+        {isLoggedIn(this.props.currentUser) && (
+          <li>
+            <a href="#" onClick={this.onAnalyzeProjectClick}>
+              {translate('embed_docs.analyze_new_project')}
+            </a>
+          </li>
+        )}
         <li className="divider" />
         {this.renderTitle(translate('embed_docs.get_support'))}
         <li>
@@ -128,6 +133,7 @@ export default class EmbedDocsPopup extends React.PureComponent<Props> {
             'Stack Overflow'
           )}
         </li>
+        <li className="divider" />
         {this.renderTitle(translate('embed_docs.stay_connected'))}
         <li>
           {this.renderIconLink('https://blog.sonarsource.com/', 'sq-icon.svg', 'Product News')}
@@ -148,7 +154,7 @@ export default class EmbedDocsPopup extends React.PureComponent<Props> {
           {this.renderSuggestions()}
           <li>
             <Link onClick={this.props.onClose} to="/documentation">
-              {translate('embed_docs.documentation_index')}
+              {translate('embed_docs.documentation')}
             </Link>
           </li>
           <li>
index aca948c6aa967dd90d11d3605210d151d95a43a8..29b58e4e6e3814c5cd405e4e3e93c0444ee1cb69 100644 (file)
 import * as React from 'react';
 import EmbedDocsPopup from './EmbedDocsPopup';
 import { SuggestionLink } from './SuggestionsProvider';
+import { CurrentUser } from '../../types';
 import BubblePopupHelper from '../../../components/common/BubblePopupHelper';
 import HelpIcon from '../../../components/icons-components/HelpIcon';
 import Tooltip from '../../../components/controls/Tooltip';
 import { translate } from '../../../helpers/l10n';
 
 interface Props {
+  currentUser: CurrentUser;
   showTooltip: boolean;
   suggestions: Array<SuggestionLink>;
   tooltip: boolean;
@@ -79,7 +81,13 @@ export default class EmbedDocsPopupHelper extends React.PureComponent<Props, Sta
       <BubblePopupHelper
         isOpen={this.state.helpOpen}
         offset={{ horizontal: 12, vertical: -10 }}
-        popup={<EmbedDocsPopup onClose={this.closeHelp} suggestions={this.props.suggestions} />}
+        popup={
+          <EmbedDocsPopup
+            currentUser={this.props.currentUser}
+            onClose={this.closeHelp}
+            suggestions={this.props.suggestions}
+          />
+        }
         position="bottomleft"
         togglePopup={this.setHelpDisplay}>
         <Tooltip
index 647715c847add973c13fa7a90916d8703ab9aa1d..48bb8a0799a7f7a94063ab88ab7d97b792cc028b 100644 (file)
@@ -25,9 +25,16 @@ const suggestions = [{ link: '#', text: 'foo' }, { link: '#', text: 'bar' }];
 
 it('should display suggestion links', () => {
   const context = {};
-  const wrapper = shallow(<EmbedDocsPopups onClose={jest.fn()} suggestions={suggestions} />, {
-    context
-  });
+  const wrapper = shallow(
+    <EmbedDocsPopups
+      currentUser={{ isLoggedIn: true }}
+      onClose={jest.fn()}
+      suggestions={suggestions}
+    />,
+    {
+      context
+    }
+  );
   wrapper.update();
   expect(wrapper).toMatchSnapshot();
 });
index 8867991dcc56dfc517eac3cd8d0589fad53e1c30..b1af003796f26c05f9b33a912c61e6ed509e6a85 100644 (file)
@@ -48,7 +48,7 @@ exports[`should display suggestion links 1`] = `
         style={Object {}}
         to="/documentation"
       >
-        embed_docs.documentation_index
+        embed_docs.documentation
       </Link>
     </li>
     <li>
@@ -110,6 +110,9 @@ exports[`should display suggestion links 1`] = `
           Stack Overflow
         </a>
       </li>
+      <li
+        className="divider"
+      />
       <li
         className="dropdown-header"
       >
index 5569d2a7844433065d1a19f027a3d1376ba28241..890e4d5f29eaddee1b13c02a76f755fe503ee11d 100644 (file)
@@ -22,8 +22,7 @@ import * as classNames from 'classnames';
 import * as PropTypes from 'prop-types';
 import { FormattedMessage } from 'react-intl';
 import ComponentNavBranchesMenu from './ComponentNavBranchesMenu';
-import SingleBranchHelperPopup from './SingleBranchHelperPopup';
-import NoBranchSupportPopup from './NoBranchSupportPopup';
+import DocTooltip from '../../../../components/docs/DocTooltip';
 import { BranchLike, Component } from '../../../types';
 import * as theme from '../../../theme';
 import BranchIcon from '../../../../components/icons-components/BranchIcon';
@@ -35,7 +34,7 @@ import {
 } from '../../../../helpers/branches';
 import { translate } from '../../../../helpers/l10n';
 import PlusCircleIcon from '../../../../components/icons-components/PlusCircleIcon';
-import Popup from '../../../../components/controls/Popup';
+import HelpTooltip from '../../../../components/controls/HelpTooltip';
 import Tooltip from '../../../../components/controls/Tooltip';
 
 interface Props {
@@ -110,10 +109,11 @@ export default class ComponentNavBranch extends React.PureComponent<Props, State
     if (isShortLivingBranch(currentBranchLike)) {
       return currentBranchLike.isOrphan ? (
         <span className="note big-spacer-left text-ellipsis flex-shrink">
-          {translate('branches.orphan_branch')}
-          <Tooltip overlay={translate('branches.orphan_branches.tooltip')}>
-            <i className="icon-help spacer-left" />
-          </Tooltip>
+          <span className="text-middle">{translate('branches.orphan_branch')}</span>
+          <HelpTooltip
+            className="spacer-left"
+            overlay={translate('branches.orphan_branches.tooltip')}
+          />
         </span>
       ) : (
         <span className="note big-spacer-left">
@@ -138,26 +138,6 @@ export default class ComponentNavBranch extends React.PureComponent<Props, State
     }
   };
 
-  renderSingleBranchPopup = () => (
-    <Popup overlay={<SingleBranchHelperPopup />}>
-      {({ onClick }) => (
-        <a className="display-flex-center spacer-left link-no-underline" href="#" onClick={onClick}>
-          <PlusCircleIcon fill={theme.blue} size={12} />
-        </a>
-      )}
-    </Popup>
-  );
-
-  renderNoBranchSupportPopup = () => (
-    <Popup overlay={<NoBranchSupportPopup />}>
-      {({ onClick }) => (
-        <a className="display-flex-center spacer-left link-no-underline" href="#" onClick={onClick}>
-          <PlusCircleIcon fill={theme.gray80} size={12} />
-        </a>
-      )}
-    </Popup>
-  );
-
   render() {
     const { branchLikes, currentBranchLike } = this.props;
 
@@ -176,7 +156,9 @@ export default class ComponentNavBranch extends React.PureComponent<Props, State
             fill={theme.gray80}
           />
           <span className="note">{displayName}</span>
-          {this.renderNoBranchSupportPopup()}
+          <DocTooltip className="spacer-left" doc="branches/no-branch-support">
+            <PlusCircleIcon fill={theme.gray71} size={12} />
+          </DocTooltip>
         </div>
       );
     }
@@ -186,7 +168,9 @@ export default class ComponentNavBranch extends React.PureComponent<Props, State
         <div className="navbar-context-branches">
           <BranchIcon branchLike={currentBranchLike} className="little-spacer-right" />
           <span className="note">{displayName}</span>
-          {this.renderSingleBranchPopup()}
+          <DocTooltip className="spacer-left" doc="branches/single-branch">
+            <PlusCircleIcon fill={theme.blue} size={12} />
+          </DocTooltip>
         </div>
       );
     }
index 4f2849bdfd8c6a89270f64f0828ef31262096fa8..10f4b1ba8851fc2e830487970a47f3812ba2a64f 100644 (file)
@@ -34,7 +34,7 @@ import {
 import { translate } from '../../../../helpers/l10n';
 import { getBranchLikeUrl } from '../../../../helpers/urls';
 import SearchBox from '../../../../components/controls/SearchBox';
-import Tooltip from '../../../../components/controls/Tooltip';
+import HelpTooltip from '../../../../components/controls/HelpTooltip';
 
 interface Props {
   branchLikes: BranchLike[];
@@ -196,10 +196,13 @@ export default class ComponentNavBranchesMenu extends React.PureComponent<Props,
           {showDivider && <li className="divider" />}
           {showOrphanHeader && (
             <li className="dropdown-header">
-              {translate('branches.orphan_branches')}
-              <Tooltip overlay={translate('branches.orphan_branches.tooltip')}>
-                <i className="icon-help spacer-left" />
-              </Tooltip>
+              <div className="display-inline-block text-middle">
+                {translate('branches.orphan_branches')}
+              </div>
+              <HelpTooltip
+                className="spacer-left"
+                overlay={translate('branches.orphan_branches.tooltip')}
+              />
             </li>
           )}
           {showPullRequestHeader && (
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/NoBranchSupportPopup.tsx b/server/sonar-web/src/main/js/app/components/nav/component/NoBranchSupportPopup.tsx
deleted file mode 100644 (file)
index 5493c37..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 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 { translate } from '../../../../helpers/l10n';
-
-export default function NoBranchSupportPopup() {
-  return (
-    <>
-      <h6 className="spacer-bottom">{translate('branches.no_support.header')}</h6>
-      <p className="big-spacer-bottom markdown">{translate('branches.no_support.header.text')}</p>
-      <p>
-        <a
-          href="https://redirect.sonarsource.com/editions/developer.html"
-          rel="noopener noreferrer"
-          target="_blank">
-          {translate('learn_more')}
-        </a>
-      </p>
-    </>
-  );
-}
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/SingleBranchHelperPopup.tsx b/server/sonar-web/src/main/js/app/components/nav/component/SingleBranchHelperPopup.tsx
deleted file mode 100644 (file)
index b569b99..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 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 { translate } from '../../../../helpers/l10n';
-
-export default function SingleBranchHelperPopup() {
-  return (
-    <>
-      <h6 className="spacer-bottom">{translate('branches.learn_how_to_analyze')}</h6>
-      <p className="big-spacer-bottom markdown">
-        {translate('branches.learn_how_to_analyze.text')}
-      </p>
-      <a
-        className="button"
-        href="https://redirect.sonarsource.com/doc/branches.html"
-        rel="noopener noreferrer"
-        target="_blank">
-        {translate('about_page.read_documentation')}
-      </a>
-    </>
-  );
-}
index 2c2651988af0ca1b64e085e704e759663cb99c63..8ea67da8b970f12e997a4da33d7d9df290b1e6d2 100644 (file)
@@ -114,7 +114,7 @@ it('renders single branch popup', () => {
     />,
     { context: { branchesEnabled: true } }
   );
-  expect(wrapper.find('Popup')).toMatchSnapshot();
+  expect(wrapper.find('DocTooltip')).toMatchSnapshot();
 });
 
 it('renders no branch support popup', () => {
@@ -127,7 +127,7 @@ it('renders no branch support popup', () => {
     />,
     { context: { branchesEnabled: false } }
   );
-  expect(wrapper.find('Popup')).toMatchSnapshot();
+  expect(wrapper.find('DocTooltip')).toMatchSnapshot();
 });
 
 it('renders nothing on SonarCloud without branch support', () => {
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/NoBranchSupportPopup-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/NoBranchSupportPopup-test.tsx
deleted file mode 100644 (file)
index 14c49cc..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 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 { shallow } from 'enzyme';
-import NoBranchSupportPopup from '../NoBranchSupportPopup';
-
-it('renders', () => {
-  expect(shallow(<NoBranchSupportPopup />)).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/SingleBranchHelperPopup-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/SingleBranchHelperPopup-test.tsx
deleted file mode 100644 (file)
index a6185bc..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 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 { shallow } from 'enzyme';
-import SingleBranchHelperPopup from '../SingleBranchHelperPopup';
-
-it('renders', () => {
-  expect(shallow(<SingleBranchHelperPopup />)).toMatchSnapshot();
-});
index c3042574729c795b7d2c6636f9b2f004ae8a6b6d..dc23c7b4368f7c588c165b98e7a7634ce21f7c89 100644 (file)
@@ -36,9 +36,15 @@ exports[`renders main branch 1`] = `
 `;
 
 exports[`renders no branch support popup 1`] = `
-<Popup
-  overlay={<NoBranchSupportPopup />}
-/>
+<DocTooltip
+  className="spacer-left"
+  doc="branches/no-branch-support"
+>
+  <PlusCircleIcon
+    fill="#b4b4b4"
+    size={12}
+  />
+</DocTooltip>
 `;
 
 exports[`renders pull request 1`] = `
@@ -150,7 +156,13 @@ exports[`renders short-living branch 1`] = `
 `;
 
 exports[`renders single branch popup 1`] = `
-<Popup
-  overlay={<SingleBranchHelperPopup />}
-/>
+<DocTooltip
+  className="spacer-left"
+  doc="branches/single-branch"
+>
+  <PlusCircleIcon
+    fill="#4b9fd5"
+    size={12}
+  />
+</DocTooltip>
 `;
index a8c10d0f990335ba9bdf36dee30f5c87dba38157..c104c23e7d39b2d682178067f26431447f6254c6 100644 (file)
@@ -80,14 +80,15 @@ exports[`renders list 1`] = `
       <li
         className="dropdown-header"
       >
-        branches.orphan_branches
-        <Tooltip
-          overlay="branches.orphan_branches.tooltip"
+        <div
+          className="display-inline-block text-middle"
         >
-          <i
-            className="icon-help spacer-left"
-          />
-        </Tooltip>
+          branches.orphan_branches
+        </div>
+        <HelpTooltip
+          className="spacer-left"
+          overlay="branches.orphan_branches.tooltip"
+        />
       </li>
       <ComponentNavBranchesMenuItem
         branchLike={
@@ -177,14 +178,15 @@ exports[`renders list 1`] = `
       <li
         className="dropdown-header"
       >
-        branches.orphan_branches
-        <Tooltip
-          overlay="branches.orphan_branches.tooltip"
+        <div
+          className="display-inline-block text-middle"
         >
-          <i
-            className="icon-help spacer-left"
-          />
-        </Tooltip>
+          branches.orphan_branches
+        </div>
+        <HelpTooltip
+          className="spacer-left"
+          overlay="branches.orphan_branches.tooltip"
+        />
       </li>
       <ComponentNavBranchesMenuItem
         branchLike={
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/NoBranchSupportPopup-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/NoBranchSupportPopup-test.tsx.snap
deleted file mode 100644 (file)
index 964fc40..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders 1`] = `
-<React.Fragment>
-  <h6
-    className="spacer-bottom"
-  >
-    branches.no_support.header
-  </h6>
-  <p
-    className="big-spacer-bottom markdown"
-  >
-    branches.no_support.header.text
-  </p>
-  <p>
-    <a
-      href="https://redirect.sonarsource.com/editions/developer.html"
-      rel="noopener noreferrer"
-      target="_blank"
-    >
-      learn_more
-    </a>
-  </p>
-</React.Fragment>
-`;
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/SingleBranchHelperPopup-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/SingleBranchHelperPopup-test.tsx.snap
deleted file mode 100644 (file)
index a27c563..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders 1`] = `
-<React.Fragment>
-  <h6
-    className="spacer-bottom"
-  >
-    branches.learn_how_to_analyze
-  </h6>
-  <p
-    className="big-spacer-bottom markdown"
-  >
-    branches.learn_how_to_analyze.text
-  </p>
-  <a
-    className="button"
-    href="https://redirect.sonarsource.com/doc/branches.html"
-    rel="noopener noreferrer"
-    target="_blank"
-  >
-    about_page.read_documentation
-  </a>
-</React.Fragment>
-`;
index b91c43abb47a4a6f5c42b4e62008a8e990357d9f..866edfae8057e795267cd61a4711743d1580c9cf 100644 (file)
@@ -101,6 +101,7 @@ class GlobalNav extends React.PureComponent<Props, State> {
           <GlobalNavExplore location={this.props.location} onSonarCloud={this.props.onSonarCloud} />
           <li>
             <EmbedDocsPopupHelper
+              currentUser={this.props.currentUser}
               showTooltip={this.state.onboardingTutorialTooltip}
               suggestions={this.props.suggestions}
               tooltip={!this.props.onSonarCloud}
index 55a8586e8ea5ef76cb446cd250411acb81b85080..c4f46239db32b456dd704595a79572137827eeda 100644 (file)
@@ -430,12 +430,6 @@ a:hover > .icon-radio {
   }
 }
 
-.icon-help:before {
-  content: '\f059';
-  color: var(--blue);
-  font-size: var(--bigFontSize);
-}
-
 .icon-close:before {
   content: '\f00d';
   font-size: var(--bigFontSize);
index 798f70d69d27bc95d93a24e977dfde0582bde875..b07d8c1f53b1f46b0aa9ef6345ec69fcc10183ca 100644 (file)
@@ -32,6 +32,7 @@ import LicenseEditionSet from '../../apps/marketplace/components/LicenseEditionS
 import HomePageSelect from '../../components/controls/HomePageSelect';
 import ListFooter from '../../components/controls/ListFooter';
 import Modal from '../../components/controls/Modal';
+import HelpTooltip from '../../components/controls/HelpTooltip';
 import SearchBox from '../../components/controls/SearchBox';
 import Select from '../../components/controls/Select';
 import Tooltip from '../../components/controls/Tooltip';
@@ -60,6 +61,7 @@ const exposeLibraries = () => {
     DuplicationsRating,
     EditButton,
     FavoriteContainer,
+    HelpTooltip,
     HomePageSelect,
     Level,
     LicenseEditionSet,
index c6e327896fce4e2e6aad9186d12422240f439540..b1f851e0d36ea107ebee7474bbefb82889e255b2 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import BubblePopup from '../../../components/common/BubblePopup';
 import { translate } from '../../../helpers/l10n';
 
-interface Props {
-  popupPosition?: any;
-}
-
-export default function NoWorkersSupportPopup(props: Props) {
+export default function NoWorkersSupportPopup() {
   return (
-    <BubblePopup position={props.popupPosition} customClass="bubble-popup-bottom-right">
-      <div className="abs-width-400">
-        <h6 className="spacer-bottom">{translate('background_tasks.add_more_workers')}</h6>
-        <p className="big-spacer-bottom markdown">
-          {translate('background_tasks.add_more_workers.text')}
-        </p>
-        <p>
-          <a href="https://redirect.sonarsource.com/editions/enterprise.html" target="_blank">
-            {translate('learn_more')}
-          </a>
-        </p>
-      </div>
-    </BubblePopup>
+    <>
+      <p className="spacer-bottom">
+        <strong>{translate('background_tasks.add_more_workers')}</strong>
+      </p>
+      <p className="big-spacer-bottom markdown">
+        {translate('background_tasks.add_more_workers.text')}
+      </p>
+      <p>
+        <a
+          href="https://redirect.sonarsource.com/editions/enterprise.html"
+          rel="noopener noreferrer"
+          target="_blank">
+          {translate('learn_more')}
+        </a>
+      </p>
+    </>
   );
 }
index 1039418df339c21516a37e137bba4713919854c0..5f448358cfadb8676e488d405ce0b5d5b0000489 100644 (file)
@@ -21,10 +21,8 @@ import * as React from 'react';
 import WorkersForm from './WorkersForm';
 import NoWorkersSupportPopup from './NoWorkersSupportPopup';
 import AlertWarnIcon from '../../../components/icons-components/AlertWarnIcon';
-import BubblePopupHelper from '../../../components/common/BubblePopupHelper';
-import HelpIcon from '../../../components/icons-components/HelpIcon';
+import HelpTooltip from '../../../components/controls/HelpTooltip';
 import Tooltip from '../../../components/controls/Tooltip';
-import * as theme from '../../../app/theme';
 import { getWorkers } from '../../../api/ce';
 import { translate } from '../../../helpers/l10n';
 import { EditButton } from '../../../components/ui/buttons';
@@ -103,15 +101,12 @@ export default class Workers extends React.PureComponent<{}, State> {
     const { canSetWorkerCount, formOpen, loading, workerCount } = this.state;
 
     return (
-      <div>
+      <div className="display-flex-center">
         {!loading &&
           workerCount > 1 && (
             <Tooltip overlay={translate('background_tasks.number_of_workers.warning')}>
-              <span>
-                <AlertWarnIcon
-                  className="little-spacer-right bt-workers-warning-icon"
-                  fill="#d3d3d3"
-                />
+              <span className="display-inline-flex-center little-spacer-right">
+                <AlertWarnIcon fill="#d3d3d3" />
               </span>
             </Tooltip>
           )}
@@ -138,17 +133,7 @@ export default class Workers extends React.PureComponent<{}, State> {
 
         {!loading &&
           !canSetWorkerCount && (
-            <span className="spacer-left">
-              <a className="link-no-underline" href="#" onClick={this.handleHelpClick}>
-                <HelpIcon className="text-text-bottom" fill={theme.gray80} />
-              </a>
-              <BubblePopupHelper
-                isOpen={this.state.noSupportPopup}
-                popup={<NoWorkersSupportPopup />}
-                position="bottomright"
-                togglePopup={this.toggleNoSupportPopup}
-              />
-            </span>
+            <HelpTooltip className="spacer-left" overlay={<NoWorkersSupportPopup />} />
           )}
 
         {formOpen && <WorkersForm onClose={this.closeForm} workerCount={this.state.workerCount} />}
index 48dea3cb94d74b3073fee4aa84c8d3290f27be67..a579c08668066291d5b852af96dd8064a90fd5ab 100644 (file)
@@ -1,7 +1,9 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`opens form 1`] = `
-<div>
+<div
+  className="display-flex-center"
+>
   <span
     className="text-middle"
   >
@@ -24,7 +26,9 @@ exports[`opens form 1`] = `
 `;
 
 exports[`opens form 2`] = `
-<div>
+<div
+  className="display-flex-center"
+>
   <span
     className="text-middle"
   >
@@ -51,7 +55,9 @@ exports[`opens form 2`] = `
 `;
 
 exports[`renders 1`] = `
-<div>
+<div
+  className="display-flex-center"
+>
   <span
     className="text-middle"
   >
@@ -64,7 +70,9 @@ exports[`renders 1`] = `
 `;
 
 exports[`renders 2`] = `
-<div>
+<div
+  className="display-flex-center"
+>
   <span
     className="text-middle"
   >
@@ -87,13 +95,16 @@ exports[`renders 2`] = `
 `;
 
 exports[`renders 3`] = `
-<div>
+<div
+  className="display-flex-center"
+>
   <Tooltip
     overlay="background_tasks.number_of_workers.warning"
   >
-    <span>
+    <span
+      className="display-inline-flex-center little-spacer-right"
+    >
       <AlertWarnIcon
-        className="little-spacer-right bt-workers-warning-icon"
         fill="#d3d3d3"
       />
     </span>
@@ -120,13 +131,16 @@ exports[`renders 3`] = `
 `;
 
 exports[`renders 4`] = `
-<div>
+<div
+  className="display-flex-center"
+>
   <Tooltip
     overlay="background_tasks.number_of_workers.warning"
   >
-    <span>
+    <span
+      className="display-inline-flex-center little-spacer-right"
+    >
       <AlertWarnIcon
-        className="little-spacer-right bt-workers-warning-icon"
         fill="#d3d3d3"
       />
     </span>
@@ -141,31 +155,17 @@ exports[`renders 4`] = `
       2
     </strong>
   </span>
-  <span
+  <HelpTooltip
     className="spacer-left"
-  >
-    <a
-      className="link-no-underline"
-      href="#"
-      onClick={[Function]}
-    >
-      <HelpIcon
-        className="text-text-bottom"
-        fill="#cdcdcd"
-      />
-    </a>
-    <BubblePopupHelper
-      isOpen={false}
-      popup={<NoWorkersSupportPopup />}
-      position="bottomright"
-      togglePopup={[Function]}
-    />
-  </span>
+    overlay={<NoWorkersSupportPopup />}
+  />
 </div>
 `;
 
 exports[`updates worker count 1`] = `
-<div>
+<div
+  className="display-flex-center"
+>
   <span
     className="text-middle"
   >
@@ -192,13 +192,16 @@ exports[`updates worker count 1`] = `
 `;
 
 exports[`updates worker count 2`] = `
-<div>
+<div
+  className="display-flex-center"
+>
   <Tooltip
     overlay="background_tasks.number_of_workers.warning"
   >
-    <span>
+    <span
+      className="display-inline-flex-center little-spacer-right"
+    >
       <AlertWarnIcon
-        className="little-spacer-right bt-workers-warning-icon"
         fill="#d3d3d3"
       />
     </span>
index dad5a4ec0e23df9e3fb922216a63603b4075af4f..9031eacd7afefa98d71f3a86c073c93d9f396cdf 100644 (file)
@@ -22,8 +22,7 @@ import React from 'react';
 import EmptyResult from './EmptyResult';
 import OriginalBubbleChart from '../../../components/charts/BubbleChart';
 import ColorRatingsLegend from '../../../components/charts/ColorRatingsLegend';
-import Tooltip from '../../../components/controls/Tooltip';
-import HelpIcon from '../../../components/icons-components/HelpIcon';
+import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { formatMeasure, isDiffMetric } from '../../../helpers/measures';
 import {
   getLocalizedMetricDomain,
@@ -170,12 +169,8 @@ export default class BubbleChart extends React.PureComponent {
     return (
       <div className="measure-overview-bubble-chart-header">
         <span className="measure-overview-bubble-chart-title">
-          {title}
-          <Tooltip overlay={this.getDescription(domain)}>
-            <span className="spacer-left text-info">
-              <HelpIcon />
-            </span>
-          </Tooltip>
+          <span className="text-middle">{title}</span>
+          <HelpTooltip className="spacer-left" overlay={this.getDescription(domain)} />
         </span>
         <span className="measure-overview-bubble-chart-legend">
           <span className="note">
index 90b0bfb46eab5e749c98ed807d691007bffcf898..c623b78944d51297edafb7163386816facf71e98 100644 (file)
@@ -27,6 +27,7 @@ import ScreenPositionHelper from '../../../components/common/ScreenPositionHelpe
 import DocMarkdownBlock from '../../../components/docs/DocMarkdownBlock';
 import DeferredSpinner from '../../../components/common/DeferredSpinner';
 import { translate } from '../../../helpers/l10n';
+import '../styles.css';
 
 interface Props {
   params: { splat?: string };
@@ -87,7 +88,7 @@ export default class App extends React.PureComponent<Props, State> {
     return (
       <div className="boxed-group">
         <DocMarkdownBlock
-          className="cut-margins boxed-group-inner"
+          className="documentation-content cut-margins boxed-group-inner"
           content={this.state.content}
           displayH1={true}
         />
@@ -122,7 +123,9 @@ export default class App extends React.PureComponent<Props, State> {
         </ScreenPositionHelper>
 
         <div className="layout-page-main">
-          <div className="layout-page-main-inner">{this.renderContent()}</div>
+          <div className="layout-page-main-inner documentation-layout-inner">
+            {this.renderContent()}
+          </div>
         </div>
       </div>
     );
diff --git a/server/sonar-web/src/main/js/apps/documentation/styles.css b/server/sonar-web/src/main/js/apps/documentation/styles.css
new file mode 100644 (file)
index 0000000..089f3e3
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.
+ */
+.documentation-layout-inner {
+  max-width: 740px;
+}
+
+.documentation-content > h1 {
+  margin-bottom: calc(4 * var(--gridSize));
+  font-size: 20px;
+}
index a58ead1f8c764ec5279fd16a7c27bdcaae15294c..3bec8113a96f18633cd012be11fb2c15cae56d3b 100644 (file)
@@ -28,7 +28,7 @@ import SearchSelect from '../../../components/controls/SearchSelect';
 import Checkbox from '../../../components/controls/Checkbox';
 import Modal from '../../../components/controls/Modal';
 import Select from '../../../components/controls/Select';
-import Tooltip from '../../../components/controls/Tooltip';
+import HelpTooltip from '../../../components/controls/HelpTooltip';
 import SeverityHelper from '../../../components/shared/SeverityHelper';
 import Avatar from '../../../components/ui/Avatar';
 import { SubmitButton } from '../../../components/ui/buttons';
@@ -457,10 +457,11 @@ export default class BulkChangeModal extends React.PureComponent<Props, State> {
     return (
       <div className="modal-field">
         <label htmlFor="comment">
-          {translate('issue.comment.formlink')}
-          <Tooltip overlay={translate('issue_bulk_change.comment.help')}>
-            <i className="icon-help little-spacer-left" />
-          </Tooltip>
+          <span className="text-middle">{translate('issue.comment.formlink')}</span>
+          <HelpTooltip
+            className="spacer-left"
+            overlay={translate('issue_bulk_change.comment.help')}
+          />
         </label>
         <div>
           <textarea
index 8c647e71b56a7970b76727954c9fa04a7faf1f2a..5c575d3cd234a3bc8d932a7fd38f301f6878bc48 100644 (file)
 import React from 'react';
 import QualityGateConditions from './QualityGateConditions';
 import EmptyQualityGate from './EmptyQualityGate';
-import * as theme from '../../../app/theme';
 import { translate } from '../../../helpers/l10n';
 import Level from '../../../components/ui/Level';
-import Tooltip from '../../../components/controls/Tooltip';
+import HelpTooltip from '../../../components/controls/HelpTooltip';
 import DocTooltip from '../../../components/docs/DocTooltip';
-import HelpIcon from '../../../components/icons-components/HelpIcon';
 /*:: import type { Component, MeasuresList } from '../types'; */
 
 function parseQualityGateDetails(rawDetails /*: string */) {
@@ -73,12 +71,13 @@ export default function QualityGate({ branchLike, component, measures } /*: Prop
 
       {ignoredConditions && (
         <div className="alert alert-info display-inline-block big-spacer-top">
-          {translate('overview.quality_gate.ignored_conditions')}
-          <Tooltip overlay={translate('overview.quality_gate.ignored_conditions.tooltip')}>
-            <span className="spacer-left">
-              <HelpIcon fill={theme.blue} />
-            </span>
-          </Tooltip>
+          <span className="text-middle">
+            {translate('overview.quality_gate.ignored_conditions')}
+          </span>
+          <HelpTooltip
+            className="spacer-left"
+            overlay={translate('overview.quality_gate.ignored_conditions.tooltip')}
+          />
         </div>
       )}
 
index 2387806ada664a54f2165890a2986ef1baced97a..2e09cfa0f8c36d55a7163d3559aead5067ca57ff 100644 (file)
@@ -25,18 +25,15 @@ exports[`renders message about ignored conditions 1`] = `
   <div
     className="alert alert-info display-inline-block big-spacer-top"
   >
-    overview.quality_gate.ignored_conditions
-    <Tooltip
-      overlay="overview.quality_gate.ignored_conditions.tooltip"
+    <span
+      className="text-middle"
     >
-      <span
-        className="spacer-left"
-      >
-        <HelpIcon
-          fill="#4b9fd5"
-        />
-      </span>
-    </Tooltip>
+      overview.quality_gate.ignored_conditions
+    </span>
+    <HelpTooltip
+      className="spacer-left"
+      overlay="overview.quality_gate.ignored_conditions.tooltip"
+    />
   </div>
 </div>
 `;
index 897521276c5a28cd0c7983b785aa00b1a88dd5dc..4be5290b4463e53b3371035d7d7851a36cf6dfb2 100644 (file)
@@ -19,7 +19,7 @@
  */
 import React from 'react';
 import PropTypes from 'prop-types';
-import Tooltip from '../../../components/controls/Tooltip';
+import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { translate } from '../../../helpers/l10n';
 
 export default class ListHeader extends React.PureComponent {
@@ -42,11 +42,9 @@ export default class ListHeader extends React.PureComponent {
 
   render() {
     const cells = this.props.permissions.map(permission => (
-      <th key={permission.key} className="permission-column">
-        {translate('projects_role', permission.key)}
-        <Tooltip overlay={this.renderTooltip(permission)}>
-          <i className="icon-help little-spacer-left" />
-        </Tooltip>
+      <th className="permission-column" key={permission.key}>
+        <span className="text-middle">{translate('projects_role', permission.key)}</span>
+        <HelpTooltip className="spacer-left" overlay={this.renderTooltip(permission)} />
       </th>
     ));
 
index f00777de1bb4f89eafa89649ac768a34dfe60276..07d1787fdeda552c2f4c736997713bb729dcc735 100644 (file)
@@ -18,6 +18,7 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
+import HelpTooltip from '../../../../components/controls/HelpTooltip';
 import Tooltip from '../../../../components/controls/Tooltip';
 import { translate, translateWithParameters } from '../../../../helpers/l10n';
 
@@ -69,13 +70,11 @@ export default class PermissionHeader extends React.PureComponent<Props> {
               'global_permissions.filter_by_x_permission',
               permission.name
             )}>
-            <a href="#" onClick={this.handlePermissionClick}>
+            <a className="text-middle" href="#" onClick={this.handlePermissionClick}>
               {permission.name}
             </a>
           </Tooltip>
-          <Tooltip overlay={this.renderTooltip(permission)}>
-            <i className="icon-help little-spacer-left" />
-          </Tooltip>
+          <HelpTooltip className="spacer-left" overlay={this.renderTooltip(permission)} />
         </div>
       </th>
     );
index 6707fe36d9fb372e502dd18c4a69c1b21414a117..eae759f0acbdf6007fdc11661c0b665901b2f63b 100644 (file)
@@ -29,5 +29,5 @@
 }
 
 .permissions-table .permission-column-inner {
-  width: 112px;
+  width: 100px;
 }
index 949bc4e1d78effa76b285dc2b9ec4b5d5a00f5fe..6298f16e0a3b63bd66c89d16ba7c6734a07b1eee 100644 (file)
@@ -32,7 +32,7 @@ import {
 import { translate } from '../../../helpers/l10n';
 import { getValues } from '../../../api/settings';
 import { formatMeasure } from '../../../helpers/measures';
-import Tooltip from '../../../components/controls/Tooltip';
+import HelpTooltip from '../../../components/controls/HelpTooltip';
 
 interface Props {
   branchLikes: BranchLike[];
@@ -154,10 +154,13 @@ export default class App extends React.PureComponent<Props, State> {
                   <React.Fragment key={getBranchLikeKey(branchLike)}>
                     {showOrphanHeader && (
                       <li className="dropdown-header">
-                        {translate('branches.orphan_branches')}
-                        <Tooltip overlay={translate('branches.orphan_branches.tooltip')}>
-                          <i className="icon-help spacer-left" />
-                        </Tooltip>
+                        <div className="display-inline-block text-middle">
+                          {translate('branches.orphan_branches')}
+                        </div>
+                        <HelpTooltip
+                          className="spacer-left"
+                          overlay={translate('branches.orphan_branches.tooltip')}
+                        />
                       </li>
                     )}
                     <BranchRow
index d2e776bbee4799ad503b2eff21172dd31d827ad7..5c8f4b20cf08cafca1162b9934558161cf472544 100644 (file)
@@ -150,14 +150,15 @@ exports[`renders sorted list of branches 1`] = `
           <li
             className="dropdown-header"
           >
-            branches.orphan_branches
-            <Tooltip
-              overlay="branches.orphan_branches.tooltip"
+            <div
+              className="display-inline-block text-middle"
             >
-              <i
-                className="icon-help spacer-left"
-              />
-            </Tooltip>
+              branches.orphan_branches
+            </div>
+            <HelpTooltip
+              className="spacer-left"
+              overlay="branches.orphan_branches.tooltip"
+            />
           </li>
           <BranchRow
             branchLike={
index a82b86d69fde6a97cd2f1562f4314b0a9effe0cd..56609711677a4ac44861a1b5825e1fc8c5c8de25 100644 (file)
@@ -25,8 +25,7 @@ import { formatMeasure } from '../../../helpers/measures';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
 import { RATING_COLORS } from '../../../helpers/constants';
 import { getProjectUrl } from '../../../helpers/urls';
-import Tooltip from '../../../components/controls/Tooltip';
-import HelpIcon from '../../../components/icons-components/HelpIcon';
+import HelpTooltip from '../../../components/controls/HelpTooltip';
 
 const X_METRIC = 'sqale_index';
 const X_METRIC_TYPE = 'SHORT_WORK_DUR';
@@ -138,12 +137,8 @@ export default class Risk extends React.PureComponent<Props> {
         </div>
         <div className="measure-details-bubble-chart-axis size">
           <span className="measure-details-bubble-chart-title">
-            {translate('projects.visualization.risk')}
-            <Tooltip overlay={this.props.helpText}>
-              <span className="spacer-left text-info">
-                <HelpIcon />
-              </span>
-            </Tooltip>
+            <span className="text-middle">{translate('projects.visualization.risk')}</span>
+            <HelpTooltip className="spacer-left" overlay={this.props.helpText} />
           </span>
           <div>
             <span className="spacer-right">
index 10c1291f61ff0032457ed1528d153e88b0eda7d8..be1e6ee0f8c04ac029b3793ec95897ef9783460c 100644 (file)
@@ -25,8 +25,7 @@ import { translate, translateWithParameters } from '../../../helpers/l10n';
 import { RATING_COLORS } from '../../../helpers/constants';
 import { getProjectUrl } from '../../../helpers/urls';
 import { Project } from '../types';
-import Tooltip from '../../../components/controls/Tooltip';
-import HelpIcon from '../../../components/icons-components/HelpIcon';
+import HelpTooltip from '../../../components/controls/HelpTooltip';
 
 export interface Metric {
   key: string;
@@ -129,12 +128,8 @@ export default class SimpleBubbleChart extends React.PureComponent<Props> {
         </div>
         <div className="measure-details-bubble-chart-axis size">
           <span className="measure-details-bubble-chart-title">
-            {this.props.title}
-            <Tooltip overlay={this.props.helpText}>
-              <span className="spacer-left text-info">
-                <HelpIcon className="text-bottom" />
-              </span>
-            </Tooltip>
+            <span className="text-middle">{this.props.title}</span>
+            <HelpTooltip className="spacer-left" overlay={this.props.helpText} />
           </span>
           <div>
             {colorMetric != null && (
index ec17ac106b4449ed957001733c48ce573ac5d9bf..c1aac43c7d7b160efa9b32595e2d341fead78568 100644 (file)
@@ -100,16 +100,15 @@ exports[`renders 1`] = `
     <span
       className="measure-details-bubble-chart-title"
     >
-      projects.visualization.risk
-      <Tooltip
-        overlay="foobar"
+      <span
+        className="text-middle"
       >
-        <span
-          className="spacer-left text-info"
-        >
-          <HelpIcon />
-        </span>
-      </Tooltip>
+        projects.visualization.risk
+      </span>
+      <HelpTooltip
+        className="spacer-left"
+        overlay="foobar"
+      />
     </span>
     <div>
       <span
index 020df683ca2cc5f69854fff10ed10976c587dd4f..0c07a84920e4ae4b100810fa3b5e8149d0d7d383 100644 (file)
@@ -89,17 +89,13 @@ exports[`renders 1`] = `
     <span
       className="measure-details-bubble-chart-title"
     >
-      <Tooltip
+      <span
+        className="text-middle"
+      />
+      <HelpTooltip
+        className="spacer-left"
         overlay="foobar"
-      >
-        <span
-          className="spacer-left text-info"
-        >
-          <HelpIcon
-            className="text-bottom"
-          />
-        </span>
-      </Tooltip>
+      />
     </span>
     <div>
       <span
index 54d3e0704d833e0ab92eb6f3ca223497a298032b..7c82c9e6d22cab64cb8fdca259e779c99f8d4d4d 100644 (file)
@@ -26,7 +26,7 @@ import { Organization } from '../../app/types';
 import Checkbox from '../../components/controls/Checkbox';
 import { translate } from '../../helpers/l10n';
 import QualifierIcon from '../../components/shared/QualifierIcon';
-import Tooltip from '../../components/controls/Tooltip';
+import HelpTooltip from '../../components/controls/HelpTooltip';
 import DateInput from '../../components/controls/DateInput';
 import Select from '../../components/controls/Select';
 import SearchBox from '../../components/controls/SearchBox';
@@ -156,13 +156,14 @@ export default class Search extends React.PureComponent<Props, State> {
           className="link-checkbox-control"
           id="projects-provisioned"
           onCheck={this.props.onProvisionedChanged}>
-          <span className="little-spacer-left">
+          <span className="text-middle little-spacer-left">
             {translate('provisioning.only_provisioned')}
-            <Tooltip overlay={translate('provisioning.only_provisioned.tooltip')}>
-              <i className="spacer-left icon-help" />
-            </Tooltip>
           </span>
         </Checkbox>
+        <HelpTooltip
+          className="spacer-left"
+          overlay={translate('provisioning.only_provisioned.tooltip')}
+        />
       </td>
     ) : null;
 
index 66cec9365f8c84ad97b72f4d1109c9f6e908b528..544cef965161655604a547f10f58e778cfb52226 100644 (file)
@@ -101,18 +101,15 @@ exports[`render qualifiers filter 1`] = `
             thirdState={false}
           >
             <span
-              className="little-spacer-left"
+              className="text-middle little-spacer-left"
             >
               provisioning.only_provisioned
-              <Tooltip
-                overlay="provisioning.only_provisioned.tooltip"
-              >
-                <i
-                  className="spacer-left icon-help"
-                />
-              </Tooltip>
             </span>
           </Checkbox>
+          <HelpTooltip
+            className="spacer-left"
+            overlay="provisioning.only_provisioned.tooltip"
+          />
         </td>
         <td
           className="text-middle"
@@ -188,18 +185,15 @@ exports[`renders 1`] = `
             thirdState={false}
           >
             <span
-              className="little-spacer-left"
+              className="text-middle little-spacer-left"
             >
               provisioning.only_provisioned
-              <Tooltip
-                overlay="provisioning.only_provisioned.tooltip"
-              >
-                <i
-                  className="spacer-left icon-help"
-                />
-              </Tooltip>
             </span>
           </Checkbox>
+          <HelpTooltip
+            className="spacer-left"
+            overlay="provisioning.only_provisioned.tooltip"
+          />
         </td>
         <td
           className="text-middle"
index 88f976df8fbe6a8392c323edb67c2b4fe9ee9430..4ebd702fa00c5d3bc9675c6d362b14f0c3e94266 100644 (file)
 import * as React from 'react';
 import * as classNames from 'classnames';
 import Tooltip from '../../../components/controls/Tooltip';
+import DocInclude from '../../../components/docs/DocInclude';
 import { translate } from '../../../helpers/l10n';
 
 interface Props {
   className?: string;
-  tooltip?: boolean;
 }
 
-export default function BuiltInQualityGateBadge({ className, tooltip = true }: Props) {
+export default function BuiltInQualityGateBadge({ className }: Props) {
   const badge = (
     <div className={classNames('outline-badge', className)}>
       {translate('quality_gates.built_in')}
@@ -35,13 +35,11 @@ export default function BuiltInQualityGateBadge({ className, tooltip = true }: P
   );
 
   const overlay = (
-    <div>
-      <span>{translate('quality_gates.built_in.description.1')}</span>
-      <span className="little-spacer-left">
-        {translate('quality_gates.built_in.description.2')}
-      </span>
-    </div>
+    <DocInclude
+      className="abs-width-300 cut-margins"
+      path="/tooltips/quality-gates/built-in-quality-gate"
+    />
   );
 
-  return <Tooltip overlay={tooltip ? overlay : undefined}>{badge}</Tooltip>;
+  return <Tooltip overlay={overlay}>{badge}</Tooltip>;
 }
index 8e2b1aa14ba1af9dd4c81298769d6c1ec08dd4d5..c4c869924a3b4b3cd5449da4154546c221f383d6 100644 (file)
@@ -23,7 +23,6 @@ import RenameQualityGateForm from './RenameQualityGateForm';
 import CopyQualityGateForm from './CopyQualityGateForm';
 import DeleteQualityGateForm from './DeleteQualityGateForm';
 import { fetchQualityGate, QualityGate, setQualityGateAsDefault } from '../../../api/quality-gates';
-import DocTooltip from '../../../components/docs/DocTooltip';
 import { Button } from '../../../components/ui/buttons';
 import { translate } from '../../../helpers/l10n';
 
@@ -76,12 +75,7 @@ export default class DetailsHeader extends React.PureComponent<Props, State> {
           <div className="layout-page-main-inner">
             <div className="pull-left display-flex-center">
               <h2>{qualityGate.name}</h2>
-              {qualityGate.isBuiltIn && (
-                <>
-                  <BuiltInQualityGateBadge className="spacer-left" />
-                  <DocTooltip className="spacer-left" doc="quality-gates/built-in-quality-gate" />
-                </>
-              )}
+              {qualityGate.isBuiltIn && <BuiltInQualityGateBadge className="spacer-left" />}
             </div>
 
             <div className="pull-right">
index 69db7ff0a73cb76df22498940357c17c6d21f25b..a1319df5af51a23972e1da5c28b8a655df80dd23 100644 (file)
@@ -40,7 +40,7 @@ export default function List({ organization, qualityGates }) {
                 <td className="thin nowrap spacer-left text-right">
                   {qualityGate.isDefault && <span className="badge">{translate('default')}</span>}
                   {qualityGate.isBuiltIn && (
-                    <BuiltInQualityGateBadge className="little-spacer-left" tooltip={false} />
+                    <BuiltInQualityGateBadge className="little-spacer-left" />
                   )}
                 </td>
               </tr>
index f493d0dc2c806475097aa2c7ecabbe8f087e1796..16b64e80812c6329e91d5f76cc87f1d8b95f03d3 100644 (file)
@@ -20,6 +20,7 @@
 import * as React from 'react';
 import * as classNames from 'classnames';
 import Tooltip from '../../../components/controls/Tooltip';
+import DocInclude from '../../../components/docs/DocInclude';
 import { translate } from '../../../helpers/l10n';
 
 interface Props {
@@ -35,10 +36,10 @@ export default function BuiltInQualityProfileBadge({ className, tooltip = true }
   );
 
   const overlay = (
-    <span>
-      {translate('quality_profiles.built_in.description.1')}{' '}
-      {translate('quality_profiles.built_in.description.2')}
-    </span>
+    <DocInclude
+      className="abs-width-300 cut-margins"
+      path="/tooltips/quality-profiles/built-in-quality-profile"
+    />
   );
 
   return <Tooltip overlay={tooltip ? overlay : undefined}>{badge}</Tooltip>;
index 7a5dfe71a4cea0357d7b6672db9d8d809f6c3e3b..3940f9c61e3b3d9f29f0a5849b703f342eff6166 100644 (file)
@@ -20,7 +20,7 @@
 import * as React from 'react';
 import ProfileLink from '../components/ProfileLink';
 import BuiltInQualityProfileBadge from '../components/BuiltInQualityProfileBadge';
-import Tooltip from '../../../components/controls/Tooltip';
+import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
 
 interface Props {
@@ -50,19 +50,21 @@ export default function ProfileInheritanceBox({ displayLink = true, ...props }:
         <div style={{ paddingLeft: offset }}>
           {displayLink ? (
             <ProfileLink
+              className="text-middle"
               language={props.language}
               name={profile.name}
               organization={props.organization}>
               {profile.name}
             </ProfileLink>
           ) : (
-            profile.name
+            <span className="text-middle">{profile.name}</span>
           )}
           {profile.isBuiltIn && <BuiltInQualityProfileBadge className="spacer-left" />}
           {extendsBuiltIn && (
-            <Tooltip overlay={translate('quality_profiles.extends_built_in')}>
-              <i className="icon-help spacer-left" />
-            </Tooltip>
+            <HelpTooltip
+              className="spacer-left"
+              overlay={translate('quality_profiles.extends_built_in')}
+            />
           )}
         </div>
       </td>
index e2cd08698cefa11c440ae19e79f1f12fa8c43b84..1422fddb0497a2ea7be7a4fe3111aae2de515052 100644 (file)
@@ -19,7 +19,7 @@
  */
 import * as React from 'react';
 import { Link } from 'react-router';
-import Tooltip from '../../../components/controls/Tooltip';
+import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { getDeprecatedActiveRulesUrl } from '../../../helpers/urls';
 import { translate } from '../../../helpers/l10n';
 
@@ -33,10 +33,11 @@ export default function ProfileRulesDeprecatedWarning(props: Props) {
   return (
     <div className="quality-profile-rules-deprecated clearfix">
       <span className="pull-left">
-        {translate('quality_profiles.deprecated_rules')}
-        <Tooltip overlay={translate('quality_profiles.deprecated_rules_description')}>
-          <i className="icon-help spacer-left" />
-        </Tooltip>
+        <span className="text-middle">{translate('quality_profiles.deprecated_rules')}</span>
+        <HelpTooltip
+          className="spacer-left"
+          overlay={translate('quality_profiles.deprecated_rules_description')}
+        />
       </span>
       <Link
         className="pull-right"
index 2a14b31b4ba619db708150f4f0959b8aa2731e9c..3a305bca0918238b24d169a50e32d52fc8fa8760 100644 (file)
@@ -19,7 +19,7 @@
  */
 import * as React from 'react';
 import { Link } from 'react-router';
-import Tooltip from '../../../components/controls/Tooltip';
+import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { getRulesUrl } from '../../../helpers/urls';
 import { translate } from '../../../helpers/l10n';
 
@@ -45,12 +45,13 @@ export default function ProfileRulesSonarWayComparison(props: Props) {
   return (
     <div className="quality-profile-rules-sonarway-missing clearfix">
       <span className="pull-left">
-        {translate('quality_profiles.sonarway_missing_rules')}
-        <Tooltip overlay={translate('quality_profiles.sonarway_missing_rules_description')}>
-          <i className="icon-help spacer-left" />
-        </Tooltip>
+        <span className="text-middle">{translate('quality_profiles.sonarway_missing_rules')}</span>
+        <HelpTooltip
+          className="spacer-left"
+          overlay={translate('quality_profiles.sonarway_missing_rules_description')}
+        />
       </span>
-      <Link className="pull-right" to={url}>
+      <Link className="pull-right" data-test="rules" to={url}>
         {props.sonarWayMissingRules}
       </Link>
     </div>
index ace1b6fe12a9293ea188571eacc48d6d46a205f1..308c513f84f25ae5d5f64d7fda1c5846f79eb8ed 100644 (file)
@@ -7,14 +7,15 @@ exports[`should render correctly 1`] = `
   <span
     className="pull-left"
   >
-    quality_profiles.deprecated_rules
-    <Tooltip
-      overlay="quality_profiles.deprecated_rules_description"
+    <span
+      className="text-middle"
     >
-      <i
-        className="icon-help spacer-left"
-      />
-    </Tooltip>
+      quality_profiles.deprecated_rules
+    </span>
+    <HelpTooltip
+      className="spacer-left"
+      overlay="quality_profiles.deprecated_rules_description"
+    />
   </span>
   <Link
     className="pull-right"
index 4719fd50cf5d2b782f54d16832096e21e5da1158..69d5092c58973fc92e66c564fe5aa6a3dce266fc 100644 (file)
@@ -7,17 +7,19 @@ exports[`should render correctly 1`] = `
   <span
     className="pull-left"
   >
-    quality_profiles.sonarway_missing_rules
-    <Tooltip
-      overlay="quality_profiles.sonarway_missing_rules_description"
+    <span
+      className="text-middle"
     >
-      <i
-        className="icon-help spacer-left"
-      />
-    </Tooltip>
+      quality_profiles.sonarway_missing_rules
+    </span>
+    <HelpTooltip
+      className="spacer-left"
+      overlay="quality_profiles.sonarway_missing_rules_description"
+    />
   </span>
   <Link
     className="pull-right"
+    data-test="rules"
     onlyActiveOnIndex={false}
     style={Object {}}
     to={
index a0b3302ff480dd3d37de156306158bdc7fde6155..d05b77b2fdaad1167dcef0ecaac310d6deee1661 100644 (file)
@@ -28,7 +28,7 @@ import { getRulesUrl } from '../../../helpers/urls';
 import { isStagnant } from '../utils';
 import { Profile } from '../types';
 import Tooltip from '../../../components/controls/Tooltip';
-import DocTooltip from '../../../components/docs/DocTooltip';
+import DocInclude from '../../../components/docs/DocInclude';
 
 interface Props {
   onRequestFail: (reason: any) => void;
@@ -51,12 +51,7 @@ export default class ProfilesListRow extends React.PureComponent<Props> {
             {profile.name}
           </ProfileLink>
         </div>
-        {profile.isBuiltIn && (
-          <>
-            <BuiltInQualityProfileBadge className="spacer-left" />
-            <DocTooltip className="spacer-left" doc="quality-profiles/built-in-quality-profile" />
-          </>
-        )}
+        {profile.isBuiltIn && <BuiltInQualityProfileBadge className="spacer-left" />}
       </div>
     );
   }
@@ -66,10 +61,15 @@ export default class ProfilesListRow extends React.PureComponent<Props> {
 
     if (profile.isDefault) {
       return (
-        <>
+        <Tooltip
+          overlay={
+            <DocInclude
+              className="abs-width-300 cut-margins"
+              path="/tooltips/quality-profiles/default-quality-profile"
+            />
+          }>
           <span className="badge">{translate('default')}</span>
-          <DocTooltip className="table-cell-doc" doc="quality-profiles/default-quality-profile" />
-        </>
+        </Tooltip>
       );
     }
 
index f77c7c0220b91feb9a010da31a3a7f23561d379e..696beeb9cdc5098459729d12248d406d70ace3e5 100644 (file)
@@ -63,8 +63,8 @@
 
 .oauth-providers-help {
   position: absolute;
-  top: 12px;
-  right: -32px;
+  top: 15px;
+  right: -24px;
 }
 
 .oauth-providers + .login-form {
index b13fae5dd5ecf9f1f23e14717b3a90f577298524..1ecf27de26e9b0b1a1228986ce64683e5867130c 100644 (file)
 import * as React from 'react';
 import * as classNames from 'classnames';
 import { translateWithParameters } from '../../../helpers/l10n';
-import * as theme from '../../../app/theme';
 import { IdentityProvider } from '../../../app/types';
-import Tooltip from '../../../components/controls/Tooltip';
-import HelpIcon from '../../../components/icons-components/HelpIcon';
+import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { isDarkColor } from '../../../helpers/colors';
 import { getBaseUrl } from '../../../helpers/urls';
 import './OAuthProviders.css';
@@ -80,11 +78,7 @@ function OAuthProvider({ format, identityProvider, returnTo }: ItemProps) {
         <span>{format(identityProvider.name)}</span>
       </a>
       {identityProvider.helpMessage && (
-        <Tooltip overlay={identityProvider.helpMessage}>
-          <div className="oauth-providers-help">
-            <HelpIcon fill={theme.blue} />
-          </div>
-        </Tooltip>
+        <HelpTooltip className="oauth-providers-help" overlay={identityProvider.helpMessage} />
       )}
     </li>
   );
index e37305eb82069e9961956eeef2fa46b4e50dff78..7ab0639e4740c3b7d8f15ef0ece1add60bf4ee85 100644 (file)
@@ -81,17 +81,10 @@ exports[`should render correctly 3`] = `
       login.login_with_x.Bar
     </span>
   </a>
-  <Tooltip
+  <HelpTooltip
+    className="oauth-providers-help"
     overlay="Help message!"
-  >
-    <div
-      className="oauth-providers-help"
-    >
-      <HelpIcon
-        fill="#4b9fd5"
-      />
-    </div>
-  </Tooltip>
+  />
 </li>
 `;
 
index 1f098d804c9c2b1ec297d27f1dd5ab8d3b7a6768..49bc4e20220e04cef6c7b0a48a0b27aeffe1c600 100644 (file)
@@ -19,8 +19,7 @@
  */
 import * as React from 'react';
 import Checkbox from '../../../components/controls/Checkbox';
-import HelpIcon from '../../../components/icons-components/HelpIcon';
-import Tooltip from '../../../components/controls/Tooltip';
+import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { translate } from '../../../helpers/l10n';
 import SearchBox from '../../../components/controls/SearchBox';
 
@@ -42,27 +41,25 @@ export default function Search(props: Props) {
       </div>
 
       <div className="big-spacer-top">
-        <Checkbox checked={showInternal} onCheck={onToggleInternal}>
+        <Checkbox checked={showInternal} className="text-middle" onCheck={onToggleInternal}>
           <span className="little-spacer-left">{translate('api_documentation.show_internal')}</span>
         </Checkbox>
-        <Tooltip overlay={translate('api_documentation.internal_tooltip')}>
-          <span>
-            <HelpIcon className="spacer-left text-info" />
-          </span>
-        </Tooltip>
+        <HelpTooltip
+          className="spacer-left"
+          overlay={translate('api_documentation.internal_tooltip')}
+        />
       </div>
 
       <div className="spacer-top">
-        <Checkbox checked={showDeprecated} onCheck={onToggleDeprecated}>
+        <Checkbox checked={showDeprecated} className="text-middle" onCheck={onToggleDeprecated}>
           <span className="little-spacer-left">
             {translate('api_documentation.show_deprecated')}
           </span>
         </Checkbox>
-        <Tooltip overlay={translate('api_documentation.deprecation_tooltip')}>
-          <span>
-            <HelpIcon className="spacer-left text-info" />
-          </span>
-        </Tooltip>
+        <HelpTooltip
+          className="spacer-left"
+          overlay={translate('api_documentation.deprecation_tooltip')}
+        />
       </div>
     </div>
   );
index 339160fb83bcdb4ec84c0336ec5d406064428d6e..1802e14098850eda6d01e28e7e4b5a4716038b62 100644 (file)
@@ -15,6 +15,7 @@ exports[`should render correctly 1`] = `
   >
     <Checkbox
       checked={false}
+      className="text-middle"
       onCheck={[Function]}
       thirdState={false}
     >
@@ -24,21 +25,17 @@ exports[`should render correctly 1`] = `
         api_documentation.show_internal
       </span>
     </Checkbox>
-    <Tooltip
+    <HelpTooltip
+      className="spacer-left"
       overlay="api_documentation.internal_tooltip"
-    >
-      <span>
-        <HelpIcon
-          className="spacer-left text-info"
-        />
-      </span>
-    </Tooltip>
+    />
   </div>
   <div
     className="spacer-top"
   >
     <Checkbox
       checked={false}
+      className="text-middle"
       onCheck={[Function]}
       thirdState={false}
     >
@@ -48,15 +45,10 @@ exports[`should render correctly 1`] = `
         api_documentation.show_deprecated
       </span>
     </Checkbox>
-    <Tooltip
+    <HelpTooltip
+      className="spacer-left"
       overlay="api_documentation.deprecation_tooltip"
-    >
-      <span>
-        <HelpIcon
-          className="spacer-left text-info"
-        />
-      </span>
-    </Tooltip>
+    />
   </div>
 </div>
 `;
index 2a23425df063249ea353033112cbc64c4308d2fb..c2898e6725f078fdbb9cbadb9840d296ea5deeb7 100644 (file)
@@ -19,6 +19,7 @@
  */
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
+import { Link } from 'react-router';
 import { translate } from '../../../helpers/l10n';
 
 interface Props {
@@ -40,12 +41,7 @@ export default function PageHeader({ children, loading }: Props) {
           id={'webhooks.description'}
           values={{
             url: (
-              <a
-                href="https://redirect.sonarsource.com/doc/webhooks.html"
-                rel="noopener noreferrer"
-                target="_blank">
-                {translate('webhooks.documentation_link')}
-              </a>
+              <Link to="/documentation/webhooks">{translate('webhooks.documentation_link')}</Link>
             )
           }}
         />
index e44b8019fca435203033bf7b8c205c15fe8caa72..ce4b526d41de97f27d0521e2214b451a35fbfc5d 100644 (file)
@@ -21,13 +21,13 @@ exports[`should render correctly 1`] = `
       id="webhooks.description"
       values={
         Object {
-          "url": <a
-            href="https://redirect.sonarsource.com/doc/webhooks.html"
-            rel="noopener noreferrer"
-            target="_blank"
+          "url": <Link
+            onlyActiveOnIndex={false}
+            style={Object {}}
+            to="/documentation/webhooks"
           >
             webhooks.documentation_link
-          </a>,
+          </Link>,
         }
       }
     />
index b54a82c8fb182340a1ef89c484c9e9ade27bce47..1738e5c1fa14a3dbfdefeee2372d6502c3766e0f 100644 (file)
@@ -22,7 +22,7 @@ import StatusIndicator from './StatusIndicator';
 import Level from '../ui/Level';
 import BugIcon from '../icons-components/BugIcon';
 import CodeSmellIcon from '../icons-components/CodeSmellIcon';
-import HelpIcon from '../icons-components/HelpIcon';
+import HelpTooltip from '../controls/HelpTooltip';
 import Tooltip from '../controls/Tooltip';
 import VulnerabilityIcon from '../icons-components/VulnerabilityIcon';
 import { BranchLike } from '../../app/types';
@@ -81,15 +81,14 @@ export default function BranchStatus({ branchLike, concise = false }: Props) {
           <CodeSmellIcon className="little-spacer-left" />
         </li>
         {shouldDisplayHelper && (
-          <Tooltip
+          <HelpTooltip
+            className="spacer-left"
             overlay={translateWithParameters(
               'branches.short_lived.quality_gate.description',
               totalIssues
-            )}>
-            <li className="spacer-left">
-              <HelpIcon className="text-info" />
-            </li>
-          </Tooltip>
+            )}
+            tagName="li"
+          />
         )}
       </ul>
     );
index 369c4f0b9d247bfe87746b75272be5df0deb4e19..bf868d3263ce975a4d3e135d23b31e197b5da9b0 100644 (file)
@@ -167,16 +167,10 @@ exports[`renders status of short-living branches 4`] = `
       className="little-spacer-left"
     />
   </li>
-  <Tooltip
+  <HelpTooltip
+    className="spacer-left"
     overlay="branches.short_lived.quality_gate.description.1"
-  >
-    <li
-      className="spacer-left"
-    >
-      <HelpIcon
-        className="text-info"
-      />
-    </li>
-  </Tooltip>
+    tagName="li"
+  />
 </ul>
 `;
diff --git a/server/sonar-web/src/main/js/components/controls/HelpTooltip.css b/server/sonar-web/src/main/js/components/controls/HelpTooltip.css
new file mode 100644 (file)
index 0000000..09c45fb
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.
+ */
+.help-tooltip {
+  display: inline-flex;
+  align-items: center;
+  vertical-align: middle;
+}
+
+.help-toolip-link {
+  display: block;
+  width: 12px;
+  height: 12px;
+  border: none;
+}
diff --git a/server/sonar-web/src/main/js/components/controls/HelpTooltip.tsx b/server/sonar-web/src/main/js/components/controls/HelpTooltip.tsx
new file mode 100644 (file)
index 0000000..bc68b86
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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 * as classNames from 'classnames';
+import Tooltip from './Tooltip';
+import HelpIcon from '../icons-components/HelpIcon';
+import * as theme from '../../app/theme';
+import './HelpTooltip.css';
+
+interface Props {
+  className?: string;
+  children?: React.ReactNode;
+  onShow?: () => void;
+  overlay: React.ReactNode;
+  tagName?: string;
+}
+
+export default function HelpTooltip(props: Props) {
+  const { children = <HelpIcon fill={theme.gray71} size={12} />, tagName = 'div' } = props;
+
+  return React.createElement(
+    tagName,
+    { className: classNames('help-tooltip', props.className) },
+    <Tooltip mouseLeaveDelay={0.25} onShow={props.onShow} overlay={props.overlay}>
+      <span className="display-inline-flex-center">{children}</span>
+    </Tooltip>
+  );
+}
diff --git a/server/sonar-web/src/main/js/components/controls/Popup.tsx b/server/sonar-web/src/main/js/components/controls/Popup.tsx
deleted file mode 100644 (file)
index 68f8415..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 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 OutsideClickHandler from './OutsideClickHandler';
-import Tooltip from './Tooltip';
-
-interface Props {
-  children: (props: { onClick: () => void }) => React.ReactElement<any>;
-  overlay: React.ReactNode;
-}
-
-interface State {
-  visible: boolean;
-}
-
-export default class Popup extends React.Component<Props, State> {
-  state: State = { visible: false };
-
-  componentWillReceiveProps(nextProps: Props) {
-    if (nextProps.overlay !== this.props.overlay) {
-      this.setState({ visible: false });
-    }
-  }
-
-  handleClick = (event?: React.MouseEvent<HTMLElement>) => {
-    if (event) {
-      event.preventDefault();
-      event.currentTarget.blur();
-    }
-
-    // defer opening to not trigger OutsideClickHandler.onClickOutside callback
-    setTimeout(() => {
-      this.setState({ visible: true });
-    }, 0);
-  };
-
-  handleClickOutside = () => {
-    this.setState({ visible: false });
-  };
-
-  renderOverlay() {
-    return (
-      <OutsideClickHandler onClickOutside={this.handleClickOutside}>
-        {({ ref }) => <div ref={ref}>{this.props.overlay}</div>}
-      </OutsideClickHandler>
-    );
-  }
-
-  render() {
-    return (
-      <Tooltip classNameSpace="popup" overlay={this.renderOverlay()} visible={this.state.visible}>
-        {this.props.children({ onClick: this.handleClick })}
-      </Tooltip>
-    );
-  }
-}
index bbb8ae5c9427f4053fdf642401bf42861bc340a0..9aeb7e42b3cbf71adee6d90664070c4b000e86cb 100644 (file)
@@ -17,8 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
-.tooltip,
-.popup {
+.tooltip {
   position: absolute;
   z-index: var(--tooltipZIndex);
   display: block;
   animation: fadeIn 0.3s forwards;
 }
 
-.popup {
-  font-size: var(--baseFontSize);
-  font-weight: normal;
-}
-
-.tooltip.top,
-.popup.top {
+.tooltip.top {
   padding: 5px 0;
   margin-top: -3px;
 }
 
-.tooltip.right,
-.popup.right {
+.tooltip.right {
   padding: 0 5px;
   margin-left: 3px;
 }
 
-.tooltip.bottom,
-.popup.bottom {
+.tooltip.bottom {
   padding: 5px 0;
   margin-top: 3px;
 }
 
-.tooltip.left,
-.popup.left {
+.tooltip.left {
   padding: 0 5px;
   margin-left: -3px;
 }
 
-.tooltip-inner,
-.popup-inner {
+.tooltip-inner {
   max-width: 300px;
   text-align: left;
   text-decoration: none;
 }
 
 .tooltip-inner {
-  padding: 3px 8px;
+  padding: 12px 17px;
   color: #fff;
   background-color: #475760;
   letter-spacing: 0.04em;
 }
 
-.popup-inner {
-  padding: calc(2 * var(--gridSize));
-  border: 1px solid var(--barBorderColor);
-  color: var(--baseFontColor);
-  background-color: #fff;
-  box-shadow: var(--defaultShadow);
-}
-
 .tooltip-inner .alert {
   margin-bottom: 5px;
   border-radius: 4px;
 }
 
 .tooltip-inner a {
-  color: var(--lightBlue);
+  border-bottom-color: #8da6b3;
+  color: #a5d0ea;
+}
+
+.tooltip-inner hr {
+  background-color: #5d6d75;
 }
 
-.tooltip-arrow,
-.popup-arrow,
-.popup-arrow::after {
+.tooltip-arrow {
   position: absolute;
   width: 0;
   height: 0;
   border: solid transparent;
 }
 
-.tooltip.top .tooltip-arrow,
-.popup.top .popup-arrow,
-.popup.top .popup-arrow::after {
+.tooltip.top .tooltip-arrow {
   bottom: 0;
   left: 50%;
   border-width: 5px 5px 0;
   border-top-color: #475760;
 }
 
-.popup.top .popup-arrow {
-  border-top-color: var(--barBorderColor);
-}
-
-.popup.top .popup-arrow::after {
-  content: '';
-  border-top-color: #fff;
-  transform: translateX(-5px) translateY(-1px);
-}
-
-.tooltip.right .tooltip-arrow,
-.popup.right .popup-arrow,
-.popup.right .popup-arrow::after {
+.tooltip.right .tooltip-arrow {
   top: 50%;
   left: 0;
   transform: translateY(-5px);
   border-right-color: #475760;
 }
 
-.popup.right .popup-arrow {
-  border-right-color: var(--barBorderColor);
-}
-
-.popup.right .popup-arrow::after {
-  content: '';
-  border-right-color: #fff;
-  transform: translateY(-5px) translateX(1px);
-}
-
-.tooltip.left .tooltip-arrow,
-.popup.left .popup-arrow,
-.popup.left .popup-arrow::after {
+.tooltip.left .tooltip-arrow {
   top: 50%;
   right: 0;
   transform: translateY(-5px);
   border-left-color: #475760;
 }
 
-.popup.left .popup-arrow {
-  border-left-color: var(--barBorderColor);
-}
-
-.popup.left .popup-arrow::after {
-  content: '';
-  border-left-color: #fff;
-  transform: translateY(-5px) translateX(-1px);
-}
-
-.tooltip.bottom .tooltip-arrow,
-.popup.bottom .popup-arrow,
-.popup.bottom .popup-arrow::after {
+.tooltip.bottom .tooltip-arrow {
   top: 0;
   left: 50%;
   transform: translateX(-5px);
   border-bottom-color: #475760;
 }
 
-.popup.bottom .popup-arrow {
-  border-bottom-color: var(--barBorderColor);
-}
-
-.popup.bottom .popup-arrow::after {
-  content: '';
-  border-bottom-color: #fff;
-  transform: translateX(-5px) translateY(1px);
-}
-
 @keyframes fadeIn {
   from {
     opacity: 0;
index adc29a6270e3f84469a03764664f518da8b2c720..ca6803887e9b810ee649edf336e3bca51ec7961c 100644 (file)
@@ -28,6 +28,7 @@ interface Props {
   classNameSpace?: string;
   children: React.ReactElement<{}>;
   mouseEnterDelay?: number;
+  mouseLeaveDelay?: number;
   onShow?: () => void;
   onHide?: () => void;
   overlay: React.ReactNode;
@@ -65,8 +66,10 @@ export default function Tooltip(props: Props) {
 export class TooltipInner extends React.Component<Props, State> {
   throttledPositionTooltip: (() => void);
   mouseEnterInterval?: number;
+  mouseLeaveInterval?: number;
   tooltipNode?: HTMLElement | null;
   mounted = false;
+  mouseIn = false;
 
   static defaultProps = {
     mouseEnterDelay: 0.1
@@ -113,6 +116,7 @@ export class TooltipInner extends React.Component<Props, State> {
   componentWillUnmount() {
     this.mounted = false;
     this.removeEventListeners();
+    this.clearIntervals();
   }
 
   addEventListeners = () => {
@@ -125,6 +129,11 @@ export class TooltipInner extends React.Component<Props, State> {
     window.removeEventListener('scroll', this.throttledPositionTooltip);
   };
 
+  clearIntervals = () => {
+    window.clearInterval(this.mouseEnterInterval);
+    window.clearInterval(this.mouseLeaveInterval);
+  };
+
   isVisible = () => {
     return this.props.visible !== undefined ? this.props.visible : this.state.visible;
   };
@@ -235,15 +244,31 @@ export class TooltipInner extends React.Component<Props, State> {
       window.clearInterval(this.mouseEnterInterval);
       this.mouseEnterInterval = undefined;
     }
-    if (this.props.visible === undefined) {
-      this.setState({ visible: false });
-    }
 
-    if (this.props.onHide) {
-      this.props.onHide();
+    if (!this.mouseIn) {
+      this.mouseLeaveInterval = window.setTimeout(() => {
+        if (this.mounted) {
+          if (this.props.visible === undefined && !this.mouseIn) {
+            this.setState({ visible: false });
+          }
+        }
+      }, (this.props.mouseLeaveDelay || 0) * 1000);
+
+      if (this.props.onHide) {
+        this.props.onHide();
+      }
     }
   };
 
+  handleOverlayMouseEnter = () => {
+    this.mouseIn = true;
+  };
+
+  handleOverlayMouseLeave = () => {
+    this.mouseIn = false;
+    this.handleMouseLeave();
+  };
+
   render() {
     const { classNameSpace = 'tooltip' } = this.props;
 
@@ -257,6 +282,8 @@ export class TooltipInner extends React.Component<Props, State> {
           <TooltipPortal>
             <div
               className={`${classNameSpace} ${this.getPlacement()}`}
+              onMouseEnter={this.handleOverlayMouseEnter}
+              onMouseLeave={this.handleOverlayMouseLeave}
               ref={this.tooltipNodeRef}
               style={
                 isMeasured(this.state)
index 0f4bbb02ba03275f0ea86e4b747837214cf40527..f0b1f65f86091d07ce05a08c2bcf7531318494c8 100644 (file)
@@ -56,6 +56,8 @@ it('should open & close', () => {
   expect(onShow).toBeCalled();
 
   wrapper.find('#tooltip').simulate('mouseleave');
+  jest.runOnlyPendingTimers();
+  wrapper.update();
   expect(wrapper).toMatchSnapshot();
   expect(onHide).toBeCalled();
 });
index f7e3657057cb054b6a4235baaaaef8610367478c..4a369aceaa4e507a85fcafdfecc92552b8d87285 100644 (file)
@@ -10,6 +10,8 @@ exports[`should open & close 1`] = `
   <TooltipPortal>
     <div
       className="tooltip bottom"
+      onMouseEnter={[Function]}
+      onMouseLeave={[Function]}
     >
       <div
         className="tooltip-inner"
@@ -56,6 +58,8 @@ exports[`should render 2`] = `
   <TooltipPortal>
     <div
       className="tooltip bottom"
+      onMouseEnter={[Function]}
+      onMouseLeave={[Function]}
     >
       <div
         className="tooltip-inner"
index cafed4edcd0d0c8851a6d8ab4bb1b120e6849771..d055c6cf16a115dae33daa4207106eeeb2599e1b 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
+import { getBaseUrl } from '../../helpers/urls';
 
 export default function DocImg(props: React.ImgHTMLAttributes<HTMLImageElement>) {
   const { alt, src, ...other } = props;
 
   if (process.env.NODE_ENV === 'development') {
-    return <img alt={alt} className="max-width-100" src={src} {...other} />;
+    return <img alt={alt} className="max-width-100" src={getBaseUrl() + src} {...other} />;
   }
 
-  return <img alt={alt} className="max-width-100" src={'/images/embed-doc' + src} {...other} />;
+  return (
+    <img
+      alt={alt}
+      className="max-width-100"
+      src={getBaseUrl() + '/images/embed-doc' + src}
+      {...other}
+    />
+  );
 }
index d90d893a0bd4951d8d1deaacb6a500b78a909850..85298633439c5de385442febdd6ac2cae45a30ad 100644 (file)
@@ -21,6 +21,7 @@ import * as React from 'react';
 import DocMarkdownBlock from './DocMarkdownBlock';
 
 interface Props {
+  className?: string;
   path: string;
 }
 
@@ -67,6 +68,6 @@ export default class DocInclude extends React.PureComponent<Props, State> {
   };
 
   render() {
-    return <DocMarkdownBlock content={this.state.content} />;
+    return <DocMarkdownBlock className={this.props.className} content={this.state.content} />;
   }
 }
index 17b99af9c4ebb0952abbe55b00037bb3326ef7ba..5e741918f9509c7cd5f5148f1013cd83930b910c 100644 (file)
@@ -19,6 +19,7 @@
  */
 import * as React from 'react';
 import { Link } from 'react-router';
+import DetachIcon from '../../components/icons-components/DetachIcon';
 
 export default function DocLink(props: React.AnchorHTMLAttributes<HTMLAnchorElement>) {
   const { children, href, ...other } = props;
@@ -32,8 +33,14 @@ export default function DocLink(props: React.AnchorHTMLAttributes<HTMLAnchorElem
   }
 
   return (
-    <a href={href} {...other}>
-      {children}
-    </a>
+    <>
+      <a className="text-middle" href={href} rel="noopener noreferrer" target="_blank" {...other}>
+        {children}
+      </a>
+      <DetachIcon
+        className="text-middle text-muted little-spacer-left little-spacer-right"
+        size={12}
+      />
+    </>
   );
 }
index 5c719443490d3a26035ad458a7f3570f3eb8373b..e064f15d2ee0a7acde5b662e41dd19043007a8be 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import * as classNames from 'classnames';
 import DocMarkdownBlock from './DocMarkdownBlock';
-import HelpIcon from '../icons-components/HelpIcon';
-import Tooltip from '../controls/Tooltip';
-import OutsideClickHandler from '../controls/OutsideClickHandler';
-import * as theme from '../../app/theme';
+import HelpTooltip from '../controls/HelpTooltip';
 
 interface Props {
   className?: string;
+  children?: React.ReactNode;
   /** Key of the documentation chunk */
   doc: string;
 }
@@ -77,23 +74,6 @@ export default class DocTooltip extends React.PureComponent<Props, State> {
     this.setState({ open: false });
   };
 
-  handleHelpClick = (event: React.MouseEvent<HTMLAnchorElement>) => {
-    event.preventDefault();
-    event.currentTarget.blur();
-    if (!this.state.open && !this.state.loading && this.state.content === undefined) {
-      this.fetchContent();
-    }
-
-    if (this.state.open) {
-      this.setState({ open: false });
-    } else {
-      // defer opening to not trigger OutsideClickHandler.onClickOutside callback
-      setTimeout(() => {
-        this.setState({ open: true });
-      }, 0);
-    }
-  };
-
   renderOverlay() {
     if (this.state.loading) {
       return (
@@ -103,32 +83,17 @@ export default class DocTooltip extends React.PureComponent<Props, State> {
       );
     }
 
-    return (
-      <OutsideClickHandler onClickOutside={this.close}>
-        {({ ref }) => (
-          <div ref={ref}>
-            <DocMarkdownBlock className="cut-margins abs-width-300" content={this.state.content} />
-          </div>
-        )}
-      </OutsideClickHandler>
-    );
+    return <DocMarkdownBlock className="cut-margins abs-width-300" content={this.state.content} />;
   }
 
   render() {
     return (
-      <div className={classNames('display-flex-center', this.props.className)}>
-        <Tooltip
-          classNameSpace="popup"
-          overlay={this.renderOverlay()}
-          visible={this.state.content !== undefined && this.state.open}>
-          <a
-            className="display-flex-center link-no-underline"
-            href="#"
-            onClick={this.handleHelpClick}>
-            <HelpIcon fill={theme.gray80} size={12} />
-          </a>
-        </Tooltip>
-      </div>
+      <HelpTooltip
+        className={this.props.className}
+        onShow={this.fetchContent}
+        overlay={this.renderOverlay()}>
+        {this.props.children}
+      </HelpTooltip>
     );
   }
 }
index bc5b4998cc7a8a720ed07595cf3061dd9b9ffa9e..570b68e37c027e411aec57c03aeb2100a1d03a86 100644 (file)
@@ -20,7 +20,6 @@
 import * as React from 'react';
 import { shallow } from 'enzyme';
 import DocTooltip from '../DocTooltip';
-import { click } from '../../../helpers/testUtils';
 
 jest.useFakeTimers();
 
@@ -38,11 +37,3 @@ it('should reset state when receiving new doc', () => {
   wrapper.setProps({ doc: 'baz' });
   expect(wrapper.state()).toEqual({ content: undefined, loading: false, open: false });
 });
-
-it('should toggle', () => {
-  const wrapper = shallow(<DocTooltip doc="foo/bar" />);
-  expect(wrapper.state('open')).toBe(false);
-  click(wrapper.find('a'));
-  jest.runAllTimers();
-  expect(wrapper.state('open')).toBe(true);
-});
index 97a6d1d24bc84a65802c572228af7c21a80dfaeb..d5678b25137eee7b870997803459da415b60ae7c 100644 (file)
@@ -1,7 +1,16 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`should render simple link 1`] = `
-<a
-  href="http://sample.com"
-/>
+<React.Fragment>
+  <a
+    className="text-middle"
+    href="http://sample.com"
+    rel="noopener noreferrer"
+    target="_blank"
+  />
+  <DetachIcon
+    className="text-middle text-muted little-spacer-left little-spacer-right"
+    size={12}
+  />
+</React.Fragment>
 `;
index 38e7789c0442882ba7f4290156ba3182d22072a1..cbdf355d8558ae3e2c65dbc75f437c7b76e7f53a 100644 (file)
@@ -1,61 +1,28 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`should render 1`] = `
-<div
-  className="display-flex-center"
->
-  <Tooltip
-    classNameSpace="popup"
-    overlay={
-      <div
-        className="abs-width-300"
-      >
-        <i
-          className="spinner"
-        />
-      </div>
-    }
-    visible={true}
-  >
-    <a
-      className="display-flex-center link-no-underline"
-      href="#"
-      onClick={[Function]}
+<HelpTooltip
+  onShow={[Function]}
+  overlay={
+    <div
+      className="abs-width-300"
     >
-      <HelpIcon
-        fill="#cdcdcd"
-        size={12}
+      <i
+        className="spinner"
       />
-    </a>
-  </Tooltip>
-</div>
+    </div>
+  }
+/>
 `;
 
 exports[`should render 2`] = `
-<div
-  className="display-flex-center"
->
-  <Tooltip
-    classNameSpace="popup"
-    overlay={
-      <OutsideClickHandler
-        onClickOutside={[Function]}
-      >
-        [Function]
-      </OutsideClickHandler>
-    }
-    visible={true}
-  >
-    <a
-      className="display-flex-center link-no-underline"
-      href="#"
-      onClick={[Function]}
-    >
-      <HelpIcon
-        fill="#cdcdcd"
-        size={12}
-      />
-    </a>
-  </Tooltip>
-</div>
+<HelpTooltip
+  onShow={[Function]}
+  overlay={
+    <DocMarkdownBlock
+      className="cut-margins abs-width-300"
+      content="this is *bold* text"
+    />
+  }
+/>
 `;
index cc1ae72047aea669b39cc21d37407fb7fb91c485..f4544cf5028d7cc493296857628fd773d031782c 100644 (file)
@@ -19,8 +19,7 @@
  */
 import * as React from 'react';
 import OpenCloseIcon from '../icons-components/OpenCloseIcon';
-import HelpIcon from '../icons-components/HelpIcon';
-import Tooltip from '../controls/Tooltip';
+import HelpTooltip from '../controls/HelpTooltip';
 import { Button } from '../ui/buttons';
 import { translate, translateWithParameters } from '../../helpers/l10n';
 
@@ -47,13 +46,7 @@ export default class FacetHeader extends React.PureComponent<Props> {
     if (!this.props.helper) {
       return null;
     }
-    return (
-      <Tooltip overlay={this.props.helper}>
-        <span>
-          <HelpIcon className="spacer-left text-info" />
-        </span>
-      </Tooltip>
-    );
+    return <HelpTooltip className="spacer-left" overlay={this.props.helper} />;
   }
 
   renderValueIndicator() {
@@ -77,7 +70,7 @@ export default class FacetHeader extends React.PureComponent<Props> {
     return (
       <div className="search-navigator-facet-header-wrapper">
         {this.props.onClick ? (
-          <span className="search-navigator-facet-header">
+          <span className="search-navigator-facet-header display-flex-center">
             <a href="#" onClick={this.handleClick}>
               <OpenCloseIcon className="little-spacer-right" open={this.props.open} />
               {this.props.name}
@@ -85,7 +78,7 @@ export default class FacetHeader extends React.PureComponent<Props> {
             {this.renderHelper()}
           </span>
         ) : (
-          <span className="search-navigator-facet-header">
+          <span className="search-navigator-facet-header display-flex-center">
             {this.props.name}
             {this.renderHelper()}
           </span>
index e68fe594ca17eb42e6dc2210e3fa725f638d9b48..4dba5b7b37420d5be52c709fe3333c53fede950f 100644 (file)
@@ -5,7 +5,7 @@ exports[`should clear 1`] = `
   className="search-navigator-facet-header-wrapper"
 >
   <span
-    className="search-navigator-facet-header"
+    className="search-navigator-facet-header display-flex-center"
   >
     <a
       href="#"
@@ -42,7 +42,7 @@ exports[`should render closed facet with value 1`] = `
   className="search-navigator-facet-header-wrapper"
 >
   <span
-    className="search-navigator-facet-header"
+    className="search-navigator-facet-header display-flex-center"
   >
     <a
       href="#"
@@ -73,7 +73,7 @@ exports[`should render closed facet without value 1`] = `
   className="search-navigator-facet-header-wrapper"
 >
   <span
-    className="search-navigator-facet-header"
+    className="search-navigator-facet-header display-flex-center"
   >
     <a
       href="#"
@@ -97,7 +97,7 @@ exports[`should render open facet with value 1`] = `
   className="search-navigator-facet-header-wrapper"
 >
   <span
-    className="search-navigator-facet-header"
+    className="search-navigator-facet-header display-flex-center"
   >
     <a
       href="#"
@@ -121,7 +121,7 @@ exports[`should render open facet without value 1`] = `
   className="search-navigator-facet-header-wrapper"
 >
   <span
-    className="search-navigator-facet-header"
+    className="search-navigator-facet-header display-flex-center"
   >
     <a
       href="#"
@@ -145,7 +145,7 @@ exports[`should render without link 1`] = `
   className="search-navigator-facet-header-wrapper"
 >
   <span
-    className="search-navigator-facet-header"
+    className="search-navigator-facet-header display-flex-center"
   >
     foo
   </span>
index 80170315190a98b37521be9cc573cf1c476a9b53..8a2d9394501feb5cf50ebfc4fbeacf6d62e265cb 100644 (file)
@@ -24,16 +24,16 @@ export default function HelpIcon({ className, fill = 'currentColor', size = 16 }
   return (
     <svg
       className={className}
-      width={size}
       height={size}
-      viewBox="0 0 16 16"
       version="1.1"
-      xmlnsXlink="http://www.w3.org/1999/xlink"
-      xmlSpace="preserve">
+      viewBox="0 0 16 16"
+      width={size}
+      xmlSpace="preserve"
+      xmlnsXlink="http://www.w3.org/1999/xlink">
       <g transform="matrix(0.0364583,0,0,0.0364583,1,-0.166667)">
         <path
-          style={{ fill }}
           d="M224,344L224,296C224,293.667 223.25,291.75 221.75,290.25C220.25,288.75 218.333,288 216,288L168,288C165.667,288 163.75,288.75 162.25,290.25C160.75,291.75 160,293.667 160,296L160,344C160,346.333 160.75,348.25 162.25,349.75C163.75,351.25 165.667,352 168,352L216,352C218.333,352 220.25,351.25 221.75,349.75C223.25,348.25 224,346.333 224,344ZM288,176C288,161.333 283.375,147.75 274.125,135.25C264.875,122.75 253.333,113.083 239.5,106.25C225.667,99.417 211.5,96 197,96C156.5,96 125.583,113.75 104.25,149.25C101.75,153.25 102.417,156.75 106.25,159.75L139.25,184.75C140.417,185.75 142,186.25 144,186.25C146.667,186.25 148.75,185.25 150.25,183.25C159.083,171.917 166.25,164.25 171.75,160.25C177.417,156.25 184.583,154.25 193.25,154.25C201.25,154.25 208.375,156.417 214.625,160.75C220.875,165.083 224,170 224,175.5C224,181.833 222.333,186.917 219,190.75C215.667,194.583 210,198.333 202,202C191.5,206.667 181.875,213.875 173.125,223.625C164.375,233.375 160,243.833 160,255L160,264C160,266.333 160.75,268.25 162.25,269.75C163.75,271.25 165.667,272 168,272L216,272C218.333,272 220.25,271.25 221.75,269.75C223.25,268.25 224,266.333 224,264C224,260.833 225.792,256.708 229.375,251.625C232.958,246.542 237.5,242.417 243,239.25C248.333,236.25 252.417,233.875 255.25,232.125C258.083,230.375 261.917,227.458 266.75,223.375C271.583,219.292 275.292,215.292 277.875,211.375C280.458,207.458 282.792,202.417 284.875,196.25C286.958,190.083 288,183.333 288,176ZM384,224C384,258.833 375.417,290.958 358.25,320.375C341.083,349.792 317.792,373.083 288.375,390.25C258.958,407.417 226.833,416 192,416C157.167,416 125.042,407.417 95.625,390.25C66.208,373.083 42.917,349.792 25.75,320.375C8.583,290.958 0,258.833 0,224C0,189.167 8.583,157.042 25.75,127.625C42.917,98.208 66.208,74.917 95.625,57.75C125.042,40.583 157.167,32 192,32C226.833,32 258.958,40.583 288.375,57.75C317.792,74.917 341.083,98.208 358.25,127.625C375.417,157.042 384,189.167 384,224Z"
+          style={{ fill }}
         />
       </g>
     </svg>
index 5297bb3beddcf0a331adcee7db12068664d0fdf6..9d48f94d81c7eaffd678ce8d47fca4cf816306c7 100644 (file)
@@ -2559,11 +2559,11 @@ organization.change_visibility_form.submit=Change Default Visibility
 #
 #------------------------------------------------------------------------------
 embed_docs.suggestion=Suggestions For This Page
-embed_docs.documentation_index=Documentation index
+embed_docs.documentation=Documentation
 embed_docs.get_support=Get Support
 embed_docs.stay_connected=Stay Connected
-embed_docs.contact_form=Contact form
-embed_docs.analyze_new_project=Analyze new project
+embed_docs.contact_form=Contact Form
+embed_docs.analyze_new_project=Analyze New Project
 
 #------------------------------------------------------------------------------
 #
@@ -2679,8 +2679,6 @@ onboarding.project_watcher.failed=Something went wrong, please check the analysi
 # BRANCHES
 #
 #------------------------------------------------------------------------------
-branches.learn_how_to_analyze=Learn how to analyze branches in SonarQube
-branches.learn_how_to_analyze.text=Quickly setup branch analysis and get separate insights for each of your branches and pull requests.
 branches.delete=Delete Branch
 branches.delete.are_you_sure=Are you sure you want to delete branch "{0}"?
 branches.pull_request.delete=Delete Pull Request
@@ -2697,8 +2695,6 @@ branches.detection_of_long_living_branches=Detection of long living branches
 branches.detection_of_long_living_branches.description=Regular expression used to detect whether a branch is a long living branch (as opposed to short living branch), based on its name. This applies only during first analysis, the type of a branch cannot be changed later.
 branches.set_leak_period=Set Leak Period
 branches.last_analysis_date=Last Analysis Date
-branches.no_support.header=Get the most out of SonarQube with branches analysis
-branches.no_support.header.text=Analyze each branch of your project separately with the Developer Edition.
 branches.search_for_branches=Search for branches...
 branches.pull_requests=Pull Requests
 branches.short_lived.quality_gate.description=The branch status is passed because there are no open issue. The remaining {0} issue(s) have been confirmed.