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

**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

**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

public QualityProfilePage shouldHaveMissingSonarWayRules(Integer nbRules) { public QualityProfilePage shouldHaveMissingSonarWayRules(Integer nbRules) {
Selenide.$(".quality-profile-rules-sonarway-missing") Selenide.$(".quality-profile-rules-sonarway-missing")
.shouldBe(Condition.visible) .shouldBe(Condition.visible)
.$("a").shouldHave(Condition.text(nbRules.toString()));
.shouldHave(Condition.text(nbRules.toString()));
return this; return this;
} }


public RulesPage showMissingSonarWayRules() { public RulesPage showMissingSonarWayRules() {
Selenide.$(".quality-profile-rules-sonarway-missing") Selenide.$(".quality-profile-rules-sonarway-missing")
.shouldBe(Condition.visible).$("a").click();
.shouldBe(Condition.visible).$("[data-test=\"rules\"]").click();
return Selenide.page(RulesPage.class); return Selenide.page(RulesPage.class);
} }



+ 12
- 6
server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopup.tsx View File

import * as PropTypes from 'prop-types'; import * as PropTypes from 'prop-types';
import { Link } from 'react-router'; import { Link } from 'react-router';
import { SuggestionLink } from './SuggestionsProvider'; import { SuggestionLink } from './SuggestionsProvider';
import { CurrentUser, isLoggedIn } from '../../types';
import BubblePopup, { BubblePopupPosition } from '../../../components/common/BubblePopup'; import BubblePopup, { BubblePopupPosition } from '../../../components/common/BubblePopup';
import { translate } from '../../../helpers/l10n'; import { translate } from '../../../helpers/l10n';
import { getBaseUrl } from '../../../helpers/urls'; import { getBaseUrl } from '../../../helpers/urls';


interface Props { interface Props {
currentUser: CurrentUser;
onClose: () => void; onClose: () => void;
popupPosition?: BubblePopupPosition; popupPosition?: BubblePopupPosition;
suggestions: Array<SuggestionLink>; suggestions: Array<SuggestionLink>;
translate('embed_docs.contact_form') translate('embed_docs.contact_form')
)} )}
</li> </li>
<li className="divider" />
{this.renderTitle(translate('embed_docs.stay_connected'))} {this.renderTitle(translate('embed_docs.stay_connected'))}
<li> <li>
{this.renderIconLink('https://about.sonarcloud.io/news/', 'sc-icon.svg', 'Product News')} {this.renderIconLink('https://about.sonarcloud.io/news/', 'sc-icon.svg', 'Product News')}
renderSonarQubeLinks() { renderSonarQubeLinks() {
return ( return (
<React.Fragment> <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" /> <li className="divider" />
{this.renderTitle(translate('embed_docs.get_support'))} {this.renderTitle(translate('embed_docs.get_support'))}
<li> <li>
'Stack Overflow' 'Stack Overflow'
)} )}
</li> </li>
<li className="divider" />
{this.renderTitle(translate('embed_docs.stay_connected'))} {this.renderTitle(translate('embed_docs.stay_connected'))}
<li> <li>
{this.renderIconLink('https://blog.sonarsource.com/', 'sq-icon.svg', 'Product News')} {this.renderIconLink('https://blog.sonarsource.com/', 'sq-icon.svg', 'Product News')}
{this.renderSuggestions()} {this.renderSuggestions()}
<li> <li>
<Link onClick={this.props.onClose} to="/documentation"> <Link onClick={this.props.onClose} to="/documentation">
{translate('embed_docs.documentation_index')}
{translate('embed_docs.documentation')}
</Link> </Link>
</li> </li>
<li> <li>

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

import * as React from 'react'; import * as React from 'react';
import EmbedDocsPopup from './EmbedDocsPopup'; import EmbedDocsPopup from './EmbedDocsPopup';
import { SuggestionLink } from './SuggestionsProvider'; import { SuggestionLink } from './SuggestionsProvider';
import { CurrentUser } from '../../types';
import BubblePopupHelper from '../../../components/common/BubblePopupHelper'; import BubblePopupHelper from '../../../components/common/BubblePopupHelper';
import HelpIcon from '../../../components/icons-components/HelpIcon'; import HelpIcon from '../../../components/icons-components/HelpIcon';
import Tooltip from '../../../components/controls/Tooltip'; import Tooltip from '../../../components/controls/Tooltip';
import { translate } from '../../../helpers/l10n'; import { translate } from '../../../helpers/l10n';


interface Props { interface Props {
currentUser: CurrentUser;
showTooltip: boolean; showTooltip: boolean;
suggestions: Array<SuggestionLink>; suggestions: Array<SuggestionLink>;
tooltip: boolean; tooltip: boolean;
<BubblePopupHelper <BubblePopupHelper
isOpen={this.state.helpOpen} isOpen={this.state.helpOpen}
offset={{ horizontal: 12, vertical: -10 }} 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" position="bottomleft"
togglePopup={this.setHelpDisplay}> togglePopup={this.setHelpDisplay}>
<Tooltip <Tooltip

+ 10
- 3
server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx View File



it('should display suggestion links', () => { it('should display suggestion links', () => {
const context = {}; 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(); wrapper.update();
expect(wrapper).toMatchSnapshot(); expect(wrapper).toMatchSnapshot();
}); });

+ 4
- 1
server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/__snapshots__/EmbedDocsPopup-test.tsx.snap View File

style={Object {}} style={Object {}}
to="/documentation" to="/documentation"
> >
embed_docs.documentation_index
embed_docs.documentation
</Link> </Link>
</li> </li>
<li> <li>
Stack Overflow Stack Overflow
</a> </a>
</li> </li>
<li
className="divider"
/>
<li <li
className="dropdown-header" className="dropdown-header"
> >

+ 13
- 29
server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranch.tsx View File

import * as PropTypes from 'prop-types'; import * as PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import ComponentNavBranchesMenu from './ComponentNavBranchesMenu'; import ComponentNavBranchesMenu from './ComponentNavBranchesMenu';
import SingleBranchHelperPopup from './SingleBranchHelperPopup';
import NoBranchSupportPopup from './NoBranchSupportPopup';
import DocTooltip from '../../../../components/docs/DocTooltip';
import { BranchLike, Component } from '../../../types'; import { BranchLike, Component } from '../../../types';
import * as theme from '../../../theme'; import * as theme from '../../../theme';
import BranchIcon from '../../../../components/icons-components/BranchIcon'; import BranchIcon from '../../../../components/icons-components/BranchIcon';
} from '../../../../helpers/branches'; } from '../../../../helpers/branches';
import { translate } from '../../../../helpers/l10n'; import { translate } from '../../../../helpers/l10n';
import PlusCircleIcon from '../../../../components/icons-components/PlusCircleIcon'; 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'; import Tooltip from '../../../../components/controls/Tooltip';


interface Props { interface Props {
if (isShortLivingBranch(currentBranchLike)) { if (isShortLivingBranch(currentBranchLike)) {
return currentBranchLike.isOrphan ? ( return currentBranchLike.isOrphan ? (
<span className="note big-spacer-left text-ellipsis flex-shrink"> <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>
) : ( ) : (
<span className="note big-spacer-left"> <span className="note big-spacer-left">
} }
}; };


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() { render() {
const { branchLikes, currentBranchLike } = this.props; const { branchLikes, currentBranchLike } = this.props;


fill={theme.gray80} fill={theme.gray80}
/> />
<span className="note">{displayName}</span> <span className="note">{displayName}</span>
{this.renderNoBranchSupportPopup()}
<DocTooltip className="spacer-left" doc="branches/no-branch-support">
<PlusCircleIcon fill={theme.gray71} size={12} />
</DocTooltip>
</div> </div>
); );
} }
<div className="navbar-context-branches"> <div className="navbar-context-branches">
<BranchIcon branchLike={currentBranchLike} className="little-spacer-right" /> <BranchIcon branchLike={currentBranchLike} className="little-spacer-right" />
<span className="note">{displayName}</span> <span className="note">{displayName}</span>
{this.renderSingleBranchPopup()}
<DocTooltip className="spacer-left" doc="branches/single-branch">
<PlusCircleIcon fill={theme.blue} size={12} />
</DocTooltip>
</div> </div>
); );
} }

+ 8
- 5
server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranchesMenu.tsx View File

import { translate } from '../../../../helpers/l10n'; import { translate } from '../../../../helpers/l10n';
import { getBranchLikeUrl } from '../../../../helpers/urls'; import { getBranchLikeUrl } from '../../../../helpers/urls';
import SearchBox from '../../../../components/controls/SearchBox'; import SearchBox from '../../../../components/controls/SearchBox';
import Tooltip from '../../../../components/controls/Tooltip';
import HelpTooltip from '../../../../components/controls/HelpTooltip';


interface Props { interface Props {
branchLikes: BranchLike[]; branchLikes: BranchLike[];
{showDivider && <li className="divider" />} {showDivider && <li className="divider" />}
{showOrphanHeader && ( {showOrphanHeader && (
<li className="dropdown-header"> <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> </li>
)} )}
{showPullRequestHeader && ( {showPullRequestHeader && (

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

/*
* 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

/>, />,
{ context: { branchesEnabled: true } } { context: { branchesEnabled: true } }
); );
expect(wrapper.find('Popup')).toMatchSnapshot();
expect(wrapper.find('DocTooltip')).toMatchSnapshot();
}); });


it('renders no branch support popup', () => { it('renders no branch support popup', () => {
/>, />,
{ context: { branchesEnabled: false } } { context: { branchesEnabled: false } }
); );
expect(wrapper.find('Popup')).toMatchSnapshot();
expect(wrapper.find('DocTooltip')).toMatchSnapshot();
}); });


it('renders nothing on SonarCloud without branch support', () => { 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

`; `;


exports[`renders no branch support popup 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`] = ` exports[`renders pull request 1`] = `
`; `;


exports[`renders single branch popup 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

<li <li
className="dropdown-header" 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> </li>
<ComponentNavBranchesMenuItem <ComponentNavBranchesMenuItem
branchLike={ branchLike={
<li <li
className="dropdown-header" 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> </li>
<ComponentNavBranchesMenuItem <ComponentNavBranchesMenuItem
branchLike={ branchLike={

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

// 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

// 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

<GlobalNavExplore location={this.props.location} onSonarCloud={this.props.onSonarCloud} /> <GlobalNavExplore location={this.props.location} onSonarCloud={this.props.onSonarCloud} />
<li> <li>
<EmbedDocsPopupHelper <EmbedDocsPopupHelper
currentUser={this.props.currentUser}
showTooltip={this.state.onboardingTutorialTooltip} showTooltip={this.state.onboardingTutorialTooltip}
suggestions={this.props.suggestions} suggestions={this.props.suggestions}
tooltip={!this.props.onSonarCloud} tooltip={!this.props.onSonarCloud}

+ 0
- 6
server/sonar-web/src/main/js/app/styles/init/icons.css View File

} }
} }


.icon-help:before {
content: '\f059';
color: var(--blue);
font-size: var(--bigFontSize);
}

.icon-close:before { .icon-close:before {
content: '\f00d'; content: '\f00d';
font-size: var(--bigFontSize); font-size: var(--bigFontSize);

+ 2
- 0
server/sonar-web/src/main/js/app/utils/exposeLibraries.ts View File

import HomePageSelect from '../../components/controls/HomePageSelect'; import HomePageSelect from '../../components/controls/HomePageSelect';
import ListFooter from '../../components/controls/ListFooter'; import ListFooter from '../../components/controls/ListFooter';
import Modal from '../../components/controls/Modal'; import Modal from '../../components/controls/Modal';
import HelpTooltip from '../../components/controls/HelpTooltip';
import SearchBox from '../../components/controls/SearchBox'; import SearchBox from '../../components/controls/SearchBox';
import Select from '../../components/controls/Select'; import Select from '../../components/controls/Select';
import Tooltip from '../../components/controls/Tooltip'; import Tooltip from '../../components/controls/Tooltip';
DuplicationsRating, DuplicationsRating,
EditButton, EditButton,
FavoriteContainer, FavoriteContainer,
HelpTooltip,
HomePageSelect, HomePageSelect,
Level, Level,
LicenseEditionSet, LicenseEditionSet,

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

* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
import * as React from 'react'; import * as React from 'react';
import BubblePopup from '../../../components/common/BubblePopup';
import { translate } from '../../../helpers/l10n'; import { translate } from '../../../helpers/l10n';


interface Props {
popupPosition?: any;
}

export default function NoWorkersSupportPopup(props: Props) {
export default function NoWorkersSupportPopup() {
return ( 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

import WorkersForm from './WorkersForm'; import WorkersForm from './WorkersForm';
import NoWorkersSupportPopup from './NoWorkersSupportPopup'; import NoWorkersSupportPopup from './NoWorkersSupportPopup';
import AlertWarnIcon from '../../../components/icons-components/AlertWarnIcon'; 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 Tooltip from '../../../components/controls/Tooltip';
import * as theme from '../../../app/theme';
import { getWorkers } from '../../../api/ce'; import { getWorkers } from '../../../api/ce';
import { translate } from '../../../helpers/l10n'; import { translate } from '../../../helpers/l10n';
import { EditButton } from '../../../components/ui/buttons'; import { EditButton } from '../../../components/ui/buttons';
const { canSetWorkerCount, formOpen, loading, workerCount } = this.state; const { canSetWorkerCount, formOpen, loading, workerCount } = this.state;


return ( return (
<div>
<div className="display-flex-center">
{!loading && {!loading &&
workerCount > 1 && ( workerCount > 1 && (
<Tooltip overlay={translate('background_tasks.number_of_workers.warning')}> <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> </span>
</Tooltip> </Tooltip>
)} )}


{!loading && {!loading &&
!canSetWorkerCount && ( !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} />} {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

// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP


exports[`opens form 1`] = ` exports[`opens form 1`] = `
<div>
<div
className="display-flex-center"
>
<span <span
className="text-middle" className="text-middle"
> >
`; `;


exports[`opens form 2`] = ` exports[`opens form 2`] = `
<div>
<div
className="display-flex-center"
>
<span <span
className="text-middle" className="text-middle"
> >
`; `;


exports[`renders 1`] = ` exports[`renders 1`] = `
<div>
<div
className="display-flex-center"
>
<span <span
className="text-middle" className="text-middle"
> >
`; `;


exports[`renders 2`] = ` exports[`renders 2`] = `
<div>
<div
className="display-flex-center"
>
<span <span
className="text-middle" className="text-middle"
> >
`; `;


exports[`renders 3`] = ` exports[`renders 3`] = `
<div>
<div
className="display-flex-center"
>
<Tooltip <Tooltip
overlay="background_tasks.number_of_workers.warning" overlay="background_tasks.number_of_workers.warning"
> >
<span>
<span
className="display-inline-flex-center little-spacer-right"
>
<AlertWarnIcon <AlertWarnIcon
className="little-spacer-right bt-workers-warning-icon"
fill="#d3d3d3" fill="#d3d3d3"
/> />
</span> </span>
`; `;


exports[`renders 4`] = ` exports[`renders 4`] = `
<div>
<div
className="display-flex-center"
>
<Tooltip <Tooltip
overlay="background_tasks.number_of_workers.warning" overlay="background_tasks.number_of_workers.warning"
> >
<span>
<span
className="display-inline-flex-center little-spacer-right"
>
<AlertWarnIcon <AlertWarnIcon
className="little-spacer-right bt-workers-warning-icon"
fill="#d3d3d3" fill="#d3d3d3"
/> />
</span> </span>
2 2
</strong> </strong>
</span> </span>
<span
<HelpTooltip
className="spacer-left" 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> </div>
`; `;


exports[`updates worker count 1`] = ` exports[`updates worker count 1`] = `
<div>
<div
className="display-flex-center"
>
<span <span
className="text-middle" className="text-middle"
> >
`; `;


exports[`updates worker count 2`] = ` exports[`updates worker count 2`] = `
<div>
<div
className="display-flex-center"
>
<Tooltip <Tooltip
overlay="background_tasks.number_of_workers.warning" overlay="background_tasks.number_of_workers.warning"
> >
<span>
<span
className="display-inline-flex-center little-spacer-right"
>
<AlertWarnIcon <AlertWarnIcon
className="little-spacer-right bt-workers-warning-icon"
fill="#d3d3d3" fill="#d3d3d3"
/> />
</span> </span>

+ 3
- 8
server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.js View File

import EmptyResult from './EmptyResult'; import EmptyResult from './EmptyResult';
import OriginalBubbleChart from '../../../components/charts/BubbleChart'; import OriginalBubbleChart from '../../../components/charts/BubbleChart';
import ColorRatingsLegend from '../../../components/charts/ColorRatingsLegend'; 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 { formatMeasure, isDiffMetric } from '../../../helpers/measures';
import { import {
getLocalizedMetricDomain, getLocalizedMetricDomain,
return ( return (
<div className="measure-overview-bubble-chart-header"> <div className="measure-overview-bubble-chart-header">
<span className="measure-overview-bubble-chart-title"> <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>
<span className="measure-overview-bubble-chart-legend"> <span className="measure-overview-bubble-chart-legend">
<span className="note"> <span className="note">

+ 5
- 2
server/sonar-web/src/main/js/apps/documentation/components/App.tsx View File

import DocMarkdownBlock from '../../../components/docs/DocMarkdownBlock'; import DocMarkdownBlock from '../../../components/docs/DocMarkdownBlock';
import DeferredSpinner from '../../../components/common/DeferredSpinner'; import DeferredSpinner from '../../../components/common/DeferredSpinner';
import { translate } from '../../../helpers/l10n'; import { translate } from '../../../helpers/l10n';
import '../styles.css';


interface Props { interface Props {
params: { splat?: string }; params: { splat?: string };
return ( return (
<div className="boxed-group"> <div className="boxed-group">
<DocMarkdownBlock <DocMarkdownBlock
className="cut-margins boxed-group-inner"
className="documentation-content cut-margins boxed-group-inner"
content={this.state.content} content={this.state.content}
displayH1={true} displayH1={true}
/> />
</ScreenPositionHelper> </ScreenPositionHelper>


<div className="layout-page-main"> <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>
</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

* along with this program; if not, write to the Free Software Foundation, * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 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

import Checkbox from '../../../components/controls/Checkbox'; import Checkbox from '../../../components/controls/Checkbox';
import Modal from '../../../components/controls/Modal'; import Modal from '../../../components/controls/Modal';
import Select from '../../../components/controls/Select'; 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 SeverityHelper from '../../../components/shared/SeverityHelper';
import Avatar from '../../../components/ui/Avatar'; import Avatar from '../../../components/ui/Avatar';
import { SubmitButton } from '../../../components/ui/buttons'; import { SubmitButton } from '../../../components/ui/buttons';
return ( return (
<div className="modal-field"> <div className="modal-field">
<label htmlFor="comment"> <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> </label>
<div> <div>
<textarea <textarea

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

import React from 'react'; import React from 'react';
import QualityGateConditions from './QualityGateConditions'; import QualityGateConditions from './QualityGateConditions';
import EmptyQualityGate from './EmptyQualityGate'; import EmptyQualityGate from './EmptyQualityGate';
import * as theme from '../../../app/theme';
import { translate } from '../../../helpers/l10n'; import { translate } from '../../../helpers/l10n';
import Level from '../../../components/ui/Level'; 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 DocTooltip from '../../../components/docs/DocTooltip';
import HelpIcon from '../../../components/icons-components/HelpIcon';
/*:: import type { Component, MeasuresList } from '../types'; */ /*:: import type { Component, MeasuresList } from '../types'; */


function parseQualityGateDetails(rawDetails /*: string */) { function parseQualityGateDetails(rawDetails /*: string */) {


{ignoredConditions && ( {ignoredConditions && (
<div className="alert alert-info display-inline-block big-spacer-top"> <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> </div>
)} )}



+ 8
- 11
server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/QualityGate-test.js.snap View File

<div <div
className="alert alert-info display-inline-block big-spacer-top" 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>
</div> </div>
`; `;

+ 4
- 6
server/sonar-web/src/main/js/apps/permission-templates/components/ListHeader.js View File

*/ */
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Tooltip from '../../../components/controls/Tooltip';
import HelpTooltip from '../../../components/controls/HelpTooltip';
import { translate } from '../../../helpers/l10n'; import { translate } from '../../../helpers/l10n';


export default class ListHeader extends React.PureComponent { export default class ListHeader extends React.PureComponent {


render() { render() {
const cells = this.props.permissions.map(permission => ( 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> </th>
)); ));



+ 3
- 4
server/sonar-web/src/main/js/apps/permissions/shared/components/PermissionHeader.tsx View File

* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
import * as React from 'react'; import * as React from 'react';
import HelpTooltip from '../../../../components/controls/HelpTooltip';
import Tooltip from '../../../../components/controls/Tooltip'; import Tooltip from '../../../../components/controls/Tooltip';
import { translate, translateWithParameters } from '../../../../helpers/l10n'; import { translate, translateWithParameters } from '../../../../helpers/l10n';


'global_permissions.filter_by_x_permission', 'global_permissions.filter_by_x_permission',
permission.name permission.name
)}> )}>
<a href="#" onClick={this.handlePermissionClick}>
<a className="text-middle" href="#" onClick={this.handlePermissionClick}>
{permission.name} {permission.name}
</a> </a>
</Tooltip> </Tooltip>
<Tooltip overlay={this.renderTooltip(permission)}>
<i className="icon-help little-spacer-left" />
</Tooltip>
<HelpTooltip className="spacer-left" overlay={this.renderTooltip(permission)} />
</div> </div>
</th> </th>
); );

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

} }


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

+ 8
- 5
server/sonar-web/src/main/js/apps/projectBranches/components/App.tsx View File

import { translate } from '../../../helpers/l10n'; import { translate } from '../../../helpers/l10n';
import { getValues } from '../../../api/settings'; import { getValues } from '../../../api/settings';
import { formatMeasure } from '../../../helpers/measures'; import { formatMeasure } from '../../../helpers/measures';
import Tooltip from '../../../components/controls/Tooltip';
import HelpTooltip from '../../../components/controls/HelpTooltip';


interface Props { interface Props {
branchLikes: BranchLike[]; branchLikes: BranchLike[];
<React.Fragment key={getBranchLikeKey(branchLike)}> <React.Fragment key={getBranchLikeKey(branchLike)}>
{showOrphanHeader && ( {showOrphanHeader && (
<li className="dropdown-header"> <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> </li>
)} )}
<BranchRow <BranchRow

+ 8
- 7
server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/App-test.tsx.snap View File

<li <li
className="dropdown-header" 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> </li>
<BranchRow <BranchRow
branchLike={ branchLike={

+ 3
- 8
server/sonar-web/src/main/js/apps/projects/visualizations/Risk.tsx View File

import { translate, translateWithParameters } from '../../../helpers/l10n'; import { translate, translateWithParameters } from '../../../helpers/l10n';
import { RATING_COLORS } from '../../../helpers/constants'; import { RATING_COLORS } from '../../../helpers/constants';
import { getProjectUrl } from '../../../helpers/urls'; 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 = 'sqale_index';
const X_METRIC_TYPE = 'SHORT_WORK_DUR'; const X_METRIC_TYPE = 'SHORT_WORK_DUR';
</div> </div>
<div className="measure-details-bubble-chart-axis size"> <div className="measure-details-bubble-chart-axis size">
<span className="measure-details-bubble-chart-title"> <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> </span>
<div> <div>
<span className="spacer-right"> <span className="spacer-right">

+ 3
- 8
server/sonar-web/src/main/js/apps/projects/visualizations/SimpleBubbleChart.tsx View File

import { RATING_COLORS } from '../../../helpers/constants'; import { RATING_COLORS } from '../../../helpers/constants';
import { getProjectUrl } from '../../../helpers/urls'; import { getProjectUrl } from '../../../helpers/urls';
import { Project } from '../types'; 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 { export interface Metric {
key: string; key: string;
</div> </div>
<div className="measure-details-bubble-chart-axis size"> <div className="measure-details-bubble-chart-axis size">
<span className="measure-details-bubble-chart-title"> <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> </span>
<div> <div>
{colorMetric != null && ( {colorMetric != null && (

+ 8
- 9
server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Risk-test.tsx.snap View File

<span <span
className="measure-details-bubble-chart-title" 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> </span>
<div> <div>
<span <span

+ 6
- 10
server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/SimpleBubbleChart-test.tsx.snap View File

<span <span
className="measure-details-bubble-chart-title" className="measure-details-bubble-chart-title"
> >
<Tooltip
<span
className="text-middle"
/>
<HelpTooltip
className="spacer-left"
overlay="foobar" overlay="foobar"
>
<span
className="spacer-left text-info"
>
<HelpIcon
className="text-bottom"
/>
</span>
</Tooltip>
/>
</span> </span>
<div> <div>
<span <span

+ 6
- 5
server/sonar-web/src/main/js/apps/projectsManagement/Search.tsx View File

import Checkbox from '../../components/controls/Checkbox'; import Checkbox from '../../components/controls/Checkbox';
import { translate } from '../../helpers/l10n'; import { translate } from '../../helpers/l10n';
import QualifierIcon from '../../components/shared/QualifierIcon'; 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 DateInput from '../../components/controls/DateInput';
import Select from '../../components/controls/Select'; import Select from '../../components/controls/Select';
import SearchBox from '../../components/controls/SearchBox'; import SearchBox from '../../components/controls/SearchBox';
className="link-checkbox-control" className="link-checkbox-control"
id="projects-provisioned" id="projects-provisioned"
onCheck={this.props.onProvisionedChanged}> onCheck={this.props.onProvisionedChanged}>
<span className="little-spacer-left">
<span className="text-middle little-spacer-left">
{translate('provisioning.only_provisioned')} {translate('provisioning.only_provisioned')}
<Tooltip overlay={translate('provisioning.only_provisioned.tooltip')}>
<i className="spacer-left icon-help" />
</Tooltip>
</span> </span>
</Checkbox> </Checkbox>
<HelpTooltip
className="spacer-left"
overlay={translate('provisioning.only_provisioned.tooltip')}
/>
</td> </td>
) : null; ) : null;



+ 10
- 16
server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Search-test.tsx.snap View File

thirdState={false} thirdState={false}
> >
<span <span
className="little-spacer-left"
className="text-middle little-spacer-left"
> >
provisioning.only_provisioned provisioning.only_provisioned
<Tooltip
overlay="provisioning.only_provisioned.tooltip"
>
<i
className="spacer-left icon-help"
/>
</Tooltip>
</span> </span>
</Checkbox> </Checkbox>
<HelpTooltip
className="spacer-left"
overlay="provisioning.only_provisioned.tooltip"
/>
</td> </td>
<td <td
className="text-middle" className="text-middle"
thirdState={false} thirdState={false}
> >
<span <span
className="little-spacer-left"
className="text-middle little-spacer-left"
> >
provisioning.only_provisioned provisioning.only_provisioned
<Tooltip
overlay="provisioning.only_provisioned.tooltip"
>
<i
className="spacer-left icon-help"
/>
</Tooltip>
</span> </span>
</Checkbox> </Checkbox>
<HelpTooltip
className="spacer-left"
overlay="provisioning.only_provisioned.tooltip"
/>
</td> </td>
<td <td
className="text-middle" className="text-middle"

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

import * as React from 'react'; import * as React from 'react';
import * as classNames from 'classnames'; import * as classNames from 'classnames';
import Tooltip from '../../../components/controls/Tooltip'; import Tooltip from '../../../components/controls/Tooltip';
import DocInclude from '../../../components/docs/DocInclude';
import { translate } from '../../../helpers/l10n'; import { translate } from '../../../helpers/l10n';


interface Props { interface Props {
className?: string; className?: string;
tooltip?: boolean;
} }


export default function BuiltInQualityGateBadge({ className, tooltip = true }: Props) {
export default function BuiltInQualityGateBadge({ className }: Props) {
const badge = ( const badge = (
<div className={classNames('outline-badge', className)}> <div className={classNames('outline-badge', className)}>
{translate('quality_gates.built_in')} {translate('quality_gates.built_in')}
); );


const overlay = ( 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

import CopyQualityGateForm from './CopyQualityGateForm'; import CopyQualityGateForm from './CopyQualityGateForm';
import DeleteQualityGateForm from './DeleteQualityGateForm'; import DeleteQualityGateForm from './DeleteQualityGateForm';
import { fetchQualityGate, QualityGate, setQualityGateAsDefault } from '../../../api/quality-gates'; import { fetchQualityGate, QualityGate, setQualityGateAsDefault } from '../../../api/quality-gates';
import DocTooltip from '../../../components/docs/DocTooltip';
import { Button } from '../../../components/ui/buttons'; import { Button } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n'; import { translate } from '../../../helpers/l10n';


<div className="layout-page-main-inner"> <div className="layout-page-main-inner">
<div className="pull-left display-flex-center"> <div className="pull-left display-flex-center">
<h2>{qualityGate.name}</h2> <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>


<div className="pull-right"> <div className="pull-right">

+ 1
- 1
server/sonar-web/src/main/js/apps/quality-gates/components/List.js View File

<td className="thin nowrap spacer-left text-right"> <td className="thin nowrap spacer-left text-right">
{qualityGate.isDefault && <span className="badge">{translate('default')}</span>} {qualityGate.isDefault && <span className="badge">{translate('default')}</span>}
{qualityGate.isBuiltIn && ( {qualityGate.isBuiltIn && (
<BuiltInQualityGateBadge className="little-spacer-left" tooltip={false} />
<BuiltInQualityGateBadge className="little-spacer-left" />
)} )}
</td> </td>
</tr> </tr>

+ 5
- 4
server/sonar-web/src/main/js/apps/quality-profiles/components/BuiltInQualityProfileBadge.tsx View File

import * as React from 'react'; import * as React from 'react';
import * as classNames from 'classnames'; import * as classNames from 'classnames';
import Tooltip from '../../../components/controls/Tooltip'; import Tooltip from '../../../components/controls/Tooltip';
import DocInclude from '../../../components/docs/DocInclude';
import { translate } from '../../../helpers/l10n'; import { translate } from '../../../helpers/l10n';


interface Props { interface Props {
); );


const overlay = ( 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>; return <Tooltip overlay={tooltip ? overlay : undefined}>{badge}</Tooltip>;

+ 7
- 5
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritanceBox.tsx View File

import * as React from 'react'; import * as React from 'react';
import ProfileLink from '../components/ProfileLink'; import ProfileLink from '../components/ProfileLink';
import BuiltInQualityProfileBadge from '../components/BuiltInQualityProfileBadge'; import BuiltInQualityProfileBadge from '../components/BuiltInQualityProfileBadge';
import Tooltip from '../../../components/controls/Tooltip';
import HelpTooltip from '../../../components/controls/HelpTooltip';
import { translate, translateWithParameters } from '../../../helpers/l10n'; import { translate, translateWithParameters } from '../../../helpers/l10n';


interface Props { interface Props {
<div style={{ paddingLeft: offset }}> <div style={{ paddingLeft: offset }}>
{displayLink ? ( {displayLink ? (
<ProfileLink <ProfileLink
className="text-middle"
language={props.language} language={props.language}
name={profile.name} name={profile.name}
organization={props.organization}> organization={props.organization}>
{profile.name} {profile.name}
</ProfileLink> </ProfileLink>
) : ( ) : (
profile.name
<span className="text-middle">{profile.name}</span>
)} )}
{profile.isBuiltIn && <BuiltInQualityProfileBadge className="spacer-left" />} {profile.isBuiltIn && <BuiltInQualityProfileBadge className="spacer-left" />}
{extendsBuiltIn && ( {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> </div>
</td> </td>

+ 6
- 5
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesDeprecatedWarning.tsx View File

*/ */
import * as React from 'react'; import * as React from 'react';
import { Link } from 'react-router'; import { Link } from 'react-router';
import Tooltip from '../../../components/controls/Tooltip';
import HelpTooltip from '../../../components/controls/HelpTooltip';
import { getDeprecatedActiveRulesUrl } from '../../../helpers/urls'; import { getDeprecatedActiveRulesUrl } from '../../../helpers/urls';
import { translate } from '../../../helpers/l10n'; import { translate } from '../../../helpers/l10n';


return ( return (
<div className="quality-profile-rules-deprecated clearfix"> <div className="quality-profile-rules-deprecated clearfix">
<span className="pull-left"> <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> </span>
<Link <Link
className="pull-right" className="pull-right"

+ 7
- 6
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesSonarWayComparison.tsx View File

*/ */
import * as React from 'react'; import * as React from 'react';
import { Link } from 'react-router'; import { Link } from 'react-router';
import Tooltip from '../../../components/controls/Tooltip';
import HelpTooltip from '../../../components/controls/HelpTooltip';
import { getRulesUrl } from '../../../helpers/urls'; import { getRulesUrl } from '../../../helpers/urls';
import { translate } from '../../../helpers/l10n'; import { translate } from '../../../helpers/l10n';


return ( return (
<div className="quality-profile-rules-sonarway-missing clearfix"> <div className="quality-profile-rules-sonarway-missing clearfix">
<span className="pull-left"> <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> </span>
<Link className="pull-right" to={url}>
<Link className="pull-right" data-test="rules" to={url}>
{props.sonarWayMissingRules} {props.sonarWayMissingRules}
</Link> </Link>
</div> </div>

+ 8
- 7
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesDeprecatedWarning-test.tsx.snap View File

<span <span
className="pull-left" 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> </span>
<Link <Link
className="pull-right" className="pull-right"

+ 9
- 7
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesSonarWayComparison-test.tsx.snap View File

<span <span
className="pull-left" 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> </span>
<Link <Link
className="pull-right" className="pull-right"
data-test="rules"
onlyActiveOnIndex={false} onlyActiveOnIndex={false}
style={Object {}} style={Object {}}
to={ to={

+ 10
- 10
server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.tsx View File

import { isStagnant } from '../utils'; import { isStagnant } from '../utils';
import { Profile } from '../types'; import { Profile } from '../types';
import Tooltip from '../../../components/controls/Tooltip'; import Tooltip from '../../../components/controls/Tooltip';
import DocTooltip from '../../../components/docs/DocTooltip';
import DocInclude from '../../../components/docs/DocInclude';


interface Props { interface Props {
onRequestFail: (reason: any) => void; onRequestFail: (reason: any) => void;
{profile.name} {profile.name}
</ProfileLink> </ProfileLink>
</div> </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> </div>
); );
} }


if (profile.isDefault) { if (profile.isDefault) {
return ( return (
<>
<Tooltip
overlay={
<DocInclude
className="abs-width-300 cut-margins"
path="/tooltips/quality-profiles/default-quality-profile"
/>
}>
<span className="badge">{translate('default')}</span> <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



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


.oauth-providers + .login-form { .oauth-providers + .login-form {

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

import * as React from 'react'; import * as React from 'react';
import * as classNames from 'classnames'; import * as classNames from 'classnames';
import { translateWithParameters } from '../../../helpers/l10n'; import { translateWithParameters } from '../../../helpers/l10n';
import * as theme from '../../../app/theme';
import { IdentityProvider } from '../../../app/types'; 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 { isDarkColor } from '../../../helpers/colors';
import { getBaseUrl } from '../../../helpers/urls'; import { getBaseUrl } from '../../../helpers/urls';
import './OAuthProviders.css'; import './OAuthProviders.css';
<span>{format(identityProvider.name)}</span> <span>{format(identityProvider.name)}</span>
</a> </a>
{identityProvider.helpMessage && ( {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> </li>
); );

+ 3
- 10
server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/OAuthProviders-test.tsx.snap View File

login.login_with_x.Bar login.login_with_x.Bar
</span> </span>
</a> </a>
<Tooltip
<HelpTooltip
className="oauth-providers-help"
overlay="Help message!" overlay="Help message!"
>
<div
className="oauth-providers-help"
>
<HelpIcon
fill="#4b9fd5"
/>
</div>
</Tooltip>
/>
</li> </li>
`; `;



+ 11
- 14
server/sonar-web/src/main/js/apps/web-api/components/Search.tsx View File

*/ */
import * as React from 'react'; import * as React from 'react';
import Checkbox from '../../../components/controls/Checkbox'; 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 { translate } from '../../../helpers/l10n';
import SearchBox from '../../../components/controls/SearchBox'; import SearchBox from '../../../components/controls/SearchBox';


</div> </div>


<div className="big-spacer-top"> <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> <span className="little-spacer-left">{translate('api_documentation.show_internal')}</span>
</Checkbox> </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>


<div className="spacer-top"> <div className="spacer-top">
<Checkbox checked={showDeprecated} onCheck={onToggleDeprecated}>
<Checkbox checked={showDeprecated} className="text-middle" onCheck={onToggleDeprecated}>
<span className="little-spacer-left"> <span className="little-spacer-left">
{translate('api_documentation.show_deprecated')} {translate('api_documentation.show_deprecated')}
</span> </span>
</Checkbox> </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>
</div> </div>
); );

+ 8
- 16
server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Search-test.tsx.snap View File

> >
<Checkbox <Checkbox
checked={false} checked={false}
className="text-middle"
onCheck={[Function]} onCheck={[Function]}
thirdState={false} thirdState={false}
> >
api_documentation.show_internal api_documentation.show_internal
</span> </span>
</Checkbox> </Checkbox>
<Tooltip
<HelpTooltip
className="spacer-left"
overlay="api_documentation.internal_tooltip" overlay="api_documentation.internal_tooltip"
>
<span>
<HelpIcon
className="spacer-left text-info"
/>
</span>
</Tooltip>
/>
</div> </div>
<div <div
className="spacer-top" className="spacer-top"
> >
<Checkbox <Checkbox
checked={false} checked={false}
className="text-middle"
onCheck={[Function]} onCheck={[Function]}
thirdState={false} thirdState={false}
> >
api_documentation.show_deprecated api_documentation.show_deprecated
</span> </span>
</Checkbox> </Checkbox>
<Tooltip
<HelpTooltip
className="spacer-left"
overlay="api_documentation.deprecation_tooltip" overlay="api_documentation.deprecation_tooltip"
>
<span>
<HelpIcon
className="spacer-left text-info"
/>
</span>
</Tooltip>
/>
</div> </div>
</div> </div>
`; `;

+ 2
- 6
server/sonar-web/src/main/js/apps/webhooks/components/PageHeader.tsx View File

*/ */
import * as React from 'react'; import * as React from 'react';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { Link } from 'react-router';
import { translate } from '../../../helpers/l10n'; import { translate } from '../../../helpers/l10n';


interface Props { interface Props {
id={'webhooks.description'} id={'webhooks.description'}
values={{ values={{
url: ( 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

id="webhooks.description" id="webhooks.description"
values={ values={
Object { 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 webhooks.documentation_link
</a>,
</Link>,
} }
} }
/> />

+ 6
- 7
server/sonar-web/src/main/js/components/common/BranchStatus.tsx View File

import Level from '../ui/Level'; import Level from '../ui/Level';
import BugIcon from '../icons-components/BugIcon'; import BugIcon from '../icons-components/BugIcon';
import CodeSmellIcon from '../icons-components/CodeSmellIcon'; import CodeSmellIcon from '../icons-components/CodeSmellIcon';
import HelpIcon from '../icons-components/HelpIcon';
import HelpTooltip from '../controls/HelpTooltip';
import Tooltip from '../controls/Tooltip'; import Tooltip from '../controls/Tooltip';
import VulnerabilityIcon from '../icons-components/VulnerabilityIcon'; import VulnerabilityIcon from '../icons-components/VulnerabilityIcon';
import { BranchLike } from '../../app/types'; import { BranchLike } from '../../app/types';
<CodeSmellIcon className="little-spacer-left" /> <CodeSmellIcon className="little-spacer-left" />
</li> </li>
{shouldDisplayHelper && ( {shouldDisplayHelper && (
<Tooltip
<HelpTooltip
className="spacer-left"
overlay={translateWithParameters( overlay={translateWithParameters(
'branches.short_lived.quality_gate.description', 'branches.short_lived.quality_gate.description',
totalIssues totalIssues
)}>
<li className="spacer-left">
<HelpIcon className="text-info" />
</li>
</Tooltip>
)}
tagName="li"
/>
)} )}
</ul> </ul>
); );

+ 4
- 10
server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/BranchStatus-test.tsx.snap View File

className="little-spacer-left" className="little-spacer-left"
/> />
</li> </li>
<Tooltip
<HelpTooltip
className="spacer-left"
overlay="branches.short_lived.quality_gate.description.1" overlay="branches.short_lived.quality_gate.description.1"
>
<li
className="spacer-left"
>
<HelpIcon
className="text-info"
/>
</li>
</Tooltip>
tagName="li"
/>
</ul> </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

* along with this program; if not, write to the Free Software Foundation, * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 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

* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
import * as React from 'react'; 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

/*
* 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

* along with this program; if not, write to the Free Software Foundation, * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
.tooltip,
.popup {
.tooltip {
position: absolute; position: absolute;
z-index: var(--tooltipZIndex); z-index: var(--tooltipZIndex);
display: block; display: block;
animation: fadeIn 0.3s forwards; animation: fadeIn 0.3s forwards;
} }


.popup {
font-size: var(--baseFontSize);
font-weight: normal;
}

.tooltip.top,
.popup.top {
.tooltip.top {
padding: 5px 0; padding: 5px 0;
margin-top: -3px; margin-top: -3px;
} }


.tooltip.right,
.popup.right {
.tooltip.right {
padding: 0 5px; padding: 0 5px;
margin-left: 3px; margin-left: 3px;
} }


.tooltip.bottom,
.popup.bottom {
.tooltip.bottom {
padding: 5px 0; padding: 5px 0;
margin-top: 3px; margin-top: 3px;
} }


.tooltip.left,
.popup.left {
.tooltip.left {
padding: 0 5px; padding: 0 5px;
margin-left: -3px; margin-left: -3px;
} }


.tooltip-inner,
.popup-inner {
.tooltip-inner {
max-width: 300px; max-width: 300px;
text-align: left; text-align: left;
text-decoration: none; text-decoration: none;
} }


.tooltip-inner { .tooltip-inner {
padding: 3px 8px;
padding: 12px 17px;
color: #fff; color: #fff;
background-color: #475760; background-color: #475760;
letter-spacing: 0.04em; 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 { .tooltip-inner .alert {
margin-bottom: 5px; margin-bottom: 5px;
border-radius: 4px; border-radius: 4px;
} }


.tooltip-inner a { .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; position: absolute;
width: 0; width: 0;
height: 0; height: 0;
border: solid transparent; border: solid transparent;
} }


.tooltip.top .tooltip-arrow,
.popup.top .popup-arrow,
.popup.top .popup-arrow::after {
.tooltip.top .tooltip-arrow {
bottom: 0; bottom: 0;
left: 50%; left: 50%;
border-width: 5px 5px 0; border-width: 5px 5px 0;
border-top-color: #475760; 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%; top: 50%;
left: 0; left: 0;
transform: translateY(-5px); transform: translateY(-5px);
border-right-color: #475760; 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%; top: 50%;
right: 0; right: 0;
transform: translateY(-5px); transform: translateY(-5px);
border-left-color: #475760; 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; top: 0;
left: 50%; left: 50%;
transform: translateX(-5px); transform: translateX(-5px);
border-bottom-color: #475760; 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 { @keyframes fadeIn {
from { from {
opacity: 0; opacity: 0;

+ 32
- 5
server/sonar-web/src/main/js/components/controls/Tooltip.tsx View File

classNameSpace?: string; classNameSpace?: string;
children: React.ReactElement<{}>; children: React.ReactElement<{}>;
mouseEnterDelay?: number; mouseEnterDelay?: number;
mouseLeaveDelay?: number;
onShow?: () => void; onShow?: () => void;
onHide?: () => void; onHide?: () => void;
overlay: React.ReactNode; overlay: React.ReactNode;
export class TooltipInner extends React.Component<Props, State> { export class TooltipInner extends React.Component<Props, State> {
throttledPositionTooltip: (() => void); throttledPositionTooltip: (() => void);
mouseEnterInterval?: number; mouseEnterInterval?: number;
mouseLeaveInterval?: number;
tooltipNode?: HTMLElement | null; tooltipNode?: HTMLElement | null;
mounted = false; mounted = false;
mouseIn = false;


static defaultProps = { static defaultProps = {
mouseEnterDelay: 0.1 mouseEnterDelay: 0.1
componentWillUnmount() { componentWillUnmount() {
this.mounted = false; this.mounted = false;
this.removeEventListeners(); this.removeEventListeners();
this.clearIntervals();
} }


addEventListeners = () => { addEventListeners = () => {
window.removeEventListener('scroll', this.throttledPositionTooltip); window.removeEventListener('scroll', this.throttledPositionTooltip);
}; };


clearIntervals = () => {
window.clearInterval(this.mouseEnterInterval);
window.clearInterval(this.mouseLeaveInterval);
};

isVisible = () => { isVisible = () => {
return this.props.visible !== undefined ? this.props.visible : this.state.visible; return this.props.visible !== undefined ? this.props.visible : this.state.visible;
}; };
window.clearInterval(this.mouseEnterInterval); window.clearInterval(this.mouseEnterInterval);
this.mouseEnterInterval = undefined; 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() { render() {
const { classNameSpace = 'tooltip' } = this.props; const { classNameSpace = 'tooltip' } = this.props;


<TooltipPortal> <TooltipPortal>
<div <div
className={`${classNameSpace} ${this.getPlacement()}`} className={`${classNameSpace} ${this.getPlacement()}`}
onMouseEnter={this.handleOverlayMouseEnter}
onMouseLeave={this.handleOverlayMouseLeave}
ref={this.tooltipNodeRef} ref={this.tooltipNodeRef}
style={ style={
isMeasured(this.state) isMeasured(this.state)

+ 2
- 0
server/sonar-web/src/main/js/components/controls/__tests__/Tooltip-test.tsx View File

expect(onShow).toBeCalled(); expect(onShow).toBeCalled();


wrapper.find('#tooltip').simulate('mouseleave'); wrapper.find('#tooltip').simulate('mouseleave');
jest.runOnlyPendingTimers();
wrapper.update();
expect(wrapper).toMatchSnapshot(); expect(wrapper).toMatchSnapshot();
expect(onHide).toBeCalled(); expect(onHide).toBeCalled();
}); });

+ 4
- 0
server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Tooltip-test.tsx.snap View File

<TooltipPortal> <TooltipPortal>
<div <div
className="tooltip bottom" className="tooltip bottom"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
> >
<div <div
className="tooltip-inner" className="tooltip-inner"
<TooltipPortal> <TooltipPortal>
<div <div
className="tooltip bottom" className="tooltip bottom"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
> >
<div <div
className="tooltip-inner" className="tooltip-inner"

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

* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
import * as React from 'react'; import * as React from 'react';
import { getBaseUrl } from '../../helpers/urls';


export default function DocImg(props: React.ImgHTMLAttributes<HTMLImageElement>) { export default function DocImg(props: React.ImgHTMLAttributes<HTMLImageElement>) {
const { alt, src, ...other } = props; const { alt, src, ...other } = props;


if (process.env.NODE_ENV === 'development') { 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

import DocMarkdownBlock from './DocMarkdownBlock'; import DocMarkdownBlock from './DocMarkdownBlock';


interface Props { interface Props {
className?: string;
path: string; path: string;
} }


}; };


render() { 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

*/ */
import * as React from 'react'; import * as React from 'react';
import { Link } from 'react-router'; import { Link } from 'react-router';
import DetachIcon from '../../components/icons-components/DetachIcon';


export default function DocLink(props: React.AnchorHTMLAttributes<HTMLAnchorElement>) { export default function DocLink(props: React.AnchorHTMLAttributes<HTMLAnchorElement>) {
const { children, href, ...other } = props; const { children, href, ...other } = props;
} }


return ( 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

* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
import * as React from 'react'; import * as React from 'react';
import * as classNames from 'classnames';
import DocMarkdownBlock from './DocMarkdownBlock'; 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 { interface Props {
className?: string; className?: string;
children?: React.ReactNode;
/** Key of the documentation chunk */ /** Key of the documentation chunk */
doc: string; doc: string;
} }
this.setState({ open: false }); 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() { renderOverlay() {
if (this.state.loading) { if (this.state.loading) {
return ( return (
); );
} }


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() { render() {
return ( 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

import * as React from 'react'; import * as React from 'react';
import { shallow } from 'enzyme'; import { shallow } from 'enzyme';
import DocTooltip from '../DocTooltip'; import DocTooltip from '../DocTooltip';
import { click } from '../../../helpers/testUtils';


jest.useFakeTimers(); jest.useFakeTimers();


wrapper.setProps({ doc: 'baz' }); wrapper.setProps({ doc: 'baz' });
expect(wrapper.state()).toEqual({ content: undefined, loading: false, open: false }); 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

// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP


exports[`should render simple link 1`] = ` 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

// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP


exports[`should render 1`] = ` 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`] = ` 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

*/ */
import * as React from 'react'; import * as React from 'react';
import OpenCloseIcon from '../icons-components/OpenCloseIcon'; 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 { Button } from '../ui/buttons';
import { translate, translateWithParameters } from '../../helpers/l10n'; import { translate, translateWithParameters } from '../../helpers/l10n';


if (!this.props.helper) { if (!this.props.helper) {
return null; 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() { renderValueIndicator() {
return ( return (
<div className="search-navigator-facet-header-wrapper"> <div className="search-navigator-facet-header-wrapper">
{this.props.onClick ? ( {this.props.onClick ? (
<span className="search-navigator-facet-header">
<span className="search-navigator-facet-header display-flex-center">
<a href="#" onClick={this.handleClick}> <a href="#" onClick={this.handleClick}>
<OpenCloseIcon className="little-spacer-right" open={this.props.open} /> <OpenCloseIcon className="little-spacer-right" open={this.props.open} />
{this.props.name} {this.props.name}
{this.renderHelper()} {this.renderHelper()}
</span> </span>
) : ( ) : (
<span className="search-navigator-facet-header">
<span className="search-navigator-facet-header display-flex-center">
{this.props.name} {this.props.name}
{this.renderHelper()} {this.renderHelper()}
</span> </span>

+ 6
- 6
server/sonar-web/src/main/js/components/facet/__tests__/__snapshots__/FacetHeader-test.tsx.snap View File

className="search-navigator-facet-header-wrapper" className="search-navigator-facet-header-wrapper"
> >
<span <span
className="search-navigator-facet-header"
className="search-navigator-facet-header display-flex-center"
> >
<a <a
href="#" href="#"
className="search-navigator-facet-header-wrapper" className="search-navigator-facet-header-wrapper"
> >
<span <span
className="search-navigator-facet-header"
className="search-navigator-facet-header display-flex-center"
> >
<a <a
href="#" href="#"
className="search-navigator-facet-header-wrapper" className="search-navigator-facet-header-wrapper"
> >
<span <span
className="search-navigator-facet-header"
className="search-navigator-facet-header display-flex-center"
> >
<a <a
href="#" href="#"
className="search-navigator-facet-header-wrapper" className="search-navigator-facet-header-wrapper"
> >
<span <span
className="search-navigator-facet-header"
className="search-navigator-facet-header display-flex-center"
> >
<a <a
href="#" href="#"
className="search-navigator-facet-header-wrapper" className="search-navigator-facet-header-wrapper"
> >
<span <span
className="search-navigator-facet-header"
className="search-navigator-facet-header display-flex-center"
> >
<a <a
href="#" href="#"
className="search-navigator-facet-header-wrapper" className="search-navigator-facet-header-wrapper"
> >
<span <span
className="search-navigator-facet-header"
className="search-navigator-facet-header display-flex-center"
> >
foo foo
</span> </span>

+ 5
- 5
server/sonar-web/src/main/js/components/icons-components/HelpIcon.tsx View File

return ( return (
<svg <svg
className={className} className={className}
width={size}
height={size} height={size}
viewBox="0 0 16 16"
version="1.1" 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)"> <g transform="matrix(0.0364583,0,0,0.0364583,1,-0.166667)">
<path <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" 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> </g>
</svg> </svg>

+ 3
- 7
sonar-core/src/main/resources/org/sonar/l10n/core.properties View File

# #
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
embed_docs.suggestion=Suggestions For This Page 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.get_support=Get Support
embed_docs.stay_connected=Stay Connected 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


#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
# #
# BRANCHES # 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=Delete Branch
branches.delete.are_you_sure=Are you sure you want to delete branch "{0}"? branches.delete.are_you_sure=Are you sure you want to delete branch "{0}"?
branches.pull_request.delete=Delete Pull Request branches.pull_request.delete=Delete Pull Request
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.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.set_leak_period=Set Leak Period
branches.last_analysis_date=Last Analysis Date 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.search_for_branches=Search for branches...
branches.pull_requests=Pull Requests 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. 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