Browse Source

SONAR-10611 use new help tooltips across the app (#203)

tags/7.5
Stas Vilchik 6 years ago
parent
commit
c87c2986e9
75 changed files with 539 additions and 818 deletions
  1. 7
    0
      server/sonar-docs/src/tooltips/branches/no-branch-support.md
  2. 7
    0
      server/sonar-docs/src/tooltips/branches/single-branch.md
  3. 2
    2
      server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/QualityProfilePage.java
  4. 12
    6
      server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopup.tsx
  5. 9
    1
      server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopupHelper.tsx
  6. 10
    3
      server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx
  7. 4
    1
      server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/__snapshots__/EmbedDocsPopup-test.tsx.snap
  8. 13
    29
      server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranch.tsx
  9. 8
    5
      server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranchesMenu.tsx
  10. 0
    39
      server/sonar-web/src/main/js/app/components/nav/component/SingleBranchHelperPopup.tsx
  11. 2
    2
      server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBranch-test.tsx
  12. 18
    6
      server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBranch-test.tsx.snap
  13. 16
    14
      server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBranchesMenu-test.tsx.snap
  14. 0
    25
      server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/NoBranchSupportPopup-test.tsx.snap
  15. 0
    24
      server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/SingleBranchHelperPopup-test.tsx.snap
  16. 1
    0
      server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx
  17. 0
    6
      server/sonar-web/src/main/js/app/styles/init/icons.css
  18. 2
    0
      server/sonar-web/src/main/js/app/utils/exposeLibraries.ts
  19. 17
    19
      server/sonar-web/src/main/js/apps/background-tasks/components/NoWorkersSupportPopup.tsx
  20. 5
    20
      server/sonar-web/src/main/js/apps/background-tasks/components/Workers.tsx
  21. 36
    33
      server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/Workers-test.tsx.snap
  22. 3
    8
      server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.js
  23. 5
    2
      server/sonar-web/src/main/js/apps/documentation/components/App.tsx
  24. 7
    6
      server/sonar-web/src/main/js/apps/documentation/styles.css
  25. 6
    5
      server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx
  26. 8
    9
      server/sonar-web/src/main/js/apps/overview/qualityGate/QualityGate.js
  27. 8
    11
      server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/QualityGate-test.js.snap
  28. 4
    6
      server/sonar-web/src/main/js/apps/permission-templates/components/ListHeader.js
  29. 3
    4
      server/sonar-web/src/main/js/apps/permissions/shared/components/PermissionHeader.tsx
  30. 1
    1
      server/sonar-web/src/main/js/apps/permissions/styles.css
  31. 8
    5
      server/sonar-web/src/main/js/apps/projectBranches/components/App.tsx
  32. 8
    7
      server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/App-test.tsx.snap
  33. 3
    8
      server/sonar-web/src/main/js/apps/projects/visualizations/Risk.tsx
  34. 3
    8
      server/sonar-web/src/main/js/apps/projects/visualizations/SimpleBubbleChart.tsx
  35. 8
    9
      server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Risk-test.tsx.snap
  36. 6
    10
      server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/SimpleBubbleChart-test.tsx.snap
  37. 6
    5
      server/sonar-web/src/main/js/apps/projectsManagement/Search.tsx
  38. 10
    16
      server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Search-test.tsx.snap
  39. 7
    9
      server/sonar-web/src/main/js/apps/quality-gates/components/BuiltInQualityGateBadge.tsx
  40. 1
    7
      server/sonar-web/src/main/js/apps/quality-gates/components/DetailsHeader.tsx
  41. 1
    1
      server/sonar-web/src/main/js/apps/quality-gates/components/List.js
  42. 5
    4
      server/sonar-web/src/main/js/apps/quality-profiles/components/BuiltInQualityProfileBadge.tsx
  43. 7
    5
      server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritanceBox.tsx
  44. 6
    5
      server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesDeprecatedWarning.tsx
  45. 7
    6
      server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesSonarWayComparison.tsx
  46. 8
    7
      server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesDeprecatedWarning-test.tsx.snap
  47. 9
    7
      server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesSonarWayComparison-test.tsx.snap
  48. 10
    10
      server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.tsx
  49. 2
    2
      server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.css
  50. 2
    8
      server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.tsx
  51. 3
    10
      server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/OAuthProviders-test.tsx.snap
  52. 11
    14
      server/sonar-web/src/main/js/apps/web-api/components/Search.tsx
  53. 8
    16
      server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Search-test.tsx.snap
  54. 2
    6
      server/sonar-web/src/main/js/apps/webhooks/components/PageHeader.tsx
  55. 5
    5
      server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/PageHeader-test.tsx.snap
  56. 6
    7
      server/sonar-web/src/main/js/components/common/BranchStatus.tsx
  57. 4
    10
      server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/BranchStatus-test.tsx.snap
  58. 11
    6
      server/sonar-web/src/main/js/components/controls/HelpTooltip.css
  59. 22
    15
      server/sonar-web/src/main/js/components/controls/HelpTooltip.tsx
  60. 0
    73
      server/sonar-web/src/main/js/components/controls/Popup.tsx
  61. 18
    82
      server/sonar-web/src/main/js/components/controls/Tooltip.css
  62. 32
    5
      server/sonar-web/src/main/js/components/controls/Tooltip.tsx
  63. 2
    0
      server/sonar-web/src/main/js/components/controls/__tests__/Tooltip-test.tsx
  64. 4
    0
      server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Tooltip-test.tsx.snap
  65. 10
    2
      server/sonar-web/src/main/js/components/docs/DocImg.tsx
  66. 2
    1
      server/sonar-web/src/main/js/components/docs/DocInclude.tsx
  67. 10
    3
      server/sonar-web/src/main/js/components/docs/DocLink.tsx
  68. 9
    44
      server/sonar-web/src/main/js/components/docs/DocTooltip.tsx
  69. 0
    9
      server/sonar-web/src/main/js/components/docs/__tests__/DocTooltip-test.tsx
  70. 12
    3
      server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocLink-test.tsx.snap
  71. 19
    52
      server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltip-test.tsx.snap
  72. 4
    11
      server/sonar-web/src/main/js/components/facet/FacetHeader.tsx
  73. 6
    6
      server/sonar-web/src/main/js/components/facet/__tests__/__snapshots__/FacetHeader-test.tsx.snap
  74. 5
    5
      server/sonar-web/src/main/js/components/icons-components/HelpIcon.tsx
  75. 3
    7
      sonar-core/src/main/resources/org/sonar/l10n/core.properties

+ 7
- 0
server/sonar-docs/src/tooltips/branches/no-branch-support.md View File

@@ -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)

+ 7
- 0
server/sonar-docs/src/tooltips/branches/single-branch.md View File

@@ -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)

+ 2
- 2
server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/QualityProfilePage.java View 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);
}


+ 12
- 6
server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopup.tsx View 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>

+ 9
- 1
server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopupHelper.tsx View File

@@ -20,12 +20,14 @@
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

+ 10
- 3
server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx View 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();
});

+ 4
- 1
server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/__snapshots__/EmbedDocsPopup-test.tsx.snap View 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"
>

+ 13
- 29
server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranch.tsx View 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>
);
}

+ 8
- 5
server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranchesMenu.tsx View 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 && (

+ 0
- 39
server/sonar-web/src/main/js/app/components/nav/component/SingleBranchHelperPopup.tsx View File

@@ -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>
</>
);
}

+ 2
- 2
server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBranch-test.tsx View 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', () => {

+ 18
- 6
server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBranch-test.tsx.snap View 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>
`;

+ 16
- 14
server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBranchesMenu-test.tsx.snap View 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={

+ 0
- 25
server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/NoBranchSupportPopup-test.tsx.snap View File

@@ -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>
`;

+ 0
- 24
server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/SingleBranchHelperPopup-test.tsx.snap View File

@@ -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>
`;

+ 1
- 0
server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx View 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}

+ 0
- 6
server/sonar-web/src/main/js/app/styles/init/icons.css View 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);

+ 2
- 0
server/sonar-web/src/main/js/app/utils/exposeLibraries.ts View 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,

+ 17
- 19
server/sonar-web/src/main/js/apps/background-tasks/components/NoWorkersSupportPopup.tsx View File

@@ -18,27 +18,25 @@
* 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>
</>
);
}

+ 5
- 20
server/sonar-web/src/main/js/apps/background-tasks/components/Workers.tsx View 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} />}

+ 36
- 33
server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/Workers-test.tsx.snap View 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>

+ 3
- 8
server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.js View 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">

+ 5
- 2
server/sonar-web/src/main/js/apps/documentation/components/App.tsx View 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>
);

server/sonar-web/src/main/js/app/components/nav/component/__tests__/NoBranchSupportPopup-test.tsx → server/sonar-web/src/main/js/apps/documentation/styles.css View File

@@ -17,10 +17,11 @@
* 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';
.documentation-layout-inner {
max-width: 740px;
}

it('renders', () => {
expect(shallow(<NoBranchSupportPopup />)).toMatchSnapshot();
});
.documentation-content > h1 {
margin-bottom: calc(4 * var(--gridSize));
font-size: 20px;
}

+ 6
- 5
server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx View 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

+ 8
- 9
server/sonar-web/src/main/js/apps/overview/qualityGate/QualityGate.js View File

@@ -21,12 +21,10 @@
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>
)}


+ 8
- 11
server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/QualityGate-test.js.snap View 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>
`;

+ 4
- 6
server/sonar-web/src/main/js/apps/permission-templates/components/ListHeader.js View 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>
));


+ 3
- 4
server/sonar-web/src/main/js/apps/permissions/shared/components/PermissionHeader.tsx View 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>
);

+ 1
- 1
server/sonar-web/src/main/js/apps/permissions/styles.css View File

@@ -29,5 +29,5 @@
}

.permissions-table .permission-column-inner {
width: 112px;
width: 100px;
}

+ 8
- 5
server/sonar-web/src/main/js/apps/projectBranches/components/App.tsx View 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

+ 8
- 7
server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/App-test.tsx.snap View 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={

+ 3
- 8
server/sonar-web/src/main/js/apps/projects/visualizations/Risk.tsx View 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">

+ 3
- 8
server/sonar-web/src/main/js/apps/projects/visualizations/SimpleBubbleChart.tsx View 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 && (

+ 8
- 9
server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Risk-test.tsx.snap View 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

+ 6
- 10
server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/SimpleBubbleChart-test.tsx.snap View 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

+ 6
- 5
server/sonar-web/src/main/js/apps/projectsManagement/Search.tsx View 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;


+ 10
- 16
server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Search-test.tsx.snap View 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"

+ 7
- 9
server/sonar-web/src/main/js/apps/quality-gates/components/BuiltInQualityGateBadge.tsx View File

@@ -20,14 +20,14 @@
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>;
}

+ 1
- 7
server/sonar-web/src/main/js/apps/quality-gates/components/DetailsHeader.tsx View 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">

+ 1
- 1
server/sonar-web/src/main/js/apps/quality-gates/components/List.js View 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>

+ 5
- 4
server/sonar-web/src/main/js/apps/quality-profiles/components/BuiltInQualityProfileBadge.tsx View 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>;

+ 7
- 5
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritanceBox.tsx View 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>

+ 6
- 5
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesDeprecatedWarning.tsx View 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"

+ 7
- 6
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesSonarWayComparison.tsx View 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>

+ 8
- 7
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesDeprecatedWarning-test.tsx.snap View 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"

+ 9
- 7
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesSonarWayComparison-test.tsx.snap View 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={

+ 10
- 10
server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.tsx View 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>
);
}


+ 2
- 2
server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.css View File

@@ -63,8 +63,8 @@

.oauth-providers-help {
position: absolute;
top: 12px;
right: -32px;
top: 15px;
right: -24px;
}

.oauth-providers + .login-form {

+ 2
- 8
server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.tsx View File

@@ -20,10 +20,8 @@
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>
);

+ 3
- 10
server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/OAuthProviders-test.tsx.snap View 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>
`;


+ 11
- 14
server/sonar-web/src/main/js/apps/web-api/components/Search.tsx View 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>
);

+ 8
- 16
server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Search-test.tsx.snap View 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>
`;

+ 2
- 6
server/sonar-web/src/main/js/apps/webhooks/components/PageHeader.tsx View 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>
)
}}
/>

+ 5
- 5
server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/PageHeader-test.tsx.snap View 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>,
}
}
/>

+ 6
- 7
server/sonar-web/src/main/js/components/common/BranchStatus.tsx View 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>
);

+ 4
- 10
server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/BranchStatus-test.tsx.snap View 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>
`;

server/sonar-web/src/main/js/app/components/nav/component/__tests__/SingleBranchHelperPopup-test.tsx → server/sonar-web/src/main/js/components/controls/HelpTooltip.css View File

@@ -17,10 +17,15 @@
* 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';
.help-tooltip {
display: inline-flex;
align-items: center;
vertical-align: middle;
}

it('renders', () => {
expect(shallow(<SingleBranchHelperPopup />)).toMatchSnapshot();
});
.help-toolip-link {
display: block;
width: 12px;
height: 12px;
border: none;
}

server/sonar-web/src/main/js/app/components/nav/component/NoBranchSupportPopup.tsx → server/sonar-web/src/main/js/components/controls/HelpTooltip.tsx View File

@@ -18,21 +18,28 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
import { translate } from '../../../../helpers/l10n';
import * as classNames from 'classnames';
import Tooltip from './Tooltip';
import HelpIcon from '../icons-components/HelpIcon';
import * as theme from '../../app/theme';
import './HelpTooltip.css';

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>
</>
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>
);
}

+ 0
- 73
server/sonar-web/src/main/js/components/controls/Popup.tsx View File

@@ -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>
);
}
}

+ 18
- 82
server/sonar-web/src/main/js/components/controls/Tooltip.css View 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;
@@ -33,37 +32,27 @@
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;
@@ -73,41 +62,34 @@
}

.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;
@@ -118,19 +100,7 @@
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);
@@ -142,19 +112,7 @@
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);
@@ -166,19 +124,7 @@
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);
@@ -190,16 +136,6 @@
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;

+ 32
- 5
server/sonar-web/src/main/js/components/controls/Tooltip.tsx View 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)

+ 2
- 0
server/sonar-web/src/main/js/components/controls/__tests__/Tooltip-test.tsx View 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();
});

+ 4
- 0
server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Tooltip-test.tsx.snap View 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"

+ 10
- 2
server/sonar-web/src/main/js/components/docs/DocImg.tsx View File

@@ -18,13 +18,21 @@
* 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}
/>
);
}

+ 2
- 1
server/sonar-web/src/main/js/components/docs/DocInclude.tsx View 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} />;
}
}

+ 10
- 3
server/sonar-web/src/main/js/components/docs/DocLink.tsx View 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}
/>
</>
);
}

+ 9
- 44
server/sonar-web/src/main/js/components/docs/DocTooltip.tsx View File

@@ -18,15 +18,12 @@
* 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>
);
}
}

+ 0
- 9
server/sonar-web/src/main/js/components/docs/__tests__/DocTooltip-test.tsx View 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);
});

+ 12
- 3
server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocLink-test.tsx.snap View 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>
`;

+ 19
- 52
server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltip-test.tsx.snap View 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"
/>
}
/>
`;

+ 4
- 11
server/sonar-web/src/main/js/components/facet/FacetHeader.tsx View 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>

+ 6
- 6
server/sonar-web/src/main/js/components/facet/__tests__/__snapshots__/FacetHeader-test.tsx.snap View 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>

+ 5
- 5
server/sonar-web/src/main/js/components/icons-components/HelpIcon.tsx View 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>

+ 3
- 7
sonar-core/src/main/resources/org/sonar/l10n/core.properties View 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.

Loading…
Cancel
Save